Summary
Resolving a promise with an object costs +78.5% instructions versus resolving with a number, on identical topology — identical promise, microtask and closure counts. The only differing counter is thenable_probe: 0 vs 24 000.
The cost is the spec-mandated Get(resolution, "then") assimilation check. Per probe it pays: a setjmp frame, re-interning the "then" key string, the generic dynamic getter's preamble, and a name-keyed miss walk into Object.prototype — roughly 72 000 times, answering undefined every time.
~9% of asyncpipe.
Why it was not fixed in #7906
The safe version needs an Object.prototype mutation-generation counter covering assignment, defineProperty, delete, and setPrototypeOf. Getting that wrong makes a genuine thenable stop being assimilated, and the failure mode is a hang rather than a wrong value — which is exactly the kind of thing that must not be landed against a deadline where each validation cycle is ~40 minutes.
Acceptance
- A fast path for the overwhelmingly common case (plain object, no
then anywhere on the chain) guarded by a generation counter that is invalidated by every mutation route into Object.prototype.
- A test that mutates
Object.prototype.then after the fast path has been taken and proves assimilation resumes.
- Negative test: a real thenable still assimilates.
Evidence
gc-handoff/ASYNC2-NOTES.md, with counters and file:line pointers.
Summary
Resolving a promise with an object costs +78.5% instructions versus resolving with a number, on identical topology — identical promise, microtask and closure counts. The only differing counter is
thenable_probe: 0 vs 24 000.The cost is the spec-mandated
Get(resolution, "then")assimilation check. Per probe it pays: asetjmpframe, re-interning the"then"key string, the generic dynamic getter's preamble, and a name-keyed miss walk intoObject.prototype— roughly 72 000 times, answeringundefinedevery time.~9% of
asyncpipe.Why it was not fixed in #7906
The safe version needs an
Object.prototypemutation-generation counter covering assignment,defineProperty,delete, andsetPrototypeOf. Getting that wrong makes a genuine thenable stop being assimilated, and the failure mode is a hang rather than a wrong value — which is exactly the kind of thing that must not be landed against a deadline where each validation cycle is ~40 minutes.Acceptance
thenanywhere on the chain) guarded by a generation counter that is invalidated by every mutation route intoObject.prototype.Object.prototype.thenafter the fast path has been taken and proves assimilation resumes.Evidence
gc-handoff/ASYNC2-NOTES.md, with counters and file:line pointers.