feat(ffi): expand native call capabilities - #1034
Conversation
Support mixed f32 signatures, high-arity and variadic calls, collision-safe aggregate metadata, and nullable UTF-8 arguments.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📝 WalkthroughWalkthroughAdds explicit nullable UTF-8 and variadic FFI descriptors, raises supported arity to 64, expands ABI planning for mixed and variadic arguments, exposes aggregate metadata access, and adds native fixtures, tests, ADR documentation, and validation messages. ChangesFFI descriptor contracts
ABI and invocation
Fixtures and documentation
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant JavaScript
participant FFILibrary
participant BoundFunction
participant ABIPlanner
participant NativeFunction
JavaScript->>FFILibrary: bind variadic signature
FFILibrary->>BoundFunction: create bound function
JavaScript->>BoundFunction: invoke with FFI.varargs
BoundFunction->>ABIPlanner: promote and compile call layout
BoundFunction->>NativeFunction: marshal and invoke arguments
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
Web Tooling Benchmark
18 pinned Web Tooling workloads; 18 workloads produced at least one Goccia sample. Raw results from 1 sample per workload; full stdout/stderr for failures and min/max/CV stay in the |
Suite TimingTest Runner (interpreted: 11,565 passed; bytecode: 11,565 passed)
MemoryGC rows aggregate the main thread plus all worker thread-local GCs. Test runner worker shutdown frees thread-local heaps in bulk; that shutdown reclamation is not counted as GC collections or collected objects.
Benchmarks (interpreted: 439; bytecode: 439)
MemoryGC rows aggregate the main thread plus all worker thread-local GCs. Benchmark runner performs explicit between-file collections, so collection and collected-object counts can be much higher than the test runner.
Boot
Empty-script ( Measured on ubuntu-latest x64. |
Benchmark Results439 benchmarks · PR vs same-runner Interpreted: 🟢 59 improved · 🔴 43 regressed · 337 unchanged · avg +0.4% Typical per-run noise (median variance): interpreted ±1.9%, bytecode ±1.3%. Deltas within noise overlap and read as unchanged. arraybuffer.js — Interp: 14 unch. · avg +1.3% · Bytecode: 14 unch. · avg +0.8%
arrays.js — Interp: 🟢 2, 17 unch. · avg +2.0% · Bytecode: 🔴 3, 16 unch. · avg -0.7%
async-await.js — Interp: 6 unch. · avg +0.8% · Bytecode: 6 unch. · avg +2.5%
async-generators.js — Interp: 2 unch. · avg +9.5% · Bytecode: 2 unch. · avg +0.5%
atomics.js — Interp: 6 unch. · avg +0.7% · Bytecode: 🟢 1, 🔴 1, 4 unch. · avg -0.0%
base64.js — Interp: 🟢 1, 9 unch. · avg +0.7% · Bytecode: 🟢 1, 9 unch. · avg +0.1%
classes.js — Interp: 🟢 3, 🔴 2, 26 unch. · avg +0.5% · Bytecode: 🟢 1, 30 unch. · avg +0.2%
closures.js — Interp: 🟢 1, 10 unch. · avg -0.5% · Bytecode: 🟢 1, 🔴 1, 9 unch. · avg -0.3%
collections.js — Interp: 🟢 3, 9 unch. · avg +0.9% · Bytecode: 🔴 2, 10 unch. · avg -1.1%
csv.js — Interp: 13 unch. · avg -0.0% · Bytecode: 🟢 1, 12 unch. · avg -0.4%
destructuring.js — Interp: 🟢 1, 🔴 1, 20 unch. · avg +0.4% · Bytecode: 🟢 1, 🔴 3, 18 unch. · avg +0.3%
fibonacci.js — Interp: 8 unch. · avg -0.8% · Bytecode: 🔴 1, 7 unch. · avg -1.4%
float16array.js — Interp: 🟢 6, 🔴 4, 22 unch. · avg -1.3% · Bytecode: 🟢 1, 🔴 1, 30 unch. · avg -0.3%
for-in/for-in.js — Interp: 3 unch. · avg +0.7% · Bytecode: 🔴 1, 2 unch. · avg +0.3%
for-of.js — Interp: 7 unch. · avg +3.3% · Bytecode: 7 unch. · avg +5.9%
generators.js — Interp: 4 unch. · avg +1.2% · Bytecode: 🟢 1, 3 unch. · avg +1.8%
intl.js — Interp: 🔴 2, 4 unch. · avg -4.5% · Bytecode: 🔴 2, 4 unch. · avg -2.9%
iterators.js — Interp: 🟢 17, 25 unch. · avg +4.5% · Bytecode: 🟢 7, 🔴 3, 32 unch. · avg +1.5%
json.js — Interp: 🟢 1, 🔴 5, 17 unch. · avg -2.9% · Bytecode: 🟢 5, 🔴 2, 16 unch. · avg +2.1%
jsx.jsx — Interp: 🟢 3, 18 unch. · avg +1.8% · Bytecode: 🟢 2, 🔴 6, 13 unch. · avg -2.1%
modules.js — Interp: 9 unch. · avg -1.4% · Bytecode: 🟢 1, 8 unch. · avg +2.2%
numbers.js — Interp: 🟢 2, 🔴 2, 8 unch. · avg +0.0% · Bytecode: 🟢 2, 10 unch. · avg +0.5%
objects.js — Interp: 🟢 2, 🔴 1, 4 unch. · avg +3.7% · Bytecode: 🔴 1, 6 unch. · avg +1.5%
promises.js — Interp: 🔴 1, 11 unch. · avg -0.4% · Bytecode: 🟢 1, 🔴 1, 10 unch. · avg +2.8%
property-access.js — Interp: 🟢 1, 4 unch. · avg +2.3% · Bytecode: 5 unch. · avg +1.1%
regexp.js — Interp: 🟢 1, 🔴 4, 8 unch. · avg -0.1% · Bytecode: 13 unch. · avg +1.4%
strings.js — Interp: 🟢 1, 🔴 4, 14 unch. · avg -0.3% · Bytecode: 🟢 6, 13 unch. · avg +2.6%
temporal.js — Interp: 🔴 1, 5 unch. · avg -0.1% · Bytecode: 6 unch. · avg +1.2%
tsv.js — Interp: 🟢 5, 4 unch. · avg +10.5% · Bytecode: 🟢 2, 7 unch. · avg +0.6%
typed-arrays.js — Interp: 🟢 2, 🔴 12, 8 unch. · avg -14.0% · Bytecode: 🟢 4, 🔴 6, 12 unch. · avg -0.9%
uint8array-encoding.js — Interp: 🟢 5, 🔴 2, 11 unch. · avg +10.7% · Bytecode: 🟢 6, 🔴 3, 9 unch. · avg +36.1%
weak-collections.js — Interp: 🟢 2, 🔴 2, 11 unch. · avg -2.5% · Bytecode: 🟢 3, 🔴 3, 9 unch. · avg +4.8%
Deterministic profile diffDeterministic profile diff: no significant changes. Measured on ubuntu-latest x64. Each PR run also builds the |
JetStream 3 Performance Barometer
Geomean reference ratio: QuickJS 27.66×; Node.js 305.64×. 1.00× means aligned; values above 1.00× mean Goccia was proportionally slower after normalizing JetStream’s higher-is-better score. This is a directional barometer across runtimes with different goals, not a product ranking. Raw samples and failure details remain in the |
test262 Conformance
Areas closest to 100%
Per-test deltas (+0 / -0 / timeout +0 / -6)Resolved timeouts (6):
Steady-state failures and timeouts are non-blocking; PASS → non-timeout failure transitions fail the conformance gate. Measured on ubuntu-latest x64, bytecode mode. Areas grouped by the first two test262 path components; minimum 25 attempted tests, areas already at 100% excluded. Δ vs main compares against the most recent cached |
AWFY Results
Geomean Ratios
14 pinned AWFY benchmarks. Medians from 5 interleaved samples per engine; raw JSON includes min/max/CV and is attached as the |
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/built-ins-ffi.md`:
- Around line 81-95: The nullable UTF-8 documentation must state that non-null
arguments use temporary NUL-terminated buffers valid only for the duration of
the native call, and that native code must not retain the pointer afterward.
Update the nullable UTF-8 section in docs/built-ins-ffi.md (lines 81-95) and the
corresponding ownership/lifetime contract in
docs/adr/0102-explicit-bounded-ffi-call-descriptors.md (lines 24-29).
In `@tests/built-ins/FFI/prototype/variadic.js`:
- Around line 95-110: Extend the test named “bounds the combined fixed and
variadic argument count” to verify the accepted 64-argument boundary: invoke sum
with one fixed argument and 63 variadic i32 values, and assert it succeeds with
the expected result. Keep the existing 65-total-argument RangeError assertion to
preserve rejection coverage.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 74194f9e-cf9b-411c-b89c-f72d7915ff20
📒 Files selected for processing (17)
docs/adr/0102-explicit-bounded-ffi-call-descriptors.mddocs/adr/README.mddocs/built-ins-ffi.mdfixtures/ffi/fixture.csource/units/Goccia.Builtins.GlobalFFI.passource/units/Goccia.Error.Messages.passource/units/Goccia.FFI.ABI.Test.passource/units/Goccia.FFI.ABI.passource/units/Goccia.FFI.Types.passource/units/Goccia.Values.FFILibrary.passource/units/Goccia.Values.FFIType.pastests/built-ins/FFI/ffi-v2-callback.jstests/built-ins/FFI/ffi-v2-types.jstests/built-ins/FFI/prototype/arity.jstests/built-ins/FFI/prototype/bind.jstests/built-ins/FFI/prototype/mixed.jstests/built-ins/FFI/prototype/variadic.js
Summary
f32arguments and a defensible 64-argument bound for calls and reverse callbacks, including a nine-argumentDrawBillboardPro-shaped fixture.{ variadic: true }plus oneFFI.varargs(types, values)tail, with pre-entry validation, C default promotions, Windows x64 register mirroring, and Darwin ARM64 variadic stack placement. Variadic callbacks remain unsupported.FFI.nullable("utf8string")for strict borrowed UTF-8-or-NULLinputs using call-scoped temporary storage, while preserving plainutf8stringcoercion behavior.bufferandbyteOffset, and expose collision-free backing information throughFFI.metadata(value).Closes #1029
Closes #1030
Closes #1031
Closes #1032
Closes #1033
Testing
Validation run locally on Darwin ARM64 with FPC 3.2.2:
./build/GocciaTestRunner tests/built-ins/FFI— 106/106 tests, 382 assertions./build/GocciaTestRunner tests/built-ins/FFI --mode=bytecode— 106/106 tests, 382 assertions./build/GocciaTestRunner tests --silent --no-progress— 11,565/11,565 tests, 25,879 assertions./build/GocciaTestRunner tests --mode=bytecode --silent --no-progress— 11,565/11,565 tests, 25,879 assertions./build/Goccia.FFI.ABI.Test— 4/4 tests covering all five planner models./build.pas testsplus all 61build/Goccia.*.Testbinaries — passed./format.pas --check— 430 files formattedbun run scripts/check-test-structure.ts— 1,440 JavaScript test files checkedcc -std=c11 -Wall -Wextra -Werror -fsyntax-only fixtures/ffi/fixture.c— passedThe local native FFI executions cover Darwin ARM64. The host-neutral Pascal regression constructs and verifies SysV x64, Win64, AAPCS64, Darwin ARM64, and i386 Windows plans; compiler-generated Darwin ARM64 and Win64 probe call sites were also compared during self-review. The PR workflow executes Ubuntu x64, while the repository's main CI matrix remains the build authority for x86_64 Darwin, AArch64 Linux, Win64, and i386 Windows.