Skip to content

Commit 818fa91

Browse files
BridgeJS: Wrap imported calls in try-catch to handle exceptions
1 parent 6222727 commit 818fa91

Some content is hidden

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

45 files changed

+640
-80
lines changed

Benchmarks/Sources/Generated/BridgeJS.ImportTS.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ func benchmarkHelperNoop() throws(JSException) -> Void {
1616
}
1717
#endif
1818
bjs_benchmarkHelperNoop()
19+
if let error = _swift_js_take_exception() {
20+
throw error
21+
}
1922
}
2023

2124
func benchmarkHelperNoopWithNumber(_ n: Double) throws(JSException) -> Void {
@@ -28,6 +31,9 @@ func benchmarkHelperNoopWithNumber(_ n: Double) throws(JSException) -> Void {
2831
}
2932
#endif
3033
bjs_benchmarkHelperNoopWithNumber(n)
34+
if let error = _swift_js_take_exception() {
35+
throw error
36+
}
3137
}
3238

3339
func benchmarkRunner(_ name: String, _ body: JSObject) throws(JSException) -> Void {
@@ -44,4 +50,7 @@ func benchmarkRunner(_ name: String, _ body: JSObject) throws(JSException) -> Vo
4450
_swift_js_make_js_string(b.baseAddress.unsafelyUnwrapped, Int32(b.count))
4551
}
4652
bjs_benchmarkRunner(nameId, Int32(bitPattern: body.id))
53+
if let error = _swift_js_take_exception() {
54+
throw error
55+
}
4756
}

Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.ImportTS.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ func createTS2Skeleton() throws(JSException) -> TS2Skeleton {
1616
}
1717
#endif
1818
let ret = bjs_createTS2Skeleton()
19+
if let error = _swift_js_take_exception() {
20+
throw error
21+
}
1922
return TS2Skeleton(takingThis: ret)
2023
}
2124

@@ -44,6 +47,9 @@ struct TS2Skeleton {
4447
_swift_js_make_js_string(b.baseAddress.unsafelyUnwrapped, Int32(b.count))
4548
}
4649
let ret = bjs_TS2Skeleton_convert(Int32(bitPattern: self.this.id), tsId)
50+
if let error = _swift_js_take_exception() {
51+
throw error
52+
}
4753
return String(unsafeUninitializedCapacity: Int(ret)) { b in
4854
_swift_js_init_memory_with_result(b.baseAddress.unsafelyUnwrapped, Int32(ret))
4955
return Int(ret)

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -433,25 +433,7 @@ class ExportSwift {
433433
}
434434

435435
func lowerReturnValue(returnType: BridgeType) {
436-
switch returnType {
437-
case .void:
438-
abiReturnType = nil
439-
case .bool:
440-
abiReturnType = .i32
441-
case .int:
442-
abiReturnType = .i32
443-
case .float:
444-
abiReturnType = .f32
445-
case .double:
446-
abiReturnType = .f64
447-
case .string:
448-
abiReturnType = nil
449-
case .jsObject:
450-
abiReturnType = .i32
451-
case .swiftHeapObject:
452-
// UnsafeMutableRawPointer is returned as an i32 pointer
453-
abiReturnType = .pointer
454-
}
436+
abiReturnType = returnType.abiReturnType
455437

456438
switch returnType {
457439
case .void: break

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ struct ImportTS {
151151
} else {
152152
body.append("let ret = \(raw: call)")
153153
}
154+
body.append("if let error = _swift_js_take_exception() { throw error }")
154155
}
155156

156157
func liftReturnValue(returnType: BridgeType) throws {

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ struct BridgeJSLink {
118118
export async function createInstantiator(options, swift) {
119119
let instance;
120120
let memory;
121+
let setException;
121122
const textDecoder = new TextDecoder("utf-8");
122123
const textEncoder = new TextEncoder("utf-8");
123124
@@ -161,6 +162,9 @@ struct BridgeJSLink {
161162
setInstance: (i) => {
162163
instance = i;
163164
memory = instance.exports.memory;
165+
setException = (error) => {
166+
instance.exports._swift_js_exception.value = swift.memory.retain(error)
167+
}
164168
},
165169
/** @param {WebAssembly.Instance} instance */
166170
createExports: (instance) => {
@@ -419,16 +423,24 @@ struct BridgeJSLink {
419423

420424
func renderFunction(
421425
name: String,
422-
returnExpr: String?
426+
returnExpr: String?,
427+
returnType: BridgeType
423428
) -> [String] {
424429
var funcLines: [String] = []
425430
funcLines.append(
426431
"function \(name)(\(parameterNames.joined(separator: ", "))) {"
427432
)
428-
funcLines.append(contentsOf: bodyLines.map { $0.indent(count: 4) })
433+
funcLines.append("try {".indent(count: 4))
434+
funcLines.append(contentsOf: bodyLines.map { $0.indent(count: 8) })
429435
if let returnExpr = returnExpr {
430-
funcLines.append("return \(returnExpr);".indent(count: 4))
436+
funcLines.append("return \(returnExpr);".indent(count: 8))
431437
}
438+
funcLines.append("} catch (error) {".indent(count: 4))
439+
funcLines.append("setException(error);".indent(count: 8))
440+
if let abiReturnType = returnType.abiReturnType {
441+
funcLines.append("return \(abiReturnType.placeholderValue)".indent(count: 8))
442+
}
443+
funcLines.append("}".indent(count: 4))
432444
funcLines.append("}")
433445
return funcLines
434446
}
@@ -518,7 +530,8 @@ struct BridgeJSLink {
518530
let returnExpr = try thunkBuilder.lowerReturnValue(returnType: function.returnType)
519531
let funcLines = thunkBuilder.renderFunction(
520532
name: function.abiName(context: nil),
521-
returnExpr: returnExpr
533+
returnExpr: returnExpr,
534+
returnType: function.returnType
522535
)
523536
importObjectBuilder.appendDts(
524537
[
@@ -591,7 +604,8 @@ struct BridgeJSLink {
591604
let abiName = constructor.abiName(context: type)
592605
let funcLines = thunkBuilder.renderFunction(
593606
name: abiName,
594-
returnExpr: returnExpr
607+
returnExpr: returnExpr,
608+
returnType: returnType
595609
)
596610
importObjectBuilder.assignToImportObject(name: abiName, function: funcLines)
597611
importObjectBuilder.appendDts([
@@ -611,7 +625,8 @@ struct BridgeJSLink {
611625
let returnExpr = try emitCall(thunkBuilder)
612626
let funcLines = thunkBuilder.renderFunction(
613627
name: abiName,
614-
returnExpr: returnExpr
628+
returnExpr: returnExpr,
629+
returnType: property.type
615630
)
616631
return (funcLines, [])
617632
}
@@ -629,7 +644,8 @@ struct BridgeJSLink {
629644
let returnExpr = try thunkBuilder.lowerReturnValue(returnType: method.returnType)
630645
let funcLines = thunkBuilder.renderFunction(
631646
name: method.abiName(context: context),
632-
returnExpr: returnExpr
647+
returnExpr: returnExpr,
648+
returnType: method.returnType
633649
)
634650
return (funcLines, [])
635651
}
@@ -667,3 +683,11 @@ extension BridgeType {
667683
}
668684
}
669685
}
686+
687+
extension WasmCoreType {
688+
fileprivate var placeholderValue: String {
689+
switch self {
690+
case .i32, .i64, .f32, .f64, .pointer: return "0"
691+
}
692+
}
693+
}

Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,20 @@ struct ImportedModuleSkeleton: Codable {
101101
let moduleName: String
102102
var children: [ImportedFileSkeleton]
103103
}
104+
105+
extension BridgeType {
106+
var abiReturnType: WasmCoreType? {
107+
switch self {
108+
case .void: return nil
109+
case .bool: return .i32
110+
case .int: return .i32
111+
case .float: return .f32
112+
case .double: return .f64
113+
case .string: return nil
114+
case .jsObject: return .i32
115+
case .swiftHeapObject:
116+
// UnsafeMutableRawPointer is returned as an i32 pointer
117+
return .pointer
118+
}
119+
}
120+
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
export async function createInstantiator(options, swift) {
88
let instance;
99
let memory;
10+
let setException;
1011
const textDecoder = new TextDecoder("utf-8");
1112
const textEncoder = new TextEncoder("utf-8");
1213

@@ -47,18 +48,33 @@ export async function createInstantiator(options, swift) {
4748
}
4849
const TestModule = importObject["TestModule"] = {};
4950
TestModule["bjs_checkArray"] = function bjs_checkArray(a) {
50-
options.imports.checkArray(swift.memory.getObject(a));
51+
try {
52+
options.imports.checkArray(swift.memory.getObject(a));
53+
} catch (error) {
54+
setException(error);
55+
}
5156
}
5257
TestModule["bjs_checkArrayWithLength"] = function bjs_checkArrayWithLength(a, b) {
53-
options.imports.checkArrayWithLength(swift.memory.getObject(a), b);
58+
try {
59+
options.imports.checkArrayWithLength(swift.memory.getObject(a), b);
60+
} catch (error) {
61+
setException(error);
62+
}
5463
}
5564
TestModule["bjs_checkArray"] = function bjs_checkArray(a) {
56-
options.imports.checkArray(swift.memory.getObject(a));
65+
try {
66+
options.imports.checkArray(swift.memory.getObject(a));
67+
} catch (error) {
68+
setException(error);
69+
}
5770
}
5871
},
5972
setInstance: (i) => {
6073
instance = i;
6174
memory = instance.exports.memory;
75+
setException = (error) => {
76+
instance.exports._swift_js_exception.value = swift.memory.retain(error)
77+
}
6278
},
6379
/** @param {WebAssembly.Instance} instance */
6480
createExports: (instance) => {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
export async function createInstantiator(options, swift) {
88
let instance;
99
let memory;
10+
let setException;
1011
const textDecoder = new TextDecoder("utf-8");
1112
const textEncoder = new TextEncoder("utf-8");
1213

@@ -47,21 +48,39 @@ export async function createInstantiator(options, swift) {
4748
}
4849
const TestModule = importObject["TestModule"] = {};
4950
TestModule["bjs_returnAnimatable"] = function bjs_returnAnimatable() {
50-
let ret = options.imports.returnAnimatable();
51-
return swift.memory.retain(ret);
51+
try {
52+
let ret = options.imports.returnAnimatable();
53+
return swift.memory.retain(ret);
54+
} catch (error) {
55+
setException(error);
56+
return 0
57+
}
5258
}
5359
TestModule["bjs_Animatable_animate"] = function bjs_Animatable_animate(self, keyframes, options) {
54-
let ret = swift.memory.getObject(self).animate(swift.memory.getObject(keyframes), swift.memory.getObject(options));
55-
return swift.memory.retain(ret);
60+
try {
61+
let ret = swift.memory.getObject(self).animate(swift.memory.getObject(keyframes), swift.memory.getObject(options));
62+
return swift.memory.retain(ret);
63+
} catch (error) {
64+
setException(error);
65+
return 0
66+
}
5667
}
5768
TestModule["bjs_Animatable_getAnimations"] = function bjs_Animatable_getAnimations(self, options) {
58-
let ret = swift.memory.getObject(self).getAnimations(swift.memory.getObject(options));
59-
return swift.memory.retain(ret);
69+
try {
70+
let ret = swift.memory.getObject(self).getAnimations(swift.memory.getObject(options));
71+
return swift.memory.retain(ret);
72+
} catch (error) {
73+
setException(error);
74+
return 0
75+
}
6076
}
6177
},
6278
setInstance: (i) => {
6379
instance = i;
6480
memory = instance.exports.memory;
81+
setException = (error) => {
82+
instance.exports._swift_js_exception.value = swift.memory.retain(error)
83+
}
6584
},
6685
/** @param {WebAssembly.Instance} instance */
6786
createExports: (instance) => {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
export async function createInstantiator(options, swift) {
88
let instance;
99
let memory;
10+
let setException;
1011
const textDecoder = new TextDecoder("utf-8");
1112
const textEncoder = new TextEncoder("utf-8");
1213

@@ -50,6 +51,9 @@ export async function createInstantiator(options, swift) {
5051
setInstance: (i) => {
5152
instance = i;
5253
memory = instance.exports.memory;
54+
setException = (error) => {
55+
instance.exports._swift_js_exception.value = swift.memory.retain(error)
56+
}
5357
},
5458
/** @param {WebAssembly.Instance} instance */
5559
createExports: (instance) => {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
export async function createInstantiator(options, swift) {
88
let instance;
99
let memory;
10+
let setException;
1011
const textDecoder = new TextDecoder("utf-8");
1112
const textEncoder = new TextEncoder("utf-8");
1213

@@ -47,12 +48,19 @@ export async function createInstantiator(options, swift) {
4748
}
4849
const TestModule = importObject["TestModule"] = {};
4950
TestModule["bjs_check"] = function bjs_check(a, b) {
50-
options.imports.check(a, b);
51+
try {
52+
options.imports.check(a, b);
53+
} catch (error) {
54+
setException(error);
55+
}
5156
}
5257
},
5358
setInstance: (i) => {
5459
instance = i;
5560
memory = instance.exports.memory;
61+
setException = (error) => {
62+
instance.exports._swift_js_exception.value = swift.memory.retain(error)
63+
}
5664
},
5765
/** @param {WebAssembly.Instance} instance */
5866
createExports: (instance) => {

0 commit comments

Comments
 (0)