Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 91ce11ddd17b5efd19d7f36509e756fec4f08a14
      
https://github.com/WebKit/WebKit/commit/91ce11ddd17b5efd19d7f36509e756fec4f08a14
  Author: Sosuke Suzuki <[email protected]>
  Date:   2026-05-13 (Wed, 13 May 2026)

  Changed paths:
    A JSTests/stress/promise-inline-reaction.js
    M Source/JavaScriptCore/interpreter/Interpreter.cpp
    M Source/JavaScriptCore/runtime/JSMicrotask.cpp
    M Source/JavaScriptCore/runtime/JSPromise.cpp
    M Source/JavaScriptCore/runtime/JSPromise.h

  Log Message:
  -----------
  [JSC] Avoid allocating `JSSlimPromiseReaction` for the single-await case
https://bugs.webkit.org/show_bug.cgi?id=314637

Reviewed by Yusuke Suzuki.

When a pending promise gains its first reaction via
performPromiseThenWithInternalMicrotask with an undefined result promise -- the
common path for `await pendingPromise`, async generator resume, and
`for await...of` -- the reaction is fully described by an InternalMicrotask
(8 bits) and one context cell. We were heap-allocating a JSSlimPromiseReaction
(~32 bytes) just to hold those.

This patch stores that reaction inline in the promise's existing fields:
  - Flags bit 4: hasInlineReactionFlag
  - Flags bits 5-12: the InternalMicrotask
  - ReactionsOrResult: the reaction's context cell

Both fields were previously underused while pending: Flags only used bits 0-3,
and ReactionsOrResult was empty until the first reaction arrived.

When the promise settles, fulfillPromise/rejectPromise read the inline reaction
and queue the microtask directly without touching a reaction object. If a second
consumer attaches before settlement -- another `await` of the same promise, or a
`.then()` on a promise that is already being awaited -- reactionHead() spills
the inline reaction into a JSSlimPromiseReaction chain and the existing path
takes over. The spill is rare: in practice almost every awaited promise has
exactly one consumer.

In local runs of the JetStream3 async/promise-heavy subset (doxbee-promise,
doxbee-async, async-fs, lazy-collections), this looks like a slight improvement
in score and peak memory footprint, with a small drop in Eden GC count. The
numbers are noisy but the direction is consistent across runs.

Test: JSTests/stress/promise-inline-reaction.js

* JSTests/stress/promise-inline-reaction.js: Added.
(shouldBe):
(asyncTest):
(async let):
(async const):
(async Promise):
(async gen):
(async g):
(async for):
(async try):
(finish):
* Source/JavaScriptCore/interpreter/Interpreter.cpp:
(JSC::Interpreter::getAsyncStackTrace):
* Source/JavaScriptCore/runtime/JSMicrotask.cpp:
(JSC::runInternalMicrotask):
* Source/JavaScriptCore/runtime/JSPromise.cpp:
(JSC::JSPromise::spillInlineReaction):
(JSC::JSPromise::reactionHead):
(JSC::JSPromise::performPromiseThen):
(JSC::JSPromise::performPromiseThenWithInternalMicrotask):
(JSC::JSPromise::settleInlineReaction):
(JSC::JSPromise::rejectPromise):
(JSC::JSPromise::fulfillPromise):
* Source/JavaScriptCore/runtime/JSPromise.h:
(JSC::JSPromise::hasInlineReaction const):
(JSC::JSPromise::inlineReactionContext const):
(JSC::JSPromise::inlineReactionMicrotask const):
(JSC::JSPromise::setInlineReaction):
(JSC::JSPromise::clearInlineReaction):

Canonical link: https://commits.webkit.org/313138@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to