LibJS/Bytecode: Round constant operands of bitwise binary expressions

This helps some of the Cloudflare Turnstile stuff run faster, since they
are deliberately screwing with JS engines by asking us to do a bunch of
bitwise operations on e.g 65535.56

By rounding such values in bytecode generation, the interpreter can stay
on the happy path while executing, and finish quite a bit faster.
This commit is contained in:
Andreas Kling 2024-05-09 15:17:34 +02:00 committed by Alexander Kalenik
commit 448f837d38
Notes: sideshowbarker 2024-07-18 02:47:59 +09:00

View file

@ -90,9 +90,59 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> BinaryExpression::gener
return dst;
}
auto lhs = TRY(m_lhs->generate_bytecode(generator)).value();
auto rhs = TRY(m_rhs->generate_bytecode(generator)).value();
// OPTIMIZATION: If LHS and/or RHS are numeric literals, we make sure they are converted to i32/u32
// as appropriate, to avoid having to perform these conversions at runtime.
auto get_left_side = [&](Expression const& side) -> CodeGenerationErrorOr<Optional<ScopedOperand>> {
switch (m_op) {
case BinaryOp::BitwiseAnd:
case BinaryOp::BitwiseOr:
case BinaryOp::BitwiseXor:
case BinaryOp::LeftShift:
case BinaryOp::RightShift:
case BinaryOp::UnsignedRightShift:
// LHS will always be converted to i32 for these ops.
if (side.is_numeric_literal()) {
auto value = MUST(static_cast<NumericLiteral const&>(side).value().to_i32(generator.vm()));
return generator.add_constant(Value(value));
}
break;
default:
break;
}
return side.generate_bytecode(generator);
};
auto get_right_side = [&](Expression const& side) -> CodeGenerationErrorOr<Optional<ScopedOperand>> {
switch (m_op) {
case BinaryOp::BitwiseAnd:
case BinaryOp::BitwiseOr:
case BinaryOp::BitwiseXor:
// RHS will always be converted to i32 for these ops.
if (side.is_numeric_literal()) {
auto value = MUST(static_cast<NumericLiteral const&>(side).value().to_i32(generator.vm()));
return generator.add_constant(Value(value));
}
break;
case BinaryOp::LeftShift:
case BinaryOp::RightShift:
case BinaryOp::UnsignedRightShift:
// RHS will always be converted to u32 for these ops.
if (side.is_numeric_literal()) {
auto value = MUST(static_cast<NumericLiteral const&>(side).value().to_u32(generator.vm()));
return generator.add_constant(Value(value));
}
break;
default:
break;
}
return side.generate_bytecode(generator);
};
auto lhs = TRY(get_left_side(*m_lhs)).value();
auto rhs = TRY(get_right_side(*m_rhs)).value();
auto dst = choose_dst(generator, preferred_dst);
switch (m_op) {
case BinaryOp::Addition: