Implement `await using` syntax from Explicit Resource Management proposal
JSTests/stress/await-using-declaration-basic.js
The Explicit Resource Management proposal adds using (sync) and await using (async) declarations to JavaScript — RAII-style resource cleanup where a resource's dispose method is automatically invoked on scope exit. JSC already had using; this commit adds the async variant await using, which requires Await suspend points during disposal. The implementation reuses JSC's Generatorification infrastructure that transforms async functions into yield-based state machines.
The bytecode compiler's "using scope" machinery emits a finally-like block that iterates UsingSlot entries in reverse order, calling each slot's dispose method. For async slots, a new @getAsyncDisposeMethod built-in looks up @@asyncDispose first, falling back to @@dispose with a wrapping closure that converts the sync result into a resolved promise. The spec mandates a subtle invariant: await using x = null must produce exactly one Await(undefined) — so the compiler emits a two-register needsAwait/hasAwaited protocol tracking whether an actual await has occurred during disposal, plus a per-slot reached boolean that separately tracks whether method lookup succeeded (so a throwing getter doesn't trigger a spurious await before propagating the error). The parser adds a two-token lookahead with savepoint restore for the await [no LineTerminator here] using production.
Disposal sequence for: { using a = r1; await using b = r2; }
slot[1] (b, async, disposed first):
@getAsyncDisposeMethod(b)
├─ method = undefined (null resource) → needsAwait = true
└─ method found → call method(); Await(result); hasAwaited = true
slot[0] (a, sync):
Step 3.d: if (needsAwait && !hasAwaited) → Await(undefined)
call a[@@dispose]()
trailing Step 6: statically elided (last slot is sync)
Significance
This completes JSC's Explicit Resource Management support, introducing a non-trivial new async execution path with per-slot state machine logic inside scope exit finally blocks. The needsAwait/hasAwaited protocol, the reached flag semantics, and the @@asyncDispose → @@dispose fallback wrapper each introduce subtle correctness requirements that interact with async generator lifecycles and exception propagation.