Skip to content

Commit

Permalink
feat(minifier): support subtraction assignment. (#6214)
Browse files Browse the repository at this point in the history
Due to the potential for string concatenation when using the `+=` operator, we should only handle the scenario when using the `-=` operator.
  • Loading branch information
7086cmd committed Oct 2, 2024
1 parent ea28ee9 commit 585ccda
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 15 deletions.
21 changes: 11 additions & 10 deletions crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
use std::cmp::Ordering;

use num_bigint::BigInt;
use oxc_ast::ast::*;
use oxc_span::{GetSpan, Span, SPAN};
use oxc_syntax::{
number::{NumberBase, ToJsInt32},
operator::{BinaryOperator, LogicalOperator, UnaryOperator},
};
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};

use crate::{
node_util::{
is_exact_int64, IsLiteralValue, MayHaveSideEffects, NodeUtil, NumberValue, ValueType,
Expand All @@ -6,16 +17,6 @@ use crate::{
ty::Ty,
CompressorPass,
};
use num_bigint::BigInt;
use oxc_ast::ast::*;
use oxc_span::{GetSpan, Span, SPAN};
use oxc_syntax::number::ToJsInt32;
use oxc_syntax::{
number::NumberBase,
operator::{BinaryOperator, LogicalOperator, UnaryOperator},
};
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
use std::cmp::Ordering;

/// Constant Folding
///
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use oxc_ast::ast::*;
use oxc_span::{GetSpan, SPAN};
use oxc_syntax::number::ToJsInt32;
use oxc_syntax::{
number::NumberBase,
operator::{BinaryOperator, UnaryOperator},
Expand Down Expand Up @@ -77,6 +78,12 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
}

fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
if let Expression::AssignmentExpression(assignment_expr) = expr {
if let Some(new_expr) = self.try_compress_assignment_expression(assignment_expr, ctx) {
*expr = new_expr;
self.changed = true;
}
}
if !self.compress_undefined(expr, ctx) {
self.compress_boolean(expr, ctx);
}
Expand Down Expand Up @@ -260,6 +267,45 @@ impl<'a> PeepholeSubstituteAlternateSyntax {
self.changed = true;
}
}

fn try_compress_assignment_expression(
&mut self,
expr: &mut AssignmentExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Option<Expression<'a>> {
let target = expr.left.as_simple_assignment_target_mut()?;
if matches!(expr.operator, AssignmentOperator::Subtraction) {
match &expr.right {
Expression::NumericLiteral(num) if num.value.to_js_int_32() == 1 => {
// The `_` will not be placed to the target code.
let target = std::mem::replace(
target,
ctx.ast.simple_assignment_target_identifier_reference(SPAN, "_"),
);
Some(ctx.ast.expression_update(SPAN, UpdateOperator::Decrement, true, target))
}
Expression::UnaryExpression(un)
if matches!(un.operator, UnaryOperator::UnaryNegation) =>
{
if let Expression::NumericLiteral(num) = &un.argument {
(num.value.to_js_int_32() == 1).then(|| {
// The `_` will not be placed to the target code.
let target = std::mem::replace(
target,
ctx.ast.simple_assignment_target_identifier_reference(SPAN, "_"),
);
ctx.ast.expression_update(SPAN, UpdateOperator::Increment, true, target)
})
} else {
None
}
}
_ => None,
}
} else {
None
}
}
}

/// <https://github.com/google/closure-compiler/blob/master/test/com/google/javascript/jscomp/PeepholeSubstituteAlternateSyntax.java>
Expand Down Expand Up @@ -302,4 +348,25 @@ mod test {
// shadowd
test_same("(function(undefined) { let x = typeof undefined; })()");
}

#[test]
#[ignore]
fn fold_true_false_comparison() {
test("x == true", "x == 1");
test("x == false", "x == 0");
test("x != true", "x != 1");
test("x < true", "x < 1");
test("x <= true", "x <= 1");
test("x > true", "x > 1");
test("x >= true", "x >= 1");
}

#[test]
fn test_fold_subtraction_assignment() {
test("x -= 1", "--x");
test("x -= -1", "++x");
test_same("x -= 2");
test_same("x += 1"); // The string concatenation may be triggered, so we don't fold this.
test_same("x += -1");
}
}
10 changes: 5 additions & 5 deletions tasks/minsize/minsize.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Original | Minified | esbuild | Gzip | esbuild

72.14 kB | 24.47 kB | 23.70 kB | 8.65 kB | 8.54 kB | react.development.js

173.90 kB | 61.70 kB | 59.82 kB | 19.54 kB | 19.33 kB | moment.js
173.90 kB | 61.69 kB | 59.82 kB | 19.54 kB | 19.33 kB | moment.js

287.63 kB | 92.83 kB | 90.07 kB | 32.29 kB | 31.95 kB | jquery.js

Expand All @@ -14,13 +14,13 @@ Original | Minified | esbuild | Gzip | esbuild

1.01 MB | 470.11 kB | 458.89 kB | 126.97 kB | 126.71 kB | bundle.min.js

1.25 MB | 671 kB | 646.76 kB | 164.72 kB | 163.73 kB | three.js
1.25 MB | 671.00 kB | 646.76 kB | 164.72 kB | 163.73 kB | three.js

2.14 MB | 756.69 kB | 724.14 kB | 182.87 kB | 181.07 kB | victory.js

3.20 MB | 1.05 MB | 1.01 MB | 334.11 kB | 331.56 kB | echarts.js
3.20 MB | 1.05 MB | 1.01 MB | 334.10 kB | 331.56 kB | echarts.js

6.69 MB | 2.44 MB | 2.31 MB | 498.90 kB | 488.28 kB | antd.js
6.69 MB | 2.44 MB | 2.31 MB | 498.93 kB | 488.28 kB | antd.js

10.95 MB | 3.59 MB | 3.49 MB | 913.94 kB | 915.50 kB | typescript.js
10.95 MB | 3.59 MB | 3.49 MB | 913.96 kB | 915.50 kB | typescript.js

0 comments on commit 585ccda

Please sign in to comment.