BridgeJS: Optimize numeric array transfer with bulk TypedArray copy by krodak · Pull Request #745 · swiftwasm/JavaScriptKit
Overview
Optimize numeric array transfer by using bulk TypedArray memory copy instead of element-by-element stack serialization. When a Swift function passes or receives a numeric array ([Int], [UInt8], [Float], [Double], etc.), BridgeJS now transfers the data as a single bulk operation. TypeScript types remain number[] / bigint[] — no user-facing API change.
This is a transparent performance optimization following the same pattern as bridgeJSStackPopAsOptional — a specialized ABI for numeric element types without changing the type contract. Non-numeric arrays ([String], [MyStruct], etc.) continue using the existing element-by-element stack protocol.
1. Swift → JS direction: Array.bridgeJSTypedArrayPush() calls withUnsafeBufferPointer to pass (ptr, count, kind) to a new swift_js_push_typed_array WASM import, which copies the bytes into a JS TypedArray. A pre-allocated for-loop then converts to number[] for the caller.
2. JS → Swift direction: [T].bridgeJSTypedArrayLiftParameter(sourceId, count) receives a retained TypedArray from JS, allocates via Array(unsafeUninitializedCapacity:), and calls back to JS via swift_js_init_typed_array_memory to bulk copy — the same retain-allocate-callback pattern used by string lowering.
3. Affected types: All integer types (Int8 through Int64, signed and unsigned), Float, Double, plus pointer-width Int/UInt. A new _BridgeJSTypedArrayElement protocol marks eligible types. BridgeType.isNumericScalar and typedArrayKind on the skeleton side route the codegen.
Benchmark results
Release build, 10K iterations × 5 runs:
| Test | Before | After | Speedup |
|---|---|---|---|
| takeIntArray (1K, JS→Swift) | 758 ms | 13 ms | 58× |
| takeDoubleArray (1K, JS→Swift) | 791 ms | 13 ms | 61× |
| makeIntArray (1K, Swift→JS) | 221 ms | 18 ms | 12× |
| makeIntArrayLarge (10K, Swift→JS) | 2160 ms | 146 ms | 15× |
| roundtripIntArray (1K) | 964 ms | 29 ms | 33× |
| takeStringArray (non-numeric) | 23 ms | 25 ms | unchanged |