Skip to content

[embind] Generate value type element writers per type - #27751

Open
dimokol wants to merge 1 commit into
emscripten-core:mainfrom
dimokol:embind-value-array-writes
Open

dimokol wants to merge 1 commit into
emscripten-core:mainfrom
dimokol:embind-value-array-writes

Conversation

@dimokol

@dimokol dimokol commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #27610. On box3d.js (about forty value types, node v24, -O3) every value_object or value_array argument with non-integer float fields still cost 16 B of garbage per element: b3Body_SetTransform with real floats measured 80 B/call, ApplyForce 96, while the same calls with integer values measured 0. The element writes went through one closure literal shared by every value type, so its setter call site was megamorphic and V8 stopped inlining the JS-to-wasm call, boxing each double.

With DYNAMIC_EXECUTION the element write step is now generated per value type, one call per element, each site monomorphic, and in non-ASSERTIONS builds number types pass straight through without the identity toWireType call. Without DYNAMIC_EXECUTION the path is unchanged. value_object writes keep the field table's enumeration order and last-registration-wins for a repeated name, with a test for both paths. In the same measurement the float setter rows above go to 0 B/call. Timings also dropped in that run (SetTransform 904 ns to 589 ns, GetPosition 378 ns to 182 ns), taken on a loaded machine, so treat them as indicative. The two identityToWireType flags add 10 bytes to the embind codesize baselines.

No allocation regression test is added: whether the boxing happens depends on V8 tiering and on how many value types a module registers, so it isn't stable in a unit test. The numbers come from forced-GC heapUsed deltas over 20k-call rounds after a 300k-call warmup, with GC events inside the windows checked; happy to share the probe. On the preceding revision, I ran 105 test_other and 92 core0/core2 embind tests; the only failures also reproduced on main (test_embind_resource_management needs node 25, and the *_emscripten exception variants need -femscripten-exceptions, which my installed LLVM lacks). On this revision, all 13 targeted checks passed, including the new field-order regression in both modes, Closure, AOT and code-size checks.

@dimokol
dimokol force-pushed the embind-value-array-writes branch from 62cef9e to 805b45d Compare September 19, 2026 09:59
Under DYNAMIC_EXECUTION, build one write function per value_object and
value_array so each element's wasm setter gets its own call site. The
shared per-element closure made that site megamorphic in modules with
many value types, and V8 then boxed every non-integer double on the way
in. Number types with an identity conversion are passed straight through.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant