JSC: inline allocation for Promise.resolve(non-thenable)
ConstantFoldingPhase uses condition-set watchpoints to prove an object's prototype chain has no then property, making it a non-thenable. Previously, when proven, it still emitted NewResolvedPromise with a clobberTop() C-call to operationNewResolvedPromise, defeating the optimization potential. This commit threads an isResolvedValueKnownNonThenable flag through the node so proven-object arguments produce inline allocation; clobberize narrows from clobberTop() to HeapObjectCount, and the abstract interpreter propagates a sharper inferred type.
Significance
The clobberize change from clobberTop() to HeapObjectCount is a significant alias-analysis loosening that lets store elimination, LICM, and GVN reason past the node — but it depends on the inline allocation truly having no side effects beyond allocation.
Audit directions
-
Deopt-boundary race on watchpoint invalidation. The flag is baked into compiled code based on a watchpoint-guarded assumption. If prototype-chain mutation fires the watchpoint after
ConstantFoldingPhasesets the flag but before deoptimization fully takes effect, the inline allocation path runs without verifying thenable-ness — a classic JIT deopt-boundary race. -
Clobberize narrowing soundness. If any edge case lets the inline allocation path do more than allocate (run a finalizer, touch a weak reference), the new modeling is wrong and could corrupt dependent optimizations.
-
Abstract interpreter type propagation. A different inferred type now reaches downstream nodes. Incorrect propagation here could make speculations elsewhere in the graph unsound — the
resolvePrototest explicitly exercises the watchpoint-invalidation boundary that historically produced exploitable JIT bugs in V8 and SpiderMonkey.