java-topology/defects/spidermonkey/patch/sm-0002-unrollloops-remapper-hashmap.md

58 lines
2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UNDF: UNDF-2026-000000536
# SM-0002: MDefinitionRemapper::lookup() O(N) linear scan in loop-unrolling phase
**File:** `js/src/jit/UnrollLoops.cpp`
**Lines:** 344354 (`lookup`), 11321140 (call site in unrolling loop)
**Severity:** MEDIUM
**CWE:** CWE-407 (Inefficient Algorithmic Complexity)
## Description
`MDefinitionRemapper` stores `(original, replacement)` pairs in a
`mozilla::Vector<Pair, 32, SystemAllocPolicy>`. Its `lookup()` method
iterates the entire vector linearly (O(V)) to find a key.
`lookup()` is called from `MakeReplacementInstruction()` and
`MakeReplacementPhi()` — once per operand of every instruction/phi being
cloned. These helpers are called inside a doubly-nested loop:
```
for cix in 1..unrollFactor: // copies
for bix in 0..numBlocksInOriginal: // blocks
for each phi in block:
for each operand of phi:
mapper.lookup(operand) // O(V) scan
for each insn in block:
for each operand of insn:
mapper.lookup(operand) // O(V) scan
```
With V values in the mapper (bounded by `MaxValuesForPeel = 150`), each
lookup is O(V) and the total cloning cost per body copy is O(V²) = up to
22 500 pointer comparisons. With `unrollFactor` up to ~4, worst case is
O(4 × V²) = 90 000 ops for a single loop unroll.
## Fix
Replace `mozilla::Vector<Pair, 32>` with
`mozilla::HashMap<MDefinition*, MDefinition*, DefaultHasher<MDefinition*>>`
(already available in `js/src/ds/PointerSet.h` or via `HashSet.h`).
`lookup()` becomes O(1) amortised. `enregister()` uses `put()`,
`update()` uses `put()`. No iteration order requirement exists for the
remapper — unlike `ValueSet` which has an inline size.
## Complexity
| Path | Before | After |
|------|--------|-------|
| `lookup()` | O(V) | O(1) |
| Total unroll of loop with V values | O(V²) | O(V) |
| Worst case (V=150, 4× unroll) | 90 000 ops | 600 ops |
**Speedup:** ~150× at V=150
## References
- `SimpleSet::add()` also calls `contains()` (O(N)) — see SM-0003
- Related fix: SM-0001 (LinearSum::add HashMap)