Skip to content

Commit 28b97a9

Browse files
BridgeJS: Fix memory management of SwiftHeapObject
1 parent 87817dc commit 28b97a9

File tree

1 file changed

+7
-33
lines changed

1 file changed

+7
-33
lines changed

Sources/JavaScriptKit/BridgeJSIntrinsics.swift

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ internal func _swift_js_closure_unregister(_ id: Int32) {
124124
// - `func bridgeJSStackPush()`: push the value onto the return stack (used by _BridgedSwiftStackType for array elements)
125125
//
126126
// Optional types (ExportSwift only) additionally define:
127-
// - `func bridgeJSLowerParameterWithRetain()`: lower optional heap object with ownership transfer for escaping closures
128127
// - `func bridgeJSLiftReturnFromSideChannel()`: lift optional from side-channel storage for protocol property getters
129128
//
130129
// See JSGlueGen.swift in BridgeJSLink for JS-side lowering/lifting implementation.
@@ -467,9 +466,10 @@ public protocol _BridgedSwiftHeapObject: AnyObject, _BridgedSwiftStackType {}
467466
extension _BridgedSwiftHeapObject {
468467

469468
// MARK: ImportTS
470-
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> UnsafeMutableRawPointer {
471-
// For protocol parameters, we pass the unretained pointer since JS already has a reference
472-
return Unmanaged.passUnretained(self).toOpaque()
469+
@_spi(BridgeJS) @_transparent public func bridgeJSLowerParameter() -> UnsafeMutableRawPointer {
470+
// Transfer ownership to JS for imported SwiftHeapObject parameters.
471+
// JS side must eventually release (via release() or FinalizationRegistry).
472+
return Unmanaged.passRetained(self).toOpaque()
473473
}
474474
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ pointer: UnsafeMutableRawPointer) -> Self {
475475
// For protocol returns, take an unretained value since JS manages the lifetime
@@ -1489,11 +1489,10 @@ extension Optional where Wrapped: _BridgedSwiftHeapObject {
14891489
// MARK: ExportSwift
14901490
/// Lowers optional Swift heap object as (isSome, pointer) tuple for protocol parameters.
14911491
///
1492-
/// This method uses `passUnretained()` because the caller (JavaScript protocol implementation)
1493-
/// already owns the object and will not retain it. The pointer is only valid for the
1494-
/// duration of the call.
1492+
/// Transfer ownership to JavaScript for imported optional heap-object parameters; JS must
1493+
/// release via `release()` or finalizer.
14951494
///
1496-
/// - Returns: A tuple containing presence flag (0 for nil, 1 for some) and unretained pointer
1495+
/// - Returns: A tuple containing presence flag (0 for nil, 1 for some) and retained pointer
14971496
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> (
14981497
isSome: Int32, pointer: UnsafeMutableRawPointer
14991498
) {
@@ -1505,25 +1504,6 @@ extension Optional where Wrapped: _BridgedSwiftHeapObject {
15051504
}
15061505
}
15071506

1508-
/// Lowers optional Swift heap object with ownership transfer for escaping closures.
1509-
///
1510-
/// This method uses `passRetained()` to transfer ownership to JavaScript, ensuring the
1511-
/// object remains valid even if the JavaScript closure escapes and stores the parameter.
1512-
/// JavaScript must wrap the pointer with `__construct()` to create a managed reference
1513-
/// that will be cleaned up via FinalizationRegistry.
1514-
///
1515-
/// - Returns: A tuple containing presence flag (0 for nil, 1 for some) and retained pointer
1516-
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithRetain() -> (
1517-
isSome: Int32, pointer: UnsafeMutableRawPointer
1518-
) {
1519-
switch consume self {
1520-
case .none:
1521-
return (isSome: 0, pointer: UnsafeMutableRawPointer(bitPattern: 1)!)
1522-
case .some(let value):
1523-
return (isSome: 1, pointer: Unmanaged.passRetained(value).toOpaque())
1524-
}
1525-
}
1526-
15271507
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ pointer: UnsafeMutableRawPointer) -> Wrapped?
15281508
{
15291509
if pointer == UnsafeMutableRawPointer(bitPattern: 0) {
@@ -2008,12 +1988,6 @@ extension _BridgedAsOptional where Wrapped: _BridgedSwiftHeapObject {
20081988
asOptional.bridgeJSLowerParameter()
20091989
}
20101990

2011-
@_spi(BridgeJS) public consuming func bridgeJSLowerParameterWithRetain() -> (
2012-
isSome: Int32, pointer: UnsafeMutableRawPointer
2013-
) {
2014-
asOptional.bridgeJSLowerParameterWithRetain()
2015-
}
2016-
20171991
@_spi(BridgeJS) public static func bridgeJSLiftParameter(
20181992
_ isSome: Int32,
20191993
_ pointer: UnsafeMutableRawPointer

0 commit comments

Comments
 (0)