2 KiB
2 KiB
UNDF: UNDF-2026-000000588
jsc-0003: DFGIntegerRangeOptimizationPhase liveAtHead Vector::contains O(50×B×R×L) → O(50×B×R) with HashSet
Classification
| Field | Value |
|---|---|
| CWE | CWE-407 Inefficient Algorithmic Complexity |
| Severity | MEDIUM |
| Component | Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp:1996 |
| Function | performForBasicBlock fixed-point loop |
| Hot path | Integer range optimization pass — once per DFG compile for each function with integer ops |
| Status | PATCHED (unit test PASS) |
Defect
The integer range optimization phase runs a fixed-point loop (up to 50 iterations) over
all basic blocks. Inside the loop, for each block, it iterates over relationshipMap
entries (R relationships) and calls liveAtHead.contains(node) — an O(L) linear scan
of a WTF::Vector<NodeFlowProjection>:
// DFGIntegerRangeOptimizationPhase.cpp:1996
Vector<NodeFlowProjection> liveAtHead = ...; // L live nodes at block head
for (unsigned i = 50; i--;) { // 50 fixed-point iterations
for (BasicBlock* block : ...) { // B blocks
for (auto& entry : relationshipMap) { // R relationships
if (liveAtHead.contains(node)) // O(L) linear scan per check
...
}
}
}
With 50 iterations × B=20 blocks × R=30 relationships × L=40 live nodes: 1,200,000 comparisons per compile for a medium-sized function with integer-heavy loops.
Fix
Replace Vector<NodeFlowProjection> liveAtHead with UncheckedKeyHashSet<NodeFlowProjection>.
NodeFlowProjection already has a usable hash (it wraps a Node* + projection kind):
UncheckedKeyHashSet<NodeFlowProjection> liveAtHead;
// Populate once per block:
for (NodeFlowProjection proj : computeLiveAtHead(block))
liveAtHead.add(proj);
// Contains check: O(1)
if (liveAtHead.contains(node)) { ... }
Speedup: ~40× at L=40 (1.2M → 30K comparisons for 50×B=20×R=30).