Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions crates/oxc_minifier/src/peephole/fold_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use oxc_ecmascript::{
use oxc_span::GetSpan;
use oxc_syntax::operator::{BinaryOperator, LogicalOperator};

use crate::ctx::Ctx;
use crate::{ctx::Ctx, peephole::DeleteCode};

use super::PeepholeOptimizations;

Expand All @@ -30,6 +30,7 @@ impl<'a> PeepholeOptimizations {
_ if e.may_have_side_effects(ctx) => {}
_ => {
if let Some(changed) = e.evaluate_value(ctx).map(|v| ctx.value_to_expr(e.span, v)) {
expr.delete(ctx);
*expr = changed;
ctx.state.changed = true;
}
Expand All @@ -44,6 +45,7 @@ impl<'a> PeepholeOptimizations {
return;
}
if let Some(changed) = e.evaluate_value(ctx).map(|value| ctx.value_to_expr(e.span, value)) {
expr.delete(ctx);
*expr = changed;
ctx.state.changed = true;
}
Expand All @@ -56,6 +58,7 @@ impl<'a> PeepholeOptimizations {
return;
}
if let Some(changed) = e.evaluate_value(ctx).map(|value| ctx.value_to_expr(e.span, value)) {
expr.delete(ctx);
*expr = changed;
ctx.state.changed = true;
}
Expand All @@ -67,6 +70,7 @@ impl<'a> PeepholeOptimizations {
LogicalOperator::And | LogicalOperator::Or => Self::try_fold_and_or(e, ctx),
LogicalOperator::Coalesce => Self::try_fold_coalesce(e, ctx),
} {
expr.delete(ctx);
*expr = changed;
ctx.state.changed = true;
}
Expand Down Expand Up @@ -94,6 +98,7 @@ impl<'a> PeepholeOptimizations {
if let Some(changed) = (ty.is_null() || ty.is_undefined())
.then(|| ctx.value_to_expr(e.span, ConstantValue::Undefined))
{
expr.delete(ctx);
*expr = changed;
ctx.state.changed = true;
}
Expand Down Expand Up @@ -334,6 +339,7 @@ impl<'a> PeepholeOptimizations {
BinaryOperator::In => None,
};
if let Some(changed) = changed {
expr.delete(ctx);
*expr = changed;
ctx.state.changed = true;
}
Expand Down Expand Up @@ -541,19 +547,24 @@ impl<'a> PeepholeOptimizations {
if let Some(n) = arg.evaluate_value_to_number(ctx) {
n
} else {
*expr = ctx.ast.expression_unary(
let new_expr = ctx.ast.expression_unary(
e.span,
UnaryOperator::UnaryPlus,
ctx.ast.expression_string_literal(n.span, n.value, n.raw),
);

expr.delete(ctx);
*expr = new_expr;
ctx.state.changed = true;
return;
}
}
e if e.is_void_0() => f64::NAN,
_ => return,
});
*expr = ctx.value_to_expr(e.span, value);
let new_expr = ctx.value_to_expr(e.span, value);
expr.delete(ctx);
*expr = new_expr;
ctx.state.changed = true;
}

Expand All @@ -575,7 +586,9 @@ impl<'a> PeepholeOptimizations {
e.operator,
BinaryOperator::StrictEquality | BinaryOperator::Equality
);
*expr = ctx.ast.expression_boolean_literal(e.span, b);
let new_expr = ctx.ast.expression_boolean_literal(e.span, b);
expr.delete(ctx);
*expr = new_expr;
ctx.state.changed = true;
return;
}
Expand All @@ -591,11 +604,13 @@ impl<'a> PeepholeOptimizations {
let right_ty = e.right.value_type(ctx);

if !right_ty.is_undetermined() && right_ty != ValueType::String {
*expr = ctx.ast.expression_boolean_literal(
let new_expr = ctx.ast.expression_boolean_literal(
e.span,
e.operator == BinaryOperator::Inequality
|| e.operator == BinaryOperator::StrictInequality,
);
expr.delete(ctx);
*expr = new_expr;
ctx.state.changed = true;
return;
}
Expand All @@ -612,11 +627,13 @@ impl<'a> PeepholeOptimizations {
| "function"
| "unknown" // IE
) {
*expr = ctx.ast.expression_boolean_literal(
let new_expr = ctx.ast.expression_boolean_literal(
e.span,
e.operator == BinaryOperator::Inequality
|| e.operator == BinaryOperator::StrictInequality,
);
expr.delete(ctx);
*expr = new_expr;
ctx.state.changed = true;
}
}
Expand Down
6 changes: 4 additions & 2 deletions crates/oxc_minifier/src/peephole/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use oxc_traverse::Ancestor;

use crate::ctx::Ctx;

use super::PeepholeOptimizations;
use super::{DeleteCode, PeepholeOptimizations};

impl<'a> PeepholeOptimizations {
pub fn init_symbol_value(decl: &VariableDeclarator<'a>, ctx: &mut Ctx<'a, '_>) {
Expand Down Expand Up @@ -45,7 +45,9 @@ impl<'a> PeepholeOptimizations {
ConstantValue::Boolean(_) | ConstantValue::Undefined | ConstantValue::Null => true,
}
{
*expr = ctx.value_to_expr(expr.span(), cv.clone());
let new_expr = ctx.value_to_expr(expr.span(), cv.clone());
expr.delete(ctx);
*expr = new_expr;
ctx.state.changed = true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use oxc_ecmascript::{
use oxc_span::{ContentEq, GetSpan};
use oxc_syntax::es_target::ESTarget;

use crate::ctx::Ctx;
use crate::{ctx::Ctx, peephole::DeleteCode};

use super::PeepholeOptimizations;

Expand Down Expand Up @@ -244,6 +244,7 @@ impl<'a> PeepholeOptimizations {
if matches!(consequent.arguments[0], Argument::SpreadElement(_))
&& matches!(alternate.arguments[0], Argument::SpreadElement(_))
{
alternate.callee.delete(ctx);
let callee = consequent.callee.take_in(ctx.ast);
let consequent_first_arg = {
let Argument::SpreadElement(el) = &mut consequent.arguments[0] else {
Expand Down Expand Up @@ -273,8 +274,8 @@ impl<'a> PeepholeOptimizations {
if !matches!(consequent.arguments[0], Argument::SpreadElement(_))
&& !matches!(alternate.arguments[0], Argument::SpreadElement(_))
{
alternate.callee.delete(ctx);
let callee = consequent.callee.take_in(ctx.ast);

let consequent_first_arg =
consequent.arguments[0].to_expression_mut().take_in(ctx.ast);
let alternate_first_arg =
Expand Down Expand Up @@ -339,8 +340,10 @@ impl<'a> PeepholeOptimizations {
value_expr.take_in(ctx.ast),
LogicalOperator::Coalesce,
if is_negate {
expr.consequent.delete(ctx);
expr.alternate.take_in(ctx.ast)
} else {
expr.alternate.delete(ctx);
expr.consequent.take_in(ctx.ast)
},
));
Expand Down
15 changes: 11 additions & 4 deletions crates/oxc_minifier/src/peephole/minimize_conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use oxc_syntax::es_target::ESTarget;

use crate::ctx::Ctx;

use super::PeepholeOptimizations;
use super::{DeleteCode, PeepholeOptimizations};

/// Minimize Conditions
///
Expand Down Expand Up @@ -108,6 +108,8 @@ impl<'a> PeepholeOptimizations {
BinaryOperator::Equality => {}
_ => return,
}
e.left.delete(ctx);
e.right.delete(ctx);
*expr = if b {
e.left.take_in(ctx.ast)
} else {
Expand All @@ -130,6 +132,7 @@ impl<'a> PeepholeOptimizations {
return;
}
if let Some(ConstantValue::Boolean(left_bool)) = e.left.evaluate_value(ctx) {
e.left.delete(ctx);
e.left = ctx.ast.expression_numeric_literal(
e.left.span(),
if left_bool { 1.0 } else { 0.0 },
Expand All @@ -140,6 +143,7 @@ impl<'a> PeepholeOptimizations {
return;
}
if let Some(ConstantValue::Boolean(right_bool)) = e.right.evaluate_value(ctx) {
e.right.delete(ctx);
e.right = ctx.ast.expression_numeric_literal(
e.right.span(),
if right_bool { 1.0 } else { 0.0 },
Expand Down Expand Up @@ -206,7 +210,9 @@ impl<'a> PeepholeOptimizations {

let new_op = logical_expr.operator.to_assignment_operator();
expr.operator = new_op;
expr.right = logical_expr.right.take_in(ctx.ast);
let new_expr = logical_expr.right.take_in(ctx.ast);
expr.right.delete(ctx);
expr.right = new_expr;
ctx.state.changed = true;
}

Expand All @@ -226,9 +232,10 @@ impl<'a> PeepholeOptimizations {
}

Self::mark_assignment_target_as_read(&expr.left, ctx);

let new_expr = binary_expr.right.take_in(ctx.ast);
expr.right.delete(ctx);
expr.operator = new_op;
expr.right = binary_expr.right.take_in(ctx.ast);
expr.right = new_expr;
ctx.state.changed = true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use oxc_semantic::ReferenceFlags;
use oxc_span::{ContentEq, GetSpan};
use oxc_syntax::es_target::ESTarget;

use crate::ctx::Ctx;
use crate::{ctx::Ctx, peephole::DeleteCode};

use super::PeepholeOptimizations;

Expand Down Expand Up @@ -32,7 +32,7 @@ impl<'a> PeepholeOptimizations {
/// - `document.all == null` is `true`
fn try_compress_is_null_or_undefined(
expr: &mut LogicalExpression<'a>,
ctx: &Ctx<'a, '_>,
ctx: &mut Ctx<'a, '_>,
) -> Option<Expression<'a>> {
let op = expr.operator;
let target_ops = match op {
Expand Down Expand Up @@ -78,7 +78,7 @@ impl<'a> PeepholeOptimizations {
right: &mut Expression<'a>,
span: Span,
(find_op, replace_op): (BinaryOperator, BinaryOperator),
ctx: &Ctx<'a, '_>,
ctx: &mut Ctx<'a, '_>,
) -> Option<Expression<'a>> {
enum LeftPairValueResult {
Null(Span),
Expand Down Expand Up @@ -136,6 +136,7 @@ impl<'a> PeepholeOptimizations {
if left_id_name != right_id.name {
return None;
}
right_id.delete(ctx);

let null_expr_span = match left_value {
LeftPairValueResult::Null(span) => span,
Expand Down
7 changes: 4 additions & 3 deletions crates/oxc_minifier/src/peephole/minimize_statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use oxc_traverse::Ancestor;

use crate::{ctx::Ctx, keep_var::KeepVar};

use super::PeepholeOptimizations;
use super::{DeleteCode, PeepholeOptimizations};

impl<'a> PeepholeOptimizations {
/// `mangleStmts`: <https://github.com/evanw/esbuild/blob/v0.24.2/internal/js_ast/js_parser.go#L8788>
Expand Down Expand Up @@ -1099,7 +1099,7 @@ impl<'a> PeepholeOptimizations {
fn substitute_single_use_symbol_in_statement(
expr_in_stmt: &mut Expression<'a>,
stmts: &mut Vec<'a, Statement<'a>>,
ctx: &Ctx<'a, '_>,
ctx: &mut Ctx<'a, '_>,
) -> bool {
// TODO: we should skip this compression when direct eval exists
// because the code inside eval may reference the variable
Expand Down Expand Up @@ -1183,11 +1183,12 @@ impl<'a> PeepholeOptimizations {
search_for: &str,
replacement: &mut Expression<'a>,
replacement_has_side_effect: bool,
ctx: &Ctx<'a, '_>,
ctx: &mut Ctx<'a, '_>,
) -> Option<bool> {
match target_expr {
Expression::Identifier(id) => {
if id.name == search_for {
target_expr.delete(ctx);
*target_expr = replacement.take_in(ctx.ast);
return Some(true);
}
Expand Down
79 changes: 68 additions & 11 deletions crates/oxc_minifier/src/peephole/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,18 @@ impl<'a> Traverse<'a, MinifierState<'a>> for PeepholeOptimizations {
ctx.state.changed = false;
}

fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
fn exit_program(&mut self, _program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
self.changed = ctx.state.changed;
if self.changed {
// Remove unused references by visiting the AST again and diff the collected references.
let refs_before =
ctx.scoping().resolved_references().flatten().copied().collect::<FxHashSet<_>>();
let mut counter = ReferencesCounter::default();
counter.visit_program(program);
for reference_id_to_remove in refs_before.difference(&counter.refs) {
ctx.scoping_mut().delete_reference(*reference_id_to_remove);
}
}
// if self.changed {
// Remove unused references by visiting the AST again and diff the collected references.
// let refs_before =
// ctx.scoping().resolved_references().flatten().copied().collect::<FxHashSet<_>>();
// let mut counter = ReferencesCounter::default();
// counter.visit_program(program);
// for reference_id_to_remove in refs_before.difference(&counter.refs) {
// ctx.scoping_mut().delete_reference(*reference_id_to_remove);
// }
// }
}

fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
Expand Down Expand Up @@ -521,3 +521,60 @@ impl<'a> Visit<'a> for ReferencesCounter {
self.refs.insert(reference_id);
}
}

pub trait DeleteCode<'a, 'b> {
fn delete(&self, _ctx: &mut Ctx<'a, 'b>) {}
}

impl<'a> DeleteCode<'a, '_> for IdentifierReference<'a> {
fn delete(&self, ctx: &mut Ctx<'a, '_>) {
ReferencesRemover { ctx }.visit_identifier_reference(self);
}
}

impl<'a> DeleteCode<'a, '_> for ExpressionStatement<'a> {
fn delete(&self, ctx: &mut Ctx<'a, '_>) {
ReferencesRemover { ctx }.visit_expression_statement(self);
}
}

impl<'a> DeleteCode<'a, '_> for Statement<'a> {
fn delete(&self, ctx: &mut Ctx<'a, '_>) {
ReferencesRemover { ctx }.visit_statement(self);
}
}

impl<'a> DeleteCode<'a, '_> for Expression<'a> {
fn delete(&self, ctx: &mut Ctx<'a, '_>) {
ReferencesRemover { ctx }.visit_expression(self);
}
}

impl<'a> DeleteCode<'a, '_> for AssignmentTarget<'a> {
fn delete(&self, ctx: &mut Ctx<'a, '_>) {
ReferencesRemover { ctx }.visit_assignment_target(self);
}
}

impl<'a> DeleteCode<'a, '_> for SimpleAssignmentTarget<'a> {
fn delete(&self, ctx: &mut Ctx<'a, '_>) {
ReferencesRemover { ctx }.visit_simple_assignment_target(self);
}
}

impl<'a> DeleteCode<'a, '_> for IfStatement<'a> {
fn delete(&self, ctx: &mut Ctx<'a, '_>) {
ReferencesRemover { ctx }.visit_if_statement(self);
}
}

struct ReferencesRemover<'a, 'b, 'c> {
ctx: &'c mut Ctx<'a, 'b>,
}

impl<'a> Visit<'a> for ReferencesRemover<'a, '_, '_> {
fn visit_identifier_reference(&mut self, it: &IdentifierReference<'a>) {
let reference_id = it.reference_id();
self.ctx.scoping_mut().delete_reference(reference_id);
}
}
Loading