Skip to content

Bump WebKit (oven-sh/WebKit#438 preview): call the tag of super.tag... with the method's this - #38920

Open
robobun wants to merge 1 commit into
mainfrom
farm/49eb5711/webkit-tagged-template-super-this
Open

robobun wants to merge 1 commit into
mainfrom
farm/49eb5711/webkit-tagged-template-super-this

Conversation

@robobun

@robobun robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

Problem

  • super.tag\x`inside a method callstagwiththis = the object the property was found on (Base.prototypefor a class, the[[Prototype]]for an object literal method) instead of the receiver.super.tag()in the same method gets the receiver, and so does node; the spec gives both forms the samethis(EvaluateCall step 1.a.i: GetThisValue of a Super Reference). Same forsuper[key]`x``.
  • A smaller consequence of the same code: in a derived constructor that has not called super() yet, super[key()]\x`evaluatedkey()before throwing the ReferenceError for the uninitializedthis; superkey()and a plainsuper[key()]` read throw first (node does too).
  • Not the transpiler: bun build --no-bundle prints the tagged template unchanged and the same code misbehaves through new Function. The cause is in JavaScriptCore, TaggedTemplateNode::emitBytecode (Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp): one register, base, serves both as the object the tag is looked up on and as the call's this. For a super reference it already looked the property up with the right receiver, then moved base (the home object's prototype) into the call's this register. The super call nodes (FunctionCallDotNode, FunctionCallBracketNode) keep the two apart. Upstream WebKit has the same code.
  • Found by inspection while working on the transpiler's decorator lowering of super accesses (that lowering emits .bind(this) and is unaffected); there is no user report. It affects every plain JS/TS class or object literal method that forwards to an inherited tag this way.

Fix

Background

  • Bun links a prebuilt JavaScriptCore from oven-sh/WebKit; scripts/build/deps/webkit.ts pins which build. An engine fix lands as a WebKit PR plus a pin bump here, and autobuild-preview-pr-* tags let a bump PR run Bun's suite against the WebKit PR before it merges.
  • test/js/bun/jsc-stress/ runs files taken verbatim from WebKit's JSTests/stress under bun; preload.js supplies the jsc shell globals they use (noInline, testLoopCount, now drainMicrotasks), which is why the engine test can be shared with the WebKit PR as is.
  • A method's home object is the object it was defined on (the class prototype, the class itself for static methods, the literal for object literal methods); super.x looks x up on the home object's prototype, but a Super Reference remembers the method's own this as the receiver, which is what getters and calls through it get.
  • A tagged template f\...`is a call offwith the template object and the substitution values as arguments, and the spec computes itsthisexactly as forf(...): for o.fit iso; for super.fit is the enclosing method'sthis, while the property itself is looked up on the home object's prototype (Base.prototype`). JSC's bytecode generator has separate AST nodes for calls and tagged templates, and only the call nodes handled the super case.
  • ensureThis() in JSC's bytecode generator returns the register holding the function's this, after checking it is initialized when the code is a derived constructor (where this is in a TDZ until super() returns). Emitting it before the key expression is what fixes the evaluation order.
Repro
class Base { tag() { return this; } f() { return this; } }
class C extends Base {
  m() { return [super.tag`x` === this, super.f() === this]; }
}
console.log(JSON.stringify(new C().m()));

const o = { __proto__: { tag() { return this === o ? "o" : "proto"; } }, m() { return super.tag`x`; } };
console.log(o.m());
bun 1.4.0 (WebKit f0f60fd2):   [false,true]   proto
node v26:                      [true,true]    o
this PR:                       [true,true]    o

…g with the method's this

JavaScriptCore called the tag of super.tag`...` and super[key]`...` with
the object the tag was found on (Base.prototype) instead of the receiver
that super.tag() uses, and evaluated the key of super[key]`...` before
the this TDZ check in derived constructors. oven-sh/WebKit#438 fixes
TaggedTemplateNode::emitBytecode; this pins its preview build and runs
the stress test from that PR as a jsc-stress fixture. The fixture needs
the jsc shell's drainMicrotasks, which the preload now provides from
bun:jsc.
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@robobun, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 18 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a2359fb9-0eeb-494b-ba7c-49900bdf5cb7

📥 Commits

Reviewing files that changed from the base of the PR and between 7d276b9 and 4938773.

📒 Files selected for processing (4)
  • scripts/build/deps/webkit.ts
  • test/js/bun/jsc-stress/fixtures/tagged-templates-super-this.js
  • test/js/bun/jsc-stress/jsc-stress.test.ts
  • test/js/bun/jsc-stress/preload.js

Comment @coderabbitai help to get the list of available commands.

@robobun

robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 11:58 PM PT - Aug 14th, 2026

@robobun, your commit 4938773 is building: #97541

@robobun

robobun commented Aug 15, 2026 •

Copy link
Copy Markdown
Collaborator Author

