Skip to content

Commit d632591

Browse files
committed
feat: Swift-side per-class identity cache with JS import side channel
Replace DataView shared memory flag with @_extern(wasm) JS import for signaling, following the existing BridgeJS intrinsics pattern (_swift_js_push_i32, _swift_js_return_optional_heap_object, etc). Per-class Set tracks exported pointers. On cache hit, thunk calls _swift_js_set_identity_ref(1) and returns passUnretained. JS checks the ref and skips deinit. Trade-off vs JS-only cache: Set.contains with SipHash on WASM adds ~20-30ns per crossing, exceeding the ~4-8ns deinit WASM call it replaces. Improves create-heavy paths by ~20% but regresses roundtrip by ~50%.
1 parent 34c5d0d commit d632591

55 files changed

Lines changed: 593 additions & 133 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Benchmarks/Sources/Generated/BridgeJS.swift

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,12 +1531,23 @@ fileprivate func _bjs_IdentityCacheBenchmark_wrap_extern(_ pointer: UnsafeMutabl
15311531
return _bjs_IdentityCacheBenchmark_wrap_extern(pointer)
15321532
}
15331533

1534+
nonisolated(unsafe) var _SimpleClassIdentity_identityExported: Set<UnsafeMutableRawPointer> = []
1535+
15341536
@_expose(wasm, "bjs_SimpleClassIdentity_init")
15351537
@_cdecl("bjs_SimpleClassIdentity_init")
15361538
public func _bjs_SimpleClassIdentity_init(_ nameBytes: Int32, _ nameLength: Int32, _ count: Int32, _ flag: Int32, _ rate: Float32, _ precise: Float64) -> UnsafeMutableRawPointer {
15371539
#if arch(wasm32)
15381540
let ret = SimpleClassIdentity(name: String.bridgeJSLiftParameter(nameBytes, nameLength), count: Int.bridgeJSLiftParameter(count), flag: Bool.bridgeJSLiftParameter(flag), rate: Float.bridgeJSLiftParameter(rate), precise: Double.bridgeJSLiftParameter(precise))
1539-
return ret.bridgeJSLowerReturn()
1541+
return withExtendedLifetime(ret) {
1542+
let pointer = Unmanaged.passUnretained(ret).toOpaque()
1543+
if _SimpleClassIdentity_identityExported.contains(pointer) {
1544+
_swift_js_set_identity_ref(1)
1545+
return pointer
1546+
}
1547+
_SimpleClassIdentity_identityExported.insert(pointer)
1548+
_ = Unmanaged.passRetained(ret)
1549+
return pointer
1550+
}
15401551
#else
15411552
fatalError("Only available on WebAssembly")
15421553
#endif
@@ -1651,6 +1662,7 @@ public func _bjs_SimpleClassIdentity_precise_set(_ _self: UnsafeMutableRawPointe
16511662
@_cdecl("bjs_SimpleClassIdentity_deinit")
16521663
public func _bjs_SimpleClassIdentity_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
16531664
#if arch(wasm32)
1665+
_SimpleClassIdentity_identityExported.remove(pointer)
16541666
Unmanaged<SimpleClassIdentity>.fromOpaque(pointer).release()
16551667
#else
16561668
fatalError("Only available on WebAssembly")
@@ -1678,12 +1690,23 @@ fileprivate func _bjs_SimpleClassIdentity_wrap_extern(_ pointer: UnsafeMutableRa
16781690
return _bjs_SimpleClassIdentity_wrap_extern(pointer)
16791691
}
16801692

1693+
nonisolated(unsafe) var _ClassRoundtripIdentity_identityExported: Set<UnsafeMutableRawPointer> = []
1694+
16811695
@_expose(wasm, "bjs_ClassRoundtripIdentity_init")
16821696
@_cdecl("bjs_ClassRoundtripIdentity_init")
16831697
public func _bjs_ClassRoundtripIdentity_init() -> UnsafeMutableRawPointer {
16841698
#if arch(wasm32)
16851699
let ret = ClassRoundtripIdentity()
1686-
return ret.bridgeJSLowerReturn()
1700+
return withExtendedLifetime(ret) {
1701+
let pointer = Unmanaged.passUnretained(ret).toOpaque()
1702+
if _ClassRoundtripIdentity_identityExported.contains(pointer) {
1703+
_swift_js_set_identity_ref(1)
1704+
return pointer
1705+
}
1706+
_ClassRoundtripIdentity_identityExported.insert(pointer)
1707+
_ = Unmanaged.passRetained(ret)
1708+
return pointer
1709+
}
16871710
#else
16881711
fatalError("Only available on WebAssembly")
16891712
#endif
@@ -1725,6 +1748,7 @@ public func _bjs_ClassRoundtripIdentity_takeSimpleClassIdentity(_ _self: UnsafeM
17251748
@_cdecl("bjs_ClassRoundtripIdentity_deinit")
17261749
public func _bjs_ClassRoundtripIdentity_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
17271750
#if arch(wasm32)
1751+
_ClassRoundtripIdentity_identityExported.remove(pointer)
17281752
Unmanaged<ClassRoundtripIdentity>.fromOpaque(pointer).release()
17291753
#else
17301754
fatalError("Only available on WebAssembly")
@@ -1752,12 +1776,23 @@ fileprivate func _bjs_ClassRoundtripIdentity_wrap_extern(_ pointer: UnsafeMutabl
17521776
return _bjs_ClassRoundtripIdentity_wrap_extern(pointer)
17531777
}
17541778

1779+
nonisolated(unsafe) var _IdentityCacheBenchmarkIdentity_identityExported: Set<UnsafeMutableRawPointer> = []
1780+
17551781
@_expose(wasm, "bjs_IdentityCacheBenchmarkIdentity_init")
17561782
@_cdecl("bjs_IdentityCacheBenchmarkIdentity_init")
17571783
public func _bjs_IdentityCacheBenchmarkIdentity_init() -> UnsafeMutableRawPointer {
17581784
#if arch(wasm32)
17591785
let ret = IdentityCacheBenchmarkIdentity()
1760-
return ret.bridgeJSLowerReturn()
1786+
return withExtendedLifetime(ret) {
1787+
let pointer = Unmanaged.passUnretained(ret).toOpaque()
1788+
if _IdentityCacheBenchmarkIdentity_identityExported.contains(pointer) {
1789+
_swift_js_set_identity_ref(1)
1790+
return pointer
1791+
}
1792+
_IdentityCacheBenchmarkIdentity_identityExported.insert(pointer)
1793+
_ = Unmanaged.passRetained(ret)
1794+
return pointer
1795+
}
17611796
#else
17621797
fatalError("Only available on WebAssembly")
17631798
#endif
@@ -1788,6 +1823,7 @@ public func _bjs_IdentityCacheBenchmarkIdentity_getPoolRepeated(_ _self: UnsafeM
17881823
@_cdecl("bjs_IdentityCacheBenchmarkIdentity_deinit")
17891824
public func _bjs_IdentityCacheBenchmarkIdentity_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
17901825
#if arch(wasm32)
1826+
_IdentityCacheBenchmarkIdentity_identityExported.remove(pointer)
17911827
Unmanaged<IdentityCacheBenchmarkIdentity>.fromOpaque(pointer).release()
17921828
#else
17931829
fatalError("Only available on WebAssembly")

0 commit comments

Comments
 (0)