Repository navigation
Bump WebKit (oven-sh/WebKit#1018 preview): an arrow function of a derived constructor sees this after another one called super() - #48304
Conversation
…ived constructor sees `this` after another one called super() In a derived constructor, an arrow function that reads `this` after another arrow function of the constructor called super() threw "ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object." oven-sh/WebKit#1018 makes such arrow functions, and eval code, read `this` at each use. WEBKIT_VERSION is the preview build of that pull request. The tests: - test/js/bun/jsc-stress/fixtures/derived-constructor-this-initialized-by-another-arrow-function.js is the stress test of that pull request. - test/cli/inspect/inspect.test.ts pauses in such an arrow function, in eval code of one and in the constructor, and reads `this` of the frame and from console text. - test/bundler/bundler_bun.test.ts builds bytecode of depth 1, 2 and 3: the cache keeps what the constructor told its arrow functions. - test/aot/parallel/classes has a program that plain Bun and an executable of --aot print alike, and one with a Todo line for the order of the check in a store to a super property.
|
Updated 12:14 AM PT - Nov 9th, 2026
❌ @robobun, your commit c9edc11 has 1 failures in
🧪 To try this PR locally: bunx bun-pr 48304That installs a local version of the PR into your bun-48304 --bun |
|
Status Reproduced on Bun 1.4.3 and on a debug build of class B {}
class K extends B {
constructor() {
const callSuper = () => { super(); };
const f = () => { callSuper(); return this; };
const r = f();
console.log("K ok", r === this);
}
}
try { new K(); } catch (e) { console.log("K THROWS", e.constructor.name + ": " + e.message); }
The fix is oven-sh/WebKit#1018. This PR pins its preview build and has the tests. Related engine PRs: oven-sh/WebKit#1016, oven-sh/WebKit#1017, oven-sh/WebKit#1019. The tests here pass or fail with the engine that CI, build 139092 at c9edc11: 187 of 188 jobs pass. The one red job is a |
Problem
thisafter another one calledsuper()throwsReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.Node returns the object.thisat the start of an arrow function (BytecodeGenerator::ensureThis()). typescript: match tsc for experimentalDecorators and emitDecoratorMetadata #46553 makes this shape (esbuild's__super), and fix: do not readthisbeforesuper()in wrapped constructors nodejs/orchestrion-js#101 worked around it.Fix
thisat each use when other code of the constructor can call super() WebKit#1018 makes such arrow functions and eval code readthisat each use. This PR pins its build and adds tests.jsc-stressfixture, one test intest/cli/inspect/inspect.test.ts, three intest/bundler/bundler_bun.test.ts, a program intest/aot/parallel/classes/. Bun 1.4.3 fails each, a debug build with that engine passes.Background
WEBKIT_VERSION(scripts/build/deps/webkit.ts) names the oven-sh/WebKit release that the build links, here a pull request's build.super()returns,thisof a derived constructor has no value and a read throws the error above.Downsides
--aot: compiled code checksthisafter the key and value ofsuper[key] = value. Plain Bun now checks first in such arrow functions. A// Todo:program holds the difference.--aot: eval text in a derived constructor pays a lookup per read ofthis: 8 µs in a debug build, half of a constructor variable's read.thisat each use when other code of the constructor can call super() WebKit#1018): only arrow functions of a derived constructor whose arrow function or eval can callsuper()pay.Notes
The tests.
test/js/bun/jsc-stress/fixtures/derived-constructor-this-initialized-by-another-arrow-function.jsis the stress test of [JSC] Arrow functions and eval code of a derived constructor readthisat each use when other code of the constructor can call super() WebKit#1018.preload.jsgetsdrainMicrotasksfor it.test/cli/inspect/inspect.test.ts: six pauses. The debugger shows the new object asthisin an arrow function that has not readthissince thesuper(), in eval code of one, and in the constructor. Console text at a pause readsthis, callssuper()and reads again.test/bundler/bundler_bun.test.ts:bytecodeDepth1, 2 and 3. The bytecode then has the constructor and not the code of its arrow functions, or their code and not the code of their eval. The cache must keep what the constructor told them.test/aot/parallel/classes/an-arrow-function-sees-this-once-another-has-called-super.js: plain Bun and an executable ofbun build --compile --aotprint the same. Onmainplain Bun throws there and the executable does not.--aotand stores to a super property. Code that the ahead-of-time compiler compiles readsthisat each use already. It checksthisafter the key and the value of a store to a super property (lower_member_referenceandput_referenceinsrc/aot/lower/member/reference.rs).super[(initialize(), "setter")] = 1in an arrow function,initializecallssuper()ReferenceError, the base constructor does not runbun run, Bun 1.4.3ReferenceError, after the base constructor ranbun run, this PRReferenceError, the base constructor does not runbun build --compile --aot, this PRmainin this form. They differ in one more way now: a side effect in the key or the value happens in the executable and not in plain Bun.test/aot/parallel/classes/a-store-through-super-in-an-arrow-function-asks-for-this-ahead-of-its-key.mjshas nine such forms and a// Todo:line.run-parallel.tsreports it as skipped, and fails it when the executable agrees.thisbinding before evaluating the property expression WebKit/WebKit#76967 moves the check in front of the key in all code of the engine. The front end can take the same order with it. Before that, a check in front of the key in all compiled code would differ from plain Bun in the body of a constructor.// Todo:program is the record.--aotand eval text. The text of a direct eval in a derived constructor readsthisthrough the scope that the executable hands to the engine. Onmainit reads once, when it starts. Now it reads at each use, so that it sees asuper()that comes later. Debug build, one loop iteration of eval text:this.own8 µs,o.ownwithoa variable of the constructor 16 µs, a variable of the text itself 20 ns.Runs. Debug build of this branch with a local build of the engine of oven-sh/WebKit#1018 (6ada7bda05), Linux x64:
USE_SYSTEM_BUN=1(Bun 1.4.3) fails the fixture, the inspector test and the three bundler tests.test/cli/inspect/inspect.test.ts(31 pass),bun-inspector-protocol.test.tsanddebugger-buntranspiledmodule.test.tspass.test/aot/run-parallel.tson four programs with a direct eval in a class: pass.[policy-decision:webkit] gate passed · iteration 0 · 8 files touched
passes on PR (with fix)
diff hotspot
gate history · 1 passed · 0 rejected · iteration 0
evidence per changed file