perf: reduce per-call overhead in gin_helper hot paths#51614
Merged
MarshallOfSound merged 1 commit intoMay 13, 2026
Conversation
Several gin_helper code paths run on every native event emit, every IPC message, every option-dictionary parse, and every C++ -> JS callback. This change removes a handful of avoidable per-call costs from those paths. EmitEvent / CallMethodWithArgs: - Internalize the event name and the "emit" method name with gin::StringToSymbol so V8 dedupes them against its string table and property lookups can compare by pointer identity instead of hashing a fresh kNormal string on every emit. - Reuse the emitter object as the node::CallbackScope async resource instead of allocating a throwaway v8::Object per emit. - Drop the redundant inner EscapableHandleScope; EmitEvent / CustomEmit already open one immediately around the call. gin_helper::Dictionary: - Internalize property keys via gin::StringToSymbol (matching what gin::DataObjectBuilder and gin::ObjectTemplateBuilder already do). - Replace the unconditional Has() + Get() pair in Get() with a single GetRealNamedProperty() lookup — one V8 boundary crossing per key instead of two, with the same missing-vs-undefined disambiguation. Native interceptor objects (process.env, etc.) are detected with the zero-cost HasNamedLookupInterceptor() hidden-class flag and routed to the Has()/Get() path that drives the interceptor. gin_helper::Locker: - Store v8::Locker inline in std::optional instead of heap-allocating it per construction; this is on the path of every C++ -> JS callback. blink converters: - char16_t::FromV8: read the UTF-16 code unit directly instead of round-tripping V8's internal UTF-16 through UTF-8 and back. Microbenchmark medians (Linux x86-64 testing build): EmitEvent (1 listener) 2806 ns -> 1816 ns (-35%) EmitEvent (no listeners) 2788 ns -> 1800 ns (-35%) Dictionary::Get (per key, all hit) 82.2 ns -> 26.9 ns (-67%) Dictionary::Get (per key, all miss) 55.6 ns -> 18.5 ns (-67%) Dictionary::Set (per key) 121 ns -> 82.6 ns (-32%) gin_helper::Locker ctor/dtor 94.3 ns -> 9.85 ns (-90%) C++ -> JS callback (RepeatingCb) 463 ns -> 301 ns (-35%) Co-authored-by: Sam Attard <sattard@anthropic.com>
5 tasks
MarshallOfSound
approved these changes
May 13, 2026
|
Release Notes Persisted
|
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.
Backport of #51596
See that PR for details.
Notes: Improved performance of native event emission, IPC dispatch, and option-dictionary parsing.