Skip to content

Commit a98e49d

Browse files
authored
Merge pull request swiftwasm#625 from PassiveLogic/kr/bridgejs-next-cleanups
NFC: BridgeJS: Further simplify codegen and JSValue intrinsics
2 parents 318f3ae + 38a73c8 commit a98e49d

File tree

5 files changed

+106
-153
lines changed

5 files changed

+106
-153
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@ import BridgeJSUtilities
1111
public struct ClosureCodegen {
1212
public init() {}
1313

14+
private func swiftClosureType(for signature: ClosureSignature) -> String {
15+
let closureParams = signature.parameters.map { "\($0.swiftType)" }.joined(separator: ", ")
16+
let swiftEffects = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "")
17+
let swiftReturnType = signature.returnType.swiftType
18+
return "(\(closureParams))\(swiftEffects) -> \(swiftReturnType)"
19+
}
20+
1421
func renderClosureHelpers(_ signature: ClosureSignature) throws -> [DeclSyntax] {
1522
let mangledName = signature.mangleName
1623
let helperName = "_BJS_Closure_\(mangledName)"
17-
18-
let closureParams = signature.parameters.enumerated().map { _, type in
19-
"\(type.swiftType)"
20-
}.joined(separator: ", ")
21-
22-
let swiftEffects = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "")
23-
let swiftReturnType = signature.returnType.swiftType
24-
let swiftClosureType = "(\(closureParams))\(swiftEffects) -> \(swiftReturnType)"
24+
let swiftClosureType = swiftClosureType(for: signature)
2525

2626
let externName = "invoke_js_callback_\(signature.moduleName)_\(mangledName)"
2727

