From 62747cb3a6542cb4af0be05dd5a79acc564e6cd0 Mon Sep 17 00:00:00 2001 From: Haled Odat <8566042+HalidOdat@users.noreply.github.com> Date: Thu, 2 Apr 2026 18:57:50 +0200 Subject: [PATCH] feat(compiler): Generate optimized code for ToInt32 code patterns --- .../src/bytecompiler/expression/binary.rs | 24 ++++++++++++--- core/engine/src/vm/code_block.rs | 4 +-- core/engine/src/vm/flowgraph/mod.rs | 4 +-- core/engine/src/vm/opcode/mod.rs | 9 ++++-- core/engine/src/vm/opcode/unary_ops/mod.rs | 29 +++++++++++++++++++ 5 files changed, 60 insertions(+), 10 deletions(-) diff --git a/core/engine/src/bytecompiler/expression/binary.rs b/core/engine/src/bytecompiler/expression/binary.rs index 66a80a2d415..b603c149cf8 100644 --- a/core/engine/src/bytecompiler/expression/binary.rs +++ b/core/engine/src/bytecompiler/expression/binary.rs @@ -4,9 +4,12 @@ use crate::{ }; use boa_ast::{ Expression, - expression::operator::{ - Binary, BinaryInPrivate, - binary::{ArithmeticOp, BinaryOp, BitwiseOp, LogicalOp, RelationalOp}, + expression::{ + literal::LiteralKind, + operator::{ + Binary, BinaryInPrivate, + binary::{ArithmeticOp, BinaryOp, BitwiseOp, LogicalOp, RelationalOp}, + }, }, }; @@ -20,7 +23,20 @@ impl ByteCompiler<'_> { } BinaryOp::Bitwise(op) => { self.compile_expr_operand(binary.lhs(), |self_, lhs| { - self_.compile_binary_bitwise(op, binary.rhs(), dst, lhs); + const MAX_UINT32_LITERAL: LiteralKind = LiteralKind::Num(u32::MAX as f64); + if let Expression::Literal(literal) = binary.rhs().flatten() + && ( + // x | 0 + (op == BitwiseOp::Or && literal.kind() == &LiteralKind::Int(0)) + || + // x & 0xFFFFFFFF + (op == BitwiseOp::And && literal.kind() == &MAX_UINT32_LITERAL) + ) + { + self_.bytecode.emit_to_int32(dst.variable(), lhs); + } else { + self_.compile_binary_bitwise(op, binary.rhs(), dst, lhs); + } }); } BinaryOp::Relational(op) => { diff --git a/core/engine/src/vm/code_block.rs b/core/engine/src/vm/code_block.rs index d9eec2fc949..a6e3fb893e6 100644 --- a/core/engine/src/vm/code_block.rs +++ b/core/engine/src/vm/code_block.rs @@ -396,6 +396,7 @@ impl CodeBlock { | Instruction::CreateUnmappedArgumentsObject { dst } | Instruction::RestParameterInit { dst } | Instruction::StoreNewArray { dst } => format!("dst:{dst}"), + Instruction::ToInt32 { dst, src } => format!("dst:{dst}, src:{src}"), Instruction::Add { lhs, rhs, dst } | Instruction::Sub { lhs, rhs, dst } | Instruction::Div { lhs, rhs, dst } @@ -933,8 +934,7 @@ impl CodeBlock { | Instruction::Reserved56 | Instruction::Reserved57 | Instruction::Reserved58 - | Instruction::Reserved59 - | Instruction::Reserved60 => unreachable!("Reserved opcodes are unreachable"), + | Instruction::Reserved59 => unreachable!("Reserved opcodes are unreachable"), } } } diff --git a/core/engine/src/vm/flowgraph/mod.rs b/core/engine/src/vm/flowgraph/mod.rs index 2f96e6edcbd..da8ff98f25f 100644 --- a/core/engine/src/vm/flowgraph/mod.rs +++ b/core/engine/src/vm/flowgraph/mod.rs @@ -46,6 +46,7 @@ impl CodeBlock { | Instruction::Move { .. } | Instruction::PopIntoRegister { .. } | Instruction::PushFromRegister { .. } + | Instruction::ToInt32 { .. } | Instruction::Add { .. } | Instruction::Sub { .. } | Instruction::Div { .. } @@ -432,8 +433,7 @@ impl CodeBlock { | Instruction::Reserved56 | Instruction::Reserved57 | Instruction::Reserved58 - | Instruction::Reserved59 - | Instruction::Reserved60 => unreachable!("Reserved opcodes are unreachable"), + | Instruction::Reserved59 => unreachable!("Reserved opcodes are unreachable"), } } diff --git a/core/engine/src/vm/opcode/mod.rs b/core/engine/src/vm/opcode/mod.rs index f01c7afecbe..37cb4940311 100644 --- a/core/engine/src/vm/opcode/mod.rs +++ b/core/engine/src/vm/opcode/mod.rs @@ -767,6 +767,13 @@ generate_opcodes! { /// - Input: array PushIteratorToArray { array: RegisterOperand }, + /// Convert the value into a int32. + /// + /// - Registers + /// - Input: src + /// - Output: dst + ToInt32 { dst: RegisterOperand, src: RegisterOperand }, + /// Binary `+` operator. /// /// - Registers @@ -2270,6 +2277,4 @@ generate_opcodes! { Reserved58 => Reserved, /// Reserved [`Opcode`]. Reserved59 => Reserved, - /// Reserved [`Opcode`]. - Reserved60 => Reserved, } diff --git a/core/engine/src/vm/opcode/unary_ops/mod.rs b/core/engine/src/vm/opcode/unary_ops/mod.rs index d2ed6920956..15a5afa61ac 100644 --- a/core/engine/src/vm/opcode/unary_ops/mod.rs +++ b/core/engine/src/vm/opcode/unary_ops/mod.rs @@ -123,3 +123,32 @@ impl Operation for BitNot { const INSTRUCTION: &'static str = "INST - BitNot"; const COST: u8 = 3; } + +/// `ToInt32` implements the Opcode Operation for `Opcode::ToInt32` +/// +/// Operation: +/// - Unary bitwise `~` operator. +#[derive(Debug, Clone, Copy)] +pub(crate) struct ToInt32; + +impl ToInt32 { + #[inline(always)] + pub(super) fn operation( + (dst, src): (RegisterOperand, RegisterOperand), + context: &mut Context, + ) -> JsResult<()> { + let result = context + .vm + .get_register(src.into()) + .clone() + .to_i32(context)?; + context.vm.set_register(dst.into(), result.into()); + Ok(()) + } +} + +impl Operation for ToInt32 { + const NAME: &'static str = "ToInt32"; + const INSTRUCTION: &'static str = "INST - ToInt32"; + const COST: u8 = 1; +}