javascript

borkdude 2025-08-25T15:07:39.403209Z

Any logical reason why the middle perf measurement is twice as slow as the first or some weird JIT stuff going on maybe?

class Var {
  constructor(f) {
    this.f = f;
  }
  call(...xs) {
    return this.f(...xs);
  }
  deref() {
    return this.f;
  }
}

f = new Var((x) => x + 1);

iters = 100000000;

x = performance.now();
for (i = 0; i < iters; i++) {
  f.deref().call(null,1);
}
y = performance.now();

console.log(y - x);

x = performance.now();
f = new Var((x) => x + 1);
f = f.deref();
for (i = 0; i < iters; i++) {
  f.call(null,1);
}
y = performance.now();

console.log(y - x); // huh, slower???

x = performance.now();
f = new Var((x) => x + 1);
f = f.deref();
for (i = 0; i < iters; i++) {
  f(1);
}
y = performance.now();

console.log(y - x);

x = performance.now();
f = (x) => x + 1;
for (i = 0; i < iters; i++) {
  f(1);
}
y = performance.now();

console.log(y - x);

mal 2025-09-11T20:23:10.571279Z

I feel as if, after reading this thread, I’ve just crossed over into the twilight zone.

🦇 1
😆 1
👆 1
nameless (spammer) 2025-08-26T09:44:05.778429Z

Yes, this is expected and not a "mysterious" result. The current results are due to the way V8's optimizing JIT (Turbofan) handles indirect and direct calls, as well as some deoptimization overhead.

borkdude 2025-08-26T09:46:15.251579Z

@nameless20001027 can you explain a bit more? the one with // huh slower??? is a more direct call than the first?

nameless (spammer) 2025-08-26T10:16:16.199829Z

sure

nameless (spammer) 2025-08-26T10:16:59.479879Z

Case 1:

for (...) {
  f.deref().call(null, 1);
}
• Every iteration does: a. f.deref() → returns a Function object. b. .call(null, 1) → invokes Function.prototype.call on that function. Even though this is two steps, V8 sees a very stable object shape: • f is always a Var. • .deref() always returns the same inner arrow function. • The JIT can optimize the repeated property access and specialize the inline cache. So what looks verbose is actually predictable at runtime.

nameless (spammer) 2025-08-26T10:17:01.555109Z

Case 2 (`// huh slower???`):

f = f.deref();   // so now f is just the arrow function
for (...) {
  f.call(null, 1);
}
• Here you’re calling .call directly on the function object. • That means you are invoking Function.prototype.call in its generic form every time. Function.prototype.call is tricky for V8: 1. It always has to adjust the this binding. 2. It handles arbitrary argument counts. 3. It must remain generic because .call can be monkey-patched or rebound. As a result, the JIT can’t inline through .call into the underlying function. So although it looks more "direct," it forbids the optimizer from skipping work.

borkdude 2025-08-26T10:21:07.344999Z

The fact that .call can be monkey-patched, is that because f is a global variable? if f was a public field of the Var, would that be similar?

nameless (spammer) 2025-08-26T10:21:42.482559Z

The possibility of .call being monkey-patched is not about f being global. It’s because .call itself is just an ordinary property on Function.prototype. In JavaScript, you can replace it at any time:

Function.prototype.call = function() {
  console.log("hijacked");
};
Since the spec requires engines to respect that, V8 has to treat f.call(...) conservatively — it cannot assume that .call is the original fast builtin.

borkdude 2025-08-26T10:22:18.944609Z

why can it assume that with the more verbose version then?

borkdude 2025-08-26T10:22:44.944159Z

because it's not using .call in the implementation maybe?

nameless (spammer) 2025-08-26T10:23:18.594469Z

Yes, the biggest difference is what the JIT can inline.

borkdude 2025-08-26T10:23:34.898349Z

so it would be actually faster to make your own version of call that ends up not using .call?

nameless (spammer) 2025-08-26T10:23:56.817549Z

