Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9bb8897
Make Buffer read*/write* native functions with a DFG/FTL intrinsic
Jarred-Sumner Jul 24, 2026
4383835
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 24, 2026
9bc68f3
Report the coerced number in write* range errors; test and registrati…
Jarred-Sumner Jul 24, 2026
922d63b
Remove writeU_Int8 and the checkBounds export, now unused
Jarred-Sumner Jul 24, 2026
2800801
Move the variable-width read*/write* accessors to native functions too
Jarred-Sumner Jul 24, 2026
f289a67
Remove the now-unused dataView private name and dead var-width helper…
Jarred-Sumner Jul 24, 2026
77ba531
Build against the WebKit preview build for oven-sh/WebKit#330
Jarred-Sumner Jul 24, 2026
c404098
Bump the WebKit preview build (Windows JIT handler merge, write range…
Jarred-Sumner Jul 24, 2026
1fc5e56
Merge branch 'main' into claude/buffer-jit
Jarred-Sumner Jul 24, 2026
af34232
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 24, 2026
9bb5bd7
Pin the NaN / Infinity write semantics after tier-up
Jarred-Sumner Jul 24, 2026
c24eaa7
Run the buffer JIT tests concurrently; make the bad-receiver case rea…
Jarred-Sumner Jul 24, 2026
e702b53
Trigger the detached-receiver exit through the measured call site
Jarred-Sumner Jul 24, 2026
6382eeb
Bound the accessors by the receiver's element count, trim tier-up loops
Jarred-Sumner Jul 25, 2026
7957227
Bump the WebKit preview build (Int52 length path, review fixes)
Jarred-Sumner Jul 25, 2026
7d218bf
Buffer accessors: Node parity for DataView receivers, var-width offse…
Jarred-Sumner Jul 25, 2026
28491a1
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 25, 2026
357582d
Bump the WebKit preview build (differential fuzzer, restored Overflow…
Jarred-Sumner Jul 25, 2026
d807f2d
Guard the BigInt writers against DataView receivers as well
Jarred-Sumner Jul 25, 2026
c56e904
Check the offset before the value for one-byte var-width writes
Jarred-Sumner Jul 25, 2026
50bab58
Validate the BigInt value before reporting a DataView receiver
Jarred-Sumner Jul 25, 2026
f871414
Route the BigInt writers' DataView check through their offset validator
Jarred-Sumner Jul 25, 2026
4e3ea85
Port the JSC stress coverage into the Bun test suite
Jarred-Sumner Jul 26, 2026
9ce177c
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 26, 2026
ea0cf81
Check the offset type before the receiver in the var-width readers
Jarred-Sumner Jul 26, 2026
2a8c837
BigInt writers: validate the value before the receiver, default the o…
Jarred-Sumner Jul 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions bench/snippets/buffer-read-write.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Buffer.prototype.read* / write* — the fixed-width accessors that JSC JIT-compiles into
// bounds-checked loads/stores (see JSBuffer.cpp / JavaScriptCore BufferAccessorRegistry).
//
// Three shapes:
// - a tight loop over one buffer (constant offset): mostly measures call/loop overhead
// - a loop over increasing offsets on one buffer: the load/store + bounds check per iteration
// - one access on each of many distinct buffers: previously paid a hidden DataView allocation
// plus a structure transition per buffer
import { bench, group, run } from "../runner.mjs";

const size = 4096;
const buf = Buffer.alloc(size);
for (let i = 0; i < size; i++) buf[i] = (i * 37 + 11) & 0xff;

const many = Array.from({ length: 1024 }, () => Buffer.alloc(64));

group("constant offset (10 accesses per iteration)", () => {
bench("readInt32LE(0)", () => {
let s = 0;
for (let i = 0; i < 10; i++) s += buf.readInt32LE(0);
return s;
});
bench("writeInt32LE(v, 0)", () => {
for (let i = 0; i < 10; i++) buf.writeInt32LE(i, 0);
});
});

group("varying offset over one buffer", () => {
bench("readInt8", () => {
let s = 0;
for (let i = 0; i < size; i++) s += buf.readInt8(i);
return s;
});
bench("readUInt8", () => {
let s = 0;
for (let i = 0; i < size; i++) s += buf.readUInt8(i);
return s;
});
bench("readInt16BE", () => {
let s = 0;
for (let i = 0; i < size; i += 2) s += buf.readInt16BE(i);
return s;
});
bench("readInt32LE", () => {
let s = 0;
for (let i = 0; i < size; i += 4) s += buf.readInt32LE(i);
return s;
});
bench("readUInt32BE", () => {
let s = 0;
for (let i = 0; i < size; i += 4) s += buf.readUInt32BE(i);
return s;
});
bench("readFloatLE", () => {
let s = 0;
for (let i = 0; i < size; i += 4) s += buf.readFloatLE(i);
return s;
});
bench("readDoubleLE", () => {
let s = 0;
for (let i = 0; i < size; i += 8) s += buf.readDoubleLE(i);
return s;
});
bench("readBigInt64LE", () => {
let s = 0n;
for (let i = 0; i < size; i += 8) s += buf.readBigInt64LE(i);
return s;
});
bench("writeUInt8", () => {
for (let i = 0; i < size; i++) buf.writeUInt8(i & 0xff, i);
});
bench("writeInt16BE", () => {
for (let i = 0; i < size; i += 2) buf.writeInt16BE(i, i);
});
bench("writeInt32LE", () => {
for (let i = 0; i < size; i += 4) buf.writeInt32LE(i, i);
});
bench("writeUInt32BE", () => {
for (let i = 0; i < size; i += 4) buf.writeUInt32BE(i, i);
});
bench("writeFloatLE", () => {
for (let i = 0; i < size; i += 4) buf.writeFloatLE(i + 0.5, i);
});
bench("writeDoubleLE", () => {
for (let i = 0; i < size; i += 8) buf.writeDoubleLE(i + 0.5, i);
});
});

group("one access on each of 1024 buffers", () => {
bench("readInt32LE", () => {
let s = 0;
for (let i = 0; i < many.length; i++) s += many[i].readInt32LE(0);
return s;
});
bench("writeInt32LE", () => {
for (let i = 0; i < many.length; i++) many[i].writeInt32LE(i, 0);
});
bench("readDoubleLE", () => {
let s = 0;
for (let i = 0; i < many.length; i++) s += many[i].readDoubleLE(0);
return s;
});
});

await run();
2 changes: 1 addition & 1 deletion scripts/build/deps/webkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// Windows ICU data table filtered + per-item zstd compressed, and Windows
// unwind info (RtlAddGrowableFunctionTable) registered for the fixed JIT
// pool (LLInt pending offlineasm .seh_* emission).
export const WEBKIT_VERSION = "a40d462206e1caf8388062120acde61e37a4ae7d";
export const WEBKIT_VERSION = "autobuild-preview-pr-330-be77ad70";

Check warning on line 13 in scripts/build/deps/webkit.ts

View check run for this annotation

Claude / Claude Code Review

WEBKIT_VERSION pinned to an ephemeral preview-PR build tag

Reminder: `WEBKIT_VERSION` is pinned to the ephemeral preview tag `autobuild-preview-pr-330-be77ad70` for the not-yet-merged oven-sh/WebKit#330 (the PR description says the WebKit dependency is 'TBD', and commit 77ba5319 confirms it's temporary). Once WebKit#330 merges, this needs to be swapped for the real merged commit hash before landing — `autobuild-preview-*` release artifacts are typically pruned when the underlying PR closes, at which point `prebuiltUrl()` will 404 and `bun bd` will fail

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant version pin and URL construction.
git ls-files 'scripts/build/deps/webkit.ts' 'scripts/build/download.ts'
printf '\n--- scripts/build/deps/webkit.ts ---\n'
cat -n scripts/build/deps/webkit.ts
printf '\n--- scripts/build/download.ts (matching lines) ---\n'
rg -n -C 3 'autobuild-preview|WEBKIT_VERSION|prebuiltUrl|webkit' scripts/build/download.ts scripts/build/deps/webkit.ts

Repository: oven-sh/bun

Length of output: 35006


Do not pin WebKit to a preview release tag
scripts/build/deps/webkit.ts:13 uses autobuild-preview-pr-330-be77ad70, and autobuild-preview-pr-* releases are temporary. Once that PR closes, prebuilt WebKit downloads will 404; pin this to the merged WebKit commit SHA instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/build/deps/webkit.ts` at line 13, Update the WEBKIT_VERSION constant
to use the merged WebKit commit SHA instead of the temporary
autobuild-preview-pr-330-be77ad70 tag, ensuring prebuilt downloads remain
available after the pull request closes.

Source: MCP tools

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.

🟡 Reminder: WEBKIT_VERSION is pinned to the ephemeral preview tag autobuild-preview-pr-330-be77ad70 for the not-yet-merged oven-sh/WebKit#330 (the PR description says the WebKit dependency is 'TBD', and commit 77ba531 confirms it's temporary). Once WebKit#330 merges, this needs to be swapped for the real merged commit hash before landing — autobuild-preview-* release artifacts are typically pruned when the underlying PR closes, at which point prebuiltUrl() will 404 and bun bd will fail for anyone without a cached extraction.

Extended reasoning...

What changed

-export const WEBKIT_VERSION = "a40d462206e1caf8388062120acde61e37a4ae7d";
+export const WEBKIT_VERSION = "autobuild-preview-pr-330-be77ad70";

The stable 40-hex commit hash is replaced with a preview-PR autobuild tag. Commit 77ba531 ("Build against the WebKit preview build for oven-sh/WebKit#330") and the PR description ("depends on the WebKit PR: TBD") both confirm this is intentional temporary scaffolding while the companion WebKit PR (which introduces BufferAccessorRegistry / BufferAccessorIntrinsic) is still open.

How the value is consumed

In scripts/build/deps/webkit.ts:

function prebuiltUrl(cfg: Config): string {
  ...
  const version = cfg.webkitVersion;
  const tag = version.startsWith("autobuild-") ? version : `autobuild-${version}`;
  return `https://github.com/oven-sh/WebKit/releases/download/${tag}/${name}.tar.gz`;
}

and prebuiltDestDir() special-cases the autobuild- prefix for cache keying:

// For 40-hex shas, 16 chars is plenty. For autobuild-preview-* tags, the
// meaningful sha is at the end, so use the whole thing.
const version16 = v.startsWith("autobuild-") ? v.slice("autobuild-".length) : v.slice(0, 16);

The file's own doc comment says the value is "From https://github.com/oven-sh/WebKit releases" — a stable release, which a preview PR tag is not.

Step-by-step: why this can't merge as-is

  1. This PR merges to main with WEBKIT_VERSION = "autobuild-preview-pr-330-be77ad70".
  2. Add DFG/FTL nodes for byte-offset scalar accessors on ArrayBufferView receivers WebKit#330 later merges (or closes); the oven-sh/WebKit release workflow prunes the autobuild-preview-pr-330-* GitHub release, as it does for all preview builds once the PR is no longer open.
  3. A contributor without a cached ~/.bun-cache/webkit-preview-pr-330-be77ad70*/ extraction runs bun bd.
  4. prebuiltUrl(cfg) resolves to https://github.com/oven-sh/WebKit/releases/download/autobuild-preview-pr-330-be77ad70/bun-webkit-<os>-<arch>....tar.gz.
  5. GitHub returns 404; the WebKit dependency fetch fails; the build aborts.

CI and anyone who already downloaded the tarball keep working (the cache-dir extraction is keyed by the full tag), which is what makes this easy to accidentally merge — it only breaks fresh builds after the preview release is deleted.

Why existing code doesn't prevent it

Nothing in scripts/build/deps/webkit.ts distinguishes a stable autobuild-<sha> release from an autobuild-preview-pr-* release beyond cache-key formatting. There's no guard that refuses to pin main to a preview tag; the autobuild- special-casing exists precisely to support this workflow during PR development.

Impact

None until the WebKit preview release is pruned; then every uncached bun bd on main fails at the WebKit download step. This is a build-infrastructure availability issue, not a runtime bug — hence nit (a merge-checklist reminder, not a defect the author is unaware of).

Fix

Once oven-sh/WebKit#330 merges, replace this line with the resulting 40-hex commit hash on oven-sh/WebKit main:

export const WEBKIT_VERSION = "<merged-commit-sha>";

(Per .claude/docs/landing-prs.md — Dependencies & vendoring.)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Correct, and still the plan: the pin is currently the preview for WebKit#330's head (autobuild-preview-pr-330-6d8df126) so this PR's CI can build and test against the real dependency. It gets swapped for the merged commit hash before this lands — noted in the PR description too.


/**
* WebKit (JavaScriptCore) — the JS engine.
Expand Down
3 changes: 0 additions & 3 deletions src/js/builtins.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,6 @@ declare function $controller(): TODO;
declare function $createFIFO(): TODO;
declare function $createUninitializedArrayBuffer(size: number): ArrayBuffer;
declare function $data(): TODO;
declare function $dataView(): TODO;
declare function $decode(): TODO;
declare function $dirname(): TODO;
declare function $disturbed(): TODO;
Expand Down Expand Up @@ -692,8 +691,6 @@ declare function $toClass(fn: Function, name: string, base?: Function | undefine

declare function $min(a: number, b: number): number;

declare function $checkBufferRead(buf: Buffer, offset: number, byteLength: number): undefined;

/**
* Schedules a callback to be invoked as a microtask.
*/
Expand Down
2 changes: 0 additions & 2 deletions src/js/builtins/BunBuiltinNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ using namespace JSC;
macro(byobRequest) \
macro(bytes) \
macro(cancel) \
Comment thread
claude[bot] marked this conversation as resolved.
macro(checkBufferRead) \
macro(checks) \
macro(cloneArrayBuffer) \
macro(close) \
Expand All @@ -74,7 +73,6 @@ using namespace JSC;
macro(createUninitializedArrayBuffer) \
macro(ctimeMs) \
macro(data) \
macro(dataView) \
macro(decode) \
macro(dest) \
macro(dirname) \
Expand Down
Loading