Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: ed1ea245850f9bfe39534edb6a0db7d7cf714ec6
https://github.com/WebKit/WebKit/commit/ed1ea245850f9bfe39534edb6a0db7d7cf714ec6
Author: Yusuke Suzuki <[email protected]>
Date: 2026-10-09 (Fri, 09 Oct 2026)
Changed paths:
A JSTests/stress/movhint-removal-terminal-liveness-only-for-phantom.js
M Source/JavaScriptCore/dfg/DFGMovHintRemovalPhase.cpp
Log Message:
-----------
[JSC] MovHint removal should apply the block-terminal liveness rule only to
phantom allocations
https://bugs.webkit.org/show_bug.cgi?id=326643
rdar://189380801
Reviewed by Yijia Huang.
MovHint removal phase treats the bytecode-live locals at every block
terminal as uses even when the terminal does not exit. This is because
of phantom allocations. Let's have a code like this.
function g(c, s) {
let o = { f: 1 }; // loc5
if (c) {
let p = o; // loc6; o is never read after this
return p.f + s; // s may fail its Int32 check and exit
}
return o.f;
}
After object allocation sinking, o never escapes, so it becomes a phantom.
Block #0:
D@1: PhantomNewObject()
D@2: PutHint(D@1, StructurePLoc, %S)
D@3: PutHint(D@1, NamedPropertyPLoc(f), Int32: 1)
D@4: MovHint(D@1, loc5) // o = D@1
D@5: Branch(D@c, T:#1, F:#2) // does not exit; loc5
bytecode-live here
Block #1: // loc5 bytecode-live at
head (read by `p = o`)
D@6: MovHint(D@1, loc6) // p = D@1; loc5 dead in
bytecode from here on
D@7: ArithAdd(Int32:D@f, Int32:D@s) // Exits. Live: loc6, not
loc5
Block #2:
D@8: Return(Int32: 1) // o.f folded by sinking;
does not exit
With exit-only liveness, D@4 is removed. Nothing exits after D@4 in block
#0.
The only exit in block #1 (D@7) has loc5 dead, and block #2 has no exit.
So D@4 becomes ZombieHint(loc5). Now follow OSR availability analysis:
Tail of #0: locals { loc5: <bottom constant> }
heap { [email protected] = %S, [email protected] = 1 }
Head of #1, after pruneByLiveness:
bytecode-live locals = { loc5, ... }
loc5 holds the bottom constant, not D@1
-> no live local reaches D@1
-> heap entries keyed on D@1 are dropped
heap { }
D@6: loc6 = D@1 // the phantom is reachable again...
D@7 exit: must materialize D@1 for loc6, but D@1's Structure and f
are gone
The exit at D@7 needs o through a different local (loc6). The state
describing
o was pruned at the head of #1, because the only local that reached it at
that
point had already been zombified.
This patch makes liveness three-level lattice, Dead < Anchored < Observed.
1. Exits make a local Observed, as it must exist.
2. Block terminals make it at least Anchored.
Then when removing MovHint, we keep Anchored one only when it is
referenced from phantoms.
Test: JSTests/stress/movhint-removal-terminal-liveness-only-for-phantom.js
* JSTests/stress/movhint-removal-terminal-liveness-only-for-phantom.js: Added.
(f):
(g):
(get f):
* Source/JavaScriptCore/dfg/DFGMovHintRemovalPhase.cpp:
Canonical link: https://commits.webkit.org/323212@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications