Skip to content

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

Merged
krodak merged 1 commit into
swiftwasm:mainfrom
PassiveLogic:kr/optional-param-stack-flag
Aug 14, 2026
Merged

BridgeJS: Lower imported optional stack parameters fully on the stack#802
krodak merged 1 commit into
swiftwasm:mainfrom
PassiveLogic:kr/optional-param-stack-flag

Conversation

@krodak

@krodak krodak commented Aug 13, 2026

Copy link
Copy Markdown
Member

Overview

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

This also removes the mixed parameter representation that caused the argument-order bug fixed in #794. Optional stack-based values now use the same stack-only representation as other stack-based parameters.

Test plan

  • BridgeJS plugin tests and snapshots
  • Regenerated committed BridgeJS bindings
  • make unittest

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 129a15d to f998117 Compare August 13, 2026 14:48
@krodak
krodak requested a review from kateinoigakukun August 13, 2026 17:09
@krodak
krodak merged commit c3ac9da into swiftwasm:main Aug 14, 2026
16 checks passed
@krodak
krodak deleted the kr/optional-param-stack-flag branch August 14, 2026 08:14
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.

2 participants