mirror of
https://github.com/danbulant/oxc
synced 2026-05-21 05:08:45 +00:00
feat(minifier): implement try_fold_shift (#478)
* feat: implement `try_fold_shift` * update minsize
This commit is contained in:
parent
f12166c92f
commit
1182985bb0
3 changed files with 105 additions and 3 deletions
|
|
@ -108,6 +108,14 @@ impl<'a> Compressor<'a> {
|
|||
&binary_expr.left,
|
||||
&binary_expr.right,
|
||||
),
|
||||
BinaryOperator::ShiftLeft
|
||||
| BinaryOperator::ShiftRight
|
||||
| BinaryOperator::ShiftRightZeroFill => self.try_fold_shift(
|
||||
binary_expr.span,
|
||||
binary_expr.operator,
|
||||
&binary_expr.left,
|
||||
&binary_expr.right,
|
||||
),
|
||||
_ => None,
|
||||
},
|
||||
Expression::UnaryExpression(unary_expr) => match unary_expr.operator {
|
||||
|
|
@ -513,4 +521,63 @@ impl<'a> Compressor<'a> {
|
|||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// ported from [closure-compiler](https://github.com/google/closure-compiler/blob/a4c880032fba961f7a6c06ef99daa3641810bfdd/src/com/google/javascript/jscomp/PeepholeFoldConstants.java#L1114-L1162)
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn try_fold_shift<'b>(
|
||||
&mut self,
|
||||
span: Span,
|
||||
op: BinaryOperator,
|
||||
left: &'b Expression<'a>,
|
||||
right: &'b Expression<'a>,
|
||||
) -> Option<Expression<'a>> {
|
||||
let left_num = get_side_free_number_value(left);
|
||||
let right_num = get_side_free_number_value(right);
|
||||
|
||||
if let Some(NumberValue::Number(left_val)) = left_num &&
|
||||
let Some(NumberValue::Number(right_val)) = right_num {
|
||||
if left_val.fract() != 0.0 || right_val.fract() != 0.0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// only the lower 5 bits are used when shifting, so don't do anything
|
||||
// if the shift amount is outside [0,32)
|
||||
if !(0.0..32.0).contains(&right_val) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let right_val_int = right_val as i32;
|
||||
let bits = NumberLiteral::ecmascript_to_int32(left_val);
|
||||
|
||||
let result_val: f64 = match op {
|
||||
BinaryOperator::ShiftLeft => {
|
||||
f64::from(bits << right_val_int)
|
||||
}
|
||||
BinaryOperator::ShiftRight => {
|
||||
f64::from(bits >> right_val_int)
|
||||
}
|
||||
BinaryOperator::ShiftRightZeroFill => {
|
||||
// JavaScript always treats the result of >>> as unsigned.
|
||||
// We must force Rust to do the same here.
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
let res = bits as u32 >> right_val_int as u32;
|
||||
f64::from(res)
|
||||
}
|
||||
_ => unreachable!("Unknown binary operator {:?}", op)
|
||||
};
|
||||
|
||||
let value_raw = self.hir.new_str(result_val.to_string().as_str());
|
||||
|
||||
let number_literal = self.hir.number_literal(
|
||||
span,
|
||||
result_val,
|
||||
value_raw,
|
||||
NumberBase::Decimal,
|
||||
);
|
||||
|
||||
return Some(self.hir.literal_number_expression(number_literal));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,3 +234,38 @@ fn test_fold_void() {
|
|||
test("void x", "void 0");
|
||||
test_same("void x()");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fold_bit_shift() {
|
||||
test("x = 1 << 0", "x=1");
|
||||
test("x = -1 << 0", "x=-1");
|
||||
test("x = 1 << 1", "x=2");
|
||||
test("x = 3 << 1", "x=6");
|
||||
test("x = 1 << 8", "x=256");
|
||||
|
||||
test("x = 1 >> 0", "x=1");
|
||||
test("x = -1 >> 0", "x=-1");
|
||||
test("x = 1 >> 1", "x=0");
|
||||
test("x = 2 >> 1", "x=1");
|
||||
test("x = 5 >> 1", "x=2");
|
||||
test("x = 127 >> 3", "x=15");
|
||||
test("x = 3 >> 1", "x=1");
|
||||
test("x = 3 >> 2", "x=0");
|
||||
test("x = 10 >> 1", "x=5");
|
||||
test("x = 10 >> 2", "x=2");
|
||||
test("x = 10 >> 5", "x=0");
|
||||
|
||||
test("x = 10 >>> 1", "x=5");
|
||||
test("x = 10 >>> 2", "x=2");
|
||||
test("x = 10 >>> 5", "x=0");
|
||||
test("x = -1 >>> 1", "x=2147483647"); // 0x7fffffff
|
||||
test("x = -1 >>> 0", "x=4294967295"); // 0xffffffff
|
||||
test("x = -2 >>> 0", "x=4294967294"); // 0xfffffffe
|
||||
test("x = 0x90000000 >>> 28", "x=9");
|
||||
|
||||
test("x = 0xffffffff << 0", "x=-1");
|
||||
test("x = 0xffffffff << 4", "x=-16");
|
||||
test("1 << 32", "1<<32");
|
||||
test("1 << -1", "1<<-1");
|
||||
test("1 >> 32", "1>>32");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,15 +11,15 @@ Original -> Minified -> Gzip Brotli
|
|||
|
||||
555.77 kB -> 274.89 kB -> 91.40 kB 76.86 kB d3.js
|
||||
|
||||
977.19 kB -> 456.44 kB -> 123.71 kB 107.10 kB bundle.min.js
|
||||
977.19 kB -> 456.43 kB -> 123.71 kB 107.19 kB bundle.min.js
|
||||
|
||||
1.25 MB -> 677.74 kB -> 166.58 kB 134.57 kB three.js
|
||||
|
||||
2.14 MB -> 743.86 kB -> 181.82 kB 138.89 kB victory.js
|
||||
|
||||
3.20 MB -> 1.03 MB -> 332.93 kB 268.96 kB echarts.js
|
||||
3.20 MB -> 1.03 MB -> 332.93 kB 269.04 kB echarts.js
|
||||
|
||||
6.69 MB -> 2.40 MB -> 498.41 kB 390.35 kB antd.js
|
||||
|
||||
10.82 MB -> 3.53 MB -> 903.10 kB 692.91 kB typescript.js
|
||||
10.82 MB -> 3.53 MB -> 903.09 kB 693.53 kB typescript.js
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue