perf(minifier): update boolean context expressions in place (#26823)

update `minimize_expression_in_boolean_context` to update expressions in
place instead of creating dummy nodes

Co-authored-by: Cameron Clark <cameron.clark@hey.com>
This commit is contained in:
ArmanoandCameron Clark authored and GitHub committed 2026-09-22 11:30:57 +00:00
1 parent de8af47874
commit 3893d641e2
2 files changed
+49 -48

No files matched your search

@@ -1,4 +1,3 @@
use oxc_allocator::TakeIn;
use oxc_ast::ast::*;
use oxc_ecmascript::constant_evaluation::{ConstantEvaluation, IsInt32OrUint32};
use oxc_span::GetSpan;
@@ -29,23 +28,17 @@ impl<'a> PeepholeOptimizations {
&& e.right.is_number_0()
&& e.left.is_int32_or_uint32(ctx) =>
{
let argument = e.left.take_in(ctx);
let new_expr = if matches!(
e.operator,
BinaryOperator::StrictInequality | BinaryOperator::Inequality
) {
// `if ((a | b) !== 0)` -> `if (a | b);`
argument
} else {
// `if ((a | b) === 0);", "if (!(a | b));")`
Expression::new_unary_expression(
e.span,
UnaryOperator::LogicalNot,
argument,
ctx,
)
};
ctx.replace_expression(expr, new_expr);
ctx.replace_expression_with(expr, |e, ctx| {
let Expression::BinaryExpression(e) = e else { unreachable!() };
let BinaryExpression { operator: op, left, span, .. } = e.unbox();
if matches!(op, BinaryOperator::StrictInequality | BinaryOperator::Inequality) {
// `if ((a | b) !== 0)` -> `if (a | b);`
left
} else {
// `if ((a | b) === 0);", "if (!(a | b));")`
Expression::new_unary_expression(span, UnaryOperator::LogicalNot, left, ctx)
}
});
}
// "if (!!a && !!b)" => "if (a && b)"
Expression::LogicalExpression(e) if e.operator.is_and() => {
@@ -53,8 +46,11 @@ impl<'a> PeepholeOptimizations {
Self::minimize_expression_in_boolean_context(&mut e.right, ctx);
// "if (anything && truthyNoSideEffects)" => "if (anything)"
if e.right.get_side_free_boolean_value(ctx) == Some(true) {
let new_expr = e.left.take_in(ctx);
ctx.replace_expression(expr, new_expr);
ctx.drop_expression(&e.right);
ctx.replace_expression_with(expr, |e, _ctx| {
let Expression::LogicalExpression(e) = e else { unreachable!() };
e.unbox().left
});
}
}
// "if (!!a ||!!b)" => "if (a || b)"
@@ -63,8 +59,11 @@ impl<'a> PeepholeOptimizations {
Self::minimize_expression_in_boolean_context(&mut e.right, ctx);
// "if (anything || falsyNoSideEffects)" => "if (anything)"
if e.right.get_side_free_boolean_value(ctx) == Some(false) {
let new_expr = e.left.take_in(ctx);
ctx.replace_expression(expr, new_expr);
ctx.drop_expression(&e.right);
ctx.replace_expression_with(expr, |e, _ctx| {
let Expression::LogicalExpression(e) = e else { unreachable!() };
e.unbox().left
});
}
}
Expression::ConditionalExpression(e) => {
@@ -72,33 +71,35 @@ impl<'a> PeepholeOptimizations {
Self::minimize_expression_in_boolean_context(&mut e.consequent, ctx);
Self::minimize_expression_in_boolean_context(&mut e.alternate, ctx);
if let Some(boolean) = e.consequent.get_side_free_boolean_value(ctx) {
let right = e.alternate.take_in(ctx);
let left = e.test.take_in(ctx);
let span = e.span;
let (op, left) = if boolean {
// "if (anything1 ? truthyNoSideEffects : anything2)" => "if (anything1 || anything2)"
(LogicalOperator::Or, left)
} else {
// "if (anything1 ? falsyNoSideEffects : anything2)" => "if (!anything1 && anything2)"
(LogicalOperator::And, Self::minimize_not(left.span(), left, ctx, true))
};
let new_expr = Self::join_with_left_associative_op(span, op, left, right, ctx);
ctx.replace_expression(expr, new_expr);
ctx.drop_expression(&e.consequent);
ctx.replace_expression_with(expr, |e, ctx| {
let Expression::ConditionalExpression(e) = e else { unreachable!() };
let ConditionalExpression { test, alternate, span, .. } = e.unbox();
let (op, left) = if boolean {
// "if (anything1 ? truthyNoSideEffects : anything2)" => "if (anything1 || anything2)"
(LogicalOperator::Or, test)
} else {
// "if (anything1 ? falsyNoSideEffects : anything2)" => "if (!anything1 && anything2)"
(LogicalOperator::And, Self::minimize_not(test.span(), test, ctx, true))
};
Self::join_with_left_associative_op(span, op, left, alternate, ctx)
});
return;
}
if let Some(boolean) = e.alternate.get_side_free_boolean_value(ctx) {
let left = e.test.take_in(ctx);
let right = e.consequent.take_in(ctx);
let span = e.span;
let (op, left) = if boolean {
// "if (anything1 ? anything2 : truthyNoSideEffects)" => "if (!anything1 || anything2)"
(LogicalOperator::Or, Self::minimize_not(left.span(), left, ctx, true))
} else {
// "if (anything1 ? anything2 : falsyNoSideEffects)" => "if (anything1 && anything2)"
(LogicalOperator::And, left)
};
let new_expr = Self::join_with_left_associative_op(span, op, left, right, ctx);
ctx.replace_expression(expr, new_expr);
ctx.drop_expression(&e.alternate);
ctx.replace_expression_with(expr, |e, ctx| {
let Expression::ConditionalExpression(e) = e else { unreachable!() };
let ConditionalExpression { test, consequent, span, .. } = e.unbox();
let (op, left) = if boolean {
// "if (anything1 ? anything2 : truthyNoSideEffects)" => "if (!anything1 || anything2)"
(LogicalOperator::Or, Self::minimize_not(test.span(), test, ctx, true))
} else {
// "if (anything1 ? anything2 : falsyNoSideEffects)" => "if (anything1 && anything2)"
(LogicalOperator::And, test)
};
Self::join_with_left_associative_op(span, op, left, consequent, ctx)
});
}
}
Expression::SequenceExpression(seq_expr) => {
@@ -49,9 +49,9 @@ antd.js:
sys deallocs: 860
sys alloc bytes: 29973448 # 29.97 MB
sys peak growth: 19934725 # 19.93 MB
arena allocs: 181686
arena allocs: 181679
arena reallocs: 34406
arena size: 43044360 # 43.04 MB
arena size: 43044248 # 43.04 MB
binder.ts:
file size: 193077 # 193.08 kB