◐ Shell
clean mode source ↗

Box JSException storage in a class to fit the direct typed-error convention by krodak · Pull Request #13 · PassiveLogic/JavaScriptKit

Overview

An intermediate solution for the async closure reject path broken by swiftlang/swift#89320, until the IRGen fix in swiftlang/swift#89715 ships.

JSException (~36 bytes) exceeds the direct typed-error convention on wasm32, so an async throws(JSException) closure value takes the indirect-error path that swiftlang/swift#89320 miscompiles: when the closure is captureless, the thrown error is corrupted across the async unwind and the rejected Promise receives garbage instead of the JSException. Boxing JSException's storage into a single class reference (~4 bytes) moves it into the direct convention, so the broken path is never taken.

The function-export variant of the same bug was fixed separately at the codegen level in swiftwasm#760 (already on main); this PR addresses the closure side, which codegen cannot reach (the closure value is constructed by user code). With the minimum supported Swift version now 6.3 (swiftwasm#762), the boxing is unconditional: the boxed layout is validated on 6.3, and the 6.1 wasm IRGen crash it would have triggered is no longer in support scope.

1. Boxing. thrownValue, description, and stack move into a private final class; the struct holds one stored reference. The public surface is unchanged (computed accessors, same initializers, equivalent Equatable); the cost is one heap allocation per thrown exception, on the error path only.

2. Reject tests un-gated. The Swift-to-JS async throws(JSException) closure reject assertions from the base PR run unconditionally and pass; the gate is removed.

3. Base-PR mitigations removed. Since BridgeJS closures only permit throws(JSException), boxing covers every reachable closure case, so the build-time warning and the doc callouts from the base PR are dropped.

4. JSClosure.async reject path. The same bug shape existed in JSClosure.async and was untested; this PR adds the missing reject-path test, which passes with boxing.

Notes