mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
refactor(minifier): remove all the unnecessary fake ast passes (#8618)
This also removes handling of making cjs-module-lexer to work.
This commit is contained in:
parent
787aaad977
commit
6f95cd599a
14 changed files with 203 additions and 511 deletions
|
|
@ -1,41 +1,27 @@
|
|||
use oxc_allocator::Vec;
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, TraverseCtx};
|
||||
use oxc_traverse::TraverseCtx;
|
||||
|
||||
use crate::CompressorPass;
|
||||
use super::PeepholeOptimizations;
|
||||
|
||||
/// Collapse variable declarations.
|
||||
///
|
||||
/// Join Vars:
|
||||
/// `var a; var b = 1; var c = 2` => `var a, b = 1; c = 2`
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/CollapseVariableDeclarations.java>
|
||||
///
|
||||
/// Collapse into for statements:
|
||||
/// `var a = 0; for(;a<0;a++) {}` => `for(var a = 0;a<0;a++) {}`
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/Denormalize.java>
|
||||
pub struct CollapseVariableDeclarations {
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for CollapseVariableDeclarations {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Traverse<'a> for CollapseVariableDeclarations {
|
||||
fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
|
||||
impl<'a> PeepholeOptimizations {
|
||||
/// Collapse variable declarations.
|
||||
///
|
||||
/// Join Vars:
|
||||
/// `var a; var b = 1; var c = 2` => `var a, b = 1; c = 2`
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/CollapseVariableDeclarations.java>
|
||||
///
|
||||
/// Collapse into for statements:
|
||||
/// `var a = 0; for(;a<0;a++) {}` => `for(var a = 0;a<0;a++) {}`
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/Denormalize.java>
|
||||
pub fn collapse_variable_declarations(
|
||||
&mut self,
|
||||
stmts: &mut Vec<'a, Statement<'a>>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.join_vars(stmts, ctx);
|
||||
self.maybe_collapse_into_for_statements(stmts, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
// Join Vars
|
||||
impl<'a> CollapseVariableDeclarations {
|
||||
pub fn new() -> Self {
|
||||
Self { changed: false }
|
||||
}
|
||||
|
||||
fn is_require_call(var_decl: &VariableDeclaration) -> bool {
|
||||
var_decl
|
||||
|
|
@ -112,7 +98,7 @@ impl<'a> CollapseVariableDeclarations {
|
|||
}
|
||||
|
||||
// Collapse into for statements
|
||||
impl<'a> CollapseVariableDeclarations {
|
||||
impl<'a> PeepholeOptimizations {
|
||||
fn maybe_collapse_into_for_statements(
|
||||
&mut self,
|
||||
stmts: &mut Vec<'a, Statement<'a>>,
|
||||
|
|
@ -240,18 +226,6 @@ mod test {
|
|||
mod join_vars {
|
||||
use super::{test, test_same};
|
||||
|
||||
#[test]
|
||||
fn cjs() {
|
||||
// Do not join `require` calls for cjs-module-lexer.
|
||||
test_same(
|
||||
" Object.defineProperty(exports, '__esModule', { value: true });
|
||||
var compilerDom = require('@vue/compiler-dom');
|
||||
var runtimeDom = require('@vue/runtime-dom');
|
||||
var shared = require('@vue/shared');
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_collapsing() {
|
||||
// Basic collapsing
|
||||
|
|
|
|||
|
|
@ -1,27 +1,16 @@
|
|||
use oxc_ast::ast::*;
|
||||
use oxc_syntax::identifier::is_identifier_name;
|
||||
use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, TraverseCtx};
|
||||
use oxc_traverse::TraverseCtx;
|
||||
|
||||
use crate::{ctx::Ctx, CompressorPass};
|
||||
use super::PeepholeOptimizations;
|
||||
use crate::ctx::Ctx;
|
||||
|
||||
/// Converts property accesses from quoted string or bracket access syntax to dot or unquoted string
|
||||
/// syntax, where possible. Dot syntax is more compact.
|
||||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/ConvertToDottedProperties.java>
|
||||
pub struct ConvertToDottedProperties {
|
||||
pub(crate) changed: bool,
|
||||
in_fixed_loop: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for ConvertToDottedProperties {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = true;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Traverse<'a> for ConvertToDottedProperties {
|
||||
fn exit_member_expression(
|
||||
impl<'a> PeepholeOptimizations {
|
||||
/// Converts property accesses from quoted string or bracket access syntax to dot or unquoted string
|
||||
/// syntax, where possible. Dot syntax is more compact.
|
||||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/ConvertToDottedProperties.java>
|
||||
pub fn convert_to_dotted_properties(
|
||||
&mut self,
|
||||
expr: &mut MemberExpression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
|
|
@ -30,12 +19,6 @@ impl<'a> Traverse<'a> for ConvertToDottedProperties {
|
|||
self.try_compress_computed_member_expression(expr, Ctx(ctx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ConvertToDottedProperties {
|
||||
pub fn new(in_fixed_loop: bool) -> Self {
|
||||
Self { changed: false, in_fixed_loop }
|
||||
}
|
||||
|
||||
/// `foo['bar']` -> `foo.bar`
|
||||
/// `foo?.['bar']` -> `foo?.bar`
|
||||
|
|
|
|||
|
|
@ -1,31 +1,19 @@
|
|||
use oxc_allocator::Vec;
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, TraverseCtx};
|
||||
use oxc_traverse::TraverseCtx;
|
||||
|
||||
use crate::CompressorPass;
|
||||
use super::PeepholeOptimizations;
|
||||
|
||||
/// Tries to chain assignments together.
|
||||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/ExploitAssigns.java>
|
||||
pub struct ExploitAssigns {
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for ExploitAssigns {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Traverse<'a> for ExploitAssigns {
|
||||
fn exit_statements(&mut self, _stmts: &mut Vec<'a, Statement<'a>>, _ctx: &mut TraverseCtx<'a>) {
|
||||
}
|
||||
}
|
||||
|
||||
impl ExploitAssigns {
|
||||
pub fn new() -> Self {
|
||||
Self { changed: false }
|
||||
impl<'a> PeepholeOptimizations {
|
||||
/// Tries to chain assignments together.
|
||||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/ExploitAssigns.java>
|
||||
#[expect(clippy::unused_self)]
|
||||
pub fn exploit_assigns(
|
||||
&mut self,
|
||||
_stmts: &mut Vec<'a, Statement<'a>>,
|
||||
_ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,34 +1,21 @@
|
|||
use oxc_allocator::Vec;
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, TraverseCtx};
|
||||
use oxc_traverse::TraverseCtx;
|
||||
|
||||
use crate::CompressorPass;
|
||||
use super::PeepholeOptimizations;
|
||||
|
||||
/// Transform the structure of the AST so that the number of explicit exits
|
||||
/// are minimized and instead flows to implicit exits conditions.
|
||||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/MinimizeExitPoints.java>
|
||||
pub struct MinimizeExitPoints {
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for MinimizeExitPoints {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl Traverse<'_> for MinimizeExitPoints {
|
||||
fn exit_function_body(&mut self, body: &mut FunctionBody<'_>, _ctx: &mut TraverseCtx<'_>) {
|
||||
impl<'a> PeepholeOptimizations {
|
||||
/// Transform the structure of the AST so that the number of explicit exits
|
||||
/// are minimized and instead flows to implicit exits conditions.
|
||||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/MinimizeExitPoints.java>
|
||||
pub fn minimize_exit_points(
|
||||
&mut self,
|
||||
body: &mut FunctionBody<'_>,
|
||||
_ctx: &mut TraverseCtx<'_>,
|
||||
) {
|
||||
self.remove_last_return(&mut body.statements);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MinimizeExitPoints {
|
||||
pub fn new() -> Self {
|
||||
Self { changed: false }
|
||||
}
|
||||
|
||||
// `function foo() { return }` -> `function foo() {}`
|
||||
fn remove_last_return(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
||||
|
|
|
|||
|
|
@ -16,84 +16,25 @@ mod peephole_substitute_alternate_syntax;
|
|||
mod remove_unused_code;
|
||||
mod statement_fusion;
|
||||
|
||||
pub use collapse_variable_declarations::CollapseVariableDeclarations;
|
||||
pub use convert_to_dotted_properties::ConvertToDottedProperties;
|
||||
pub use exploit_assigns::ExploitAssigns;
|
||||
pub use minimize_exit_points::MinimizeExitPoints;
|
||||
pub use normalize::{Normalize, NormalizeOptions};
|
||||
pub use peephole_fold_constants::PeepholeFoldConstants;
|
||||
pub use peephole_minimize_conditions::PeepholeMinimizeConditions;
|
||||
pub use peephole_remove_dead_code::PeepholeRemoveDeadCode;
|
||||
pub use peephole_replace_known_methods::PeepholeReplaceKnownMethods;
|
||||
pub use peephole_substitute_alternate_syntax::PeepholeSubstituteAlternateSyntax;
|
||||
#[expect(unused)]
|
||||
pub use remove_unused_code::RemoveUnusedCode;
|
||||
pub use statement_fusion::StatementFusion;
|
||||
|
||||
use crate::CompressOptions;
|
||||
|
||||
pub trait CompressorPass<'a>: Traverse<'a> {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>);
|
||||
}
|
||||
|
||||
pub struct PeepholeOptimizations {
|
||||
x0_statement_fusion: StatementFusion,
|
||||
x1_minimize_exit_points: MinimizeExitPoints,
|
||||
x2_exploit_assigns: ExploitAssigns,
|
||||
x3_collapse_variable_declarations: CollapseVariableDeclarations,
|
||||
x4_peephole_fold_constants: PeepholeFoldConstants,
|
||||
x6_peephole_remove_dead_code: PeepholeRemoveDeadCode,
|
||||
x5_peephole_minimize_conditions: PeepholeMinimizeConditions,
|
||||
x7_convert_to_dotted_properties: ConvertToDottedProperties,
|
||||
x8_peephole_replace_known_methods: PeepholeReplaceKnownMethods,
|
||||
x9_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax,
|
||||
target: ESTarget,
|
||||
changed: bool,
|
||||
/// `in_fixed_loop`: Do not compress syntaxes that are hard to analyze inside the fixed loop.
|
||||
/// Opposite of `late` in Closure Compiler.
|
||||
in_fixed_loop: bool,
|
||||
}
|
||||
|
||||
impl PeepholeOptimizations {
|
||||
/// `in_fixed_loop`: Do not compress syntaxes that are hard to analyze inside the fixed loop.
|
||||
/// Opposite of `late` in Closure Compiler.
|
||||
pub fn new(target: ESTarget, in_fixed_loop: bool, options: CompressOptions) -> Self {
|
||||
Self {
|
||||
x0_statement_fusion: StatementFusion::new(),
|
||||
x1_minimize_exit_points: MinimizeExitPoints::new(),
|
||||
x2_exploit_assigns: ExploitAssigns::new(),
|
||||
x3_collapse_variable_declarations: CollapseVariableDeclarations::new(),
|
||||
x4_peephole_fold_constants: PeepholeFoldConstants::new(),
|
||||
x5_peephole_minimize_conditions: PeepholeMinimizeConditions::new(target),
|
||||
x6_peephole_remove_dead_code: PeepholeRemoveDeadCode::new(in_fixed_loop),
|
||||
x7_convert_to_dotted_properties: ConvertToDottedProperties::new(in_fixed_loop),
|
||||
x8_peephole_replace_known_methods: PeepholeReplaceKnownMethods::new(),
|
||||
x9_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax::new(
|
||||
options.target,
|
||||
in_fixed_loop,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_changed(&mut self) {
|
||||
self.x0_statement_fusion.changed = false;
|
||||
self.x1_minimize_exit_points.changed = false;
|
||||
self.x2_exploit_assigns.changed = false;
|
||||
self.x3_collapse_variable_declarations.changed = false;
|
||||
self.x4_peephole_fold_constants.changed = false;
|
||||
self.x5_peephole_minimize_conditions.changed = false;
|
||||
self.x6_peephole_remove_dead_code.changed = false;
|
||||
self.x7_convert_to_dotted_properties.changed = false;
|
||||
self.x8_peephole_replace_known_methods.changed = false;
|
||||
self.x9_peephole_substitute_alternate_syntax.changed = false;
|
||||
}
|
||||
|
||||
fn changed(&self) -> bool {
|
||||
self.x0_statement_fusion.changed
|
||||
|| self.x1_minimize_exit_points.changed
|
||||
|| self.x2_exploit_assigns.changed
|
||||
|| self.x3_collapse_variable_declarations.changed
|
||||
|| self.x4_peephole_fold_constants.changed
|
||||
|| self.x5_peephole_minimize_conditions.changed
|
||||
|| self.x6_peephole_remove_dead_code.changed
|
||||
|| self.x7_convert_to_dotted_properties.changed
|
||||
|| self.x8_peephole_replace_known_methods.changed
|
||||
|| self.x9_peephole_substitute_alternate_syntax.changed
|
||||
pub fn new(target: ESTarget, in_fixed_loop: bool) -> Self {
|
||||
Self { target, changed: false, in_fixed_loop }
|
||||
}
|
||||
|
||||
pub fn run_in_loop<'a>(
|
||||
|
|
@ -103,9 +44,9 @@ impl PeepholeOptimizations {
|
|||
) {
|
||||
let mut i = 0;
|
||||
loop {
|
||||
self.reset_changed();
|
||||
self.changed = false;
|
||||
self.build(program, ctx);
|
||||
if !self.changed() {
|
||||
if !self.changed {
|
||||
break;
|
||||
}
|
||||
if i > 10 {
|
||||
|
|
@ -124,33 +65,29 @@ impl<'a> CompressorPass<'a> for PeepholeOptimizations {
|
|||
}
|
||||
|
||||
impl<'a> Traverse<'a> for PeepholeOptimizations {
|
||||
fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x6_peephole_remove_dead_code.exit_program(program, ctx);
|
||||
}
|
||||
|
||||
fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x0_statement_fusion.exit_statements(stmts, ctx);
|
||||
self.x2_exploit_assigns.exit_statements(stmts, ctx);
|
||||
self.x3_collapse_variable_declarations.exit_statements(stmts, ctx);
|
||||
self.x5_peephole_minimize_conditions.exit_statements(stmts, ctx);
|
||||
self.x6_peephole_remove_dead_code.exit_statements(stmts, ctx);
|
||||
self.statement_fusion_exit_statements(stmts, ctx);
|
||||
self.exploit_assigns(stmts, ctx);
|
||||
self.collapse_variable_declarations(stmts, ctx);
|
||||
self.minimize_conditions_exit_statements(stmts, ctx);
|
||||
self.remove_dead_code_exit_statements(stmts, ctx);
|
||||
}
|
||||
|
||||
fn exit_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x5_peephole_minimize_conditions.exit_statement(stmt, ctx);
|
||||
self.x6_peephole_remove_dead_code.exit_statement(stmt, ctx);
|
||||
self.minimize_conditions_exit_statement(stmt, ctx);
|
||||
self.remove_dead_code_exit_statement(stmt, ctx);
|
||||
}
|
||||
|
||||
fn exit_return_statement(&mut self, stmt: &mut ReturnStatement<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x9_peephole_substitute_alternate_syntax.exit_return_statement(stmt, ctx);
|
||||
self.substitute_return_statement(stmt, ctx);
|
||||
}
|
||||
|
||||
fn exit_function_body(&mut self, body: &mut FunctionBody<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x1_minimize_exit_points.exit_function_body(body, ctx);
|
||||
self.minimize_exit_points(body, ctx);
|
||||
}
|
||||
|
||||
fn exit_class_body(&mut self, body: &mut ClassBody<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x6_peephole_remove_dead_code.exit_class_body(body, ctx);
|
||||
self.remove_dead_code_exit_class_body(body, ctx);
|
||||
}
|
||||
|
||||
fn exit_variable_declaration(
|
||||
|
|
@ -158,23 +95,19 @@ impl<'a> Traverse<'a> for PeepholeOptimizations {
|
|||
decl: &mut VariableDeclaration<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.x9_peephole_substitute_alternate_syntax.exit_variable_declaration(decl, ctx);
|
||||
self.substitute_variable_declaration(decl, ctx);
|
||||
}
|
||||
|
||||
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x4_peephole_fold_constants.exit_expression(expr, ctx);
|
||||
self.x5_peephole_minimize_conditions.exit_expression(expr, ctx);
|
||||
self.x6_peephole_remove_dead_code.exit_expression(expr, ctx);
|
||||
self.x8_peephole_replace_known_methods.exit_expression(expr, ctx);
|
||||
self.x9_peephole_substitute_alternate_syntax.exit_expression(expr, ctx);
|
||||
}
|
||||
|
||||
fn enter_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x9_peephole_substitute_alternate_syntax.enter_call_expression(expr, ctx);
|
||||
self.fold_constants_exit_expression(expr, ctx);
|
||||
self.minimize_conditions_exit_expression(expr, ctx);
|
||||
self.remove_dead_code_exit_expression(expr, ctx);
|
||||
self.replace_known_methods_exit_expression(expr, ctx);
|
||||
self.substitute_exit_expression(expr, ctx);
|
||||
}
|
||||
|
||||
fn exit_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x9_peephole_substitute_alternate_syntax.exit_call_expression(expr, ctx);
|
||||
self.substitute_call_expression(expr, ctx);
|
||||
}
|
||||
|
||||
fn exit_member_expression(
|
||||
|
|
@ -182,11 +115,11 @@ impl<'a> Traverse<'a> for PeepholeOptimizations {
|
|||
expr: &mut MemberExpression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.x7_convert_to_dotted_properties.exit_member_expression(expr, ctx);
|
||||
self.convert_to_dotted_properties(expr, ctx);
|
||||
}
|
||||
|
||||
fn exit_object_property(&mut self, prop: &mut ObjectProperty<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x9_peephole_substitute_alternate_syntax.exit_object_property(prop, ctx);
|
||||
self.substitute_object_property(prop, ctx);
|
||||
}
|
||||
|
||||
fn exit_assignment_target_property_property(
|
||||
|
|
@ -194,12 +127,11 @@ impl<'a> Traverse<'a> for PeepholeOptimizations {
|
|||
prop: &mut AssignmentTargetPropertyProperty<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.x9_peephole_substitute_alternate_syntax
|
||||
.exit_assignment_target_property_property(prop, ctx);
|
||||
self.substitute_assignment_target_property_property(prop, ctx);
|
||||
}
|
||||
|
||||
fn exit_binding_property(&mut self, prop: &mut BindingProperty<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x9_peephole_substitute_alternate_syntax.exit_binding_property(prop, ctx);
|
||||
self.substitute_binding_property(prop, ctx);
|
||||
}
|
||||
|
||||
fn exit_method_definition(
|
||||
|
|
@ -207,7 +139,7 @@ impl<'a> Traverse<'a> for PeepholeOptimizations {
|
|||
prop: &mut MethodDefinition<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.x9_peephole_substitute_alternate_syntax.exit_method_definition(prop, ctx);
|
||||
self.substitute_method_definition(prop, ctx);
|
||||
}
|
||||
|
||||
fn exit_property_definition(
|
||||
|
|
@ -215,7 +147,7 @@ impl<'a> Traverse<'a> for PeepholeOptimizations {
|
|||
prop: &mut PropertyDefinition<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.x9_peephole_substitute_alternate_syntax.exit_property_definition(prop, ctx);
|
||||
self.substitute_property_definition(prop, ctx);
|
||||
}
|
||||
|
||||
fn exit_accessor_property(
|
||||
|
|
@ -223,25 +155,21 @@ impl<'a> Traverse<'a> for PeepholeOptimizations {
|
|||
prop: &mut AccessorProperty<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.x9_peephole_substitute_alternate_syntax.exit_accessor_property(prop, ctx);
|
||||
self.substitute_accessor_property(prop, ctx);
|
||||
}
|
||||
|
||||
fn exit_catch_clause(&mut self, catch: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x9_peephole_substitute_alternate_syntax.exit_catch_clause(catch, ctx);
|
||||
self.substitute_catch_clause(catch, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DeadCodeElimination {
|
||||
x1_peephole_fold_constants: PeepholeFoldConstants,
|
||||
x2_peephole_remove_dead_code: PeepholeRemoveDeadCode,
|
||||
inner: PeepholeOptimizations,
|
||||
}
|
||||
|
||||
impl DeadCodeElimination {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
x1_peephole_fold_constants: PeepholeFoldConstants::new(),
|
||||
x2_peephole_remove_dead_code: PeepholeRemoveDeadCode::new(false),
|
||||
}
|
||||
Self { inner: PeepholeOptimizations::new(ESTarget::ESNext, false) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -253,19 +181,15 @@ impl<'a> CompressorPass<'a> for DeadCodeElimination {
|
|||
|
||||
impl<'a> Traverse<'a> for DeadCodeElimination {
|
||||
fn exit_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x2_peephole_remove_dead_code.exit_statement(stmt, ctx);
|
||||
}
|
||||
|
||||
fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x2_peephole_remove_dead_code.exit_program(program, ctx);
|
||||
self.inner.remove_dead_code_exit_statement(stmt, ctx);
|
||||
}
|
||||
|
||||
fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x2_peephole_remove_dead_code.exit_statements(stmts, ctx);
|
||||
self.inner.remove_dead_code_exit_statements(stmts, ctx);
|
||||
}
|
||||
|
||||
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x1_peephole_fold_constants.exit_expression(expr, ctx);
|
||||
self.x2_peephole_remove_dead_code.exit_expression(expr, ctx);
|
||||
self.inner.fold_constants_exit_expression(expr, ctx);
|
||||
self.inner.remove_dead_code_exit_expression(expr, ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,26 +8,21 @@ use oxc_syntax::{
|
|||
number::NumberBase,
|
||||
operator::{BinaryOperator, LogicalOperator},
|
||||
};
|
||||
use oxc_traverse::{traverse_mut_with_ctx, Ancestor, ReusableTraverseCtx, Traverse, TraverseCtx};
|
||||
use oxc_traverse::{Ancestor, TraverseCtx};
|
||||
|
||||
use crate::{ctx::Ctx, CompressorPass};
|
||||
use crate::ctx::Ctx;
|
||||
|
||||
/// Constant Folding
|
||||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeFoldConstants.java>
|
||||
pub struct PeepholeFoldConstants {
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
use super::PeepholeOptimizations;
|
||||
|
||||
impl<'a> CompressorPass<'a> for PeepholeFoldConstants {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Traverse<'a> for PeepholeFoldConstants {
|
||||
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
impl<'a, 'b> PeepholeOptimizations {
|
||||
/// Constant Folding
|
||||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeFoldConstants.java>
|
||||
pub fn fold_constants_exit_expression(
|
||||
&mut self,
|
||||
expr: &mut Expression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
let ctx = Ctx(ctx);
|
||||
if let Some(folded_expr) = match expr {
|
||||
Expression::BinaryExpression(e) => Self::try_fold_binary_expr(e, ctx)
|
||||
|
|
@ -44,12 +39,6 @@ impl<'a> Traverse<'a> for PeepholeFoldConstants {
|
|||
self.changed = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> PeepholeFoldConstants {
|
||||
pub fn new() -> Self {
|
||||
Self { changed: false }
|
||||
}
|
||||
|
||||
#[expect(clippy::float_cmp)]
|
||||
fn try_fold_unary_expr(e: &UnaryExpression<'a>, ctx: Ctx<'a, 'b>) -> Option<Expression<'a>> {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ use oxc_allocator::Vec;
|
|||
use oxc_ast::{ast::*, NONE};
|
||||
use oxc_ecmascript::constant_evaluation::{ConstantEvaluation, ValueType};
|
||||
use oxc_span::{cmp::ContentEq, GetSpan};
|
||||
use oxc_syntax::es_target::ESTarget;
|
||||
use oxc_traverse::{traverse_mut_with_ctx, Ancestor, ReusableTraverseCtx, Traverse, TraverseCtx};
|
||||
use oxc_traverse::{Ancestor, TraverseCtx};
|
||||
|
||||
use crate::{ctx::Ctx, CompressorPass};
|
||||
use crate::ctx::Ctx;
|
||||
|
||||
use super::PeepholeOptimizations;
|
||||
|
||||
/// Minimize Conditions
|
||||
///
|
||||
|
|
@ -14,21 +15,8 @@ use crate::{ctx::Ctx, CompressorPass};
|
|||
/// with `? :` and short-circuit binary operators.
|
||||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeMinimizeConditions.java>
|
||||
pub struct PeepholeMinimizeConditions {
|
||||
#[allow(unused)]
|
||||
target: ESTarget,
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for PeepholeMinimizeConditions {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Traverse<'a> for PeepholeMinimizeConditions {
|
||||
fn exit_statements(
|
||||
impl<'a> PeepholeOptimizations {
|
||||
pub fn minimize_conditions_exit_statements(
|
||||
&mut self,
|
||||
stmts: &mut oxc_allocator::Vec<'a, Statement<'a>>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
|
|
@ -45,7 +33,11 @@ impl<'a> Traverse<'a> for PeepholeMinimizeConditions {
|
|||
self.changed = self.changed || changed;
|
||||
}
|
||||
|
||||
fn exit_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
pub fn minimize_conditions_exit_statement(
|
||||
&mut self,
|
||||
stmt: &mut Statement<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
let expr = match stmt {
|
||||
Statement::IfStatement(s) => Some(&mut s.test),
|
||||
Statement::WhileStatement(s) => Some(&mut s.test),
|
||||
|
|
@ -76,7 +68,11 @@ impl<'a> Traverse<'a> for PeepholeMinimizeConditions {
|
|||
};
|
||||
}
|
||||
|
||||
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
pub fn minimize_conditions_exit_expression(
|
||||
&mut self,
|
||||
expr: &mut Expression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
loop {
|
||||
let mut changed = false;
|
||||
if let Expression::ConditionalExpression(logical_expr) = expr {
|
||||
|
|
@ -106,12 +102,6 @@ impl<'a> Traverse<'a> for PeepholeMinimizeConditions {
|
|||
self.changed = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PeepholeMinimizeConditions {
|
||||
pub fn new(target: ESTarget) -> Self {
|
||||
Self { target, changed: false }
|
||||
}
|
||||
|
||||
fn try_minimize_not(
|
||||
expr: &mut UnaryExpression<'a>,
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ use oxc_ecmascript::{
|
|||
side_effects::MayHaveSideEffects,
|
||||
};
|
||||
use oxc_span::GetSpan;
|
||||
use oxc_traverse::{traverse_mut_with_ctx, Ancestor, ReusableTraverseCtx, Traverse, TraverseCtx};
|
||||
use oxc_traverse::{Ancestor, TraverseCtx};
|
||||
|
||||
use crate::{ctx::Ctx, keep_var::KeepVar, CompressorPass};
|
||||
use crate::{ctx::Ctx, keep_var::KeepVar};
|
||||
|
||||
use super::PeepholeOptimizations;
|
||||
|
||||
/// Remove Dead Code from the AST.
|
||||
///
|
||||
|
|
@ -15,28 +17,23 @@ use crate::{ctx::Ctx, keep_var::KeepVar, CompressorPass};
|
|||
///
|
||||
/// See `KeepVar` at the end of this file for `var` hoisting logic.
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeRemoveDeadCode.java>
|
||||
pub struct PeepholeRemoveDeadCode {
|
||||
pub(crate) changed: bool,
|
||||
|
||||
in_fixed_loop: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for PeepholeRemoveDeadCode {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Traverse<'a> for PeepholeRemoveDeadCode {
|
||||
fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
|
||||
impl<'a, 'b> PeepholeOptimizations {
|
||||
pub fn remove_dead_code_exit_statements(
|
||||
&mut self,
|
||||
stmts: &mut Vec<'a, Statement<'a>>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if stmts.iter().any(|stmt| matches!(stmt, Statement::EmptyStatement(_))) {
|
||||
stmts.retain(|stmt| !matches!(stmt, Statement::EmptyStatement(_)));
|
||||
}
|
||||
self.dead_code_elimination(stmts, Ctx(ctx));
|
||||
}
|
||||
|
||||
fn exit_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
pub fn remove_dead_code_exit_statement(
|
||||
&mut self,
|
||||
stmt: &mut Statement<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
let ctx = Ctx(ctx);
|
||||
if let Some(new_stmt) = match stmt {
|
||||
Statement::BlockStatement(s) => Self::try_optimize_block(s, ctx),
|
||||
|
|
@ -59,7 +56,11 @@ impl<'a> Traverse<'a> for PeepholeRemoveDeadCode {
|
|||
}
|
||||
}
|
||||
|
||||
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
pub fn remove_dead_code_exit_expression(
|
||||
&mut self,
|
||||
expr: &mut Expression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
let ctx = Ctx(ctx);
|
||||
if let Some(folded_expr) = match expr {
|
||||
Expression::ConditionalExpression(e) => Self::try_fold_conditional_expression(e, ctx),
|
||||
|
|
@ -73,17 +74,15 @@ impl<'a> Traverse<'a> for PeepholeRemoveDeadCode {
|
|||
}
|
||||
}
|
||||
|
||||
fn exit_class_body(&mut self, body: &mut ClassBody<'a>, _ctx: &mut TraverseCtx<'a>) {
|
||||
pub fn remove_dead_code_exit_class_body(
|
||||
&mut self,
|
||||
body: &mut ClassBody<'a>,
|
||||
_ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if !self.in_fixed_loop {
|
||||
Self::remove_empty_class_static_block(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> PeepholeRemoveDeadCode {
|
||||
pub fn new(in_fixed_loop: bool) -> Self {
|
||||
Self { changed: false, in_fixed_loop }
|
||||
}
|
||||
|
||||
/// Removes dead code thats comes after `return` statements after inlining `if` statements
|
||||
fn dead_code_elimination(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: Ctx<'a, 'b>) {
|
||||
|
|
|
|||
|
|
@ -7,34 +7,23 @@ use oxc_ecmascript::{
|
|||
constant_evaluation::ConstantEvaluation, StringCharAt, StringCharCodeAt, StringIndexOf,
|
||||
StringLastIndexOf, StringSubstring, ToInt32,
|
||||
};
|
||||
use oxc_traverse::{traverse_mut_with_ctx, Ancestor, ReusableTraverseCtx, Traverse, TraverseCtx};
|
||||
use oxc_traverse::{Ancestor, TraverseCtx};
|
||||
|
||||
use crate::{ctx::Ctx, CompressorPass};
|
||||
use crate::ctx::Ctx;
|
||||
|
||||
/// Minimize With Known Methods
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeReplaceKnownMethods.java>
|
||||
pub struct PeepholeReplaceKnownMethods {
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
use super::PeepholeOptimizations;
|
||||
|
||||
impl<'a> CompressorPass<'a> for PeepholeReplaceKnownMethods {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Traverse<'a> for PeepholeReplaceKnownMethods {
|
||||
fn exit_expression(&mut self, node: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
impl<'a> PeepholeOptimizations {
|
||||
/// Minimize With Known Methods
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeReplaceKnownMethods.java>
|
||||
pub fn replace_known_methods_exit_expression(
|
||||
&mut self,
|
||||
node: &mut Expression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.try_fold_concat_chain(node, ctx);
|
||||
self.try_fold_known_string_methods(node, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PeepholeReplaceKnownMethods {
|
||||
pub fn new() -> Self {
|
||||
Self { changed: false }
|
||||
}
|
||||
|
||||
fn try_fold_known_string_methods(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -13,41 +13,34 @@ use oxc_syntax::{
|
|||
number::NumberBase,
|
||||
operator::{BinaryOperator, UnaryOperator},
|
||||
};
|
||||
use oxc_traverse::{traverse_mut_with_ctx, Ancestor, ReusableTraverseCtx, Traverse, TraverseCtx};
|
||||
use oxc_traverse::{Ancestor, TraverseCtx};
|
||||
|
||||
use crate::{ctx::Ctx, CompressorPass};
|
||||
use crate::ctx::Ctx;
|
||||
|
||||
use super::PeepholeOptimizations;
|
||||
|
||||
/// A peephole optimization that minimizes code by simplifying conditional
|
||||
/// expressions, replacing IFs with HOOKs, replacing object constructors
|
||||
/// with literals, and simplifying returns.
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeSubstituteAlternateSyntax.java>
|
||||
pub struct PeepholeSubstituteAlternateSyntax {
|
||||
target: ESTarget,
|
||||
|
||||
in_fixed_loop: bool,
|
||||
|
||||
in_define_export: bool,
|
||||
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for PeepholeSubstituteAlternateSyntax {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
|
||||
fn exit_catch_clause(&mut self, catch: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
impl<'a, 'b> PeepholeOptimizations {
|
||||
pub fn substitute_catch_clause(
|
||||
&mut self,
|
||||
catch: &mut CatchClause<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.compress_catch_clause(catch, ctx);
|
||||
}
|
||||
|
||||
fn exit_object_property(&mut self, prop: &mut ObjectProperty<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
pub fn substitute_object_property(
|
||||
&mut self,
|
||||
prop: &mut ObjectProperty<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.try_compress_property_key(&mut prop.key, &mut prop.computed, ctx);
|
||||
}
|
||||
|
||||
fn exit_assignment_target_property_property(
|
||||
pub fn substitute_assignment_target_property_property(
|
||||
&mut self,
|
||||
prop: &mut AssignmentTargetPropertyProperty<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
|
|
@ -55,11 +48,15 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
|
|||
self.try_compress_property_key(&mut prop.name, &mut prop.computed, ctx);
|
||||
}
|
||||
|
||||
fn exit_binding_property(&mut self, prop: &mut BindingProperty<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
pub fn substitute_binding_property(
|
||||
&mut self,
|
||||
prop: &mut BindingProperty<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.try_compress_property_key(&mut prop.key, &mut prop.computed, ctx);
|
||||
}
|
||||
|
||||
fn exit_method_definition(
|
||||
pub fn substitute_method_definition(
|
||||
&mut self,
|
||||
prop: &mut MethodDefinition<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
|
|
@ -67,7 +64,7 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
|
|||
self.try_compress_property_key(&mut prop.key, &mut prop.computed, ctx);
|
||||
}
|
||||
|
||||
fn exit_property_definition(
|
||||
pub fn substitute_property_definition(
|
||||
&mut self,
|
||||
prop: &mut PropertyDefinition<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
|
|
@ -75,7 +72,7 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
|
|||
self.try_compress_property_key(&mut prop.key, &mut prop.computed, ctx);
|
||||
}
|
||||
|
||||
fn exit_accessor_property(
|
||||
pub fn substitute_accessor_property(
|
||||
&mut self,
|
||||
prop: &mut AccessorProperty<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
|
|
@ -83,11 +80,15 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
|
|||
self.try_compress_property_key(&mut prop.key, &mut prop.computed, ctx);
|
||||
}
|
||||
|
||||
fn exit_return_statement(&mut self, stmt: &mut ReturnStatement<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
pub fn substitute_return_statement(
|
||||
&mut self,
|
||||
stmt: &mut ReturnStatement<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.compress_return_statement(stmt, ctx);
|
||||
}
|
||||
|
||||
fn exit_variable_declaration(
|
||||
pub fn substitute_variable_declaration(
|
||||
&mut self,
|
||||
decl: &mut VariableDeclaration<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
|
|
@ -97,36 +98,19 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
|
|||
}
|
||||
}
|
||||
|
||||
/// Set `in_define_export` flag if this is a top-level statement of form:
|
||||
/// ```js
|
||||
/// Object.defineProperty(exports, 'Foo', {
|
||||
/// enumerable: true,
|
||||
/// get: function() { return Foo_1.Foo; }
|
||||
/// });
|
||||
/// ```
|
||||
fn enter_call_expression(
|
||||
pub fn substitute_call_expression(
|
||||
&mut self,
|
||||
call_expr: &mut CallExpression<'a>,
|
||||
expr: &mut CallExpression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if !self.in_fixed_loop {
|
||||
let parent = ctx.parent();
|
||||
if (parent.is_expression_statement() || parent.is_sequence_expression())
|
||||
&& Self::is_object_define_property_exports(call_expr)
|
||||
{
|
||||
self.in_define_export = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn exit_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
if !self.in_fixed_loop {
|
||||
self.in_define_export = false;
|
||||
}
|
||||
self.try_compress_call_expression_arguments(expr, ctx);
|
||||
}
|
||||
|
||||
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
pub fn substitute_exit_expression(
|
||||
&mut self,
|
||||
expr: &mut Expression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
let ctx = Ctx(ctx);
|
||||
|
||||
// Change syntax
|
||||
|
|
@ -188,12 +172,6 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
|
|||
self.changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> PeepholeSubstituteAlternateSyntax {
|
||||
pub fn new(target: ESTarget, in_fixed_loop: bool) -> Self {
|
||||
Self { target, in_fixed_loop, in_define_export: false, changed: false }
|
||||
}
|
||||
|
||||
fn compress_catch_clause(&mut self, catch: &mut CatchClause<'_>, ctx: &mut TraverseCtx<'a>) {
|
||||
if !self.in_fixed_loop && self.target >= ESTarget::ES2019 {
|
||||
|
|
@ -218,25 +196,6 @@ impl<'a, 'b> PeepholeSubstituteAlternateSyntax {
|
|||
}
|
||||
}
|
||||
|
||||
/// Test `Object.defineProperty(exports, ...)`
|
||||
fn is_object_define_property_exports(call_expr: &CallExpression<'a>) -> bool {
|
||||
let Some(Argument::Identifier(ident)) = call_expr.arguments.first() else { return false };
|
||||
if ident.name != "exports" {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use tighter check than `call_expr.callee.is_specific_member_access("Object", "defineProperty")`
|
||||
// because we're looking for `Object.defineProperty` specifically, not e.g. `Object['defineProperty']`
|
||||
if let Expression::StaticMemberExpression(callee) = &call_expr.callee {
|
||||
if let Expression::Identifier(id) = &callee.object {
|
||||
if id.name == "Object" && callee.property.name == "defineProperty" {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Transforms `undefined` => `void 0`
|
||||
fn try_compress_undefined(
|
||||
&self,
|
||||
|
|
@ -265,9 +224,6 @@ impl<'a, 'b> PeepholeSubstituteAlternateSyntax {
|
|||
) -> Option<Expression<'a>> {
|
||||
debug_assert!(!self.in_fixed_loop);
|
||||
let Expression::BooleanLiteral(lit) = expr else { return None };
|
||||
if self.in_define_export {
|
||||
return None;
|
||||
}
|
||||
let parent = ctx.ancestry.parent();
|
||||
let no_unary = {
|
||||
if let Ancestor::BinaryExpressionRight(u) = parent {
|
||||
|
|
|
|||
|
|
@ -2,36 +2,23 @@ use oxc_allocator::Vec;
|
|||
use oxc_ast::ast::*;
|
||||
use oxc_ecmascript::side_effects::MayHaveSideEffects;
|
||||
use oxc_span::GetSpan;
|
||||
use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, TraverseCtx};
|
||||
use oxc_traverse::TraverseCtx;
|
||||
|
||||
use crate::CompressorPass;
|
||||
use super::PeepholeOptimizations;
|
||||
|
||||
/// Statement Fusion
|
||||
///
|
||||
/// Tries to fuse all the statements in a block into a one statement by using COMMAs or statements.
|
||||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/StatementFusion.java>
|
||||
pub struct StatementFusion {
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for StatementFusion {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Traverse<'a> for StatementFusion {
|
||||
fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
|
||||
impl<'a> PeepholeOptimizations {
|
||||
pub fn statement_fusion_exit_statements(
|
||||
&mut self,
|
||||
stmts: &mut Vec<'a, Statement<'a>>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.fuse_statements(stmts, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> StatementFusion {
|
||||
pub fn new() -> Self {
|
||||
Self { changed: false }
|
||||
}
|
||||
|
||||
fn fuse_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
|
||||
let len = stmts.len();
|
||||
|
|
|
|||
|
|
@ -34,10 +34,8 @@ impl<'a> Compressor<'a> {
|
|||
// RemoveUnusedCode::new(self.options).build(program, &mut ctx);
|
||||
let normalize_options = NormalizeOptions { convert_while_to_fors: true };
|
||||
Normalize::new(normalize_options, self.options).build(program, &mut ctx);
|
||||
PeepholeOptimizations::new(self.options.target, true, self.options)
|
||||
.run_in_loop(program, &mut ctx);
|
||||
PeepholeOptimizations::new(self.options.target, false, self.options)
|
||||
.build(program, &mut ctx);
|
||||
PeepholeOptimizations::new(self.options.target, true).run_in_loop(program, &mut ctx);
|
||||
PeepholeOptimizations::new(self.options.target, false).build(program, &mut ctx);
|
||||
}
|
||||
|
||||
pub fn dead_code_elimination(self, program: &mut Program<'a>) {
|
||||
|
|
|
|||
|
|
@ -98,75 +98,3 @@ fn tagged_template() {
|
|||
test("foo(true && o.f)", "foo(o.f)");
|
||||
test("foo(true ? o.f : false)", "foo(o.f)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cjs() {
|
||||
// Bail `cjs-module-lexer`.
|
||||
test_same("0 && (module.exports = { version });");
|
||||
|
||||
// Bail `cjs-module-lexer`.
|
||||
// Export is undefined when `enumerable` is "!0".
|
||||
// https://github.com/nodejs/cjs-module-lexer/issues/64
|
||||
test_same(
|
||||
"Object.defineProperty(exports, 'ConnectableObservable', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return ConnectableObservable_1.ConnectableObservable;
|
||||
}
|
||||
});",
|
||||
);
|
||||
test_same(
|
||||
"Object.defineProperty(exports, 'ConnectableObservable', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return ConnectableObservable_1.ConnectableObservable;
|
||||
}
|
||||
});",
|
||||
);
|
||||
// @babel/types/lib/index.js
|
||||
test(
|
||||
r#"
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "TargetNames", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _options.TargetNames;
|
||||
}
|
||||
});"#,
|
||||
r#"
|
||||
Object.defineProperty(exports, "__esModule", { value: true }), Object.defineProperty(exports, "TargetNames", {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return _options.TargetNames;
|
||||
}
|
||||
});"#,
|
||||
);
|
||||
|
||||
test(
|
||||
r#"Object.keys(_index6).forEach(function(key) {
|
||||
if (key === "default" || key === "__esModule") return;
|
||||
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
||||
if (key in exports && exports[key] === _index6[key]) return;
|
||||
Object.defineProperty(exports, key, {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return _index6[key];
|
||||
}
|
||||
});
|
||||
});"#,
|
||||
"
|
||||
Object.keys(_index6).forEach(function(key) {
|
||||
if (key === 'default' || key === '__esModule') return;
|
||||
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
||||
if (key in exports && exports[key] === _index6[key]) return;
|
||||
Object.defineProperty(exports, key, {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return _index6[key];
|
||||
}
|
||||
});
|
||||
});",
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Original | minified | minified | gzip | gzip | Fixture
|
|||
|
||||
2.14 MB | 724.06 kB | 724.14 kB | 179.94 kB | 181.07 kB | victory.js
|
||||
|
||||
3.20 MB | 1.01 MB | 1.01 MB | 332.01 kB | 331.56 kB | echarts.js
|
||||
3.20 MB | 1.01 MB | 1.01 MB | 332.00 kB | 331.56 kB | echarts.js
|
||||
|
||||
6.69 MB | 2.31 MB | 2.31 MB | 492.53 kB | 488.28 kB | antd.js
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue