perf(minfiier): reduce allocs when creating indirect access (#26601)

- simplify code for `try_fold_conditional_expression` 
- `preserve_indirect_access` should now preserve more accurate `span`
range
- `try_fold_coalesce` and `try_fold_and_or` reuses now
`preserve_indirect_access` helper
This commit is contained in:
Armano
2026-09-14 04:30:29 +02:00
committed by GitHub
parent ca649e059c
commit a242469f37
4 changed files with 40 additions and 96 deletions
@@ -143,22 +143,11 @@ impl<'a> PeepholeOptimizations {
}
return Some(logical_expr.left.take_in(ctx));
} else if !left.may_have_side_effects(ctx) {
let should_keep_indirect_access =
Self::should_keep_indirect_access(&logical_expr.right, ctx);
// (true && o.f) => (0, o.f)
if should_keep_indirect_access {
return Some(Expression::new_sequence_expression(
logical_expr.span,
[
Expression::new_numeric_literal(
logical_expr.left.span(),
0.0,
None,
NumberBase::Decimal,
ctx,
),
logical_expr.right.take_in(ctx),
],
// `(true && o.f)` => `(0, o.f)`
if Self::should_keep_indirect_access(&logical_expr.right, ctx) {
return Some(Self::preserve_indirect_access(
logical_expr.left.span(),
logical_expr.right.take_in(ctx),
ctx,
));
}
@@ -214,27 +203,16 @@ impl<'a> PeepholeOptimizations {
match left_val {
ValueType::Null | ValueType::Undefined => {
Some(if left.may_have_side_effects(ctx) {
// e.g. `(a(), null) ?? 1` => `(a(), null, 1)`
// `(a(), null) ?? 1` => `(a(), null, 1)`
let expressions =
[logical_expr.left.take_in(ctx), logical_expr.right.take_in(ctx)];
Expression::new_sequence_expression(logical_expr.span, expressions, ctx)
} else {
let should_keep_indirect_access =
Self::should_keep_indirect_access(&logical_expr.right, ctx);
// (null ?? o.f) => (0, o.f)
if should_keep_indirect_access {
return Some(Expression::new_sequence_expression(
logical_expr.span,
[
Expression::new_numeric_literal(
logical_expr.left.span(),
0.0,
None,
NumberBase::Decimal,
ctx,
),
logical_expr.right.take_in(ctx),
],
// `(null ?? o.f)` => `(0, o.f)`
if Self::should_keep_indirect_access(&logical_expr.right, ctx) {
return Some(Self::preserve_indirect_access(
logical_expr.left.span(),
logical_expr.right.take_in(ctx),
ctx,
));
}
@@ -247,22 +225,11 @@ impl<'a> PeepholeOptimizations {
| ValueType::String
| ValueType::Boolean
| ValueType::Object => {
let should_keep_indirect_access =
Self::should_keep_indirect_access(&logical_expr.left, ctx);
// (o.f ?? something) => (0, o.f)
if should_keep_indirect_access {
return Some(Expression::new_sequence_expression(
logical_expr.span,
[
Expression::new_numeric_literal(
logical_expr.right.span(),
0.0,
None,
NumberBase::Decimal,
ctx,
),
logical_expr.left.take_in(ctx),
],
// `(o.f ?? something)` => `(0, o.f)`
if Self::should_keep_indirect_access(&logical_expr.left, ctx) {
return Some(Self::preserve_indirect_access(
logical_expr.right.span(),
logical_expr.left.take_in(ctx),
ctx,
));
}
@@ -428,44 +428,28 @@ impl<'a> PeepholeOptimizations {
pub fn try_fold_conditional_expression(expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
let Expression::ConditionalExpression(e) = expr else { return };
let Some(v) = e.test.evaluate_value_to_boolean(ctx) else { return };
let new_expr = if e.test.may_have_side_effects(ctx) {
// "(a, true) ? b : c" => "a, b"
Expression::new_sequence_expression(
e.span,
[
{
let mut test = e.test.take_in(ctx);
Self::remove_unused_expression(&mut test, ctx);
test
},
if v { e.consequent.take_in(ctx) } else { e.alternate.take_in(ctx) },
],
ctx,
)
} else {
let result_expr = if v { e.consequent.take_in(ctx) } else { e.alternate.take_in(ctx) };
let should_keep_as_sequence_expr = Self::should_keep_indirect_access(&result_expr, ctx);
// "(1 ? a.b : 0)()" => "(0, a.b)()"
if should_keep_as_sequence_expr {
Expression::new_sequence_expression(
e.span,
[
Expression::new_numeric_literal(
e.span,
0.0,
None,
NumberBase::Decimal,
ctx,
),
result_expr,
],
ctx,
)
ctx.drop_expression(if v { &e.alternate } else { &e.consequent });
ctx.replace_expression_with(expr, |e, ctx| {
let Expression::ConditionalExpression(e) = e else {
unreachable!();
};
let mut e = e.unbox();
let result_expr = if v { e.consequent } else { e.alternate };
if Self::remove_unused_expression(&mut e.test, ctx) {
ctx.drop_expression(&e.test);
// `(1 ? a.b : 0)()` => `(0, a.b)()`
if Self::should_keep_indirect_access(&result_expr, ctx) {
Self::preserve_indirect_access(e.span, result_expr, ctx)
} else {
result_expr
}
} else {
result_expr
// `(a, true) ? b : c` => `a, b`
Expression::new_sequence_expression(e.span, [e.test, result_expr], ctx)
}
};
ctx.replace_expression(expr, new_expr);
});
}
pub fn remove_sequence_expression(expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
@@ -720,7 +704,7 @@ impl<'a> PeepholeOptimizations {
ctx: &TraverseCtx<'a>,
) -> Expression<'a> {
Expression::new_sequence_expression(
span,
span.merge(expr.span()),
[Expression::new_numeric_literal(span, 0.0, None, NumberBase::Decimal, ctx), expr],
ctx,
)
@@ -1542,14 +1542,7 @@ impl<'a> PeepholeOptimizations {
return;
};
let new_callee = Expression::new_sequence_expression(
span,
[
Expression::new_numeric_literal(span, 0.0, None, NumberBase::Decimal, ctx),
arg_expr.take_in(ctx),
],
ctx,
);
let new_callee = Self::preserve_indirect_access(span, arg_expr.take_in(ctx), ctx);
ctx.replace_expression(&mut expr.callee, new_callee);
}
@@ -49,7 +49,7 @@ antd.js:
sys deallocs: 860
sys alloc bytes: 29976375 # 29.98 MB
sys peak growth: 19934749 # 19.93 MB
arena allocs: 187032
arena allocs: 187025
arena reallocs: 63323
arena size: 43370040 # 43.37 MB
@@ -71,6 +71,6 @@ kitchen-sink.tsx:
sys deallocs: 1854
sys alloc bytes: 5304692 # 5.30 MB
sys peak growth: 3707457 # 3.71 MB
arena allocs: 31944
arena allocs: 31927
arena reallocs: 12185
arena size: 8688104 # 8.69 MB