Skip to content

Commit 118db02

Browse files
BridgeJS: Take ownership of source Uint8Array id in swift_js_init_memory (#635)
This allows us to insert cleanup code for String parameter passing for JS -> Swift.
1 parent a8b249c commit 118db02

Some content is hidden

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

44 files changed

+72
-249
lines changed

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,9 @@ public struct BridgeJSLink {
297297
printer.write(
298298
"const source = \(JSGlueVariableScope.reservedSwift).\(JSGlueVariableScope.reservedMemory).getObject(sourceId);"
299299
)
300+
printer.write(
301+
"\(JSGlueVariableScope.reservedSwift).\(JSGlueVariableScope.reservedMemory).release(sourceId);"
302+
)
300303
printer.write(
301304
"const bytes = new Uint8Array(\(JSGlueVariableScope.reservedMemory).buffer, bytesPtr);"
302305
)

Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -238,13 +238,12 @@ struct IntrinsicJSFragment: Sendable {
238238
static let stringLowerParameter = IntrinsicJSFragment(
239239
parameters: ["value"],
240240
printCode: { arguments, context in
241-
let (scope, printer, cleanupCode) = (context.scope, context.printer, context.cleanupCode)
241+
let (scope, printer) = (context.scope, context.printer)
242242
let argument = arguments[0]
243243
let bytesLabel = scope.variable("\(argument)Bytes")
244244
let bytesIdLabel = scope.variable("\(argument)Id")
245245
printer.write("const \(bytesLabel) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(argument));")
246246
printer.write("const \(bytesIdLabel) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesLabel));")
247-
cleanupCode.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(bytesIdLabel));")
248247
return [bytesIdLabel, "\(bytesLabel).length"]
249248
}
250249
)
@@ -840,12 +839,6 @@ struct IntrinsicJSFragment: Sendable {
840839
printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));")
841840
}
842841
printer.write("}")
843-
cleanupCode.write("if (\(idVar) != undefined) {")
844-
cleanupCode.indent {
845-
cleanupCode.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(idVar));")
846-
}
847-
cleanupCode.write("}")
848-
849842
return ["+\(isSomeVar)", "\(isSomeVar) ? \(idVar) : 0", "\(isSomeVar) ? \(bytesVar).length : 0"]
850843
case .jsValue:
851844
let lowered = try jsValueLower.printCode([value], context)
@@ -1920,11 +1913,6 @@ struct IntrinsicJSFragment: Sendable {
19201913
}
19211914
printer.write("}")
19221915
scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer)
1923-
cleanup.write("if(\(idVar)) {")
1924-
cleanup.indent {
1925-
cleanup.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(idVar));")
1926-
}
1927-
cleanup.write("}")
19281916
case .int, .uint:
19291917
scope.emitPushI32Parameter("\(isSomeVar) ? (\(value) | 0) : 0", printer: printer)
19301918
scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer)
@@ -1964,13 +1952,6 @@ struct IntrinsicJSFragment: Sendable {
19641952
}
19651953
printer.write("}")
19661954
scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer)
1967-
cleanup.write("if(\(idVar)) {")
1968-
cleanup.indent {
1969-
cleanup.write(
1970-
"\(JSGlueVariableScope.reservedSwift).memory.release(\(idVar));"
1971-
)
1972-
}
1973-
cleanup.write("}")
19741955
case .float:
19751956
scope.emitPushF32Parameter("\(isSomeVar) ? Math.fround(\(value)) : 0.0", printer: printer)
19761957
scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer)
@@ -2554,15 +2535,14 @@ struct IntrinsicJSFragment: Sendable {
25542535
return IntrinsicJSFragment(
25552536
parameters: ["value"],
25562537
printCode: { arguments, context in
2557-
let (scope, printer, cleanup) = (context.scope, context.printer, context.cleanupCode)
2538+
let (scope, printer) = (context.scope, context.printer)
25582539
let value = arguments[0]
25592540
let bytesVar = scope.variable("bytes")
25602541
let idVar = scope.variable("id")
25612542
printer.write("const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));")
25622543
printer.write("const \(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));")
25632544
scope.emitPushI32Parameter("\(bytesVar).length", printer: printer)
25642545
scope.emitPushI32Parameter(idVar, printer: printer)
2565-
cleanup.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(idVar));")
25662546
return []
25672547
}
25682548
)
@@ -2632,7 +2612,7 @@ struct IntrinsicJSFragment: Sendable {
26322612
return IntrinsicJSFragment(
26332613
parameters: ["value"],
26342614
printCode: { arguments, context in
2635-
let (scope, printer, cleanup) = (context.scope, context.printer, context.cleanupCode)
2615+
let (scope, printer) = (context.scope, context.printer)
26362616
let value = arguments[0]
26372617
let bytesVar = scope.variable("bytes")
26382618
let idVar = scope.variable("id")
@@ -2644,7 +2624,6 @@ struct IntrinsicJSFragment: Sendable {
26442624
)
26452625
scope.emitPushI32Parameter("\(bytesVar).length", printer: printer)
26462626
scope.emitPushI32Parameter(idVar, printer: printer)
2647-
cleanup.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(idVar));")
26482627
return []
26492628
}
26502629
)
@@ -3088,9 +3067,6 @@ struct IntrinsicJSFragment: Sendable {
30883067
}
30893068
printer.write("}")
30903069
scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer)
3091-
cleanup.write(
3092-
"if(\(idVar) !== undefined) { \(JSGlueVariableScope.reservedSwift).memory.release(\(idVar)); }"
3093-
)
30943070
return [idVar]
30953071
case .float:
30963072
printer.write("if (\(isSomeVar)) {")
@@ -3179,9 +3155,6 @@ struct IntrinsicJSFragment: Sendable {
31793155
}
31803156
printer.write("}")
31813157
scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer)
3182-
cleanup.write(
3183-
"if(\(idVar) !== undefined) { \(JSGlueVariableScope.reservedSwift).memory.release(\(idVar)); }"
3184-
)
31853158
return [idVar]
31863159
} else if case .jsObject = wrappedType {
31873160
let idVar = scope.variable("id")

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

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export async function createInstantiator(options, swift) {
7171
}
7272
bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) {
7373
const source = swift.memory.getObject(sourceId);
74+
swift.memory.release(sourceId);
7475
const bytes = new Uint8Array(memory.buffer, bytesPtr);
7576
bytes.set(source);
7677
}
@@ -317,9 +318,6 @@ export async function createInstantiator(options, swift) {
317318
const id = swift.memory.retain(bytes);
318319
i32Stack.push(bytes.length);
319320
i32Stack.push(id);
320-
arrayCleanups.push(() => {
321-
swift.memory.release(id);
322-
});
323321
}
324322
i32Stack.push(ret.length);
325323
} catch (error) {
@@ -411,9 +409,6 @@ export async function createInstantiator(options, swift) {
411409
const id = swift.memory.retain(bytes);
412410
i32Stack.push(bytes.length);
413411
i32Stack.push(id);
414-
arrayCleanups.push(() => {
415-
swift.memory.release(id);
416-
});
417412
}
418413
i32Stack.push(values.length);
419414
instance.exports.bjs_processStringArray();
@@ -539,7 +534,6 @@ export async function createInstantiator(options, swift) {
539534
instance.exports.bjs_findFirstPoint(matchingId, matchingBytes.length);
540535
const structValue = structHelpers.Point.lift();
541536
for (const cleanup of arrayCleanups) { cleanup(); }
542-
swift.memory.release(matchingId);
543537
return structValue;
544538
},
545539
processUnsafeRawPointerArray: function bjs_processUnsafeRawPointerArray(values) {
@@ -632,7 +626,6 @@ export async function createInstantiator(options, swift) {
632626
const id = swift.memory.retain(bytes);
633627
i32Stack.push(bytes.length);
634628
i32Stack.push(id);
635-
arrayCleanups.push(() => { swift.memory.release(id); });
636629
} else {
637630
i32Stack.push(0);
638631
i32Stack.push(0);
@@ -817,9 +810,6 @@ export async function createInstantiator(options, swift) {
817810
const id = swift.memory.retain(bytes);
818811
i32Stack.push(bytes.length);
819812
i32Stack.push(id);
820-
arrayCleanups1.push(() => {
821-
swift.memory.release(id);
822-
});
823813
}
824814
i32Stack.push(elem.length);
825815
arrayCleanups.push(() => {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export async function createInstantiator(options, swift) {
4343
}
4444
bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) {
4545
const source = swift.memory.getObject(sourceId);
46+
swift.memory.release(sourceId);
4647
const bytes = new Uint8Array(memory.buffer, bytesPtr);
4748
bytes.set(source);
4849
}
@@ -225,7 +226,6 @@ export async function createInstantiator(options, swift) {
225226
const ret = instance.exports.bjs_asyncRoundTripString(vId, vBytes.length);
226227
const ret1 = swift.memory.getObject(ret);
227228
swift.memory.release(ret);
228-
swift.memory.release(vId);
229229
return ret1;
230230
},
231231
asyncRoundTripBool: function bjs_asyncRoundTripBool(v) {

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

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,7 @@ export async function createInstantiator(options, swift) {
4444
i32Stack.push(id);
4545
i32Stack.push((value.value | 0));
4646
i32Stack.push(value.enabled ? 1 : 0);
47-
const cleanup = () => {
48-
swift.memory.release(id);
49-
};
50-
return { cleanup };
47+
return { cleanup: undefined };
5148
},
5249
lift: () => {
5350
const bool = i32Stack.pop() !== 0;
@@ -96,6 +93,7 @@ export async function createInstantiator(options, swift) {
9693
}
9794
bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) {
9895
const source = swift.memory.getObject(sourceId);
96+
swift.memory.release(sourceId);
9997
const bytes = new Uint8Array(memory.buffer, bytesPtr);
10098
bytes.set(source);
10199
}
@@ -325,7 +323,6 @@ export async function createInstantiator(options, swift) {
325323
const nameBytes = textEncoder.encode(name);
326324
const nameId = swift.memory.retain(nameBytes);
327325
const ret = instance.exports.bjs_DefaultGreeter_init(nameId, nameBytes.length);
328-
swift.memory.release(nameId);
329326
return DefaultGreeter.__construct(ret);
330327
}
331328
get name() {
@@ -338,7 +335,6 @@ export async function createInstantiator(options, swift) {
338335
const valueBytes = textEncoder.encode(value);
339336
const valueId = swift.memory.retain(valueBytes);
340337
instance.exports.bjs_DefaultGreeter_name_set(this.pointer, valueId, valueBytes.length);
341-
swift.memory.release(valueId);
342338
}
343339
}
344340
class EmptyGreeter extends SwiftHeapObject {
@@ -366,10 +362,6 @@ export async function createInstantiator(options, swift) {
366362
tagId = swift.memory.retain(tagBytes);
367363
}
368364
const ret = instance.exports.bjs_ConstructorDefaults_init(nameId, nameBytes.length, count, enabled, status, +isSome, isSome ? tagId : 0, isSome ? tagBytes.length : 0);
369-
swift.memory.release(nameId);
370-
if (tagId != undefined) {
371-
swift.memory.release(tagId);
372-
}
373365
return ConstructorDefaults.__construct(ret);
374366
}
375367
get name() {
@@ -382,7 +374,6 @@ export async function createInstantiator(options, swift) {
382374
const valueBytes = textEncoder.encode(value);
383375
const valueId = swift.memory.retain(valueBytes);
384376
instance.exports.bjs_ConstructorDefaults_name_set(this.pointer, valueId, valueBytes.length);
385-
swift.memory.release(valueId);
386377
}
387378
get count() {
388379
const ret = instance.exports.bjs_ConstructorDefaults_count_get(this.pointer);
@@ -419,9 +410,6 @@ export async function createInstantiator(options, swift) {
419410
valueId = swift.memory.retain(valueBytes);
420411
}
421412
instance.exports.bjs_ConstructorDefaults_tag_set(this.pointer, +isSome, isSome ? valueId : 0, isSome ? valueBytes.length : 0);
422-
if (valueId != undefined) {
423-
swift.memory.release(valueId);
424-
}
425413
}
426414
}
427415
const ConfigHelpers = __bjs_createConfigHelpers()();
@@ -440,7 +428,6 @@ export async function createInstantiator(options, swift) {
440428
instance.exports.bjs_testStringDefault(messageId, messageBytes.length);
441429
const ret = tmpRetString;
442430
tmpRetString = undefined;
443-
swift.memory.release(messageId);
444431
return ret;
445432
},
446433
testNegativeIntDefault: function bjs_testNegativeIntDefault(value = -42) {
@@ -469,9 +456,6 @@ export async function createInstantiator(options, swift) {
469456
instance.exports.bjs_testOptionalDefault(+isSome, isSome ? nameId : 0, isSome ? nameBytes.length : 0);
470457
const optResult = tmpRetString;
471458
tmpRetString = undefined;
472-
if (nameId != undefined) {
473-
swift.memory.release(nameId);
474-
}
475459
return optResult;
476460
},
477461
testOptionalStringDefault: function bjs_testOptionalStringDefault(greeting = "Hi") {
@@ -484,9 +468,6 @@ export async function createInstantiator(options, swift) {
484468
instance.exports.bjs_testOptionalStringDefault(+isSome, isSome ? greetingId : 0, isSome ? greetingBytes.length : 0);
485469
const optResult = tmpRetString;
486470
tmpRetString = undefined;
487-
if (greetingId != undefined) {
488-
swift.memory.release(greetingId);
489-
}
490471
return optResult;
491472
},
492473
testMultipleDefaults: function bjs_testMultipleDefaults(title = "Default Title", count = 10, enabled = false) {
@@ -495,7 +476,6 @@ export async function createInstantiator(options, swift) {
495476
instance.exports.bjs_testMultipleDefaults(titleId, titleBytes.length, count, enabled);
496477
const ret = tmpRetString;
497478
tmpRetString = undefined;
498-
swift.memory.release(titleId);
499479
return ret;
500480
},
501481
testEnumDefault: function bjs_testEnumDefault(status = StatusValues.Active) {
@@ -572,9 +552,6 @@ export async function createInstantiator(options, swift) {
572552
const id = swift.memory.retain(bytes);
573553
i32Stack.push(bytes.length);
574554
i32Stack.push(id);
575-
arrayCleanups.push(() => {
576-
swift.memory.release(id);
577-
});
578555
}
579556
i32Stack.push(names.length);
580557
instance.exports.bjs_testStringArrayDefault();
@@ -650,7 +627,6 @@ export async function createInstantiator(options, swift) {
650627
instance.exports.bjs_testMixedWithArrayDefault(nameId, nameBytes.length, enabled);
651628
const ret = tmpRetString;
652629
tmpRetString = undefined;
653-
swift.memory.release(nameId);
654630
for (const cleanup of arrayCleanups) { cleanup(); }
655631
return ret;
656632
},

0 commit comments

Comments
 (0)