refactor(ecmascript): avoid redundant checks by splitting up match arms (#12782)

Makes code a lot easier to understand and avoids some redundant checks
in runtime.
This commit is contained in:
Ulrich Stark authored and GitHub committed 2025-08-05 14:53:29 +08:00
1 parent 3f37ed1aff
commit f3f601235d
1 file changed
+87 -79
@@ -233,51 +233,60 @@ fn binary_operation_evaluate_value_to<'a>(
}
None
}
BinaryOperator::Subtraction
| BinaryOperator::Division
| BinaryOperator::Remainder
| BinaryOperator::Multiplication
| BinaryOperator::Exponential => {
BinaryOperator::Subtraction => {
let lval = left.evaluate_value_to_number(ctx)?;
let rval = right.evaluate_value_to_number(ctx)?;
let val = match operator {
BinaryOperator::Subtraction => lval - rval,
BinaryOperator::Division => lval / rval,
BinaryOperator::Remainder => {
if rval.is_zero() {
f64::NAN
} else {
lval % rval
}
}
BinaryOperator::Multiplication => lval * rval,
BinaryOperator::Exponential => {
let result = lval.powf(rval);
// For now, ignore the result if it large or has a decimal part
// so that the output does not become bigger than the input.
if result.is_finite() && (result.fract() != 0.0 || result.log10() > 4.0) {
return None;
}
result
}
_ => unreachable!(),
};
Some(ConstantValue::Number(val))
Some(ConstantValue::Number(lval - rval))
}
BinaryOperator::Division => {
let lval = left.evaluate_value_to_number(ctx)?;
let rval = right.evaluate_value_to_number(ctx)?;
Some(ConstantValue::Number(lval / rval))
}
BinaryOperator::Remainder => {
let lval = left.evaluate_value_to_number(ctx)?;
let rval = right.evaluate_value_to_number(ctx)?;
Some(ConstantValue::Number(if rval.is_zero() { f64::NAN } else { lval % rval }))
}
BinaryOperator::Multiplication => {
let lval = left.evaluate_value_to_number(ctx)?;
let rval = right.evaluate_value_to_number(ctx)?;
Some(ConstantValue::Number(lval * rval))
}
BinaryOperator::Exponential => {
let lval = left.evaluate_value_to_number(ctx)?;
let rval = right.evaluate_value_to_number(ctx)?;
let result = lval.powf(rval);
// For now, ignore the result if it large or has a decimal part
// so that the output does not become bigger than the input.
if result.is_finite() && (result.fract() != 0.0 || result.log10() > 4.0) {
return None;
}
Some(ConstantValue::Number(result))
}
#[expect(clippy::cast_sign_loss)]
BinaryOperator::ShiftLeft
| BinaryOperator::ShiftRight
| BinaryOperator::ShiftRightZeroFill => {
BinaryOperator::ShiftLeft => {
let left = left.evaluate_value_to_number(ctx)?;
let right = right.evaluate_value_to_number(ctx)?;
let left = left.to_int_32();
let right = (right.to_int_32() as u32) & 31;
Some(ConstantValue::Number(match operator {
BinaryOperator::ShiftLeft => f64::from(left << right),
BinaryOperator::ShiftRight => f64::from(left >> right),
BinaryOperator::ShiftRightZeroFill => f64::from((left as u32) >> right),
_ => unreachable!(),
}))
Some(ConstantValue::Number(f64::from(left << right)))
}
#[expect(clippy::cast_sign_loss)]
BinaryOperator::ShiftRight => {
let left = left.evaluate_value_to_number(ctx)?;
let right = right.evaluate_value_to_number(ctx)?;
let left = left.to_int_32();
let right = (right.to_int_32() as u32) & 31;
Some(ConstantValue::Number(f64::from(left >> right)))
}
#[expect(clippy::cast_sign_loss)]
BinaryOperator::ShiftRightZeroFill => {
let left = left.evaluate_value_to_number(ctx)?;
let right = right.evaluate_value_to_number(ctx)?;
let left = left.to_int_32();
let right = (right.to_int_32() as u32) & 31;
Some(ConstantValue::Number(f64::from((left as u32) >> right)))
}
BinaryOperator::LessThan => is_less_than(ctx, left, right).map(|value| match value {
ConstantValue::Undefined => ConstantValue::Boolean(false),
@@ -303,33 +312,35 @@ fn binary_operation_evaluate_value_to<'a>(
_ => unreachable!(),
})
}
BinaryOperator::BitwiseAnd | BinaryOperator::BitwiseOR | BinaryOperator::BitwiseXOR => {
BinaryOperator::BitwiseAnd => {
if left.value_type(ctx).is_bigint() && right.value_type(ctx).is_bigint() {
let left_val = left.evaluate_value_to_bigint(ctx)?;
let right_val = right.evaluate_value_to_bigint(ctx)?;
let result_val: BigInt = match operator {
BinaryOperator::BitwiseAnd => left_val & right_val,
BinaryOperator::BitwiseOR => left_val | right_val,
BinaryOperator::BitwiseXOR => left_val ^ right_val,
_ => unreachable!(),
};
return Some(ConstantValue::BigInt(result_val));
let left_biginit = left.evaluate_value_to_bigint(ctx)?;
let right_bigint = right.evaluate_value_to_bigint(ctx)?;
return Some(ConstantValue::BigInt(left_biginit & right_bigint));
}
let left_num = left.evaluate_value_to_number(ctx);
let right_num = right.evaluate_value_to_number(ctx);
if let (Some(left_val), Some(right_val)) = (left_num, right_num) {
let left_val_int = left_val.to_int_32();
let right_val_int = right_val.to_int_32();
let result_val: f64 = match operator {
BinaryOperator::BitwiseAnd => f64::from(left_val_int & right_val_int),
BinaryOperator::BitwiseOR => f64::from(left_val_int | right_val_int),
BinaryOperator::BitwiseXOR => f64::from(left_val_int ^ right_val_int),
_ => unreachable!(),
};
return Some(ConstantValue::Number(result_val));
let left_int = left.evaluate_value_to_number(ctx)?.to_int_32();
let right_int = right.evaluate_value_to_number(ctx)?.to_int_32();
Some(ConstantValue::Number(f64::from(left_int & right_int)))
}
BinaryOperator::BitwiseOR => {
if left.value_type(ctx).is_bigint() && right.value_type(ctx).is_bigint() {
let left_biginit = left.evaluate_value_to_bigint(ctx)?;
let right_bigint = right.evaluate_value_to_bigint(ctx)?;
return Some(ConstantValue::BigInt(left_biginit | right_bigint));
}
None
let left_int = left.evaluate_value_to_number(ctx)?.to_int_32();
let right_int = right.evaluate_value_to_number(ctx)?.to_int_32();
Some(ConstantValue::Number(f64::from(left_int | right_int)))
}
BinaryOperator::BitwiseXOR => {
if left.value_type(ctx).is_bigint() && right.value_type(ctx).is_bigint() {
let left_biginit = left.evaluate_value_to_bigint(ctx)?;
let right_bigint = right.evaluate_value_to_bigint(ctx)?;
return Some(ConstantValue::BigInt(left_biginit ^ right_bigint));
}
let left_int = left.evaluate_value_to_number(ctx)?.to_int_32();
let right_int = right.evaluate_value_to_number(ctx)?.to_int_32();
Some(ConstantValue::Number(f64::from(left_int ^ right_int)))
}
BinaryOperator::Instanceof => {
if let Expression::Identifier(right_ident) = right {
@@ -348,24 +359,21 @@ fn binary_operation_evaluate_value_to<'a>(
}
None
}
BinaryOperator::StrictEquality
| BinaryOperator::StrictInequality
| BinaryOperator::Equality
| BinaryOperator::Inequality => {
let value = match operator {
BinaryOperator::StrictEquality | BinaryOperator::StrictInequality => {
strict_equality_comparison(ctx, left, right)?
}
BinaryOperator::Equality | BinaryOperator::Inequality => {
abstract_equality_comparison(ctx, left, right)?
}
_ => unreachable!(),
};
Some(ConstantValue::Boolean(match operator {
BinaryOperator::StrictEquality | BinaryOperator::Equality => value,
BinaryOperator::StrictInequality | BinaryOperator::Inequality => !value,
_ => unreachable!(),
}))
BinaryOperator::StrictEquality => {
let value = strict_equality_comparison(ctx, left, right)?;
Some(ConstantValue::Boolean(value))
}
BinaryOperator::StrictInequality => {
let value = strict_equality_comparison(ctx, left, right)?;
Some(ConstantValue::Boolean(!value))
}
BinaryOperator::Equality => {
let value = abstract_equality_comparison(ctx, left, right)?;
Some(ConstantValue::Boolean(value))
}
BinaryOperator::Inequality => {
let value = abstract_equality_comparison(ctx, left, right)?;
Some(ConstantValue::Boolean(!value))
}
BinaryOperator::In => None,
}