diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 61ffc778..36e6f482 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -50,13 +50,19 @@ public struct BridgeJSLink { } """ + // Both the FinalizationRegistry callback and release() wrap state.deinit() in try/catch + // because either can fire during process shutdown after the Wasm instance is already torn + // down. Calling into Wasm at that point throws RuntimeError (memory access / table index + // out of bounds). There's nothing to do but swallow it - the process is exiting anyway. let swiftHeapObjectClassJs = """ const swiftHeapObjectFinalizationRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { if (state.hasReleased) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -77,7 +83,9 @@ public struct BridgeJSLink { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } """ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index e7bdf975..3a6c0dc1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -340,7 +340,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -361,7 +363,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class Item extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index 0538b807..ceb7b1b6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -277,7 +277,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -298,7 +300,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class DefaultGreeter extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index efbd9b09..27c4573a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -235,7 +235,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -256,7 +258,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class Box extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 43cc9f96..785870b4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -972,7 +972,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -993,7 +995,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class User extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js index a5f97641..8b3f0d35 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js @@ -261,7 +261,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -282,7 +284,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class Converter extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js index a30709cb..f52908db 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js @@ -242,7 +242,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -263,7 +265,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class Converter extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index 0a4d3784..7c4948d6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -336,7 +336,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -357,7 +359,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class JSValueHolder extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js index 457661b6..e93fc62d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js @@ -209,7 +209,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -230,7 +232,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class GlobalClass extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js index 6c0c5ad9..0a03688e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js @@ -217,7 +217,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -238,7 +240,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class GlobalClass extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js index a576e82b..d5fe3f96 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js @@ -209,7 +209,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -230,7 +232,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class PrivateClass extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index 806697af..622d8d20 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -217,7 +217,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -238,7 +240,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class Greeter extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index 1f536682..31de2bca 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -217,7 +217,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -238,7 +240,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class Greeter extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 03a3cf56..2ffcb704 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -469,7 +469,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -490,7 +492,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class Greeter extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js index dbdd030b..287dbef7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js @@ -209,7 +209,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -230,7 +232,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class PropertyHolder extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index 9043d19e..93253ea7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -568,7 +568,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -589,7 +591,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class Helper extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 109a403b..975b56c9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -255,7 +255,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -276,7 +278,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class MathUtils extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index 1be36c28..f867e883 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -255,7 +255,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -276,7 +278,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class MathUtils extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js index 12afbb82..462c5ecf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js @@ -214,7 +214,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -235,7 +237,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class PropertyClass extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js index e9c5d105..542252c3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js @@ -214,7 +214,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -235,7 +237,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class PropertyClass extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index cd6c9062..a5f9916f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -237,7 +237,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -258,7 +260,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class Greeter extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 68bcfbe9..fe206962 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -888,7 +888,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -909,7 +911,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class Person extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index dbbbd6bc..035abac2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -483,7 +483,9 @@ export async function createInstantiator(options, swift) { return; } state.hasReleased = true; - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} }); /// Represents a Swift heap object like a class instance or an actor instance. @@ -504,7 +506,9 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); - state.deinit(state.pointer); + try { + state.deinit(state.pointer); + } catch {} } } class Greeter extends SwiftHeapObject { diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 8a775c15..597fbf90 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -11252,6 +11252,18 @@ fileprivate func bjs_SwiftClassSupportImports_jsRoundTripOptionalGreeter_static_ return bjs_SwiftClassSupportImports_jsRoundTripOptionalGreeter_static_extern(greeterIsSome, greeterPointer) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_SwiftClassSupportImports_jsSabotageAndReleaseGreeter_static") +fileprivate func bjs_SwiftClassSupportImports_jsSabotageAndReleaseGreeter_static_extern(_ greeter: UnsafeMutableRawPointer) -> Void +#else +fileprivate func bjs_SwiftClassSupportImports_jsSabotageAndReleaseGreeter_static_extern(_ greeter: UnsafeMutableRawPointer) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_SwiftClassSupportImports_jsSabotageAndReleaseGreeter_static(_ greeter: UnsafeMutableRawPointer) -> Void { + return bjs_SwiftClassSupportImports_jsSabotageAndReleaseGreeter_static_extern(greeter) +} + func _$SwiftClassSupportImports_jsRoundTripGreeter(_ greeter: Greeter) throws(JSException) -> Greeter { let greeterPointer = greeter.bridgeJSLowerParameter() let ret = bjs_SwiftClassSupportImports_jsRoundTripGreeter_static(greeterPointer) @@ -11268,4 +11280,12 @@ func _$SwiftClassSupportImports_jsRoundTripOptionalGreeter(_ greeter: Optional.bridgeJSLiftReturn(ret) +} + +func _$SwiftClassSupportImports_jsSabotageAndReleaseGreeter(_ greeter: Greeter) throws(JSException) -> Void { + let greeterPointer = greeter.bridgeJSLowerParameter() + bjs_SwiftClassSupportImports_jsSabotageAndReleaseGreeter_static(greeterPointer) + if let error = _swift_js_take_exception() { + throw error + } } \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 45acc8a9..89665300 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -15643,6 +15643,24 @@ "_1" : "null" } } + }, + { + "name" : "jsSabotageAndReleaseGreeter", + "parameters" : [ + { + "name" : "greeter", + "type" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + ], + "returnType" : { + "void" : { + + } + } } ] } diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/SwiftClassSupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/SwiftClassSupportTests.mjs index 0368cb74..7d42f2f9 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/SwiftClassSupportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/SwiftClassSupportTests.mjs @@ -9,5 +9,11 @@ export function getImports(importsContext) { jsRoundTripOptionalGreeter: (greeter) => { return greeter; }, + jsSabotageAndReleaseGreeter: (greeter) => { + greeter.__swiftHeapObjectState.deinit = () => { + throw new WebAssembly.RuntimeError("simulated Wasm teardown"); + }; + greeter.release(); + }, }; -} \ No newline at end of file +} diff --git a/Tests/BridgeJSRuntimeTests/SwiftClassSupportTests.swift b/Tests/BridgeJSRuntimeTests/SwiftClassSupportTests.swift index d9a68b1c..eeacef3d 100644 --- a/Tests/BridgeJSRuntimeTests/SwiftClassSupportTests.swift +++ b/Tests/BridgeJSRuntimeTests/SwiftClassSupportTests.swift @@ -4,6 +4,7 @@ import JavaScriptKit @JSClass struct SwiftClassSupportImports { @JSFunction static func jsRoundTripGreeter(_ greeter: Greeter) throws(JSException) -> Greeter @JSFunction static func jsRoundTripOptionalGreeter(_ greeter: Greeter?) throws(JSException) -> Greeter? + @JSFunction static func jsSabotageAndReleaseGreeter(_ greeter: Greeter) throws(JSException) } @JSFunction(from: .global) func gc() throws(JSException) -> Void @@ -28,6 +29,15 @@ final class SwiftClassSupportTests: XCTestCase { XCTAssertEqual(jsGreeter["name"].string, "BridgeJS") } + func testReleaseHandlesThrowingDeinit() throws { + // Verify that release() catches errors from deinit. The JS side replaces the + // wrapper's deinit to throw WebAssembly.RuntimeError after calling the real one + // (same error as calling into torn-down Wasm memory). Without the try/catch + // guard in release(), this crashes the process. + let greeter = Greeter(name: "Test") + try SwiftClassSupportImports.jsSabotageAndReleaseGreeter(greeter) + } + func testJSWrapperIsDeallocatedAfterFinalization() async throws { weak var weakGreeter: Greeter? var wrapperObject: JSObject?