Status

  • Reproduced on bun 1.4.0 (WebKit f0f60fd2): super.tag\x`inside a method calls the tag withthis=Base.prototype`; node and the spec give the receiver. Repro in the PR description.
  • Engine fix: TaggedTemplateNode: call super.tag... and super[key]... with the method's this WebKit#438 (preview build autobuild-preview-pr-438-31f493c1, which this PR pins).
  • Fail before / pass after: bun bd test test/js/bun/jsc-stress/jsc-stress.test.ts -t tagged-templates-super-this fails on the f0f60fd2 pin (18 of 20 groups) and passes on the preview pin; the whole jsc-stress file passes on the preview pin (116/116, debug + ASAN).
  • Full JSTests/stress run on both engines' jsc shells: no deterministic differences besides the new test and the 4 FFI tests that go with the carried FFI: convert Number arguments of i64/u64 parameters modulo 2^64 WebKit#421 (numbers in the WebKit PR).
  • CI (build 97541): the new fixture passed on every lane. The failures are unrelated to this diff: test/bake/deinitialization.test.ts segfaulting at exit on Windows 2019 x64, which also fails the same way on other PRs with the stock WebKit pin (e.g. build 97101) and has been reported separately; the other four are marked flaky and passed when rerun alone.
  • Blocked on landing until TaggedTemplateNode: call super.tag... and super[key]... with the method's this WebKit#438 merges; WEBKIT_VERSION then moves from the preview tag to the merged main sha (that push re-runs CI).

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this PR and didn't find any bugs. The Bun-side changes are mechanical (fixture registration, drainMicrotasks preload polyfill, pin bump), but this is a WebKit engine bump on a preview tag that the description says must be repointed to the merged main sha before landing, and it carries three other fork commits — a human should coordinate the land.

What was reviewed:

  • prebuiltUrl/prebuiltDestDir in scripts/build/deps/webkit.ts already handle autobuild-preview-* tags (no truncation, correct release URL).
  • jsc.drainMicrotasks exists in bun:jsc (BunJSCModule.h), so the new preload line resolves.
  • The new fixture's // @bun first line is compatible with parseJSCFlags (skipped before the //@ break check), and the failures-then-throw structure means any shouldBe miss produces a nonzero exit.
Extended reasoning...

Overview

This PR bumps WEBKIT_VERSION to a preview build of oven-sh/WebKit#438 (fixing super.tag\...`to call the tag with the method'sthisinstead of the super base) and adds the corresponding JSTests/stress fixture to Bun's jsc-stress suite. Bun-side changes: one-line pin edit inscripts/build/deps/webkit.ts, a new 347-line fixture file, one line registering it in jsc-stress.test.ts, and a one-line drainMicrotaskspolyfill inpreload.js`.

Security risks

None. No user-facing API surface, no auth/crypto/network code. The fixture is a self-contained JS file run in a subprocess with no filesystem or network access.

Level of scrutiny

The Bun-repo diff itself is low-risk and mechanical — I'd approve it in isolation. But the substance of the change is a JavaScriptCore engine bump, and per the PR description this preview pin (a) must be replaced with the merged main sha before landing, and (b) also carries three unrelated WebKit fork commits (#420 vm.Script reuse, #437 threadsafe FFI callback teardown, #421 i64/u64 FFI args) whose Bun-side PRs are separate. Engine bumps and their landing order are a maintainer decision.

Other factors

  • The build system already handles autobuild-preview-* tags: prebuiltUrl doesn't double-prefix autobuild-, prebuiltDestDir uses the whole tag as the cache key, and download.ts prints a targeted hint if the preview release disappears — so the pin format is fine.
  • The fixture is thorough (dot/bracket, static/instance, object literals, arrows, eval, field initializers, generators/async, TDZ ordering, JIT-tier loop, and a negative-control group for non-super tags) and structured so any failing shouldBe accumulates into a final throw → nonzero exit → test failure. The description documents fail-before/pass-after and a full JSTests/stress diff between the two engine builds.
  • parseJSCFlags in jsc-stress.test.ts explicitly skips the // @bun line before its //@ break, so the fixture having no //@ run* directive just yields an empty env (correct — it runs the default variant).
  • No prior human or bot reviews to address; CI is still building.

@robobun

robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

Agreed on the landing order. To spell it out for whoever lands this:

  1. TaggedTemplateNode: call super.tag... and super[key]... with the method's this WebKit#438 merges (its verification results are in a comment there: new test fail to pass, the 103 super/template stress tests unchanged, full JSTests/stress diff between the two shells explained).
  2. WEBKIT_VERSION in scripts/build/deps/webkit.ts moves from autobuild-preview-pr-438-31f493c1 to the resulting main sha; I will push that change here once the merge happens. That main sha will also contain Let an embedder run a program from an UnlinkedProgramCodeBlock it already holds WebKit#420, Escape quotes in filename used as start #437 and ReferenceError on a bundle made by rollup #421 plus whatever else has merged by then, the same as any other bump taken at that point; nothing in this PR depends on them.
  3. If another bump that already includes Cant install ethersjs #438 lands first, this PR reduces to the fixture, its registration and the drainMicrotasks preload line.

@robobun

robobun commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator Author

oven-sh/WebKit#534 (the (a?.b)\x`receiver fix) rewrites the same two branches ofTaggedTemplateNode::emitBytecodeas oven-sh/WebKit#438 and conflicted with it in three hunks, so #534 now carries #438's commit underneath its own change. #40848 pins that combined preview and absorbs this PR's fixture, its registration and thedrainMicrotasks` preload line. When #40848 lands, this PR can close. If this one lands first, #40848 rebases onto it.

robobun added a commit that referenced this pull request Aug 29, 2026
…fixture

oven-sh/WebKit#534 now also carries oven-sh/WebKit#438's commit, which
fixes the this of super.tag`...`: both rewrite the same two branches of
TaggedTemplateNode::emitBytecode and conflicted. The preview moves to
autobuild-preview-pr-534-492e8dd6, and the jsc-stress fixture of #38920
(tagged-templates-super-this.js, its registration and the drainMicrotasks
preload global it uses) comes along.

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.

1 participant