-
Notifications
You must be signed in to change notification settings - Fork 5k
Make Buffer read*/write* native functions with a DFG/FTL intrinsic #35343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 7 commits
9bb8897
4383835
9bc68f3
922d63b
2800801
f289a67
77ba531
c404098
1fc5e56
af34232
9bb5bd7
c24eaa7
e702b53
6382eeb
7957227
7d218bf
28491a1
357582d
d807f2d
c56e904
50bab58
f871414
4e3ea85
9ce177c
ea0cf81
2a8c837
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Reminder: 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 How the value is consumedIn 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 // 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
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 itNothing in ImpactNone until the WebKit preview release is pruned; then every uncached FixOnce oven-sh/WebKit#330 merges, replace this line with the resulting 40-hex commit hash on oven-sh/WebKit export const WEBKIT_VERSION = "<merged-commit-sha>";(Per
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 ( |
||
|
|
||
| /** | ||
| * WebKit (JavaScriptCore) — the JS engine. | ||
|
|
||
There was a problem hiding this comment.
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:
Repository: oven-sh/bun
Length of output: 35006
Do not pin WebKit to a preview release tag
scripts/build/deps/webkit.ts:13usesautobuild-preview-pr-330-be77ad70, andautobuild-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
Source: MCP tools