Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions Benchmarks/Sources/Generated/BridgeJS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,49 @@ extension SimpleStruct: _BridgedSwiftStruct {
_swift_js_push_f32(self.rate)
_swift_js_push_f64(self.precise)
}

init(unsafelyCopying jsObject: JSObject) {
let __bjs_cleanupId = _SimpleStructHelpers.lower(jsObject)
defer {
_swift_js_struct_cleanup(__bjs_cleanupId)
}
self = Self.bridgeJSLiftParameter()
}

func toJSObject() -> JSObject {
var __bjs_self = self
__bjs_self.bridgeJSLowerReturn()
return _SimpleStructHelpers.raise()
}
}

fileprivate enum _SimpleStructHelpers {
static func lower(_ jsObject: JSObject) -> Int32 {
return _bjs_struct_lower_SimpleStruct(jsObject.bridgeJSLowerParameter())
}

static func raise() -> JSObject {
return JSObject(id: UInt32(bitPattern: _bjs_struct_raise_SimpleStruct()))
}
}

#if arch(wasm32)
@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_SimpleStruct")
fileprivate func _bjs_struct_lower_SimpleStruct(_ objectId: Int32) -> Int32
#else
fileprivate func _bjs_struct_lower_SimpleStruct(_ objectId: Int32) -> Int32 {
fatalError("Only available on WebAssembly")
}
#endif

#if arch(wasm32)
@_extern(wasm, module: "bjs", name: "swift_js_struct_raise_SimpleStruct")
fileprivate func _bjs_struct_raise_SimpleStruct() -> Int32
#else
fileprivate func _bjs_struct_raise_SimpleStruct() -> Int32 {
fatalError("Only available on WebAssembly")
}
#endif

extension Address: _BridgedSwiftStruct {
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter() -> Address {
Expand All @@ -288,7 +330,49 @@ extension Address: _BridgedSwiftStruct {
}
_swift_js_push_int(Int32(self.zipCode))
}

init(unsafelyCopying jsObject: JSObject) {
let __bjs_cleanupId = _AddressHelpers.lower(jsObject)
defer {
_swift_js_struct_cleanup(__bjs_cleanupId)
}
self = Self.bridgeJSLiftParameter()
}

func toJSObject() -> JSObject {
var __bjs_self = self
__bjs_self.bridgeJSLowerReturn()
return _AddressHelpers.raise()
}
}

fileprivate enum _AddressHelpers {
static func lower(_ jsObject: JSObject) -> Int32 {
return _bjs_struct_lower_Address(jsObject.bridgeJSLowerParameter())
}

static func raise() -> JSObject {
return JSObject(id: UInt32(bitPattern: _bjs_struct_raise_Address()))
}
}

#if arch(wasm32)
@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Address")
fileprivate func _bjs_struct_lower_Address(_ objectId: Int32) -> Int32
#else
fileprivate func _bjs_struct_lower_Address(_ objectId: Int32) -> Int32 {
fatalError("Only available on WebAssembly")
}
#endif

#if arch(wasm32)
@_extern(wasm, module: "bjs", name: "swift_js_struct_raise_Address")
fileprivate func _bjs_struct_raise_Address() -> Int32
#else
fileprivate func _bjs_struct_raise_Address() -> Int32 {
fatalError("Only available on WebAssembly")
}
#endif

extension Person: _BridgedSwiftStruct {
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter() -> Person {
Expand All @@ -315,7 +399,49 @@ extension Person: _BridgedSwiftStruct {
}
_swift_js_push_int(__bjs_isSome_email ? 1 : 0)
}

init(unsafelyCopying jsObject: JSObject) {
let __bjs_cleanupId = _PersonHelpers.lower(jsObject)
defer {
_swift_js_struct_cleanup(__bjs_cleanupId)
}
self = Self.bridgeJSLiftParameter()
}

func toJSObject() -> JSObject {
var __bjs_self = self
__bjs_self.bridgeJSLowerReturn()
return _PersonHelpers.raise()
}
}

fileprivate enum _PersonHelpers {
static func lower(_ jsObject: JSObject) -> Int32 {
return _bjs_struct_lower_Person(jsObject.bridgeJSLowerParameter())
}

static func raise() -> JSObject {
return JSObject(id: UInt32(bitPattern: _bjs_struct_raise_Person()))
}
}

#if arch(wasm32)
@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Person")
fileprivate func _bjs_struct_lower_Person(_ objectId: Int32) -> Int32
#else
fileprivate func _bjs_struct_lower_Person(_ objectId: Int32) -> Int32 {
fatalError("Only available on WebAssembly")
}
#endif

#if arch(wasm32)
@_extern(wasm, module: "bjs", name: "swift_js_struct_raise_Person")
fileprivate func _bjs_struct_raise_Person() -> Int32
#else
fileprivate func _bjs_struct_raise_Person() -> Int32 {
fatalError("Only available on WebAssembly")
}
#endif

extension ComplexStruct: _BridgedSwiftStruct {
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter() -> ComplexStruct {
Expand Down Expand Up @@ -345,7 +471,49 @@ extension ComplexStruct: _BridgedSwiftStruct {
_swift_js_push_string(ptr.baseAddress, Int32(ptr.count))
}
}

init(unsafelyCopying jsObject: JSObject) {
let __bjs_cleanupId = _ComplexStructHelpers.lower(jsObject)
defer {
_swift_js_struct_cleanup(__bjs_cleanupId)
}
self = Self.bridgeJSLiftParameter()
}

func toJSObject() -> JSObject {
var __bjs_self = self
__bjs_self.bridgeJSLowerReturn()
return _ComplexStructHelpers.raise()
}
}

fileprivate enum _ComplexStructHelpers {
static func lower(_ jsObject: JSObject) -> Int32 {
return _bjs_struct_lower_ComplexStruct(jsObject.bridgeJSLowerParameter())
}

static func raise() -> JSObject {
return JSObject(id: UInt32(bitPattern: _bjs_struct_raise_ComplexStruct()))
}
}

#if arch(wasm32)
@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_ComplexStruct")
fileprivate func _bjs_struct_lower_ComplexStruct(_ objectId: Int32) -> Int32
#else
fileprivate func _bjs_struct_lower_ComplexStruct(_ objectId: Int32) -> Int32 {
fatalError("Only available on WebAssembly")
}
#endif

#if arch(wasm32)
@_extern(wasm, module: "bjs", name: "swift_js_struct_raise_ComplexStruct")
fileprivate func _bjs_struct_raise_ComplexStruct() -> Int32
#else
fileprivate func _bjs_struct_raise_ComplexStruct() -> Int32 {
fatalError("Only available on WebAssembly")
}
#endif

@_expose(wasm, "bjs_run")
@_cdecl("bjs_run")
Expand Down
88 changes: 85 additions & 3 deletions Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public class ExportSwift {

let structCodegen = StructCodegen()
for structDef in skeleton.structs {
decls.append(structCodegen.renderStructHelpers(structDef))
decls.append(contentsOf: structCodegen.renderStructHelpers(structDef))
decls.append(contentsOf: try renderSingleExportedStruct(struct: structDef))
}

Expand Down Expand Up @@ -1147,12 +1147,19 @@ struct EnumCodegen {
struct StructCodegen {
private let stackCodegen = StackCodegen()

func renderStructHelpers(_ structDef: ExportedStruct) -> DeclSyntax {
func renderStructHelpers(_ structDef: ExportedStruct) -> [DeclSyntax] {
let typeName = structDef.swiftCallName
let liftCode = generateStructLiftCode(structDef: structDef)
let lowerCode = generateStructLowerCode(structDef: structDef)
let accessControl = structDef.explicitAccessControl.map { "\($0) " } ?? ""

return """
let helpersTypeName = "_\(structDef.name)Helpers"
let lowerExternName = "swift_js_struct_lower_\(structDef.name)"
let raiseExternName = "swift_js_struct_raise_\(structDef.name)"
let lowerFunctionName = "_bjs_struct_lower_\(structDef.name)"
let raiseFunctionName = "_bjs_struct_raise_\(structDef.name)"

let bridgedStructExtension: DeclSyntax = """
extension \(raw: typeName): _BridgedSwiftStruct {
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter() -> \(raw: typeName) {
\(raw: liftCode.joined(separator: "\n"))
Expand All @@ -1161,8 +1168,83 @@ struct StructCodegen {
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() {
\(raw: lowerCode.joined(separator: "\n"))
}

\(raw: accessControl)init(unsafelyCopying jsObject: JSObject) {
let __bjs_cleanupId = \(raw: helpersTypeName).lower(jsObject)
defer { _swift_js_struct_cleanup(__bjs_cleanupId) }
self = Self.bridgeJSLiftParameter()
}

\(raw: accessControl)func toJSObject() -> JSObject {
var __bjs_self = self
__bjs_self.bridgeJSLowerReturn()
return \(raw: helpersTypeName).raise()
}
}
"""

let helpersType: DeclSyntax = """
fileprivate enum \(raw: helpersTypeName) {
static func lower(_ jsObject: JSObject) -> Int32 {
return \(raw: lowerFunctionName)(jsObject.bridgeJSLowerParameter())
}

static func raise() -> JSObject {
return JSObject(id: UInt32(bitPattern: \(raw: raiseFunctionName)()))
}
}
"""

let lowerExternDecl = Self.renderStructExtern(
externName: lowerExternName,
functionName: lowerFunctionName,
signature: SwiftSignatureBuilder.buildABIFunctionSignature(
abiParameters: [("objectId", .i32)],
returnType: .i32
)
)
let raiseExternDecl = Self.renderStructExtern(
externName: raiseExternName,
functionName: raiseFunctionName,
signature: SwiftSignatureBuilder.buildABIFunctionSignature(
abiParameters: [],
returnType: .i32
)
)

return [bridgedStructExtension, helpersType, lowerExternDecl, raiseExternDecl]
}

private static func renderStructExtern(
externName: String,
functionName: String,
signature: FunctionSignatureSyntax
) -> DeclSyntax {
let externFuncDecl = SwiftCodePattern.buildExternFunctionDecl(
moduleName: "bjs",
abiName: externName,
functionName: functionName,
signature: signature
)

let stubFuncDecl = FunctionDeclSyntax(
modifiers: DeclModifierListSyntax {
DeclModifierSyntax(name: .keyword(.fileprivate))
},
funcKeyword: .keyword(.func),
name: .identifier(functionName),
signature: signature,
body: CodeBlockSyntax {
"fatalError(\"Only available on WebAssembly\")"
}
)

return DeclSyntax(
SwiftCodePattern.buildWasmConditionalCompilationDecls(
wasmDecl: DeclSyntax(externFuncDecl),
elseDecl: DeclSyntax(stubFuncDecl)
)
)
}

private func generateStructLiftCode(structDef: ExportedStruct) -> [String] {
Expand Down
49 changes: 49 additions & 0 deletions Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ public struct BridgeJSLink {
"let \(JSGlueVariableScope.reservedTmpParamF64s) = [];",
"let \(JSGlueVariableScope.reservedTmpRetPointers) = [];",
"let \(JSGlueVariableScope.reservedTmpParamPointers) = [];",
"let \(JSGlueVariableScope.reservedTmpStructCleanups) = [];",
"const \(JSGlueVariableScope.reservedEnumHelpers) = {};",
"const \(JSGlueVariableScope.reservedStructHelpers) = {};",
"",
Expand Down Expand Up @@ -295,6 +296,7 @@ public struct BridgeJSLink {

private func generateAddImports() -> CodeFragmentPrinter {
let printer = CodeFragmentPrinter()
let allStructs = skeletons.compactMap { $0.exported?.structs }.flatMap { $0 }
printer.write("return {")
printer.indent {
printer.write(lines: [
Expand Down Expand Up @@ -427,6 +429,53 @@ public struct BridgeJSLink {
printer.write("return \(JSGlueVariableScope.reservedTmpParamPointers).pop();")
}
printer.write("}")

printer.write("bjs[\"swift_js_struct_cleanup\"] = function(cleanupId) {")
printer.indent {
printer.write("if (cleanupId === 0) { return; }")
printer.write("const index = (cleanupId | 0) - 1;")
printer.write("const cleanup = \(JSGlueVariableScope.reservedTmpStructCleanups)[index];")
printer.write("\(JSGlueVariableScope.reservedTmpStructCleanups)[index] = null;")
printer.write("if (cleanup) { cleanup(); }")
printer.write(
"while (\(JSGlueVariableScope.reservedTmpStructCleanups).length > 0 && \(JSGlueVariableScope.reservedTmpStructCleanups)[\(JSGlueVariableScope.reservedTmpStructCleanups).length - 1] == null) {"
)
printer.indent {
printer.write("\(JSGlueVariableScope.reservedTmpStructCleanups).pop();")
}
printer.write("}")
}
printer.write("}")

if !allStructs.isEmpty {
for structDef in allStructs {
printer.write("bjs[\"swift_js_struct_lower_\(structDef.name)\"] = function(objectId) {")
printer.indent {
printer.write(
"const { cleanup: cleanup } = \(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lower(\(JSGlueVariableScope.reservedSwift).memory.getObject(objectId));"
)
printer.write("if (cleanup) {")
printer.indent {
printer.write(
"return \(JSGlueVariableScope.reservedTmpStructCleanups).push(cleanup);"
)
}
printer.write("}")
printer.write("return 0;")
}
printer.write("}")

printer.write("bjs[\"swift_js_struct_raise_\(structDef.name)\"] = function() {")
printer.indent {
printer.write(
"const value = \(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).raise(\(JSGlueVariableScope.reservedTmpRetStrings), \(JSGlueVariableScope.reservedTmpRetInts), \(JSGlueVariableScope.reservedTmpRetF32s), \(JSGlueVariableScope.reservedTmpRetF64s), \(JSGlueVariableScope.reservedTmpRetPointers));"
)
printer.write("return \(JSGlueVariableScope.reservedSwift).memory.retain(value);")
}
printer.write("}")
}
}

printer.write("bjs[\"swift_js_return_optional_bool\"] = function(isSome, value) {")
printer.indent {
printer.write("if (isSome === 0) {")
Expand Down
Loading