Parent: #496 Related: #493, #520, #609, #610
Problem
Parser.checkParamBodyConflict enforced the FormalParameters/LexicallyDeclaredNames early error by first inserting every simple parameter into a hash table, then visiting the function body's direct lexical declarations. A body with no direct lexical declaration cannot conflict, but a 4K-parameter function still hashed, grew, and allocated the complete index before discovering that fact.
After #610 removed statement-location rescans, a current ReleaseFast profile made this redundant work explicit: checkParamBodyConflict owned StringHashMap.getOrPut, growth, and Wyhash samples for a frozen body containing only a directive expression and return. This was distinct from #520's required strict duplicate-parameter index.
Resolution
- Benchmark contract:
62a340ef,bench(frontend): add parameter conflict controls (#611). - Runtime fix:
bd24f7f2,perf(parser): skip impossible parameter conflicts (#611).
The parser now performs a bounded, non-recursive scan of only the function body's direct statement roots. Directive, return, expression, var-only, and nested-block bodies return before indexing parameters. Direct let, const, class, destructuring, and declaration-group shapes retain the existing exact indexed conflict algorithm.
Exact-parent evidence
Fifteen order-balanced pairs per row, all 150 fresh processes, no discarded samples. The host is diagnostic; wall values are supporting observations, while retired instructions and exact allocator accounting are the stable claims.
| ReleaseFast 4K row | wall | instructions | allocations | allocated bytes |
|---|---|---|---|---|
| ASCII strict parameters | 0.722x | 0.8035x | 68 -> 57 | 2,813,224 -> 2,534,568 |
| escaped identifiers | 0.825x | 0.8568x | 8,260 -> 8,249 | 4,475,960 -> 4,197,304 |
| Unicode identifiers | 0.725x | 0.8462x | 68 -> 57 | 2,813,224 -> 2,534,568 |
| direct lexical slow-path control | 1.032x | 1.0013x | 72 -> 72 | 2,813,688 -> 2,813,688 |
| nested-shadow control | 0.696x | 0.8031x | 75 -> 64 | 2,814,304 -> 2,535,648 |
All source hashes, binary identities, AST checksums, thermal states, and input identities matched. Energy was below counter resolution, so no energy claim is made. The direct control's exact allocation/byte result and 0.13% instruction delta show the required conflict path remains intact without material CPU regression.
Correctness
- test262 matches exactly across ordinary functions 451, statement generators 266, expression generators 290, statement async generators 301, expression async generators 623, async arrows 60, async function expressions 93, async declarations 74, object methods 303, and class methods 65:
2,526 -> 2,526, zero failures or flips. - Zero-capacity allocator coverage proves empty and nested-only bodies allocate no conflict index while a direct lexical declaration still enters the indexed path.
- Ordinary, async, generator, arrow, method, class, destructuring, and grouped direct conflicts remain rejected; nested lexical shadowing remains accepted.
- Frontend gate: 12/12. Focused Debug and TSan: 2/2 each.
- Four real-corpus witnesses pass in forced tree-walker and required-bytecode modes.
- Full units: 1,728 passed, one expected skip, zero failures, zero leaks.
Acceptance
- Zero-lexical bodies allocate/hash no parameter-body conflict index, including directive, return, expression,
var, and nested-block controls. - Direct
let,const, class, destructuring, and declaration-group conflicts remain SyntaxErrors for ordinary, async, generator, arrow, and method functions. - Nested lexical declarations remain outside the function body's direct LexicallyDeclaredNames and do not trigger false positives.
- Exact-parent evidence covers Unicode and ASCII 4K strict parameters plus a direct lexical-conflict control and a no-conflict nested-declaration control.
- Allocation and instruction reductions are causal; existing strict-parameter duplicate validation remains enabled and unchanged.
- Focused frontend Debug/TSan, full units, parameter/function test262, and forced tree-walker/required-bytecode witnesses remain exact.
Security and no-workaround ruling
Parameter count, identifier bytes, body statement count, declaration grouping, and destructuring depth remain attacker-controlled. The new precheck is bounded to direct roots and mirrors every AST shape inspected by the existing conflict algorithm. No early error, strict duplicate validation, or declaration traversal was removed; there is no source/benchmark recognition, name limit, AST/token widening, or job/Promise/microtask/Worker lifecycle change.