Skip to content

BridgeJS: Lower imported optional stack parameters fully on the stack - #19

Draft
krodak wants to merge 1 commit into
mainfrom
kr/optional-param-stack-flag
Draft

BridgeJS: Lower imported optional stack parameters fully on the stack#19
krodak wants to merge 1 commit into
mainfrom
kr/optional-param-stack-flag

Conversation

@krodak

@krodak krodak commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Imported optional parameters with stack-only payloads ([T]?, [String: V]?, @JS struct?) used a hybrid convention: the isSome flag crossed as a wasm i32 argument while the payload went on the shared stacks. Optional returns and optional array elements of the same types already put both on the stacks.

This lowers those parameters the same way. The wasm signature carries no argument for them; JS pops the flag and conditionally lifts, through the same fragment as optional returns. Scalars, strings, JSObject, closures, enums and heap objects keep their current optional ABIs, as do all exported signatures.

// before: flag as a wasm argument, payload on the stacks
let aIsSome = a.bridgeJSLowerParameter()
let ret = bjs_f(aIsSome)      // JS: function bjs_f(a) { if (a) { ...lift... } }

// after: all-stack
let _ = a.bridgeJSLowerParameter()
let ret = bjs_f()             // JS: pops flag, conditionally lifts

The hybrid shape was the last parameter kind that both passed a wasm argument and pushed stack data, which is what enabled the argument transposition fixed in swiftwasm#794. After this, every stack-touching parameter is flagless and reverse-ordered.

Test plan

  • BridgeJS plugin tests / snapshots (8 snapshot files, all imported optional-stack shapes)
  • make unittest: ImportAPITests.testStackLoweredParameterOrder, optional round-trips with some and nil
  • check:bridgejs-dts, formatter, no generated drift

@krodak krodak self-assigned this Aug 11, 2026
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.
@krodak
krodak force-pushed the kr/optional-param-stack-flag branch from 4d57e98 to 3f508a1 Compare August 11, 2026 10:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant