Skip to content

lib: short-circuit WebIDL BufferSource SAB check#62833

Open
panva wants to merge 2 commits intonodejs:mainfrom
panva:fast-buffersource
Open

lib: short-circuit WebIDL BufferSource SAB check#62833
panva wants to merge 2 commits intonodejs:mainfrom
panva:fast-buffersource

Conversation

@panva
Copy link
Copy Markdown
Member

@panva panva commented Apr 19, 2026

Avoid the C++ isSharedArrayBuffer binding call on the BufferSource and ArrayBufferView converter hot path by first checking whether the buffer's prototype chain contains ArrayBuffer.prototype. Every genuine (non-shared) ArrayBuffer is covered by the fast path; SharedArrayBuffers and prototype-tampered objects still fall through to the authoritative brand-checking binding, preserving the existing SharedArrayBuffer rejection semantics.

While here, dispatch the view-kind (TypedArray vs DataView) from the primordial %TypedArray%.prototype.@@toStringTag getter directly, dropping the redundant ArrayBufferIsView check that isDataView would repeat at each call site.


                                                    before ops/sec    after ops/sec    speedup
input="arraybuffer"                                     16,889,535       16,890,841      equal
input="buffer"                                          14,935,801      125,791,768      8.42x
input="dataview"                                        16,317,802      177,117,590     10.85x
input="uint8array"                                      15,414,470      125,996,487      8.17x
input="uint8clampedarray"                               14,872,961      124,526,604      8.37x
input="int8array"                                       15,157,350      124,766,713      8.23x
input="uint16array"                                     15,090,143      123,827,379      8.21x
input="int16array"                                      14,903,084      120,681,548      8.10x
input="uint32array"                                     14,646,015      120,610,045      8.23x
input="int32array"                                      14,516,087      120,635,143      8.31x
input="float16array"                                    15,233,858      120,150,187      7.89x
input="float32array"                                    15,345,072      124,486,881      8.11x
input="float64array"                                    14,764,074      122,339,186      8.29x
input="bigint64array"                                   15,217,740      125,704,732      8.26x
input="biguint64array"                                  15,027,624      125,533,190      8.35x

Avoid the C++ `isSharedArrayBuffer` binding call on the BufferSource
and ArrayBufferView converter hot path by first checking whether the
buffer's prototype chain contains `ArrayBuffer.prototype`. Every
genuine (non-shared) ArrayBuffer is covered by the fast path;
SharedArrayBuffers and prototype-tampered objects still fall through to
the authoritative brand-checking binding, preserving the existing
SharedArrayBuffer rejection semantics.

While here, dispatch the view-kind (TypedArray vs DataView) from the
primordial `%TypedArray%.prototype.@@toStringTag` getter directly,
dropping the redundant `ArrayBufferIsView` check that `isDataView`
would repeat at each call site.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
@nodejs-github-bot
Copy link
Copy Markdown
Collaborator

nodejs-github-bot commented Apr 19, 2026

Review requested:

  • @nodejs/performance
  • @nodejs/web-standards

@nodejs-github-bot nodejs-github-bot added the needs-ci PRs that need a full CI run. label Apr 19, 2026
@panva panva added the web-standards Issues and PRs related to Web APIs label Apr 19, 2026
Copy link
Copy Markdown
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

lgtm

@panva panva added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. request-ci Add this label to start a Jenkins CI on a PR. labels Apr 19, 2026
Comment thread lib/internal/webidl.js Outdated
@panva panva removed request-ci Add this label to start a Jenkins CI on a PR. author ready PRs that have at least one approval, no pending requests for changes, and a CI started. labels Apr 19, 2026
Comment thread lib/internal/webidl.js
// `ArrayBuffer`; only buffers whose prototype chain has been detached or
// reassigned (and real SABs) fall through to the authoritative brand check.
function isSharedArrayBufferBacking(buffer) {
return !ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, buffer) &&
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Theoretically non-compliant for Object.setPrototypeOf(new SharedArrayBuffer(), ArrayBuffer.prototype) – would presumably be a fairly useless object, I don't know how much we need to care about that sort of thing.

Copy link
Copy Markdown
Member Author

@panva panva Apr 19, 2026

Choose a reason for hiding this comment

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

Good catch, I don't think I have a way of dealing with that. 🤷 nor do I have an opinion on caring about it. What do others think?

Copy link
Copy Markdown
Contributor

@MattiasBuelens MattiasBuelens Apr 20, 2026

Choose a reason for hiding this comment

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

This function is only ever used on buffers returned by getViewedArrayBuffer, right? Since that function uses the primordial .buffer getters which already perform brand checks on the ArrayBufferView, I don't think we can get a forged array buffer here. Unless you first did Object.setPrototypeOf(view.buffer, ArrayBuffer.prototype)? Is that allowed, and does that persist on view.buffer? 🤔

Alternatively, we could call the getter of a property on SharedArrayBuffer.prototype and check if it throws or not, see webidl2js. I don't know if that's faster than calling into C++ though.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.61%. Comparing base (a79e224) to head (5ee831f).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #62833      +/-   ##
==========================================
- Coverage   89.64%   89.61%   -0.03%     
==========================================
  Files         706      706              
  Lines      219024   219147     +123     
  Branches    41960    41980      +20     
==========================================
+ Hits       196338   196384      +46     
- Misses      14587    14656      +69     
- Partials     8099     8107       +8     
Files with missing lines Coverage Δ
lib/internal/webidl.js 96.71% <100.00%> (+0.08%) ⬆️

... and 37 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

Labels

needs-ci PRs that need a full CI run. web-standards Issues and PRs related to Web APIs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants