Skip to content

Commit 3e66088

Browse files
committed
BridgeJS: Add OptionalConvention, move side-channel/stack flags to descriptor, unify return-type switches
1 parent 094bcb1 commit 3e66088

File tree

23 files changed

+1537
-1638
lines changed

23 files changed

+1537
-1638
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public struct ClosureCodegen {
139139

140140
let closureCallExpr = ExprSyntax("closure(\(raw: liftedParams.joined(separator: ", ")))")
141141

142-
let abiReturnWasmType = try signature.returnType.loweringReturnInfo().returnType
142+
let abiReturnWasmType = try signature.returnType.loweringReturnInfo()
143143

144144
// Build signature using SwiftSignatureBuilder
145145
let funcSignature = SwiftSignatureBuilder.buildABIFunctionSignature(

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 49 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -134,39 +134,26 @@ public class ExportSwift {
134134
case .closure(let signature, _):
135135
typeNameForIntrinsic = param.type.swiftType
136136
liftingExpr = ExprSyntax("_BJS_Closure_\(raw: signature.mangleName).bridgeJSLift(\(raw: param.name))")
137-
case .swiftStruct(let structName):
138-
typeNameForIntrinsic = structName
139-
liftingExpr = ExprSyntax("\(raw: structName).bridgeJSLiftParameter()")
140137
case .array:
141138
typeNameForIntrinsic = param.type.swiftType
142139
liftingExpr = StackCodegen().liftExpression(for: param.type)
143140
case .nullable(let wrappedType, let kind):
144-
let optionalSwiftType: String
145-
if case .null = kind {
146-
optionalSwiftType = "Optional"
147-
} else {
148-
optionalSwiftType = "JSUndefinedOr"
149-
}
150-
if case .swiftProtocol(let protocolName) = wrappedType {
151-
let wrapperName = "Any\(protocolName)"
152-
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrapperName)>"
153-
liftingExpr = ExprSyntax(
154-
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
155-
)
156-
} else {
157-
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrappedType.swiftType)>"
158-
liftingExpr = ExprSyntax(
159-
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
160-
)
161-
}
162-
case .swiftProtocol(let protocolName):
163-
let wrapperName = "Any\(protocolName)"
164-
typeNameForIntrinsic = wrapperName
141+
let optionalSwiftType: String =
142+
if case .null = kind { "Optional" } else { "JSUndefinedOr" }
143+
let wrappedName: String =
144+
if case .cast(let name) = wrappedType.descriptor.accessorTransform { name } else {
145+
wrappedType.swiftType
146+
}
147+
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrappedName)>"
165148
liftingExpr = ExprSyntax(
166-
"\(raw: wrapperName).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
149+
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
167150
)
168151
default:
169-
typeNameForIntrinsic = param.type.swiftType
152+
if case .cast(let name) = param.type.descriptor.accessorTransform {
153+
typeNameForIntrinsic = name
154+
} else {
155+
typeNameForIntrinsic = param.type.swiftType
156+
}
170157
liftingExpr = ExprSyntax(
171158
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
172159
)
@@ -211,26 +198,9 @@ public class ExportSwift {
211198
if returnType == .void {
212199
return CodeBlockItemSyntax(item: .init(ExpressionStmtSyntax(expression: callExpr)))
213200
} else {
214-
switch returnType {
215-
case .swiftProtocol(let protocolName):
216-
let wrapperName = "Any\(protocolName)"
217-
return CodeBlockItemSyntax(
218-
item: .init(DeclSyntax("let ret = \(raw: callExpr) as! \(raw: wrapperName)"))
219-
)
220-
case .nullable(let wrappedType, _):
221-
if case .swiftProtocol(let protocolName) = wrappedType {
222-
let wrapperName = "Any\(protocolName)"
223-
return CodeBlockItemSyntax(
224-
item: .init(
225-
DeclSyntax("let ret = (\(raw: callExpr)).flatMap { $0 as? \(raw: wrapperName) }")
226-
)
227-
)
228-
} else {
229-
return CodeBlockItemSyntax(item: .init(DeclSyntax("let ret = \(raw: callExpr)")))
230-
}
231-
default:
232-
return CodeBlockItemSyntax(item: .init(DeclSyntax("let ret = \(raw: callExpr)")))
233-
}
201+
let binding = returnType.descriptor.accessorTransform
202+
.applyToReturnBinding("\(callExpr)", isOptional: returnType.isOptional)
203+
return CodeBlockItemSyntax(item: .init(DeclSyntax("\(raw: binding)")))
234204
}
235205
}
236206

@@ -244,20 +214,9 @@ public class ExportSwift {
244214
if returnType == .void {
245215
append("\(raw: name)")
246216
} else {
247-
switch returnType {
248-
case .swiftProtocol(let protocolName):
249-
let wrapperName = "Any\(protocolName)"
250-
append("let ret = \(raw: name) as! \(raw: wrapperName)")
251-
case .nullable(let wrappedType, _):
252-
if case .swiftProtocol(let protocolName) = wrappedType {
253-
let wrapperName = "Any\(protocolName)"
254-
append("let ret = \(raw: name).flatMap { $0 as? \(raw: wrapperName) }")
255-
} else {
256-
append("let ret = \(raw: name)")
257-
}
258-
default:
259-
append("let ret = \(raw: name)")
260-
}
217+
let binding = returnType.descriptor.accessorTransform
218+
.applyToReturnBinding(name, isOptional: returnType.isOptional)
219+
append("\(raw: binding)")
261220
}
262221
}
263222

@@ -274,14 +233,7 @@ public class ExportSwift {
274233
/// Generates intermediate variables for stack-using parameters if needed for LIFO compatibility
275234
private func generateParameterLifting() {
276235
let stackParamIndices = parameters.enumerated().compactMap { index, param -> Int? in
277-
switch param.type {
278-
case .swiftStruct, .nullable(.swiftStruct, _),
279-
.associatedValueEnum, .nullable(.associatedValueEnum, _),
280-
.array:
281-
return index
282-
default:
283-
return nil
284-
}
236+
param.type.descriptor.usesStackLifting ? index : nil
285237
}
286238

287239
guard stackParamIndices.count > 1 else { return }
@@ -298,23 +250,13 @@ public class ExportSwift {
298250

299251
func callPropertyGetter(propertyName: String, returnType: BridgeType) {
300252
let (_, selfExpr) = removeFirstLiftedParameter()
253+
let expr = "\(selfExpr).\(propertyName)"
301254
if returnType == .void {
302-
append("\(raw: selfExpr).\(raw: propertyName)")
255+
append("\(raw: expr)")
303256
} else {
304-
switch returnType {
305-
case .swiftProtocol(let protocolName):
306-
let wrapperName = "Any\(protocolName)"
307-
append("let ret = \(raw: selfExpr).\(raw: propertyName) as! \(raw: wrapperName)")
308-
case .nullable(let wrappedType, _):
309-
if case .swiftProtocol(let protocolName) = wrappedType {
310-
let wrapperName = "Any\(protocolName)"
311-
append("let ret = \(raw: selfExpr).\(raw: propertyName).flatMap { $0 as? \(raw: wrapperName) }")
312-
} else {
313-
append("let ret = \(raw: selfExpr).\(raw: propertyName)")
314-
}
315-
default:
316-
append("let ret = \(raw: selfExpr).\(raw: propertyName)")
317-
}
257+
let binding = returnType.descriptor.accessorTransform
258+
.applyToReturnBinding(expr, isOptional: returnType.isOptional)
259+
append("\(raw: binding)")
318260
}
319261
}
320262

@@ -339,8 +281,7 @@ public class ExportSwift {
339281
}
340282

341283
private func _lowerReturnValue(returnType: BridgeType) throws {
342-
let loweringInfo = try returnType.loweringReturnInfo()
343-
abiReturnType = loweringInfo.returnType
284+
abiReturnType = try returnType.loweringReturnInfo()
344285
if returnType == .void {
345286
return
346287
}
@@ -782,6 +723,7 @@ struct StackCodegen {
782723
return "\(raw: type.swiftType).bridgeJSLiftParameter()"
783724
case .jsObject(let className?):
784725
return "\(raw: className)(unsafelyWrapping: JSObject.bridgeJSLiftParameter())"
726+
785727
case .nullable(let wrappedType, let kind):
786728
return liftNullableExpression(wrappedType: wrappedType, kind: kind)
787729
case .array(let elementType):
@@ -801,8 +743,6 @@ struct StackCodegen {
801743
return "[JSObject].bridgeJSLiftParameter().map { \(raw: className)(unsafelyWrapping: $0) }"
802744
case .nullable, .closure:
803745
return liftArrayExpressionInline(elementType: elementType)
804-
case .void, .namespaceEnum:
805-
fatalError("Invalid array element type: \(elementType)")
806746
default:
807747
return "[\(raw: elementType.swiftType)].bridgeJSLiftParameter()"
808748
}
@@ -915,23 +855,16 @@ struct StackCodegen {
915855
accessor: String,
916856
varPrefix: String
917857
) -> [CodeBlockItemSyntax] {
918-
// Types needing accessor transformation
919-
switch elementType {
920-
case .jsObject(let className?) where className != "JSObject":
921-
return ["\(raw: accessor).map { $0.jsObject }.bridgeJSLowerReturn()"]
922-
case .swiftProtocol:
923-
return ["\(raw: accessor).map { $0 as! \(raw: elementType.swiftType) }.bridgeJSLowerReturn()"]
924-
case .nullable, .closure:
925-
return lowerArrayStatementsInline(
926-
elementType: elementType,
927-
accessor: accessor,
928-
varPrefix: varPrefix
929-
)
930-
case .void, .namespaceEnum:
931-
fatalError("Invalid array element type: \(elementType)")
932-
default:
933-
return ["\(raw: accessor).bridgeJSLowerReturn()"]
858+
if case .nullable = elementType {
859+
return lowerArrayStatementsInline(elementType: elementType, accessor: accessor, varPrefix: varPrefix)
860+
}
861+
if case .closure = elementType {
862+
return lowerArrayStatementsInline(elementType: elementType, accessor: accessor, varPrefix: varPrefix)
934863
}
864+
if let mapClosure = elementType.descriptor.accessorTransform.mapClosure {
865+
return ["\(raw: accessor).map { \(raw: mapClosure) }.bridgeJSLowerReturn()"]
866+
}
867+
return ["\(raw: accessor).bridgeJSLowerReturn()"]
935868
}
936869

937870
private func lowerArrayStatementsInline(
@@ -963,22 +896,16 @@ struct StackCodegen {
963896
accessor: String,
964897
varPrefix: String
965898
) -> [CodeBlockItemSyntax] {
966-
switch valueType {
967-
case .jsObject(let className?) where className != "JSObject":
968-
return ["\(raw: accessor).mapValues { $0.jsObject }.bridgeJSLowerReturn()"]
969-
case .swiftProtocol:
970-
return ["\(raw: accessor).mapValues { $0 as! \(raw: valueType.swiftType) }.bridgeJSLowerReturn()"]
971-
case .nullable, .closure:
972-
return lowerDictionaryStatementsInline(
973-
valueType: valueType,
974-
accessor: accessor,
975-
varPrefix: varPrefix
976-
)
977-
case .void, .namespaceEnum:
978-
fatalError("Invalid dictionary value type: \(valueType)")
979-
default:
980-
return ["\(raw: accessor).bridgeJSLowerReturn()"]
899+
if case .nullable = valueType {
900+
return lowerDictionaryStatementsInline(valueType: valueType, accessor: accessor, varPrefix: varPrefix)
901+
}
902+
if case .closure = valueType {
903+
return lowerDictionaryStatementsInline(valueType: valueType, accessor: accessor, varPrefix: varPrefix)
904+
}
905+
if let mapClosure = valueType.descriptor.accessorTransform.mapClosure {
906+
return ["\(raw: accessor).mapValues { \(raw: mapClosure) }.bridgeJSLowerReturn()"]
981907
}
908+
return ["\(raw: accessor).bridgeJSLowerReturn()"]
982909
}
983910

984911
private func lowerDictionaryStatementsInline(
@@ -1020,7 +947,7 @@ struct StackCodegen {
1020947
accessor: String,
1021948
varPrefix: String
1022949
) -> [CodeBlockItemSyntax] {
1023-
if wrappedType.descriptor.optionalUsesStackABI {
950+
if wrappedType.descriptor.optionalConvention == .stackABI {
1024951
return ["\(raw: accessor).bridgeJSLowerReturn()"]
1025952
}
1026953

@@ -1651,20 +1578,6 @@ extension BridgeType {
16511578
struct LiftingIntrinsicInfo: Sendable {
16521579
let parameters: [(name: String, type: WasmCoreType)]
16531580

1654-
static let bool = LiftingIntrinsicInfo(parameters: [("value", .i32)])
1655-
static let int = LiftingIntrinsicInfo(parameters: [("value", .i32)])
1656-
static let float = LiftingIntrinsicInfo(parameters: [("value", .f32)])
1657-
static let double = LiftingIntrinsicInfo(parameters: [("value", .f64)])
1658-
static let string = LiftingIntrinsicInfo(parameters: [("bytes", .i32), ("length", .i32)])
1659-
static let jsObject = LiftingIntrinsicInfo(parameters: [("value", .i32)])
1660-
static let jsValue = LiftingIntrinsicInfo(parameters: [("kind", .i32), ("payload1", .i32), ("payload2", .f64)])
1661-
static let swiftHeapObject = LiftingIntrinsicInfo(parameters: [("value", .pointer)])
1662-
static let unsafePointer = LiftingIntrinsicInfo(parameters: [("pointer", .pointer)])
1663-
static let void = LiftingIntrinsicInfo(parameters: [])
1664-
static let caseEnum = LiftingIntrinsicInfo(parameters: [("value", .i32)])
1665-
static let associatedValueEnum = LiftingIntrinsicInfo(parameters: [
1666-
("caseId", .i32)
1667-
])
16681581
}
16691582

16701583
func liftParameterInfo() throws -> LiftingIntrinsicInfo {
@@ -1684,18 +1597,14 @@ extension BridgeType {
16841597
}
16851598
}
16861599

1687-
struct LoweringIntrinsicInfo: Sendable {
1688-
let returnType: WasmCoreType?
1689-
}
1690-
1691-
func loweringReturnInfo() throws -> LoweringIntrinsicInfo {
1600+
func loweringReturnInfo() throws -> WasmCoreType? {
16921601
switch self {
16931602
case .nullable:
1694-
return LoweringIntrinsicInfo(returnType: nil)
1603+
return nil
16951604
case .namespaceEnum:
16961605
throw BridgeJSCoreError("Namespace enums are not supported to pass as parameters")
16971606
default:
1698-
return LoweringIntrinsicInfo(returnType: descriptor.wasmReturnType)
1607+
return descriptor.wasmReturnType
16991608
}
17001609
}
17011610
}

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,15 +1535,15 @@ public struct BridgeJSLink {
15351535

15361536
switch enumDefinition.enumType {
15371537
case .simple:
1538-
let fragment = IntrinsicJSFragment.simpleEnumHelper(enumDefinition: enumDefinition)
1538+
let fragment = IntrinsicJSFragment.caseEnumHelper(enumDefinition: enumDefinition)
15391539
_ = try fragment.printCode([enumValuesName], context)
15401540
jsTopLevelLines.append(contentsOf: printer.lines)
15411541
case .rawValue:
15421542
guard enumDefinition.rawType != nil else {
15431543
throw BridgeJSLinkError(message: "Raw value enum \(enumDefinition.name) is missing rawType")
15441544
}
15451545

1546-
let fragment = IntrinsicJSFragment.rawValueEnumHelper(enumDefinition: enumDefinition)
1546+
let fragment = IntrinsicJSFragment.caseEnumHelper(enumDefinition: enumDefinition)
15471547
_ = try fragment.printCode([enumValuesName], context)
15481548
jsTopLevelLines.append(contentsOf: printer.lines)
15491549
case .associatedValue:
@@ -2172,7 +2172,7 @@ extension BridgeJSLink {
21722172
printer.write("} catch (error) {")
21732173
printer.indent {
21742174
printer.write("setException(error);")
2175-
if let abiReturnType = returnType.abiReturnType {
2175+
if !returnType.isOptional, let abiReturnType = returnType.descriptor.wasmReturnType {
21762176
printer.write("return \(abiReturnType.placeholderValue)")
21772177
}
21782178
}

0 commit comments

Comments
 (0)