Stack-allocate trivial value_object/value_array argument temporaries - #27610
Draft
dimokol wants to merge 1 commit into
Draft
Stack-allocate trivial value_object/value_array argument temporaries#27610dimokol wants to merge 1 commit into
dimokol wants to merge 1 commit into
Conversation
When a value type is trivially constructible and destructible (and
alignof(T) <= STACK_ALIGN), its argument temporaries no longer
round-trip through new T() plus destructor bookkeeping. The
registration passes sizeof(T) and a triviality flag; toWireType places
the temporary on the wasm stack when the invoker brackets the call in
stackSave/stackRestore (a null destructors argument is that contract),
zero-filled so unregistered fields and padding match the heap path's
value-initialization. The bracket is a try/finally, so a throwing
argument conversion or callee cannot leak stack. Callers that defer
destruction (emval returns, property setters) keep the heap path, as
do Asyncify builds and JSPI-async invokers, which outlive the frame.
Field and element writes skip their per-write destructors array when
the element type registers no destructor, the dominant source of
per-call garbage in large modules. The AOT generator mirrors the type
shape so invoker signatures stay in sync ('s' kind), and libsigs.js is
regenerated for the new registration parameters.
Note the registration arity change means objects built against an
older bind.h need a rebuild.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses the argument-marshaling side of #27553.
When a value type is trivially constructible and destructible and does not require over-alignment (alignof(T) <= STACK_ALIGN), its argument temporaries no longer round-trip through
new T()plus destructor bookkeeping. The registration passessizeof(T)and a triviality flag;toWireTypeplaces the temporary on the wasm stack when the invoker brackets the call instackSave/stackRestore(a nulldestructorsargument is that contract), zero-filled so unregistered fields and padding match the heap path's value-initialization. The bracket restores the frame in afinally, so a throwing argument conversion or callee cannot leak stack. Over-aligned types keep the heap path, as do callers that defer destruction (emval returns, property setters), Asyncify builds, and JSPI-async invokers, which outlive the frame. Field/element writes skip their per-write destructors array when the element type registers no destructor, which turns out to be the dominant source of per-call garbage in large modules (V8 sinks those arrays in small benchmarks but not at scale). The AOT generator mirrors the type shape so invoker signatures stay in sync, andlibsigs.jsis regenerated for the new registration parameters.Measured on box3d.js (a real embind physics binding) rebuilt with this branch, forced-GC heapUsed deltas, median over 9 rounds of 20k calls:
A stock rebuild with an unpatched toolchain reproduces the before column exactly. The remaining nonzeros are value-type returns, which still materialize fresh objects by design and are out of scope here.
other.test_embind,other.test_embind_aot_js, andother.test_embind_no_dynamicpass locally.Draft because two things are still missing and I'd like direction before writing them: dedicated tests for the new behavior (a trivial POD value type exercising the stack path, plus an allocation regression check if that fits the suite), and the ChangeLog entry. Note the registration arity change means objects built against an older
bind.hneed a rebuild.