Skip to content

Bump WebKit (oven-sh/WebKit#1018 preview): an arrow function of a derived constructor sees this after another one called super() - #48304

Draft
robobun wants to merge 1 commit into
mainfrom
robobun/e0501bca/derived-constructor-this-in-arrow-functions
Draft

robobun wants to merge 1 commit into
mainfrom
robobun/e0501bca/derived-constructor-this-in-arrow-functions

Conversation

@robobun

@robobun robobun commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

WEBKIT_VERSION is the preview build of oven-sh/WebKit#1018: the pinned engine (5a61071f79) plus that change. Move it to oven-sh/WebKit main before this lands.

Problem

Fix

Background

  • WEBKIT_VERSION (scripts/build/deps/webkit.ts) names the oven-sh/WebKit release that the build links, here a pull request's build.
  • Before super() returns, this of a derived constructor has no value and a read throws the error above.

Downsides

Notes

The tests.

  • test/js/bun/jsc-stress/fixtures/derived-constructor-this-initialized-by-another-arrow-function.js is the stress test of [JSC] Arrow functions and eval code of a derived constructor read this at each use when other code of the constructor can call super() WebKit#1018. preload.js gets drainMicrotasks for it.
  • test/cli/inspect/inspect.test.ts: six pauses. The debugger shows the new object as this in an arrow function that has not read this since the super(), in eval code of one, and in the constructor. Console text at a pause reads this, calls super() and reads again.
  • test/bundler/bundler_bun.test.ts: bytecodeDepth 1, 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 of bun build --compile --aot print the same. On main plain Bun throws there and the executable does not.

--aot and stores to a super property. Code that the ahead-of-time compiler compiles reads this at each use already. It checks this after the key and the value of a store to a super property (lower_member_reference and put_reference in src/aot/lower/member/reference.rs).

super[(initialize(), "setter")] = 1 in an arrow function, initialize calls super() Output
Node v26.3.0 ReferenceError, the base constructor does not run
bun run, Bun 1.4.3 ReferenceError, after the base constructor ran
bun run, this PR ReferenceError, the base constructor does not run
executable of bun build --compile --aot, this PR stores, the base constructor ran
  • The two already differ on main in 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.mjs has nine such forms and a // Todo: line. run-parallel.ts reports it as skipped, and fails it when the executable agrees.
  • [JSC] Super property should check this binding 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.
  • I could not file an issue for this: the // Todo: program is the record.

--aot and eval text. The text of a direct eval in a derived constructor reads this through the scope that the executable hands to the engine. On main it reads once, when it starts. Now it reads at each use, so that it sees a super() that comes later. Debug build, one loop iteration of eval text: this.own 8 µs, o.own with o a 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:

  • the four test files above pass. 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.ts and debugger-buntranspiledmodule.test.ts pass.
  • test/aot/run-parallel.ts on 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)
Test-only change.

Debug/ASAN (expected pass):
$ bun bd test 'test/bundler/bundler_bun.test.ts' 'test/cli/inspect/inspect.test.ts' 'test/js/bun/jsc-stress/jsc-stress.test.ts'
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test test/bundler/bundler_bun.test.ts test/cli/inspect/inspect.test.ts test/js/bun/jsc-stress/jsc-stress.test.ts
bun test v1.4.4 (367d939d9)

