Skip to content

Commit d9e038b

Browse files
committed
BridgeJS: Fix JSValue reference ownership across the bridge
1 parent 461360a commit d9e038b

28 files changed

Lines changed: 281 additions & 37 deletions

‎Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,7 @@ struct IntrinsicJSFragment: Sendable {
749749

750750
private static let jsValueLowerHelperName = "__bjs_jsValueLower"
751751
private static let jsValueLiftHelperName = "__bjs_jsValueLift"
752+
private static let jsValueTakeHelperName = "__bjs_jsValueTake"
752753

753754
private static func registerJSValueHelpers(scope: JSGlueVariableScope) {
754755
scope.registerIntrinsic("jsValueHelpers") { helperPrinter in
@@ -777,6 +778,17 @@ struct IntrinsicJSFragment: Sendable {
777778
helperPrinter.write("return \(resultVar);")
778779
}
779780
helperPrinter.write("}")
781+
helperPrinter.write("function \(jsValueTakeHelperName)(kind, payload1, payload2) {")
782+
helperPrinter.indent {
783+
helperPrinter.write("const value = \(jsValueLiftHelperName)(kind, payload1, payload2);")
784+
helperPrinter.write("if (kind === 1 || kind === 3 || kind === 7 || kind === 8) {")
785+
helperPrinter.indent {
786+
helperPrinter.write("\(JSGlueVariableScope.reservedSwift).memory.release(payload1);")
787+
}
788+
helperPrinter.write("}")
789+
helperPrinter.write("return value;")
790+
}
791+
helperPrinter.write("}")
780792
}
781793
}
782794

@@ -961,11 +973,12 @@ struct IntrinsicJSFragment: Sendable {
961973
let resultVar = scope.variable("jsValue")
962974
registerJSValueHelpers(scope: scope)
963975
printer.write(
964-
"const \(resultVar) = \(jsValueLiftHelperName)(\(kind), \(payload1), \(payload2));"
976+
"const \(resultVar) = \(jsValueTakeHelperName)(\(kind), \(payload1), \(payload2));"
965977
)
966978
return [resultVar]
967979
}
968980
)
981+
/// Swift lends the payload reference for the duration of the call, so it is not released here.
969982
static let jsValueLiftParameter = IntrinsicJSFragment(
970983
parameters: ["kind", "payload1", "payload2"],
971984
printCode: { arguments, context in
@@ -2232,7 +2245,7 @@ struct IntrinsicJSFragment: Sendable {
22322245
let resultVar = scope.variable("jsValue")
22332246
registerJSValueHelpers(scope: scope)
22342247
printer.write(
2235-
"const \(resultVar) = \(jsValueLiftHelperName)(\(kindVar), \(payload1Var), \(payload2Var));"
2248+
"const \(resultVar) = \(jsValueTakeHelperName)(\(kindVar), \(payload1Var), \(payload2Var));"
22362249
)
22372250
return [resultVar]
22382251
}

‎Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ export async function createInstantiator(options, swift) {
267267
const jsValuePayload2 = f64Stack.pop();
268268
const jsValuePayload1 = i32Stack.pop();
269269
const jsValueKind = i32Stack.pop();
270-
const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2);
270+
const jsValue = __bjs_jsValueTake(jsValueKind, jsValuePayload1, jsValuePayload2);
271271
return jsValue;
272272
},
273273
},
@@ -361,6 +361,13 @@ export async function createInstantiator(options, swift) {
361361
}
362362
return jsValue;
363363
}
364+
function __bjs_jsValueTake(kind, payload1, payload2) {
365+
const value = __bjs_jsValueLift(kind, payload1, payload2);
366+
if (kind === 1 || kind === 3 || kind === 7 || kind === 8) {
367+
swift.memory.release(payload1);
368+
}
369+
return value;
370+
}
364371

365372
const __bjs_codec_M10TestModuleT16PolygonReference = {
366373
lower: (v) => {

‎Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ export async function createInstantiator(options, swift) {
274274
const jsValuePayload2 = f64Stack.pop();
275275
const jsValuePayload1 = i32Stack.pop();
276276
const jsValueKind = i32Stack.pop();
277-
const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2);
277+
const jsValue = __bjs_jsValueTake(jsValueKind, jsValuePayload1, jsValuePayload2);
278278
return jsValue;
279279
},
280280
},
@@ -368,6 +368,13 @@ export async function createInstantiator(options, swift) {
368368
}
369369
return jsValue;
370370
}
371+
function __bjs_jsValueTake(kind, payload1, payload2) {
372+
const value = __bjs_jsValueLift(kind, payload1, payload2);
373+
if (kind === 1 || kind === 3 || kind === 7 || kind === 8) {
374+
swift.memory.release(payload1);
375+
}
376+
return value;
377+
}
371378

372379
const __bjs_codec_Array_Int = __bjs_arrayCodec(__bjs_primitiveCodecs.Int);
373380
const __bjs_codec_Array_String = __bjs_arrayCodec(__bjs_stringCodec);

