mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-15 06:39:17 +00:00
feat(minifier): fold safe integer exponentiation (#25009)
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.
This commit is contained in:
1 parent
73fc747699
commit
70d6ecedb3
5 files changed
+25
-4
No files matched your search
@@ -358,6 +358,11 @@ impl<'a> PeepholeOptimizations {
|
||||
BinaryOperator::Multiplication => {
|
||||
Self::try_fold_shorter_numeric_expression(e, ctx)
|
||||
}
|
||||
// Number exponentiation is implementation-approximated, so only fold
|
||||
// integer-valued operands where the result is an exact safe integer.
|
||||
BinaryOperator::Exponential => Self::extract_numeric_values(e, ctx)
|
||||
.filter(|(base, exponent)| base.fract() == 0.0 && exponent.fract() == 0.0)
|
||||
.and_then(|_| Self::try_fold_safe_integer_numeric_expression(e, ctx)),
|
||||
BinaryOperator::Remainder => {
|
||||
Self::try_fold_safe_integer_numeric_expression(e, ctx)
|
||||
}
|
||||
|
||||
@@ -934,7 +934,7 @@ fn constant_evaluation_test() {
|
||||
test("x = 3 * 6", "x = 18;");
|
||||
test("x = 3 / 6", "x = 3 / 6;");
|
||||
test("x = 3 % 6", "x = 3;");
|
||||
test("x = 3 ** 6", "x = 3 ** 6;");
|
||||
test("x = 3 ** 6", "x = 729;");
|
||||
test("x = 0 / 0", "x = NaN;");
|
||||
test("x = 123 / 0", "x = Infinity;");
|
||||
test("x = 123 / -0", "x = -Infinity;");
|
||||
|
||||
@@ -1106,10 +1106,26 @@ fn test_fold_remainder() {
|
||||
|
||||
#[test]
|
||||
fn test_fold_exponential() {
|
||||
fold_same("x = 2 ** 3");
|
||||
fold("x = 2 ** 3", "x = 8");
|
||||
fold("x = 10 ** 4", "x = 1e4");
|
||||
fold("x = (-2) ** 3", "x = -8");
|
||||
|
||||
fold_same("x = 0.5 ** -2");
|
||||
fold_same("x = 4 ** 0.5");
|
||||
fold_same("x = (-5e-324) ** 3");
|
||||
fold_same("x = 2 ** -3");
|
||||
fold_same("x = 2 ** 50");
|
||||
fold_same("x = 2 ** 55");
|
||||
fold_same("x = 1e8 ** 2");
|
||||
fold_same("x = 3 ** -1");
|
||||
fold_same("x = f() ** 2");
|
||||
fold_same("x = 2 ** f()");
|
||||
fold_same("x = ({ valueOf: f }) ** 2");
|
||||
fold_same("x = 2n ** 3n");
|
||||
fold_same("x = 2n ** 3");
|
||||
fold_same("x = 2 ** 3n");
|
||||
fold_same("x = (void f()) ** 0");
|
||||
test_same("function f(Infinity) {\n\treturn Infinity ** 0;\n}");
|
||||
fold_same("x = (-1) ** 0.5");
|
||||
fold("x = (-0) ** 3", "x = -0");
|
||||
fold("x = null ** 0", "x = 1");
|
||||
|
||||
@@ -987,7 +987,7 @@ fn test_to_string() {
|
||||
|
||||
#[test]
|
||||
fn test_fold_pow() {
|
||||
test("v = Math.pow(2, 3)", "v = 2 ** 3");
|
||||
test("v = Math.pow(2, 3)", "v = 8");
|
||||
test("v = Math.pow(a, 3)", "v = a ** 3");
|
||||
test("v = Math.pow(2, b)", "v = 2 ** b");
|
||||
test("v = Math.pow(a, b)", "v = a ** +b");
|
||||
|
||||
@@ -71,7 +71,7 @@ kitchen-sink.tsx:
|
||||
sys deallocs: 1858
|
||||
sys alloc bytes: 5338078 # 5.34 MB
|
||||
sys peak growth: 3737991 # 3.74 MB
|
||||
arena allocs: 71930
|
||||
arena allocs: 71936
|
||||
arena reallocs: 12252
|
||||
arena size: 9561752 # 9.56 MB
|
||||
|
||||
Reference in new issue
Block a user