perf(minifier): unwrap all unary exprs without creating dummy expressions (#25891)

This is a follow up for changes introduced in #25836 by applying
`replace_expression_with` helper to unused expressions and to substitute
This commit is contained in:
Armano authored and GitHub committed 2026-08-19 10:04:50 +08:00
1 parent 8783524015
commit 5ef0c93295
4 files changed
+15 -17

No files matched your search

@@ -46,7 +46,7 @@ impl<'a> PeepholeOptimizations {
// `!(a !== b)` => `a === b`
Expression::BinaryExpression(binary_expr) if binary_expr.operator.is_equality() => {
binary_expr.operator = binary_expr.operator.equality_inverse_operator().unwrap();
ctx.replace_expression_with(expr, Self::unwrap_not);
ctx.replace_expression_with(expr, Self::unwrap_unary);
}
// `!(a == b || c == d)` => `a != b && c != d`
// `!(a == b && c == d)` => `a != b || c != d`
@@ -60,7 +60,7 @@ impl<'a> PeepholeOptimizations {
if Self::de_morgan_paren_delta(logical_expr).is_some_and(|delta| delta <= 0) =>
{
Self::de_morgan_invert_logical(logical_expr);
ctx.replace_expression_with(expr, Self::unwrap_not);
ctx.replace_expression_with(expr, Self::unwrap_unary);
}
// "!(a, b)" => "a, !b"
Expression::SequenceExpression(sequence_expr) => {
@@ -68,15 +68,16 @@ impl<'a> PeepholeOptimizations {
ctx.replace_expression_with(last_expr, |old, ctx| {
Self::minimize_not(old.span(), old, ctx)
});
ctx.replace_expression_with(expr, Self::unwrap_not);
ctx.replace_expression_with(expr, Self::unwrap_unary);
}
}
_ => {}
}
}
/// Unwrap `!x` into `x`. The discarded `!` wrapper contains no references.
fn unwrap_not(old: Expression<'a>, _ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
/// Attempts to unwrap a `UnaryExpression` from an `Expression` enum variant, returning its argument.
/// E.g. `!x` into `x`. The discarded `!` wrapper contains no references.
pub fn unwrap_unary(old: Expression<'a>, _ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
let Expression::UnaryExpression(e) = old else { unreachable!() };
e.unbox().argument
}
@@ -92,16 +92,14 @@ impl<'a> PeepholeOptimizations {
let Expression::UnaryExpression(unary_expr) = e else { return false };
match unary_expr.operator {
UnaryOperator::Void | UnaryOperator::LogicalNot => {
let new_expr = unary_expr.argument.take_in(ctx);
ctx.replace_expression(e, new_expr);
ctx.replace_expression_with(e, Self::unwrap_unary);
Self::remove_unused_expression(e, ctx)
}
UnaryOperator::Typeof => {
if unary_expr.argument.is_identifier_reference() {
true
} else {
let new_expr = unary_expr.argument.take_in(ctx);
ctx.replace_expression(e, new_expr);
ctx.replace_expression_with(e, Self::unwrap_unary);
Self::remove_unused_expression(e, ctx)
}
}
@@ -286,8 +286,7 @@ impl<'a> PeepholeOptimizations {
if !parent_expression_does_to_number_conversion {
return;
}
let new_value = e.argument.take_in(ctx);
ctx.replace_expression(expr, new_value);
ctx.replace_expression_with(expr, Self::unwrap_unary);
}
/// For `+a - n` => `a - n` (assuming n is a number)
@@ -5,7 +5,7 @@ checker.ts:
sys deallocs: 150
sys alloc bytes: 14996600 # 15.00 MB
sys peak growth: 10169560 # 10.17 MB
arena allocs: 144629
arena allocs: 144626
arena reallocs: 28468
arena size: 19144184 # 19.14 MB
@@ -38,9 +38,9 @@ pdf.mjs:
sys deallocs: 2427
sys alloc bytes: 5334247 # 5.33 MB
sys peak growth: 3693355 # 3.69 MB
arena allocs: 44972
arena allocs: 44970
arena reallocs: 7718
arena size: 6312336 # 6.31 MB
arena size: 6311296 # 6.31 MB
antd.js:
file size: 6686316 # 6.69 MB
@@ -49,7 +49,7 @@ antd.js:
sys deallocs: 1038
sys alloc bytes: 29976031 # 29.98 MB
sys peak growth: 19934725 # 19.93 MB
arena allocs: 352732
arena allocs: 352722
arena reallocs: 76289
arena size: 48806072 # 48.81 MB
@@ -71,6 +71,6 @@ kitchen-sink.tsx:
sys deallocs: 1854
sys alloc bytes: 5307512 # 5.31 MB
sys peak growth: 3707425 # 3.71 MB
arena allocs: 65730
arena allocs: 65134
arena reallocs: 12252
arena size: 9407416 # 9.41 MB
arena size: 9397712 # 9.40 MB