‎Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ export async function createInstantiator(options, swift) {
271271
const jsValuePayload2 = f64Stack.pop();
272272
const jsValuePayload1 = i32Stack.pop();
273273
const jsValueKind = i32Stack.pop();
274-
const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2);
274+
const jsValue = __bjs_jsValueTake(jsValueKind, jsValuePayload1, jsValuePayload2);
275275
return jsValue;
276276
},
277277
},
@@ -365,6 +365,13 @@ export async function createInstantiator(options, swift) {
365365
}
366366
return jsValue;
367367
}
368+
function __bjs_jsValueTake(kind, payload1, payload2) {
369+
const value = __bjs_jsValueLift(kind, payload1, payload2);
370+
if (kind === 1 || kind === 3 || kind === 7 || kind === 8) {
371+
swift.memory.release(payload1);
372+
}
373+
return value;
374+
}
368375

369376
const __bjs_codec_M10TestModuleT10AsyncPoint = {
370377
lower: (v) => {

‎Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ export async function createInstantiator(options, swift) {
128128
}
129129
return jsValue;
130130
}
131+
function __bjs_jsValueTake(kind, payload1, payload2) {
132+
const value = __bjs_jsValueLift(kind, payload1, payload2);
133+
if (kind === 1 || kind === 3 || kind === 7 || kind === 8) {
134+
swift.memory.release(payload1);
135+
}
136+
return value;
137+
}
131138

132139
const __bjs_createEnumHelpers_M10TestModuleT18AsyncPayloadResult = () => ({
133140
lower: (value) => {

‎Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,13 @@ export async function createInstantiator(options, swift) {
121121
}
122122
return jsValue;
123123
}
124+
function __bjs_jsValueTake(kind, payload1, payload2) {
125+
const value = __bjs_jsValueLift(kind, payload1, payload2);
126+
if (kind === 1 || kind === 3 || kind === 7 || kind === 8) {
127+
swift.memory.release(payload1);
128+
}
129+
return value;
130+
}
124131

125132
const swiftClosureRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => {
126133
if (state.unregistered) { return; }

‎Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,13 @@ export async function createInstantiator(options, swift) {
121121
}
122122
return jsValue;
123123
}
124+
function __bjs_jsValueTake(kind, payload1, payload2) {
125+
const value = __bjs_jsValueLift(kind, payload1, payload2);
126+
if (kind === 1 || kind === 3 || kind === 7 || kind === 8) {
127+
swift.memory.release(payload1);
128+
}
129+
return value;
130+
}
124131

125132
const swiftClosureRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => {
126133
if (state.unregistered) { return; }

‎Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ export async function createInstantiator(options, swift) {
267267
const jsValuePayload2 = f64Stack.pop();
268268
const jsValuePayload1 = i32Stack.pop();
269269
const jsValueKind = i32Stack.pop();
270-
const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2);
270+
const jsValue = __bjs_jsValueTake(jsValueKind, jsValuePayload1, jsValuePayload2);
271271
return jsValue;
272272
},
273273
},
@@ -361,6 +361,13 @@ export async function createInstantiator(options, swift) {
361361
}
362362
return jsValue;
363363
}
364+
function __bjs_jsValueTake(kind, payload1, payload2) {
365+
const value = __bjs_jsValueLift(kind, payload1, payload2);
366+
if (kind === 1 || kind === 3 || kind === 7 || kind === 8) {
367+
swift.memory.release(payload1);
368+
}
369+
return value;
370+
}
364371

365372
const __bjs_codec_M10TestModuleT6Config = {
366373
lower: (v) => {

‎Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ export async function createInstantiator(options, swift) {
261261
const jsValuePayload2 = f64Stack.pop();
262262
const jsValuePayload1 = i32Stack.pop();
263263
const jsValueKind = i32Stack.pop();
264-
const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2);
264+
const jsValue = __bjs_jsValueTake(jsValueKind, jsValuePayload1, jsValuePayload2);
265265
return jsValue;
266266
},
267267
},
@@ -355,6 +355,13 @@ export async function createInstantiator(options, swift) {
355355
}
356356
return jsValue;
357357
}
358+
function __bjs_jsValueTake(kind, payload1, payload2) {
359+
const value = __bjs_jsValueLift(kind, payload1, payload2);
360+
if (kind === 1 || kind === 3 || kind === 7 || kind === 8) {
361+
swift.memory.release(payload1);
362+
}
363+
return value;
364+
}
358365

359366
const __bjs_codec_Dict_Int = __bjs_dictCodec(__bjs_primitiveCodecs.Int);
360367
const __bjs_codec_Dict_String = __bjs_dictCodec(__bjs_stringCodec);

‎Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ export async function createInstantiator(options, swift) {
342342
const jsValuePayload2 = f64Stack.pop();
343343
const jsValuePayload1 = i32Stack.pop();
344344
const jsValueKind = i32Stack.pop();
345-
const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2);
345+
const jsValue = __bjs_jsValueTake(jsValueKind, jsValuePayload1, jsValuePayload2);
346346
return jsValue;
347347
},
348348
},
@@ -436,6 +436,13 @@ export async function createInstantiator(options, swift) {
436436
}
437437
return jsValue;
438438
}
439+
function __bjs_jsValueTake(kind, payload1, payload2) {
440+
const value = __bjs_jsValueLift(kind, payload1, payload2);
441+
if (kind === 1 || kind === 3 || kind === 7 || kind === 8) {
442+
swift.memory.release(payload1);
443+
}
444+
return value;
445+
}
439446

440447
const __bjs_codec_Optional_String = __bjs_optionalCodec(__bjs_stringCodec);
441448
const __bjs_codec_Optional_Bool = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool);

0 commit comments

Comments
 (0)