Skip to content

BridgeJS: Move optional JSObject to stack ABI, enabling Optional<@JSClass>#738

Open
krodak wants to merge 1 commit intomainfrom
kr/optional-jsobj-stack-abi
Open

BridgeJS: Move optional JSObject to stack ABI, enabling Optional<@JSClass>#738
krodak wants to merge 1 commit intomainfrom
kr/optional-jsobj-stack-abi

Conversation

@krodak
Copy link
Copy Markdown
Member

@krodak krodak commented May 1, 2026

Overview

Fixes #666. Moves Optional<JSObject> (and by extension Optional<@JSClass>) from the side-channel ABI to the stack ABI, enabling optional custom types on both import and export sides.

Previously, @JSFunction func foo() -> Foo? where Foo is a @JSClass struct would fail because the side-channel path for JSObject optionals lacked a bridgeJSLiftReturnFromSideChannel implementation. Rather than adding another per-type side-channel intrinsic, this switches jsObject optionals to the stack ABI — the same convention already used by structs, arrays, and dictionaries.

@JSClass struct Foo {
    @JSGetter var id: String
}
@JSFunction func foo() throws(JSException) -> Foo?  // now works

What changed:

1. JSGlueGen.swiftoptionalConvention for .jsObject: changed from .sideChannelReturn(.retainedObject) to .stackABI. Removed jsObject from nilSentinel (stack ABI uses the isSome flag instead).

2. BridgeJSSkeleton.swiftusesSideChannelForOptionalReturn(): moved .jsObject from the true branch to false.

3. ImportTS.swiftliftingReturnInfo for .nullable: when the wrapped type no longer uses side-channel, returns valueToLift: nil so the extern returns void (values go through typed stacks).

4. BridgeJSIntrinsics.swiftOptional<JSObject>.bridgeJSLowerReturn(): changed from calling _swift_js_return_optional_object (global side-channel) to Wrapped.bridgeJSStackPushAsOptional (stack ABI). JSObject already conforms to _BridgedSwiftStackType, and _JSBridgedClass inherits from it, so Optional<Foo> gets stack-based lifting/lowering for free through the protocol chain.

Tests: Added childOrNull getter/setter/roundTrip for WithOptionalJSClass? to the Optionals test fixture, covering the import-side @JSClass optional pattern from the original issue.

@krodak krodak self-assigned this May 1, 2026
@krodak krodak marked this pull request as draft May 1, 2026 10:55
@krodak krodak force-pushed the kr/optional-jsobj-stack-abi branch from 19f9d4f to c562383 Compare May 1, 2026 10:58
@krodak krodak requested a review from kateinoigakukun May 1, 2026 11:19
@krodak krodak marked this pull request as ready for review May 1, 2026 11:19
@krodak
Copy link
Copy Markdown
Member Author

krodak commented May 1, 2026

@kateinoigakukun let me know if this aligns with your comment of revisiting side-channel ABI, I remembered that we've discussed moving this to stack ABI, but might be wrong 😅 🙏🏻

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.

[BridgeJS] Optionals with custom types

1 participant