From 37c9959611c542d1ad3493c3d858682ce8acd6bc Mon Sep 17 00:00:00 2001 From: Boshen <1430279+Boshen@users.noreply.github.com> Date: Sat, 28 Dec 2024 06:05:04 +0000 Subject: [PATCH] feat(minifier): normalize `Infinity` into `f64::Infinity` (#8148) --- .../oxc_minifier/src/ast_passes/normalize.rs | 23 ++++++++++++++++++- .../peephole_minimize_conditions.rs | 7 ++++-- .../ast_passes/peephole_remove_dead_code.rs | 2 +- .../src/ast_passes/statement_fusion.rs | 10 ++++---- crates/oxc_minifier/src/node_util/mod.rs | 7 ++++++ crates/oxc_minifier/src/tester.rs | 3 ++- tasks/minsize/minsize.snap | 12 +++++----- 7 files changed, 48 insertions(+), 16 deletions(-) diff --git a/crates/oxc_minifier/src/ast_passes/normalize.rs b/crates/oxc_minifier/src/ast_passes/normalize.rs index cb25270742053..964e2c548d63e 100644 --- a/crates/oxc_minifier/src/ast_passes/normalize.rs +++ b/crates/oxc_minifier/src/ast_passes/normalize.rs @@ -2,7 +2,7 @@ use oxc_ast::ast::*; use oxc_syntax::scope::ScopeFlags; use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, TraverseCtx}; -use crate::CompressorPass; +use crate::{node_util::Ctx, CompressorPass}; /// Normalize AST /// @@ -25,6 +25,12 @@ impl<'a> Traverse<'a> for Normalize { Self::convert_while_to_for(stmt, ctx); } } + + fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { + if let Expression::Identifier(_) = expr { + Self::convert_infinity_into_number(expr, ctx); + } + } } impl<'a> Normalize { @@ -45,6 +51,21 @@ impl<'a> Normalize { ); *stmt = Statement::ForStatement(for_stmt); } + + fn convert_infinity_into_number(expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { + let ctx = Ctx(ctx); + match expr { + Expression::Identifier(ident) if ctx.is_identifier_infinity(ident) => { + *expr = ctx.ast.expression_numeric_literal( + ident.span, + f64::INFINITY, + None, + NumberBase::Decimal, + ); + } + _ => {} + } + } } #[cfg(test)] diff --git a/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs b/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs index 95568cd304af2..f3b4e8593bd3a 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs @@ -1276,8 +1276,11 @@ mod test { #[test] fn test_coercion_substitution_while() { // enableTypeCheck(); - test_same("var x = {}; while (x != null) throw 'a';"); - test_same("var x = 1; while (x != 0) throw 'a';"); + test( + "var x = {}; while (x != null) throw 'a';", + "var x = {}; for (;x != null;) throw 'a';", + ); + test("var x = 1; while (x != 0) throw 'a';", "var x = 1; for (;x != 0;) throw 'a';"); } #[test] diff --git a/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs b/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs index 5590a62b53417..18d23ed4b9353 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs @@ -456,7 +456,7 @@ mod test { // Cases to test for empty block. // fold("while(x()){x}", "while(x());"); - fold("while(x()){x()}", "while(x())x()"); + fold("while(x()){x()}", "for(;x();)x()"); // fold("for(x=0;x<100;x++){x}", "for(x=0;x<100;x++);"); // fold("for(x in y){x}", "for(x in y);"); // fold("for (x of y) {x}", "for(x of y);"); diff --git a/crates/oxc_minifier/src/ast_passes/statement_fusion.rs b/crates/oxc_minifier/src/ast_passes/statement_fusion.rs index 017af1aa98481..4d563d94789dc 100644 --- a/crates/oxc_minifier/src/ast_passes/statement_fusion.rs +++ b/crates/oxc_minifier/src/ast_passes/statement_fusion.rs @@ -285,10 +285,10 @@ mod test { #[test] fn fuse_into_label() { - // fuse("a;b;c;label:for(x in y){}", "label:for(x in a,b,c,y){}"); - // fuse("a;b;c;label:for(;g;){}", "label:for(a,b,c;g;){}"); - // fuse("a;b;c;l1:l2:l3:for(;g;){}", "l1:l2:l3:for(a,b,c;g;){}"); - fuse_same("a;b;c;label:while(true){}"); + fuse("a;b;c;label:for(x in y){}", "label:for(x in a,b,c,y){}"); + fuse("a;b;c;label:for(;g;){}", "label:for(a,b,c;g;){}"); + fuse("a;b;c;l1:l2:l3:for(;g;){}", "l1:l2:l3:for(a,b,c;g;){}"); + fuse("a;b;c;label:while(true){}", "label:for(a,b,c;true;){}"); } #[test] @@ -304,7 +304,7 @@ mod test { #[test] fn no_fuse_into_while() { - fuse_same("a;b;c;while(x){}"); + fuse("a;b;c;while(x){}", "for(a,b,c;x;){}"); } #[test] diff --git a/crates/oxc_minifier/src/node_util/mod.rs b/crates/oxc_minifier/src/node_util/mod.rs index a3c62f6d08480..cf662b884bc52 100644 --- a/crates/oxc_minifier/src/node_util/mod.rs +++ b/crates/oxc_minifier/src/node_util/mod.rs @@ -64,4 +64,11 @@ impl<'a> Ctx<'a, '_> { } false } + + pub fn is_identifier_infinity(self, ident: &IdentifierReference) -> bool { + if ident.name == "Infinity" && ident.is_global_reference(self.symbols()) { + return true; + } + false + } } diff --git a/crates/oxc_minifier/src/tester.rs b/crates/oxc_minifier/src/tester.rs index 0ae6dcaa875d0..25e438531028a 100644 --- a/crates/oxc_minifier/src/tester.rs +++ b/crates/oxc_minifier/src/tester.rs @@ -6,7 +6,7 @@ use oxc_span::SourceType; use oxc_traverse::ReusableTraverseCtx; use crate::{ - ast_passes::{CompressorPass, RemoveSyntax}, + ast_passes::{CompressorPass, Normalize, RemoveSyntax}, CompressOptions, }; @@ -45,6 +45,7 @@ fn run<'a, P: CompressorPass<'a>>( SemanticBuilder::new().build(&program).semantic.into_symbol_table_and_scope_tree(); let mut ctx = ReusableTraverseCtx::new(scopes, symbols, allocator); RemoveSyntax::new(CompressOptions::all_false()).build(&mut program, &mut ctx); + Normalize::new().build(&mut program, &mut ctx); pass.build(&mut program, &mut ctx); } diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index 8bb240402d3bf..0d863febd2b80 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -9,19 +9,19 @@ Original | minified | minified | gzip | gzip | Fixture 342.15 kB | 118.76 kB | 118.14 kB | 44.54 kB | 44.37 kB | vue.js -544.10 kB | 72.05 kB | 72.48 kB | 26.19 kB | 26.20 kB | lodash.js +544.10 kB | 72.04 kB | 72.48 kB | 26.18 kB | 26.20 kB | lodash.js -555.77 kB | 274.04 kB | 270.13 kB | 91.20 kB | 90.80 kB | d3.js +555.77 kB | 273.90 kB | 270.13 kB | 91.19 kB | 90.80 kB | d3.js 1.01 MB | 461.13 kB | 458.89 kB | 126.91 kB | 126.71 kB | bundle.min.js -1.25 MB | 656.86 kB | 646.76 kB | 164.20 kB | 163.73 kB | three.js +1.25 MB | 656.81 kB | 646.76 kB | 164.16 kB | 163.73 kB | three.js -2.14 MB | 735.43 kB | 724.14 kB | 181.01 kB | 181.07 kB | victory.js +2.14 MB | 735.33 kB | 724.14 kB | 180.99 kB | 181.07 kB | victory.js -3.20 MB | 1.01 MB | 1.01 MB | 332.34 kB | 331.56 kB | echarts.js +3.20 MB | 1.01 MB | 1.01 MB | 332.27 kB | 331.56 kB | echarts.js 6.69 MB | 2.36 MB | 2.31 MB | 495.04 kB | 488.28 kB | antd.js -10.95 MB | 3.51 MB | 3.49 MB | 910.95 kB | 915.50 kB | typescript.js +10.95 MB | 3.51 MB | 3.49 MB | 910.93 kB | 915.50 kB | typescript.js