@@ -72,7 +72,7 @@ public struct ClosureCodegen {
7272
} else {
7373
parameters =
7474
" ("
75-
+ signature.parameters.enumerated().map { index, param in
75+
+ signature.parameters.enumerated().map { index, _ in
7676
"param\(index)"
7777
}.joined(separator: ", ") + ")"
7878
}
@@ -113,12 +113,7 @@ public struct ClosureCodegen {
113113
}
114114

115115
func renderClosureInvokeHandler(_ signature: ClosureSignature) throws -> DeclSyntax {
116-
let closureParams = signature.parameters.enumerated().map { _, type in
117-
"\(type.swiftType)"
118-
}.joined(separator: ", ")
119-
let swiftEffects = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "")
120-
let swiftReturnType = signature.returnType.swiftType
121-
let swiftClosureType = "(\(closureParams))\(swiftEffects) -> \(swiftReturnType)"
116+
let swiftClosureType = swiftClosureType(for: signature)
122117
let boxType = "_BridgeJSTypedClosureBox<\(swiftClosureType)>"
123118
let abiName = "invoke_swift_closure_\(signature.moduleName)_\(signature.mangleName)"
124119

@@ -144,17 +139,7 @@ public struct ClosureCodegen {
144139

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

147-
// Determine return type
148-
let abiReturnWasmType: WasmCoreType?
149-
if signature.returnType == .void {
150-
abiReturnWasmType = nil
151-
} else if let wasmType = try signature.returnType.loweringReturnInfo().returnType {
152-
abiReturnWasmType = wasmType
153-
} else {
154-
abiReturnWasmType = nil
155-
}
156-
157-
let throwReturn = abiReturnWasmType?.swiftReturnPlaceholderStmt ?? "return"
142+
let abiReturnWasmType = try signature.returnType.loweringReturnInfo().returnType
158143

159144
// Build signature using SwiftSignatureBuilder
160145
let funcSignature = SwiftSignatureBuilder.buildABIFunctionSignature(

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 77 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -482,12 +482,7 @@ public class ExportSwift {
482482
}
483483

484484
if function.effects.isStatic, let staticContext = function.staticContext {
485-
let callName: String
486-
switch staticContext {
487-
case .className(let baseName), .enumName(let baseName), .structName(let baseName),
488-
.namespaceEnum(let baseName):
489-
callName = "\(baseName).\(function.name)"
490-
}
485+
let callName = "\(staticContextBaseName(staticContext)).\(function.name)"
491486
builder.call(name: callName, returnType: function.returnType)
492487
} else {
493488
builder.call(name: function.name, returnType: function.returnType)
@@ -497,17 +492,61 @@ public class ExportSwift {
497492
return builder.render(abiName: function.abiName)
498493
}
499494

495+
private func staticContextBaseName(_ staticContext: StaticContext) -> String {
496+
switch staticContext {
497+
case .className(let baseName), .enumName(let baseName), .structName(let baseName),
498+
.namespaceEnum(let baseName):
499+
return baseName
500+
}
501+
}
502+
503+
private func renderSingleExportedConstructor(
504+
constructor: ExportedConstructor,
505+
callName: String,
506+
returnType: BridgeType
507+
) throws -> DeclSyntax {
508+
let builder = ExportedThunkBuilder(effects: constructor.effects)
509+
for param in constructor.parameters {
510+
try builder.liftParameter(param: param)
511+
}
512+
builder.call(name: callName, returnType: returnType)
513+
try builder.lowerReturnValue(returnType: returnType)
514+
return builder.render(abiName: constructor.abiName)
515+
}
516+
517+
private func renderSingleExportedMethod(
518+
method: ExportedFunction,
519+
ownerTypeName: String,
520+
instanceSelfType: BridgeType
521+
) throws -> DeclSyntax {
522+
let builder = ExportedThunkBuilder(effects: method.effects)
523+
if !method.effects.isStatic {
524+
try builder.liftParameter(param: Parameter(label: nil, name: "_self", type: instanceSelfType))
525+
}
526+
for param in method.parameters {
527+
try builder.liftParameter(param: param)
528+
}
529+
530+
if method.effects.isStatic {
531+
builder.call(name: "\(ownerTypeName).\(method.name)", returnType: method.returnType)
532+
} else {
533+
builder.callMethod(methodName: method.name, returnType: method.returnType)
534+
}
535+
try builder.lowerReturnValue(returnType: method.returnType)
536+
return builder.render(abiName: method.abiName)
537+
}
538+
500539
func renderSingleExportedStruct(struct structDef: ExportedStruct) throws -> [DeclSyntax] {
501540
var decls: [DeclSyntax] = []
502541

503542
if let constructor = structDef.constructor {
504-
let builder = ExportedThunkBuilder(effects: constructor.effects)
505-
for param in constructor.parameters {
506-
try builder.liftParameter(param: param)
507-
}
508-
builder.call(name: structDef.swiftCallName, returnType: .swiftStruct(structDef.swiftCallName))
509-
try builder.lowerReturnValue(returnType: .swiftStruct(structDef.swiftCallName))
510-
decls.append(builder.render(abiName: constructor.abiName))
543+
decls.append(
544+
try renderSingleExportedConstructor(
545+
constructor: constructor,
546+
callName: structDef.swiftCallName,
547+
returnType: .swiftStruct(structDef.swiftCallName)
548+
)
549+
)
511550
}
512551

513552
for property in structDef.properties where property.isStatic {
@@ -520,28 +559,13 @@ public class ExportSwift {
520559
}
521560

522561
for method in structDef.methods {
523-
let builder = ExportedThunkBuilder(effects: method.effects)
524-
525-
if method.effects.isStatic {
526-
for param in method.parameters {
527-
try builder.liftParameter(param: param)
528-
}
529-
builder.call(name: "\(structDef.swiftCallName).\(method.name)", returnType: method.returnType)
530-
} else {
531-
try builder.liftParameter(
532-
param: Parameter(label: nil, name: "_self", type: .swiftStruct(structDef.swiftCallName))
533-
)
534-
for param in method.parameters {
535-
try builder.liftParameter(param: param)
536-
}
537-
builder.callMethod(
538-
methodName: method.name,
539-
returnType: method.returnType
562+
decls.append(
563+
try renderSingleExportedMethod(
564+
method: method,
565+
ownerTypeName: structDef.swiftCallName,
566+
instanceSelfType: .swiftStruct(structDef.swiftCallName)
540567
)
541-
}
542-
543-
try builder.lowerReturnValue(returnType: method.returnType)
544-
decls.append(builder.render(abiName: method.abiName))
568+
)
545569
}
546570

547571
return decls
@@ -598,55 +622,29 @@ public class ExportSwift {
598622
var decls: [DeclSyntax] = []
599623

600624
if let constructor = klass.constructor {
601-
let builder = ExportedThunkBuilder(effects: constructor.effects)
602-
for param in constructor.parameters {
603-
try builder.liftParameter(param: param)
604-
}
605-
builder.call(name: klass.swiftCallName, returnType: BridgeType.swiftHeapObject(klass.name))
606-
try builder.lowerReturnValue(returnType: BridgeType.swiftHeapObject(klass.name))
607-
decls.append(builder.render(abiName: constructor.abiName))
625+
decls.append(
626+
try renderSingleExportedConstructor(
627+
constructor: constructor,
628+
callName: klass.swiftCallName,
629+
returnType: .swiftHeapObject(klass.name)
630+
)
631+
)
608632
}
609633
for method in klass.methods {
610-
let builder = ExportedThunkBuilder(effects: method.effects)
611-
612-
if method.effects.isStatic {
613-
for param in method.parameters {
614-
try builder.liftParameter(param: param)
615-
}
616-
builder.call(name: "\(klass.swiftCallName).\(method.name)", returnType: method.returnType)
617-
} else {
618-
try builder.liftParameter(
619-
param: Parameter(label: nil, name: "_self", type: BridgeType.swiftHeapObject(klass.swiftCallName))
620-
)
621-
for param in method.parameters {
622-
try builder.liftParameter(param: param)
623-
}
624-
builder.callMethod(
625-
methodName: method.name,
626-
returnType: method.returnType
634+
decls.append(
635+
try renderSingleExportedMethod(
636+
method: method,
637+
ownerTypeName: klass.swiftCallName,
638+
instanceSelfType: .swiftHeapObject(klass.swiftCallName)
627639
)
628-
}
629-
try builder.lowerReturnValue(returnType: method.returnType)
630-
decls.append(builder.render(abiName: method.abiName))
640+
)
631641
}
632642

633643
// Generate property getters and setters
634644
for property in klass.properties {
635-
if property.isStatic {
636-
decls.append(
637-
contentsOf: try renderSingleExportedProperty(
638-
property: property,
639-
context: .classStatic(klass: klass)
640-
)
641-
)
642-
} else {
643-
decls.append(
644-
contentsOf: try renderSingleExportedProperty(
645-
property: property,
646-
context: .classInstance(klass: klass)
647-
)
648-
)
649-
}
645+
let context: PropertyRenderingContext =
646+
property.isStatic ? .classStatic(klass: klass) : .classInstance(klass: klass)
647+
decls.append(contentsOf: try renderSingleExportedProperty(property: property, context: context))
650648
}
651649

652650
do {
@@ -760,7 +758,7 @@ struct StackCodegen {
760758
func liftArrayExpression(elementType: BridgeType) -> ExprSyntax {
761759
switch elementType {
762760
case .jsObject(let className?) where className != "JSObject":
763-
return liftArrayExpressionInline(elementType: elementType)
761+
return "[JSObject].bridgeJSLiftParameter().map { \(raw: className)(unsafelyWrapping: $0) }"
764762
case .nullable, .closure:
765763
return liftArrayExpressionInline(elementType: elementType)
766764
case .void, .namespaceEnum:
@@ -992,8 +990,7 @@ struct StackCodegen {
992990

993991
let innerStatements = lowerUnwrappedOptionalStatements(
994992
wrappedType: wrappedType,
995-
unwrappedVar: "__bjs_unwrapped_\(varPrefix)",
996-
varPrefix: varPrefix
993+
unwrappedVar: "__bjs_unwrapped_\(varPrefix)"
997994
)
998995
for stmt in innerStatements {
999996
statements.append(stmt.description)
@@ -1007,8 +1004,7 @@ struct StackCodegen {
10071004

10081005
private func lowerUnwrappedOptionalStatements(
10091006
wrappedType: BridgeType,
1010-
unwrappedVar: String,
1011-
varPrefix: String
1007+
unwrappedVar: String
10121008
) -> [CodeBlockItemSyntax] {
10131009
switch wrappedType {
10141010
case .jsObject(_?):

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,7 @@ public func _bjs_makeFoo() -> Int32 {
7676
@_cdecl("bjs_processFooArray")
7777
public func _bjs_processFooArray() -> Void {
7878
#if arch(wasm32)
79-
let ret = processFooArray(_: {
80-
let __count = Int(_swift_js_pop_i32())
81-
var __result: [Foo] = []
82-
__result.reserveCapacity(__count)
83-
for _ in 0..<__count {
84-
__result.append(Foo(unsafelyWrapping: JSObject.bridgeJSLiftParameter()))
85-
}
86-
__result.reverse()
87-
return __result
88-
}())
79+
let ret = processFooArray(_: [JSObject].bridgeJSLiftParameter().map { Foo(unsafelyWrapping: $0) })
8980
ret.map { $0.jsObject }.bridgeJSLowerReturn()
9081
#else
9182
fatalError("Only available on WebAssembly")

Sources/JavaScriptKit/BridgeJSIntrinsics.swift

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,19 @@ extension JSObject: _BridgedSwiftStackType {
386386
extension JSValue: _BridgedSwiftStackType {
387387
public typealias StackLiftResult = JSValue
388388

389+
@_transparent
390+
private static func bridgeJSRetainPayloadIfNeeded(kind: Int32, payload1: Int32) -> Int32 {
391+
guard let kindEnum = JavaScriptValueKind(rawValue: UInt32(kind)) else {
392+
return payload1
393+
}
394+
switch kindEnum {
395+
case .string, .object, .symbol, .bigInt:
396+
return _swift_js_retain(payload1)
397+
default:
398+
return payload1
399+
}
400+
}
401+
389402
@_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (kind: Int32, payload1: Int32, payload2: Double) {
390403
return withRawJSValue { raw in
391404
(
@@ -409,17 +422,7 @@ extension JSValue: _BridgedSwiftStackType {
409422
_ payload1: Int32,
410423
_ payload2: Double
411424
) -> JSValue {
412-
let retainedPayload1: Int32
413-
if let kindEnum = JavaScriptValueKind(rawValue: UInt32(kind)) {
414-
switch kindEnum {
415-
case .string, .object, .symbol, .bigInt:
416-
retainedPayload1 = _swift_js_retain(payload1)
417-
default:
418-
retainedPayload1 = payload1
419-
}
420-
} else {
421-
retainedPayload1 = payload1
422-
}
425+
let retainedPayload1 = bridgeJSRetainPayloadIfNeeded(kind: kind, payload1: payload1)
423426

424427
guard let kindEnum = JavaScriptValueKind(rawValue: UInt32(kind)) else {
425428
fatalError("Invalid JSValue kind: \(kind)")
@@ -440,25 +443,12 @@ extension JSValue: _BridgedSwiftStackType {
440443
}
441444

442445
@_spi(BridgeJS) public static func bridgeJSLiftReturn() -> JSValue {
443-
let payload2 = _swift_js_pop_f64()
444-
let payload1 = _swift_js_pop_i32()
445-
let kind = _swift_js_pop_i32()
446-
return bridgeJSLiftParameter(kind, payload1, payload2)
446+
bridgeJSLiftParameter()
447447
}
448448

449449
@_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void {
450450
let lowered = bridgeJSLowerParameter()
451-
let retainedPayload1: Int32
452-
if let kind = JavaScriptValueKind(rawValue: UInt32(lowered.kind)) {
453-
switch kind {
454-
case .string, .object, .symbol, .bigInt:
455-
retainedPayload1 = _swift_js_retain(lowered.payload1)
456-
default:
457-
retainedPayload1 = lowered.payload1
458-
}
459-
} else {
460-
retainedPayload1 = lowered.payload1
461-
}
451+
let retainedPayload1 = Self.bridgeJSRetainPayloadIfNeeded(kind: lowered.kind, payload1: lowered.payload1)
462452
_swift_js_push_i32(lowered.kind)
463453
_swift_js_push_i32(retainedPayload1)
464454
_swift_js_push_f64(lowered.payload2)

Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5555,16 +5555,7 @@ public func _bjs_roundTripOptionalJSObjectArray() -> Void {
55555555
@_cdecl("bjs_roundTripFooArray")
55565556
public func _bjs_roundTripFooArray() -> Void {
55575557
#if arch(wasm32)
5558-
let ret = roundTripFooArray(_: {
5559-
let __count = Int(_swift_js_pop_i32())
5560-
var __result: [Foo] = []
5561-
__result.reserveCapacity(__count)
5562-
for _ in 0..<__count {
5563-
__result.append(Foo(unsafelyWrapping: JSObject.bridgeJSLiftParameter()))
5564-
}
5565-
__result.reverse()
5566-
return __result
5567-
}())
5558+
let ret = roundTripFooArray(_: [JSObject].bridgeJSLiftParameter().map { Foo(unsafelyWrapping: $0) })
55685559
ret.map { $0.jsObject }.bridgeJSLowerReturn()
55695560
#else
55705561
fatalError("Only available on WebAssembly")

0 commit comments

Comments
 (0)