From 67fad18cf23ebe8c87b548c58fbdb83421998dc1 Mon Sep 17 00:00:00 2001 From: Shivanshu <112751483+shivanshu877@users.noreply.github.com> Date: Sun, 10 May 2026 03:46:02 +0530 Subject: [PATCH 1/7] fix: add isMutating to Effects for mutating struct method support Adds `isMutating: Bool` to the `Effects` struct with backward-compatible Codable implementation. The field is only serialised when true, so existing JSON snapshots are unaffected. Old JSON without the key decodes cleanly via `decodeIfPresent(...) ?? false`. Part of the fix for swiftwasm/JavaScriptKit#736. --- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 346b7333b..d132888b3 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -635,11 +635,35 @@ public struct Effects: Codable, Equatable, Sendable { public var isAsync: Bool public var isThrows: Bool public var isStatic: Bool + public var isMutating: Bool - public init(isAsync: Bool, isThrows: Bool, isStatic: Bool = false) { + public init(isAsync: Bool, isThrows: Bool, isStatic: Bool = false, isMutating: Bool = false) { self.isAsync = isAsync self.isThrows = isThrows self.isStatic = isStatic + self.isMutating = isMutating + } + + private enum CodingKeys: String, CodingKey { + case isAsync, isThrows, isStatic, isMutating + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.isAsync = try container.decode(Bool.self, forKey: .isAsync) + self.isThrows = try container.decode(Bool.self, forKey: .isThrows) + self.isStatic = try container.decode(Bool.self, forKey: .isStatic) + self.isMutating = try container.decodeIfPresent(Bool.self, forKey: .isMutating) ?? false + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(isAsync, forKey: .isAsync) + try container.encode(isThrows, forKey: .isThrows) + try container.encode(isStatic, forKey: .isStatic) + if isMutating { + try container.encode(isMutating, forKey: .isMutating) + } } } From cd676829f9124561398ac4c0bdffc911a2a5ca69 Mon Sep 17 00:00:00 2001 From: Shivanshu <112751483+shivanshu877@users.noreply.github.com> Date: Sun, 10 May 2026 03:51:58 +0530 Subject: [PATCH 2/7] test: add snapshot test input for mutating struct methods --- .../Inputs/MacroSwift/MutatingStructMethod.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/MutatingStructMethod.swift diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/MutatingStructMethod.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/MutatingStructMethod.swift new file mode 100644 index 000000000..23d2e6538 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/MutatingStructMethod.swift @@ -0,0 +1,12 @@ +@JS struct Counter { + var number: Int +} + +extension Counter { + @JS public mutating func increment() { + number += 1 + } + @JS public mutating func add(_ value: Int) { + number += value + } +} From ea9836509893e394ee6b6e19821d6ecaff69ada5 Mon Sep 17 00:00:00 2001 From: Shivanshu <112751483+shivanshu877@users.noreply.github.com> Date: Sun, 10 May 2026 03:57:33 +0530 Subject: [PATCH 3/7] fix: generate mutable self binding for @JS mutating struct methods --- .../Sources/BridgeJSCore/ExportSwift.swift | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index b649b244d..3b1d87de3 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -228,14 +228,24 @@ public class ExportSwift { } } - func callMethod(methodName: String, returnType: BridgeType) { - let (_, selfExpr) = removeFirstLiftedParameter() - generateParameterLifting() - let item = renderCallStatement( - callee: "\(raw: selfExpr).\(raw: methodName)", - returnType: returnType - ) - append(item) + func callMethod(methodName: String, returnType: BridgeType, isMutating: Bool = false) { + let (selfParam, selfExpr) = removeFirstLiftedParameter() + if isMutating, case .swiftStruct = selfParam.type { + append("var _self = \(selfExpr)") + generateParameterLifting() + let item = renderCallStatement( + callee: "_self.\(raw: methodName)", + returnType: returnType + ) + append(item) + } else { + generateParameterLifting() + let item = renderCallStatement( + callee: "\(raw: selfExpr).\(raw: methodName)", + returnType: returnType + ) + append(item) + } } /// Generates intermediate variables for stack-using parameters if needed for LIFO compatibility @@ -561,7 +571,7 @@ public class ExportSwift { if method.effects.isStatic { builder.call(name: "\(ownerTypeName).\(method.name)", returnType: method.returnType) } else { - builder.callMethod(methodName: method.name, returnType: method.returnType) + builder.callMethod(methodName: method.name, returnType: method.returnType, isMutating: method.effects.isMutating) } try builder.lowerReturnValue(returnType: method.returnType) return builder.render(abiName: method.abiName) From 360e459b194c4011b285f0d03680ba09e9ba28b5 Mon Sep 17 00:00:00 2001 From: Shivanshu <112751483+shivanshu877@users.noreply.github.com> Date: Sun, 10 May 2026 04:00:04 +0530 Subject: [PATCH 4/7] fix: detect mutating modifier in collectEffects for struct methods --- .../BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index f39ac16f8..2fa051e33 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -1198,7 +1198,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { className: classNameForABI ) - guard let effects = collectEffects(signature: node.signature, isStatic: isStatic) else { + let isMutating = node.modifiers.contains { $0.name.tokenKind == .keyword(.mutating) } + guard let effects = collectEffects(signature: node.signature, isStatic: isStatic, isMutating: isMutating) else { return nil } @@ -1213,7 +1214,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { ) } - private func collectEffects(signature: FunctionSignatureSyntax, isStatic: Bool = false) -> Effects? { + private func collectEffects(signature: FunctionSignatureSyntax, isStatic: Bool = false, isMutating: Bool = false) -> Effects? { let isAsync = signature.effectSpecifiers?.asyncSpecifier != nil var isThrows = false if let throwsClause: ThrowsClauseSyntax = signature.effectSpecifiers?.throwsClause { @@ -1234,7 +1235,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } isThrows = true } - return Effects(isAsync: isAsync, isThrows: isThrows, isStatic: isStatic) + return Effects(isAsync: isAsync, isThrows: isThrows, isStatic: isStatic, isMutating: isMutating) } private func extractNamespace( @@ -1522,7 +1523,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } } - /// Walks extension members under the matching type’s state, returning whether the type was found. + /// Walks extension members under the matching type's state, returning whether the type was found. /// /// Note: The lookup scans dictionaries keyed by `makeKey(name:namespace:)`, matching only by /// plain name. If two types share a name but differ by namespace, `.first(where:)` picks From 7fffe0c5d72bad236d12fc818f09cc18e11ca1ff Mon Sep 17 00:00:00 2001 From: Shivanshu <112751483+shivanshu877@users.noreply.github.com> Date: Sat, 16 May 2026 10:32:12 +0530 Subject: [PATCH 5/7] fix: emit diagnostic for @JS mutating struct methods instead of generating broken code Per reviewer feedback (wfltaylor): mutations to `_self` are not propagated back to JavaScript, so the mutable-self binding approach silently discards all mutations. Replace it with a clear compile-time diagnostic pointing users to a value-returning redesign. --- .../Sources/BridgeJSCore/ExportSwift.swift | 28 ++++++------------- .../BridgeJSCore/SwiftToSkeleton.swift | 15 +++++++--- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 3b1d87de3..b649b244d 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -228,24 +228,14 @@ public class ExportSwift { } } - func callMethod(methodName: String, returnType: BridgeType, isMutating: Bool = false) { - let (selfParam, selfExpr) = removeFirstLiftedParameter() - if isMutating, case .swiftStruct = selfParam.type { - append("var _self = \(selfExpr)") - generateParameterLifting() - let item = renderCallStatement( - callee: "_self.\(raw: methodName)", - returnType: returnType - ) - append(item) - } else { - generateParameterLifting() - let item = renderCallStatement( - callee: "\(raw: selfExpr).\(raw: methodName)", - returnType: returnType - ) - append(item) - } + func callMethod(methodName: String, returnType: BridgeType) { + let (_, selfExpr) = removeFirstLiftedParameter() + generateParameterLifting() + let item = renderCallStatement( + callee: "\(raw: selfExpr).\(raw: methodName)", + returnType: returnType + ) + append(item) } /// Generates intermediate variables for stack-using parameters if needed for LIFO compatibility @@ -571,7 +561,7 @@ public class ExportSwift { if method.effects.isStatic { builder.call(name: "\(ownerTypeName).\(method.name)", returnType: method.returnType) } else { - builder.callMethod(methodName: method.name, returnType: method.returnType, isMutating: method.effects.isMutating) + builder.callMethod(methodName: method.name, returnType: method.returnType) } try builder.lowerReturnValue(returnType: method.returnType) return builder.render(abiName: method.abiName) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 2fa051e33..aa696ec31 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -1198,8 +1198,15 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { className: classNameForABI ) - let isMutating = node.modifiers.contains { $0.name.tokenKind == .keyword(.mutating) } - guard let effects = collectEffects(signature: node.signature, isStatic: isStatic, isMutating: isMutating) else { + if let mutatingModifier = node.modifiers.first(where: { $0.name.tokenKind == .keyword(.mutating) }) { + diagnose( + node: mutatingModifier, + message: "@JS does not support mutating struct methods: mutations to 'self' cannot be propagated back to JavaScript", + hint: "Remove the mutating keyword or redesign the API to return the updated value instead" + ) + return nil + } + guard let effects = collectEffects(signature: node.signature, isStatic: isStatic) else { return nil } @@ -1214,7 +1221,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { ) } - private func collectEffects(signature: FunctionSignatureSyntax, isStatic: Bool = false, isMutating: Bool = false) -> Effects? { + private func collectEffects(signature: FunctionSignatureSyntax, isStatic: Bool = false) -> Effects? { let isAsync = signature.effectSpecifiers?.asyncSpecifier != nil var isThrows = false if let throwsClause: ThrowsClauseSyntax = signature.effectSpecifiers?.throwsClause { @@ -1235,7 +1242,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } isThrows = true } - return Effects(isAsync: isAsync, isThrows: isThrows, isStatic: isStatic, isMutating: isMutating) + return Effects(isAsync: isAsync, isThrows: isThrows, isStatic: isStatic) } private func extractNamespace( From 7d815cada9395a29c2f27d29a762122bf2002b62 Mon Sep 17 00:00:00 2001 From: Shivanshu <112751483+shivanshu877@users.noreply.github.com> Date: Sat, 16 May 2026 10:38:09 +0530 Subject: [PATCH 6/7] fix: emit diagnostic for @JS mutating struct methods instead of generating broken code Per reviewer feedback (wfltaylor): mutations to `_self` are not propagated back to JavaScript, so the mutable-self binding approach silently discards all mutations. Replace it with a clear compile-time diagnostic pointing users to a value-returning redesign. From f85dfef72bb553491435cda7def1bc48c9f3031a Mon Sep 17 00:00:00 2001 From: shivanshu877 Date: Fri, 22 May 2026 16:00:13 +0530 Subject: [PATCH 7/7] test(bridgejs): commit MutatingStructMethod snapshots and add diagnostic e2e tests - Commit the four auto-generated snapshot fixtures (json/swift/d.ts/js) that were missing for the MutatingStructMethod input. - Add three e2e tests in DiagnosticsTests.swift covering: * emission of BridgeJSCoreDiagnosticError for a mutating struct method, * the exact diagnostic message and hint text, * regression guard that non-mutating struct methods still pass. Tests follow the same shape as structInitMismatchedOrderProducesDiagnostic. Per @krodak review on #743. --- .../BridgeJSToolTests/DiagnosticsTests.swift | 93 +++++++ .../MutatingStructMethod.json | 45 ++++ .../MutatingStructMethod.swift | 45 ++++ .../MutatingStructMethod.d.ts | 20 ++ .../BridgeJSLinkTests/MutatingStructMethod.js | 230 ++++++++++++++++++ 5 files changed, 433 insertions(+) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MutatingStructMethod.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MutatingStructMethod.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MutatingStructMethod.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MutatingStructMethod.js diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift index e71a1f84e..8acc9ea13 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift @@ -319,4 +319,97 @@ import Testing // No line 3 in source, so output must not show a " 3 |" context line after the pointer #expect(!description.contains(" 3 |")) } + + // MARK: - Mutating struct method diagnostic + + /// `@JS` on a `mutating` struct method cannot be supported: the JS-side + /// bridge calls a Swift function whose `self` was lowered across the WASM + /// boundary, so mutations to `self` cannot be propagated back to the + /// JavaScript caller. The codegen detects the `mutating` modifier and + /// emits an explicit diagnostic pointing the user at the right fix, + /// rather than silently producing a thunk that would discard their + /// mutations at runtime. + @Test + func mutatingStructMethodEmitsDiagnostic() throws { + let source = """ + @JS struct Counter { + var number: Int + + @JS public mutating func increment() { + number += 1 + } + } + """ + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "test.swift") + #expect(throws: BridgeJSCoreDiagnosticError.self) { + _ = try swiftAPI.finalize() + } + } + + @Test + func mutatingStructMethodDiagnosticMessageAndHint() throws { + let source = """ + @JS struct Counter { + var number: Int + + @JS public mutating func increment() { + number += 1 + } + } + """ + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "test.swift") + do { + _ = try swiftAPI.finalize() + Issue.record("Expected finalize() to throw for a mutating @JS struct method") + } catch let error as BridgeJSCoreDiagnosticError { + let allMessages = error.diagnostics.map { $0.diagnostic.message }.joined(separator: "\n") + #expect( + allMessages.contains( + "@JS does not support mutating struct methods: mutations to 'self' cannot be propagated back to JavaScript" + ) + ) + let allHints = error.diagnostics.compactMap { $0.diagnostic.hint }.joined(separator: "\n") + #expect( + allHints.contains( + "Remove the mutating keyword or redesign the API to return the updated value instead" + ) + ) + } + } + + @Test + func nonMutatingStructMethodSucceeds() throws { + // Regression guard: an otherwise-identical struct method WITHOUT the + // `mutating` modifier should still pass through the codegen cleanly. + let source = """ + @JS struct Counter { + var number: Int + + @JS public func describe() -> String { + return "Counter(\\(number))" + } + } + """ + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "test.swift") + let skeleton = try swiftAPI.finalize() + #expect(skeleton.exported != nil) + } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MutatingStructMethod.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MutatingStructMethod.json new file mode 100644 index 000000000..3e360fd00 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MutatingStructMethod.json @@ -0,0 +1,45 @@ +{ + "exported" : { + "classes" : [ + + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + { + "methods" : [ + + ], + "name" : "Counter", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "number", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "Counter" + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MutatingStructMethod.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MutatingStructMethod.swift new file mode 100644 index 000000000..c77ec562f --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MutatingStructMethod.swift @@ -0,0 +1,45 @@ +extension Counter: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Counter { + let number = Int.bridgeJSStackPop() + return Counter(number: number) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.number.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Counter(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Counter())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Counter") +fileprivate func _bjs_struct_lower_Counter_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Counter_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Counter(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Counter_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Counter") +fileprivate func _bjs_struct_lift_Counter_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Counter_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Counter() -> Int32 { + return _bjs_struct_lift_Counter_extern() +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MutatingStructMethod.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MutatingStructMethod.d.ts new file mode 100644 index 000000000..25d90921a --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MutatingStructMethod.d.ts @@ -0,0 +1,20 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export interface Counter { + number: number; +} +export type Exports = { +} +export type Imports = { +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MutatingStructMethod.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MutatingStructMethod.js new file mode 100644 index 000000000..0b11f90fa --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MutatingStructMethod.js @@ -0,0 +1,230 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + let decodeString; + const textDecoder = new TextDecoder("utf-8"); + const textEncoder = new TextEncoder("utf-8"); + let tmpRetString; + let tmpRetBytes; + let tmpRetException; + let tmpRetOptionalBool; + let tmpRetOptionalInt; + let tmpRetOptionalFloat; + let tmpRetOptionalDouble; + let tmpRetOptionalHeapObject; + let strStack = []; + let i32Stack = []; + let i64Stack = []; + let f32Stack = []; + let f64Stack = []; + let ptrStack = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + const __bjs_createCounterHelpers = () => ({ + lower: (value) => { + i32Stack.push((value.number | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return { number: int }; + } + }); + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + bjs["swift_js_return_string"] = function(ptr, len) { + tmpRetString = decodeString(ptr, len); + } + bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { + const source = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const bytes = new Uint8Array(memory.buffer, bytesPtr); + bytes.set(source); + } + bjs["swift_js_make_js_string"] = function(ptr, len) { + return swift.memory.retain(decodeString(ptr, len)); + } + bjs["swift_js_init_memory_with_result"] = function(ptr, len) { + const target = new Uint8Array(memory.buffer, ptr, len); + target.set(tmpRetBytes); + tmpRetBytes = undefined; + } + bjs["swift_js_throw"] = function(id) { + tmpRetException = swift.memory.retainByRef(id); + } + bjs["swift_js_retain"] = function(id) { + return swift.memory.retainByRef(id); + } + bjs["swift_js_release"] = function(id) { + swift.memory.release(id); + } + bjs["swift_js_push_i32"] = function(v) { + i32Stack.push(v | 0); + } + bjs["swift_js_push_f32"] = function(v) { + f32Stack.push(Math.fround(v)); + } + bjs["swift_js_push_f64"] = function(v) { + f64Stack.push(v); + } + bjs["swift_js_push_string"] = function(ptr, len) { + const value = decodeString(ptr, len); + strStack.push(value); + } + bjs["swift_js_pop_i32"] = function() { + return i32Stack.pop(); + } + bjs["swift_js_pop_f32"] = function() { + return f32Stack.pop(); + } + bjs["swift_js_pop_f64"] = function() { + return f64Stack.pop(); + } + bjs["swift_js_push_pointer"] = function(pointer) { + ptrStack.push(pointer); + } + bjs["swift_js_pop_pointer"] = function() { + return ptrStack.pop(); + } + bjs["swift_js_push_i64"] = function(v) { + i64Stack.push(v); + } + bjs["swift_js_pop_i64"] = function() { + return i64Stack.pop(); + } + bjs["swift_js_struct_lower_Counter"] = function(objectId) { + structHelpers.Counter.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Counter"] = function() { + const value = structHelpers.Counter.lift(); + return swift.memory.retain(value); + } + bjs["swift_js_return_optional_bool"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalBool = null; + } else { + tmpRetOptionalBool = value !== 0; + } + } + bjs["swift_js_return_optional_int"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalInt = null; + } else { + tmpRetOptionalInt = value | 0; + } + } + bjs["swift_js_return_optional_float"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalFloat = null; + } else { + tmpRetOptionalFloat = Math.fround(value); + } + } + bjs["swift_js_return_optional_double"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalDouble = null; + } else { + tmpRetOptionalDouble = value; + } + } + bjs["swift_js_return_optional_string"] = function(isSome, ptr, len) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = decodeString(ptr, len); + } + } + bjs["swift_js_return_optional_object"] = function(isSome, objectId) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = swift.memory.getObject(objectId); + } + } + bjs["swift_js_return_optional_heap_object"] = function(isSome, pointer) { + if (isSome === 0) { + tmpRetOptionalHeapObject = null; + } else { + tmpRetOptionalHeapObject = pointer; + } + } + bjs["swift_js_get_optional_int_presence"] = function() { + return tmpRetOptionalInt != null ? 1 : 0; + } + bjs["swift_js_get_optional_int_value"] = function() { + const value = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return value; + } + bjs["swift_js_get_optional_string"] = function() { + const str = tmpRetString; + tmpRetString = undefined; + if (str == null) { + return -1; + } else { + const bytes = textEncoder.encode(str); + tmpRetBytes = bytes; + return bytes.length; + } + } + bjs["swift_js_get_optional_float_presence"] = function() { + return tmpRetOptionalFloat != null ? 1 : 0; + } + bjs["swift_js_get_optional_float_value"] = function() { + const value = tmpRetOptionalFloat; + tmpRetOptionalFloat = undefined; + return value; + } + bjs["swift_js_get_optional_double_presence"] = function() { + return tmpRetOptionalDouble != null ? 1 : 0; + } + bjs["swift_js_get_optional_double_value"] = function() { + const value = tmpRetOptionalDouble; + tmpRetOptionalDouble = undefined; + return value; + } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } + bjs["swift_js_closure_unregister"] = function(funcRef) {} + }, + setInstance: (i) => { + instance = i; + memory = instance.exports.memory; + + decodeString = (ptr, len) => { const bytes = new Uint8Array(memory.buffer, ptr >>> 0, len >>> 0); return textDecoder.decode(bytes); } + + setException = (error) => { + instance.exports._swift_js_exception.value = swift.memory.retain(error) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const CounterHelpers = __bjs_createCounterHelpers(); + structHelpers.Counter = CounterHelpers; + + const exports = { + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file