feat(minifier): drop 0 from new Int8Array(0) and other TypedArrays (#8431)

Compresses `new Int8Array(0)` into `new Int8Array()`. (then will be compress into `new Int8Array`).

Partial quote from the [spec](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-typedarray):

> 5. If numberOfArgs = 0, then
>   a. Return ? AllocateTypedArray(constructorName, NewTarget, proto, 0).
> 6. Else,
>   c. Else,
>       ii. Let elementLength be ? ToIndex(firstArgument).
>      iii. Return ? AllocateTypedArray(constructorName, NewTarget, proto, elementLength).
This commit is contained in:
sapphi-red 2025-01-11 07:45:36 +00:00
parent f935d9434f
commit d56020b84c
No known key found for this signature in database
GPG key ID: 67631A259A77AC6C
2 changed files with 64 additions and 1 deletions

View file

@ -140,6 +140,9 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
self.try_compress_normal_assignment_to_combined_assignment(e, ctx);
self.try_compress_normal_assignment_to_combined_logical_assignment(e, ctx);
}
Expression::NewExpression(e) => {
self.try_compress_typed_array_constructor(e, ctx);
}
_ => {}
}
@ -1038,6 +1041,46 @@ impl<'a, 'b> PeepholeSubstituteAlternateSyntax {
)
}
/// `new Int8Array(0)` -> `new Int8Array()` (also for other TypedArrays)
fn try_compress_typed_array_constructor(
&mut self,
e: &mut NewExpression<'a>,
ctx: Ctx<'a, 'b>,
) {
let Expression::Identifier(ident) = &e.callee else { return };
let name = ident.name.as_str();
if !Self::is_typed_array_name(name) || !ctx.is_global_reference(ident) {
return;
}
if e.arguments.len() == 1
&& e.arguments[0].as_expression().is_some_and(Expression::is_number_0)
{
e.arguments.clear();
self.changed = true;
}
}
/// Whether the name matches any TypedArray name.
///
/// See <https://tc39.es/ecma262/multipage/indexed-collections.html#sec-typedarray-objects> for the list of TypedArrays.
fn is_typed_array_name(name: &str) -> bool {
matches!(
name,
"Int8Array"
| "Uint8Array"
| "Uint8ClampedArray"
| "Int16Array"
| "Uint16Array"
| "Int32Array"
| "Uint32Array"
| "Float32Array"
| "Float64Array"
| "BigInt64Array"
| "BigUint64Array"
)
}
/// `typeof foo === 'number'` -> `typeof foo == 'number'`
fn try_compress_type_of_equal_string(&mut self, e: &mut BinaryExpression<'a>) {
let op = match e.operator {
@ -1462,6 +1505,26 @@ mod test {
test_same("new RegExp(/foo/)");
}
#[test]
fn test_compress_typed_array_constructor() {
test("new Int8Array(0)", "new Int8Array()");
test("new Uint8Array(0)", "new Uint8Array()");
test("new Uint8ClampedArray(0)", "new Uint8ClampedArray()");
test("new Int16Array(0)", "new Int16Array()");
test("new Uint16Array(0)", "new Uint16Array()");
test("new Int32Array(0)", "new Int32Array()");
test("new Uint32Array(0)", "new Uint32Array()");
test("new Float32Array(0)", "new Float32Array()");
test("new Float64Array(0)", "new Float64Array()");
test("new BigInt64Array(0)", "new BigInt64Array()");
test("new BigUint64Array(0)", "new BigUint64Array()");
test_same("var Int8Array; new Int8Array(0)");
test_same("new Int8Array(1)");
test_same("new Int8Array(a)");
test_same("new Int8Array(0, a)");
}
#[test]
#[ignore]
fn test_split_comma_expressions() {

View file

@ -11,7 +11,7 @@ Original | minified | minified | gzip | gzip | Fixture
544.10 kB | 71.76 kB | 72.48 kB | 26.15 kB | 26.20 kB | lodash.js
555.77 kB | 273.16 kB | 270.13 kB | 90.92 kB | 90.80 kB | d3.js
555.77 kB | 273.15 kB | 270.13 kB | 90.92 kB | 90.80 kB | d3.js
1.01 MB | 460.18 kB | 458.89 kB | 126.77 kB | 126.71 kB | bundle.min.js