test/bundler/bundler_bun.test.ts:
(pass) bundler > bun/bytecode-depth-cli [1536.39ms]
(pass) bundler > bun/bytecode-depth-api [508.06ms]
(pass) bundler > bun/bytecode-depth-1-derived-constructor-this-in-arrow-function [441.22ms]
(pass) bundler > bun/bytecode-depth-2-derived-constructor-this-in-arrow-function [403.27ms]
(pass) bundler > bun/bytecode-depth-3-derived-constructor-this-in-arrow-function [417.68ms]
(pass) bundler > bun/import-bun-format-cjs [445.53ms]
(pass) bundler > bun/embedded-sqlite-file [491.17ms]
(pass) bundler > bun/sqlite-file [452.82ms]
(pass) bundler > bun/TargetBunNoSourcemapMessage [638.72ms]
(pass) bundler > bun/TargetBunSourcemapInline [703.71ms]
(pass) bundler > bun/unicode comment [349.61ms]
(pass) bundler > bun/UnknownBunSpecifierIsPrintedAsWritten-cli-esm [312.31ms]
(pass) bundler > bun/UnknownBunSpecifierIsPrintedAsWritten-cli-cjs [313.43ms]
(pass) bundler > bun/UnknownBunSpecifierIsPrintedAsWritten-api-esm [144.15ms]
(pass) bundler > bun/UnknownBunSpecifierIsPrintedAsWritten-api-cjs [169.58ms]
(pass) bundler > bun/UnknownBunSpecifierDoesNotLoadThePackageNamedLikeItsSuffix-esm [581.26ms]
(pass) bundler > bun/BunPrefixedBuiltinLoadsTheBuiltin-esm [557.18ms]
(pass) bundler > bun/UnknownBunSpecifierDoesNotLoadThePackageNamedLikeItsSuffix-cjs [728.82ms]
(pass) bundler > bun/BunPrefixedBuiltinLoadsTheBuiltin-cjs [619.84ms]
(pass) bundler > bun/UnknownBunSpecifierInShebangEntry [162.15ms]
(pass) bundler > bun/UnknownBunSpecifierInExecutable [5164.59ms]
(pass) bundler > bun/ExportsConditionsDevelopmentAPI [387.93ms]
(pass) bundler > bun/ExportsConditionsDevelopmentInProductionAPI [447.19ms]
(pass) bundler > bun/ExportsConditionsDevelopmentCLI [762.14ms]
(pass) bundler > bun/ExportsConditionsDevelopmentInProductionCLI [
... (truncated)
Exit: 0
diff hotspot
scripts/build/deps/webkit.ts                       |   2 +-
 ...row-function-asks-for-this-ahead-of-its-key.mjs |  71 +++
 ...tion-sees-this-once-another-has-called-super.js |  41 ++
 test/bundler/bundler_bun.test.ts                   |  34 ++
 test/cli/inspect/inspect.test.ts                   | 179 +++++++
 ...r-this-initialized-by-another-arrow-function.js | 595 +++++++++++++++++++++
 test/js/bun/jsc-stress/jsc-stress.test.ts          |   2 +
 test/js/bun/jsc-stress/preload.js                  |   3 +
 8 files changed, 926 insertions(+), 1 deletion(-)

gate history · 1 passed · 0 rejected · iteration 0

evidence per changed file
file                                                      reads  edits  tests
scripts/build/deps/webkit.ts                                  0      0     30
…in-an-arrow-function-asks-for-this-ahead-of-its-key.mjs      0      0     30
…row-function-sees-this-once-another-has-called-super.js      0      0     31
test/bundler/bundler_bun.test.ts                              0      0      9
test/cli/inspect/inspect.test.ts                              0      0     18
…nstructor-this-initialized-by-another-arrow-function.js      0      0     30
test/js/bun/jsc-stress/jsc-stress.test.ts                     0      0     12
test/js/bun/jsc-stress/preload.js                             0      0     29

…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.
@robobun

robobun commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 12:14 AM PT - Nov 9th, 2026

❌ @robobun, your commit c9edc11 has 1 failures in Build #139092 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 48304

That installs a local version of the PR into your bun-48304 executable, so you can run:

bun-48304 --bun

@robobun

robobun commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator Author

Status

Reproduced on Bun 1.4.3 and on a debug build of main (2596ac5):

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 WEBKIT_VERSION names, not with src/: with the pin of main the fixture, the inspector test and the three bundler tests fail.

CI, build 139092 at c9edc11: 187 of 188 jobs pass. The one red job is a darwin x64 test-bun shard, where test/js/third_party/grpc-js/test-tonic.test.ts fails all four attempts with error: FILE_ENDED: it cannot unzip the protoc archive that it downloads and keeps on the machine. This PR does not touch that test, and it passes on macOS arm64, Linux and Windows in the same build. No test of this PR failed on any lane.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants