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