Skip to content

Commit aa961dc

Browse files
[NFC] BridgeJS: Work around extern inlining by adding an extra non-inlined layer of indirection
1 parent 2a92246 commit aa961dc

Some content is hidden

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

49 files changed

+2676
-1119
lines changed

Benchmarks/Sources/Generated/BridgeJS.swift

Lines changed: 110 additions & 44 deletions
Large diffs are not rendered by default.

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

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,27 @@ extension PlayBridgeJSOutput: _BridgedSwiftStruct {
3737

3838
#if arch(wasm32)
3939
@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_PlayBridgeJSOutput")
40-
fileprivate func _bjs_struct_lower_PlayBridgeJSOutput(_ objectId: Int32) -> Void
40+
fileprivate func _bjs_struct_lower_PlayBridgeJSOutput_extern(_ objectId: Int32) -> Void
4141
#else
42-
fileprivate func _bjs_struct_lower_PlayBridgeJSOutput(_ objectId: Int32) -> Void {
42+
fileprivate func _bjs_struct_lower_PlayBridgeJSOutput_extern(_ objectId: Int32) -> Void {
4343
fatalError("Only available on WebAssembly")
4444
}
4545
#endif
46+
@inline(never) fileprivate func _bjs_struct_lower_PlayBridgeJSOutput(_ objectId: Int32) -> Void {
47+
return _bjs_struct_lower_PlayBridgeJSOutput_extern(objectId)
48+
}
4649

4750
#if arch(wasm32)
4851
@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_PlayBridgeJSOutput")
49-
fileprivate func _bjs_struct_lift_PlayBridgeJSOutput() -> Int32
52+
fileprivate func _bjs_struct_lift_PlayBridgeJSOutput_extern() -> Int32
5053
#else
51-
fileprivate func _bjs_struct_lift_PlayBridgeJSOutput() -> Int32 {
54+
fileprivate func _bjs_struct_lift_PlayBridgeJSOutput_extern() -> Int32 {
5255
fatalError("Only available on WebAssembly")
5356
}
5457
#endif
58+
@inline(never) fileprivate func _bjs_struct_lift_PlayBridgeJSOutput() -> Int32 {
59+
return _bjs_struct_lift_PlayBridgeJSOutput_extern()
60+
}
5561

5662
extension PlayBridgeJSDiagnostic: _BridgedSwiftStruct {
5763
@_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> PlayBridgeJSDiagnostic {
@@ -87,21 +93,27 @@ extension PlayBridgeJSDiagnostic: _BridgedSwiftStruct {
8793

8894
#if arch(wasm32)
8995
@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_PlayBridgeJSDiagnostic")
90-
fileprivate func _bjs_struct_lower_PlayBridgeJSDiagnostic(_ objectId: Int32) -> Void
96+
fileprivate func _bjs_struct_lower_PlayBridgeJSDiagnostic_extern(_ objectId: Int32) -> Void
9197
#else
92-
fileprivate func _bjs_struct_lower_PlayBridgeJSDiagnostic(_ objectId: Int32) -> Void {
98+
fileprivate func _bjs_struct_lower_PlayBridgeJSDiagnostic_extern(_ objectId: Int32) -> Void {
9399
fatalError("Only available on WebAssembly")
94100
}
95101
#endif
102+
@inline(never) fileprivate func _bjs_struct_lower_PlayBridgeJSDiagnostic(_ objectId: Int32) -> Void {
103+
return _bjs_struct_lower_PlayBridgeJSDiagnostic_extern(objectId)
104+
}
96105

97106
#if arch(wasm32)
98107
@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_PlayBridgeJSDiagnostic")
99-
fileprivate func _bjs_struct_lift_PlayBridgeJSDiagnostic() -> Int32
108+
fileprivate func _bjs_struct_lift_PlayBridgeJSDiagnostic_extern() -> Int32
100109
#else
101-
fileprivate func _bjs_struct_lift_PlayBridgeJSDiagnostic() -> Int32 {
110+
fileprivate func _bjs_struct_lift_PlayBridgeJSDiagnostic_extern() -> Int32 {
102111
fatalError("Only available on WebAssembly")
103112
}
104113
#endif
114+
@inline(never) fileprivate func _bjs_struct_lift_PlayBridgeJSDiagnostic() -> Int32 {
115+
return _bjs_struct_lift_PlayBridgeJSDiagnostic_extern()
116+
}
105117

106118
extension PlayBridgeJSResult: _BridgedSwiftStruct {
107119
@_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> PlayBridgeJSResult {
@@ -129,21 +141,27 @@ extension PlayBridgeJSResult: _BridgedSwiftStruct {
129141

130142
#if arch(wasm32)
131143
@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_PlayBridgeJSResult")
132-
fileprivate func _bjs_struct_lower_PlayBridgeJSResult(_ objectId: Int32) -> Void
144+
fileprivate func _bjs_struct_lower_PlayBridgeJSResult_extern(_ objectId: Int32) -> Void
133145
#else
134-
fileprivate func _bjs_struct_lower_PlayBridgeJSResult(_ objectId: Int32) -> Void {
146+
fileprivate func _bjs_struct_lower_PlayBridgeJSResult_extern(_ objectId: Int32) -> Void {
135147
fatalError("Only available on WebAssembly")
136148
}
137149
#endif
150+
@inline(never) fileprivate func _bjs_struct_lower_PlayBridgeJSResult(_ objectId: Int32) -> Void {
151+
return _bjs_struct_lower_PlayBridgeJSResult_extern(objectId)
152+
}
138153

139154
#if arch(wasm32)
140155
@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_PlayBridgeJSResult")
141-
fileprivate func _bjs_struct_lift_PlayBridgeJSResult() -> Int32
156+
fileprivate func _bjs_struct_lift_PlayBridgeJSResult_extern() -> Int32
142157
#else
143-
fileprivate func _bjs_struct_lift_PlayBridgeJSResult() -> Int32 {
158+
fileprivate func _bjs_struct_lift_PlayBridgeJSResult_extern() -> Int32 {
144159
fatalError("Only available on WebAssembly")
145160
}
146161
#endif
162+
@inline(never) fileprivate func _bjs_struct_lift_PlayBridgeJSResult() -> Int32 {
163+
return _bjs_struct_lift_PlayBridgeJSResult_extern()
164+
}
147165

148166
@_expose(wasm, "bjs_PlayBridgeJS_init")
149167
@_cdecl("bjs_PlayBridgeJS_init")
@@ -199,21 +217,27 @@ extension PlayBridgeJS: ConvertibleToJSValue, _BridgedSwiftHeapObject {
199217

200218
#if arch(wasm32)
201219
@_extern(wasm, module: "PlayBridgeJS", name: "bjs_PlayBridgeJS_wrap")
202-
fileprivate func _bjs_PlayBridgeJS_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32
220+
fileprivate func _bjs_PlayBridgeJS_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32
203221
#else
204-
fileprivate func _bjs_PlayBridgeJS_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 {
222+
fileprivate func _bjs_PlayBridgeJS_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 {
205223
fatalError("Only available on WebAssembly")
206224
}
207225
#endif
226+
@inline(never) fileprivate func _bjs_PlayBridgeJS_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 {
227+
return _bjs_PlayBridgeJS_wrap_extern(pointer)
228+
}
208229

209230
#if arch(wasm32)
210231
@_extern(wasm, module: "PlayBridgeJS", name: "bjs_createTS2Swift")
211-
fileprivate func bjs_createTS2Swift() -> Int32
232+
fileprivate func bjs_createTS2Swift_extern() -> Int32
212233
#else
213-
fileprivate func bjs_createTS2Swift() -> Int32 {
234+
fileprivate func bjs_createTS2Swift_extern() -> Int32 {
214235
fatalError("Only available on WebAssembly")
215236
}
216237
#endif
238+
@inline(never) fileprivate func bjs_createTS2Swift() -> Int32 {
239+
return bjs_createTS2Swift_extern()
240+
}
217241

218242
func _$createTS2Swift() throws(JSException) -> TS2Swift {
219243
let ret = bjs_createTS2Swift()
@@ -225,12 +249,15 @@ func _$createTS2Swift() throws(JSException) -> TS2Swift {
225249

226250
#if arch(wasm32)
227251
@_extern(wasm, module: "PlayBridgeJS", name: "bjs_TS2Swift_convert")
228-
fileprivate func bjs_TS2Swift_convert(_ self: Int32, _ ts: Int32) -> Int32
252+
fileprivate func bjs_TS2Swift_convert_extern(_ self: Int32, _ ts: Int32) -> Int32
229253
#else
230-
fileprivate func bjs_TS2Swift_convert(_ self: Int32, _ ts: Int32) -> Int32 {
254+
fileprivate func bjs_TS2Swift_convert_extern(_ self: Int32, _ ts: Int32) -> Int32 {
231255
fatalError("Only available on WebAssembly")
232256
}
233257
#endif
258+
@inline(never) fileprivate func bjs_TS2Swift_convert(_ self: Int32, _ ts: Int32) -> Int32 {
259+
return bjs_TS2Swift_convert_extern(self, ts)
260+
}
234261

235262
func _$TS2Swift_convert(_ self: JSObject, _ ts: String) throws(JSException) -> String {
236263
let selfValue = self.bridgeJSLowerParameter()

Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ public struct ClosureCodegen {
5353
moduleName: "bjs",
5454
abiName: externABIName,
5555
functionName: externABIName,
56-
signature: "(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer<UInt8>, _ line: UInt32) -> Int32"
56+
signature: "(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer<UInt8>, _ line: UInt32) -> Int32",
57+
parameterNames: ["boxPtr", "file", "line"]
5758
)
5859
let makeClosureExternDecl: DeclSyntax = "\(raw: externDeclPrinter.lines.joined(separator: "\n"))"
5960

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 18 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -695,18 +695,14 @@ public class ExportSwift {
695695
}
696696
"""
697697
// Build common function signature
698-
let funcSignature = SwiftSignatureBuilder.buildABIFunctionSignature(
699-
abiParameters: [("pointer", .pointer)],
700-
returnType: .i32
701-
)
702-
703698
let externDeclPrinter = CodeFragmentPrinter()
704699
SwiftCodePattern.buildExternFunctionDecl(
705700
printer: externDeclPrinter,
706701
moduleName: moduleName,
707702
abiName: externFunctionName,
708703
functionName: wrapFunctionName,
709-
signature: funcSignature
704+
abiParameters: [("pointer", .pointer)],
705+
returnType: .i32
710706
)
711707
let externDecl: DeclSyntax = "\(raw: externDeclPrinter.lines.joined(separator: "\n"))"
712708
return [extensionDecl, externDecl]
@@ -1251,24 +1247,22 @@ struct StructCodegen {
12511247
let bridgedStructExtension: DeclSyntax = "\(raw: printer.lines.joined(separator: "\n"))"
12521248

12531249
let lowerExternDeclPrinter = CodeFragmentPrinter()
1254-
Self.renderStructExtern(
1250+
SwiftCodePattern.buildExternFunctionDecl(
12551251
printer: lowerExternDeclPrinter,
1256-
externName: lowerExternName,
1252+
moduleName: "bjs",
1253+
abiName: lowerExternName,
12571254
functionName: lowerFunctionName,
1258-
signature: SwiftSignatureBuilder.buildABIFunctionSignature(
1259-
abiParameters: [("objectId", .i32)],
1260-
returnType: nil
1261-
)
1255+
abiParameters: [("objectId", .i32)],
1256+
returnType: nil
12621257
)
12631258
let liftExternDeclPrinter = CodeFragmentPrinter()
1264-
Self.renderStructExtern(
1259+
SwiftCodePattern.buildExternFunctionDecl(
12651260
printer: liftExternDeclPrinter,
1266-
externName: liftExternName,
1261+
moduleName: "bjs",
1262+
abiName: liftExternName,
12671263
functionName: liftFunctionName,
1268-
signature: SwiftSignatureBuilder.buildABIFunctionSignature(
1269-
abiParameters: [],
1270-
returnType: .i32
1271-
)
1264+
abiParameters: [],
1265+
returnType: .i32
12721266
)
12731267

12741268
return [
@@ -1277,21 +1271,6 @@ struct StructCodegen {
12771271
]
12781272
}
12791273

1280-
private static func renderStructExtern(
1281-
printer: CodeFragmentPrinter,
1282-
externName: String,
1283-
functionName: String,
1284-
signature: String
1285-
) {
1286-
SwiftCodePattern.buildExternFunctionDecl(
1287-
printer: printer,
1288-
moduleName: "bjs",
1289-
abiName: externName,
1290-
functionName: functionName,
1291-
signature: signature
1292-
)
1293-
}
1294-
12951274
private func generateStructLiftCode(structDef: ExportedStruct) -> [String] {
12961275
var lines: [String] = []
12971276
let instanceProps = structDef.properties.filter { !$0.isStatic }
@@ -1357,17 +1336,14 @@ struct ProtocolCodegen {
13571336
)
13581337

13591338
// Build extern declaration using helper function
1360-
let externSignature = SwiftSignatureBuilder.buildABIFunctionSignature(
1361-
abiParameters: builder.abiParameterSignatures,
1362-
returnType: builder.abiReturnType
1363-
)
13641339
let externDeclPrinter = CodeFragmentPrinter()
13651340
SwiftCodePattern.buildExternFunctionDecl(
13661341
printer: externDeclPrinter,
13671342
moduleName: moduleName,
13681343
abiName: method.abiName,
13691344
functionName: "_extern_\(method.name)",
1370-
signature: externSignature
1345+
abiParameters: builder.abiParameterSignatures,
1346+
returnType: builder.abiReturnType
13711347
)
13721348
externDecls.append(DeclSyntax("\(raw: externDeclPrinter.lines.joined(separator: "\n"))"))
13731349
let methodImplPrinter = CodeFragmentPrinter()
@@ -1448,17 +1424,14 @@ struct ProtocolCodegen {
14481424
try getterBuilder.liftReturnValue(returnType: property.type)
14491425

14501426
// Build getter extern declaration using helper function
1451-
let getterExternSignature = SwiftSignatureBuilder.buildABIFunctionSignature(
1452-
abiParameters: getterBuilder.abiParameterSignatures,
1453-
returnType: getterBuilder.abiReturnType
1454-
)
14551427
let getterExternDeclPrinter = CodeFragmentPrinter()
14561428
SwiftCodePattern.buildExternFunctionDecl(
14571429
printer: getterExternDeclPrinter,
14581430
moduleName: moduleName,
14591431
abiName: getterAbiName,
14601432
functionName: getterAbiName,
1461-
signature: getterExternSignature
1433+
abiParameters: getterBuilder.abiParameterSignatures,
1434+
returnType: getterBuilder.abiReturnType
14621435
)
14631436
let getterExternDecl = DeclSyntax("\(raw: getterExternDeclPrinter.lines.joined(separator: "\n"))")
14641437
var externDecls: [DeclSyntax] = [getterExternDecl]
@@ -1483,17 +1456,14 @@ struct ProtocolCodegen {
14831456
try setterBuilder.call(returnType: .void)
14841457

14851458
// Build setter extern declaration using helper function
1486-
let setterExternSignature = SwiftSignatureBuilder.buildABIFunctionSignature(
1487-
abiParameters: setterBuilder.abiParameterSignatures,
1488-
returnType: setterBuilder.abiReturnType
1489-
)
14901459
let setterExternDeclPrinter = CodeFragmentPrinter()
14911460
SwiftCodePattern.buildExternFunctionDecl(
14921461
printer: setterExternDeclPrinter,
14931462
moduleName: moduleName,
14941463
abiName: setterAbiName,
14951464
functionName: setterAbiName,
1496-
signature: setterExternSignature
1465+
abiParameters: setterBuilder.abiParameterSignatures,
1466+
returnType: setterBuilder.abiReturnType
14971467
)
14981468
let setterExternDecl = DeclSyntax("\(raw: setterExternDeclPrinter.lines.joined(separator: "\n"))")
14991469
externDecls.append(setterExternDecl)

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,18 +222,14 @@ public struct ImportTS {
222222
}
223223

224224
func renderImportDecl() -> DeclSyntax {
225-
let signature = SwiftSignatureBuilder.buildABIFunctionSignature(
226-
abiParameters: abiParameterSignatures,
227-
returnType: abiReturnType
228-
)
229-
230225
let printer = CodeFragmentPrinter()
231226
SwiftCodePattern.buildExternFunctionDecl(
232227
printer: printer,
233228
moduleName: moduleName,
234229
abiName: abiName,
235230
functionName: abiName,
236-
signature: signature
231+
abiParameters: abiParameterSignatures,
232+
returnType: abiReturnType
237233
)
238234
return "\(raw: printer.lines.joined(separator: "\n"))"
239235
}
@@ -634,6 +630,27 @@ enum SwiftCodePattern {
634630
elseDecl(printer)
635631
printer.write("#endif")
636632
}
633+
static func buildExternFunctionDecl(
634+
printer: CodeFragmentPrinter,
635+
moduleName: String,
636+
abiName: String,
637+
functionName: String,
638+
abiParameters: [(name: String, type: WasmCoreType)],
639+
returnType: WasmCoreType?
640+
) {
641+
let signature = SwiftSignatureBuilder.buildABIFunctionSignature(
642+
abiParameters: abiParameters,
643+
returnType: returnType
644+
)
645+
buildExternFunctionDecl(
646+
printer: printer,
647+
moduleName: moduleName,
648+
abiName: abiName,
649+
functionName: functionName,
650+
signature: signature,
651+
parameterNames: abiParameters.map { $0.name }
652+
)
653+
}
637654

638655
/// Builds the @_extern attribute for WebAssembly extern function declarations
639656
/// Builds an @_extern function declaration (no body, just the declaration)
@@ -642,22 +659,31 @@ enum SwiftCodePattern {
642659
moduleName: String,
643660
abiName: String,
644661
functionName: String,
645-
signature: String
662+
signature: String,
663+
parameterNames: [String],
646664
) {
665+
// NOTE: Due to a Swift compiler issue, we can't declare possibly inlined functions as @_extern
666+
// https://github.com/swiftlang/swift/pull/87250
667+
let inModuleDeclName = "\(functionName)_extern"
647668
buildWasmConditionalCompilationDecls(
648669
printer: printer,
649670
wasmDecl: { printer in
650671
printer.write(buildExternAttribute(moduleName: moduleName, abiName: abiName))
651-
printer.write("fileprivate func \(functionName)\(signature)")
672+
printer.write("fileprivate func \(inModuleDeclName)\(signature)")
652673
},
653674
elseDecl: { printer in
654-
printer.write("fileprivate func \(functionName)\(signature) {")
675+
printer.write("fileprivate func \(inModuleDeclName)\(signature) {")
655676
printer.indent {
656677
printer.write("fatalError(\"Only available on WebAssembly\")")
657678
}
658679
printer.write("}")
659680
}
660681
)
682+
printer.write("@inline(never) fileprivate func \(functionName)\(signature) {")
683+
printer.indent {
684+
printer.write("return \(inModuleDeclName)(\(parameterNames.joined(separator: ", ")))")
685+
}
686+
printer.write("}")
661687
}
662688

663689
/// Builds the standard @_expose and @_cdecl attributes for WebAssembly-exposed functions

0 commit comments

Comments
 (0)