perf: skip optional argument fallback for fixed-arity HybridFunctions - #1586
Open
mrousavy wants to merge 1 commit into
Open
perf: skip optional argument fallback for fixed-arity HybridFunctions#1586mrousavy wants to merge 1 commit into
mrousavy wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
mrousavy
marked this pull request as ready for review
September 4, 2026 10:41
mrousavy
force-pushed
the
perf/required-argument-fast-path
branch
from
September 5, 2026 12:19
98fe667 to
e205c55
Compare
Performance Report
iOS
All Benchmarks
Android
All Benchmarks
Benchmarking Code Diff |
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.
Summary
Avoid instantiating
callMethod()'s static undefined fallback when a HybridFunction signature has no trailing optional arguments.The argument count is already validated before entering
callMethod(). Anif constexprnow usesargs[Is]directly for fixed-arity signatures, including zero-argument functions and signatures with non-trailing optionals. Signatures with trailing optional arguments retain the existing undefined fallback. A local invocation lambda shares the existing void/non-void return conversion without duplicating it.No receiver binding, JNI, virtual dispatch, public API, codegen, argument-count validation, or JSI type-checking changes.
Why
Previously, even required-only calls declared
static const jsi::Value defaultValue. Its initialization/lifetime guard survived optimized compilation despite the fallback never being needed on that path. Moving the declaration into the optional-only compile-time branch removes that guard and its initialization/exit-destructor registration code from fixed-arity instantiations. Simply making the value automatic would introduce a per-call JSI destructor instead.Regression coverage
Add eight cases to the existing native test suite (each runs against C++ and Swift/Kotlin):
undefinedand an incorrect type for required numbers.undefinedfor a trailing optional.Existing cases cover successful required calls, void methods, omitted/provided optionals, multiple trailing optionals, and explicit undefined in the middle of an argument list.
Validation
bun run build, Node 24.16.0 / Bun 1.3.14).git diff --check.HybridFunction::createHybridFunctioninstantiations using NDK 29.0.14206865, React Native 0.85.3 headers, C++20,-O2 -DNDEBUG: the default-value guard exists before the change for(double, double) -> doubleand() -> void, and is absent afterward. The(double, optional<double>) -> doublefallback and guard remain.:app:assembleDebug).minSdk 26matching the CI harness configuration).The initial local minSdk 24 harness run passed 545/554 tests; the nine failures were HardwareBuffer cases whose native implementation requires a compile-time minSdk of at least 26. Rebuilding with the existing CI harness's minSdk 26 configuration passed all 554. The temporary build-configuration edit was reverted and is not part of this PR.
This PR claims removal of verified generated-code overhead, not a newly measured end-to-end percentage speedup. The earlier benchmark experiment motivated this fix but is not a timing measurement of this exact patch.
In the current Android compiler output, the required scalar path loses the four guard instructions (
adrp,add,ldarb,tbz). The exact argument-count check, both checkedasNumber()calls, and the virtual member invocation remain. These are assembly observations, not cycle counts or timings.