Skip to content

Commit f998117

Browse files
committed
BridgeJS: Lower imported optional stack parameters fully on the stack
An imported optional whose payload is stack-only ([T]?, [String: V]?, @js struct?) used a hybrid convention: the isSome flag crossed as a wasm i32 parameter while the payload was conditionally pushed onto the shared stacks. Optional returns and optional array elements of the same types already travel entirely on the stacks: payload first, then a 0/1 flag on the i32 stack. This lowers those parameters the same way. The Swift thunk pushes the payload (if some) followed by the flag, the wasm signature carries no argument for the parameter, and the JS handler pops the flag before conditionally lifting the payload, through the same fragment already used for optional returns and elements. The hybrid shape was the last parameter category that both passed a wasm argument and pushed stack data, which is what enabled the argument transposition fixed in swiftwasm#794. Every stack-touching parameter is now flagless and reverse-ordered, matching returns and elements. All other optional parameter ABIs (scalars, strings, JSObject, closures, enums, heap objects) are unchanged.
1 parent 3966530 commit f998117

14 files changed

Lines changed: 129 additions & 230 deletions

File tree

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,9 @@ extension BridgeType {
971971
throw BridgeJSCoreError("Namespace enums cannot be used as parameters")
972972
case .nullable(let wrappedType, _):
973973
let wrappedInfo = try wrappedType.loweringParameterInfo(context: context)
974+
if wrappedInfo.loweredParameters.isEmpty {
975+
return LoweringParameterInfo(loweredParameters: [])
976+
}
974977
var params = [("isSome", WasmCoreType.i32)]
975978
params.append(contentsOf: wrappedInfo.loweredParameters)
976979
return LoweringParameterInfo(loweredParameters: params, useBorrowing: wrappedInfo.useBorrowing)

Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,16 +1051,13 @@ struct IntrinsicJSFragment: Sendable {
10511051
)
10521052
}
10531053

1054-
let innerFragment =
1055-
if wrappedType.optionalParameterUsesStackABI {
1056-
try stackLiftFragment(elementType: wrappedType)
1057-
} else {
1058-
try liftParameter(type: wrappedType, context: bridgeContext)
1059-
}
1054+
if wrappedType.optionalParameterUsesStackABI {
1055+
return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind)
1056+
}
10601057
return compositeOptionalLiftParameter(
10611058
wrappedType: wrappedType,
10621059
kind: kind,
1063-
innerFragment: innerFragment
1060+
innerFragment: try liftParameter(type: wrappedType, context: bridgeContext)
10641061
)
10651062
}
10661063

@@ -1075,22 +1072,14 @@ struct IntrinsicJSFragment: Sendable {
10751072
kind: JSOptionalKind,
10761073
innerFragment: IntrinsicJSFragment
10771074
) -> IntrinsicJSFragment {
1078-
let isStackConvention = wrappedType.optionalParameterUsesStackABI
10791075
let absenceLiteral = kind.absenceLiteral
10801076

1081-
let outerParams: [String]
1082-
if isStackConvention {
1083-
outerParams = ["isSome"]
1084-
} else {
1085-
outerParams = ["isSome"] + innerFragment.parameters
1086-
}
1087-
10881077
return IntrinsicJSFragment(
1089-
parameters: outerParams,
1078+
parameters: ["isSome"] + innerFragment.parameters,
10901079
printCode: { arguments, context in
10911080
let (scope, printer) = (context.scope, context.printer)
10921081
let isSome = arguments[0]
1093-
let innerArgs = isStackConvention ? [] : Array(arguments.dropFirst())
1082+
let innerArgs = Array(arguments.dropFirst())
10941083

10951084
let bufferPrinter = CodeFragmentPrinter()
10961085
let innerResults = try innerFragment.printCode(

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -626,20 +626,20 @@ func _$Promise_resolve_Sq10AsyncThemeO(_ promise: JSObject, _ value: Optional<As
626626
627627
#if arch(wasm32)
628628
@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_Sq10AsyncPointV")
629-
fileprivate func promise_resolve_TestModule_Sq10AsyncPointV_extern(_ promise: Int32, _ value: Int32) -> Void
629+
fileprivate func promise_resolve_TestModule_Sq10AsyncPointV_extern(_ promise: Int32) -> Void
630630
#else
631-
fileprivate func promise_resolve_TestModule_Sq10AsyncPointV_extern(_ promise: Int32, _ value: Int32) -> Void {
631+
fileprivate func promise_resolve_TestModule_Sq10AsyncPointV_extern(_ promise: Int32) -> Void {
632632
fatalError("Only available on WebAssembly")
633633
}
634634
#endif
635-
@inline(never) fileprivate func promise_resolve_TestModule_Sq10AsyncPointV(_ promise: Int32, _ value: Int32) -> Void {
636-
return promise_resolve_TestModule_Sq10AsyncPointV_extern(promise, value)
635+
@inline(never) fileprivate func promise_resolve_TestModule_Sq10AsyncPointV(_ promise: Int32) -> Void {
636+
return promise_resolve_TestModule_Sq10AsyncPointV_extern(promise)
637637
}
638638
639639
func _$Promise_resolve_Sq10AsyncPointV(_ promise: JSObject, _ value: Optional<AsyncPoint>) throws(JSException) -> Void {
640-
let valueIsSome = value.bridgeJSLowerParameter()
640+
let _ = value.bridgeJSLowerParameter()
641641
let promiseValue = promise.bridgeJSLowerParameter()
642-
promise_resolve_TestModule_Sq10AsyncPointV(promiseValue, valueIsSome)
642+
promise_resolve_TestModule_Sq10AsyncPointV(promiseValue)
643643
if let error = _swift_js_take_exception() { throw error }
644644
}
645645

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -354,20 +354,20 @@ func _$importGenericDictionary<T: BridgedSwiftGenericBridgeable>(_ values: [Stri
354354

355355
#if arch(wasm32)
356356
@_extern(wasm, module: "TestModule", name: "bjs_importGenericAfterOptionalArray")
357-
fileprivate func bjs_importGenericAfterOptionalArray_extern(_ values: Int32, _ _generic0TypeId: Int32) -> Void
357+
fileprivate func bjs_importGenericAfterOptionalArray_extern(_ _generic0TypeId: Int32) -> Void
358358
#else
359-
fileprivate func bjs_importGenericAfterOptionalArray_extern(_ values: Int32, _ _generic0TypeId: Int32) -> Void {
359+
fileprivate func bjs_importGenericAfterOptionalArray_extern(_ _generic0TypeId: Int32) -> Void {
360360
fatalError("Only available on WebAssembly")
361361
}
362362
#endif
363-
@inline(never) fileprivate func bjs_importGenericAfterOptionalArray(_ values: Int32, _ _generic0TypeId: Int32) -> Void {
364-
return bjs_importGenericAfterOptionalArray_extern(values, _generic0TypeId)
363+
@inline(never) fileprivate func bjs_importGenericAfterOptionalArray(_ _generic0TypeId: Int32) -> Void {
364+
return bjs_importGenericAfterOptionalArray_extern(_generic0TypeId)
365365
}
366366

367367
func _$importGenericAfterOptionalArray<T: BridgedSwiftGenericBridgeable>(_ values: Optional<[Int]>, _ value: T) throws(JSException) -> T {
368368
value.bridgeJSStackPush()
369-
let valuesIsSome = values.bridgeJSLowerParameter()
370-
bjs_importGenericAfterOptionalArray(valuesIsSome, T.bridgeJSTypeID)
369+
let _ = values.bridgeJSLowerParameter()
370+
bjs_importGenericAfterOptionalArray(T.bridgeJSTypeID)
371371
if let error = _swift_js_take_exception() {
372372
throw error
373373
}

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,20 @@ func _$logStrings(_ items: [String]) throws(JSException) -> Void {
4141

4242
#if arch(wasm32)
4343
@_extern(wasm, module: "TestModule", name: "bjs_optionalArrayThenArray")
44-
fileprivate func bjs_optionalArrayThenArray_extern(_ a: Int32) -> Int32
44+
fileprivate func bjs_optionalArrayThenArray_extern() -> Int32
4545
#else
46-
fileprivate func bjs_optionalArrayThenArray_extern(_ a: Int32) -> Int32 {
46+
fileprivate func bjs_optionalArrayThenArray_extern() -> Int32 {
4747
fatalError("Only available on WebAssembly")
4848
}
4949
#endif
50-
@inline(never) fileprivate func bjs_optionalArrayThenArray(_ a: Int32) -> Int32 {
51-
return bjs_optionalArrayThenArray_extern(a)
50+
@inline(never) fileprivate func bjs_optionalArrayThenArray() -> Int32 {
51+
return bjs_optionalArrayThenArray_extern()
5252
}
5353

5454
func _$optionalArrayThenArray(_ a: Optional<[Int]>, _ b: [Int]) throws(JSException) -> Int {
5555
let _ = b.bridgeJSLowerParameter()
56-
let aIsSome = a.bridgeJSLowerParameter()
57-
let ret = bjs_optionalArrayThenArray(aIsSome)
56+
let _ = a.bridgeJSLowerParameter()
57+
let ret = bjs_optionalArrayThenArray()
5858
if let error = _swift_js_take_exception() {
5959
throw error
6060
}
@@ -63,21 +63,21 @@ func _$optionalArrayThenArray(_ a: Optional<[Int]>, _ b: [Int]) throws(JSExcepti
6363

6464
#if arch(wasm32)
6565
@_extern(wasm, module: "TestModule", name: "bjs_borrowedStringAroundStackParams")
66-
fileprivate func bjs_borrowedStringAroundStackParams_extern(_ sBytes: Int32, _ sLength: Int32, _ a: Int32) -> Int32
66+
fileprivate func bjs_borrowedStringAroundStackParams_extern(_ sBytes: Int32, _ sLength: Int32) -> Int32
6767
#else
68-
fileprivate func bjs_borrowedStringAroundStackParams_extern(_ sBytes: Int32, _ sLength: Int32, _ a: Int32) -> Int32 {
68+
fileprivate func bjs_borrowedStringAroundStackParams_extern(_ sBytes: Int32, _ sLength: Int32) -> Int32 {
6969
fatalError("Only available on WebAssembly")
7070
}
7171
#endif
72-
@inline(never) fileprivate func bjs_borrowedStringAroundStackParams(_ sBytes: Int32, _ sLength: Int32, _ a: Int32) -> Int32 {
73-
return bjs_borrowedStringAroundStackParams_extern(sBytes, sLength, a)
72+
@inline(never) fileprivate func bjs_borrowedStringAroundStackParams(_ sBytes: Int32, _ sLength: Int32) -> Int32 {
73+
return bjs_borrowedStringAroundStackParams_extern(sBytes, sLength)
7474
}
7575

7676
func _$borrowedStringAroundStackParams(_ s: String, _ a: Optional<[Int]>, _ b: [Int]) throws(JSException) -> Int {
7777
let ret0 = s.bridgeJSWithLoweredParameter { (sBytes, sLength) in
7878
let _ = b.bridgeJSLowerParameter()
79-
let aIsSome = a.bridgeJSLowerParameter()
80-
let ret = bjs_borrowedStringAroundStackParams(sBytes, sLength, aIsSome)
79+
let _ = a.bridgeJSLowerParameter()
80+
let ret = bjs_borrowedStringAroundStackParams(sBytes, sLength)
8181
return ret
8282
}
8383
let ret = ret0

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -992,14 +992,14 @@ public func _invoke_swift_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO(_ b
992992

993993
#if arch(wasm32)
994994
@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV")
995-
fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ callback: Int32, _ param0: Int32) -> Void
995+
fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ callback: Int32) -> Void
996996
#else
997-
fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ callback: Int32, _ param0: Int32) -> Void {
997+
fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ callback: Int32) -> Void {
998998
fatalError("Only available on WebAssembly")
999999
}
10001000
#endif
1001-
@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(_ callback: Int32, _ param0: Int32) -> Void {
1002-
return invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(callback, param0)
1001+
@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(_ callback: Int32) -> Void {
1002+
return invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(callback)
10031003
}
10041004

10051005
#if arch(wasm32)
@@ -1019,9 +1019,9 @@ private enum _BJS_Closure_10TestModuleSq6AnimalV_Sq6AnimalV {
10191019
let callback = JSObject.bridgeJSLiftParameter(callbackId)
10201020
return { [callback] param0 in
10211021
#if arch(wasm32)
1022-
let param0IsSome = param0.bridgeJSLowerParameter()
1022+
let _ = param0.bridgeJSLowerParameter()
10231023
let callbackValue = callback.bridgeJSLowerParameter()
1024-
invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(callbackValue, param0IsSome)
1024+
invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(callbackValue)
10251025
return Optional<Animal>.bridgeJSLiftReturn()
10261026
#else
10271027
fatalError("Only available on WebAssembly")

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,19 @@ func _$translate(_ point: Point, _ dx: Int, _ dy: Int) throws(JSException) -> Po
7575

7676
#if arch(wasm32)
7777
@_extern(wasm, module: "TestModule", name: "bjs_roundTripOptional")
78-
fileprivate func bjs_roundTripOptional_extern(_ point: Int32) -> Void
78+
fileprivate func bjs_roundTripOptional_extern() -> Void
7979
#else
80-
fileprivate func bjs_roundTripOptional_extern(_ point: Int32) -> Void {
80+
fileprivate func bjs_roundTripOptional_extern() -> Void {
8181
fatalError("Only available on WebAssembly")
8282
}
8383
#endif
84-
@inline(never) fileprivate func bjs_roundTripOptional(_ point: Int32) -> Void {
85-
return bjs_roundTripOptional_extern(point)
84+
@inline(never) fileprivate func bjs_roundTripOptional() -> Void {
85+
return bjs_roundTripOptional_extern()
8686
}
8787

8888
func _$roundTripOptional(_ point: Optional<Point>) throws(JSException) -> Optional<Point> {
89-
let pointIsSome = point.bridgeJSLowerParameter()
90-
bjs_roundTripOptional(pointIsSome)
89+
let _ = point.bridgeJSLowerParameter()
90+
bjs_roundTripOptional()
9191
if let error = _swift_js_take_exception() {
9292
throw error
9393
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -584,16 +584,10 @@ export async function createInstantiator(options, swift) {
584584
setException(error);
585585
}
586586
}
587-
bjs["promise_resolve_TestModule_Sq10AsyncPointV"] = function(promise, value) {
587+
bjs["promise_resolve_TestModule_Sq10AsyncPointV"] = function(promise) {
588588
try {
589-
let optResult;
590-
if (value) {
591-
const struct = structHelpers.M10TestModuleT10AsyncPoint.lift();
592-
optResult = struct;
593-
} else {
594-
optResult = null;
595-
}
596-
swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(optResult);
589+
const optValue = __bjs_codec_Optional_M10TestModuleT10AsyncPoint.lift();
590+
swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(optValue);
597591
} catch (error) {
598592
setException(error);
599593
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ export async function createInstantiator(options, swift) {
389389
}
390390

391391
const __bjs_codec_Array_Int = __bjs_arrayCodec(__bjs_primitiveCodecs.Int);
392+
const __bjs_codec_Optional_Array_Int = __bjs_optionalCodec(__bjs_codec_Array_Int);
392393
const __bjs_codec_M10TestModuleT12GenericPoint = {
393394
lower: (v) => {
394395
structHelpers.M10TestModuleT12GenericPoint.lower(v);
@@ -771,18 +772,12 @@ export async function createInstantiator(options, swift) {
771772
setException(error);
772773
}
773774
}
774-
TestModule["bjs_importGenericAfterOptionalArray"] = function bjs_importGenericAfterOptionalArray(values, tTypeId) {
775+
TestModule["bjs_importGenericAfterOptionalArray"] = function bjs_importGenericAfterOptionalArray(tTypeId) {
775776
try {
776777
const codecT = __bjs_codecForTypeId(tTypeId);
777-
let optResult;
778-
if (values) {
779-
const arrayResult = __bjs_codec_Array_Int.lift();
780-
optResult = arrayResult;
781-
} else {
782-
optResult = null;
783-
}
778+
const optValue = __bjs_codec_Optional_Array_Int.lift();
784779
const value = codecT.lift();
785-
let ret = imports.importGenericAfterOptionalArray(optResult, value);
780+
let ret = imports.importGenericAfterOptionalArray(optValue, value);
786781
codecT.lower(ret);
787782
} catch (error) {
788783
setException(error);

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ export async function createInstantiator(options, swift) {
356356

357357
const __bjs_codec_Array_Int = __bjs_arrayCodec(__bjs_primitiveCodecs.Int);
358358
const __bjs_codec_Array_String = __bjs_arrayCodec(__bjs_stringCodec);
359+
const __bjs_codec_Optional_Array_Int = __bjs_optionalCodec(__bjs_codec_Array_Int);
359360

360361

361362
return {
@@ -549,35 +550,23 @@ export async function createInstantiator(options, swift) {
549550
setException(error);
550551
}
551552
}
552-
TestModule["bjs_optionalArrayThenArray"] = function bjs_optionalArrayThenArray(a) {
553+
TestModule["bjs_optionalArrayThenArray"] = function bjs_optionalArrayThenArray() {
553554
try {
554-
let optResult;
555-
if (a) {
556-
const arrayResult = __bjs_codec_Array_Int.lift();
557-
optResult = arrayResult;
558-
} else {
559-
optResult = null;
560-
}
561-
const arrayResult1 = __bjs_codec_Array_Int.lift();
562-
let ret = imports.optionalArrayThenArray(optResult, arrayResult1);
555+
const optValue = __bjs_codec_Optional_Array_Int.lift();
556+
const arrayResult = __bjs_codec_Array_Int.lift();
557+
let ret = imports.optionalArrayThenArray(optValue, arrayResult);
563558
return ret;
564559
} catch (error) {
565560
setException(error);
566561
return 0
567562
}
568563
}
569-
TestModule["bjs_borrowedStringAroundStackParams"] = function bjs_borrowedStringAroundStackParams(sBytes, sCount, a) {
564+
TestModule["bjs_borrowedStringAroundStackParams"] = function bjs_borrowedStringAroundStackParams(sBytes, sCount) {
570565
try {
571566
const string = decodeString(sBytes, sCount);
572-
let optResult;
573-
if (a) {
574-
const arrayResult = __bjs_codec_Array_Int.lift();
575-
optResult = arrayResult;
576-
} else {
577-
optResult = null;
578-
}
579-
const arrayResult1 = __bjs_codec_Array_Int.lift();
580-
let ret = imports.borrowedStringAroundStackParams(string, optResult, arrayResult1);
567+
const optValue = __bjs_codec_Optional_Array_Int.lift();
568+
const arrayResult = __bjs_codec_Array_Int.lift();
569+
let ret = imports.borrowedStringAroundStackParams(string, optValue, arrayResult);
581570
return ret;
582571
} catch (error) {
583572
setException(error);

0 commit comments

Comments
 (0)