Skip to content

BridgeJS: Optimize numeric array transfer with bulk TypedArray copy#8

Closed
krodak wants to merge 1 commit into
mainfrom
krodak/typed-array
Closed

BridgeJS: Optimize numeric array transfer with bulk TypedArray copy#8
krodak wants to merge 1 commit into
mainfrom
krodak/typed-array

Conversation

@krodak
Copy link
Copy Markdown
Collaborator

@krodak krodak commented May 12, 2026

Overview

Use bulk TypedArray memory copy instead of element-by-element stack serialization for numeric arrays ([Int], [UInt8], [Float], [Double], etc.). TypeScript types remain number[] / bigint[]no user-facing API change.

This is a transparent performance optimization following the same pattern as bridgeJSStackPopAsOptional — the ABI changes internally but the type contract is unchanged.

How it works

Swift → JS (return values): Array.bridgeJSTypedArrayPush() calls withUnsafeBufferPointerswift_js_push_typed_array(ptr, count, kind) → JS copies bytes into a TypedArray → pre-allocated for-loop converts to number[].

JS → Swift (parameters): [T].bridgeJSTypedArrayLiftParameter(sourceId, count) receives a retained TypedArray from JS → allocates via Array(unsafeUninitializedCapacity:) → calls back to JS via swift_js_init_typed_array_memory to bulk copy.

Non-numeric arrays ([String], [MyStruct], etc.) continue using the existing element-by-element stack protocol.

What changed

  • BridgeJSSkeleton.swiftisNumericScalar and typedArrayKind helpers on BridgeType
  • BridgeJSIntrinsics.swift_BridgeJSTypedArrayElement protocol with 12 numeric conformances, extension Array where Element: _BridgeJSTypedArrayElement with bridgeJSTypedArrayPush() and bridgeJSTypedArrayLiftParameter(_:_:), WASM externs for swift_js_push_typed_array and swift_js_init_typed_array_memory
  • JSGlueGen.swiftnumericArrayLift, numericArrayLower, numericArrayLowerReturn JS fragment generators; routing to detect numeric arrays
  • BridgeJSLink.swifttaStack, typedArrayConstructors, swift_js_push_typed_array, swift_js_init_typed_array_memory handlers
  • ExportSwift.swift — Numeric array params use [T].bridgeJSTypedArrayLiftParameter(sourceId, count); returns use ret.bridgeJSTypedArrayPush()
  • ImportTS.swift — Same pattern for imported function params/returns
  • ClosureCodegen.swift — Numeric array closure params use bulk path

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×
makeDoubleArray (1K, Swift→JS) 271 ms 36 ms 7.5×
roundtripIntArray (1K) 964 ms 29 ms 33×
roundtripDoubleArray (1K) 1065 ms 29 ms 37×
takeStringArray (non-numeric) 23 ms 25 ms unchanged

Follow-up

For users who want actual Uint8Array / Float32Array in their JS API (e.g., for fetch body, WebGPU), see PR #9 which adds JSTypedArray<T> as a recognized BridgeJS type.

Use bulk TypedArray memory copy instead of element-by-element stack
serialization for numeric arrays ([Int], [UInt8], [Float], [Double],
etc.). TypeScript types remain number[]/bigint[] — no API change.

Swift->JS: Array.bridgeJSTypedArrayPush() passes (ptr, count, kind)
to swift_js_push_typed_array which copies into a JS TypedArray, then
a for-loop converts to number[] for the caller.

JS->Swift: Array.bridgeJSTypedArrayLiftParameter(id, count) receives
a retained TypedArray ID, allocates via unsafeUninitializedCapacity,
and calls swift_js_init_typed_array_memory to bulk copy.

Non-numeric arrays (String, structs, classes, enums) are unaffected.
@krodak krodak force-pushed the krodak/typed-array branch from 84dd885 to 16d3b1e Compare May 13, 2026 08:44
@krodak krodak changed the title BridgeJS: Add opt-in TypedArray bridging for numeric arrays BridgeJS: Optimize numeric array transfer with bulk TypedArray copy May 13, 2026
@krodak
Copy link
Copy Markdown
Collaborator Author

krodak commented May 13, 2026

Tracked in new PR against main repo

@krodak krodak closed this May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant