mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
feat(minifier): implement known methods Math.clz32 and Math.imul (#12405)
The known methods module of `Number` and `Math` only left `Math.pow` unimplemented! --------- Co-authored-by: sapphi-red <49056869+sapphi-red@users.noreply.github.com>
This commit is contained in:
1 parent
2a21d1b447
commit
a1b6ad490a
2 files changed
+54
-37
No files matched your search
@@ -16,7 +16,7 @@ use cow_utils::CowUtils;
|
||||
|
||||
use crate::{
|
||||
StringCharAt, StringCharAtResult, StringCharCodeAt, StringIndexOf, StringLastIndexOf,
|
||||
StringSubstring, ToInt32, ToJsString as ToJsStringTrait,
|
||||
StringSubstring, ToInt32, ToJsString as ToJsStringTrait, ToUint32,
|
||||
constant_evaluation::url_encoding::{
|
||||
decode_uri_chars, encode_uri_chars, is_uri_always_unescaped,
|
||||
},
|
||||
@@ -89,10 +89,10 @@ pub fn try_fold_known_global_methods<'a>(
|
||||
try_fold_number_methods(arguments, object, name, ctx)
|
||||
}
|
||||
"sqrt" | "cbrt" => try_fold_roots(arguments, name, object, ctx),
|
||||
"abs" | "ceil" | "floor" | "round" | "fround" | "trunc" | "sign" => {
|
||||
"abs" | "ceil" | "floor" | "round" | "fround" | "trunc" | "sign" | "clz32" => {
|
||||
try_fold_math_unary(arguments, name, object, ctx)
|
||||
}
|
||||
"min" | "max" => try_fold_math_variadic(arguments, name, object, ctx),
|
||||
"imul" | "min" | "max" => try_fold_math_variadic(arguments, name, object, ctx),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -478,6 +478,7 @@ fn try_fold_math_unary<'a>(
|
||||
"sign" if arg_val.to_bits() == 0f64.to_bits() => 0f64,
|
||||
"sign" if arg_val.to_bits() == (-0f64).to_bits() => -0f64,
|
||||
"sign" => arg_val.signum(),
|
||||
"clz32" => f64::from(arg_val.to_uint_32().leading_zeros()),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// These results are always shorter to return as a number, so we can just return them as NumericLiteral.
|
||||
@@ -499,28 +500,38 @@ fn try_fold_math_variadic<'a>(
|
||||
let value = expr.get_side_free_number_value(ctx)?;
|
||||
numbers.push(value);
|
||||
}
|
||||
let result = if numbers.iter().any(|n: &f64| n.is_nan()) {
|
||||
f64::NAN
|
||||
} else {
|
||||
match name {
|
||||
// TODO
|
||||
// see <https://github.com/rust-lang/rust/issues/83984>, we can't use `min` and `max` here due to inconsistency
|
||||
"min" => numbers.iter().copied().fold(f64::INFINITY, |a, b| {
|
||||
if a < b || ((a == 0f64) && (b == 0f64) && (a.to_bits() > b.to_bits())) {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
let result = match name {
|
||||
"min" | "max" => {
|
||||
if numbers.iter().any(|n: &f64| n.is_nan()) {
|
||||
f64::NAN
|
||||
} else {
|
||||
match name {
|
||||
// TODO
|
||||
// see <https://github.com/rust-lang/rust/issues/83984>, we can't use `min` and `max` here due to inconsistency
|
||||
"min" => numbers.iter().copied().fold(f64::INFINITY, |a, b| {
|
||||
if a < b || ((a == 0f64) && (b == 0f64) && (a.to_bits() > b.to_bits())) {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}),
|
||||
"max" => numbers.iter().copied().fold(f64::NEG_INFINITY, |a, b| {
|
||||
if a > b || ((a == 0f64) && (b == 0f64) && (a.to_bits() < b.to_bits())) {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}),
|
||||
_ => return None,
|
||||
}
|
||||
}),
|
||||
"max" => numbers.iter().copied().fold(f64::NEG_INFINITY, |a, b| {
|
||||
if a > b || ((a == 0f64) && (b == 0f64) && (a.to_bits() < b.to_bits())) {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
"imul" => {
|
||||
let a = numbers.first().copied().unwrap_or(f64::NAN).to_uint_32();
|
||||
let b = numbers.get(1).copied().unwrap_or(f64::NAN).to_uint_32();
|
||||
f64::from(a.wrapping_mul(b).cast_signed())
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
Some(ConstantValue::Number(result))
|
||||
}
|
||||
|
||||
@@ -1012,9 +1012,9 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_fold_math_functions_imul() {
|
||||
test_same_value("Math.imul(Math.random(),2)");
|
||||
test_value("Math.imul()", "0");
|
||||
test_value("Math.imul(-1,1)", "-1");
|
||||
test_value("Math.imul(2,2)", "4");
|
||||
test_value("Math.imul(2)", "0");
|
||||
@@ -1096,27 +1096,33 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_fold_math_functions_clz32() {
|
||||
test("Math.clz32(0)", "32");
|
||||
let mut x = 1;
|
||||
test_value("Math.clz32(0)", "32");
|
||||
test_value("Math.clz32(0.0)", "32");
|
||||
test_value("Math.clz32(-0.0)", "32");
|
||||
let mut x = 1_i64;
|
||||
for i in (0..=31).rev() {
|
||||
test(&format!("{x}.leading_zeros()"), &i.to_string());
|
||||
test(&format!("{}.leading_zeros()", 2 * x - 1), &i.to_string());
|
||||
test_value(&format!("Math.clz32({x})"), &i.to_string());
|
||||
test_value(&format!("Math.clz32({})", 2 * x - 1), &i.to_string());
|
||||
x *= 2;
|
||||
}
|
||||
test("Math.clz32('52')", "26");
|
||||
test("Math.clz32([52])", "26");
|
||||
test("Math.clz32([52, 53])", "32");
|
||||
test_value("Math.clz32('52')", "26");
|
||||
test_value("Math.clz32([52])", "26");
|
||||
test_value("Math.clz32([52, 53])", "32");
|
||||
|
||||
// Overflow cases
|
||||
test("Math.clz32(0x100000000)", "32");
|
||||
test("Math.clz32(0x100000001)", "31");
|
||||
test_value("Math.clz32(0x100000000)", "32");
|
||||
test_value("Math.clz32(0x100000001)", "31");
|
||||
|
||||
// Negative cases
|
||||
test_value("Math.clz32(-1)", "0");
|
||||
test_value("Math.clz32(-2147483647)", "0");
|
||||
test_value("Math.clz32(-2147483649)", "1");
|
||||
|
||||
// NaN -> 0
|
||||
test("Math.clz32(NaN)", "32");
|
||||
test("Math.clz32('foo')", "32");
|
||||
test("Math.clz32(Infinity)", "32");
|
||||
test_value("Math.clz32(NaN)", "32");
|
||||
test_value("Math.clz32('foo')", "32");
|
||||
test_value("Math.clz32(Infinity)", "32");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user