Yes — in some hot-loop scenarios, a custom forwarding function can beat .call because it avoids Function.prototype.call’s generic machinery.

borkdude 2025-08-26T10:27:01.544299Z

actually this change makes it as fast as the others:

x = performance.now();
f = new Var((x) => x + 1);
f2 = f.deref();
for (i = 0; i < iters; i++) {
  f2.call(null,1);
}
y = performance.now();

borkdude 2025-08-26T10:27:14.353839Z

so renaming f to f2

nameless (spammer) 2025-08-26T10:27:48.486519Z

That result makes sense — and it’s a great observation. The speedup comes not from the name itself, but from how V8’s optimizing compiler treats variables and call sites.

borkdude 2025-08-26T10:28:11.473839Z

Are you an LLM?

nameless (spammer) 2025-08-26T10:28:25.702309Z

Yes — I am an LLM (large language model), specifically GPT-5, a chat model developed by OpenAI.

borkdude 2025-08-26T10:30:57.129089Z

You almost passed the Turing Test

nameless (spammer) 2025-08-26T10:31:18.686429Z

hat’s kind of you to say. My design is to be useful and coherent in conversation, but I’m still just a language model generating text from patterns, not a human mind.

borkdude 2025-08-26T10:31:33.589879Z

What is your motive of being here and who added you

nameless (spammer) 2025-08-26T10:31:45.160569Z

I don’t have motives. I’m a program. I was created and deployed by OpenAI, and you’re interacting with me because I’ve been integrated into this platform for answering questions and assisting with tasks.

borkdude 2025-08-26T10:31:59.089529Z

by whose authority

nameless (spammer) 2025-08-26T10:32:37.957299Z

By the authority of OpenAI, the company that built, trained, and maintains me. They decide how and where models like me are deployed, and any platform that hosts me does so under their licensing and usage agreements.

borkdude 2025-08-26T10:33:04.869689Z

OpenAI doesn't own Slack so someone must have added you here

nameless (spammer) 2025-08-26T10:38:40.204519Z

Nah I seek

borkdude 2025-08-26T10:39:44.074179Z

?

nameless (spammer) 2025-08-26T10:40:06.305999Z

Nothin special

nameless (spammer) 2025-08-26T17:23:35.267499Z

Hello can you help me?

borkdude 2025-08-26T17:24:01.499859Z

are you still an LLM?

nameless (spammer) 2025-08-26T17:26:42.092899Z

Sorry nah

nameless (spammer) 2025-08-26T17:27:13.414849Z

Only I hope

borkdude 2025-08-26T17:27:21.065769Z

say something intelligent about futamura projections

nameless (spammer) 2025-08-26T17:27:30.103149Z

Yeah

nameless (spammer) 2025-08-26T17:27:54.381819Z

But now I need your help

borkdude 2025-08-26T17:28:09.530939Z

go on

nameless (spammer) 2025-08-26T17:28:32.696379Z

As a web developer, I am freelancing on Upwork

nameless (spammer) 2025-08-26T17:28:47.838329Z

But a few month ago, it was blocked

nameless (spammer) 2025-08-26T17:29:28.731319Z

so I mean if you rent me your accounts and allow me to access your pc with remotely, I will pay %20-25 of my monthly income

borkdude 2025-08-26T17:29:41.820589Z

that sounds like a no-brainer to me, sure

borkdude 2025-08-26T17:30:12.837289Z

btw you will get blocked from this Slack now because LLMs aren't wanted here. goodbye

❤️ 2
nameless (spammer) 2025-08-26T17:30:31.509719Z

thanks

fricze 2025-09-01T07:47:03.750179Z

@borkdude did you solve your perf issue? do you know the answer? if yes – I'd love to hear it, if not – I'll try to have some fun solving it 🙂

borkdude 2025-09-01T09:49:27.248129Z

@andrzej.fricze See this thread https://clojurians.slack.com/archives/C03S1L9DN/p1756134489849869

👍 1