JSPromise: inline reaction storage for single-handler .then(f)
3f9955f
JSTests/stress/promise-inline-child-reaction.js
+// PATH 1 — inline-child: single .then(f), no allocation
+{
+ let d = defer();
+ let q = d.promise.then(v => { counter++; return v + 1; });
+ d.resolve(10);
+ shouldBe(await q, 11);
+}
+// PATH 2 — spill: second .then() converts inline storage to reaction list
+{
+ let d = defer();
+ let a = d.promise.then(v => v * 2);
+ let b = d.promise.then(v => v * 3); // triggers spillInlineReaction
+ let c = d.promise.then(v => v * 4);
+}
+// PATH 3 — two-arg .then(f,g): falls through to JSFullPromiseReaction, no inline
JSPromise previously subclassed JSInternalFieldObjectImpl, storing state and reactions as JSValues in a fixed internal-fields array shared with WeakRef, FinalizationRegistry, and similar objects. Every .then() call allocated a separate JSPromiseReaction cell holding the callback and child-promise pointer, even when only one handler ever fires. This commit reworks JSPromise into a plain JSObject with a CompactPointerTuple member packing the first reaction's handler (or microtask context) alongside flag bits in one machine word; a second .then() triggers spillInlineReaction which promotes the inline cell to a JSSlimPromiseReaction linked list. New DFG nodes NewPromise and PhantomNewPromise mirror how JSFunction participates in allocation sinking, with PhantomNewPromise reconstructing the promise on OSR exit.
Before — every .then():
JSPromise [JSInternalFieldObjectImpl]
internalFields[1]: reactions ─► JSPromiseReaction (heap cell)
After — first .then(f) [no allocation]:
JSPromise [JSObject]
packed: CompactPointerTuple
cell ─► fulfillHandler (JSFunction*)
bits: InlineHandler flag
After — second .then() spills:
JSPromise [JSObject]
packed: CompactPointerTuple
cell ─► JSSlimPromiseReaction ─► JSSlimPromiseReaction
Significance
Eliminating the per-.then() JSPromiseReaction allocation removes heap pressure across every Promise-heavy workload and rewires the entire JSPromise object model in the process. Switching from JSInternalFieldObjectImpl to plain JSObject means the GC is no longer auto-visiting an internal-fields array; the CompactPointerTuple's cell pointer must now be visited by an explicit visitChildrenImpl. New IR nodes (NewPromise, PhantomNewPromise) participate in scalar replacement and OSR-exit materialization.
Audit directions
a Aaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaa Aa Aaa Aaaaaa Aaaaaaaa Aaaaaaa Aaa Aaaaaa Aaaaa Aaaaaa a Aaa Aaaaaaaaa Aaaaaaaaa Aaa Aaaaa Aa Aaa Aaaaa Aaaa Aaaa Aaaaa Aaa Aaaa Aaaaaaa Aaaaa Aaaaaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaa a Aaaa Aaaaaaaaaaaa Aaaaaaa Aa a Aaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aa Aaaa Aaaaaa Aaa Aaaaaaaaaaaa Aaaaa Aa Aaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaa Aa Aaa Aaaaaaaa Aaaaa Aaaaaa Aaaaa Aaaaaaaa Aa Aaaaaaaaaaaaaa Aaaaaaaa Aaa Aaaa Aaaaaa Aaaaaaaaaaaa
a Aaaaaaaaaaaa Aa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaa Aaaaaaa Aaa Aaaaaa Aaaa Aa a Aaaaaaaaaaaaaa Aaaa Aaaaa Aa a Aa Aaaaa Aaaaaaa Aaaaaaa Aaa Aaa Aaaaaa Aaaa Aaa Aaaaaaa Aaa Aaa Aaaa Aaaaa Aaa Aaaaaa Aaaa Aaaaa Aa Aaaaaaaaa Aaaaaa Aaaaa Aaaaaa Aa Aaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaa Aaaaaaa Aaaa Aaaaaaa
a Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aa Aaaaaaaaa Aaaaaaaaa Aaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaa Aaaaaaaa Aaaaaa Aaaaaaaaaaaaaa Aa Aaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaa Aaa Aaaaaaaaa Aaaaa Aaaaaaa Aaaaaaaaaaaaaaaaa Aaaaa Aaaaa Aaa Aaaaaa Aaaaaaa Aa Aaaaa Aaaaaaa Aa Aaaaaaaaa Aaa Aaa Aaa Aaaaaaa Aa a Aaa Aaaaaaaa
a Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaaaaaa Aaa Aaaaaaa Aaaaaaa Aaaaaaa Aaaaaa Aaa Aaa Aaaa Aaaaaaaaaaa Aaaaaa Aaaaaa Aaaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaa Aa Aaaaaa a Aaaaaaaaaaaa Aaaaaaaa Aaaaaa Aaaaaaaaaaaaaa Aaaaaaaa a Aaaa Aaaaaaaaaaa Aaaa Aaaaaaa Aaaaa Aa a Aaaaaaaa Aaaa Aaaaaaaa Aaaaaaaaaaa Aaaa Aa Aaaa Aaa Aaaaaaa Aa Aaaaaaaa
a Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaa Aaaaaaa Aaaaaaaaa Aaaaa Aaa Aaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaa Aa Aaaaaaaaaa Aaaaaaaaa Aaaa Aaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaaa Aa Aaa Aaaaa Aaaaaaaa Aaaaaa Aaa Aaaaa Aaaaaaaa Aa Aaaaaaaaaaaaaaa a Aaaaaaaa
🔒New inline reaction storage, spill path, and PhantomNewPromise materialization each introduce edge cases across GC, JIT, and settle dispatch worth close inspection.
더 확인하려면 구독해 주세요