feat(minifier): fold safe integer exponentiation - #25009
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Merging this PR will not alter performance
Comparing Footnotes
|
Merge activity
|
Integer exponentiation remains uncompressed even when its Number result is an exact safe integer and a shorter literal can represent it. This also prevents the existing `Math.pow` rewrite from completing beyond the exponentiation form. Fold these cases only when both operands have side-effect-free integer-valued numeric values, the result is within the Number safe-integer range, and the serialized literal is no longer than a conservative lower bound for the original expression. Number exponentiation is implementation-approximated, so fractional operands remain unchanged. BigInt, observable coercions, side effects, unsafe results, and size regressions are rejected. ## Example Input: ```js use(2 ** 3); ``` Before: ```js use(2 ** 3); ``` After: ```js use(8); ``` The minsize corpus reduces Three.js by 2 raw bytes and 1 byte with gzip, below the reported 0.01 kB snapshot precision. The tracked kitchen-sink fixture records six additional arena node allocations from the new replacement; heap metrics and arena size are unchanged. Verified with the full `oxc_minifier` test suite, `just minsize`, Clippy with warnings denied, formatting, and `git diff --check`. Implemented with AI assistance (OpenAI Codex). The contributor remains responsible for reviewing, understanding, and submitting the changes under the repository AI usage policy.
0fc2835 to
70d6ece
Compare
### 💥 BREAKING CHANGES - 4120da0 semantic: [**BREAKING**] Return borrowed JSDoc so the parse cache works (#25186) (Connor Shea) - f0a41c8 allocator: [**BREAKING**] Remove `ArenaBox::dangling` method (#25236) (overlookmotel) - 067da8c ast: [**BREAKING**] Store single parameter in `TSIndexSignature::parameter` (#25154) (camc314) - a0c7788 ast: [**BREAKING**] Change `TSIndexSignatureName::name` to `Ident` (#25150) (camc314) - 1bdedd1 ast: [**BREAKING**] Introduce `ExportDeclaration`, `ExportFromDeclaration` (#25095) (camc314) - c917f20 ast: [**BREAKING**] Introduce `ArrowFunctionBody` enum (#24987) (camc314) - 7e1199c ast: [**BREAKING**] Remove conversion to `Box` from AST builder methods (#25038) (overlookmotel) ### 🚀 Features - 3c8312e allocator: Make `Box` `Send` + `Sync` when the type it contains is (#25242) (overlookmotel) - cb5bc08 ast: Derive `GetSpan` for `Comment` (#25147) (leaysgur) - 8541e18 ast_tools: Generate minifier scope collector (#25088) (camc314) - 5acdae2 ecmascript: Skip transparent TS expressions (#25072) (camc314) - 85d0f4d napi: Add React Compiler transform binding (#24934) (Boshen) - 70d6ece minifier: Fold safe integer exponentiation (#25009) (Dunqing) - 73fc747 minifier: Enable termination statement optimization for do while (#24921) (Armano) - 5eadfdb minifier: Fold safe integer division and remainder (#24981) (Dunqing) ### 🐛 Bug Fixes - 6c9ee14 minifier: Preserve if-chain idempotency and correct side effects when alternate should not be moved (#25041) (Armano) - 8a47ff3 ecmascript: Do not treat lone-surrogate strings as constants (#25084) (Dunqing) - 468b970 isolated-declarations: Strip re-export attributes (#25090) (camc314) - a70035d parser: Report export imports in namespaces (#25086) (camc314) - 5d8ccf5 react_compiler: Preserve nonfatal diagnostics (#25066) (Boshen) - d349e4a react_compiler: Match eslint suppression gating (#25068) (Boshen) - 0dc16ba react_compiler: Track catch block declarations (#25067) (Boshen) - e6734a5 minifier: Fold typeof comparisons with known object strings (#25017) (Dunqing) - 3a9d5a5 minifier: Keep `typeof foo == ['object']` as-is (#24941) (sapphi-red) - 10ec276 ast: Custom AST builder methods take `IntoIn<ArenaBox>` where child method does (#25033) (overlookmotel) - fbe8d31 minifier: Respect targets when folding RegExp source (#24790) (Dunqing) ### ⚡ Performance - fb402b0 minifier: Stop re-deriving printed numeric spellings (#25103) (Dunqing) - 7251e52 react_compiler: Avoid large types on stack (#25037) (overlookmotel) - e07718f isolated_declarations: Avoid large types on stack (#25036) (overlookmotel) - 9fb1e3e transformer: Avoid large types on stack (#25035) (overlookmotel) - 8b80f8b parser: Avoid large types on stack (#25034) (overlookmotel) ### 📚 Documentation - 2ea0aa9 ast: Correct grammar in AST builder methods doc comments (#25173) (overlookmotel)

Integer exponentiation remains uncompressed even when its Number result is an exact safe integer and a shorter literal can represent it. This also prevents the existing
Math.powrewrite from completing beyond the exponentiation form.Fold these cases only when both operands have side-effect-free integer-valued numeric values, the result is within the Number safe-integer range, and the serialized literal is no longer than a conservative lower bound for the original expression. Number exponentiation is implementation-approximated, so fractional operands remain unchanged. BigInt, observable coercions, side effects, unsafe results, and size regressions are rejected.
Example
Input:
Before:
After:
The minsize corpus reduces Three.js by 2 raw bytes and 1 byte with gzip, below the reported 0.01 kB snapshot precision. The tracked kitchen-sink fixture records six additional arena node allocations from the new replacement; heap metrics and arena size are unchanged.
Verified with the full
oxc_minifiertest suite,just minsize, Clippy with warnings denied, formatting, andgit diff --check.Implemented with AI assistance (OpenAI Codex). The contributor remains responsible for reviewing, understanding, and submitting the changes under the repository AI usage policy.