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

@krodakkrodak commented May 12, 2026

Copy link
Copy Markdown
Collaborator

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:

TestBeforeAfterSpeedup
takeIntArray (1K, JS→Swift)758 ms13 ms58×
takeDoubleArray (1K, JS→Swift)791 ms13 ms61×
makeIntArray (1K, Swift→JS)221 ms18 ms12×
makeIntArrayLarge (10K, Swift→JS)2160 ms146 ms15×
makeDoubleArray (1K, Swift→JS)271 ms36 ms7.5×
roundtripIntArray (1K)964 ms29 ms33×
roundtripDoubleArray (1K)1065 ms29 ms37×
takeStringArray (non-numeric)23 ms25 msunchanged

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
krodakforce-pushed the krodak/typed-array branch from 84dd885 to 16d3b1eCompareMay 13, 2026 08:44
@krodakkrodak changed the title BridgeJS: Add opt-in TypedArray bridging for numeric arraysBridgeJS: Optimize numeric array transfer with bulk TypedArray copyMay 13, 2026
@krodak

Copy link
Copy Markdown
CollaboratorAuthor

Tracked in new PR against main repo

@krodakkrodak closed this May 13, 2026
Sign up for freeto 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

@krodak