Files
electron/shell/services/node
Samuel Attard 6fd69709f7 perf: dispatch gin_helper-bound methods without a callback object or a per-call liveness probe (#54331)
* perf: dispatch gin_helper-bound methods and accessors to a target named at compile time

CreateFunctionTemplate stores a base::RepeatingCallback in a heap-allocated
holder, hands V8 an External pointing at it, and on every call unwraps the
External, runs the callback through two indirect calls and holds a
reference on its bind state for the duration. For a plain function or
member function none of that is needed: SetMethod<&T::Method>(name) and
SetProperty<&T::Getter[, &T::Setter]>(name) instantiate a V8 callback that
calls the target directly, with the same argument conversion, destroyed
check, microtasks scope and error messages as before.

Converts every call site on gin_helper::ObjectTemplateBuilder and
gin_helper::Dictionary whose target is a plain function or member
function. Classes built through gin::ObjectTemplateBuilder keep the
callback path until gin grows the same overload upstream.

* perf: only ask whether the receiver is destroyed once it has failed to convert

Every bound call checked Destroyable::IsDestroyed on the holder before
converting it, and for cppgc wrappers that check cannot short-circuit on
an internal field, so it unwrapped the object through a TLS isolate
lookup on every call. The check never guards the call itself: a destroyed
gin_helper wrapper has a null internal field and an inert cppgc wrapper
unwraps to null, so both already fail the receiver conversion and throw.
All it decides is whether the error says 'Object has been destroyed' or
'Illegal invocation'. Make that decision in ThrowConversionError, after
the conversion has failed, so a successful call pays nothing for it.

This relies on every receiver converter on main being null-safe, which
has held since the deprecated wrappable path was removed in #53758.

* refactor: share the direct dispatcher's conversion code per signature

Split the compile-time dispatcher the way the gin change does it:
SignatureDispatcher<Target> converts the arguments (receiver included, as
the first argument, for a member function) and calls through a Target
passed at run time, and DirectDispatcher<kTarget> is the V8 callback, a
thunk that hands it kTarget. Targets of the same signature share one
converter; the receiver goes through the same ArgumentHolder path as the
callback form, so there is one place that decides the error message.
CreateDirectFunctionTemplate<kTarget> becomes an overload of
CreateFunctionTemplate<kTarget>, matching gin.
2026-09-25 00:21:07 -07:00
..