Skip to content

BridgeJS: Unify thunk argument preparation - #22

Draft
krodak wants to merge 1 commit into
mainfrom
fix/struct-self-stack-order
Draft

BridgeJS: Unify thunk argument preparation#22
krodak wants to merge 1 commit into
mainfrom
fix/struct-self-stack-order

Conversation

@krodak

@krodak krodak commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Overview

Prepare Swift arguments before invoking user code instead of embedding their lifting expressions in calls. JavaScript pushes stack-backed values in parameter order, so Swift must lift them in reverse order, including a struct receiver. Those lifts must also finish before an async task is scheduled.

The previous code only hoisted synchronous arguments when more than one used the stack. A struct method with one such argument could therefore pop self before the argument. Separate closure handlers had the same ordering problem and left async argument lifts inside the deferred task.

1. One parameter preparation step

Emit local bindings for all parameters in reverse order, then call the function using those values. Remove the parameter-count guard, receiver flag, and stack-type classification. Type conversion and async scheduling continue to use the existing BridgeJS intrinsics.

let _tmp_values = [Int].bridgeJSStackPop()
let _tmp__self = ArrayMembers.bridgeJSLiftParameter()
return _bjs_makePromise(resolve: Promise_resolve_Si, reject: Promise_reject) {
    return await _tmp__self.sumAsync(_: _tmp_values)
}

2. Reuse the thunk builders

Generate Swift closure invocation handlers through the same builder as exported functions and methods. Generate struct JavaScript wrappers through the normal JS thunk builder, which also fixes their missing Promise lifting and exception checks.

3. Disambiguate continuation callbacks

Generate named JSTypedClosure.sending(...) factories for internal continuation callbacks instead of additional initializers. Ordinary (Int) -> Void callbacks can then coexist with generated (sending Int) -> Void callbacks without ambiguous initializer errors. The callback ABI is unchanged.

Test Plan

  • Reproduced reversed closure arguments and invalid async struct results before the changes.
  • Added runtime coverage for concurrent async struct calls, synchronous and async array closures, and throwing struct methods.
  • Reproduced the initializer ambiguity, restored the Int-returning async array regression in both directions, and enabled the existing integer-array callback round-trip test.
  • BridgeJS diagnostics and snapshots with SwiftSyntax 600, 601, 602, and 603.
  • Verified ABI names and signatures remain unchanged across existing codegen snapshots.
  • ./Utilities/format.swift
  • ./Utilities/bridge-js-generate.sh
  • npm run check:bridgejs-dts
  • make unittest SWIFT_SDK_ID=swift-6.3-RELEASE_wasm BUILD_SYSTEM=native
  • git diff --check

@krodak krodak self-assigned this Sep 8, 2026
@krodak krodak changed the title BridgeJS: Lift struct method arguments before self BridgeJS: Unify thunk argument preparation Sep 8, 2026
@krodak
krodak force-pushed the fix/struct-self-stack-order branch from fecb9bf to f8e6dec Compare September 8, 2026 13:15
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