From a825377a6d2390e9f2098e72703cb12bb5cd2661 Mon Sep 17 00:00:00 2001 From: vrindisbacher Date: Tue, 19 May 2026 17:32:36 -0700 Subject: [PATCH 01/11] add initial IC stub & feedback --- src/js/runtime/bytecode/function.rs | 12 +++ src/js/runtime/bytecode/generator.rs | 62 +++++++++++++- src/js/runtime/bytecode/instruction.rs | 6 +- src/js/runtime/bytecode/operand.rs | 22 +++++ src/js/runtime/bytecode/stack_frame.rs | 43 ++++++++-- src/js/runtime/bytecode/vm.rs | 100 ++++++++++++++++++++++ src/js/runtime/gc/heap_item.rs | 3 + src/js/runtime/heap_item_descriptor.rs | 5 ++ src/js/runtime/ic/feedback.rs | 110 +++++++++++++++++++++++++ src/js/runtime/ic/mod.rs | 1 + src/js/runtime/mod.rs | 1 + 11 files changed, 355 insertions(+), 10 deletions(-) create mode 100644 src/js/runtime/ic/feedback.rs create mode 100644 src/js/runtime/ic/mod.rs diff --git a/src/js/runtime/bytecode/function.rs b/src/js/runtime/bytecode/function.rs index b8ec5b74..860bcaab 100644 --- a/src/js/runtime/bytecode/function.rs +++ b/src/js/runtime/bytecode/function.rs @@ -11,6 +11,7 @@ use crate::{ function::{set_function_length, set_function_name}, gc::{HeapItem, HeapVisitor}, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, + ic::feedback::FeedbackVector, intrinsics::{intrinsics::Intrinsic, rust_runtime::RuntimeFunctionId}, object_value::ObjectValue, ordinary_object::{ @@ -252,6 +253,8 @@ pub struct BytecodeFunction { /// This function may be a stub function back into the Rust runtime. If this is set then this /// function has an empty bytecode array and default values for many other fields. runtime_function_id: Option, + /// Feedback vector for IC stubs + feedback_vector: Option>, /// Inlined bytecode array for the function. bytecode: InlineArray, } @@ -276,6 +279,7 @@ impl BytecodeFunction { name: Option>, source_file: Handle, source_map: Handle, + feedback_vector: Option>, ) -> AllocResult> { let size = Self::calculate_size_in_bytes(bytecode.len()); let mut object = cx.alloc_uninit_with_size::(size)?; @@ -298,6 +302,7 @@ impl BytecodeFunction { set_uninit!(object.source_file, Some(*source_file)); set_uninit!(object.source_map, Some(*source_map)); set_uninit!(object.runtime_function_id, None); + set_uninit!(object.feedback_vector, feedback_vector.map(|v| *v)); object.bytecode.init_from_slice(&bytecode); Ok(object.to_handle()) @@ -339,6 +344,7 @@ impl BytecodeFunction { set_uninit!(object.name, name.map(|n| *n)); set_uninit!(object.source_file, None); set_uninit!(object.source_map, None); + set_uninit!(object.feedback_vector, None); set_uninit!(object.runtime_function_id, Some(runtime_func_id)); object.bytecode.init_from_slice(&[]); @@ -361,6 +367,11 @@ impl BytecodeFunction { self.constant_table } + #[inline] + pub fn feedback_vector_ptr(&self) -> Option> { + self.feedback_vector + } + #[inline] pub fn exception_handlers_ptr(&self) -> Option> { self.exception_handlers @@ -517,6 +528,7 @@ impl HeapItem for HeapPtr { visitor.visit_pointer(&mut self.descriptor); visitor.visit_pointer_opt(&mut self.constant_table); + visitor.visit_pointer_opt(&mut self.feedback_vector); visitor.visit_pointer_opt(&mut self.exception_handlers); visitor.visit_pointer(&mut self.realm); visitor.visit_pointer_opt(&mut self.name); diff --git a/src/js/runtime/bytecode/generator.rs b/src/js/runtime/bytecode/generator.rs index 0617837b..ea8815ba 100644 --- a/src/js/runtime/bytecode/generator.rs +++ b/src/js/runtime/bytecode/generator.rs @@ -34,6 +34,7 @@ use crate::{ bytecode::{ function::{dump_bytecode_function, BytecodeFunction}, instruction::DefinePropertyFlags, + operand::FeedbackSlotIndex, source_map::BytecodeSourceMap, }, class_names::{ClassNames, HomeObjectLocation, Method}, @@ -42,6 +43,7 @@ use crate::{ gc::Escapable, global_names::GlobalNames, heap_item_descriptor::HeapItemKind, + ic::feedback::{FeedbackSlot, FeedbackVector}, interned_strings::InternedStrings, module::{ import_attributes::ImportAttributes, @@ -1102,6 +1104,9 @@ pub struct BytecodeFunctionGenerator<'a> { /// Queue of functions that still need to be generated. pending_functions_queue: PendingFunctionNodes<'a>, + + /// The feedback slots to allocate for this function + feedback_slots: Vec, } impl<'a> BytecodeFunctionGenerator<'a> { @@ -1160,6 +1165,7 @@ impl<'a> BytecodeFunctionGenerator<'a> { register_allocator: TemporaryRegisterAllocator::new(num_local_registers), exception_handler_builder: ExceptionHandlersBuilder::new(), pending_functions_queue: vec![], + feedback_slots: vec![], } } @@ -1243,6 +1249,13 @@ impl<'a> BytecodeFunctionGenerator<'a> { )) } + fn add_feedback_index_slot(&mut self, slot_kind: FeedbackSlot) -> u32 { + let slot_offset = self.feedback_slots.len(); + self.feedback_slots.push(slot_kind); + debug_assert!(slot_offset <= (u32::MAX as usize)); + slot_offset as u32 + } + fn new_for_program( cx: Context, program: &ast::Program, @@ -1998,6 +2011,12 @@ impl<'a> BytecodeFunctionGenerator<'a> { let source_positions_object = BytecodeSourceMap::new(self.cx, &source_positions)?; + let feedback_vector = if self.feedback_slots.is_empty() { + None + } else { + Some(FeedbackVector::new(self.cx, &self.feedback_slots)?) + }; + let bytecode_function = BytecodeFunction::new( self.cx, bytecode, @@ -2017,6 +2036,7 @@ impl<'a> BytecodeFunctionGenerator<'a> { name, self.source_file, source_positions_object, + feedback_vector, )?; Ok(EmitFunctionResult { @@ -3337,7 +3357,17 @@ impl<'a> BytecodeFunctionGenerator<'a> { let dest = self.allocate_destination(dest)?; match expr.operator { - ast::BinaryOperator::Add => self.writer.add_instruction(dest, left, right, pos), + ast::BinaryOperator::Add => { + // Add feedback slot with add type uninitialized + let slot_offset = self.add_feedback_index_slot(FeedbackSlot::add_uninit()); + self.writer.add_instruction( + dest, + left, + right, + FeedbackSlotIndex::new(slot_offset), + pos, + ) + } ast::BinaryOperator::Subtract => self.writer.sub_instruction(dest, left, right, pos), ast::BinaryOperator::Multiply => self.writer.mul_instruction(dest, left, right, pos), ast::BinaryOperator::Divide => self.writer.div_instruction(dest, left, right, pos), @@ -4740,7 +4770,16 @@ impl<'a> BytecodeFunctionGenerator<'a> { let pos = expr.operator_pos; match operator { - ast::AssignmentOperator::Add => self.writer.add_instruction(dest, left, right, pos), + ast::AssignmentOperator::Add => { + let feedback_slot_offset = self.add_feedback_index_slot(FeedbackSlot::add_uninit()); + self.writer.add_instruction( + dest, + left, + right, + FeedbackSlotIndex::new(feedback_slot_offset), + pos, + ) + } ast::AssignmentOperator::Subtract => { self.writer.sub_instruction(dest, left, right, pos) } @@ -5918,7 +5957,15 @@ impl<'a> BytecodeFunctionGenerator<'a> { .to_string_instruction(temp, expression_reg, expression_pos); // Cannot throw since both values are guaranteed to be strings - self.writer.add_instruction(acc, acc, temp, NO_POS); + let feedback_slot_offset = + self.add_feedback_index_slot(FeedbackSlot::add_string_concat()); + self.writer.add_instruction( + acc, + acc, + temp, + FeedbackSlotIndex::new(feedback_slot_offset), + NO_POS, + ); self.register_allocator.release(temp); } @@ -5942,7 +5989,14 @@ impl<'a> BytecodeFunctionGenerator<'a> { self.writer.load_constant_instruction(temp, constant_index); // Cannot throw since both values are guaranteed to be strings - self.writer.add_instruction(acc, acc, temp, NO_POS); + let slot_offset = self.add_feedback_index_slot(FeedbackSlot::add_string_concat()); + self.writer.add_instruction( + acc, + acc, + temp, + FeedbackSlotIndex::new(slot_offset), + NO_POS, + ); } } diff --git a/src/js/runtime/bytecode/instruction.rs b/src/js/runtime/bytecode/instruction.rs index aa047db8..619e0e81 100644 --- a/src/js/runtime/bytecode/instruction.rs +++ b/src/js/runtime/bytecode/instruction.rs @@ -11,7 +11,10 @@ use super::{ writer::BytecodeWriter, }; -use crate::{count, replace_expr, runtime::debug_print::DebugPrinter}; +use crate::{ + count, replace_expr, + runtime::{bytecode::operand::FeedbackSlotIndex, debug_print::DebugPrinter}, +}; /// Generic properties of instructions. #[allow(dead_code)] @@ -566,6 +569,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] feedback_slot_offset: FeedbackSlotIndex, } } diff --git a/src/js/runtime/bytecode/operand.rs b/src/js/runtime/bytecode/operand.rs index 74c1a357..b41b4a58 100644 --- a/src/js/runtime/bytecode/operand.rs +++ b/src/js/runtime/bytecode/operand.rs @@ -123,11 +123,15 @@ operand_type!(SInt, SIGNED); // An index into the constant table operand_type!(ConstantIndex, UNSIGNED); +// An index into a feedback vector +operand_type!(FeedbackSlotIndex, UNSIGNED); + pub enum OperandType { Register, UInt, SInt, ConstantIndex, + FeedbackSlotIndex, } /// Registers may be either registers local to a function or arguments to that function. Registers @@ -311,12 +315,30 @@ impl ConstantIndex { } } +impl FeedbackSlotIndex { + #[inline] + pub fn new(value: W::UInt) -> Self { + Self::from_unsigned(value) + } + + #[inline] + pub fn value(&self) -> W::UInt { + self.unsigned() + } +} + impl fmt::Display for ConstantIndex { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "c{}", self.value()) } } +impl fmt::Display for FeedbackSlotIndex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "fb{}", self.value()) + } +} + /// Return the minimum width needed to fit the given signed value. pub fn min_width_for_signed(value: isize) -> WidthEnum { if (Narrow::SIGNED_MIN..=Narrow::SIGNED_MAX).contains(&value) { diff --git a/src/js/runtime/bytecode/stack_frame.rs b/src/js/runtime/bytecode/stack_frame.rs index d1cb55d3..08bf089b 100644 --- a/src/js/runtime/bytecode/stack_frame.rs +++ b/src/js/runtime/bytecode/stack_frame.rs @@ -1,4 +1,9 @@ -use crate::runtime::{gc::HeapVisitor, scope::Scope, HeapPtr, Value}; +use crate::runtime::{ + gc::HeapVisitor, + ic::feedback::{FeedbackSlot, FeedbackVector}, + scope::Scope, + HeapPtr, Value, +}; use super::{constant_table::ConstantTable, function::Closure}; @@ -20,6 +25,8 @@ use super::{constant_table::ConstantTable, function::Closure}; /// | closure | (closure of the caller) /// +40 +------------------+ /// | constant_table | (constant table of the called closure) +/// +40 +------------------+ +/// | feedback_vector | (feedback vector of the called closure) /// +32 +------------------+ /// | scope | (current VM scope) /// +24 +------------------+ @@ -187,6 +194,29 @@ impl StackFrame { unsafe { &mut *(self.fp.add(CONSTANT_TABLE_SLOT_INDEX) as *mut HeapPtr) } } + #[inline] + pub fn feedback_vector(&self) -> HeapPtr { + let ptr = unsafe { *self.fp.add(FEEDBACK_VECTOR_SLOT_INDEX) }; + HeapPtr::from_ptr(ptr as *mut FeedbackVector) + } + + #[inline] + pub fn feedback_vector_mut(&self) -> &mut HeapPtr { + unsafe { &mut *(self.fp.add(FEEDBACK_VECTOR_SLOT_INDEX) as *mut HeapPtr) } + } + + #[inline] + pub fn get_feedback(&self, slot: usize) -> FeedbackSlot { + *self.feedback_vector().slots().get_unchecked(slot) + } + + #[inline] + pub fn set_feedback(&mut self, slot: usize, value: FeedbackSlot) { + self.feedback_vector() + .slots_mut() + .set_unchecked(slot, value); + } + /// The callee function in this stack frame. #[inline] pub fn closure(&self) -> HeapPtr { @@ -273,6 +303,7 @@ impl StackFrame { visitor.visit_pointer(self.closure_mut()); visitor.visit_pointer(self.constant_table_mut()); + visitor.visit_pointer(self.feedback_vector_mut()); visitor.visit_pointer(self.scope_mut()); } } @@ -313,10 +344,12 @@ pub const SCOPE_SLOT_INDEX: usize = 3; const CONSTANT_TABLE_SLOT_INDEX: usize = 4; -pub const CLOSURE_SLOT_INDEX: usize = 5; +const FEEDBACK_VECTOR_SLOT_INDEX: usize = 5; + +pub const CLOSURE_SLOT_INDEX: usize = 6; -const ARGC_SLOT_INDEX: usize = 6; +const ARGC_SLOT_INDEX: usize = 7; -pub const RECEIVER_SLOT_INDEX: usize = 7; +pub const RECEIVER_SLOT_INDEX: usize = 8; -pub const FIRST_ARGUMENT_SLOT_INDEX: usize = 8; +pub const FIRST_ARGUMENT_SLOT_INDEX: usize = 9; diff --git a/src/js/runtime/bytecode/vm.rs b/src/js/runtime/bytecode/vm.rs index d9dfa262..066db551 100644 --- a/src/js/runtime/bytecode/vm.rs +++ b/src/js/runtime/bytecode/vm.rs @@ -41,6 +41,7 @@ use crate::{ generator_object::{GeneratorCompletionType, GeneratorObject, TGeneratorObject}, get, heap_item_descriptor::HeapItemKind, + ic::feedback::{AddFeedbackState, FeedbackSlot, FeedbackVector}, intrinsics::{ async_generator_prototype::AsyncGeneratorPrototype, generator_prototype::GeneratorPrototype, @@ -60,6 +61,7 @@ use crate::{ scope::Scope, scope_names::ScopeNames, source_file::SourceFile, + string_value::StringValue, to_string, type_utilities::{ is_callable, is_callable_object, is_loosely_equal, is_strictly_equal, @@ -220,6 +222,16 @@ impl VM { self.stack.as_ptr_range().end } + #[inline] + fn get_feedback(&self, slot_index: usize) -> FeedbackSlot { + self.stack_frame().get_feedback(slot_index) + } + + #[inline] + fn set_feedback(&mut self, slot_index: usize, slot: FeedbackSlot) { + self.stack_frame().set_feedback(slot_index, slot); + } + pub fn stack_trace_top(&self) -> Option { self.stack_trace_top } @@ -2045,6 +2057,14 @@ impl VM { // Push the function self.push(closure.as_ptr() as StackSlotValue); + // push the feedback vector + let feedback_vector = unsafe { + std::mem::transmute::>, usize>( + bytecode_function.feedback_vector_ptr(), + ) + }; + self.push(feedback_vector); + // Push the constant table let constant_table = unsafe { std::mem::transmute::>, usize>( @@ -2730,10 +2750,90 @@ impl VM { let left_value = self.read_register_to_handle(instr.left()); let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); + let slot_index = instr.feedback_slot_offset().value().to_usize(); + + // this should always be an addop - otherwise something has gone very wrong + let feedback_slot = self.get_feedback(slot_index); + debug_assert!(matches!(feedback_slot, FeedbackSlot::AddOp(_))); + + // try the fast path + // see if we should update feedback - this is only the case + // if we see that the feedback state is unitialized + let mut should_update_feedback = false; + + if let FeedbackSlot::AddOp(add_feedback_state) = self.get_feedback(slot_index) { + match add_feedback_state { + AddFeedbackState::Uninitialized => { + should_update_feedback = true; + } + AddFeedbackState::SmiSmi => { + if left_value.is_smi() && right_value.is_smi() { + let l = left_value.as_smi() as i64; + let r = right_value.as_smi() as i64; + let sum = l + r; + if sum >= i32::MIN as i64 && sum <= i32::MAX as i64 { + let result = self.cx.smi(sum as i32); + self.write_register(dest, *result); + return Ok(()); + } + // Overflow — widen feedback to Number, fall through to slow path + self.set_feedback( + slot_index, + FeedbackSlot::AddOp(AddFeedbackState::Number), + ); + } + } + AddFeedbackState::Number => { + if left_value.is_number() && right_value.is_number() { + let result = self + .cx + .number(left_value.as_number() + right_value.as_number()); + self.write_register(dest, *result); + return Ok(()); + } + } + AddFeedbackState::StringConcat => { + if left_value.is_string() && right_value.is_string() { + let left_string = left_value.as_string(); + let right_string = right_value.as_string(); + let result = + StringValue::concat(self.cx, left_string, right_string)?.as_value(); + self.write_register(dest, *result); + return Ok(()); + } + } + AddFeedbackState::BigInt => { + if left_value.is_bigint() && right_value.is_bigint() { + let result = + left_value.as_bigint().bigint() + right_value.as_bigint().bigint(); + let result: Handle = BigIntValue::new(self.cx, result)?.into(); + self.write_register(dest, *result); + return Ok(()); + } + } + AddFeedbackState::Any => {} + } + } + // slow path // May allocate let result = eval_add(self.cx(), left_value, right_value)?; + if should_update_feedback { + let new_state = if left_value.is_smi() && right_value.is_smi() && result.is_smi() { + AddFeedbackState::SmiSmi + } else if left_value.is_number() && right_value.is_number() { + AddFeedbackState::Number + } else if left_value.is_string() || right_value.is_string() { + AddFeedbackState::StringConcat + } else if left_value.is_bigint() && right_value.is_bigint() { + AddFeedbackState::BigInt + } else { + AddFeedbackState::Any + }; + self.set_feedback(slot_index, FeedbackSlot::AddOp(new_state)); + } + self.write_register(dest, *result); Ok(()) diff --git a/src/js/runtime/gc/heap_item.rs b/src/js/runtime/gc/heap_item.rs index c32614d3..bd1bf342 100644 --- a/src/js/runtime/gc/heap_item.rs +++ b/src/js/runtime/gc/heap_item.rs @@ -23,6 +23,7 @@ use crate::runtime::{ generator_object::GeneratorObject, global_names::GlobalNames, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, + ic::feedback::FeedbackVector, interned_strings::InternedStringsSetField, intrinsics::{ array_buffer_constructor::ArrayBufferObject, @@ -217,6 +218,7 @@ impl HeapPtr { } HeapItemKind::GlobalScopes => self.cast::().byte_size(), HeapItemKind::ValueVec => value_vec_byte_size(self.cast()), + HeapItemKind::FeedbackVector => self.cast::().byte_size(), HeapItemKind::Last => unreachable!("No objects are created with this descriptor"), } } @@ -380,6 +382,7 @@ impl HeapPtr { .visit_pointers(visitor), HeapItemKind::GlobalScopes => self.cast::().visit_pointers(visitor), HeapItemKind::ValueVec => value_vec_visit_pointers(self.cast_mut(), visitor), + HeapItemKind::FeedbackVector => self.cast::().visit_pointers(visitor), HeapItemKind::Last => unreachable!("No objects are created with this descriptor"), } } diff --git a/src/js/runtime/heap_item_descriptor.rs b/src/js/runtime/heap_item_descriptor.rs index 208148d8..fa32c4e3 100644 --- a/src/js/runtime/heap_item_descriptor.rs +++ b/src/js/runtime/heap_item_descriptor.rs @@ -159,6 +159,9 @@ pub enum HeapItemKind { // Vectors ValueVec, + // Feedback vectors for IC stubs + FeedbackVector, + // Numerical value is the number of kinds in the enum Last, } @@ -393,6 +396,8 @@ impl BaseDescriptors { other_heap_item_descriptor!(HeapItemKind::ValueVec); + other_heap_item_descriptor!(HeapItemKind::FeedbackVector); + Ok(base_descriptors) } diff --git a/src/js/runtime/ic/feedback.rs b/src/js/runtime/ic/feedback.rs new file mode 100644 index 00000000..b8ed9f7a --- /dev/null +++ b/src/js/runtime/ic/feedback.rs @@ -0,0 +1,110 @@ +use crate::{ + field_offset, + runtime::{ + alloc_error::AllocResult, + collections::InlineArray, + gc::{HeapItem, HeapVisitor}, + heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, + Context, Handle, HeapPtr, + }, + set_uninit, +}; + +#[repr(u8)] +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum AddFeedbackState { + /// No feedback collected yet. + Uninitialized = 0, + /// Both operands were smis, result was smi (no overflow). + SmiSmi = 1, + /// Both operands were numbers (smi or double), at least one was double. + Number = 2, + /// At least one operand was a string + StringConcat = 3, + /// Both operands were BigInts + BigInt = 4, + /// Mixed/incompatible types seen, or types changed across executions. + Any = 5, +} + +#[repr(u8)] +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum FeedbackSlot { + AddOp(AddFeedbackState), + Unknown, +} + +impl FeedbackSlot { + pub fn add_uninit() -> Self { + Self::AddOp(AddFeedbackState::Uninitialized) + } + + pub fn add_string_concat() -> Self { + Self::AddOp(AddFeedbackState::StringConcat) + } +} + +#[repr(C)] +pub struct FeedbackVector { + descriptor: HeapPtr, + /// Number of feedback slots + num_slots: u32, + /// Inline array of slot data. + /// Note: the layout of FeedbackSlot + /// needs to be very precise for this to + /// work, hence the repr(u8) + slots: InlineArray, +} + +impl FeedbackVector { + /// The offset of the `slots` field in a FeedbackVector + const SLOTS_BYTE_OFFSET: usize = field_offset!(FeedbackVector, slots); + + pub fn slots(&self) -> &InlineArray { + &self.slots + } + + pub fn slots_mut(&mut self) -> &mut InlineArray { + &mut self.slots + } + + /// Calculates the total size in bytes for a Feedback vector + /// Note that the slots InlineArray can be variable length (i.e., length `num_slots`) + /// The size is the byte offset of `slots` + the numbers of bytes needed for the array + /// of feedback slots + fn calculate_size_in_bytes(num_slots: usize) -> usize { + Self::SLOTS_BYTE_OFFSET + InlineArray::::calculate_size_in_bytes(num_slots) + } + + /// Create a new feedback vector with the passed feedback slots + pub fn new(cx: Context, initial_slots: &[FeedbackSlot]) -> AllocResult> { + // get the size of the the FeedbackVector + let num_slots = initial_slots.len(); + let size = Self::calculate_size_in_bytes(num_slots); + // allocate the FeedbackVector on the heap + let mut object = cx.alloc_uninit_with_size::(size)?; + + // set the object's descriptor + set_uninit!(object.descriptor, cx.base_descriptors.get(HeapItemKind::FeedbackVector)); + // set the number of slots + set_uninit!(object.num_slots, num_slots as u32); + + // Initialize the slots to the passed feedback slots + object.slots.init_from_slice(initial_slots); + + Ok(object.to_handle()) + } +} + +/// GC Integration for FeedbackVector +impl HeapItem for HeapPtr { + fn byte_size(&self) -> usize { + FeedbackVector::calculate_size_in_bytes(self.num_slots as usize) + } + + fn visit_pointers(&mut self, visitor: &mut impl HeapVisitor) { + // For now, only visit the descriptor, and we do not + // need to visit feedback slots as those have no pointers + visitor.visit_pointer(&mut self.descriptor); + } +} diff --git a/src/js/runtime/ic/mod.rs b/src/js/runtime/ic/mod.rs new file mode 100644 index 00000000..be280060 --- /dev/null +++ b/src/js/runtime/ic/mod.rs @@ -0,0 +1 @@ +pub mod feedback; diff --git a/src/js/runtime/mod.rs b/src/js/runtime/mod.rs index 1d11b2e5..ca998403 100644 --- a/src/js/runtime/mod.rs +++ b/src/js/runtime/mod.rs @@ -26,6 +26,7 @@ pub mod gc_object; mod generator_object; pub mod global_names; mod heap_item_descriptor; +mod ic; mod interned_strings; pub mod intrinsics; mod iterator; From 53577a3942a3922212faa601ca1ad717e657ed96 Mon Sep 17 00:00:00 2001 From: vrindisbacher Date: Tue, 19 May 2026 17:59:44 -0700 Subject: [PATCH 02/11] update all the snapshot tests for extra feedback slot index argument --- .../js_bytecode/arguments_object/binding.exp | 6 +- tests/js_bytecode/arguments_object/mapped.exp | 8 +- tests/js_bytecode/bytecode/assign_hazard.exp | 98 +++--- tests/js_bytecode/class/fields.exp | 166 +++++----- tests/js_bytecode/class/methods.exp | 54 ++-- tests/js_bytecode/class/private_member.exp | 8 +- .../js_bytecode/class/static_initializer.exp | 54 ++-- tests/js_bytecode/class/super_class.exp | 8 +- tests/js_bytecode/eval/completion.exp | 12 +- .../eval/dynamic_lookup_out_of_eval.exp | 4 +- tests/js_bytecode/eval/forces_dynamic.exp | 14 +- .../js_bytecode/eval/function_constructor.exp | 16 +- tests/js_bytecode/example_program/fib.exp | 4 +- .../js_bytecode/expression/arrow_function.exp | 18 +- tests/js_bytecode/expression/assign.exp | 294 +++++++++--------- tests/js_bytecode/expression/binary.exp | 50 +-- tests/js_bytecode/expression/calls/basic.exp | 6 +- tests/js_bytecode/expression/calls/member.exp | 44 +-- tests/js_bytecode/expression/conditional.exp | 62 ++-- tests/js_bytecode/expression/delete.exp | 14 +- tests/js_bytecode/expression/function.exp | 14 +- tests/js_bytecode/expression/logical.exp | 48 +-- tests/js_bytecode/expression/member.exp | 14 +- tests/js_bytecode/expression/new.exp | 6 +- tests/js_bytecode/expression/new_target.exp | 16 +- tests/js_bytecode/expression/object/basic.exp | 26 +- .../expression/object/named_evalution.exp | 14 +- tests/js_bytecode/expression/super_member.exp | 6 +- .../expression/tagged_template.exp | 50 +-- .../expression/template_literal.exp | 62 ++-- tests/js_bytecode/expression/this.exp | 12 +- tests/js_bytecode/function/async.exp | 40 +-- tests/js_bytecode/function/basic.exp | 4 +- tests/js_bytecode/function/generator.exp | 4 +- tests/js_bytecode/function/parameters.exp | 24 +- tests/js_bytecode/module/dynamic_import.exp | 20 +- .../module/export_default_expression.exp | 8 +- .../js_bytecode/module/exported_bindings.exp | 52 ++-- tests/js_bytecode/module/import_meta.exp | 6 +- .../module/import_named/import_named.exp | 38 +-- .../module/reexport_named/importing.exp | 10 +- .../module/reexport_star/importing.exp | 6 +- tests/js_bytecode/module/top_level_await.exp | 30 +- tests/js_bytecode/module/toplevel.exp | 22 +- tests/js_bytecode/scope/captured.exp | 116 +++---- tests/js_bytecode/scope/captured_this.exp | 20 +- tests/js_bytecode/scope/catch.exp | 16 +- tests/js_bytecode/scope/for.exp | 64 ++-- tests/js_bytecode/scope/for_break.exp | 34 +- tests/js_bytecode/scope/for_continue.exp | 34 +- tests/js_bytecode/scope/for_in.exp | 18 +- tests/js_bytecode/scope/for_in_break.exp | 34 +- tests/js_bytecode/scope/for_in_continue.exp | 34 +- tests/js_bytecode/scope/for_of.exp | 30 +- tests/js_bytecode/scope/for_of_break.exp | 20 +- tests/js_bytecode/scope/for_of_continue.exp | 20 +- tests/js_bytecode/scope/function.exp | 22 +- tests/js_bytecode/scope/function_body.exp | 12 +- tests/js_bytecode/scope/labeled_break.exp | 10 +- tests/js_bytecode/scope/switch.exp | 20 +- tests/js_bytecode/scope/with.exp | 38 +-- .../statement/const_let_declaration.exp | 48 +-- .../statement/lexical_declaration.exp | 10 +- tests/js_bytecode/statement/try/catch.exp | 10 +- .../statement/try/finally_break.exp | 10 +- .../statement/try/finally_continue.exp | 10 +- .../js_bytecode/statement/var_declaration.exp | 18 +- tests/js_bytecode/statement/with.exp | 22 +- 68 files changed, 1071 insertions(+), 1071 deletions(-) diff --git a/tests/js_bytecode/arguments_object/binding.exp b/tests/js_bytecode/arguments_object/binding.exp index bb684c74..8b54b1ba 100644 --- a/tests/js_bytecode/arguments_object/binding.exp +++ b/tests/js_bytecode/arguments_object/binding.exp @@ -17,9 +17,9 @@ Parameters: 0, Registers: 2 0: NewUnmappedArguments r0 2: LoadImmediate r1, 1 - 5: Add r1, r0, r1 - 9: LoadUndefined r1 - 11: Ret r1 + 5: Add r1, r0, r1, fb0 + 10: LoadUndefined r1 + 12: Ret r1 } [BytecodeFunction: capturedByArrow] { diff --git a/tests/js_bytecode/arguments_object/mapped.exp b/tests/js_bytecode/arguments_object/mapped.exp index ac34ef5f..73567f7a 100644 --- a/tests/js_bytecode/arguments_object/mapped.exp +++ b/tests/js_bytecode/arguments_object/mapped.exp @@ -77,8 +77,8 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 3, 0 4: LoadFromScope r1, 4, 0 - 8: Add r0, r0, r1 - 12: LoadFromScope r1, 2, 0 - 16: Add r0, r0, r1 - 20: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: LoadFromScope r1, 2, 0 + 17: Add r0, r0, r1, fb1 + 22: Ret r0 } diff --git a/tests/js_bytecode/bytecode/assign_hazard.exp b/tests/js_bytecode/bytecode/assign_hazard.exp index ba721789..985a455c 100644 --- a/tests/js_bytecode/bytecode/assign_hazard.exp +++ b/tests/js_bytecode/bytecode/assign_hazard.exp @@ -45,30 +45,30 @@ Parameters: 1, Registers: 1 0: Mov r0, a0 3: LoadImmediate a0, 2 - 6: Add r0, r0, a0 - 10: Ret r0 + 6: Add r0, r0, a0, fb0 + 11: Ret r0 } [BytecodeFunction: inOuterExpr] { Parameters: 1, Registers: 1 0: Mov r0, a0 3: LoadImmediate a0, 2 - 6: Add r0, r0, a0 - 10: JumpToBooleanFalse r0, 3 (.L0) + 6: Add r0, r0, a0, fb0 + 11: JumpToBooleanFalse r0, 3 (.L0) .L0: - 13: LoadUndefined r0 - 15: Ret r0 + 14: LoadUndefined r0 + 16: Ret r0 } [BytecodeFunction: inRegularParam] { Parameters: 2, Registers: 1 - 0: JumpNotUndefined a1, 13 (.L0) + 0: JumpNotUndefined a1, 14 (.L0) 3: Mov r0, a0 6: LoadImmediate a0, 2 - 9: Add a1, r0, a0 + 9: Add a1, r0, a0, fb0 .L0: - 13: LoadUndefined r0 - 15: Ret r0 + 14: LoadUndefined r0 + 16: Ret r0 } [BytecodeFunction: inRestParam] { @@ -76,24 +76,24 @@ 0: RestParameter r1 2: Mov r2, a0 5: LoadImmediate a0, 2 - 8: Add r2, r2, a0 - 12: GetProperty r0, r1, r2 - 16: LoadUndefined r1 - 18: Ret r1 + 8: Add r2, r2, a0, fb0 + 13: GetProperty r0, r1, r2 + 17: LoadUndefined r1 + 19: Ret r1 } [BytecodeFunction: inVarDeclarator] { Parameters: 1, Registers: 4 0: NewObject r1 2: GetNamedProperty r2, r1, c0 - 6: JumpNotUndefined r2, 13 (.L0) + 6: JumpNotUndefined r2, 14 (.L0) 9: Mov r3, a0 12: LoadImmediate a0, 2 - 15: Add r2, r3, a0 + 15: Add r2, r3, a0, fb0 .L0: - 19: Mov r0, r2 - 22: LoadUndefined r1 - 24: Ret r1 + 20: Mov r0, r2 + 23: LoadUndefined r1 + 25: Ret r1 Constant Table: 0: [String: x] } @@ -102,16 +102,16 @@ Parameters: 1, Registers: 4 0: Mov r1, 3: LoadImmediate r2, 1 - 6: Jump 22 (.L0) + 6: Jump 23 (.L0) 8: Mov , r1 11: Mov r3, a0 14: LoadImmediate a0, 2 - 17: Add r3, r3, a0 - 21: GetProperty r0, r2, r3 - 25: LoadImmediate r2, 3 + 17: Add r3, r3, a0, fb0 + 22: GetProperty r0, r2, r3 + 26: LoadImmediate r2, 3 .L0: - 28: LoadUndefined r1 - 30: Ret r1 + 29: LoadUndefined r1 + 31: Ret r1 Exception Handlers: 3-6 -> 8 (r2) } @@ -119,46 +119,46 @@ [BytecodeFunction: inForEachInit] { Parameters: 2, Registers: 3 0: NewObject r0 - 2: JumpNullish r0, 28 (.L1) + 2: JumpNullish r0, 29 (.L1) 5: NewForInIterator r0, r0 .L0: 8: ForInNext r1, r0 - 11: JumpNullish r1, 19 (.L1) + 11: JumpNullish r1, 20 (.L1) 14: Mov r2, a0 17: LoadImmediate a0, 2 - 20: Add r2, r2, a0 - 24: GetProperty a1, r1, r2 - 28: Jump -20 (.L0) + 20: Add r2, r2, a0, fb0 + 25: GetProperty a1, r1, r2 + 29: Jump -21 (.L0) .L1: - 30: LoadUndefined r0 - 32: Ret r0 + 31: LoadUndefined r0 + 33: Ret r0 } [BytecodeFunction: toplevelAssignExpressions] { Parameters: 2, Registers: 1 0: LoadImmediate r0, 1 - 3: Add a0, a0, r0 - 7: Mov r0, a0 - 10: LoadImmediate a0, 2 - 13: Add a1, r0, a0 - 17: LoadImmediate a0, 3 - 20: Mov a1, a0 - 23: LoadUndefined r0 - 25: Ret r0 + 3: Add a0, a0, r0, fb0 + 8: Mov r0, a0 + 11: LoadImmediate a0, 2 + 14: Add a1, r0, a0, fb1 + 19: LoadImmediate a0, 3 + 22: Mov a1, a0 + 25: LoadUndefined r0 + 27: Ret r0 } [BytecodeFunction: nestedFunctionOrClass] { Parameters: 2, Registers: 2 0: NewClosure r0, c0 - 3: Add a0, a1, r0 - 7: NewClosure r0, c1 - 10: Add a0, a1, r0 - 14: NewObject r0 - 16: NewClosure r1, c3 - 19: DefineNamedProperty r0, c2, r1 - 23: Add a0, a1, r0 - 27: LoadUndefined r0 - 29: Ret r0 + 3: Add a0, a1, r0, fb0 + 8: NewClosure r0, c1 + 11: Add a0, a1, r0, fb1 + 16: NewObject r0 + 18: NewClosure r1, c3 + 21: DefineNamedProperty r0, c2, r1 + 25: Add a0, a1, r0, fb2 + 30: LoadUndefined r0 + 32: Ret r0 Constant Table: 0: [BytecodeFunction: ] 1: [BytecodeFunction: ] diff --git a/tests/js_bytecode/class/fields.exp b/tests/js_bytecode/class/fields.exp index b0c7e421..23b6eb0d 100644 --- a/tests/js_bytecode/class/fields.exp +++ b/tests/js_bytecode/class/fields.exp @@ -119,20 +119,20 @@ 2: LoadEmpty r1 4: LoadImmediate r2, 1 7: LoadImmediate r3, 2 - 10: Add r2, r2, r3 - 14: ToPropertyKey r2, r2 - 17: StoreToScope r2, 0, 0 - 21: LoadImmediate r2, 3 - 24: LoadImmediate r3, 4 - 27: Add r2, r2, r3 - 31: ToPropertyKey r2, r2 - 34: StoreToScope r2, 1, 0 - 38: NewClass r0, c2, c1, r1, r0 - 44: NewClosure r2, c3 - 47: CallWithReceiver r2, r2, r0, r2, 0 - 53: PopScope - 54: LoadUndefined r1 - 56: Ret r1 + 10: Add r2, r2, r3, fb0 + 15: ToPropertyKey r2, r2 + 18: StoreToScope r2, 0, 0 + 22: LoadImmediate r2, 3 + 25: LoadImmediate r3, 4 + 28: Add r2, r2, r3, fb1 + 33: ToPropertyKey r2, r2 + 36: StoreToScope r2, 1, 0 + 40: NewClass r0, c2, c1, r1, r0 + 46: NewClosure r2, c3 + 49: CallWithReceiver r2, r2, r0, r2, 0 + 55: PopScope + 56: LoadUndefined r1 + 58: Ret r1 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: C] @@ -229,20 +229,20 @@ 14: StoreToScope r2, 5, 0 18: LoadImmediate r2, 1 21: LoadImmediate r3, 2 - 24: Add r2, r2, r3 - 28: ToPropertyKey r2, r2 - 31: StoreToScope r2, 0, 0 - 35: LoadImmediate r2, 3 - 38: LoadImmediate r3, 4 - 41: Add r2, r2, r3 - 45: ToPropertyKey r2, r2 - 48: StoreToScope r2, 1, 0 - 52: NewClass r0, c4, c3, r1, r0 - 58: NewClosure r2, c5 - 61: CallWithReceiver r2, r2, r0, r2, 0 - 67: PopScope - 68: LoadUndefined r1 - 70: Ret r1 + 24: Add r2, r2, r3, fb0 + 29: ToPropertyKey r2, r2 + 32: StoreToScope r2, 0, 0 + 36: LoadImmediate r2, 3 + 39: LoadImmediate r3, 4 + 42: Add r2, r2, r3, fb1 + 47: ToPropertyKey r2, r2 + 50: StoreToScope r2, 1, 0 + 54: NewClass r0, c4, c3, r1, r0 + 60: NewClosure r2, c5 + 63: CallWithReceiver r2, r2, r0, r2, 0 + 69: PopScope + 70: LoadUndefined r1 + 72: Ret r1 Constant Table: 0: [ScopeNames] 1: [String: private1] @@ -300,13 +300,13 @@ 2: LoadEmpty r1 4: LoadImmediate r2, 1 7: LoadImmediate r3, 2 - 10: Add r2, r2, r3 - 14: ToPropertyKey r2, r2 - 17: StoreToScope r2, 0, 0 - 21: NewClass r0, c2, c1, r1, r0 - 27: PopScope - 28: LoadUndefined r1 - 30: Ret r1 + 10: Add r2, r2, r3, fb0 + 15: ToPropertyKey r2, r2 + 18: StoreToScope r2, 0, 0 + 22: NewClass r0, c2, c1, r1, r0 + 28: PopScope + 29: LoadUndefined r1 + 31: Ret r1 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: C] @@ -432,20 +432,20 @@ 18: NewClosure r2, c3 21: LoadImmediate r3, 1 24: LoadImmediate r4, 2 - 27: Add r3, r3, r4 - 31: ToPropertyKey r3, r3 - 34: StoreToScope r3, 0, 0 - 38: LoadImmediate r3, 3 - 41: LoadImmediate r4, 4 - 44: Add r3, r3, r4 - 48: ToPropertyKey r3, r3 - 51: NewClosure r4, c4 - 54: NewClosure r5, c5 - 57: StoreToScope r5, 1, 0 - 61: NewClass r0, c7, c6, r1, r2 - 67: PopScope - 68: LoadUndefined r1 - 70: Ret r1 + 27: Add r3, r3, r4, fb0 + 32: ToPropertyKey r3, r3 + 35: StoreToScope r3, 0, 0 + 39: LoadImmediate r3, 3 + 42: LoadImmediate r4, 4 + 45: Add r3, r3, r4, fb1 + 50: ToPropertyKey r3, r3 + 53: NewClosure r4, c4 + 56: NewClosure r5, c5 + 59: StoreToScope r5, 1, 0 + 63: NewClass r0, c7, c6, r1, r2 + 69: PopScope + 70: LoadUndefined r1 + 72: Ret r1 Constant Table: 0: [ScopeNames] 1: [String: private1] @@ -514,17 +514,17 @@ 13: StoreToScope r2, 3, 0 17: LoadImmediate r2, 1 20: LoadImmediate r3, 2 - 23: Add r2, r2, r3 - 27: ToPropertyKey r2, r2 - 30: StoreToScope r2, 0, 0 - 34: NewClosure r2, c2 - 37: StoreToScope r2, 1, 0 - 41: NewClosure r2, c3 - 44: NewClass r0, c5, c4, r1, r2 - 50: StoreToScope r0, 2, 0 - 54: PopScope - 55: LoadUndefined r1 - 57: Ret r1 + 23: Add r2, r2, r3, fb0 + 28: ToPropertyKey r2, r2 + 31: StoreToScope r2, 0, 0 + 35: NewClosure r2, c2 + 38: StoreToScope r2, 1, 0 + 42: NewClosure r2, c3 + 45: NewClass r0, c5, c4, r1, r2 + 51: StoreToScope r0, 2, 0 + 55: PopScope + 56: LoadUndefined r1 + 58: Ret r1 Constant Table: 0: [ScopeNames] 1: [String: private1] @@ -579,15 +579,15 @@ 7: StoreToScope r2, 2, 0 11: LoadImmediate r2, 1 14: LoadImmediate r3, 2 - 17: Add r2, r2, r3 - 21: ToPropertyKey r2, r2 - 24: StoreToScope r2, 0, 0 - 28: NewClass r0, c3, c2, r1, r0 - 34: NewClosure r2, c4 - 37: CallWithReceiver r2, r2, r0, r2, 0 - 43: PopScope - 44: LoadUndefined r1 - 46: Ret r1 + 17: Add r2, r2, r3, fb0 + 22: ToPropertyKey r2, r2 + 25: StoreToScope r2, 0, 0 + 29: NewClass r0, c3, c2, r1, r0 + 35: NewClosure r2, c4 + 38: CallWithReceiver r2, r2, r0, r2, 0 + 44: PopScope + 45: LoadUndefined r1 + 47: Ret r1 Constant Table: 0: [ScopeNames] 1: [String: private] @@ -626,20 +626,20 @@ 14: StoreToScope r2, 5, 0 18: LoadImmediate r2, 1 21: LoadImmediate r3, 2 - 24: Add r2, r2, r3 - 28: ToPropertyKey r2, r2 - 31: StoreToScope r2, 0, 0 - 35: LoadImmediate r2, 3 - 38: LoadImmediate r3, 4 - 41: Add r2, r2, r3 - 45: ToPropertyKey r2, r2 - 48: StoreToScope r2, 1, 0 - 52: NewClass r0, c4, c3, r1, r0 - 58: NewClosure r2, c5 - 61: CallWithReceiver r2, r2, r0, r2, 0 - 67: PopScope - 68: LoadUndefined r1 - 70: Ret r1 + 24: Add r2, r2, r3, fb0 + 29: ToPropertyKey r2, r2 + 32: StoreToScope r2, 0, 0 + 36: LoadImmediate r2, 3 + 39: LoadImmediate r3, 4 + 42: Add r2, r2, r3, fb1 + 47: ToPropertyKey r2, r2 + 50: StoreToScope r2, 1, 0 + 54: NewClass r0, c4, c3, r1, r0 + 60: NewClosure r2, c5 + 63: CallWithReceiver r2, r2, r0, r2, 0 + 69: PopScope + 70: LoadUndefined r1 + 72: Ret r1 Constant Table: 0: [ScopeNames] 1: [String: private1] diff --git a/tests/js_bytecode/class/methods.exp b/tests/js_bytecode/class/methods.exp index 1341994c..0aa7be71 100644 --- a/tests/js_bytecode/class/methods.exp +++ b/tests/js_bytecode/class/methods.exp @@ -11,33 +11,33 @@ 23: NewClosure r7, c4 26: LoadImmediate r8, 1 29: LoadImmediate r9, 2 - 32: Add r8, r8, r9 - 36: ToPropertyKey r8, r8 - 39: NewClosure r9, c5 - 42: NewClosure r10, c6 - 45: NewClosure r11, c7 - 48: LoadImmediate r12, 3 - 51: LoadImmediate r13, 4 - 54: Add r12, r12, r13 - 58: ToPropertyKey r12, r12 - 61: NewClosure r13, c8 - 64: LoadImmediate r14, 5 - 67: LoadImmediate r15, 6 - 70: Add r14, r14, r15 - 74: ToPropertyKey r14, r14 - 77: NewClosure r15, c9 - 80: NewClosure r16, c10 - 83: NewClosure r17, c11 - 86: NewClosure r18, c12 - 89: LoadImmediate r19, 1 - 92: LoadImmediate r20, 2 - 95: Add r19, r19, r20 - 99: ToPropertyKey r19, r19 - 102: NewClosure r20, c13 - 105: NewClass r0, c15, c14, r1, r2 - 111: StoreToScope r0, 1, 0 - 115: LoadUndefined r0 - 117: Ret r0 + 32: Add r8, r8, r9, fb0 + 37: ToPropertyKey r8, r8 + 40: NewClosure r9, c5 + 43: NewClosure r10, c6 + 46: NewClosure r11, c7 + 49: LoadImmediate r12, 3 + 52: LoadImmediate r13, 4 + 55: Add r12, r12, r13, fb1 + 60: ToPropertyKey r12, r12 + 63: NewClosure r13, c8 + 66: LoadImmediate r14, 5 + 69: LoadImmediate r15, 6 + 72: Add r14, r14, r15, fb2 + 77: ToPropertyKey r14, r14 + 80: NewClosure r15, c9 + 83: NewClosure r16, c10 + 86: NewClosure r17, c11 + 89: NewClosure r18, c12 + 92: LoadImmediate r19, 1 + 95: LoadImmediate r20, 2 + 98: Add r19, r19, r20, fb3 + 103: ToPropertyKey r19, r19 + 106: NewClosure r20, c13 + 109: NewClass r0, c15, c14, r1, r2 + 115: StoreToScope r0, 1, 0 + 119: LoadUndefined r0 + 121: Ret r0 Constant Table: 0: [BytecodeFunction: named1] 1: [BytecodeFunction: named2] diff --git a/tests/js_bytecode/class/private_member.exp b/tests/js_bytecode/class/private_member.exp index 18a19c34..1bcebc9f 100644 --- a/tests/js_bytecode/class/private_member.exp +++ b/tests/js_bytecode/class/private_member.exp @@ -114,10 +114,10 @@ Parameters: 1, Registers: 2 0: LoadFromScope r1, 1, 0 4: GetPrivateProperty r0, , r1 - 8: Add r0, r0, a0 - 12: SetPrivateProperty , r1, r0 - 16: LoadUndefined r0 - 18: Ret r0 + 8: Add r0, r0, a0, fb0 + 13: SetPrivateProperty , r1, r0 + 17: LoadUndefined r0 + 19: Ret r0 } [BytecodeFunction: privateUpdate] { diff --git a/tests/js_bytecode/class/static_initializer.exp b/tests/js_bytecode/class/static_initializer.exp index 7aa4c0d1..b17b5b56 100644 --- a/tests/js_bytecode/class/static_initializer.exp +++ b/tests/js_bytecode/class/static_initializer.exp @@ -76,12 +76,12 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1 - 10: LoadImmediate r0, 3 - 13: LoadImmediate r1, 4 - 16: Add r0, r0, r1 - 20: LoadUndefined r0 - 22: Ret r0 + 6: Add r0, r0, r1, fb0 + 11: LoadImmediate r0, 3 + 14: LoadImmediate r1, 4 + 17: Add r0, r0, r1, fb1 + 22: LoadUndefined r0 + 24: Ret r0 } [BytecodeFunction: StaticInitializerAfterCreateClass] { @@ -94,9 +94,9 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1 - 10: LoadUndefined r0 - 12: Ret r0 + 6: Add r0, r0, r1, fb0 + 11: LoadUndefined r0 + 13: Ret r0 } [BytecodeFunction: method1] { @@ -115,15 +115,15 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1 - 10: LoadImmediate r0, 3 - 13: LoadImmediate r1, 4 - 16: Add r0, r0, r1 - 20: LoadImmediate r0, 5 - 23: LoadImmediate r1, 6 - 26: Add r0, r0, r1 - 30: LoadUndefined r0 - 32: Ret r0 + 6: Add r0, r0, r1, fb0 + 11: LoadImmediate r0, 3 + 14: LoadImmediate r1, 4 + 17: Add r0, r0, r1, fb1 + 22: LoadImmediate r0, 5 + 25: LoadImmediate r1, 6 + 28: Add r0, r0, r1, fb2 + 33: LoadUndefined r0 + 35: Ret r0 } [BytecodeFunction: EvalInStaticInitializer] { @@ -177,15 +177,15 @@ [BytecodeFunction: staticInitializer] { Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 - 3: Add r1, , r1 - 7: LoadImmediate r1, 2 - 10: Add r1, r0, r1 - 14: LoadFromScope r1, 1, 0 - 18: GetNamedSuperProperty r1, r1, , c0 - 23: LoadImmediate r2, 3 - 26: Add r1, r1, r2 - 30: LoadUndefined r1 - 32: Ret r1 + 3: Add r1, , r1, fb0 + 8: LoadImmediate r1, 2 + 11: Add r1, r0, r1, fb1 + 16: LoadFromScope r1, 1, 0 + 20: GetNamedSuperProperty r1, r1, , c0 + 25: LoadImmediate r2, 3 + 28: Add r1, r1, r2, fb2 + 33: LoadUndefined r1 + 35: Ret r1 Constant Table: 0: [String: foo] } diff --git a/tests/js_bytecode/class/super_class.exp b/tests/js_bytecode/class/super_class.exp index 40123514..1cdcb06e 100644 --- a/tests/js_bytecode/class/super_class.exp +++ b/tests/js_bytecode/class/super_class.exp @@ -13,10 +13,10 @@ Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 3: LoadImmediate r2, 2 - 6: Add r1, r1, r2 - 10: NewClass r0, c1, c0, r1, r0 - 16: LoadUndefined r1 - 18: Ret r1 + 6: Add r1, r1, r2, fb0 + 11: NewClass r0, c1, c0, r1, r0 + 17: LoadUndefined r1 + 19: Ret r1 Constant Table: 0: [BytecodeFunction: C] 1: [ClassNames] diff --git a/tests/js_bytecode/eval/completion.exp b/tests/js_bytecode/eval/completion.exp index 3827afaf..2ea26371 100644 --- a/tests/js_bytecode/eval/completion.exp +++ b/tests/js_bytecode/eval/completion.exp @@ -117,12 +117,12 @@ 0: LoadConstant r0, c0 3: LoadImmediate r1, 1 6: LoadImmediate r2, 2 - 9: Add r0, r1, r2 - 13: LoadDynamic r1, c1 - 16: LoadDynamic r2, c2 - 19: Add r0, r1, r2 - 23: LoadConstant r0, c3 - 26: Ret r0 + 9: Add r0, r1, r2, fb0 + 14: LoadDynamic r1, c1 + 17: LoadDynamic r2, c2 + 20: Add r0, r1, r2, fb1 + 25: LoadConstant r0, c3 + 28: Ret r0 Constant Table: 0: [String: expression statement completions] 1: [String: a] diff --git a/tests/js_bytecode/eval/dynamic_lookup_out_of_eval.exp b/tests/js_bytecode/eval/dynamic_lookup_out_of_eval.exp index 828b3dd7..a9afae92 100644 --- a/tests/js_bytecode/eval/dynamic_lookup_out_of_eval.exp +++ b/tests/js_bytecode/eval/dynamic_lookup_out_of_eval.exp @@ -114,8 +114,8 @@ Parameters: 0, Registers: 3 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r2, r0, r1 - 10: Ret r2 + 6: Add r2, r0, r1, fb0 + 11: Ret r2 } [BytecodeFunction: ] { diff --git a/tests/js_bytecode/eval/forces_dynamic.exp b/tests/js_bytecode/eval/forces_dynamic.exp index 5e520724..f0b67378 100644 --- a/tests/js_bytecode/eval/forces_dynamic.exp +++ b/tests/js_bytecode/eval/forces_dynamic.exp @@ -77,13 +77,13 @@ 115: CheckTdz r0, c2 118: LoadDynamic r0, c5 121: LoadImmediate r1, 5 - 124: Add r0, r0, r1 - 128: LoadDynamic r0, c4 - 131: LoadDynamic r0, c5 - 134: LoadImmediate r1, 6 - 137: Add r0, r0, r1 - 141: LoadUndefined r0 - 143: Ret r0 + 124: Add r0, r0, r1, fb0 + 129: LoadDynamic r0, c4 + 132: LoadDynamic r0, c5 + 135: LoadImmediate r1, 6 + 138: Add r0, r0, r1, fb1 + 143: LoadUndefined r0 + 145: Ret r0 Constant Table: 0: [ScopeNames] 1: [ScopeNames] diff --git a/tests/js_bytecode/eval/function_constructor.exp b/tests/js_bytecode/eval/function_constructor.exp index 0fe4aa4c..f6fec5b6 100644 --- a/tests/js_bytecode/eval/function_constructor.exp +++ b/tests/js_bytecode/eval/function_constructor.exp @@ -35,20 +35,20 @@ Parameters: 0, Registers: 2 0: LoadGlobal r0, c0 3: LoadImmediate r1, 1 - 6: Add r0, r0, r1 - 10: LoadUndefined r0 - 12: Ret r0 + 6: Add r0, r0, r1, fb0 + 11: LoadUndefined r0 + 13: Ret r0 Constant Table: 0: [String: y] } [BytecodeFunction: anonymous] { Parameters: 2, Registers: 2 - 0: Add r0, a0, a1 - 4: LoadGlobal r1, c0 - 7: Add r0, r0, r1 - 11: LoadUndefined r0 - 13: Ret r0 + 0: Add r0, a0, a1, fb0 + 5: LoadGlobal r1, c0 + 8: Add r0, r0, r1, fb1 + 13: LoadUndefined r0 + 15: Ret r0 Constant Table: 0: [String: z] } diff --git a/tests/js_bytecode/example_program/fib.exp b/tests/js_bytecode/example_program/fib.exp index 8d7a9f46..68bce83a 100644 --- a/tests/js_bytecode/example_program/fib.exp +++ b/tests/js_bytecode/example_program/fib.exp @@ -28,8 +28,8 @@ 33: LoadImmediate r2, 2 36: Sub r2, a0, r2 40: Call r1, r1, r2, 1 - 45: Add r0, r0, r1 - 49: Ret r0 + 45: Add r0, r0, r1, fb0 + 50: Ret r0 Constant Table: 0: [String: fib] } diff --git a/tests/js_bytecode/expression/arrow_function.exp b/tests/js_bytecode/expression/arrow_function.exp index ff4b5d75..78fa3da9 100644 --- a/tests/js_bytecode/expression/arrow_function.exp +++ b/tests/js_bytecode/expression/arrow_function.exp @@ -17,13 +17,13 @@ Parameters: 0, Registers: 3 0: NewClosure r1, c0 3: LoadImmediate r2, 2 - 6: Add r1, r1, r2 - 10: NewClosure r1, c1 - 13: LoadImmediate r2, 4 - 16: Add r1, r1, r2 - 20: NewClosure r0, c2 - 23: LoadUndefined r1 - 25: Ret r1 + 6: Add r1, r1, r2, fb0 + 11: NewClosure r1, c1 + 14: LoadImmediate r2, 4 + 17: Add r1, r1, r2, fb1 + 22: NewClosure r0, c2 + 25: LoadUndefined r1 + 27: Ret r1 Constant Table: 0: [BytecodeFunction: ] 1: [BytecodeFunction: ] @@ -40,8 +40,8 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 9 3: LoadImmediate r1, 3 - 6: Add r1, r0, r1 - 10: Ret r1 + 6: Add r1, r0, r1, fb0 + 11: Ret r1 } [BytecodeFunction: x] { diff --git a/tests/js_bytecode/expression/assign.exp b/tests/js_bytecode/expression/assign.exp index d79ba87a..39edb2d1 100644 --- a/tests/js_bytecode/expression/assign.exp +++ b/tests/js_bytecode/expression/assign.exp @@ -270,9 +270,9 @@ 9: NewClosure r1, c3 12: SetNamedProperty r0, c2, r1 16: NewClosure r1, c4 - 19: Add r0, r0, r1 - 23: LoadUndefined r1 - 25: Ret r1 + 19: Add r0, r0, r1, fb0 + 24: LoadUndefined r1 + 26: Ret r1 Constant Table: 0: [BytecodeFunction: x] 1: [BytecodeFunction: ] @@ -309,50 +309,50 @@ Parameters: 1, Registers: 3 0: LoadImmediate r0, 2 3: LoadImmediate r1, 3 - 6: Add a0, a0, r1 - 10: LoadImmediate r1, 4 - 13: Add r0, r0, r1 - 17: LoadGlobal r1, c0 - 20: LoadImmediate r2, 5 - 23: Add r1, r1, r2 - 27: StoreGlobal r1, c0 - 30: LoadUndefined r1 - 32: Ret r1 + 6: Add a0, a0, r1, fb0 + 11: LoadImmediate r1, 4 + 14: Add r0, r0, r1, fb1 + 19: LoadGlobal r1, c0 + 22: LoadImmediate r2, 5 + 25: Add r1, r1, r2, fb2 + 30: StoreGlobal r1, c0 + 33: LoadUndefined r1 + 35: Ret r1 Constant Table: 0: [String: global] } [BytecodeFunction: operatorIdAssignReturnValue] { Parameters: 1, Registers: 5 - 0: LoadImmediate r0, 2 - 3: LoadGlobal r1, c0 - 6: Mov r2, a0 - 9: LoadImmediate r3, 3 - 12: Add a0, r2, r3 - 16: Mov r2, a0 - 19: Call r1, r1, r2, 1 - 24: LoadGlobal r1, c0 - 27: Mov r2, r0 - 30: LoadImmediate r3, 4 - 33: Add r0, r2, r3 - 37: Mov r2, r0 - 40: Call r1, r1, r2, 1 - 45: LoadGlobal r1, c0 - 48: LoadGlobal r2, c1 - 51: LoadImmediate r3, 5 - 54: Add r2, r2, r3 - 58: StoreGlobal r2, c1 - 61: Call r1, r1, r2, 1 - 66: Mov r1, r0 - 69: Mov r2, a0 - 72: LoadGlobal r3, c1 - 75: LoadImmediate r4, 6 - 78: Add r3, r3, r4 - 82: StoreGlobal r3, c1 - 85: Add a0, r2, r3 - 89: Add r0, r1, a0 - 93: LoadUndefined r1 - 95: Ret r1 + 0: LoadImmediate r0, 2 + 3: LoadGlobal r1, c0 + 6: Mov r2, a0 + 9: LoadImmediate r3, 3 + 12: Add a0, r2, r3, fb0 + 17: Mov r2, a0 + 20: Call r1, r1, r2, 1 + 25: LoadGlobal r1, c0 + 28: Mov r2, r0 + 31: LoadImmediate r3, 4 + 34: Add r0, r2, r3, fb1 + 39: Mov r2, r0 + 42: Call r1, r1, r2, 1 + 47: LoadGlobal r1, c0 + 50: LoadGlobal r2, c1 + 53: LoadImmediate r3, 5 + 56: Add r2, r2, r3, fb2 + 61: StoreGlobal r2, c1 + 64: Call r1, r1, r2, 1 + 69: Mov r1, r0 + 72: Mov r2, a0 + 75: LoadGlobal r3, c1 + 78: LoadImmediate r4, 6 + 81: Add r3, r3, r4, fb3 + 86: StoreGlobal r3, c1 + 89: Add a0, r2, r3, fb4 + 94: Add r0, r1, a0, fb5 + 99: LoadUndefined r1 + 101: Ret r1 Constant Table: 0: [String: use] 1: [String: global] @@ -381,70 +381,70 @@ [BytecodeFunction: operatorIdAllOperators] { Parameters: 1, Registers: 1 0: LoadImmediate r0, 1 - 3: Add a0, a0, r0 - 7: LoadImmediate r0, 2 - 10: Sub a0, a0, r0 - 14: LoadImmediate r0, 3 - 17: Mul a0, a0, r0 - 21: LoadImmediate r0, 4 - 24: Div a0, a0, r0 - 28: LoadImmediate r0, 5 - 31: Rem a0, a0, r0 - 35: LoadImmediate r0, 6 - 38: Exp a0, a0, r0 - 42: LoadImmediate r0, 7 - 45: BitAnd a0, a0, r0 - 49: LoadImmediate r0, 8 - 52: BitOr a0, a0, r0 - 56: LoadImmediate r0, 9 - 59: BitXor a0, a0, r0 - 63: LoadImmediate r0, 10 - 66: ShiftLeft a0, a0, r0 - 70: LoadImmediate r0, 11 - 73: ShiftRightArithmetic a0, a0, r0 - 77: LoadImmediate r0, 12 - 80: ShiftRightLogical a0, a0, r0 - 84: LoadUndefined r0 - 86: Ret r0 + 3: Add a0, a0, r0, fb0 + 8: LoadImmediate r0, 2 + 11: Sub a0, a0, r0 + 15: LoadImmediate r0, 3 + 18: Mul a0, a0, r0 + 22: LoadImmediate r0, 4 + 25: Div a0, a0, r0 + 29: LoadImmediate r0, 5 + 32: Rem a0, a0, r0 + 36: LoadImmediate r0, 6 + 39: Exp a0, a0, r0 + 43: LoadImmediate r0, 7 + 46: BitAnd a0, a0, r0 + 50: LoadImmediate r0, 8 + 53: BitOr a0, a0, r0 + 57: LoadImmediate r0, 9 + 60: BitXor a0, a0, r0 + 64: LoadImmediate r0, 10 + 67: ShiftLeft a0, a0, r0 + 71: LoadImmediate r0, 11 + 74: ShiftRightArithmetic a0, a0, r0 + 78: LoadImmediate r0, 12 + 81: ShiftRightLogical a0, a0, r0 + 85: LoadUndefined r0 + 87: Ret r0 } [BytecodeFunction: operatorMemberAssign] { Parameters: 2, Registers: 5 0: GetNamedProperty r0, a0, c0 4: LoadImmediate r1, 1 - 7: Add r0, r0, r1 - 11: SetNamedProperty a0, c0, r0 - 15: LoadGlobal r0, c1 - 18: Mov r2, a0 - 21: GetNamedProperty r1, r2, c0 - 25: LoadImmediate r3, 2 - 28: Add r1, r1, r3 - 32: SetNamedProperty r2, c0, r1 - 36: Call r0, r0, r1, 1 - 41: Mov r1, a0 - 44: GetNamedProperty r0, r1, c0 - 48: Mov r3, a0 - 51: GetNamedProperty r2, r3, c2 - 55: LoadImmediate r4, 3 - 58: Add r2, r2, r4 - 62: SetNamedProperty r3, c2, r2 - 66: Add r0, r0, r2 - 70: SetNamedProperty r1, c0, r0 - 74: LoadGlobal r0, c1 - 77: Mov r2, a0 - 80: GetNamedProperty r1, r2, c0 - 84: Mov r3, a0 - 87: Add r1, r1, r3 - 91: SetNamedProperty r2, c0, r1 - 95: Call r0, r0, r1, 1 - 100: Mov r1, a0 - 103: GetNamedProperty r0, r1, c0 - 107: LoadImmediate r2, 4 - 110: Add r0, r0, r2 - 114: SetNamedProperty r1, c0, r0 - 118: Mov a1, r0 - 121: LoadUndefined r0 - 123: Ret r0 + 7: Add r0, r0, r1, fb0 + 12: SetNamedProperty a0, c0, r0 + 16: LoadGlobal r0, c1 + 19: Mov r2, a0 + 22: GetNamedProperty r1, r2, c0 + 26: LoadImmediate r3, 2 + 29: Add r1, r1, r3, fb1 + 34: SetNamedProperty r2, c0, r1 + 38: Call r0, r0, r1, 1 + 43: Mov r1, a0 + 46: GetNamedProperty r0, r1, c0 + 50: Mov r3, a0 + 53: GetNamedProperty r2, r3, c2 + 57: LoadImmediate r4, 3 + 60: Add r2, r2, r4, fb2 + 65: SetNamedProperty r3, c2, r2 + 69: Add r0, r0, r2, fb3 + 74: SetNamedProperty r1, c0, r0 + 78: LoadGlobal r0, c1 + 81: Mov r2, a0 + 84: GetNamedProperty r1, r2, c0 + 88: Mov r3, a0 + 91: Add r1, r1, r3, fb4 + 96: SetNamedProperty r2, c0, r1 + 100: Call r0, r0, r1, 1 + 105: Mov r1, a0 + 108: GetNamedProperty r0, r1, c0 + 112: LoadImmediate r2, 4 + 115: Add r0, r0, r2, fb5 + 120: SetNamedProperty r1, c0, r0 + 124: Mov a1, r0 + 127: LoadUndefined r0 + 129: Ret r0 Constant Table: 0: [String: foo] 1: [String: use] @@ -455,54 +455,54 @@ Parameters: 1, Registers: 2 0: GetNamedProperty r0, a0, c0 4: LoadImmediate r1, 1 - 7: Add r0, r0, r1 - 11: SetNamedProperty a0, c0, r0 - 15: GetNamedProperty r0, a0, c0 - 19: LoadImmediate r1, 2 - 22: Sub r0, r0, r1 - 26: SetNamedProperty a0, c0, r0 - 30: GetNamedProperty r0, a0, c0 - 34: LoadImmediate r1, 3 - 37: Mul r0, r0, r1 - 41: SetNamedProperty a0, c0, r0 - 45: GetNamedProperty r0, a0, c0 - 49: LoadImmediate r1, 4 - 52: Div r0, r0, r1 - 56: SetNamedProperty a0, c0, r0 - 60: GetNamedProperty r0, a0, c0 - 64: LoadImmediate r1, 5 - 67: Rem r0, r0, r1 - 71: SetNamedProperty a0, c0, r0 - 75: GetNamedProperty r0, a0, c0 - 79: LoadImmediate r1, 6 - 82: Exp r0, r0, r1 - 86: SetNamedProperty a0, c0, r0 - 90: GetNamedProperty r0, a0, c0 - 94: LoadImmediate r1, 7 - 97: BitAnd r0, r0, r1 - 101: SetNamedProperty a0, c0, r0 - 105: GetNamedProperty r0, a0, c0 - 109: LoadImmediate r1, 8 - 112: BitOr r0, r0, r1 - 116: SetNamedProperty a0, c0, r0 - 120: GetNamedProperty r0, a0, c0 - 124: LoadImmediate r1, 9 - 127: BitXor r0, r0, r1 - 131: SetNamedProperty a0, c0, r0 - 135: GetNamedProperty r0, a0, c0 - 139: LoadImmediate r1, 10 - 142: ShiftLeft r0, r0, r1 - 146: SetNamedProperty a0, c0, r0 - 150: GetNamedProperty r0, a0, c0 - 154: LoadImmediate r1, 11 - 157: ShiftRightArithmetic r0, r0, r1 - 161: SetNamedProperty a0, c0, r0 - 165: GetNamedProperty r0, a0, c0 - 169: LoadImmediate r1, 12 - 172: ShiftRightLogical r0, r0, r1 - 176: SetNamedProperty a0, c0, r0 - 180: LoadUndefined r0 - 182: Ret r0 + 7: Add r0, r0, r1, fb0 + 12: SetNamedProperty a0, c0, r0 + 16: GetNamedProperty r0, a0, c0 + 20: LoadImmediate r1, 2 + 23: Sub r0, r0, r1 + 27: SetNamedProperty a0, c0, r0 + 31: GetNamedProperty r0, a0, c0 + 35: LoadImmediate r1, 3 + 38: Mul r0, r0, r1 + 42: SetNamedProperty a0, c0, r0 + 46: GetNamedProperty r0, a0, c0 + 50: LoadImmediate r1, 4 + 53: Div r0, r0, r1 + 57: SetNamedProperty a0, c0, r0 + 61: GetNamedProperty r0, a0, c0 + 65: LoadImmediate r1, 5 + 68: Rem r0, r0, r1 + 72: SetNamedProperty a0, c0, r0 + 76: GetNamedProperty r0, a0, c0 + 80: LoadImmediate r1, 6 + 83: Exp r0, r0, r1 + 87: SetNamedProperty a0, c0, r0 + 91: GetNamedProperty r0, a0, c0 + 95: LoadImmediate r1, 7 + 98: BitAnd r0, r0, r1 + 102: SetNamedProperty a0, c0, r0 + 106: GetNamedProperty r0, a0, c0 + 110: LoadImmediate r1, 8 + 113: BitOr r0, r0, r1 + 117: SetNamedProperty a0, c0, r0 + 121: GetNamedProperty r0, a0, c0 + 125: LoadImmediate r1, 9 + 128: BitXor r0, r0, r1 + 132: SetNamedProperty a0, c0, r0 + 136: GetNamedProperty r0, a0, c0 + 140: LoadImmediate r1, 10 + 143: ShiftLeft r0, r0, r1 + 147: SetNamedProperty a0, c0, r0 + 151: GetNamedProperty r0, a0, c0 + 155: LoadImmediate r1, 11 + 158: ShiftRightArithmetic r0, r0, r1 + 162: SetNamedProperty a0, c0, r0 + 166: GetNamedProperty r0, a0, c0 + 170: LoadImmediate r1, 12 + 173: ShiftRightLogical r0, r0, r1 + 177: SetNamedProperty a0, c0, r0 + 181: LoadUndefined r0 + 183: Ret r0 Constant Table: 0: [String: foo] } diff --git a/tests/js_bytecode/expression/binary.exp b/tests/js_bytecode/expression/binary.exp index b58cdfaf..1ea655ce 100644 --- a/tests/js_bytecode/expression/binary.exp +++ b/tests/js_bytecode/expression/binary.exp @@ -15,31 +15,31 @@ [BytecodeFunction: test1] { Parameters: 2, Registers: 1 - 0: Add r0, a0, a1 - 4: Sub r0, a0, a1 - 8: Mul r0, a0, a1 - 12: Div r0, a0, a1 - 16: Rem r0, a0, a1 - 20: Exp r0, a0, a1 - 24: LooseEqual r0, a0, a1 - 28: LooseNotEqual r0, a0, a1 - 32: StrictEqual r0, a0, a1 - 36: StrictNotEqual r0, a0, a1 - 40: LessThan r0, a0, a1 - 44: LessThanOrEqual r0, a0, a1 - 48: GreaterThan r0, a0, a1 - 52: GreaterThanOrEqual r0, a0, a1 - 56: BitAnd r0, a0, a1 - 60: BitOr r0, a0, a1 - 64: BitXor r0, a0, a1 - 68: ShiftLeft r0, a0, a1 - 72: ShiftRightArithmetic r0, a0, a1 - 76: ShiftRightLogical r0, a0, a1 - 80: LoadConstant r0, c0 - 83: In r0, a1, r0 - 87: InstanceOf r0, a0, a1 - 91: LoadUndefined r0 - 93: Ret r0 + 0: Add r0, a0, a1, fb0 + 5: Sub r0, a0, a1 + 9: Mul r0, a0, a1 + 13: Div r0, a0, a1 + 17: Rem r0, a0, a1 + 21: Exp r0, a0, a1 + 25: LooseEqual r0, a0, a1 + 29: LooseNotEqual r0, a0, a1 + 33: StrictEqual r0, a0, a1 + 37: StrictNotEqual r0, a0, a1 + 41: LessThan r0, a0, a1 + 45: LessThanOrEqual r0, a0, a1 + 49: GreaterThan r0, a0, a1 + 53: GreaterThanOrEqual r0, a0, a1 + 57: BitAnd r0, a0, a1 + 61: BitOr r0, a0, a1 + 65: BitXor r0, a0, a1 + 69: ShiftLeft r0, a0, a1 + 73: ShiftRightArithmetic r0, a0, a1 + 77: ShiftRightLogical r0, a0, a1 + 81: LoadConstant r0, c0 + 84: In r0, a1, r0 + 88: InstanceOf r0, a0, a1 + 92: LoadUndefined r0 + 94: Ret r0 Constant Table: 0: [String: x] } diff --git a/tests/js_bytecode/expression/calls/basic.exp b/tests/js_bytecode/expression/calls/basic.exp index ebb936a1..e36917e8 100644 --- a/tests/js_bytecode/expression/calls/basic.exp +++ b/tests/js_bytecode/expression/calls/basic.exp @@ -34,9 +34,9 @@ 9: Mov r3, a0 12: LoadGlobal r4, c0 15: Call r1, r1, r2, 3 - 20: Add r0, r0, r1 - 24: LoadUndefined r0 - 26: Ret r0 + 20: Add r0, r0, r1, fb0 + 25: LoadUndefined r0 + 27: Ret r0 Constant Table: 0: [String: foo] } diff --git a/tests/js_bytecode/expression/calls/member.exp b/tests/js_bytecode/expression/calls/member.exp index 52e34458..c68e18df 100644 --- a/tests/js_bytecode/expression/calls/member.exp +++ b/tests/js_bytecode/expression/calls/member.exp @@ -32,12 +32,12 @@ 23: CallWithReceiver r1, r1, a0, r2, 3 29: LoadImmediate r1, 1 32: LoadImmediate r2, 2 - 35: Add r0, r1, r2 - 39: GetNamedProperty r1, r0, c0 - 43: LoadImmediate r2, 4 - 46: CallWithReceiver r1, r1, r0, r2, 1 - 52: LoadUndefined r1 - 54: Ret r1 + 35: Add r0, r1, r2, fb0 + 40: GetNamedProperty r1, r0, c0 + 44: LoadImmediate r2, 4 + 47: CallWithReceiver r1, r1, r0, r2, 1 + 53: LoadUndefined r1 + 55: Ret r1 Constant Table: 0: [String: foo] } @@ -49,22 +49,22 @@ 7: CallWithReceiver r1, r1, a0, r1, 0 13: LoadImmediate r1, 0 16: LoadImmediate r2, 9 - 19: Add r1, r1, r2 - 23: LoadConstant r2, c0 - 26: GetProperty r2, r1, r2 - 30: LoadImmediate r3, 1 - 33: LoadImmediate r4, 2 - 36: LoadImmediate r5, 3 - 39: CallWithReceiver r1, r2, r1, r3, 3 - 45: LoadImmediate r1, 1 - 48: LoadImmediate r2, 2 - 51: Add r0, r1, r2 - 55: LoadConstant r1, c0 - 58: GetProperty r1, r0, r1 - 62: LoadImmediate r2, 4 - 65: CallWithReceiver r1, r1, r0, r2, 1 - 71: LoadUndefined r1 - 73: Ret r1 + 19: Add r1, r1, r2, fb0 + 24: LoadConstant r2, c0 + 27: GetProperty r2, r1, r2 + 31: LoadImmediate r3, 1 + 34: LoadImmediate r4, 2 + 37: LoadImmediate r5, 3 + 40: CallWithReceiver r1, r2, r1, r3, 3 + 46: LoadImmediate r1, 1 + 49: LoadImmediate r2, 2 + 52: Add r0, r1, r2, fb1 + 57: LoadConstant r1, c0 + 60: GetProperty r1, r0, r1 + 64: LoadImmediate r2, 4 + 67: CallWithReceiver r1, r1, r0, r2, 1 + 73: LoadUndefined r1 + 75: Ret r1 Constant Table: 0: [String: foo] } diff --git a/tests/js_bytecode/expression/conditional.exp b/tests/js_bytecode/expression/conditional.exp index bba14efd..7581e3d7 100644 --- a/tests/js_bytecode/expression/conditional.exp +++ b/tests/js_bytecode/expression/conditional.exp @@ -15,43 +15,43 @@ [BytecodeFunction: testBasic] { Parameters: 0, Registers: 4 - 0: LoadImmediate r0, 1 - 3: JumpToBooleanFalse r0, 8 (.L0) - 6: LoadImmediate r0, 2 - 9: Jump 5 (.L1) + 0: LoadImmediate r0, 1 + 3: JumpToBooleanFalse r0, 8 (.L0) + 6: LoadImmediate r0, 2 + 9: Jump 5 (.L1) .L0: - 11: LoadImmediate r0, 3 + 11: LoadImmediate r0, 3 .L1: - 14: LoadImmediate r0, 1 - 17: LoadImmediate r1, 2 - 20: Add r0, r0, r1 - 24: JumpToBooleanFalse r0, 15 (.L2) - 27: LoadImmediate r1, 3 - 30: LoadImmediate r2, 4 - 33: Add r0, r1, r2 - 37: Jump 12 (.L3) + 14: LoadImmediate r0, 1 + 17: LoadImmediate r1, 2 + 20: Add r0, r0, r1, fb0 + 25: JumpToBooleanFalse r0, 16 (.L2) + 28: LoadImmediate r1, 3 + 31: LoadImmediate r2, 4 + 34: Add r0, r1, r2, fb1 + 39: Jump 13 (.L3) .L2: - 39: LoadImmediate r1, 5 - 42: LoadImmediate r2, 6 - 45: Add r0, r1, r2 + 41: LoadImmediate r1, 5 + 44: LoadImmediate r2, 6 + 47: Add r0, r1, r2, fb2 .L3: - 49: LoadGlobal r0, c0 - 52: LoadImmediate r1, 1 - 55: JumpToBooleanFalse r1, 15 (.L4) - 58: LoadImmediate r2, 2 - 61: LoadImmediate r3, 3 - 64: Add r1, r2, r3 - 68: Jump 19 (.L5) + 52: LoadGlobal r0, c0 + 55: LoadImmediate r1, 1 + 58: JumpToBooleanFalse r1, 16 (.L4) + 61: LoadImmediate r2, 2 + 64: LoadImmediate r3, 3 + 67: Add r1, r2, r3, fb3 + 72: Jump 21 (.L5) .L4: - 70: LoadImmediate r2, 4 - 73: LoadImmediate r3, 5 - 76: Add r2, r2, r3 - 80: LoadImmediate r3, 6 - 83: Add r1, r2, r3 + 74: LoadImmediate r2, 4 + 77: LoadImmediate r3, 5 + 80: Add r2, r2, r3, fb4 + 85: LoadImmediate r3, 6 + 88: Add r1, r2, r3, fb5 .L5: - 87: Call r0, r0, r1, 1 - 92: LoadUndefined r0 - 94: Ret r0 + 93: Call r0, r0, r1, 1 + 98: LoadUndefined r0 + 100: Ret r0 Constant Table: 0: [String: use] } diff --git a/tests/js_bytecode/expression/delete.exp b/tests/js_bytecode/expression/delete.exp index e8eb78ea..380d45ca 100644 --- a/tests/js_bytecode/expression/delete.exp +++ b/tests/js_bytecode/expression/delete.exp @@ -121,10 +121,10 @@ 3: LoadTrue r0 5: LoadImmediate r0, 1 8: LoadImmediate r1, 2 - 11: Add r0, r0, r1 - 15: LoadTrue r0 - 17: LoadUndefined r0 - 19: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: LoadTrue r0 + 18: LoadUndefined r0 + 20: Ret r0 } [BytecodeFunction: deleteIdVars] { @@ -234,9 +234,9 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1 - 10: ThrowNewError 0, c0 - 13: Ret r0 + 6: Add r0, r0, r1, fb0 + 11: ThrowNewError 0, c0 + 14: Ret r0 Constant Table: 0: [String: cannot delete super property] } diff --git a/tests/js_bytecode/expression/function.exp b/tests/js_bytecode/expression/function.exp index 3aa30f35..1b376b26 100644 --- a/tests/js_bytecode/expression/function.exp +++ b/tests/js_bytecode/expression/function.exp @@ -37,13 +37,13 @@ Parameters: 0, Registers: 3 0: NewClosure r1, c0 3: LoadImmediate r2, 2 - 6: Add r1, r1, r2 - 10: NewClosure r1, c1 - 13: LoadImmediate r2, 4 - 16: Add r1, r1, r2 - 20: NewClosure r0, c2 - 23: LoadUndefined r1 - 25: Ret r1 + 6: Add r1, r1, r2, fb0 + 11: NewClosure r1, c1 + 14: LoadImmediate r2, 4 + 17: Add r1, r1, r2, fb1 + 22: NewClosure r0, c2 + 25: LoadUndefined r1 + 27: Ret r1 Constant Table: 0: [BytecodeFunction: foo] 1: [BytecodeFunction: ] diff --git a/tests/js_bytecode/expression/logical.exp b/tests/js_bytecode/expression/logical.exp index a0928a6f..05971cfe 100644 --- a/tests/js_bytecode/expression/logical.exp +++ b/tests/js_bytecode/expression/logical.exp @@ -50,62 +50,62 @@ [BytecodeFunction: logicalAndBoolean] { Parameters: 0, Registers: 3 0: LoadTrue r0 - 2: JumpFalse r0, 13 (.L0) + 2: JumpFalse r0, 14 (.L0) 5: LoadImmediate r1, 1 8: LoadImmediate r2, 2 - 11: Add r0, r1, r2 + 11: Add r0, r1, r2, fb0 .L0: - 15: Ret r0 + 16: Ret r0 } [BytecodeFunction: logicalAndNotBoolean] { Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 3: LoadImmediate r2, 2 - 6: Add r0, r1, r2 - 10: JumpToBooleanFalse r0, 13 (.L0) - 13: LoadImmediate r1, 3 - 16: LoadImmediate r2, 4 - 19: Add r0, r1, r2 + 6: Add r0, r1, r2, fb0 + 11: JumpToBooleanFalse r0, 14 (.L0) + 14: LoadImmediate r1, 3 + 17: LoadImmediate r2, 4 + 20: Add r0, r1, r2, fb1 .L0: - 23: Ret r0 + 25: Ret r0 } [BytecodeFunction: logicalOrBoolean] { Parameters: 0, Registers: 3 0: LoadTrue r0 - 2: JumpTrue r0, 13 (.L0) + 2: JumpTrue r0, 14 (.L0) 5: LoadImmediate r1, 1 8: LoadImmediate r2, 2 - 11: Add r0, r1, r2 + 11: Add r0, r1, r2, fb0 .L0: - 15: Ret r0 + 16: Ret r0 } [BytecodeFunction: logicalOrNotBoolean] { Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 3: LoadImmediate r2, 2 - 6: Add r0, r1, r2 - 10: JumpToBooleanTrue r0, 13 (.L0) - 13: LoadImmediate r1, 3 - 16: LoadImmediate r2, 4 - 19: Add r0, r1, r2 + 6: Add r0, r1, r2, fb0 + 11: JumpToBooleanTrue r0, 14 (.L0) + 14: LoadImmediate r1, 3 + 17: LoadImmediate r2, 4 + 20: Add r0, r1, r2, fb1 .L0: - 23: Ret r0 + 25: Ret r0 } [BytecodeFunction: nullishCoalesce] { Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 3: LoadImmediate r2, 2 - 6: Add r0, r1, r2 - 10: JumpNotNullish r0, 13 (.L0) - 13: LoadImmediate r1, 3 - 16: LoadImmediate r2, 4 - 19: Add r0, r1, r2 + 6: Add r0, r1, r2, fb0 + 11: JumpNotNullish r0, 14 (.L0) + 14: LoadImmediate r1, 3 + 17: LoadImmediate r2, 4 + 20: Add r0, r1, r2, fb1 .L0: - 23: Ret r0 + 25: Ret r0 } [BytecodeFunction: logicalAndWithTemporary] { diff --git a/tests/js_bytecode/expression/member.exp b/tests/js_bytecode/expression/member.exp index 499d8e56..9cff57da 100644 --- a/tests/js_bytecode/expression/member.exp +++ b/tests/js_bytecode/expression/member.exp @@ -34,13 +34,13 @@ 3: GetProperty r0, a0, r0 7: LoadImmediate r0, 1 10: LoadImmediate r1, 2 - 13: Add r0, r0, r1 - 17: LoadImmediate r1, 3 - 20: LoadImmediate r2, 4 - 23: Add r1, r1, r2 - 27: GetProperty r0, r0, r1 - 31: LoadUndefined r0 - 33: Ret r0 + 13: Add r0, r0, r1, fb0 + 18: LoadImmediate r1, 3 + 21: LoadImmediate r2, 4 + 24: Add r1, r1, r2, fb1 + 29: GetProperty r0, r0, r1 + 33: LoadUndefined r0 + 35: Ret r0 Constant Table: 0: [String: foo] } diff --git a/tests/js_bytecode/expression/new.exp b/tests/js_bytecode/expression/new.exp index f40434d4..853c5ba8 100644 --- a/tests/js_bytecode/expression/new.exp +++ b/tests/js_bytecode/expression/new.exp @@ -42,9 +42,9 @@ 9: Mov r3, a0 12: LoadGlobal r4, c0 15: Construct r1, r1, r1, r2, 3 - 21: Add r0, r0, r1 - 25: LoadUndefined r0 - 27: Ret r0 + 21: Add r0, r0, r1, fb0 + 26: LoadUndefined r0 + 28: Ret r0 Constant Table: 0: [String: foo] } diff --git a/tests/js_bytecode/expression/new_target.exp b/tests/js_bytecode/expression/new_target.exp index 39bf140b..a045db40 100644 --- a/tests/js_bytecode/expression/new_target.exp +++ b/tests/js_bytecode/expression/new_target.exp @@ -20,8 +20,8 @@ [BytecodeFunction: simpleNewTarget] { Parameters: 0, Registers: 2 0: LoadImmediate r1, 1 - 3: Add r1, r0, r1 - 7: Ret r1 + 3: Add r1, r0, r1, fb0 + 8: Ret r1 } [BytecodeFunction: captured] { @@ -31,8 +31,8 @@ 6: NewClosure r0, c1 9: LoadFromScope r0, 0, 0 13: LoadImmediate r1, 1 - 16: Add r0, r0, r1 - 20: Ret r0 + 16: Add r0, r0, r1, fb0 + 21: Ret r0 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: ] @@ -49,8 +49,8 @@ Parameters: 0, Registers: 3 0: NewClosure r0, c0 3: LoadImmediate r2, 3 - 6: Add r2, r1, r2 - 10: Ret r2 + 6: Add r2, r1, r2, fb0 + 11: Ret r2 Constant Table: 0: [BytecodeFunction: inner] } @@ -59,6 +59,6 @@ Parameters: 0, Registers: 3 0: LoadImmediate r0, 1 3: LoadImmediate r2, 2 - 6: Add r2, r1, r2 - 10: Ret r2 + 6: Add r2, r1, r2, fb0 + 11: Ret r2 } diff --git a/tests/js_bytecode/expression/object/basic.exp b/tests/js_bytecode/expression/object/basic.exp index 471f76ef..26445e5d 100644 --- a/tests/js_bytecode/expression/object/basic.exp +++ b/tests/js_bytecode/expression/object/basic.exp @@ -76,9 +76,9 @@ 5: DefineNamedProperty r0, c0, r1 9: LoadImmediate r1, 2 12: LoadImmediate r2, 3 - 15: Add r1, r1, r2 - 19: DefineNamedProperty r0, c1, r1 - 23: Ret r0 + 15: Add r1, r1, r2, fb0 + 20: DefineNamedProperty r0, c1, r1 + 24: Ret r0 Constant Table: 0: [String: a] 1: [String: global] @@ -108,10 +108,10 @@ 19: DefineProperty r0, r1, r2, 0 24: LoadImmediate r1, 4 27: LoadImmediate r2, 5 - 30: Add r1, r1, r2 - 34: LoadImmediate r2, 6 - 37: DefineProperty r0, r1, r2, 0 - 42: Ret r0 + 30: Add r1, r1, r2, fb0 + 35: LoadImmediate r2, 6 + 38: DefineProperty r0, r1, r2, 0 + 43: Ret r0 Constant Table: 0: [String: a] } @@ -122,9 +122,9 @@ 2: CopyDataProperties r0, a0, a0, 0 7: LoadImmediate r1, 1 10: LoadImmediate r2, 2 - 13: Add r1, r1, r2 - 17: CopyDataProperties r0, r1, r1, 0 - 22: Ret r0 + 13: Add r1, r1, r2, fb0 + 18: CopyDataProperties r0, r1, r1, 0 + 23: Ret r0 } [BytecodeFunction: proto] { @@ -132,9 +132,9 @@ 0: NewObject r0 2: LoadImmediate r1, 1 5: LoadImmediate r2, 2 - 8: Add r1, r1, r2 - 12: SetPrototypeOf r0, r1 - 15: Ret r0 + 8: Add r1, r1, r2, fb0 + 13: SetPrototypeOf r0, r1 + 16: Ret r0 Constant Table: 0: [String: __proto__] } diff --git a/tests/js_bytecode/expression/object/named_evalution.exp b/tests/js_bytecode/expression/object/named_evalution.exp index 14bea7f9..b4995b77 100644 --- a/tests/js_bytecode/expression/object/named_evalution.exp +++ b/tests/js_bytecode/expression/object/named_evalution.exp @@ -81,13 +81,13 @@ 0: NewObject r0 2: LoadImmediate r1, 1 5: LoadImmediate r2, 2 - 8: Add r1, r1, r2 - 12: NewClosure r2, c0 - 15: DefineProperty r0, r1, r2, 1 - 20: LoadImmediate r1, 3 - 23: NewClosure r2, c1 - 26: DefineProperty r0, r1, r2, 1 - 31: Ret r0 + 8: Add r1, r1, r2, fb0 + 13: NewClosure r2, c0 + 16: DefineProperty r0, r1, r2, 1 + 21: LoadImmediate r1, 3 + 24: NewClosure r2, c1 + 27: DefineProperty r0, r1, r2, 1 + 32: Ret r0 Constant Table: 0: [BytecodeFunction: ] 1: [BytecodeFunction: ] diff --git a/tests/js_bytecode/expression/super_member.exp b/tests/js_bytecode/expression/super_member.exp index 96392286..edc6ab37 100644 --- a/tests/js_bytecode/expression/super_member.exp +++ b/tests/js_bytecode/expression/super_member.exp @@ -36,9 +36,9 @@ 0: LoadFromScope r0, 0, 0 4: LoadImmediate r1, 1 7: LoadImmediate r2, 2 - 10: Add r1, r1, r2 - 14: GetSuperProperty r0, r0, , r1 - 19: Ret r0 + 10: Add r1, r1, r2, fb0 + 15: GetSuperProperty r0, r0, , r1 + 20: Ret r0 } [BytecodeFunction: captured] { diff --git a/tests/js_bytecode/expression/tagged_template.exp b/tests/js_bytecode/expression/tagged_template.exp index 95b4c957..a81086a8 100644 --- a/tests/js_bytecode/expression/tagged_template.exp +++ b/tests/js_bytecode/expression/tagged_template.exp @@ -41,16 +41,16 @@ Parameters: 0, Registers: 5 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1 - 10: LoadConstant r1, c0 - 13: LoadImmediate r2, 3 - 16: LoadImmediate r3, 4 - 19: Add r2, r2, r3 - 23: LoadImmediate r3, 5 - 26: LoadImmediate r4, 6 - 29: Add r3, r3, r4 - 33: Call r0, r0, r1, 3 - 38: Ret r0 + 6: Add r0, r0, r1, fb0 + 11: LoadConstant r1, c0 + 14: LoadImmediate r2, 3 + 17: LoadImmediate r3, 4 + 20: Add r2, r2, r3, fb1 + 25: LoadImmediate r3, 5 + 28: LoadImmediate r4, 6 + 31: Add r3, r3, r4, fb2 + 36: Call r0, r0, r1, 3 + 41: Ret r0 Constant Table: 0: [ArrayObject] } @@ -98,13 +98,13 @@ 13: CallWithReceiver r1, r1, a0, r2, 3 19: LoadImmediate r1, 1 22: LoadImmediate r2, 2 - 25: Add r0, r1, r2 - 29: GetNamedProperty r1, r0, c0 - 33: LoadConstant r2, c2 - 36: LoadImmediate r3, 3 - 39: CallWithReceiver r1, r1, r0, r2, 2 - 45: LoadUndefined r1 - 47: Ret r1 + 25: Add r0, r1, r2, fb0 + 30: GetNamedProperty r1, r0, c0 + 34: LoadConstant r2, c2 + 37: LoadImmediate r3, 3 + 40: CallWithReceiver r1, r1, r0, r2, 2 + 46: LoadUndefined r1 + 48: Ret r1 Constant Table: 0: [String: foo] 1: [ArrayObject] @@ -121,14 +121,14 @@ 16: CallWithReceiver r1, r1, a0, r2, 3 22: LoadImmediate r1, 1 25: LoadImmediate r2, 2 - 28: Add r0, r1, r2 - 32: LoadConstant r1, c0 - 35: GetProperty r1, r0, r1 - 39: LoadConstant r2, c2 - 42: LoadImmediate r3, 3 - 45: CallWithReceiver r1, r1, r0, r2, 2 - 51: LoadUndefined r1 - 53: Ret r1 + 28: Add r0, r1, r2, fb0 + 33: LoadConstant r1, c0 + 36: GetProperty r1, r0, r1 + 40: LoadConstant r2, c2 + 43: LoadImmediate r3, 3 + 46: CallWithReceiver r1, r1, r0, r2, 2 + 52: LoadUndefined r1 + 54: Ret r1 Constant Table: 0: [String: foo] 1: [ArrayObject] diff --git a/tests/js_bytecode/expression/template_literal.exp b/tests/js_bytecode/expression/template_literal.exp index 8e54c493..b16656b6 100644 --- a/tests/js_bytecode/expression/template_literal.exp +++ b/tests/js_bytecode/expression/template_literal.exp @@ -56,13 +56,13 @@ 0: LoadImmediate r1, 1 3: ToString r0, r1 6: LoadConstant r1, c0 - 9: Add r0, r0, r1 - 13: Mov a0, r0 - 16: LoadImmediate r1, 1 - 19: ToString r0, r1 - 22: LoadConstant r1, c0 - 25: Add r0, r0, r1 - 29: Ret r0 + 9: Add r0, r0, r1, fb0 + 14: Mov a0, r0 + 17: LoadImmediate r1, 1 + 20: ToString r0, r1 + 23: LoadConstant r1, c0 + 26: Add r0, r0, r1, fb1 + 31: Ret r0 Constant Table: 0: [String: test] } @@ -72,8 +72,8 @@ 0: LoadConstant r0, c0 3: LoadImmediate r1, 1 6: ToString r1, r1 - 9: Add r0, r0, r1 - 13: Ret r0 + 9: Add r0, r0, r1, fb0 + 14: Ret r0 Constant Table: 0: [String: test] } @@ -84,11 +84,11 @@ 3: ToString r0, r1 6: LoadImmediate r1, 2 9: ToString r1, r1 - 12: Add r0, r0, r1 - 16: LoadImmediate r1, 3 - 19: ToString r1, r1 - 22: Add r0, r0, r1 - 26: Ret r0 + 12: Add r0, r0, r1, fb0 + 17: LoadImmediate r1, 3 + 20: ToString r1, r1 + 23: Add r0, r0, r1, fb1 + 28: Ret r0 } [BytecodeFunction: expressionsAndNonEmptyLiterals] { @@ -96,15 +96,15 @@ 0: LoadConstant r0, c0 3: LoadImmediate r1, 1 6: ToString r1, r1 - 9: Add r0, r0, r1 - 13: LoadConstant r1, c1 - 16: Add r0, r0, r1 - 20: LoadImmediate r1, 2 - 23: ToString r1, r1 - 26: Add r0, r0, r1 - 30: LoadConstant r1, c2 - 33: Add r0, r0, r1 - 37: Ret r0 + 9: Add r0, r0, r1, fb0 + 14: LoadConstant r1, c1 + 17: Add r0, r0, r1, fb1 + 22: LoadImmediate r1, 2 + 25: ToString r1, r1 + 28: Add r0, r0, r1, fb2 + 33: LoadConstant r1, c2 + 36: Add r0, r0, r1, fb3 + 41: Ret r0 Constant Table: 0: [String: a] 1: [String: b] @@ -117,14 +117,14 @@ 3: ToString a1, a1 6: LoadConstant r0, c0 9: ToString r1, a0 - 12: Add r0, r0, r1 - 16: LoadConstant r1, c1 - 19: Add r0, r0, r1 - 23: ToString r1, a1 - 26: Add r0, r0, r1 - 30: LoadConstant r1, c2 - 33: Add r0, r0, r1 - 37: Ret r0 + 12: Add r0, r0, r1, fb0 + 17: LoadConstant r1, c1 + 20: Add r0, r0, r1, fb1 + 25: ToString r1, a1 + 28: Add r0, r0, r1, fb2 + 33: LoadConstant r1, c2 + 36: Add r0, r0, r1, fb3 + 41: Ret r0 Constant Table: 0: [String: a] 1: [String: b] diff --git a/tests/js_bytecode/expression/this.exp b/tests/js_bytecode/expression/this.exp index d0ebab2c..df945187 100644 --- a/tests/js_bytecode/expression/this.exp +++ b/tests/js_bytecode/expression/this.exp @@ -23,12 +23,12 @@ Parameters: 0, Registers: 3 0: Mov r0, 3: LoadImmediate r1, 1 - 6: Add r1, , r1 - 10: LoadGlobal r1, c0 - 13: Mov r2, - 16: Call r1, r1, r2, 1 - 21: LoadUndefined r1 - 23: Ret r1 + 6: Add r1, , r1, fb0 + 11: LoadGlobal r1, c0 + 14: Mov r2, + 17: Call r1, r1, r2, 1 + 22: LoadUndefined r1 + 24: Ret r1 Constant Table: 0: [String: use] } diff --git a/tests/js_bytecode/function/async.exp b/tests/js_bytecode/function/async.exp index e9df0a8b..0e8c4ae7 100644 --- a/tests/js_bytecode/function/async.exp +++ b/tests/js_bytecode/function/async.exp @@ -61,37 +61,37 @@ 2: LoadImmediate r1, 1 5: LoadImmediate r1, 2 8: LoadImmediate r2, 3 - 11: Add r1, r1, r2 - 15: Await r1, r2, r0, r1 - 20: JumpTrue r2, 5 (.L0) - 23: Throw r1 + 11: Add r1, r1, r2, fb0 + 16: Await r1, r2, r0, r1 + 21: JumpTrue r2, 5 (.L0) + 24: Throw r1 .L0: - 25: LoadImmediate r1, 4 - 28: LoadUndefined r1 - 30: ResolvePromise r0, r1 - 33: Ret r0 - 35: RejectPromise r0, r1 - 38: Ret r0 + 26: LoadImmediate r1, 4 + 29: LoadUndefined r1 + 31: ResolvePromise r0, r1 + 34: Ret r0 + 36: RejectPromise r0, r1 + 39: Ret r0 Exception Handlers: - 2-35 -> 35 (r1) + 2-36 -> 36 (r1) } [BytecodeFunction: paramExpressions] { Parameters: 1, Registers: 3 0: NewPromise r0 - 2: JumpNotUndefined a0, 13 (.L0) + 2: JumpNotUndefined a0, 14 (.L0) 5: LoadImmediate r1, 1 8: LoadImmediate r2, 2 - 11: Add a0, r1, r2 + 11: Add a0, r1, r2, fb0 .L0: - 15: LoadImmediate r1, 3 - 18: LoadUndefined r1 - 20: ResolvePromise r0, r1 - 23: Ret r0 - 25: RejectPromise r0, r1 - 28: Ret r0 + 16: LoadImmediate r1, 3 + 19: LoadUndefined r1 + 21: ResolvePromise r0, r1 + 24: Ret r0 + 26: RejectPromise r0, r1 + 29: Ret r0 Exception Handlers: - 2-25 -> 25 (r1) + 2-26 -> 26 (r1) } [BytecodeFunction: returnInFinally] { diff --git a/tests/js_bytecode/function/basic.exp b/tests/js_bytecode/function/basic.exp index 3a4c586d..51274007 100644 --- a/tests/js_bytecode/function/basic.exp +++ b/tests/js_bytecode/function/basic.exp @@ -23,8 +23,8 @@ [BytecodeFunction: test1] { Parameters: 2, Registers: 1 - 0: Add r0, a0, a1 - 4: Ret r0 + 0: Add r0, a0, a1, fb0 + 5: Ret r0 } [BytecodeFunction: test2] { diff --git a/tests/js_bytecode/function/generator.exp b/tests/js_bytecode/function/generator.exp index cc25db87..3e2ab717 100644 --- a/tests/js_bytecode/function/generator.exp +++ b/tests/js_bytecode/function/generator.exp @@ -211,8 +211,8 @@ .L2: 65: Throw r2 .L3: - 67: Add r1, r1, r2 - 71: Ret r1 + 67: Add r1, r1, r2, fb0 + 72: Ret r1 Constant Table: 0: [String: value] 1: [String: done] diff --git a/tests/js_bytecode/function/parameters.exp b/tests/js_bytecode/function/parameters.exp index 9561f68b..71a35ee5 100644 --- a/tests/js_bytecode/function/parameters.exp +++ b/tests/js_bytecode/function/parameters.exp @@ -115,10 +115,10 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadFromScope r1, 1, 0 - 8: Add r0, r0, r1 - 12: LoadFromScope r1, 2, 0 - 16: Add r0, r0, r1 - 20: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: LoadFromScope r1, 2, 0 + 17: Add r0, r0, r1, fb1 + 22: Ret r0 } [BytecodeFunction: tdz] { @@ -130,9 +130,9 @@ .L0: 11: Mov r0, a1 14: CheckTdz r0, c0 - 17: Add r1, a0, r0 - 21: LoadUndefined r1 - 23: Ret r1 + 17: Add r1, a0, r0, fb0 + 22: LoadUndefined r1 + 24: Ret r1 Constant Table: 0: [String: b] } @@ -153,9 +153,9 @@ 32: LoadFromScope r1, 0, 0 36: LoadFromScope r2, 1, 0 40: CheckTdz r2, c1 - 43: Add r1, r1, r2 - 47: LoadUndefined r1 - 49: Ret r1 + 43: Add r1, r1, r2, fb0 + 48: LoadUndefined r1 + 50: Ret r1 Constant Table: 0: [ScopeNames] 1: [String: b] @@ -167,8 +167,8 @@ 0: LoadFromScope r0, 0, 0 4: LoadFromScope r1, 1, 0 8: CheckTdz r1, c0 - 11: Add r0, r0, r1 - 15: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: Ret r0 Constant Table: 0: [String: b] } diff --git a/tests/js_bytecode/module/dynamic_import.exp b/tests/js_bytecode/module/dynamic_import.exp index 32189b9d..e97113f3 100644 --- a/tests/js_bytecode/module/dynamic_import.exp +++ b/tests/js_bytecode/module/dynamic_import.exp @@ -2,14 +2,14 @@ Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 3: LoadImmediate r2, 2 - 6: Add r1, r1, r2 - 10: LoadUndefined r2 - 12: DynamicImport r0, r1, r2 - 16: LoadImmediate r1, 3 - 19: Add r0, r0, r1 - 23: LoadImmediate r1, 4 - 26: NewObject r2 - 28: DynamicImport r0, r1, r2 - 32: LoadUndefined r0 - 34: Ret r0 + 6: Add r1, r1, r2, fb0 + 11: LoadUndefined r2 + 13: DynamicImport r0, r1, r2 + 17: LoadImmediate r1, 3 + 20: Add r0, r0, r1, fb1 + 25: LoadImmediate r1, 4 + 28: NewObject r2 + 30: DynamicImport r0, r1, r2 + 34: LoadUndefined r0 + 36: Ret r0 } diff --git a/tests/js_bytecode/module/export_default_expression.exp b/tests/js_bytecode/module/export_default_expression.exp index d6d9deca..dc1ec6de 100644 --- a/tests/js_bytecode/module/export_default_expression.exp +++ b/tests/js_bytecode/module/export_default_expression.exp @@ -2,8 +2,8 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1 - 10: StoreToModule r0, 1, 0 - 14: LoadUndefined r0 - 16: Ret r0 + 6: Add r0, r0, r1, fb0 + 11: StoreToModule r0, 1, 0 + 15: LoadUndefined r0 + 17: Ret r0 } diff --git a/tests/js_bytecode/module/exported_bindings.exp b/tests/js_bytecode/module/exported_bindings.exp index e3920ec7..6a145a81 100644 --- a/tests/js_bytecode/module/exported_bindings.exp +++ b/tests/js_bytecode/module/exported_bindings.exp @@ -40,24 +40,24 @@ Parameters: 0, Registers: 3 0: LoadFromModule r1, 1, 0 4: LoadFromModule r2, 2, 0 - 8: Add r1, r1, r2 - 12: LoadFromModule r2, 3, 0 - 16: Add r1, r1, r2 - 20: LoadFromModule r2, 4, 0 - 24: Add r1, r1, r2 - 28: LoadFromModule r2, 5, 0 - 32: Add r1, r1, r2 - 36: PushLexicalScope c0 - 38: LoadEmpty r1 - 40: StoreToScope r1, 0, 0 - 44: NewClosure r0, c1 - 47: LoadImmediate r1, 4 - 50: StoreToScope r1, 0, 0 - 54: LoadFromModule r1, 3, 1 - 58: Call r1, r0, r1, 1 - 63: PopScope - 64: LoadUndefined r1 - 66: Ret r1 + 8: Add r1, r1, r2, fb0 + 13: LoadFromModule r2, 3, 0 + 17: Add r1, r1, r2, fb1 + 22: LoadFromModule r2, 4, 0 + 26: Add r1, r1, r2, fb2 + 31: LoadFromModule r2, 5, 0 + 35: Add r1, r1, r2, fb3 + 40: PushLexicalScope c0 + 42: LoadEmpty r1 + 44: StoreToScope r1, 0, 0 + 48: NewClosure r0, c1 + 51: LoadImmediate r1, 4 + 54: StoreToScope r1, 0, 0 + 58: LoadFromModule r1, 3, 1 + 62: Call r1, r0, r1, 1 + 67: PopScope + 68: LoadUndefined r1 + 70: Ret r1 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: capturing] @@ -68,9 +68,9 @@ 0: LoadFromModule r0, 3, 1 4: LoadFromScope r1, 0, 0 8: CheckTdz r1, c0 - 11: Add r0, r0, r1 - 15: LoadUndefined r0 - 17: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: LoadUndefined r0 + 18: Ret r0 Constant Table: 0: [String: const2] } @@ -79,11 +79,11 @@ Parameters: 0, Registers: 2 0: LoadFromModule r0, 6, 0 4: LoadFromModule r1, 7, 0 - 8: Add r0, r0, r1 - 12: LoadGlobal r1, c0 - 15: Add r0, r0, r1 - 19: LoadUndefined r0 - 21: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: LoadGlobal r1, c0 + 16: Add r0, r0, r1, fb1 + 21: LoadUndefined r0 + 23: Ret r0 Constant Table: 0: [String: renamedVar3] } diff --git a/tests/js_bytecode/module/import_meta.exp b/tests/js_bytecode/module/import_meta.exp index c7394122..7c87b3a0 100644 --- a/tests/js_bytecode/module/import_meta.exp +++ b/tests/js_bytecode/module/import_meta.exp @@ -2,7 +2,7 @@ Parameters: 0, Registers: 2 0: ImportMeta r0 2: LoadImmediate r1, 1 - 5: Add r0, r0, r1 - 9: LoadUndefined r0 - 11: Ret r0 + 5: Add r0, r0, r1, fb0 + 10: LoadUndefined r0 + 12: Ret r0 } diff --git a/tests/js_bytecode/module/import_named/import_named.exp b/tests/js_bytecode/module/import_named/import_named.exp index dab9793e..2949e93f 100644 --- a/tests/js_bytecode/module/import_named/import_named.exp +++ b/tests/js_bytecode/module/import_named/import_named.exp @@ -11,22 +11,22 @@ Parameters: 0, Registers: 3 0: LoadFromModule r1, 1, 0 4: LoadFromModule r2, 2, 0 - 8: Add r1, r1, r2 - 12: LoadFromModule r2, 3, 0 - 16: Add r1, r1, r2 - 20: LoadFromModule r2, 4, 0 - 24: Add r1, r1, r2 - 28: PushLexicalScope c0 - 30: LoadEmpty r1 - 32: StoreToScope r1, 0, 0 - 36: NewClosure r0, c1 - 39: LoadImmediate r1, 0 - 42: StoreToScope r1, 0, 0 - 46: LoadFromModule r1, 1, 1 - 50: Call r1, r0, r1, 1 - 55: PopScope - 56: LoadUndefined r1 - 58: Ret r1 + 8: Add r1, r1, r2, fb0 + 13: LoadFromModule r2, 3, 0 + 17: Add r1, r1, r2, fb1 + 22: LoadFromModule r2, 4, 0 + 26: Add r1, r1, r2, fb2 + 31: PushLexicalScope c0 + 33: LoadEmpty r1 + 35: StoreToScope r1, 0, 0 + 39: NewClosure r0, c1 + 42: LoadImmediate r1, 0 + 45: StoreToScope r1, 0, 0 + 49: LoadFromModule r1, 1, 1 + 53: Call r1, r0, r1, 1 + 58: PopScope + 59: LoadUndefined r1 + 61: Ret r1 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: capturing] @@ -37,9 +37,9 @@ 0: LoadFromModule r0, 1, 1 4: LoadFromScope r1, 0, 0 8: CheckTdz r1, c0 - 11: Add r0, r0, r1 - 15: LoadUndefined r0 - 17: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: LoadUndefined r0 + 18: Ret r0 Constant Table: 0: [String: c] } diff --git a/tests/js_bytecode/module/reexport_named/importing.exp b/tests/js_bytecode/module/reexport_named/importing.exp index 47e65584..f4706170 100644 --- a/tests/js_bytecode/module/reexport_named/importing.exp +++ b/tests/js_bytecode/module/reexport_named/importing.exp @@ -11,9 +11,9 @@ Parameters: 0, Registers: 2 0: LoadFromModule r0, 1, 0 4: LoadFromModule r1, 2, 0 - 8: Add r0, r0, r1 - 12: LoadFromModule r1, 3, 0 - 16: Add r0, r0, r1 - 20: LoadUndefined r0 - 22: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: LoadFromModule r1, 3, 0 + 17: Add r0, r0, r1, fb1 + 22: LoadUndefined r0 + 24: Ret r0 } diff --git a/tests/js_bytecode/module/reexport_star/importing.exp b/tests/js_bytecode/module/reexport_star/importing.exp index 1dba1dd3..b0891723 100644 --- a/tests/js_bytecode/module/reexport_star/importing.exp +++ b/tests/js_bytecode/module/reexport_star/importing.exp @@ -11,7 +11,7 @@ Parameters: 0, Registers: 2 0: LoadFromModule r0, 1, 0 4: LoadFromModule r1, 2, 0 - 8: Add r0, r0, r1 - 12: LoadUndefined r0 - 14: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: LoadUndefined r0 + 15: Ret r0 } diff --git a/tests/js_bytecode/module/top_level_await.exp b/tests/js_bytecode/module/top_level_await.exp index 0f77c95e..1ce61c14 100644 --- a/tests/js_bytecode/module/top_level_await.exp +++ b/tests/js_bytecode/module/top_level_await.exp @@ -3,21 +3,21 @@ 0: Mov r0, a0 3: LoadImmediate r1, 1 6: LoadImmediate r2, 2 - 9: Add r1, r1, r2 - 13: LoadImmediate r1, 3 - 16: Await r1, r2, r0, r1 - 21: JumpTrue r2, 5 (.L0) - 24: Throw r1 + 9: Add r1, r1, r2, fb0 + 14: LoadImmediate r1, 3 + 17: Await r1, r2, r0, r1 + 22: JumpTrue r2, 5 (.L0) + 25: Throw r1 .L0: - 26: LoadImmediate r1, 4 - 29: LoadImmediate r2, 5 - 32: Add r1, r1, r2 - 36: LoadUndefined r1 - 38: ResolvePromise r0, r1 - 41: Ret r0 - 43: RejectPromise r0, r1 - 46: LoadUndefined r0 - 48: Ret r0 + 27: LoadImmediate r1, 4 + 30: LoadImmediate r2, 5 + 33: Add r1, r1, r2, fb1 + 38: LoadUndefined r1 + 40: ResolvePromise r0, r1 + 43: Ret r0 + 45: RejectPromise r0, r1 + 48: LoadUndefined r0 + 50: Ret r0 Exception Handlers: - 3-43 -> 43 (r1) + 3-45 -> 45 (r1) } diff --git a/tests/js_bytecode/module/toplevel.exp b/tests/js_bytecode/module/toplevel.exp index b1d37998..d91e3e29 100644 --- a/tests/js_bytecode/module/toplevel.exp +++ b/tests/js_bytecode/module/toplevel.exp @@ -16,9 +16,9 @@ 43: NewClosure r1, c2 46: LoadImmediate r2, 100 49: LoadFromScope r3, 1, 0 - 53: Add r2, r2, r3 - 57: LoadUndefined r2 - 59: Ret r2 + 53: Add r2, r2, r3, fb0 + 58: LoadUndefined r2 + 60: Ret r2 Constant Table: 0: [BytecodeFunction: toplevelMethod] 1: [BytecodeFunction: testToplevelBinding] @@ -42,14 +42,14 @@ 0: LoadFromScope r0, 1, 0 4: LoadFromScope r1, 2, 0 8: CheckTdz r1, c0 - 11: Add r0, r0, r1 - 15: LoadFromScope r1, 3, 0 - 19: CheckTdz r1, c1 - 22: Add r0, r0, r1 - 26: LoadFromScope r1, 4, 0 - 30: Add r0, r0, r1 - 34: LoadUndefined r0 - 36: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: LoadFromScope r1, 3, 0 + 20: CheckTdz r1, c1 + 23: Add r0, r0, r1, fb1 + 28: LoadFromScope r1, 4, 0 + 32: Add r0, r0, r1, fb2 + 37: LoadUndefined r0 + 39: Ret r0 Constant Table: 0: [String: x2] 1: [String: x3] diff --git a/tests/js_bytecode/scope/captured.exp b/tests/js_bytecode/scope/captured.exp index e0b8e780..d6ea563e 100644 --- a/tests/js_bytecode/scope/captured.exp +++ b/tests/js_bytecode/scope/captured.exp @@ -71,8 +71,8 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadImmediate r1, 2 - 7: Add r0, r0, r1 - 11: Ret r0 + 7: Add r0, r0, r1, fb0 + 12: Ret r0 } [BytecodeFunction: multipleCaptures] { @@ -94,8 +94,8 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadFromScope r1, 1, 0 - 8: Add r0, r0, r1 - 12: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: Ret r0 } [BytecodeFunction: capturedLexical] { @@ -114,9 +114,9 @@ 35: CheckTdz r1, c2 38: LoadFromScope r2, 1, 0 42: CheckTdz r2, c3 - 45: Add r1, r1, r2 - 49: LoadUndefined r1 - 51: Ret r1 + 45: Add r1, r1, r2, fb0 + 50: LoadUndefined r1 + 52: Ret r1 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: inner] @@ -130,8 +130,8 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 1, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: Ret r0 Constant Table: 0: [String: c1] 1: [String: l1] @@ -173,15 +173,15 @@ 0: NewClosure r0, c0 3: LoadGlobal r1, c1 6: LoadGlobal r2, c2 - 9: Add r1, r1, r2 - 13: LoadGlobal r2, c3 - 16: Add r1, r1, r2 - 20: LoadImmediate r1, 3 - 23: StoreGlobal r1, c1 - 26: LoadImmediate r1, 5 - 29: StoreGlobal r1, c3 - 32: LoadUndefined r1 - 34: Ret r1 + 9: Add r1, r1, r2, fb0 + 14: LoadGlobal r2, c3 + 17: Add r1, r1, r2, fb1 + 22: LoadImmediate r1, 3 + 25: StoreGlobal r1, c1 + 28: LoadImmediate r1, 5 + 31: StoreGlobal r1, c3 + 34: LoadUndefined r1 + 36: Ret r1 Constant Table: 0: [BytecodeFunction: inner1] 1: [String: globalVar1] @@ -197,11 +197,11 @@ 8: StoreToScope r1, 0, 0 12: LoadGlobal r1, c2 15: LoadGlobal r2, c3 - 18: Add r1, r1, r2 - 22: LoadGlobal r2, c4 - 25: Add r1, r1, r2 - 29: LoadUndefined r1 - 31: Ret r1 + 18: Add r1, r1, r2, fb0 + 23: LoadGlobal r2, c4 + 26: Add r1, r1, r2, fb1 + 31: LoadUndefined r1 + 33: Ret r1 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: inner2] @@ -214,12 +214,12 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadGlobal r1, c0 - 7: Add r0, r0, r1 - 11: LoadGlobal r1, c1 - 14: Add r0, r0, r1 - 18: LoadGlobal r1, c2 - 21: Add r0, r0, r1 - 25: Ret r0 + 7: Add r0, r0, r1, fb0 + 12: LoadGlobal r1, c1 + 15: Add r0, r0, r1, fb1 + 20: LoadGlobal r1, c2 + 23: Add r0, r0, r1, fb2 + 28: Ret r0 Constant Table: 0: [String: globalVar1] 1: [String: globalConst1] @@ -247,9 +247,9 @@ 8: StoreToScope r1, 0, 0 12: LoadFromScope r1, 0, 1 16: LoadFromScope r2, 0, 0 - 20: Add r1, r1, r2 - 24: LoadUndefined r1 - 26: Ret r1 + 20: Add r1, r1, r2, fb0 + 25: LoadUndefined r1 + 27: Ret r1 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: inner2] @@ -263,11 +263,11 @@ 8: StoreToScope r1, 0, 0 12: LoadFromScope r1, 0, 2 16: LoadFromScope r2, 0, 1 - 20: Add r1, r1, r2 - 24: LoadFromScope r2, 0, 0 - 28: Add r1, r1, r2 - 32: LoadUndefined r1 - 34: Ret r1 + 20: Add r1, r1, r2, fb0 + 25: LoadFromScope r2, 0, 0 + 29: Add r1, r1, r2, fb1 + 34: LoadUndefined r1 + 36: Ret r1 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: inner3] @@ -278,11 +278,11 @@ 0: LoadImmediate r0, 4 3: LoadFromScope r1, 0, 2 7: LoadFromScope r2, 0, 1 - 11: Add r1, r1, r2 - 15: LoadFromScope r2, 0, 0 - 19: Add r1, r1, r2 - 23: Add r1, r1, r0 - 27: Ret r1 + 11: Add r1, r1, r2, fb0 + 16: LoadFromScope r2, 0, 0 + 20: Add r1, r1, r2, fb1 + 25: Add r1, r1, r0, fb2 + 30: Ret r1 } [BytecodeFunction: arrowFunctionsCapture] { @@ -326,10 +326,10 @@ 22: StoreToScope r1, 2, 0 26: LoadFromScope r1, 0, 0 30: LoadFromScope r2, 1, 0 - 34: Add r1, r1, r2 - 38: LoadFromScope r2, 2, 0 - 42: Add r1, r1, r2 - 46: Ret r1 + 34: Add r1, r1, r2, fb0 + 39: LoadFromScope r2, 2, 0 + 43: Add r1, r1, r2, fb1 + 48: Ret r1 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: inner] @@ -339,10 +339,10 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadFromScope r1, 1, 0 - 8: Add r0, r0, r1 - 12: LoadFromScope r1, 2, 0 - 16: Add r0, r0, r1 - 20: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: LoadFromScope r1, 2, 0 + 17: Add r0, r0, r1, fb1 + 22: Ret r0 } [BytecodeFunction: blockScopes] { @@ -384,14 +384,14 @@ 0: LoadFromScope r0, 0, 3 4: LoadFromScope r1, 0, 2 8: CheckTdz r1, c0 - 11: Add r0, r0, r1 - 15: LoadFromScope r1, 0, 1 - 19: CheckTdz r1, c1 - 22: Add r0, r0, r1 - 26: LoadFromScope r1, 0, 0 - 30: CheckTdz r1, c2 - 33: Add r0, r0, r1 - 37: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: LoadFromScope r1, 0, 1 + 20: CheckTdz r1, c1 + 23: Add r0, r0, r1, fb1 + 28: LoadFromScope r1, 0, 0 + 32: CheckTdz r1, c2 + 35: Add r0, r0, r1, fb2 + 40: Ret r0 Constant Table: 0: [String: v2] 1: [String: v3] diff --git a/tests/js_bytecode/scope/captured_this.exp b/tests/js_bytecode/scope/captured_this.exp index f84bb4bd..81e8f5d6 100644 --- a/tests/js_bytecode/scope/captured_this.exp +++ b/tests/js_bytecode/scope/captured_this.exp @@ -21,8 +21,8 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadFromScope r1, 1, 0 - 7: Add r0, r0, r1 - 11: Ret r0 + 7: Add r0, r0, r1, fb0 + 12: Ret r0 } [BytecodeFunction: capturedFunctionThis] { @@ -44,16 +44,16 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 2 3: LoadFromScope r1, 0, 0 - 7: Add r0, r0, r1 - 11: Ret r0 + 7: Add r0, r0, r1, fb0 + 12: Ret r0 } [BytecodeFunction: ] { Parameters: 0, Registers: 2 0: LoadImmediate r0, 3 3: NewClosure r1, c0 - 6: Add r0, r0, r1 - 10: Ret r0 + 6: Add r0, r0, r1, fb0 + 11: Ret r0 Constant Table: 0: [BytecodeFunction: ] } @@ -62,8 +62,8 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 4 3: NewClosure r1, c0 - 6: Add r0, r0, r1 - 10: Ret r0 + 6: Add r0, r0, r1, fb0 + 11: Ret r0 Constant Table: 0: [BytecodeFunction: ] } @@ -72,8 +72,8 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 5 3: LoadFromScope r1, 0, 0 - 7: Add r0, r0, r1 - 11: Ret r0 + 7: Add r0, r0, r1, fb0 + 12: Ret r0 } [BytecodeFunction: noCapture] { diff --git a/tests/js_bytecode/scope/catch.exp b/tests/js_bytecode/scope/catch.exp index 4c54a55d..5e25200a 100644 --- a/tests/js_bytecode/scope/catch.exp +++ b/tests/js_bytecode/scope/catch.exp @@ -85,8 +85,8 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -128,19 +128,19 @@ Parameters: 0, Registers: 4 0: Mov r2, 3: LoadImmediate r3, 1 - 6: Jump 28 (.L0) + 6: Jump 29 (.L0) 8: Mov , r2 11: PushLexicalScope c0 13: LoadEmpty r3 15: StoreToScope r3, 0, 0 19: NewClosure r1, c1 22: LoadImmediate r3, 1 - 25: Add r3, r3, r0 - 29: StoreToScope r3, 0, 0 - 33: PopScope + 25: Add r3, r3, r0, fb0 + 30: StoreToScope r3, 0, 0 + 34: PopScope .L0: - 34: LoadUndefined r2 - 36: Ret r2 + 35: LoadUndefined r2 + 37: Ret r2 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: inner] diff --git a/tests/js_bytecode/scope/for.exp b/tests/js_bytecode/scope/for.exp index 13ce84a6..2f0a77f3 100644 --- a/tests/js_bytecode/scope/for.exp +++ b/tests/js_bytecode/scope/for.exp @@ -23,32 +23,32 @@ .L0: 3: LoadImmediate r4, 10 6: LessThan r4, r2, r4 - 10: JumpFalse r4, 25 (.L1) + 10: JumpFalse r4, 26 (.L1) 13: LoadEmpty r3 15: CheckTdz r3, c0 - 18: Add r4, r2, r3 - 22: LoadImmediate r3, 0 - 25: ToNumeric r2, r2 - 28: Mov r4, r2 - 31: Inc r2 - 33: Jump -30 (.L0) + 18: Add r4, r2, r3, fb0 + 23: LoadImmediate r3, 0 + 26: ToNumeric r2, r2 + 29: Mov r4, r2 + 32: Inc r2 + 34: Jump -31 (.L0) .L1: - 35: LoadImmediate r0, 1 + 36: LoadImmediate r0, 1 .L2: - 38: LoadImmediate r4, 10 - 41: LessThan r4, r0, r4 - 45: JumpFalse r4, 25 (.L3) - 48: LoadEmpty r1 - 50: CheckTdz r1, c0 - 53: Add r4, r0, r1 - 57: LoadImmediate r1, 0 - 60: ToNumeric r0, r0 - 63: Mov r4, r0 - 66: Inc r0 - 68: Jump -30 (.L2) + 39: LoadImmediate r4, 10 + 42: LessThan r4, r0, r4 + 46: JumpFalse r4, 26 (.L3) + 49: LoadEmpty r1 + 51: CheckTdz r1, c0 + 54: Add r4, r0, r1, fb1 + 59: LoadImmediate r1, 0 + 62: ToNumeric r0, r0 + 65: Mov r4, r0 + 68: Inc r0 + 70: Jump -31 (.L2) .L3: - 70: LoadUndefined r4 - 72: Ret r4 + 72: LoadUndefined r4 + 74: Ret r4 Constant Table: 0: [String: inner] } @@ -94,7 +94,7 @@ 20: CheckTdz r1, c1 23: LoadImmediate r2, 10 26: LessThan r1, r1, r2 - 30: JumpFalse r1, 50 (.L1) + 30: JumpFalse r1, 51 (.L1) 33: PushLexicalScope c2 35: LoadEmpty r1 37: StoreToScope r1, 0, 0 @@ -106,15 +106,15 @@ 53: LoadFromScope r1, 0, 0 57: CheckTdz r1, c1 60: LoadImmediate r2, 1 - 63: Add r1, r1, r2 - 67: LoadFromScope r2, 0, 0 - 71: CheckTdz r2, c1 - 74: StoreToScope r1, 0, 0 - 78: Jump -62 (.L0) + 63: Add r1, r1, r2, fb0 + 68: LoadFromScope r2, 0, 0 + 72: CheckTdz r2, c1 + 75: StoreToScope r1, 0, 0 + 79: Jump -63 (.L0) .L1: - 80: PopScope - 81: LoadUndefined r1 - 83: Ret r1 + 81: PopScope + 82: LoadUndefined r1 + 84: Ret r1 Constant Table: 0: [ScopeNames] 1: [String: x] @@ -128,8 +128,8 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: Ret r0 Constant Table: 0: [String: x] 1: [String: y] diff --git a/tests/js_bytecode/scope/for_break.exp b/tests/js_bytecode/scope/for_break.exp index 57ca75aa..b0ae6c69 100644 --- a/tests/js_bytecode/scope/for_break.exp +++ b/tests/js_bytecode/scope/for_break.exp @@ -78,11 +78,11 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: LoadFromScope r1, 0, 0 - 22: CheckTdz r1, c2 - 25: Add r0, r0, r1 - 29: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: LoadFromScope r1, 0, 0 + 23: CheckTdz r1, c2 + 26: Add r0, r0, r1, fb1 + 31: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -137,8 +137,8 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -192,11 +192,11 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1 - 15: LoadFromScope r1, 0, 0 - 19: CheckTdz r1, c1 - 22: Add r0, r0, r1 - 26: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: LoadFromScope r1, 0, 0 + 20: CheckTdz r1, c1 + 23: Add r0, r0, r1, fb1 + 28: Ret r0 Constant Table: 0: [String: y] 1: [String: z] @@ -242,11 +242,11 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 1 4: LoadFromScope r1, 1, 1 - 8: Add r0, r0, r1 - 12: LoadFromScope r1, 0, 0 - 16: CheckTdz r1, c0 - 19: Add r0, r0, r1 - 23: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: LoadFromScope r1, 0, 0 + 17: CheckTdz r1, c0 + 20: Add r0, r0, r1, fb1 + 25: Ret r0 Constant Table: 0: [String: z] } diff --git a/tests/js_bytecode/scope/for_continue.exp b/tests/js_bytecode/scope/for_continue.exp index 00740318..93e99f72 100644 --- a/tests/js_bytecode/scope/for_continue.exp +++ b/tests/js_bytecode/scope/for_continue.exp @@ -76,11 +76,11 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: LoadFromScope r1, 0, 0 - 22: CheckTdz r1, c2 - 25: Add r0, r0, r1 - 29: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: LoadFromScope r1, 0, 0 + 23: CheckTdz r1, c2 + 26: Add r0, r0, r1, fb1 + 31: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -133,8 +133,8 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -189,11 +189,11 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1 - 15: LoadFromScope r1, 0, 0 - 19: CheckTdz r1, c1 - 22: Add r0, r0, r1 - 26: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: LoadFromScope r1, 0, 0 + 20: CheckTdz r1, c1 + 23: Add r0, r0, r1, fb1 + 28: Ret r0 Constant Table: 0: [String: y] 1: [String: z] @@ -240,11 +240,11 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 1 4: LoadFromScope r1, 1, 1 - 8: Add r0, r0, r1 - 12: LoadFromScope r1, 0, 0 - 16: CheckTdz r1, c0 - 19: Add r0, r0, r1 - 23: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: LoadFromScope r1, 0, 0 + 17: CheckTdz r1, c0 + 20: Add r0, r0, r1, fb1 + 25: Ret r0 Constant Table: 0: [String: z] } diff --git a/tests/js_bytecode/scope/for_in.exp b/tests/js_bytecode/scope/for_in.exp index eb083cf5..516ffd57 100644 --- a/tests/js_bytecode/scope/for_in.exp +++ b/tests/js_bytecode/scope/for_in.exp @@ -24,20 +24,20 @@ [BytecodeFunction: startScope] { Parameters: 0, Registers: 4 0: NewObject r2 - 2: JumpNullish r2, 29 (.L1) + 2: JumpNullish r2, 30 (.L1) 5: NewForInIterator r2, r2 .L0: 8: ForInNext r3, r2 - 11: JumpNullish r3, 20 (.L1) + 11: JumpNullish r3, 21 (.L1) 14: Mov r0, r3 17: LoadEmpty r1 19: CheckTdz r1, c0 - 22: Add r3, r0, r1 - 26: LoadImmediate r1, 0 - 29: Jump -21 (.L0) + 22: Add r3, r0, r1, fb0 + 27: LoadImmediate r1, 0 + 30: Jump -22 (.L0) .L1: - 31: LoadUndefined r2 - 33: Ret r2 + 32: LoadUndefined r2 + 34: Ret r2 Constant Table: 0: [String: inner] } @@ -83,8 +83,8 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: Ret r0 Constant Table: 0: [String: x] 1: [String: y] diff --git a/tests/js_bytecode/scope/for_in_break.exp b/tests/js_bytecode/scope/for_in_break.exp index 6ef962d8..e90504d0 100644 --- a/tests/js_bytecode/scope/for_in_break.exp +++ b/tests/js_bytecode/scope/for_in_break.exp @@ -83,11 +83,11 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: LoadFromScope r1, 0, 0 - 22: CheckTdz r1, c2 - 25: Add r0, r0, r1 - 29: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: LoadFromScope r1, 0, 0 + 23: CheckTdz r1, c2 + 26: Add r0, r0, r1, fb1 + 31: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -147,8 +147,8 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -204,11 +204,11 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1 - 15: LoadFromScope r1, 0, 0 - 19: CheckTdz r1, c1 - 22: Add r0, r0, r1 - 26: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: LoadFromScope r1, 0, 0 + 20: CheckTdz r1, c1 + 23: Add r0, r0, r1, fb1 + 28: Ret r0 Constant Table: 0: [String: y] 1: [String: z] @@ -256,11 +256,11 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 1 4: LoadFromScope r1, 1, 1 - 8: Add r0, r0, r1 - 12: LoadFromScope r1, 0, 0 - 16: CheckTdz r1, c0 - 19: Add r0, r0, r1 - 23: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: LoadFromScope r1, 0, 0 + 17: CheckTdz r1, c0 + 20: Add r0, r0, r1, fb1 + 25: Ret r0 Constant Table: 0: [String: z] } diff --git a/tests/js_bytecode/scope/for_in_continue.exp b/tests/js_bytecode/scope/for_in_continue.exp index 6a727e4f..2116b7ac 100644 --- a/tests/js_bytecode/scope/for_in_continue.exp +++ b/tests/js_bytecode/scope/for_in_continue.exp @@ -82,11 +82,11 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: LoadFromScope r1, 0, 0 - 22: CheckTdz r1, c2 - 25: Add r0, r0, r1 - 29: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: LoadFromScope r1, 0, 0 + 23: CheckTdz r1, c2 + 26: Add r0, r0, r1, fb1 + 31: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -145,8 +145,8 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -202,11 +202,11 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1 - 15: LoadFromScope r1, 0, 0 - 19: CheckTdz r1, c1 - 22: Add r0, r0, r1 - 26: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: LoadFromScope r1, 0, 0 + 20: CheckTdz r1, c1 + 23: Add r0, r0, r1, fb1 + 28: Ret r0 Constant Table: 0: [String: y] 1: [String: z] @@ -254,11 +254,11 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 1 4: LoadFromScope r1, 1, 1 - 8: Add r0, r0, r1 - 12: LoadFromScope r1, 0, 0 - 16: CheckTdz r1, c0 - 19: Add r0, r0, r1 - 23: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: LoadFromScope r1, 0, 0 + 17: CheckTdz r1, c0 + 20: Add r0, r0, r1, fb1 + 25: Ret r0 Constant Table: 0: [String: z] } diff --git a/tests/js_bytecode/scope/for_of.exp b/tests/js_bytecode/scope/for_of.exp index f0fe1abf..09ab533f 100644 --- a/tests/js_bytecode/scope/for_of.exp +++ b/tests/js_bytecode/scope/for_of.exp @@ -27,28 +27,28 @@ 2: GetIterator r2, r3, r4 .L0: 6: IteratorNext r4, r5, r2, r3 - 11: JumpTrue r5, 35 (.L2) + 11: JumpTrue r5, 36 (.L2) 14: Mov r0, r4 17: Mov r6, 20: LoadEmpty r1 22: CheckTdz r1, c0 - 25: Add r7, r0, r1 - 29: LoadImmediate r1, 0 - 32: Jump 12 (.L1) - 34: LoadImmediate r4, 0 - 37: Mov , r6 - 40: IteratorClose r2 - 42: Throw r5 + 25: Add r7, r0, r1, fb0 + 30: LoadImmediate r1, 0 + 33: Jump 12 (.L1) + 35: LoadImmediate r4, 0 + 38: Mov , r6 + 41: IteratorClose r2 + 43: Throw r5 .L1: - 44: Jump -38 (.L0) + 45: Jump -39 (.L0) .L2: - 46: LoadUndefined r2 - 48: Ret r2 + 47: LoadUndefined r2 + 49: Ret r2 Constant Table: 0: [String: inner] Exception Handlers: - 14-32 -> 34 (r5) - 40-42 -> 42 + 14-33 -> 35 (r5) + 41-43 -> 43 } [BytecodeFunction: captures] { @@ -101,8 +101,8 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: Ret r0 Constant Table: 0: [String: x] 1: [String: y] diff --git a/tests/js_bytecode/scope/for_of_break.exp b/tests/js_bytecode/scope/for_of_break.exp index b2a9bc9a..b67dfa57 100644 --- a/tests/js_bytecode/scope/for_of_break.exp +++ b/tests/js_bytecode/scope/for_of_break.exp @@ -96,11 +96,11 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: LoadFromScope r1, 0, 0 - 22: CheckTdz r1, c2 - 25: Add r0, r0, r1 - 29: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: LoadFromScope r1, 0, 0 + 23: CheckTdz r1, c2 + 26: Add r0, r0, r1, fb1 + 31: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -179,11 +179,11 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1 - 15: LoadFromScope r1, 0, 0 - 19: CheckTdz r1, c1 - 22: Add r0, r0, r1 - 26: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: LoadFromScope r1, 0, 0 + 20: CheckTdz r1, c1 + 23: Add r0, r0, r1, fb1 + 28: Ret r0 Constant Table: 0: [String: y] 1: [String: z] diff --git a/tests/js_bytecode/scope/for_of_continue.exp b/tests/js_bytecode/scope/for_of_continue.exp index afff9456..4bd077f7 100644 --- a/tests/js_bytecode/scope/for_of_continue.exp +++ b/tests/js_bytecode/scope/for_of_continue.exp @@ -83,11 +83,11 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: LoadFromScope r1, 0, 0 - 22: CheckTdz r1, c2 - 25: Add r0, r0, r1 - 29: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: LoadFromScope r1, 0, 0 + 23: CheckTdz r1, c2 + 26: Add r0, r0, r1, fb1 + 31: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -153,11 +153,11 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1 - 15: LoadFromScope r1, 0, 0 - 19: CheckTdz r1, c1 - 22: Add r0, r0, r1 - 26: Ret r0 + 11: Add r0, r0, r1, fb0 + 16: LoadFromScope r1, 0, 0 + 20: CheckTdz r1, c1 + 23: Add r0, r0, r1, fb1 + 28: Ret r0 Constant Table: 0: [String: y] 1: [String: z] diff --git a/tests/js_bytecode/scope/function.exp b/tests/js_bytecode/scope/function.exp index 5221e09a..167d399c 100644 --- a/tests/js_bytecode/scope/function.exp +++ b/tests/js_bytecode/scope/function.exp @@ -23,11 +23,11 @@ 2: LoadEmpty r1 4: CheckTdz r0, c0 7: CheckTdz r1, c1 - 10: Add r2, r0, r1 - 14: LoadImmediate r0, 1 - 17: LoadImmediate r1, 2 - 20: LoadUndefined r2 - 22: Ret r2 + 10: Add r2, r0, r1, fb0 + 15: LoadImmediate r0, 1 + 18: LoadImmediate r1, 2 + 21: LoadUndefined r2 + 23: Ret r2 Constant Table: 0: [String: x] 1: [String: y] @@ -90,10 +90,10 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadFromScope r1, 1, 0 - 8: Add r0, r0, r1 - 12: LoadFromScope r1, 2, 0 - 16: Add r0, r0, r1 - 20: LoadFromScope r1, 3, 0 - 24: Add r0, r0, r1 - 28: Ret r0 + 8: Add r0, r0, r1, fb0 + 13: LoadFromScope r1, 2, 0 + 17: Add r0, r0, r1, fb1 + 22: LoadFromScope r1, 3, 0 + 26: Add r0, r0, r1, fb2 + 31: Ret r0 } diff --git a/tests/js_bytecode/scope/function_body.exp b/tests/js_bytecode/scope/function_body.exp index 04def420..405f480f 100644 --- a/tests/js_bytecode/scope/function_body.exp +++ b/tests/js_bytecode/scope/function_body.exp @@ -39,9 +39,9 @@ .L1: 12: LoadImmediate r0, 2 15: LoadImmediate r1, 3 - 18: Add r1, r0, r1 - 22: LoadUndefined r1 - 24: Ret r1 + 18: Add r1, r0, r1, fb0 + 23: LoadUndefined r1 + 25: Ret r1 } [BytecodeFunction: sameNameCaptureParamOnly] { @@ -56,9 +56,9 @@ .L1: 18: LoadImmediate r0, 2 21: LoadImmediate r1, 3 - 24: Add r1, r0, r1 - 28: LoadUndefined r1 - 30: Ret r1 + 24: Add r1, r0, r1, fb0 + 29: LoadUndefined r1 + 31: Ret r1 Constant Table: 0: [ScopeNames] 1: [BytecodeFunction: y] diff --git a/tests/js_bytecode/scope/labeled_break.exp b/tests/js_bytecode/scope/labeled_break.exp index 9b66b7fc..3d088e54 100644 --- a/tests/js_bytecode/scope/labeled_break.exp +++ b/tests/js_bytecode/scope/labeled_break.exp @@ -122,11 +122,11 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: LoadFromScope r1, 0, 0 - 22: CheckTdz r1, c2 - 25: Add r0, r0, r1 - 29: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: LoadFromScope r1, 0, 0 + 23: CheckTdz r1, c2 + 26: Add r0, r0, r1, fb1 + 31: Ret r0 Constant Table: 0: [String: x] 1: [String: y] diff --git a/tests/js_bytecode/scope/switch.exp b/tests/js_bytecode/scope/switch.exp index 4013ae33..369fcfc3 100644 --- a/tests/js_bytecode/scope/switch.exp +++ b/tests/js_bytecode/scope/switch.exp @@ -31,22 +31,22 @@ 14: JumpTrue r3, 25 (.L0) 17: LoadImmediate r3, 2 20: StrictEqual r3, r2, r3 - 24: JumpTrue r3, 25 (.L1) + 24: JumpTrue r3, 26 (.L1) 27: LoadImmediate r3, 3 30: StrictEqual r3, r2, r3 - 34: JumpTrue r3, 17 (.L2) - 37: Jump 16 (.L3) + 34: JumpTrue r3, 18 (.L2) + 37: Jump 17 (.L3) .L0: 39: CheckTdz r0, c0 42: CheckTdz r1, c1 - 45: Add r2, r0, r1 + 45: Add r2, r0, r1, fb0 .L1: - 49: LoadTrue r0 + 50: LoadTrue r0 .L2: - 51: LoadFalse r1 + 52: LoadFalse r1 .L3: - 53: LoadUndefined r2 - 55: Ret r2 + 54: LoadUndefined r2 + 56: Ret r2 Constant Table: 0: [String: x] 1: [String: y] @@ -137,8 +137,8 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: Ret r0 Constant Table: 0: [String: x] 1: [String: y] diff --git a/tests/js_bytecode/scope/with.exp b/tests/js_bytecode/scope/with.exp index 8912b226..e718a699 100644 --- a/tests/js_bytecode/scope/with.exp +++ b/tests/js_bytecode/scope/with.exp @@ -54,8 +54,8 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 1, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: Ret r0 Constant Table: 0: [String: x] 1: [String: y] @@ -75,23 +75,23 @@ 31: PushWithScope r1, c1 34: LoadDynamic r1, c2 37: LoadImmediate r2, 2 - 40: Add r1, r1, r2 - 44: LoadImmediate r1, 0 - 47: StoreDynamic r1, c2 - 50: LoadImmediate r0, 3 - 53: LoadImmediate r1, 4 - 56: Add r1, r0, r1 - 60: LoadDynamic r1, c3 - 63: LoadImmediate r2, 5 - 66: Add r1, r1, r2 - 70: LoadImmediate r1, 6 - 73: Add r1, r0, r1 - 77: LoadDynamic r1, c3 - 80: LoadImmediate r2, 7 - 83: Add r1, r1, r2 - 87: PopScope - 88: LoadUndefined r1 - 90: Ret r1 + 40: Add r1, r1, r2, fb0 + 45: LoadImmediate r1, 0 + 48: StoreDynamic r1, c2 + 51: LoadImmediate r0, 3 + 54: LoadImmediate r1, 4 + 57: Add r1, r0, r1, fb1 + 62: LoadDynamic r1, c3 + 65: LoadImmediate r2, 5 + 68: Add r1, r1, r2, fb2 + 73: LoadImmediate r1, 6 + 76: Add r1, r0, r1, fb3 + 81: LoadDynamic r1, c3 + 84: LoadImmediate r2, 7 + 87: Add r1, r1, r2, fb4 + 92: PopScope + 93: LoadUndefined r1 + 95: Ret r1 Constant Table: 0: [ScopeNames] 1: [ScopeNames] diff --git a/tests/js_bytecode/statement/const_let_declaration.exp b/tests/js_bytecode/statement/const_let_declaration.exp index 1badd594..e17b9a41 100644 --- a/tests/js_bytecode/statement/const_let_declaration.exp +++ b/tests/js_bytecode/statement/const_let_declaration.exp @@ -36,15 +36,15 @@ 108: CheckTdz r0, c16 111: LoadFromScope r1, 5, 0 115: CheckTdz r1, c17 - 118: Add r0, r0, r1 - 122: StoreToScope r0, 9, 0 - 126: LoadFromScope r0, 11, 0 - 130: CheckTdz r0, c18 - 133: StoreToScope r0, 10, 0 - 137: LoadImmediate r0, 1 - 140: StoreToScope r0, 11, 0 - 144: LoadUndefined r0 - 146: Ret r0 + 118: Add r0, r0, r1, fb0 + 123: StoreToScope r0, 9, 0 + 127: LoadFromScope r0, 11, 0 + 131: CheckTdz r0, c18 + 134: StoreToScope r0, 10, 0 + 138: LoadImmediate r0, 1 + 141: StoreToScope r0, 11, 0 + 145: LoadUndefined r0 + 147: Ret r0 Constant Table: 0: [BytecodeFunction: tdzGlobals] 1: [String: tdzGlobals] @@ -90,8 +90,8 @@ 0: LoadImmediate r2, 3 3: LoadImmediate r0, 1 6: LoadImmediate r1, 2 - 9: Add r2, r0, r1 - 13: Ret r2 + 9: Add r2, r0, r1, fb0 + 14: Ret r2 } [BytecodeFunction: tdzLocals] { @@ -102,16 +102,16 @@ 6: LoadImmediate r5, 3 9: CheckTdz r1, c0 12: CheckTdz r2, c1 - 15: Add r0, r1, r2 - 19: LoadImmediate r1, 1 - 22: LoadImmediate r2, 1 - 25: CheckTdz r4, c2 - 28: Mov r3, r4 - 31: LoadImmediate r4, 2 - 34: CheckTdz r1, c0 - 37: CheckTdz r2, c1 - 40: Add r5, r1, r2 - 44: Ret r5 + 15: Add r0, r1, r2, fb0 + 20: LoadImmediate r1, 1 + 23: LoadImmediate r2, 1 + 26: CheckTdz r4, c2 + 29: Mov r3, r4 + 32: LoadImmediate r4, 2 + 35: CheckTdz r1, c0 + 38: CheckTdz r2, c1 + 41: Add r5, r1, r2, fb1 + 46: Ret r5 Constant Table: 0: [String: c1] 1: [String: l1] @@ -136,9 +136,9 @@ Parameters: 0, Registers: 2 0: LoadUndefined r0 2: LoadImmediate r1, 2 - 5: Add r1, r0, r1 - 9: LoadUndefined r1 - 11: Ret r1 + 5: Add r1, r0, r1, fb0 + 10: LoadUndefined r1 + 12: Ret r1 } [BytecodeFunction: assigningConst] { diff --git a/tests/js_bytecode/statement/lexical_declaration.exp b/tests/js_bytecode/statement/lexical_declaration.exp index ace9ab85..7e92f184 100644 --- a/tests/js_bytecode/statement/lexical_declaration.exp +++ b/tests/js_bytecode/statement/lexical_declaration.exp @@ -57,11 +57,11 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 1, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: LoadFromScope r1, 2, 0 - 22: CheckTdz r1, c2 - 25: Add r0, r0, r1 - 29: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: LoadFromScope r1, 2, 0 + 23: CheckTdz r1, c2 + 26: Add r0, r0, r1, fb1 + 31: Ret r0 Constant Table: 0: [String: l1] 1: [String: l2] diff --git a/tests/js_bytecode/statement/try/catch.exp b/tests/js_bytecode/statement/try/catch.exp index 859aaa6f..edda8ad2 100644 --- a/tests/js_bytecode/statement/try/catch.exp +++ b/tests/js_bytecode/statement/try/catch.exp @@ -38,14 +38,14 @@ 0: LoadImmediate r1, 1 3: Mov r1, 6: LoadImmediate r2, 2 - 9: Jump 12 (.L0) + 9: Jump 13 (.L0) 11: Mov , r1 14: LoadImmediate r2, 3 - 17: Add r2, r2, r0 + 17: Add r2, r2, r0, fb0 .L0: - 21: LoadImmediate r1, 4 - 24: LoadUndefined r1 - 26: Ret r1 + 22: LoadImmediate r1, 4 + 25: LoadUndefined r1 + 27: Ret r1 Exception Handlers: 6-9 -> 11 (r0) } diff --git a/tests/js_bytecode/statement/try/finally_break.exp b/tests/js_bytecode/statement/try/finally_break.exp index c632698b..88e3879c 100644 --- a/tests/js_bytecode/statement/try/finally_break.exp +++ b/tests/js_bytecode/statement/try/finally_break.exp @@ -262,11 +262,11 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: LoadFromScope r1, 0, 0 - 22: CheckTdz r1, c2 - 25: Add r0, r0, r1 - 29: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: LoadFromScope r1, 0, 0 + 23: CheckTdz r1, c2 + 26: Add r0, r0, r1, fb1 + 31: Ret r0 Constant Table: 0: [String: s1] 1: [String: s2] diff --git a/tests/js_bytecode/statement/try/finally_continue.exp b/tests/js_bytecode/statement/try/finally_continue.exp index 814c9004..61c7a6ae 100644 --- a/tests/js_bytecode/statement/try/finally_continue.exp +++ b/tests/js_bytecode/statement/try/finally_continue.exp @@ -262,11 +262,11 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1 - 18: LoadFromScope r1, 0, 0 - 22: CheckTdz r1, c2 - 25: Add r0, r0, r1 - 29: Ret r0 + 14: Add r0, r0, r1, fb0 + 19: LoadFromScope r1, 0, 0 + 23: CheckTdz r1, c2 + 26: Add r0, r0, r1, fb1 + 31: Ret r0 Constant Table: 0: [String: s1] 1: [String: s2] diff --git a/tests/js_bytecode/statement/var_declaration.exp b/tests/js_bytecode/statement/var_declaration.exp index 7c36b975..8e934927 100644 --- a/tests/js_bytecode/statement/var_declaration.exp +++ b/tests/js_bytecode/statement/var_declaration.exp @@ -33,8 +33,8 @@ 0: LoadImmediate r2, 3 3: LoadImmediate r0, 1 6: LoadImmediate r1, 2 - 9: Add r2, r0, r1 - 13: Ret r2 + 9: Add r2, r0, r1, fb0 + 14: Ret r2 } [BytecodeFunction: testDuplicates] { @@ -50,13 +50,13 @@ 0: LoadImmediate r0, 1 3: LoadImmediate r4, 1 6: LoadImmediate r5, 2 - 9: Add r4, r4, r5 - 13: LoadImmediate r5, 3 - 16: Add r1, r4, r5 - 20: Mov r2, a0 - 23: LoadGlobal r3, c0 - 26: LoadUndefined r4 - 28: Ret r4 + 9: Add r4, r4, r5, fb0 + 14: LoadImmediate r5, 3 + 17: Add r1, r4, r5, fb1 + 22: Mov r2, a0 + 25: LoadGlobal r3, c0 + 28: LoadUndefined r4 + 30: Ret r4 Constant Table: 0: [String: y] } diff --git a/tests/js_bytecode/statement/with.exp b/tests/js_bytecode/statement/with.exp index 9618bdea..c1a945fc 100644 --- a/tests/js_bytecode/statement/with.exp +++ b/tests/js_bytecode/statement/with.exp @@ -60,17 +60,17 @@ 30: StoreDynamic r0, c2 33: LoadDynamic r0, c2 36: LoadImmediate r1, 2 - 39: Add r0, r0, r1 - 43: LoadImmediate r0, 3 - 46: StoreDynamic r0, c2 - 49: PopScope - 50: LoadDynamic r0, c2 - 53: LoadImmediate r1, 4 - 56: Add r0, r0, r1 - 60: LoadImmediate r0, 5 - 63: StoreDynamic r0, c2 - 66: LoadUndefined r0 - 68: Ret r0 + 39: Add r0, r0, r1, fb0 + 44: LoadImmediate r0, 3 + 47: StoreDynamic r0, c2 + 50: PopScope + 51: LoadDynamic r0, c2 + 54: LoadImmediate r1, 4 + 57: Add r0, r0, r1, fb1 + 62: LoadImmediate r0, 5 + 65: StoreDynamic r0, c2 + 68: LoadUndefined r0 + 70: Ret r0 Constant Table: 0: [ScopeNames] 1: [ScopeNames] From 7d3655dacd2b7d7637fae8f34a6e68ac112ee36d Mon Sep 17 00:00:00 2001 From: vrindisbacher Date: Wed, 20 May 2026 09:22:39 -0700 Subject: [PATCH 03/11] set up IC stubs as separate bytecode instead of feedback --- src/js/runtime/bytecode/function.rs | 8 +- src/js/runtime/bytecode/generator.rs | 54 ++++---- src/js/runtime/bytecode/instruction.rs | 4 +- src/js/runtime/bytecode/operand.rs | 8 +- src/js/runtime/bytecode/stack_frame.rs | 44 ++++--- src/js/runtime/bytecode/vm.rs | 169 ++++++++++++------------- src/js/runtime/gc/heap_item.rs | 8 +- src/js/runtime/heap_item_descriptor.rs | 8 +- src/js/runtime/ic/bytecode.rs | 150 ++++++++++++++++++++++ src/js/runtime/ic/feedback.rs | 110 ---------------- src/js/runtime/ic/mod.rs | 4 +- src/js/runtime/ic/stubs.rs | 62 +++++++++ src/js/runtime/ic/vector.rs | 77 +++++++++++ 13 files changed, 445 insertions(+), 261 deletions(-) create mode 100644 src/js/runtime/ic/bytecode.rs delete mode 100644 src/js/runtime/ic/feedback.rs create mode 100644 src/js/runtime/ic/stubs.rs create mode 100644 src/js/runtime/ic/vector.rs diff --git a/src/js/runtime/bytecode/function.rs b/src/js/runtime/bytecode/function.rs index 860bcaab..02240d2b 100644 --- a/src/js/runtime/bytecode/function.rs +++ b/src/js/runtime/bytecode/function.rs @@ -11,7 +11,7 @@ use crate::{ function::{set_function_length, set_function_name}, gc::{HeapItem, HeapVisitor}, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::feedback::FeedbackVector, + ic::vector::ICVector, intrinsics::{intrinsics::Intrinsic, rust_runtime::RuntimeFunctionId}, object_value::ObjectValue, ordinary_object::{ @@ -254,7 +254,7 @@ pub struct BytecodeFunction { /// function has an empty bytecode array and default values for many other fields. runtime_function_id: Option, /// Feedback vector for IC stubs - feedback_vector: Option>, + feedback_vector: Option>, /// Inlined bytecode array for the function. bytecode: InlineArray, } @@ -279,7 +279,7 @@ impl BytecodeFunction { name: Option>, source_file: Handle, source_map: Handle, - feedback_vector: Option>, + feedback_vector: Option>, ) -> AllocResult> { let size = Self::calculate_size_in_bytes(bytecode.len()); let mut object = cx.alloc_uninit_with_size::(size)?; @@ -368,7 +368,7 @@ impl BytecodeFunction { } #[inline] - pub fn feedback_vector_ptr(&self) -> Option> { + pub fn feedback_vector_ptr(&self) -> Option> { self.feedback_vector } diff --git a/src/js/runtime/bytecode/generator.rs b/src/js/runtime/bytecode/generator.rs index ea8815ba..7a88e3fa 100644 --- a/src/js/runtime/bytecode/generator.rs +++ b/src/js/runtime/bytecode/generator.rs @@ -34,7 +34,7 @@ use crate::{ bytecode::{ function::{dump_bytecode_function, BytecodeFunction}, instruction::DefinePropertyFlags, - operand::FeedbackSlotIndex, + operand::ICSlotIndex, source_map::BytecodeSourceMap, }, class_names::{ClassNames, HomeObjectLocation, Method}, @@ -43,7 +43,7 @@ use crate::{ gc::Escapable, global_names::GlobalNames, heap_item_descriptor::HeapItemKind, - ic::feedback::{FeedbackSlot, FeedbackVector}, + ic::vector::ICVector, interned_strings::InternedStrings, module::{ import_attributes::ImportAttributes, @@ -1105,8 +1105,13 @@ pub struct BytecodeFunctionGenerator<'a> { /// Queue of functions that still need to be generated. pending_functions_queue: PendingFunctionNodes<'a>, - /// The feedback slots to allocate for this function - feedback_slots: Vec, + /// The number of IC Stubs to allocate in the + /// ICVector. Since ICStubs are generic, every + /// single one will initially be instantiated as + /// `None`. Then, when we hit the opcode in the VM + /// we will generate ICs, changing the slot in the ICVector + /// from `None` to the concrete stub + num_ic_slots: u32, } impl<'a> BytecodeFunctionGenerator<'a> { @@ -1165,7 +1170,7 @@ impl<'a> BytecodeFunctionGenerator<'a> { register_allocator: TemporaryRegisterAllocator::new(num_local_registers), exception_handler_builder: ExceptionHandlersBuilder::new(), pending_functions_queue: vec![], - feedback_slots: vec![], + num_ic_slots: 0, } } @@ -1249,11 +1254,10 @@ impl<'a> BytecodeFunctionGenerator<'a> { )) } - fn add_feedback_index_slot(&mut self, slot_kind: FeedbackSlot) -> u32 { - let slot_offset = self.feedback_slots.len(); - self.feedback_slots.push(slot_kind); - debug_assert!(slot_offset <= (u32::MAX as usize)); - slot_offset as u32 + fn add_ic_stub(&mut self) -> u32 { + let offset = self.num_ic_slots; + self.num_ic_slots += 1; + offset } fn new_for_program( @@ -2011,10 +2015,10 @@ impl<'a> BytecodeFunctionGenerator<'a> { let source_positions_object = BytecodeSourceMap::new(self.cx, &source_positions)?; - let feedback_vector = if self.feedback_slots.is_empty() { + let ic_vector = if self.num_ic_slots == 0 { None } else { - Some(FeedbackVector::new(self.cx, &self.feedback_slots)?) + Some(ICVector::new(self.cx, self.num_ic_slots as usize)?) }; let bytecode_function = BytecodeFunction::new( @@ -2036,7 +2040,7 @@ impl<'a> BytecodeFunctionGenerator<'a> { name, self.source_file, source_positions_object, - feedback_vector, + ic_vector, )?; Ok(EmitFunctionResult { @@ -3359,14 +3363,9 @@ impl<'a> BytecodeFunctionGenerator<'a> { match expr.operator { ast::BinaryOperator::Add => { // Add feedback slot with add type uninitialized - let slot_offset = self.add_feedback_index_slot(FeedbackSlot::add_uninit()); - self.writer.add_instruction( - dest, - left, - right, - FeedbackSlotIndex::new(slot_offset), - pos, - ) + let slot_offset = self.add_ic_stub(); + self.writer + .add_instruction(dest, left, right, ICSlotIndex::new(slot_offset), pos) } ast::BinaryOperator::Subtract => self.writer.sub_instruction(dest, left, right, pos), ast::BinaryOperator::Multiply => self.writer.mul_instruction(dest, left, right, pos), @@ -4771,12 +4770,12 @@ impl<'a> BytecodeFunctionGenerator<'a> { match operator { ast::AssignmentOperator::Add => { - let feedback_slot_offset = self.add_feedback_index_slot(FeedbackSlot::add_uninit()); + let ic_stub_offset = self.add_ic_stub(); self.writer.add_instruction( dest, left, right, - FeedbackSlotIndex::new(feedback_slot_offset), + ICSlotIndex::new(ic_stub_offset), pos, ) } @@ -5957,13 +5956,12 @@ impl<'a> BytecodeFunctionGenerator<'a> { .to_string_instruction(temp, expression_reg, expression_pos); // Cannot throw since both values are guaranteed to be strings - let feedback_slot_offset = - self.add_feedback_index_slot(FeedbackSlot::add_string_concat()); + let ic_stub_offset = self.add_ic_stub(); self.writer.add_instruction( acc, acc, temp, - FeedbackSlotIndex::new(feedback_slot_offset), + ICSlotIndex::new(ic_stub_offset), NO_POS, ); @@ -5989,12 +5987,12 @@ impl<'a> BytecodeFunctionGenerator<'a> { self.writer.load_constant_instruction(temp, constant_index); // Cannot throw since both values are guaranteed to be strings - let slot_offset = self.add_feedback_index_slot(FeedbackSlot::add_string_concat()); + let ic_stub_offset = self.add_ic_stub(); self.writer.add_instruction( acc, acc, temp, - FeedbackSlotIndex::new(slot_offset), + ICSlotIndex::new(ic_stub_offset), NO_POS, ); } diff --git a/src/js/runtime/bytecode/instruction.rs b/src/js/runtime/bytecode/instruction.rs index 619e0e81..19602856 100644 --- a/src/js/runtime/bytecode/instruction.rs +++ b/src/js/runtime/bytecode/instruction.rs @@ -13,7 +13,7 @@ use super::{ use crate::{ count, replace_expr, - runtime::{bytecode::operand::FeedbackSlotIndex, debug_print::DebugPrinter}, + runtime::{bytecode::operand::ICSlotIndex, debug_print::DebugPrinter}, }; /// Generic properties of instructions. @@ -569,7 +569,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, - [3] feedback_slot_offset: FeedbackSlotIndex, + [3] ic_stub_offset: ICSlotIndex, } } diff --git a/src/js/runtime/bytecode/operand.rs b/src/js/runtime/bytecode/operand.rs index b41b4a58..79133439 100644 --- a/src/js/runtime/bytecode/operand.rs +++ b/src/js/runtime/bytecode/operand.rs @@ -124,14 +124,14 @@ operand_type!(SInt, SIGNED); operand_type!(ConstantIndex, UNSIGNED); // An index into a feedback vector -operand_type!(FeedbackSlotIndex, UNSIGNED); +operand_type!(ICSlotIndex, UNSIGNED); pub enum OperandType { Register, UInt, SInt, ConstantIndex, - FeedbackSlotIndex, + ICSlotIndex, } /// Registers may be either registers local to a function or arguments to that function. Registers @@ -315,7 +315,7 @@ impl ConstantIndex { } } -impl FeedbackSlotIndex { +impl ICSlotIndex { #[inline] pub fn new(value: W::UInt) -> Self { Self::from_unsigned(value) @@ -333,7 +333,7 @@ impl fmt::Display for ConstantIndex { } } -impl fmt::Display for FeedbackSlotIndex { +impl fmt::Display for ICSlotIndex { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "fb{}", self.value()) } diff --git a/src/js/runtime/bytecode/stack_frame.rs b/src/js/runtime/bytecode/stack_frame.rs index 08bf089b..07c2d790 100644 --- a/src/js/runtime/bytecode/stack_frame.rs +++ b/src/js/runtime/bytecode/stack_frame.rs @@ -1,8 +1,8 @@ use crate::runtime::{ gc::HeapVisitor, - ic::feedback::{FeedbackSlot, FeedbackVector}, + ic::{stubs::ICStub, vector::ICVector}, scope::Scope, - HeapPtr, Value, + Handle, HeapPtr, Value, }; use super::{constant_table::ConstantTable, function::Closure}; @@ -17,16 +17,16 @@ use super::{constant_table::ConstantTable, function::Closure}; /// | ... | /// +------------------+ /// | arg0 | (first arg) -/// +64 +------------------+ ^ ^ +/// +72 +------------------+ ^ ^ /// | receiver | (receiver) | caller's frame | -/// +56 +------------------+ +----------------+ +/// +64 +------------------+ +----------------+ /// | argc | | callee's frame | -/// +48 +------------------+ v v +/// +56 +------------------+ v v /// | closure | (closure of the caller) -/// +40 +------------------+ +/// +48 +------------------+ /// | constant_table | (constant table of the called closure) /// +40 +------------------+ -/// | feedback_vector | (feedback vector of the called closure) +/// | ic_vector | (ic vector of the called closure) /// +32 +------------------+ /// | scope | (current VM scope) /// +24 +------------------+ @@ -195,26 +195,30 @@ impl StackFrame { } #[inline] - pub fn feedback_vector(&self) -> HeapPtr { - let ptr = unsafe { *self.fp.add(FEEDBACK_VECTOR_SLOT_INDEX) }; - HeapPtr::from_ptr(ptr as *mut FeedbackVector) + pub fn ic_vector(&self) -> HeapPtr { + let ptr = unsafe { *self.fp.add(IC_VECTOR_SLOT_INDEX) }; + HeapPtr::from_ptr(ptr as *mut ICVector) } #[inline] - pub fn feedback_vector_mut(&self) -> &mut HeapPtr { - unsafe { &mut *(self.fp.add(FEEDBACK_VECTOR_SLOT_INDEX) as *mut HeapPtr) } + pub fn ic_vector_mut(&self) -> &mut HeapPtr { + unsafe { &mut *(self.fp.add(IC_VECTOR_SLOT_INDEX) as *mut HeapPtr) } } #[inline] - pub fn get_feedback(&self, slot: usize) -> FeedbackSlot { - *self.feedback_vector().slots().get_unchecked(slot) + pub fn get_ic_stub(&self, slot: usize) -> Option> { + *self.ic_vector().slots().get_unchecked(slot) } #[inline] - pub fn set_feedback(&mut self, slot: usize, value: FeedbackSlot) { - self.feedback_vector() - .slots_mut() - .set_unchecked(slot, value); + pub fn add_ic_stub(&mut self, slot: usize, mut stub: Handle) { + let slots = self.ic_vector_mut().slots_mut(); + let head = slots.get_unchecked_mut(slot); + // Prepend the stub: + // Put the current stub at the beginning of the linked list + // with the original head as the second element + stub.set_next(*head); + *head = Some(*stub); } /// The callee function in this stack frame. @@ -303,7 +307,7 @@ impl StackFrame { visitor.visit_pointer(self.closure_mut()); visitor.visit_pointer(self.constant_table_mut()); - visitor.visit_pointer(self.feedback_vector_mut()); + visitor.visit_pointer(self.ic_vector_mut()); visitor.visit_pointer(self.scope_mut()); } } @@ -344,7 +348,7 @@ pub const SCOPE_SLOT_INDEX: usize = 3; const CONSTANT_TABLE_SLOT_INDEX: usize = 4; -const FEEDBACK_VECTOR_SLOT_INDEX: usize = 5; +const IC_VECTOR_SLOT_INDEX: usize = 5; pub const CLOSURE_SLOT_INDEX: usize = 6; diff --git a/src/js/runtime/bytecode/vm.rs b/src/js/runtime/bytecode/vm.rs index 066db551..05ea4057 100644 --- a/src/js/runtime/bytecode/vm.rs +++ b/src/js/runtime/bytecode/vm.rs @@ -41,7 +41,7 @@ use crate::{ generator_object::{GeneratorCompletionType, GeneratorObject, TGeneratorObject}, get, heap_item_descriptor::HeapItemKind, - ic::feedback::{AddFeedbackState, FeedbackSlot, FeedbackVector}, + ic::{stubs::ICStub, vector::ICVector}, intrinsics::{ async_generator_prototype::AsyncGeneratorPrototype, generator_prototype::GeneratorPrototype, @@ -61,7 +61,6 @@ use crate::{ scope::Scope, scope_names::ScopeNames, source_file::SourceFile, - string_value::StringValue, to_string, type_utilities::{ is_callable, is_callable_object, is_loosely_equal, is_strictly_equal, @@ -223,13 +222,13 @@ impl VM { } #[inline] - fn get_feedback(&self, slot_index: usize) -> FeedbackSlot { - self.stack_frame().get_feedback(slot_index) + fn get_ic_stub(&self, slot_index: usize) -> Option> { + self.stack_frame().get_ic_stub(slot_index) } #[inline] - fn set_feedback(&mut self, slot_index: usize, slot: FeedbackSlot) { - self.stack_frame().set_feedback(slot_index, slot); + fn add_ic_stub(&mut self, slot_index: usize, slot: Handle) { + self.stack_frame().add_ic_stub(slot_index, slot); } pub fn stack_trace_top(&self) -> Option { @@ -2059,7 +2058,7 @@ impl VM { // push the feedback vector let feedback_vector = unsafe { - std::mem::transmute::>, usize>( + std::mem::transmute::>, usize>( bytecode_function.feedback_vector_ptr(), ) }; @@ -2750,89 +2749,87 @@ impl VM { let left_value = self.read_register_to_handle(instr.left()); let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - let slot_index = instr.feedback_slot_offset().value().to_usize(); + let slot_index = instr.ic_stub_offset().value().to_usize(); + + // // this should always be an addop - otherwise something has gone very wrong + // let feedback_slot = self.get_ic_stub(slot_index); + // debug_assert!(matches!(feedback_slot, FeedbackSlot::AddOp(_))); + + // // see if we should update feedback - this is only the case + // // if we see that the feedback state is unitialized + // let mut should_update_feedback = false; + + // if let FeedbackSlot::AddOp(add_feedback_state) = self.get_ic_stub(slot_index) { + // match add_feedback_state { + // AddFeedbackState::Uninitialized => { + // should_update_feedback = true; + // } + // AddFeedbackState::SmiSmi => { + // if left_value.is_smi() && right_value.is_smi() { + // let l = left_value.as_smi() as i64; + // let r = right_value.as_smi() as i64; + // let sum = l + r; + // if sum >= i32::MIN as i64 && sum <= i32::MAX as i64 { + // let result = self.cx.smi(sum as i32); + // self.write_register(dest, *result); + // return Ok(()); + // } + // // Overflow — widen feedback to Number, fall through to slow path + // self.add_ic_stub( + // slot_index, + // FeedbackSlot::AddOp(AddFeedbackState::Number), + // ); + // } + // } + // AddFeedbackState::Number => { + // if left_value.is_number() && right_value.is_number() { + // let result = self + // .cx + // .number(left_value.as_number() + right_value.as_number()); + // self.write_register(dest, *result); + // return Ok(()); + // } + // } + // AddFeedbackState::StringConcat => { + // if left_value.is_string() && right_value.is_string() { + // let left_string = left_value.as_string(); + // let right_string = right_value.as_string(); + // let result = + // StringValue::concat(self.cx, left_string, right_string)?.as_value(); + // self.write_register(dest, *result); + // return Ok(()); + // } + // } + // AddFeedbackState::BigInt => { + // if left_value.is_bigint() && right_value.is_bigint() { + // let result = + // left_value.as_bigint().bigint() + right_value.as_bigint().bigint(); + // let result: Handle = BigIntValue::new(self.cx, result)?.into(); + // self.write_register(dest, *result); + // return Ok(()); + // } + // } + // AddFeedbackState::Any => {} + // } + // } - // this should always be an addop - otherwise something has gone very wrong - let feedback_slot = self.get_feedback(slot_index); - debug_assert!(matches!(feedback_slot, FeedbackSlot::AddOp(_))); - - // try the fast path - - // see if we should update feedback - this is only the case - // if we see that the feedback state is unitialized - let mut should_update_feedback = false; - - if let FeedbackSlot::AddOp(add_feedback_state) = self.get_feedback(slot_index) { - match add_feedback_state { - AddFeedbackState::Uninitialized => { - should_update_feedback = true; - } - AddFeedbackState::SmiSmi => { - if left_value.is_smi() && right_value.is_smi() { - let l = left_value.as_smi() as i64; - let r = right_value.as_smi() as i64; - let sum = l + r; - if sum >= i32::MIN as i64 && sum <= i32::MAX as i64 { - let result = self.cx.smi(sum as i32); - self.write_register(dest, *result); - return Ok(()); - } - // Overflow — widen feedback to Number, fall through to slow path - self.set_feedback( - slot_index, - FeedbackSlot::AddOp(AddFeedbackState::Number), - ); - } - } - AddFeedbackState::Number => { - if left_value.is_number() && right_value.is_number() { - let result = self - .cx - .number(left_value.as_number() + right_value.as_number()); - self.write_register(dest, *result); - return Ok(()); - } - } - AddFeedbackState::StringConcat => { - if left_value.is_string() && right_value.is_string() { - let left_string = left_value.as_string(); - let right_string = right_value.as_string(); - let result = - StringValue::concat(self.cx, left_string, right_string)?.as_value(); - self.write_register(dest, *result); - return Ok(()); - } - } - AddFeedbackState::BigInt => { - if left_value.is_bigint() && right_value.is_bigint() { - let result = - left_value.as_bigint().bigint() + right_value.as_bigint().bigint(); - let result: Handle = BigIntValue::new(self.cx, result)?.into(); - self.write_register(dest, *result); - return Ok(()); - } - } - AddFeedbackState::Any => {} - } - } - // slow path // May allocate let result = eval_add(self.cx(), left_value, right_value)?; - if should_update_feedback { - let new_state = if left_value.is_smi() && right_value.is_smi() && result.is_smi() { - AddFeedbackState::SmiSmi - } else if left_value.is_number() && right_value.is_number() { - AddFeedbackState::Number - } else if left_value.is_string() || right_value.is_string() { - AddFeedbackState::StringConcat - } else if left_value.is_bigint() && right_value.is_bigint() { - AddFeedbackState::BigInt - } else { - AddFeedbackState::Any - }; - self.set_feedback(slot_index, FeedbackSlot::AddOp(new_state)); - } + // if should_update_feedback { + // let new_state = if left_value.is_smi() && right_value.is_smi() && result.is_smi() { + // AddFeedbackState::SmiSmi + // } else if left_value.is_number() && right_value.is_number() { + // AddFeedbackState::Number + // } else if left_value.is_string() || right_value.is_string() { + // AddFeedbackState::StringConcat + // } else if left_value.is_bigint() && right_value.is_bigint() { + // AddFeedbackState::BigInt + // } else { + // AddFeedbackState::Any + // }; + // self.add_ic_stub(slot_index, FeedbackSlot::AddOp(new_state)); + // } self.write_register(dest, *result); diff --git a/src/js/runtime/gc/heap_item.rs b/src/js/runtime/gc/heap_item.rs index bd1bf342..59d0a71c 100644 --- a/src/js/runtime/gc/heap_item.rs +++ b/src/js/runtime/gc/heap_item.rs @@ -23,7 +23,7 @@ use crate::runtime::{ generator_object::GeneratorObject, global_names::GlobalNames, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::feedback::FeedbackVector, + ic::{vector::ICVector, stubs::ICStub}, interned_strings::InternedStringsSetField, intrinsics::{ array_buffer_constructor::ArrayBufferObject, @@ -218,7 +218,8 @@ impl HeapPtr { } HeapItemKind::GlobalScopes => self.cast::().byte_size(), HeapItemKind::ValueVec => value_vec_byte_size(self.cast()), - HeapItemKind::FeedbackVector => self.cast::().byte_size(), + HeapItemKind::ICVector => self.cast::().byte_size(), + HeapItemKind::ICStub => self.cast::().byte_size(), HeapItemKind::Last => unreachable!("No objects are created with this descriptor"), } } @@ -382,7 +383,8 @@ impl HeapPtr { .visit_pointers(visitor), HeapItemKind::GlobalScopes => self.cast::().visit_pointers(visitor), HeapItemKind::ValueVec => value_vec_visit_pointers(self.cast_mut(), visitor), - HeapItemKind::FeedbackVector => self.cast::().visit_pointers(visitor), + HeapItemKind::ICVector => self.cast::().visit_pointers(visitor), + HeapItemKind::ICStub => self.cast::().visit_pointers(visitor), HeapItemKind::Last => unreachable!("No objects are created with this descriptor"), } } diff --git a/src/js/runtime/heap_item_descriptor.rs b/src/js/runtime/heap_item_descriptor.rs index fa32c4e3..3078abfc 100644 --- a/src/js/runtime/heap_item_descriptor.rs +++ b/src/js/runtime/heap_item_descriptor.rs @@ -159,8 +159,9 @@ pub enum HeapItemKind { // Vectors ValueVec, - // Feedback vectors for IC stubs - FeedbackVector, + // IC Vectors and IC Stubs + ICVector, + ICStub, // Numerical value is the number of kinds in the enum Last, @@ -396,7 +397,8 @@ impl BaseDescriptors { other_heap_item_descriptor!(HeapItemKind::ValueVec); - other_heap_item_descriptor!(HeapItemKind::FeedbackVector); + other_heap_item_descriptor!(HeapItemKind::ICVector); + other_heap_item_descriptor!(HeapItemKind::ICStub); Ok(base_descriptors) } diff --git a/src/js/runtime/ic/bytecode.rs b/src/js/runtime/ic/bytecode.rs new file mode 100644 index 00000000..8e05909d --- /dev/null +++ b/src/js/runtime/ic/bytecode.rs @@ -0,0 +1,150 @@ +// This file defines a bytecode for Inline Caches +// +// In order to ensure we only construct valid IC Stubs, +// we use a typestate builder `ICStubByteCodeBuilder`. +// +// `ICStubByteCodeBuilder` is generic on `Args`, which +// is generally a tuple of type states representing +// facts about each operand. +// +// `ICStubByteCodeBuilder` then implements methods for +// each operation in the byte code, only if the type state +// for both arguments make it same to do so. +// +// For example, we define `add_smi` on `ICStubByteCodeBuilder<(IsSmi, IsSmi)>` +// meaning that some guard has been used on both the left and right operands +// that determine they are Smi's. In this case `IsSmi` is a trait that is implemented +// only for the `Smi` type state. A similar approach is taken for strings and `concat_str` etc. + +use std::marker::PhantomData; + +use crate::runtime::{alloc_error::AllocResult, ic::stubs::ICStub, Context, Handle}; + +/// The unguarded state: when no guards have been used +pub struct Unguarded; + +/// Macro to define other states: For example, the `smi` state is used +/// when an SMI guard has been invoked +macro_rules! define_type_tags { + ($($tag:ident),* $(,)?) => { + $(pub struct $tag;)* + } +} + +macro_rules! define_allows { + ($($trait_name:ident => [$($tag:ident),+]);* $(;)?) => { + $( + pub trait $trait_name {} + $(impl $trait_name for $tag {})+ + )* + } +} + +macro_rules! define_guards { + ($($left_name:ident, $right_name:ident => $type_tag:ident, $ir_variant:ident);* $(;)?) => { + $( + impl ICStubByteCodeBuilder<(Unguarded, R)> { + pub fn $left_name(mut self) -> ICStubByteCodeBuilder<($type_tag, R)> { + self.ops.push(CacheByteCode::$ir_variant(OperandIndex::Left)); + ICStubByteCodeBuilder { ops: self.ops, _phantom: PhantomData } + } + } + + impl ICStubByteCodeBuilder<(L, Unguarded)> { + pub fn $right_name(mut self) -> ICStubByteCodeBuilder<(L, $type_tag)> { + self.ops.push(CacheByteCode::$ir_variant(OperandIndex::Right)); + ICStubByteCodeBuilder { ops: self.ops, _phantom: PhantomData } + } + } + )* + } +} + +macro_rules! define_binary_ops { + ($($method:ident => $ir_variant:ident, $allow_left_trait:ident, $allow_right_trait:ident);* $(;)?) => { + $( + impl ICStubByteCodeBuilder<(L, R)> { + // TODO: Make this monadic so we can potentially + // chain multiple things together... + // Right now would have to concat byte code + // operations which makes things not type safe + // either + // We should finalize this into an IC Stub with a + // finalize method + pub fn $method(mut self) -> ICStubChainable { + self.ops.push(CacheByteCode::$ir_variant); + ICStubChainable { ops: self.ops } + } + } + )* + } +} + +#[repr(u8)] +#[derive(Clone, Copy)] +pub enum OperandIndex { + Left = 0, + Right = 1, +} + +#[repr(u8)] +#[derive(Clone, Copy)] +pub enum CacheByteCode { + GuardSmi(OperandIndex), + GuardNumber(OperandIndex), + GuardString(OperandIndex), + GuardBigInt(OperandIndex), + AddSmi, + AddNumber, + AddBigInt, + ConcatStr, +} + +pub struct ICStubByteCodeBuilder { + ops: Vec, + _phantom: PhantomData, +} + +impl ICStubByteCodeBuilder<(Unguarded, Unguarded)> { + pub fn new_binary() -> Self { + Self { ops: Vec::new(), _phantom: PhantomData } + } +} + +pub struct ICStubChainable { + ops: Vec, +} + +impl ICStubChainable { + // TODO: Add this once it makes sense! + // pub fn chain(self) -> ICStubByteCodeBuilder<(Unguarded, Unguarded)> { + // ICStubByteCodeBuilder { ops: self.ops, _phantom: PhantomData } + // } + + pub fn finalize(self, cx: Context) -> AllocResult> { + ICStub::new(cx, &self.ops) + } +} + +define_type_tags!(Smi, Number, StringT, BigInt); + +define_allows! { + IsSmi => [Smi]; + IsNumber => [Smi, Number]; + IsStr => [StringT]; + IsBigInt => [BigInt]; +} + +define_guards! { + guard_smi_left, guard_smi_right => Smi, GuardSmi; + guard_number_left, guard_number_right => Number, GuardNumber; + guard_string_left, guard_string_right => StringT, GuardString; + guard_bigint_left, guard_bigint_right => BigInt, GuardBigInt; +} + +define_binary_ops! { + add_smi => AddSmi, IsSmi, IsSmi; + add_number => AddNumber, IsNumber, IsNumber; + concat_str => ConcatStr, IsStr, IsStr; + add_bigint => AddBigInt, IsBigInt, IsBigInt; +} diff --git a/src/js/runtime/ic/feedback.rs b/src/js/runtime/ic/feedback.rs deleted file mode 100644 index b8ed9f7a..00000000 --- a/src/js/runtime/ic/feedback.rs +++ /dev/null @@ -1,110 +0,0 @@ -use crate::{ - field_offset, - runtime::{ - alloc_error::AllocResult, - collections::InlineArray, - gc::{HeapItem, HeapVisitor}, - heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - Context, Handle, HeapPtr, - }, - set_uninit, -}; - -#[repr(u8)] -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum AddFeedbackState { - /// No feedback collected yet. - Uninitialized = 0, - /// Both operands were smis, result was smi (no overflow). - SmiSmi = 1, - /// Both operands were numbers (smi or double), at least one was double. - Number = 2, - /// At least one operand was a string - StringConcat = 3, - /// Both operands were BigInts - BigInt = 4, - /// Mixed/incompatible types seen, or types changed across executions. - Any = 5, -} - -#[repr(u8)] -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum FeedbackSlot { - AddOp(AddFeedbackState), - Unknown, -} - -impl FeedbackSlot { - pub fn add_uninit() -> Self { - Self::AddOp(AddFeedbackState::Uninitialized) - } - - pub fn add_string_concat() -> Self { - Self::AddOp(AddFeedbackState::StringConcat) - } -} - -#[repr(C)] -pub struct FeedbackVector { - descriptor: HeapPtr, - /// Number of feedback slots - num_slots: u32, - /// Inline array of slot data. - /// Note: the layout of FeedbackSlot - /// needs to be very precise for this to - /// work, hence the repr(u8) - slots: InlineArray, -} - -impl FeedbackVector { - /// The offset of the `slots` field in a FeedbackVector - const SLOTS_BYTE_OFFSET: usize = field_offset!(FeedbackVector, slots); - - pub fn slots(&self) -> &InlineArray { - &self.slots - } - - pub fn slots_mut(&mut self) -> &mut InlineArray { - &mut self.slots - } - - /// Calculates the total size in bytes for a Feedback vector - /// Note that the slots InlineArray can be variable length (i.e., length `num_slots`) - /// The size is the byte offset of `slots` + the numbers of bytes needed for the array - /// of feedback slots - fn calculate_size_in_bytes(num_slots: usize) -> usize { - Self::SLOTS_BYTE_OFFSET + InlineArray::::calculate_size_in_bytes(num_slots) - } - - /// Create a new feedback vector with the passed feedback slots - pub fn new(cx: Context, initial_slots: &[FeedbackSlot]) -> AllocResult> { - // get the size of the the FeedbackVector - let num_slots = initial_slots.len(); - let size = Self::calculate_size_in_bytes(num_slots); - // allocate the FeedbackVector on the heap - let mut object = cx.alloc_uninit_with_size::(size)?; - - // set the object's descriptor - set_uninit!(object.descriptor, cx.base_descriptors.get(HeapItemKind::FeedbackVector)); - // set the number of slots - set_uninit!(object.num_slots, num_slots as u32); - - // Initialize the slots to the passed feedback slots - object.slots.init_from_slice(initial_slots); - - Ok(object.to_handle()) - } -} - -/// GC Integration for FeedbackVector -impl HeapItem for HeapPtr { - fn byte_size(&self) -> usize { - FeedbackVector::calculate_size_in_bytes(self.num_slots as usize) - } - - fn visit_pointers(&mut self, visitor: &mut impl HeapVisitor) { - // For now, only visit the descriptor, and we do not - // need to visit feedback slots as those have no pointers - visitor.visit_pointer(&mut self.descriptor); - } -} diff --git a/src/js/runtime/ic/mod.rs b/src/js/runtime/ic/mod.rs index be280060..251db1b5 100644 --- a/src/js/runtime/ic/mod.rs +++ b/src/js/runtime/ic/mod.rs @@ -1 +1,3 @@ -pub mod feedback; +pub mod bytecode; +pub mod vector; +pub mod stubs; diff --git a/src/js/runtime/ic/stubs.rs b/src/js/runtime/ic/stubs.rs new file mode 100644 index 00000000..7df975ab --- /dev/null +++ b/src/js/runtime/ic/stubs.rs @@ -0,0 +1,62 @@ +use crate::{ + field_offset, + runtime::{ + alloc_error::AllocResult, + collections::InlineArray, + gc::{HeapItem, HeapVisitor}, + heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, + ic::bytecode::CacheByteCode, + Context, Handle, HeapPtr, + }, + set_uninit, +}; + +#[repr(C)] +pub struct ICStub { + descriptor: HeapPtr, + /// pointer to the next stub + next: Option>, + /// The IR itself + code: InlineArray, +} + +impl ICStub { + const CODE_BYTE_OFFSET: usize = field_offset!(ICStub, code); + + /// Calculates the total size in bytes for an IC Stub + /// Note that the slots InlineArray can be variable length + /// The size is the byte offset of `code` + the numbers of bytes needed for the array + /// of bytecode + fn calculate_size_in_bytes(num_ops: usize) -> usize { + Self::CODE_BYTE_OFFSET + InlineArray::::calculate_size_in_bytes(num_ops) + } + + // New always makes the next head `None` + pub fn new(cx: Context, bytes: &[CacheByteCode]) -> AllocResult> { + let size = Self::calculate_size_in_bytes(bytes.len()); + let mut object = cx.alloc_uninit_with_size::(size)?; + + set_uninit!(object.descriptor, cx.base_descriptors.get(HeapItemKind::ICStub)); + set_uninit!(object.next, None); + object.code.init_from_slice(bytes); + + Ok(object.to_handle()) + } + + pub fn set_next(&mut self, val: Option>) { + self.next = val; + } +} + +/// GC Integration for ICStub +impl HeapItem for HeapPtr { + fn byte_size(&self) -> usize { + ICStub::calculate_size_in_bytes(self.code.len()) + } + + fn visit_pointers(&mut self, visitor: &mut impl HeapVisitor) { + // visit descriptor and next ptr if it exists + visitor.visit_pointer(&mut self.descriptor); + self.next.map(|mut ptr| visitor.visit_pointer(&mut ptr)); + } +} diff --git a/src/js/runtime/ic/vector.rs b/src/js/runtime/ic/vector.rs new file mode 100644 index 00000000..983833cf --- /dev/null +++ b/src/js/runtime/ic/vector.rs @@ -0,0 +1,77 @@ +use crate::{ + field_offset, + runtime::{ + alloc_error::AllocResult, + collections::InlineArray, + gc::{HeapItem, HeapVisitor}, + heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, + ic::stubs::ICStub, + Context, Handle, HeapPtr, + }, + set_uninit, +}; + +#[repr(C)] +pub struct ICVector { + descriptor: HeapPtr, + /// Inline array of pointers to + /// IC Stubs. Each element is a unique + /// linked list of IC Stubs for an opcode + slots: InlineArray>>, +} + +impl ICVector { + /// The offset of the `slots` field in a ICVector + const SLOTS_BYTE_OFFSET: usize = field_offset!(ICVector, slots); + + pub fn slots(&self) -> &InlineArray>> { + &self.slots + } + + pub fn slots_mut(&mut self) -> &mut InlineArray>> { + &mut self.slots + } + + /// Calculates the total size in bytes for a Feedback vector + /// Note that the slots InlineArray can be variable length + /// The size is the byte offset of `slots` + the numbers of bytes needed for the array + /// of ic stubs + fn calculate_size_in_bytes(num_slots: usize) -> usize { + Self::SLOTS_BYTE_OFFSET + + InlineArray::>>::calculate_size_in_bytes(num_slots) + } + + /// Create a new feedback vector with the passed feedback slots + pub fn new(cx: Context, num_slots: usize) -> AllocResult> { + // get the size of the the ICVector + let size = Self::calculate_size_in_bytes(num_slots); + // allocate the ICVector on the heap + let mut object = cx.alloc_uninit_with_size::(size)?; + + // set the object's descriptor + set_uninit!(object.descriptor, cx.base_descriptors.get(HeapItemKind::ICVector)); + + // Initialize the ICStubs to None + for i in 0..num_slots { + object.slots.set_unchecked(i, None); + } + + Ok(object.to_handle()) + } +} + +/// GC Integration for ICVector +impl HeapItem for HeapPtr { + fn byte_size(&self) -> usize { + ICVector::calculate_size_in_bytes(self.slots.len()) + } + + fn visit_pointers(&mut self, visitor: &mut impl HeapVisitor) { + // visit the descriptor + visitor.visit_pointer(&mut self.descriptor); + // visit each IC Stub + for stub in self.slots.as_mut_slice() { + visitor.visit_pointer_opt(stub) + } + } +} From 4024eaf44671dc11e74e99b1c3633b4915463682 Mon Sep 17 00:00:00 2001 From: vrindisbacher Date: Wed, 20 May 2026 10:22:38 -0700 Subject: [PATCH 04/11] compile and execute byte code stubs for Add --- src/js/runtime/bytecode/vm.rs | 97 ++++++++-------------------------- src/js/runtime/gc/heap_item.rs | 2 +- src/js/runtime/ic/bytecode.rs | 2 +- src/js/runtime/ic/eval.rs | 89 +++++++++++++++++++++++++++++++ src/js/runtime/ic/generate.rs | 66 +++++++++++++++++++++++ src/js/runtime/ic/mod.rs | 4 +- src/js/runtime/ic/stubs.rs | 49 +++++++++++++++-- src/js/runtime/ic/vector.rs | 5 +- 8 files changed, 231 insertions(+), 83 deletions(-) create mode 100644 src/js/runtime/ic/eval.rs create mode 100644 src/js/runtime/ic/generate.rs diff --git a/src/js/runtime/bytecode/vm.rs b/src/js/runtime/bytecode/vm.rs index 05ea4057..80099998 100644 --- a/src/js/runtime/bytecode/vm.rs +++ b/src/js/runtime/bytecode/vm.rs @@ -41,7 +41,7 @@ use crate::{ generator_object::{GeneratorCompletionType, GeneratorObject, TGeneratorObject}, get, heap_item_descriptor::HeapItemKind, - ic::{stubs::ICStub, vector::ICVector}, + ic::{generate::ICStubGenerator, stubs::ICStub, vector::ICVector}, intrinsics::{ async_generator_prototype::AsyncGeneratorPrototype, generator_prototype::GeneratorPrototype, @@ -2751,85 +2751,30 @@ impl VM { let dest = instr.dest(); let slot_index = instr.ic_stub_offset().value().to_usize(); - // // this should always be an addop - otherwise something has gone very wrong - // let feedback_slot = self.get_ic_stub(slot_index); - // debug_assert!(matches!(feedback_slot, FeedbackSlot::AddOp(_))); - - // // see if we should update feedback - this is only the case - // // if we see that the feedback state is unitialized - // let mut should_update_feedback = false; - - // if let FeedbackSlot::AddOp(add_feedback_state) = self.get_ic_stub(slot_index) { - // match add_feedback_state { - // AddFeedbackState::Uninitialized => { - // should_update_feedback = true; - // } - // AddFeedbackState::SmiSmi => { - // if left_value.is_smi() && right_value.is_smi() { - // let l = left_value.as_smi() as i64; - // let r = right_value.as_smi() as i64; - // let sum = l + r; - // if sum >= i32::MIN as i64 && sum <= i32::MAX as i64 { - // let result = self.cx.smi(sum as i32); - // self.write_register(dest, *result); - // return Ok(()); - // } - // // Overflow — widen feedback to Number, fall through to slow path - // self.add_ic_stub( - // slot_index, - // FeedbackSlot::AddOp(AddFeedbackState::Number), - // ); - // } - // } - // AddFeedbackState::Number => { - // if left_value.is_number() && right_value.is_number() { - // let result = self - // .cx - // .number(left_value.as_number() + right_value.as_number()); - // self.write_register(dest, *result); - // return Ok(()); - // } - // } - // AddFeedbackState::StringConcat => { - // if left_value.is_string() && right_value.is_string() { - // let left_string = left_value.as_string(); - // let right_string = right_value.as_string(); - // let result = - // StringValue::concat(self.cx, left_string, right_string)?.as_value(); - // self.write_register(dest, *result); - // return Ok(()); - // } - // } - // AddFeedbackState::BigInt => { - // if left_value.is_bigint() && right_value.is_bigint() { - // let result = - // left_value.as_bigint().bigint() + right_value.as_bigint().bigint(); - // let result: Handle = BigIntValue::new(self.cx, result)?.into(); - // self.write_register(dest, *result); - // return Ok(()); - // } - // } - // AddFeedbackState::Any => {} - // } - // } + // Get the IC Stub at the head of the linked list and try to execute each one + if let Some(stub) = self.get_ic_stub(slot_index) { + match stub.try_execute(self.cx(), left_value, right_value)? { + Some(result) => { + // write to register + self.write_register(dest, result); + // exit - a stub succeeded and we're done + return Ok(()); + } + // fall through to the slow path + None => {} + } + }; // May allocate let result = eval_add(self.cx(), left_value, right_value)?; - // if should_update_feedback { - // let new_state = if left_value.is_smi() && right_value.is_smi() && result.is_smi() { - // AddFeedbackState::SmiSmi - // } else if left_value.is_number() && right_value.is_number() { - // AddFeedbackState::Number - // } else if left_value.is_string() || right_value.is_string() { - // AddFeedbackState::StringConcat - // } else if left_value.is_bigint() && right_value.is_bigint() { - // AddFeedbackState::BigInt - // } else { - // AddFeedbackState::Any - // }; - // self.add_ic_stub(slot_index, FeedbackSlot::AddOp(new_state)); - // } + // compile the stub from the left_value, right_value and result + let gen = ICStubGenerator::new(&self.cx); + // May allocate + if let Some(new_stub) = gen.new_stub_for_add(&left_value, &right_value, &result) { + // add the stub to the slot + self.add_ic_stub(slot_index, new_stub?); + } self.write_register(dest, *result); diff --git a/src/js/runtime/gc/heap_item.rs b/src/js/runtime/gc/heap_item.rs index 59d0a71c..3a8e9e7e 100644 --- a/src/js/runtime/gc/heap_item.rs +++ b/src/js/runtime/gc/heap_item.rs @@ -23,7 +23,7 @@ use crate::runtime::{ generator_object::GeneratorObject, global_names::GlobalNames, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::{vector::ICVector, stubs::ICStub}, + ic::{stubs::ICStub, vector::ICVector}, interned_strings::InternedStringsSetField, intrinsics::{ array_buffer_constructor::ArrayBufferObject, diff --git a/src/js/runtime/ic/bytecode.rs b/src/js/runtime/ic/bytecode.rs index 8e05909d..62287310 100644 --- a/src/js/runtime/ic/bytecode.rs +++ b/src/js/runtime/ic/bytecode.rs @@ -121,7 +121,7 @@ impl ICStubChainable { // ICStubByteCodeBuilder { ops: self.ops, _phantom: PhantomData } // } - pub fn finalize(self, cx: Context) -> AllocResult> { + pub fn finalize(self, cx: &Context) -> AllocResult> { ICStub::new(cx, &self.ops) } } diff --git a/src/js/runtime/ic/eval.rs b/src/js/runtime/ic/eval.rs new file mode 100644 index 00000000..64d85e02 --- /dev/null +++ b/src/js/runtime/ic/eval.rs @@ -0,0 +1,89 @@ +use crate::runtime::{ + alloc_error::AllocError, ic::bytecode::CacheByteCode, string_value::StringValue, + value::BigIntValue, Context, Handle, Value, +}; + +pub enum BailReason { + ExpectedSmi, + ExpectedNumber, + ExpectedString, + ExpectedBigInt, + OverflowOnSmi, + FailedAllocation(AllocError), +} + +pub type ICStubExecutionResult = Result; + +pub struct ICStubVM { + cx: Context, +} + +impl ICStubVM { + pub fn new(cx: Context) -> Self { + Self { cx } + } + + pub fn execute( + &self, + code: &[CacheByteCode], + left: Value, + right: Value, + ) -> ICStubExecutionResult { + let args = [left, right]; + let mut pc = 0; + + while pc < code.len() { + match code[pc] { + CacheByteCode::GuardSmi(idx) => { + if !args[idx as usize].is_smi() { + return Err(BailReason::ExpectedSmi); + } + } + CacheByteCode::GuardNumber(idx) => { + if !args[idx as usize].is_number() { + return Err(BailReason::ExpectedNumber); + } + } + CacheByteCode::GuardString(idx) => { + if !args[idx as usize].is_string() { + return Err(BailReason::ExpectedString); + } + } + CacheByteCode::GuardBigInt(idx) => { + if !args[idx as usize].is_bigint() { + return Err(BailReason::ExpectedBigInt); + } + } + CacheByteCode::AddSmi => { + let l = left.as_smi() as i64; + let r = right.as_smi() as i64; + let sum = l + r; + if sum >= i32::MIN as i64 && sum <= i32::MAX as i64 { + return Ok(Value::smi(sum as i32)); + } + return Err(BailReason::OverflowOnSmi); + } + CacheByteCode::AddNumber => { + return Ok(Value::number(left.as_number() + right.as_number())); + } + CacheByteCode::ConcatStr => { + let left_string = left.as_string().to_handle(); + let right_string = right.as_string().to_handle(); + let result = StringValue::concat(self.cx, left_string, right_string) + .map_err(|e| BailReason::FailedAllocation(e))? + .as_value(); + return Ok(*result); + } + CacheByteCode::AddBigInt => { + let result = left.as_bigint().bigint() + right.as_bigint().bigint(); + let result: Handle = BigIntValue::new(self.cx, result) + .map_err(|e| BailReason::FailedAllocation(e))? + .into(); + return Ok(*result); + } + } + pc += 1; + } + unreachable!("BUG! Fell through IC Stub somehow.") + } +} diff --git a/src/js/runtime/ic/generate.rs b/src/js/runtime/ic/generate.rs new file mode 100644 index 00000000..6fab878e --- /dev/null +++ b/src/js/runtime/ic/generate.rs @@ -0,0 +1,66 @@ +use crate::runtime::{ + alloc_error::AllocResult, + ic::{bytecode::ICStubByteCodeBuilder, stubs::ICStub}, + Context, Handle, Value, +}; + +pub struct ICStubGenerator<'cx> { + cx: &'cx Context, +} + +impl<'cx> ICStubGenerator<'cx> { + pub fn new(cx: &'cx Context) -> Self { + Self { cx } + } + + pub fn new_stub_for_add( + &'cx self, + left: &Value, + right: &Value, + result: &Value, + ) -> Option>> { + let gen = ICStubByteCodeBuilder::new_binary(); + if left.is_smi() && right.is_smi() { + // if the result is also an smi then we can be confident in the add_smi fast path + // but otherwise, the op overflowed and we should generalize to add_number + if result.is_smi() { + Some( + gen.guard_smi_left() + .guard_smi_right() + .add_smi() + .finalize(self.cx), + ) + } else { + Some( + gen.guard_number_left() + .guard_number_right() + .add_number() + .finalize(self.cx), + ) + } + } else if left.is_number() && right.is_number() { + Some( + gen.guard_number_left() + .guard_number_right() + .add_number() + .finalize(self.cx), + ) + } else if left.is_bigint() && right.is_bigint() { + Some( + gen.guard_bigint_left() + .guard_bigint_right() + .add_bigint() + .finalize(self.cx), + ) + } else if left.is_string() && right.is_string() { + Some( + gen.guard_string_left() + .guard_string_right() + .concat_str() + .finalize(self.cx), + ) + } else { + None + } + } +} diff --git a/src/js/runtime/ic/mod.rs b/src/js/runtime/ic/mod.rs index 251db1b5..be81da01 100644 --- a/src/js/runtime/ic/mod.rs +++ b/src/js/runtime/ic/mod.rs @@ -1,3 +1,5 @@ pub mod bytecode; -pub mod vector; +pub mod eval; +pub mod generate; pub mod stubs; +pub mod vector; diff --git a/src/js/runtime/ic/stubs.rs b/src/js/runtime/ic/stubs.rs index 7df975ab..56c264c9 100644 --- a/src/js/runtime/ic/stubs.rs +++ b/src/js/runtime/ic/stubs.rs @@ -5,8 +5,11 @@ use crate::{ collections::InlineArray, gc::{HeapItem, HeapVisitor}, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::bytecode::CacheByteCode, - Context, Handle, HeapPtr, + ic::{ + bytecode::CacheByteCode, + eval::{ICStubExecutionResult, ICStubVM}, + }, + Context, Handle, HeapPtr, Value, }, set_uninit, }; @@ -31,8 +34,18 @@ impl ICStub { Self::CODE_BYTE_OFFSET + InlineArray::::calculate_size_in_bytes(num_ops) } + fn execute_code( + &self, + cx: Context, + left: Handle, + right: Handle, + ) -> ICStubExecutionResult { + let vm = ICStubVM::new(cx); + vm.execute(self.code.as_slice(), *left, *right) + } + // New always makes the next head `None` - pub fn new(cx: Context, bytes: &[CacheByteCode]) -> AllocResult> { + pub fn new(cx: &Context, bytes: &[CacheByteCode]) -> AllocResult> { let size = Self::calculate_size_in_bytes(bytes.len()); let mut object = cx.alloc_uninit_with_size::(size)?; @@ -46,6 +59,36 @@ impl ICStub { pub fn set_next(&mut self, val: Option>) { self.next = val; } + + pub fn try_execute( + &self, + cx: Context, + left: Handle, + right: Handle, + ) -> AllocResult> { + // try to execute each individual stub in the linked list + let mut curr = Some(self); + while let Some(stub) = curr { + match stub.execute_code(cx, left, right) { + Ok(r) => return Ok(Some(r)), + // continue to next stub + Err(e) => match e { + super::eval::BailReason::FailedAllocation(alloc_error) => { + return Err(alloc_error) + } + // fall through to next + super::eval::BailReason::ExpectedSmi + | super::eval::BailReason::ExpectedNumber + | super::eval::BailReason::ExpectedString + | super::eval::BailReason::ExpectedBigInt + | super::eval::BailReason::OverflowOnSmi => {} + }, + } + curr = stub.next.as_deref(); + } + // fall through - none of the stubs were a hit + Ok(None) + } } /// GC Integration for ICStub diff --git a/src/js/runtime/ic/vector.rs b/src/js/runtime/ic/vector.rs index 983833cf..b2069e6f 100644 --- a/src/js/runtime/ic/vector.rs +++ b/src/js/runtime/ic/vector.rs @@ -51,7 +51,10 @@ impl ICVector { // set the object's descriptor set_uninit!(object.descriptor, cx.base_descriptors.get(HeapItemKind::ICVector)); - // Initialize the ICStubs to None + // initialize the slots array + object.slots.init_with_uninit(num_slots); + + // Initialize the ICStubs in the slots array to None for i in 0..num_slots { object.slots.set_unchecked(i, None); } From d24814698cde6d03c5603009fdc49b7408c2982e Mon Sep 17 00:00:00 2001 From: vrindisbacher Date: Thu, 21 May 2026 11:35:43 -0700 Subject: [PATCH 05/11] change to executing function rather than bytecode --- src/js/runtime/bytecode/stack_frame.rs | 6 +- src/js/runtime/bytecode/vm.rs | 10 +- src/js/runtime/eval/common.rs | 65 +++++++++++ src/js/runtime/eval/expression.rs | 15 ++- src/js/runtime/eval/mod.rs | 1 + src/js/runtime/gc/heap_item.rs | 6 +- src/js/runtime/heap_item_descriptor.rs | 4 +- src/js/runtime/ic/bytecode.rs | 150 ------------------------- src/js/runtime/ic/eval.rs | 89 --------------- src/js/runtime/ic/fgc.rs | 52 +++++++++ src/js/runtime/ic/generate.rs | 116 +++++++++++-------- src/js/runtime/ic/mod.rs | 3 +- src/js/runtime/ic/stubs.rs | 105 ----------------- src/js/runtime/ic/stubs/add.rs | 93 +++++++++++++++ src/js/runtime/ic/stubs/mod.rs | 1 + src/js/runtime/ic/vector.rs | 10 +- 16 files changed, 309 insertions(+), 417 deletions(-) create mode 100644 src/js/runtime/eval/common.rs delete mode 100644 src/js/runtime/ic/bytecode.rs delete mode 100644 src/js/runtime/ic/eval.rs create mode 100644 src/js/runtime/ic/fgc.rs delete mode 100644 src/js/runtime/ic/stubs.rs create mode 100644 src/js/runtime/ic/stubs/add.rs create mode 100644 src/js/runtime/ic/stubs/mod.rs diff --git a/src/js/runtime/bytecode/stack_frame.rs b/src/js/runtime/bytecode/stack_frame.rs index 07c2d790..bc5f4990 100644 --- a/src/js/runtime/bytecode/stack_frame.rs +++ b/src/js/runtime/bytecode/stack_frame.rs @@ -1,6 +1,6 @@ use crate::runtime::{ gc::HeapVisitor, - ic::{stubs::ICStub, vector::ICVector}, + ic::{stubs::add::AddICStub, vector::ICVector}, scope::Scope, Handle, HeapPtr, Value, }; @@ -206,12 +206,12 @@ impl StackFrame { } #[inline] - pub fn get_ic_stub(&self, slot: usize) -> Option> { + pub fn get_ic_stub(&self, slot: usize) -> Option> { *self.ic_vector().slots().get_unchecked(slot) } #[inline] - pub fn add_ic_stub(&mut self, slot: usize, mut stub: Handle) { + pub fn add_ic_stub(&mut self, slot: usize, mut stub: Handle) { let slots = self.ic_vector_mut().slots_mut(); let head = slots.get_unchecked_mut(slot); // Prepend the stub: diff --git a/src/js/runtime/bytecode/vm.rs b/src/js/runtime/bytecode/vm.rs index 80099998..384f8b93 100644 --- a/src/js/runtime/bytecode/vm.rs +++ b/src/js/runtime/bytecode/vm.rs @@ -41,7 +41,7 @@ use crate::{ generator_object::{GeneratorCompletionType, GeneratorObject, TGeneratorObject}, get, heap_item_descriptor::HeapItemKind, - ic::{generate::ICStubGenerator, stubs::ICStub, vector::ICVector}, + ic::{generate::ICStubGenerator, stubs::add::AddICStub, vector::ICVector}, intrinsics::{ async_generator_prototype::AsyncGeneratorPrototype, generator_prototype::GeneratorPrototype, @@ -222,12 +222,12 @@ impl VM { } #[inline] - fn get_ic_stub(&self, slot_index: usize) -> Option> { + fn get_ic_stub(&self, slot_index: usize) -> Option> { self.stack_frame().get_ic_stub(slot_index) } #[inline] - fn add_ic_stub(&mut self, slot_index: usize, slot: Handle) { + fn add_ic_stub(&mut self, slot_index: usize, slot: Handle) { self.stack_frame().add_ic_stub(slot_index, slot); } @@ -2753,10 +2753,10 @@ impl VM { // Get the IC Stub at the head of the linked list and try to execute each one if let Some(stub) = self.get_ic_stub(slot_index) { - match stub.try_execute(self.cx(), left_value, right_value)? { + match stub.try_execute(self.cx(), left_value, right_value) { Some(result) => { // write to register - self.write_register(dest, result); + self.write_register(dest, *result?); // exit - a stub succeeded and we're done return Ok(()); } diff --git a/src/js/runtime/eval/common.rs b/src/js/runtime/eval/common.rs new file mode 100644 index 00000000..46148b2a --- /dev/null +++ b/src/js/runtime/eval/common.rs @@ -0,0 +1,65 @@ +use crate::runtime::{ + alloc_error::AllocResult, string_value::StringValue, value::BigIntValue, Context, Handle, Value, +}; + +/// Common operations that are used by IC Stubs and the interpreter + +/// Check if a value is a string +pub fn is_string(val: Handle) -> bool { + val.is_string() +} + +/// Adds two strings +pub fn add_string_fast( + cx: Context, + left: Handle, + right: Handle, +) -> AllocResult> { + return Ok(StringValue::concat(cx, left, right)?.as_value()); +} + +/// Checks if a value is a big int +pub fn is_bigint(val: Handle) -> bool { + val.is_bigint() +} + +/// Adds two big ints +pub fn add_bigint_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> AllocResult> { + let result = left_num.as_bigint().bigint() + right_num.as_bigint().bigint(); + Ok(BigIntValue::new(cx, result)?.into()) +} + +/// Checks if a value is a number +pub fn is_number(val: Handle) -> bool { + val.is_number() +} + +/// Adds two numbers +pub fn add_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + cx.number(left_num.as_number() + right_num.as_number()) +} + +/// Check if a value is an SMI +pub fn is_smi(val: Handle) -> bool { + val.is_smi() +} + +/// Adds two smi's +pub fn add_smi_fast( + cx: Context, + left_smi: Handle, + right_smi: Handle, +) -> Handle { + match left_smi.as_smi().checked_add(right_smi.as_smi()) { + Some(sum) => cx.smi(sum), + None => add_number_fast(cx, left_smi, right_smi), + } +} diff --git a/src/js/runtime/eval/expression.rs b/src/js/runtime/eval/expression.rs index c7a7b52f..7155c730 100644 --- a/src/js/runtime/eval/expression.rs +++ b/src/js/runtime/eval/expression.rs @@ -13,6 +13,7 @@ use crate::{ alloc_error::AllocResult, array_object::array_create_in_realm, error::{range_error, type_error}, + eval::common::{add_bigint_fast, add_number_fast, add_string_fast, is_bigint, is_string}, eval_result::EvalResult, heap_item_descriptor::HeapItemKind, numeric_operations::number_exponentiate, @@ -144,26 +145,24 @@ pub fn eval_add( ) -> EvalResult> { let left_prim = to_primitive(cx, left_value, ToPrimitivePreferredType::None)?; let right_prim = to_primitive(cx, right_value, ToPrimitivePreferredType::None)?; - if left_prim.is_string() || right_prim.is_string() { + if is_string(left_prim) || is_string(right_prim) { let left_string = to_string(cx, left_prim)?; let right_string = to_string(cx, right_prim)?; - - return Ok(StringValue::concat(cx, left_string, right_string)?.as_value()); + return Ok(add_string_fast(cx, left_string, right_string)?); } let left_num = to_numeric(cx, left_prim)?; let right_num = to_numeric(cx, right_prim)?; - let left_is_bigint = left_num.is_bigint(); - if left_is_bigint != right_num.is_bigint() { + let left_is_bigint = is_bigint(left_num); + if left_is_bigint != is_bigint(right_num) { return type_error(cx, "BigInt cannot be converted to number"); } if left_is_bigint { - let result = left_num.as_bigint().bigint() + right_num.as_bigint().bigint(); - Ok(BigIntValue::new(cx, result)?.into()) + Ok(add_bigint_fast(cx, left_num, right_num)?) } else { - Ok(cx.number(left_num.as_number() + right_num.as_number())) + Ok(add_number_fast(cx, left_num, right_num)) } } diff --git a/src/js/runtime/eval/mod.rs b/src/js/runtime/eval/mod.rs index 1c462c4c..51e16e70 100644 --- a/src/js/runtime/eval/mod.rs +++ b/src/js/runtime/eval/mod.rs @@ -1,3 +1,4 @@ +pub mod common; pub mod create_dynamic_function; #[allow(clippy::module_inception)] pub mod eval; diff --git a/src/js/runtime/gc/heap_item.rs b/src/js/runtime/gc/heap_item.rs index 3a8e9e7e..9d14d727 100644 --- a/src/js/runtime/gc/heap_item.rs +++ b/src/js/runtime/gc/heap_item.rs @@ -23,7 +23,7 @@ use crate::runtime::{ generator_object::GeneratorObject, global_names::GlobalNames, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::{stubs::ICStub, vector::ICVector}, + ic::{stubs::add::AddICStub, vector::ICVector}, interned_strings::InternedStringsSetField, intrinsics::{ array_buffer_constructor::ArrayBufferObject, @@ -219,7 +219,7 @@ impl HeapPtr { HeapItemKind::GlobalScopes => self.cast::().byte_size(), HeapItemKind::ValueVec => value_vec_byte_size(self.cast()), HeapItemKind::ICVector => self.cast::().byte_size(), - HeapItemKind::ICStub => self.cast::().byte_size(), + HeapItemKind::AddICStub => self.cast::().byte_size(), HeapItemKind::Last => unreachable!("No objects are created with this descriptor"), } } @@ -384,7 +384,7 @@ impl HeapPtr { HeapItemKind::GlobalScopes => self.cast::().visit_pointers(visitor), HeapItemKind::ValueVec => value_vec_visit_pointers(self.cast_mut(), visitor), HeapItemKind::ICVector => self.cast::().visit_pointers(visitor), - HeapItemKind::ICStub => self.cast::().visit_pointers(visitor), + HeapItemKind::AddICStub => self.cast::().visit_pointers(visitor), HeapItemKind::Last => unreachable!("No objects are created with this descriptor"), } } diff --git a/src/js/runtime/heap_item_descriptor.rs b/src/js/runtime/heap_item_descriptor.rs index 3078abfc..4d89867b 100644 --- a/src/js/runtime/heap_item_descriptor.rs +++ b/src/js/runtime/heap_item_descriptor.rs @@ -161,7 +161,7 @@ pub enum HeapItemKind { // IC Vectors and IC Stubs ICVector, - ICStub, + AddICStub, // Numerical value is the number of kinds in the enum Last, @@ -398,7 +398,7 @@ impl BaseDescriptors { other_heap_item_descriptor!(HeapItemKind::ValueVec); other_heap_item_descriptor!(HeapItemKind::ICVector); - other_heap_item_descriptor!(HeapItemKind::ICStub); + other_heap_item_descriptor!(HeapItemKind::AddICStub); Ok(base_descriptors) } diff --git a/src/js/runtime/ic/bytecode.rs b/src/js/runtime/ic/bytecode.rs deleted file mode 100644 index 62287310..00000000 --- a/src/js/runtime/ic/bytecode.rs +++ /dev/null @@ -1,150 +0,0 @@ -// This file defines a bytecode for Inline Caches -// -// In order to ensure we only construct valid IC Stubs, -// we use a typestate builder `ICStubByteCodeBuilder`. -// -// `ICStubByteCodeBuilder` is generic on `Args`, which -// is generally a tuple of type states representing -// facts about each operand. -// -// `ICStubByteCodeBuilder` then implements methods for -// each operation in the byte code, only if the type state -// for both arguments make it same to do so. -// -// For example, we define `add_smi` on `ICStubByteCodeBuilder<(IsSmi, IsSmi)>` -// meaning that some guard has been used on both the left and right operands -// that determine they are Smi's. In this case `IsSmi` is a trait that is implemented -// only for the `Smi` type state. A similar approach is taken for strings and `concat_str` etc. - -use std::marker::PhantomData; - -use crate::runtime::{alloc_error::AllocResult, ic::stubs::ICStub, Context, Handle}; - -/// The unguarded state: when no guards have been used -pub struct Unguarded; - -/// Macro to define other states: For example, the `smi` state is used -/// when an SMI guard has been invoked -macro_rules! define_type_tags { - ($($tag:ident),* $(,)?) => { - $(pub struct $tag;)* - } -} - -macro_rules! define_allows { - ($($trait_name:ident => [$($tag:ident),+]);* $(;)?) => { - $( - pub trait $trait_name {} - $(impl $trait_name for $tag {})+ - )* - } -} - -macro_rules! define_guards { - ($($left_name:ident, $right_name:ident => $type_tag:ident, $ir_variant:ident);* $(;)?) => { - $( - impl ICStubByteCodeBuilder<(Unguarded, R)> { - pub fn $left_name(mut self) -> ICStubByteCodeBuilder<($type_tag, R)> { - self.ops.push(CacheByteCode::$ir_variant(OperandIndex::Left)); - ICStubByteCodeBuilder { ops: self.ops, _phantom: PhantomData } - } - } - - impl ICStubByteCodeBuilder<(L, Unguarded)> { - pub fn $right_name(mut self) -> ICStubByteCodeBuilder<(L, $type_tag)> { - self.ops.push(CacheByteCode::$ir_variant(OperandIndex::Right)); - ICStubByteCodeBuilder { ops: self.ops, _phantom: PhantomData } - } - } - )* - } -} - -macro_rules! define_binary_ops { - ($($method:ident => $ir_variant:ident, $allow_left_trait:ident, $allow_right_trait:ident);* $(;)?) => { - $( - impl ICStubByteCodeBuilder<(L, R)> { - // TODO: Make this monadic so we can potentially - // chain multiple things together... - // Right now would have to concat byte code - // operations which makes things not type safe - // either - // We should finalize this into an IC Stub with a - // finalize method - pub fn $method(mut self) -> ICStubChainable { - self.ops.push(CacheByteCode::$ir_variant); - ICStubChainable { ops: self.ops } - } - } - )* - } -} - -#[repr(u8)] -#[derive(Clone, Copy)] -pub enum OperandIndex { - Left = 0, - Right = 1, -} - -#[repr(u8)] -#[derive(Clone, Copy)] -pub enum CacheByteCode { - GuardSmi(OperandIndex), - GuardNumber(OperandIndex), - GuardString(OperandIndex), - GuardBigInt(OperandIndex), - AddSmi, - AddNumber, - AddBigInt, - ConcatStr, -} - -pub struct ICStubByteCodeBuilder { - ops: Vec, - _phantom: PhantomData, -} - -impl ICStubByteCodeBuilder<(Unguarded, Unguarded)> { - pub fn new_binary() -> Self { - Self { ops: Vec::new(), _phantom: PhantomData } - } -} - -pub struct ICStubChainable { - ops: Vec, -} - -impl ICStubChainable { - // TODO: Add this once it makes sense! - // pub fn chain(self) -> ICStubByteCodeBuilder<(Unguarded, Unguarded)> { - // ICStubByteCodeBuilder { ops: self.ops, _phantom: PhantomData } - // } - - pub fn finalize(self, cx: &Context) -> AllocResult> { - ICStub::new(cx, &self.ops) - } -} - -define_type_tags!(Smi, Number, StringT, BigInt); - -define_allows! { - IsSmi => [Smi]; - IsNumber => [Smi, Number]; - IsStr => [StringT]; - IsBigInt => [BigInt]; -} - -define_guards! { - guard_smi_left, guard_smi_right => Smi, GuardSmi; - guard_number_left, guard_number_right => Number, GuardNumber; - guard_string_left, guard_string_right => StringT, GuardString; - guard_bigint_left, guard_bigint_right => BigInt, GuardBigInt; -} - -define_binary_ops! { - add_smi => AddSmi, IsSmi, IsSmi; - add_number => AddNumber, IsNumber, IsNumber; - concat_str => ConcatStr, IsStr, IsStr; - add_bigint => AddBigInt, IsBigInt, IsBigInt; -} diff --git a/src/js/runtime/ic/eval.rs b/src/js/runtime/ic/eval.rs deleted file mode 100644 index 64d85e02..00000000 --- a/src/js/runtime/ic/eval.rs +++ /dev/null @@ -1,89 +0,0 @@ -use crate::runtime::{ - alloc_error::AllocError, ic::bytecode::CacheByteCode, string_value::StringValue, - value::BigIntValue, Context, Handle, Value, -}; - -pub enum BailReason { - ExpectedSmi, - ExpectedNumber, - ExpectedString, - ExpectedBigInt, - OverflowOnSmi, - FailedAllocation(AllocError), -} - -pub type ICStubExecutionResult = Result; - -pub struct ICStubVM { - cx: Context, -} - -impl ICStubVM { - pub fn new(cx: Context) -> Self { - Self { cx } - } - - pub fn execute( - &self, - code: &[CacheByteCode], - left: Value, - right: Value, - ) -> ICStubExecutionResult { - let args = [left, right]; - let mut pc = 0; - - while pc < code.len() { - match code[pc] { - CacheByteCode::GuardSmi(idx) => { - if !args[idx as usize].is_smi() { - return Err(BailReason::ExpectedSmi); - } - } - CacheByteCode::GuardNumber(idx) => { - if !args[idx as usize].is_number() { - return Err(BailReason::ExpectedNumber); - } - } - CacheByteCode::GuardString(idx) => { - if !args[idx as usize].is_string() { - return Err(BailReason::ExpectedString); - } - } - CacheByteCode::GuardBigInt(idx) => { - if !args[idx as usize].is_bigint() { - return Err(BailReason::ExpectedBigInt); - } - } - CacheByteCode::AddSmi => { - let l = left.as_smi() as i64; - let r = right.as_smi() as i64; - let sum = l + r; - if sum >= i32::MIN as i64 && sum <= i32::MAX as i64 { - return Ok(Value::smi(sum as i32)); - } - return Err(BailReason::OverflowOnSmi); - } - CacheByteCode::AddNumber => { - return Ok(Value::number(left.as_number() + right.as_number())); - } - CacheByteCode::ConcatStr => { - let left_string = left.as_string().to_handle(); - let right_string = right.as_string().to_handle(); - let result = StringValue::concat(self.cx, left_string, right_string) - .map_err(|e| BailReason::FailedAllocation(e))? - .as_value(); - return Ok(*result); - } - CacheByteCode::AddBigInt => { - let result = left.as_bigint().bigint() + right.as_bigint().bigint(); - let result: Handle = BigIntValue::new(self.cx, result) - .map_err(|e| BailReason::FailedAllocation(e))? - .into(); - return Ok(*result); - } - } - pc += 1; - } - unreachable!("BUG! Fell through IC Stub somehow.") - } -} diff --git a/src/js/runtime/ic/fgc.rs b/src/js/runtime/ic/fgc.rs new file mode 100644 index 00000000..adf6d258 --- /dev/null +++ b/src/js/runtime/ic/fgc.rs @@ -0,0 +1,52 @@ +/// FGC: Fast Guarded Computation +/// +/// Maps fast path computations +/// +/// For example, in the `add` case, Arg would be +/// (Value, Value) for the two values being added +/// and the BailReason would be some reason related +/// to integers +pub enum FGC { + Yay(Arg), + Bail(BailReason), +} + +impl FGC { + #[inline] + pub fn new(arg: Arg) -> FGC { + Self::Yay(arg) + } + + /// Check something about the inner `val` + /// returning a new BailReason if the check fails + #[inline] + pub fn check(self, f: F, b: BailReason) -> FGC + where + F: FnOnce(&Arg) -> bool, + { + match self { + FGC::Yay(ref v) => { + if !f(v) { + Self::Bail(b) + } else { + self + } + } + FGC::Bail(_) => self, + } + } + + /// Apply some operation to the inner value + /// of FBC - this only bails if the inner value + /// of the FBC monad is already the Bail variant + #[inline] + pub fn map(self, f: F) -> FGC + where + F: FnOnce(Arg) -> NewArg, + { + match self { + FGC::Yay(v) => FGC::Yay(f(v)), + FGC::Bail(br) => FGC::Bail(br), + } + } +} diff --git a/src/js/runtime/ic/generate.rs b/src/js/runtime/ic/generate.rs index 6fab878e..64432155 100644 --- a/src/js/runtime/ic/generate.rs +++ b/src/js/runtime/ic/generate.rs @@ -1,7 +1,13 @@ +use crate::runtime::ic::stubs::add::BailReason; +use crate::runtime::Context; use crate::runtime::{ alloc_error::AllocResult, - ic::{bytecode::ICStubByteCodeBuilder, stubs::ICStub}, - Context, Handle, Value, + eval::common::{ + add_bigint_fast, add_number_fast, add_smi_fast, add_string_fast, is_bigint, is_number, + is_smi, is_string, + }, + ic::{fgc::FGC, stubs::add::AddICStub}, + Handle, Value, }; pub struct ICStubGenerator<'cx> { @@ -14,53 +20,73 @@ impl<'cx> ICStubGenerator<'cx> { } pub fn new_stub_for_add( - &'cx self, + &self, left: &Value, right: &Value, result: &Value, - ) -> Option>> { - let gen = ICStubByteCodeBuilder::new_binary(); - if left.is_smi() && right.is_smi() { - // if the result is also an smi then we can be confident in the add_smi fast path - // but otherwise, the op overflowed and we should generalize to add_number - if result.is_smi() { - Some( - gen.guard_smi_left() - .guard_smi_right() - .add_smi() - .finalize(self.cx), - ) + ) -> Option>> { + let handler: fn( + Context, + Handle, + Handle, + ) -> FGC>, BailReason> = { + if left.is_smi() && right.is_smi() { + if result.is_smi() { + Self::add_smi_handler + } else { + Self::add_number_handler + } + } else if left.is_number() && right.is_number() { + Self::add_number_handler + } else if left.is_string() && right.is_string() { + Self::concat_string_handler + } else if left.is_bigint() && right.is_bigint() { + Self::add_bigint_handler } else { - Some( - gen.guard_number_left() - .guard_number_right() - .add_number() - .finalize(self.cx), - ) + return None; } - } else if left.is_number() && right.is_number() { - Some( - gen.guard_number_left() - .guard_number_right() - .add_number() - .finalize(self.cx), - ) - } else if left.is_bigint() && right.is_bigint() { - Some( - gen.guard_bigint_left() - .guard_bigint_right() - .add_bigint() - .finalize(self.cx), - ) - } else if left.is_string() && right.is_string() { - Some( - gen.guard_string_left() - .guard_string_right() - .concat_str() - .finalize(self.cx), - ) - } else { - None - } + }; + + Some(AddICStub::new(self.cx, handler)) + } + + fn add_smi_handler( + cx: Context, + left: Handle, + right: Handle, + ) -> FGC>, BailReason> { + FGC::new((left, right)) + .check(|(l, r)| is_smi(*l) && is_smi(*r), BailReason::ExpectedSmi) + .map(|(l, r)| Ok(add_smi_fast(cx, l, r))) + } + + fn add_number_handler( + cx: Context, + left: Handle, + right: Handle, + ) -> FGC>, BailReason> { + FGC::new((left, right)) + .check(|(l, r)| is_number(*l) && is_number(*r), BailReason::ExpectedNumber) + .map(|(l, r)| Ok(add_number_fast(cx, l, r))) + } + + fn add_bigint_handler( + cx: Context, + left: Handle, + right: Handle, + ) -> FGC>, BailReason> { + FGC::new((left, right)) + .check(|(l, r)| is_bigint(*l) && is_bigint(*r), BailReason::ExpectedBigInt) + .map(|(l, r)| add_bigint_fast(cx, l, r)) + } + + fn concat_string_handler( + cx: Context, + left: Handle, + right: Handle, + ) -> FGC>, BailReason> { + FGC::new((left, right)) + .check(|(l, r)| is_string(*l) && is_string(*r), BailReason::ExpectedString) + .map(|(l, r)| add_string_fast(cx, l.as_string(), r.as_string())) } } diff --git a/src/js/runtime/ic/mod.rs b/src/js/runtime/ic/mod.rs index be81da01..0f897901 100644 --- a/src/js/runtime/ic/mod.rs +++ b/src/js/runtime/ic/mod.rs @@ -1,5 +1,4 @@ -pub mod bytecode; -pub mod eval; +pub mod fgc; pub mod generate; pub mod stubs; pub mod vector; diff --git a/src/js/runtime/ic/stubs.rs b/src/js/runtime/ic/stubs.rs deleted file mode 100644 index 56c264c9..00000000 --- a/src/js/runtime/ic/stubs.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::{ - field_offset, - runtime::{ - alloc_error::AllocResult, - collections::InlineArray, - gc::{HeapItem, HeapVisitor}, - heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::{ - bytecode::CacheByteCode, - eval::{ICStubExecutionResult, ICStubVM}, - }, - Context, Handle, HeapPtr, Value, - }, - set_uninit, -}; - -#[repr(C)] -pub struct ICStub { - descriptor: HeapPtr, - /// pointer to the next stub - next: Option>, - /// The IR itself - code: InlineArray, -} - -impl ICStub { - const CODE_BYTE_OFFSET: usize = field_offset!(ICStub, code); - - /// Calculates the total size in bytes for an IC Stub - /// Note that the slots InlineArray can be variable length - /// The size is the byte offset of `code` + the numbers of bytes needed for the array - /// of bytecode - fn calculate_size_in_bytes(num_ops: usize) -> usize { - Self::CODE_BYTE_OFFSET + InlineArray::::calculate_size_in_bytes(num_ops) - } - - fn execute_code( - &self, - cx: Context, - left: Handle, - right: Handle, - ) -> ICStubExecutionResult { - let vm = ICStubVM::new(cx); - vm.execute(self.code.as_slice(), *left, *right) - } - - // New always makes the next head `None` - pub fn new(cx: &Context, bytes: &[CacheByteCode]) -> AllocResult> { - let size = Self::calculate_size_in_bytes(bytes.len()); - let mut object = cx.alloc_uninit_with_size::(size)?; - - set_uninit!(object.descriptor, cx.base_descriptors.get(HeapItemKind::ICStub)); - set_uninit!(object.next, None); - object.code.init_from_slice(bytes); - - Ok(object.to_handle()) - } - - pub fn set_next(&mut self, val: Option>) { - self.next = val; - } - - pub fn try_execute( - &self, - cx: Context, - left: Handle, - right: Handle, - ) -> AllocResult> { - // try to execute each individual stub in the linked list - let mut curr = Some(self); - while let Some(stub) = curr { - match stub.execute_code(cx, left, right) { - Ok(r) => return Ok(Some(r)), - // continue to next stub - Err(e) => match e { - super::eval::BailReason::FailedAllocation(alloc_error) => { - return Err(alloc_error) - } - // fall through to next - super::eval::BailReason::ExpectedSmi - | super::eval::BailReason::ExpectedNumber - | super::eval::BailReason::ExpectedString - | super::eval::BailReason::ExpectedBigInt - | super::eval::BailReason::OverflowOnSmi => {} - }, - } - curr = stub.next.as_deref(); - } - // fall through - none of the stubs were a hit - Ok(None) - } -} - -/// GC Integration for ICStub -impl HeapItem for HeapPtr { - fn byte_size(&self) -> usize { - ICStub::calculate_size_in_bytes(self.code.len()) - } - - fn visit_pointers(&mut self, visitor: &mut impl HeapVisitor) { - // visit descriptor and next ptr if it exists - visitor.visit_pointer(&mut self.descriptor); - self.next.map(|mut ptr| visitor.visit_pointer(&mut ptr)); - } -} diff --git a/src/js/runtime/ic/stubs/add.rs b/src/js/runtime/ic/stubs/add.rs new file mode 100644 index 00000000..458a4c66 --- /dev/null +++ b/src/js/runtime/ic/stubs/add.rs @@ -0,0 +1,93 @@ +use crate::{ + runtime::{ + alloc_error::AllocResult, + gc::{HeapItem, HeapVisitor}, + heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, + ic::fgc::FGC, + Context, Handle, HeapPtr, Value, + }, + set_uninit, +}; + +pub enum BailReason { + ExpectedSmi, + ExpectedNumber, + ExpectedBigInt, + ExpectedString, +} + +pub type AddICStubHandler = + fn(Context, Handle, Handle) -> FGC>, BailReason>; + +pub type ICStubExecutionResult = Result>, BailReason>; + +#[repr(C)] +pub struct AddICStub { + descriptor: HeapPtr, + /// pointer to the next stub + next: Option>, + /// The actual fast path computation + handler: AddICStubHandler, +} + +impl AddICStub { + fn execute_code( + &self, + cx: Context, + left: Handle, + right: Handle, + ) -> ICStubExecutionResult { + let intermediate = (self.handler)(cx, left, right); + match intermediate { + FGC::Yay(r) => Ok(r), + FGC::Bail(br) => Err(br), + } + } + + // New always makes the next head `None` + pub fn new(cx: &Context, handler: AddICStubHandler) -> AllocResult> { + let mut object = cx.alloc_uninit::()?; + + set_uninit!(object.descriptor, cx.base_descriptors.get(HeapItemKind::AddICStub)); + set_uninit!(object.next, None); + set_uninit!(object.handler, handler); + + Ok(object.to_handle()) + } + + pub fn set_next(&mut self, val: Option>) { + self.next = val; + } + + pub fn try_execute( + &self, + cx: Context, + left: Handle, + right: Handle, + ) -> Option>> { + // try to execute each individual stub in the linked list + let mut curr = Some(self); + while let Some(stub) = curr { + match stub.execute_code(cx, left, right) { + Ok(r) => return Some(r), + // continue to next stub + Err(_e) => {} + } + curr = stub.next.as_deref(); + } + // fall through - none of the stubs were a hit + None + } +} + +/// GC Integration for AddICStub +impl HeapItem for HeapPtr { + fn byte_size(&self) -> usize { + size_of::() + } + + fn visit_pointers(&mut self, visitor: &mut impl HeapVisitor) { + visitor.visit_pointer(&mut self.descriptor); + visitor.visit_pointer_opt(&mut self.next); + } +} diff --git a/src/js/runtime/ic/stubs/mod.rs b/src/js/runtime/ic/stubs/mod.rs new file mode 100644 index 00000000..71ae505b --- /dev/null +++ b/src/js/runtime/ic/stubs/mod.rs @@ -0,0 +1 @@ +pub mod add; \ No newline at end of file diff --git a/src/js/runtime/ic/vector.rs b/src/js/runtime/ic/vector.rs index b2069e6f..faeb0f97 100644 --- a/src/js/runtime/ic/vector.rs +++ b/src/js/runtime/ic/vector.rs @@ -5,7 +5,7 @@ use crate::{ collections::InlineArray, gc::{HeapItem, HeapVisitor}, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::stubs::ICStub, + ic::stubs::add::AddICStub, Context, Handle, HeapPtr, }, set_uninit, @@ -17,18 +17,18 @@ pub struct ICVector { /// Inline array of pointers to /// IC Stubs. Each element is a unique /// linked list of IC Stubs for an opcode - slots: InlineArray>>, + slots: InlineArray>>, } impl ICVector { /// The offset of the `slots` field in a ICVector const SLOTS_BYTE_OFFSET: usize = field_offset!(ICVector, slots); - pub fn slots(&self) -> &InlineArray>> { + pub fn slots(&self) -> &InlineArray>> { &self.slots } - pub fn slots_mut(&mut self) -> &mut InlineArray>> { + pub fn slots_mut(&mut self) -> &mut InlineArray>> { &mut self.slots } @@ -38,7 +38,7 @@ impl ICVector { /// of ic stubs fn calculate_size_in_bytes(num_slots: usize) -> usize { Self::SLOTS_BYTE_OFFSET - + InlineArray::>>::calculate_size_in_bytes(num_slots) + + InlineArray::>>::calculate_size_in_bytes(num_slots) } /// Create a new feedback vector with the passed feedback slots From 60fbcb60f2f79a638fdfd259bf8581caf76bc81b Mon Sep 17 00:00:00 2001 From: vrindisbacher Date: Fri, 22 May 2026 07:50:37 -0700 Subject: [PATCH 06/11] inline common fns --- src/js/runtime/eval/common.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/js/runtime/eval/common.rs b/src/js/runtime/eval/common.rs index 46148b2a..94b47ab0 100644 --- a/src/js/runtime/eval/common.rs +++ b/src/js/runtime/eval/common.rs @@ -5,11 +5,13 @@ use crate::runtime::{ /// Common operations that are used by IC Stubs and the interpreter /// Check if a value is a string +#[inline] pub fn is_string(val: Handle) -> bool { val.is_string() } /// Adds two strings +#[inline] pub fn add_string_fast( cx: Context, left: Handle, @@ -19,11 +21,13 @@ pub fn add_string_fast( } /// Checks if a value is a big int +#[inline] pub fn is_bigint(val: Handle) -> bool { val.is_bigint() } /// Adds two big ints +#[inline] pub fn add_bigint_fast( cx: Context, left_num: Handle, @@ -34,11 +38,13 @@ pub fn add_bigint_fast( } /// Checks if a value is a number +#[inline] pub fn is_number(val: Handle) -> bool { val.is_number() } /// Adds two numbers +#[inline] pub fn add_number_fast( cx: Context, left_num: Handle, @@ -48,11 +54,13 @@ pub fn add_number_fast( } /// Check if a value is an SMI +#[inline] pub fn is_smi(val: Handle) -> bool { val.is_smi() } /// Adds two smi's +#[inline] pub fn add_smi_fast( cx: Context, left_smi: Handle, From 9b957152cb0368cd0b740110c5cdeb875dbcb8aa Mon Sep 17 00:00:00 2001 From: vrindisbacher Date: Fri, 22 May 2026 10:33:41 -0700 Subject: [PATCH 07/11] start adding more IC stub kinds --- src/js/runtime/bytecode/generator.rs | 37 +++- src/js/runtime/bytecode/instruction.rs | 5 +- src/js/runtime/bytecode/operand.rs | 43 +++-- src/js/runtime/bytecode/stack_frame.rs | 52 ++++-- src/js/runtime/bytecode/vm.rs | 80 ++++++++- src/js/runtime/eval/common.rs | 34 ++++ src/js/runtime/eval/expression.rs | 14 +- src/js/runtime/gc/heap_item.rs | 7 +- src/js/runtime/heap_item_descriptor.rs | 2 + src/js/runtime/ic/generate.rs | 87 +++++---- .../ic/stubs/{add.rs => binary_arith.rs} | 39 ++-- src/js/runtime/ic/stubs/mod.rs | 2 +- src/js/runtime/ic/vector.rs | 30 +++- .../js_bytecode/arguments_object/binding.exp | 2 +- tests/js_bytecode/arguments_object/mapped.exp | 4 +- tests/js_bytecode/bytecode/assign_hazard.exp | 24 +-- tests/js_bytecode/class/fields.exp | 22 +-- tests/js_bytecode/class/methods.exp | 8 +- tests/js_bytecode/class/private_member.exp | 2 +- .../js_bytecode/class/static_initializer.exp | 18 +- tests/js_bytecode/class/super_class.exp | 2 +- tests/js_bytecode/eval/completion.exp | 4 +- .../eval/dynamic_lookup_out_of_eval.exp | 2 +- tests/js_bytecode/eval/forces_dynamic.exp | 4 +- .../js_bytecode/eval/function_constructor.exp | 6 +- tests/js_bytecode/example_program/fib.exp | 16 +- .../js_bytecode/expression/arrow_function.exp | 6 +- tests/js_bytecode/expression/assign.exp | 170 +++++++++--------- tests/js_bytecode/expression/binary.exp | 50 +++--- tests/js_bytecode/expression/calls/basic.exp | 2 +- tests/js_bytecode/expression/calls/member.exp | 6 +- tests/js_bytecode/expression/conditional.exp | 12 +- tests/js_bytecode/expression/delete.exp | 4 +- tests/js_bytecode/expression/function.exp | 4 +- tests/js_bytecode/expression/logical.exp | 16 +- tests/js_bytecode/expression/member.exp | 4 +- tests/js_bytecode/expression/new.exp | 2 +- tests/js_bytecode/expression/new_target.exp | 8 +- tests/js_bytecode/expression/object/basic.exp | 8 +- .../expression/object/named_evalution.exp | 2 +- tests/js_bytecode/expression/super_member.exp | 2 +- .../expression/tagged_template.exp | 10 +- .../expression/template_literal.exp | 26 +-- tests/js_bytecode/expression/this.exp | 2 +- tests/js_bytecode/function/async.exp | 4 +- tests/js_bytecode/function/basic.exp | 2 +- tests/js_bytecode/function/generator.exp | 2 +- tests/js_bytecode/function/parameters.exp | 10 +- tests/js_bytecode/module/dynamic_import.exp | 4 +- .../module/export_default_expression.exp | 2 +- .../js_bytecode/module/exported_bindings.exp | 14 +- tests/js_bytecode/module/import_meta.exp | 2 +- .../module/import_named/import_named.exp | 8 +- .../module/reexport_named/importing.exp | 4 +- .../module/reexport_star/importing.exp | 2 +- tests/js_bytecode/module/top_level_await.exp | 4 +- tests/js_bytecode/module/toplevel.exp | 8 +- tests/js_bytecode/scope/captured.exp | 48 ++--- tests/js_bytecode/scope/captured_this.exp | 10 +- tests/js_bytecode/scope/catch.exp | 4 +- tests/js_bytecode/scope/for.exp | 8 +- tests/js_bytecode/scope/for_break.exp | 14 +- tests/js_bytecode/scope/for_continue.exp | 14 +- tests/js_bytecode/scope/for_in.exp | 4 +- tests/js_bytecode/scope/for_in_break.exp | 14 +- tests/js_bytecode/scope/for_in_continue.exp | 14 +- tests/js_bytecode/scope/for_of.exp | 4 +- tests/js_bytecode/scope/for_of_break.exp | 8 +- tests/js_bytecode/scope/for_of_continue.exp | 8 +- tests/js_bytecode/scope/function.exp | 8 +- tests/js_bytecode/scope/function_body.exp | 4 +- tests/js_bytecode/scope/labeled_break.exp | 4 +- tests/js_bytecode/scope/switch.exp | 4 +- tests/js_bytecode/scope/with.exp | 12 +- .../statement/const_let_declaration.exp | 10 +- .../statement/lexical_declaration.exp | 4 +- tests/js_bytecode/statement/try/catch.exp | 2 +- .../statement/try/finally_break.exp | 4 +- .../statement/try/finally_continue.exp | 4 +- .../js_bytecode/statement/var_declaration.exp | 6 +- tests/js_bytecode/statement/with.exp | 4 +- 81 files changed, 695 insertions(+), 467 deletions(-) rename src/js/runtime/ic/stubs/{add.rs => binary_arith.rs} (65%) diff --git a/src/js/runtime/bytecode/generator.rs b/src/js/runtime/bytecode/generator.rs index 7a88e3fa..dad95dfc 100644 --- a/src/js/runtime/bytecode/generator.rs +++ b/src/js/runtime/bytecode/generator.rs @@ -34,7 +34,7 @@ use crate::{ bytecode::{ function::{dump_bytecode_function, BytecodeFunction}, instruction::DefinePropertyFlags, - operand::ICSlotIndex, + operand::{AddICSlotIndex, SubICSlotIndex}, source_map::BytecodeSourceMap, }, class_names::{ClassNames, HomeObjectLocation, Method}, @@ -3364,10 +3364,24 @@ impl<'a> BytecodeFunctionGenerator<'a> { ast::BinaryOperator::Add => { // Add feedback slot with add type uninitialized let slot_offset = self.add_ic_stub(); - self.writer - .add_instruction(dest, left, right, ICSlotIndex::new(slot_offset), pos) + self.writer.add_instruction( + dest, + left, + right, + AddICSlotIndex::new(slot_offset), + pos, + ) + } + ast::BinaryOperator::Subtract => { + let slot_offset = self.add_ic_stub(); + self.writer.sub_instruction( + dest, + left, + right, + SubICSlotIndex::new(slot_offset), + pos, + ) } - ast::BinaryOperator::Subtract => self.writer.sub_instruction(dest, left, right, pos), ast::BinaryOperator::Multiply => self.writer.mul_instruction(dest, left, right, pos), ast::BinaryOperator::Divide => self.writer.div_instruction(dest, left, right, pos), ast::BinaryOperator::Remainder => self.writer.rem_instruction(dest, left, right, pos), @@ -4775,12 +4789,19 @@ impl<'a> BytecodeFunctionGenerator<'a> { dest, left, right, - ICSlotIndex::new(ic_stub_offset), + AddICSlotIndex::new(ic_stub_offset), pos, ) } ast::AssignmentOperator::Subtract => { - self.writer.sub_instruction(dest, left, right, pos) + let ic_stub_offset = self.add_ic_stub(); + self.writer.sub_instruction( + dest, + left, + right, + SubICSlotIndex::new(ic_stub_offset), + pos, + ) } ast::AssignmentOperator::Multiply => { self.writer.mul_instruction(dest, left, right, pos) @@ -5961,7 +5982,7 @@ impl<'a> BytecodeFunctionGenerator<'a> { acc, acc, temp, - ICSlotIndex::new(ic_stub_offset), + AddICSlotIndex::new(ic_stub_offset), NO_POS, ); @@ -5992,7 +6013,7 @@ impl<'a> BytecodeFunctionGenerator<'a> { acc, acc, temp, - ICSlotIndex::new(ic_stub_offset), + AddICSlotIndex::new(ic_stub_offset), NO_POS, ); } diff --git a/src/js/runtime/bytecode/instruction.rs b/src/js/runtime/bytecode/instruction.rs index 19602856..9f17d20e 100644 --- a/src/js/runtime/bytecode/instruction.rs +++ b/src/js/runtime/bytecode/instruction.rs @@ -13,7 +13,7 @@ use super::{ use crate::{ count, replace_expr, - runtime::{bytecode::operand::ICSlotIndex, debug_print::DebugPrinter}, + runtime::{bytecode::operand::{AddICSlotIndex, SubICSlotIndex}, debug_print::DebugPrinter}, }; /// Generic properties of instructions. @@ -569,7 +569,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, - [3] ic_stub_offset: ICSlotIndex, + [3] ic_stub_offset: AddICSlotIndex, } } @@ -582,6 +582,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] ic_stub_offset: SubICSlotIndex, } } diff --git a/src/js/runtime/bytecode/operand.rs b/src/js/runtime/bytecode/operand.rs index 79133439..9e87b79d 100644 --- a/src/js/runtime/bytecode/operand.rs +++ b/src/js/runtime/bytecode/operand.rs @@ -123,15 +123,17 @@ operand_type!(SInt, SIGNED); // An index into the constant table operand_type!(ConstantIndex, UNSIGNED); -// An index into a feedback vector -operand_type!(ICSlotIndex, UNSIGNED); +// Indices into ICs +operand_type!(AddICSlotIndex, UNSIGNED); +operand_type!(SubICSlotIndex, UNSIGNED); pub enum OperandType { Register, UInt, SInt, ConstantIndex, - ICSlotIndex, + AddICSlotIndex, + SubICSlotIndex, } /// Registers may be either registers local to a function or arguments to that function. Registers @@ -315,30 +317,37 @@ impl ConstantIndex { } } -impl ICSlotIndex { - #[inline] - pub fn new(value: W::UInt) -> Self { - Self::from_unsigned(value) - } +macro_rules! define_ic_slot_index_impl { + ($($name:ident),* $(,)?) => { + $( + impl $name { + #[inline] + pub fn new(value: W::UInt) -> Self { + Self::from_unsigned(value) + } + #[inline] + pub fn value(&self) -> W::UInt { + self.unsigned() + } + } - #[inline] - pub fn value(&self) -> W::UInt { - self.unsigned() + impl fmt::Display for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ic{}", self.value()) + } + } + )* } } +define_ic_slot_index_impl!(AddICSlotIndex, SubICSlotIndex); + impl fmt::Display for ConstantIndex { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "c{}", self.value()) } } -impl fmt::Display for ICSlotIndex { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "fb{}", self.value()) - } -} - /// Return the minimum width needed to fit the given signed value. pub fn min_width_for_signed(value: isize) -> WidthEnum { if (Narrow::SIGNED_MIN..=Narrow::SIGNED_MAX).contains(&value) { diff --git a/src/js/runtime/bytecode/stack_frame.rs b/src/js/runtime/bytecode/stack_frame.rs index bc5f4990..5845bc30 100644 --- a/src/js/runtime/bytecode/stack_frame.rs +++ b/src/js/runtime/bytecode/stack_frame.rs @@ -1,6 +1,13 @@ use crate::runtime::{ + bytecode::{ + operand::{AddICSlotIndex, SubICSlotIndex}, + width::{UnsignedWidthRepr, Width}, + }, gc::HeapVisitor, - ic::{stubs::add::AddICStub, vector::ICVector}, + ic::{ + stubs::binary_arith::{AddICStub, SubICStub}, + vector::{ICEntry, ICVector}, + }, scope::Scope, Handle, HeapPtr, Value, }; @@ -206,19 +213,44 @@ impl StackFrame { } #[inline] - pub fn get_ic_stub(&self, slot: usize) -> Option> { + pub fn get_ic_stub(&self, slot: usize) -> Option { *self.ic_vector().slots().get_unchecked(slot) } #[inline] - pub fn add_ic_stub(&mut self, slot: usize, mut stub: Handle) { - let slots = self.ic_vector_mut().slots_mut(); - let head = slots.get_unchecked_mut(slot); - // Prepend the stub: - // Put the current stub at the beginning of the linked list - // with the original head as the second element - stub.set_next(*head); - *head = Some(*stub); + pub fn insert_sub_ic_stub( + &mut self, + slot: SubICSlotIndex, + mut stub: Handle, + ) { + let head = self + .ic_vector_mut() + .slots_mut() + .get_unchecked_mut(slot.value().to_usize()); + match head { + Some(ICEntry::Sub(ptr)) => stub.set_next(Some(*ptr)), + Some(_) => unreachable!("SubICStub head was a different type than expected."), + None => stub.set_next(None), + } + *head = Some(ICEntry::Sub(*stub)); + } + + #[inline] + pub fn insert_add_ic_stub( + &mut self, + slot: AddICSlotIndex, + mut stub: Handle, + ) { + let head = self + .ic_vector_mut() + .slots_mut() + .get_unchecked_mut(slot.value().to_usize()); + match head { + Some(ICEntry::Add(ptr)) => stub.set_next(Some(*ptr)), + Some(_) => unreachable!("SubICStub head was a different type than expected."), + None => stub.set_next(None), + } + *head = Some(ICEntry::Add(*stub)); } /// The callee function in this stack frame. diff --git a/src/js/runtime/bytecode/vm.rs b/src/js/runtime/bytecode/vm.rs index 384f8b93..f14857f5 100644 --- a/src/js/runtime/bytecode/vm.rs +++ b/src/js/runtime/bytecode/vm.rs @@ -18,6 +18,7 @@ use crate::{ array_object::{array_create, ArrayObject}, async_generator_object::{async_generator_complete_step, AsyncGeneratorObject}, boxed_value::BoxedValue, + bytecode::operand::{AddICSlotIndex, SubICSlotIndex}, class_names::{new_class, ClassNames}, error::{ err_assign_constant, err_cannot_set_property, err_not_defined, reference_error, @@ -41,7 +42,11 @@ use crate::{ generator_object::{GeneratorCompletionType, GeneratorObject, TGeneratorObject}, get, heap_item_descriptor::HeapItemKind, - ic::{generate::ICStubGenerator, stubs::add::AddICStub, vector::ICVector}, + ic::{ + generate::ICStubGenerator, + stubs::binary_arith::{AddICStub, SubICStub}, + vector::{ICEntry, ICVector}, + }, intrinsics::{ async_generator_prototype::AsyncGeneratorPrototype, generator_prototype::GeneratorPrototype, @@ -222,13 +227,49 @@ impl VM { } #[inline] - fn get_ic_stub(&self, slot_index: usize) -> Option> { - self.stack_frame().get_ic_stub(slot_index) + fn get_add_ic_stub( + &self, + slot_index: AddICSlotIndex, + ) -> Option> { + match self + .stack_frame() + .get_ic_stub(slot_index.value().to_usize())? + { + ICEntry::Add(heap_ptr) => Some(heap_ptr), + _ => unreachable!("Expected AddICStub but got different stub kind"), + } } #[inline] - fn add_ic_stub(&mut self, slot_index: usize, slot: Handle) { - self.stack_frame().add_ic_stub(slot_index, slot); + fn get_sub_ic_stub( + &self, + slot_index: SubICSlotIndex, + ) -> Option> { + match self + .stack_frame() + .get_ic_stub(slot_index.value().to_usize())? + { + ICEntry::Sub(heap_ptr) => Some(heap_ptr), + _ => unreachable!("Expected SubICStub but got different stub kind"), + } + } + + #[inline] + fn insert_sub_ic_stub( + &mut self, + slot_index: SubICSlotIndex, + slot: Handle, + ) { + self.stack_frame().insert_sub_ic_stub(slot_index, slot); + } + + #[inline] + fn insert_add_ic_stub( + &mut self, + slot_index: AddICSlotIndex, + slot: Handle, + ) { + self.stack_frame().insert_add_ic_stub(slot_index, slot); } pub fn stack_trace_top(&self) -> Option { @@ -2749,10 +2790,10 @@ impl VM { let left_value = self.read_register_to_handle(instr.left()); let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - let slot_index = instr.ic_stub_offset().value().to_usize(); + let slot_index = instr.ic_stub_offset(); // Get the IC Stub at the head of the linked list and try to execute each one - if let Some(stub) = self.get_ic_stub(slot_index) { + if let Some(stub) = self.get_add_ic_stub(slot_index) { match stub.try_execute(self.cx(), left_value, right_value) { Some(result) => { // write to register @@ -2773,7 +2814,7 @@ impl VM { // May allocate if let Some(new_stub) = gen.new_stub_for_add(&left_value, &right_value, &result) { // add the stub to the slot - self.add_ic_stub(slot_index, new_stub?); + self.insert_add_ic_stub(slot_index, new_stub?); } self.write_register(dest, *result); @@ -2788,10 +2829,33 @@ impl VM { let left_value = self.read_register_to_handle(instr.left()); let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); + let slot_index = instr.ic_stub_offset(); + + // Get the IC Stub at the head of the linked list and try to execute each one + if let Some(stub) = self.get_sub_ic_stub(slot_index) { + match stub.try_execute(self.cx(), left_value, right_value) { + Some(result) => { + // write to register + self.write_register(dest, *result?); + // exit - a stub succeeded and we're done + return Ok(()); + } + // fall through to the slow path + None => {} + } + }; // May allocate let result = eval_subtract(self.cx(), left_value, right_value)?; + // compile the stub from the left_value, right_value and result + let gen = ICStubGenerator::new(&self.cx); + // May allocate + if let Some(new_stub) = gen.new_stub_for_sub(&left_value, &right_value, &result) { + // add the stub to the slot + self.insert_sub_ic_stub(slot_index, new_stub?); + } + self.write_register(dest, *result); Ok(()) diff --git a/src/js/runtime/eval/common.rs b/src/js/runtime/eval/common.rs index 94b47ab0..ed608419 100644 --- a/src/js/runtime/eval/common.rs +++ b/src/js/runtime/eval/common.rs @@ -71,3 +71,37 @@ pub fn add_smi_fast( None => add_number_fast(cx, left_smi, right_smi), } } + +/// Subs two numbers +#[inline] +pub fn sub_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + cx.number(left_num.as_number() - right_num.as_number()) +} + +/// Subs two smis +#[inline] +pub fn sub_smi_fast( + cx: Context, + left_smi: Handle, + right_smi: Handle, +) -> Handle { + match left_smi.as_smi().checked_sub(right_smi.as_smi()) { + Some(r) => cx.smi(r), + None => sub_number_fast(cx, left_smi, right_smi), + } +} + +/// Subs two big ints +#[inline] +pub fn sub_bigint_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> AllocResult> { + let result = left_num.as_bigint().bigint() - right_num.as_bigint().bigint(); + Ok(BigIntValue::new(cx, result)?.into()) +} diff --git a/src/js/runtime/eval/expression.rs b/src/js/runtime/eval/expression.rs index 7155c730..c961d555 100644 --- a/src/js/runtime/eval/expression.rs +++ b/src/js/runtime/eval/expression.rs @@ -13,7 +13,10 @@ use crate::{ alloc_error::AllocResult, array_object::array_create_in_realm, error::{range_error, type_error}, - eval::common::{add_bigint_fast, add_number_fast, add_string_fast, is_bigint, is_string}, + eval::common::{ + add_bigint_fast, add_number_fast, add_string_fast, is_bigint, is_string, + sub_bigint_fast, sub_number_fast, + }, eval_result::EvalResult, heap_item_descriptor::HeapItemKind, numeric_operations::number_exponentiate, @@ -174,16 +177,15 @@ pub fn eval_subtract( let left_num = to_numeric(cx, left_value)?; let right_num = to_numeric(cx, right_value)?; - let left_is_bigint = left_num.is_bigint(); - if left_is_bigint != right_num.is_bigint() { + let left_is_bigint = is_bigint(left_num); + if left_is_bigint != is_bigint(right_num) { return type_error(cx, "BigInt cannot be converted to number"); } if left_is_bigint { - let result = left_num.as_bigint().bigint() - right_num.as_bigint().bigint(); - Ok(BigIntValue::new(cx, result)?.into()) + Ok(sub_bigint_fast(cx, left_num, right_num)?) } else { - Ok(cx.number(left_num.as_number() - right_num.as_number())) + Ok(sub_number_fast(cx, left_num, right_num)) } } diff --git a/src/js/runtime/gc/heap_item.rs b/src/js/runtime/gc/heap_item.rs index 9d14d727..7a9ae802 100644 --- a/src/js/runtime/gc/heap_item.rs +++ b/src/js/runtime/gc/heap_item.rs @@ -23,7 +23,10 @@ use crate::runtime::{ generator_object::GeneratorObject, global_names::GlobalNames, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::{stubs::add::AddICStub, vector::ICVector}, + ic::{ + stubs::binary_arith::{AddICStub, SubICStub}, + vector::ICVector, + }, interned_strings::InternedStringsSetField, intrinsics::{ array_buffer_constructor::ArrayBufferObject, @@ -220,6 +223,7 @@ impl HeapPtr { HeapItemKind::ValueVec => value_vec_byte_size(self.cast()), HeapItemKind::ICVector => self.cast::().byte_size(), HeapItemKind::AddICStub => self.cast::().byte_size(), + HeapItemKind::SubICStub => self.cast::().byte_size(), HeapItemKind::Last => unreachable!("No objects are created with this descriptor"), } } @@ -385,6 +389,7 @@ impl HeapPtr { HeapItemKind::ValueVec => value_vec_visit_pointers(self.cast_mut(), visitor), HeapItemKind::ICVector => self.cast::().visit_pointers(visitor), HeapItemKind::AddICStub => self.cast::().visit_pointers(visitor), + HeapItemKind::SubICStub => self.cast::().visit_pointers(visitor), HeapItemKind::Last => unreachable!("No objects are created with this descriptor"), } } diff --git a/src/js/runtime/heap_item_descriptor.rs b/src/js/runtime/heap_item_descriptor.rs index 4d89867b..25ae3d7c 100644 --- a/src/js/runtime/heap_item_descriptor.rs +++ b/src/js/runtime/heap_item_descriptor.rs @@ -162,6 +162,7 @@ pub enum HeapItemKind { // IC Vectors and IC Stubs ICVector, AddICStub, + SubICStub, // Numerical value is the number of kinds in the enum Last, @@ -399,6 +400,7 @@ impl BaseDescriptors { other_heap_item_descriptor!(HeapItemKind::ICVector); other_heap_item_descriptor!(HeapItemKind::AddICStub); + other_heap_item_descriptor!(HeapItemKind::SubICStub); Ok(base_descriptors) } diff --git a/src/js/runtime/ic/generate.rs b/src/js/runtime/ic/generate.rs index 64432155..7634a59a 100644 --- a/src/js/runtime/ic/generate.rs +++ b/src/js/runtime/ic/generate.rs @@ -1,4 +1,5 @@ -use crate::runtime::ic::stubs::add::BailReason; +use crate::runtime::eval::common::{sub_bigint_fast, sub_number_fast, sub_smi_fast}; +use crate::runtime::ic::stubs::binary_arith::{AddICStub, BailReason, SubICStub}; use crate::runtime::Context; use crate::runtime::{ alloc_error::AllocResult, @@ -6,10 +7,24 @@ use crate::runtime::{ add_bigint_fast, add_number_fast, add_smi_fast, add_string_fast, is_bigint, is_number, is_smi, is_string, }, - ic::{fgc::FGC, stubs::add::AddICStub}, + ic::fgc::FGC, Handle, Value, }; +macro_rules! binop_handler { + ($name:ident, $check:ident, $bail:ident, $fast:expr) => { + fn $name( + cx: Context, + left: Handle, + right: Handle, + ) -> FGC>, BailReason> { + FGC::new((left, right)) + .check(|(l, r)| $check(*l) && $check(*r), BailReason::$bail) + .map(|(l, r)| $fast(cx, l, r)) + } + }; +} + pub struct ICStubGenerator<'cx> { cx: &'cx Context, } @@ -19,6 +34,37 @@ impl<'cx> ICStubGenerator<'cx> { Self { cx } } + pub fn new_stub_for_sub( + &self, + left: &Value, + right: &Value, + result: &Value, + ) -> Option>> { + let handler = if left.is_smi() && right.is_smi() { + if result.is_smi() { + Self::sub_smi_handler + } else { + Self::sub_number_handler + } + } else if left.is_number() && right.is_number() { + Self::sub_number_handler + } else if left.is_bigint() && right.is_bigint() { + Self::sub_bigint_handler + } else { + return None; + }; + Some(SubICStub::new(self.cx, handler)) + } + + // IC Stubs for `Sub` on each type + binop_handler!(sub_smi_handler, is_smi, ExpectedSmi, |cx, l, r| Ok(sub_smi_fast(cx, l, r))); + binop_handler!(sub_number_handler, is_number, ExpectedSmi, |cx, l, r| Ok(sub_number_fast( + cx, l, r + ))); + binop_handler!(sub_bigint_handler, is_bigint, ExpectedSmi, |cx, l, r| sub_bigint_fast( + cx, l, r + )); + pub fn new_stub_for_add( &self, left: &Value, @@ -50,35 +96,14 @@ impl<'cx> ICStubGenerator<'cx> { Some(AddICStub::new(self.cx, handler)) } - fn add_smi_handler( - cx: Context, - left: Handle, - right: Handle, - ) -> FGC>, BailReason> { - FGC::new((left, right)) - .check(|(l, r)| is_smi(*l) && is_smi(*r), BailReason::ExpectedSmi) - .map(|(l, r)| Ok(add_smi_fast(cx, l, r))) - } - - fn add_number_handler( - cx: Context, - left: Handle, - right: Handle, - ) -> FGC>, BailReason> { - FGC::new((left, right)) - .check(|(l, r)| is_number(*l) && is_number(*r), BailReason::ExpectedNumber) - .map(|(l, r)| Ok(add_number_fast(cx, l, r))) - } - - fn add_bigint_handler( - cx: Context, - left: Handle, - right: Handle, - ) -> FGC>, BailReason> { - FGC::new((left, right)) - .check(|(l, r)| is_bigint(*l) && is_bigint(*r), BailReason::ExpectedBigInt) - .map(|(l, r)| add_bigint_fast(cx, l, r)) - } + // IC Stubs for `Add` on each type + binop_handler!(add_smi_handler, is_smi, ExpectedSmi, |cx, l, r| Ok(add_smi_fast(cx, l, r))); + binop_handler!(add_number_handler, is_number, ExpectedSmi, |cx, l, r| Ok(add_number_fast( + cx, l, r + ))); + binop_handler!(add_bigint_handler, is_bigint, ExpectedSmi, |cx, l, r| add_bigint_fast( + cx, l, r + )); fn concat_string_handler( cx: Context, diff --git a/src/js/runtime/ic/stubs/add.rs b/src/js/runtime/ic/stubs/binary_arith.rs similarity index 65% rename from src/js/runtime/ic/stubs/add.rs rename to src/js/runtime/ic/stubs/binary_arith.rs index 458a4c66..b6e8e59c 100644 --- a/src/js/runtime/ic/stubs/add.rs +++ b/src/js/runtime/ic/stubs/binary_arith.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use crate::{ runtime::{ alloc_error::AllocResult, @@ -16,21 +18,33 @@ pub enum BailReason { ExpectedString, } -pub type AddICStubHandler = +pub type BinaryArithICStubHandler = fn(Context, Handle, Handle) -> FGC>, BailReason>; pub type ICStubExecutionResult = Result>, BailReason>; +/// Zero sized type marking the Add Op +pub struct AddOp; +/// Zero sized type marking the Sub Op +pub struct SubOp; + +/// Stub definition for Add +pub type AddICStub = BinaryArithICStub; +/// Stub definition for Sub +pub type SubICStub = BinaryArithICStub; + #[repr(C)] -pub struct AddICStub { +pub struct BinaryArithICStub { descriptor: HeapPtr, /// pointer to the next stub - next: Option>, + next: Option>>, /// The actual fast path computation - handler: AddICStubHandler, + handler: BinaryArithICStubHandler, + /// A zero sized marker that makes the IC stub chain typesafe + _phantom: PhantomData, } -impl AddICStub { +impl BinaryArithICStub { fn execute_code( &self, cx: Context, @@ -45,8 +59,11 @@ impl AddICStub { } // New always makes the next head `None` - pub fn new(cx: &Context, handler: AddICStubHandler) -> AllocResult> { - let mut object = cx.alloc_uninit::()?; + pub fn new( + cx: &Context, + handler: BinaryArithICStubHandler, + ) -> AllocResult>> { + let mut object = cx.alloc_uninit::>()?; set_uninit!(object.descriptor, cx.base_descriptors.get(HeapItemKind::AddICStub)); set_uninit!(object.next, None); @@ -55,7 +72,9 @@ impl AddICStub { Ok(object.to_handle()) } - pub fn set_next(&mut self, val: Option>) { + /// Set the next one in the chain - note that it's impossible to + /// add two ICStubs for different ops because of the `Op` type marker + pub fn set_next(&mut self, val: Option>>) { self.next = val; } @@ -81,9 +100,9 @@ impl AddICStub { } /// GC Integration for AddICStub -impl HeapItem for HeapPtr { +impl HeapItem for HeapPtr> { fn byte_size(&self) -> usize { - size_of::() + size_of::>() } fn visit_pointers(&mut self, visitor: &mut impl HeapVisitor) { diff --git a/src/js/runtime/ic/stubs/mod.rs b/src/js/runtime/ic/stubs/mod.rs index 71ae505b..18d5d68f 100644 --- a/src/js/runtime/ic/stubs/mod.rs +++ b/src/js/runtime/ic/stubs/mod.rs @@ -1 +1 @@ -pub mod add; \ No newline at end of file +pub mod binary_arith; \ No newline at end of file diff --git a/src/js/runtime/ic/vector.rs b/src/js/runtime/ic/vector.rs index faeb0f97..3d71691d 100644 --- a/src/js/runtime/ic/vector.rs +++ b/src/js/runtime/ic/vector.rs @@ -5,30 +5,38 @@ use crate::{ collections::InlineArray, gc::{HeapItem, HeapVisitor}, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::stubs::add::AddICStub, + ic::stubs::binary_arith::{AddICStub, SubICStub}, Context, Handle, HeapPtr, }, set_uninit, }; +#[derive(Clone, Copy)] +pub enum ICEntry { + Add(HeapPtr), + Sub(HeapPtr), + // Mul(HeapPtr), + // Div(HeapPtr), +} + #[repr(C)] pub struct ICVector { descriptor: HeapPtr, /// Inline array of pointers to /// IC Stubs. Each element is a unique /// linked list of IC Stubs for an opcode - slots: InlineArray>>, + slots: InlineArray>, } impl ICVector { /// The offset of the `slots` field in a ICVector const SLOTS_BYTE_OFFSET: usize = field_offset!(ICVector, slots); - pub fn slots(&self) -> &InlineArray>> { + pub fn slots(&self) -> &InlineArray> { &self.slots } - pub fn slots_mut(&mut self) -> &mut InlineArray>> { + pub fn slots_mut(&mut self) -> &mut InlineArray> { &mut self.slots } @@ -37,8 +45,7 @@ impl ICVector { /// The size is the byte offset of `slots` + the numbers of bytes needed for the array /// of ic stubs fn calculate_size_in_bytes(num_slots: usize) -> usize { - Self::SLOTS_BYTE_OFFSET - + InlineArray::>>::calculate_size_in_bytes(num_slots) + Self::SLOTS_BYTE_OFFSET + InlineArray::>::calculate_size_in_bytes(num_slots) } /// Create a new feedback vector with the passed feedback slots @@ -72,9 +79,16 @@ impl HeapItem for HeapPtr { fn visit_pointers(&mut self, visitor: &mut impl HeapVisitor) { // visit the descriptor visitor.visit_pointer(&mut self.descriptor); - // visit each IC Stub + // visit each ICEntry's underlying Stub for stub in self.slots.as_mut_slice() { - visitor.visit_pointer_opt(stub) + if let Some(ptr) = stub { + match ptr { + ICEntry::Add(heap_ptr) => visitor.visit_pointer(heap_ptr), + ICEntry::Sub(heap_ptr) => visitor.visit_pointer(heap_ptr), + // ICEntry::Mul(heap_ptr) => visitor.visit_pointer(heap_ptr), + // ICEntry::Div(heap_ptr) => visitor.visit_pointer(heap_ptr), + } + } } } } diff --git a/tests/js_bytecode/arguments_object/binding.exp b/tests/js_bytecode/arguments_object/binding.exp index 8b54b1ba..74dafb02 100644 --- a/tests/js_bytecode/arguments_object/binding.exp +++ b/tests/js_bytecode/arguments_object/binding.exp @@ -17,7 +17,7 @@ Parameters: 0, Registers: 2 0: NewUnmappedArguments r0 2: LoadImmediate r1, 1 - 5: Add r1, r0, r1, fb0 + 5: Add r1, r0, r1, ic0 10: LoadUndefined r1 12: Ret r1 } diff --git a/tests/js_bytecode/arguments_object/mapped.exp b/tests/js_bytecode/arguments_object/mapped.exp index 73567f7a..c1fa0f73 100644 --- a/tests/js_bytecode/arguments_object/mapped.exp +++ b/tests/js_bytecode/arguments_object/mapped.exp @@ -77,8 +77,8 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 3, 0 4: LoadFromScope r1, 4, 0 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: LoadFromScope r1, 2, 0 - 17: Add r0, r0, r1, fb1 + 17: Add r0, r0, r1, ic1 22: Ret r0 } diff --git a/tests/js_bytecode/bytecode/assign_hazard.exp b/tests/js_bytecode/bytecode/assign_hazard.exp index 985a455c..5adbc3bd 100644 --- a/tests/js_bytecode/bytecode/assign_hazard.exp +++ b/tests/js_bytecode/bytecode/assign_hazard.exp @@ -45,7 +45,7 @@ Parameters: 1, Registers: 1 0: Mov r0, a0 3: LoadImmediate a0, 2 - 6: Add r0, r0, a0, fb0 + 6: Add r0, r0, a0, ic0 11: Ret r0 } @@ -53,7 +53,7 @@ Parameters: 1, Registers: 1 0: Mov r0, a0 3: LoadImmediate a0, 2 - 6: Add r0, r0, a0, fb0 + 6: Add r0, r0, a0, ic0 11: JumpToBooleanFalse r0, 3 (.L0) .L0: 14: LoadUndefined r0 @@ -65,7 +65,7 @@ 0: JumpNotUndefined a1, 14 (.L0) 3: Mov r0, a0 6: LoadImmediate a0, 2 - 9: Add a1, r0, a0, fb0 + 9: Add a1, r0, a0, ic0 .L0: 14: LoadUndefined r0 16: Ret r0 @@ -76,7 +76,7 @@ 0: RestParameter r1 2: Mov r2, a0 5: LoadImmediate a0, 2 - 8: Add r2, r2, a0, fb0 + 8: Add r2, r2, a0, ic0 13: GetProperty r0, r1, r2 17: LoadUndefined r1 19: Ret r1 @@ -89,7 +89,7 @@ 6: JumpNotUndefined r2, 14 (.L0) 9: Mov r3, a0 12: LoadImmediate a0, 2 - 15: Add r2, r3, a0, fb0 + 15: Add r2, r3, a0, ic0 .L0: 20: Mov r0, r2 23: LoadUndefined r1 @@ -106,7 +106,7 @@ 8: Mov , r1 11: Mov r3, a0 14: LoadImmediate a0, 2 - 17: Add r3, r3, a0, fb0 + 17: Add r3, r3, a0, ic0 22: GetProperty r0, r2, r3 26: LoadImmediate r2, 3 .L0: @@ -126,7 +126,7 @@ 11: JumpNullish r1, 20 (.L1) 14: Mov r2, a0 17: LoadImmediate a0, 2 - 20: Add r2, r2, a0, fb0 + 20: Add r2, r2, a0, ic0 25: GetProperty a1, r1, r2 29: Jump -21 (.L0) .L1: @@ -137,10 +137,10 @@ [BytecodeFunction: toplevelAssignExpressions] { Parameters: 2, Registers: 1 0: LoadImmediate r0, 1 - 3: Add a0, a0, r0, fb0 + 3: Add a0, a0, r0, ic0 8: Mov r0, a0 11: LoadImmediate a0, 2 - 14: Add a1, r0, a0, fb1 + 14: Add a1, r0, a0, ic1 19: LoadImmediate a0, 3 22: Mov a1, a0 25: LoadUndefined r0 @@ -150,13 +150,13 @@ [BytecodeFunction: nestedFunctionOrClass] { Parameters: 2, Registers: 2 0: NewClosure r0, c0 - 3: Add a0, a1, r0, fb0 + 3: Add a0, a1, r0, ic0 8: NewClosure r0, c1 - 11: Add a0, a1, r0, fb1 + 11: Add a0, a1, r0, ic1 16: NewObject r0 18: NewClosure r1, c3 21: DefineNamedProperty r0, c2, r1 - 25: Add a0, a1, r0, fb2 + 25: Add a0, a1, r0, ic2 30: LoadUndefined r0 32: Ret r0 Constant Table: diff --git a/tests/js_bytecode/class/fields.exp b/tests/js_bytecode/class/fields.exp index 23b6eb0d..5eeb0e13 100644 --- a/tests/js_bytecode/class/fields.exp +++ b/tests/js_bytecode/class/fields.exp @@ -119,12 +119,12 @@ 2: LoadEmpty r1 4: LoadImmediate r2, 1 7: LoadImmediate r3, 2 - 10: Add r2, r2, r3, fb0 + 10: Add r2, r2, r3, ic0 15: ToPropertyKey r2, r2 18: StoreToScope r2, 0, 0 22: LoadImmediate r2, 3 25: LoadImmediate r3, 4 - 28: Add r2, r2, r3, fb1 + 28: Add r2, r2, r3, ic1 33: ToPropertyKey r2, r2 36: StoreToScope r2, 1, 0 40: NewClass r0, c2, c1, r1, r0 @@ -229,12 +229,12 @@ 14: StoreToScope r2, 5, 0 18: LoadImmediate r2, 1 21: LoadImmediate r3, 2 - 24: Add r2, r2, r3, fb0 + 24: Add r2, r2, r3, ic0 29: ToPropertyKey r2, r2 32: StoreToScope r2, 0, 0 36: LoadImmediate r2, 3 39: LoadImmediate r3, 4 - 42: Add r2, r2, r3, fb1 + 42: Add r2, r2, r3, ic1 47: ToPropertyKey r2, r2 50: StoreToScope r2, 1, 0 54: NewClass r0, c4, c3, r1, r0 @@ -300,7 +300,7 @@ 2: LoadEmpty r1 4: LoadImmediate r2, 1 7: LoadImmediate r3, 2 - 10: Add r2, r2, r3, fb0 + 10: Add r2, r2, r3, ic0 15: ToPropertyKey r2, r2 18: StoreToScope r2, 0, 0 22: NewClass r0, c2, c1, r1, r0 @@ -432,12 +432,12 @@ 18: NewClosure r2, c3 21: LoadImmediate r3, 1 24: LoadImmediate r4, 2 - 27: Add r3, r3, r4, fb0 + 27: Add r3, r3, r4, ic0 32: ToPropertyKey r3, r3 35: StoreToScope r3, 0, 0 39: LoadImmediate r3, 3 42: LoadImmediate r4, 4 - 45: Add r3, r3, r4, fb1 + 45: Add r3, r3, r4, ic1 50: ToPropertyKey r3, r3 53: NewClosure r4, c4 56: NewClosure r5, c5 @@ -514,7 +514,7 @@ 13: StoreToScope r2, 3, 0 17: LoadImmediate r2, 1 20: LoadImmediate r3, 2 - 23: Add r2, r2, r3, fb0 + 23: Add r2, r2, r3, ic0 28: ToPropertyKey r2, r2 31: StoreToScope r2, 0, 0 35: NewClosure r2, c2 @@ -579,7 +579,7 @@ 7: StoreToScope r2, 2, 0 11: LoadImmediate r2, 1 14: LoadImmediate r3, 2 - 17: Add r2, r2, r3, fb0 + 17: Add r2, r2, r3, ic0 22: ToPropertyKey r2, r2 25: StoreToScope r2, 0, 0 29: NewClass r0, c3, c2, r1, r0 @@ -626,12 +626,12 @@ 14: StoreToScope r2, 5, 0 18: LoadImmediate r2, 1 21: LoadImmediate r3, 2 - 24: Add r2, r2, r3, fb0 + 24: Add r2, r2, r3, ic0 29: ToPropertyKey r2, r2 32: StoreToScope r2, 0, 0 36: LoadImmediate r2, 3 39: LoadImmediate r3, 4 - 42: Add r2, r2, r3, fb1 + 42: Add r2, r2, r3, ic1 47: ToPropertyKey r2, r2 50: StoreToScope r2, 1, 0 54: NewClass r0, c4, c3, r1, r0 diff --git a/tests/js_bytecode/class/methods.exp b/tests/js_bytecode/class/methods.exp index 0aa7be71..8ec7173c 100644 --- a/tests/js_bytecode/class/methods.exp +++ b/tests/js_bytecode/class/methods.exp @@ -11,19 +11,19 @@ 23: NewClosure r7, c4 26: LoadImmediate r8, 1 29: LoadImmediate r9, 2 - 32: Add r8, r8, r9, fb0 + 32: Add r8, r8, r9, ic0 37: ToPropertyKey r8, r8 40: NewClosure r9, c5 43: NewClosure r10, c6 46: NewClosure r11, c7 49: LoadImmediate r12, 3 52: LoadImmediate r13, 4 - 55: Add r12, r12, r13, fb1 + 55: Add r12, r12, r13, ic1 60: ToPropertyKey r12, r12 63: NewClosure r13, c8 66: LoadImmediate r14, 5 69: LoadImmediate r15, 6 - 72: Add r14, r14, r15, fb2 + 72: Add r14, r14, r15, ic2 77: ToPropertyKey r14, r14 80: NewClosure r15, c9 83: NewClosure r16, c10 @@ -31,7 +31,7 @@ 89: NewClosure r18, c12 92: LoadImmediate r19, 1 95: LoadImmediate r20, 2 - 98: Add r19, r19, r20, fb3 + 98: Add r19, r19, r20, ic3 103: ToPropertyKey r19, r19 106: NewClosure r20, c13 109: NewClass r0, c15, c14, r1, r2 diff --git a/tests/js_bytecode/class/private_member.exp b/tests/js_bytecode/class/private_member.exp index 1bcebc9f..77c30d2e 100644 --- a/tests/js_bytecode/class/private_member.exp +++ b/tests/js_bytecode/class/private_member.exp @@ -114,7 +114,7 @@ Parameters: 1, Registers: 2 0: LoadFromScope r1, 1, 0 4: GetPrivateProperty r0, , r1 - 8: Add r0, r0, a0, fb0 + 8: Add r0, r0, a0, ic0 13: SetPrivateProperty , r1, r0 17: LoadUndefined r0 19: Ret r0 diff --git a/tests/js_bytecode/class/static_initializer.exp b/tests/js_bytecode/class/static_initializer.exp index b17b5b56..359895b5 100644 --- a/tests/js_bytecode/class/static_initializer.exp +++ b/tests/js_bytecode/class/static_initializer.exp @@ -76,10 +76,10 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1, fb0 + 6: Add r0, r0, r1, ic0 11: LoadImmediate r0, 3 14: LoadImmediate r1, 4 - 17: Add r0, r0, r1, fb1 + 17: Add r0, r0, r1, ic1 22: LoadUndefined r0 24: Ret r0 } @@ -94,7 +94,7 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1, fb0 + 6: Add r0, r0, r1, ic0 11: LoadUndefined r0 13: Ret r0 } @@ -115,13 +115,13 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1, fb0 + 6: Add r0, r0, r1, ic0 11: LoadImmediate r0, 3 14: LoadImmediate r1, 4 - 17: Add r0, r0, r1, fb1 + 17: Add r0, r0, r1, ic1 22: LoadImmediate r0, 5 25: LoadImmediate r1, 6 - 28: Add r0, r0, r1, fb2 + 28: Add r0, r0, r1, ic2 33: LoadUndefined r0 35: Ret r0 } @@ -177,13 +177,13 @@ [BytecodeFunction: staticInitializer] { Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 - 3: Add r1, , r1, fb0 + 3: Add r1, , r1, ic0 8: LoadImmediate r1, 2 - 11: Add r1, r0, r1, fb1 + 11: Add r1, r0, r1, ic1 16: LoadFromScope r1, 1, 0 20: GetNamedSuperProperty r1, r1, , c0 25: LoadImmediate r2, 3 - 28: Add r1, r1, r2, fb2 + 28: Add r1, r1, r2, ic2 33: LoadUndefined r1 35: Ret r1 Constant Table: diff --git a/tests/js_bytecode/class/super_class.exp b/tests/js_bytecode/class/super_class.exp index 1cdcb06e..d8e5b370 100644 --- a/tests/js_bytecode/class/super_class.exp +++ b/tests/js_bytecode/class/super_class.exp @@ -13,7 +13,7 @@ Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 3: LoadImmediate r2, 2 - 6: Add r1, r1, r2, fb0 + 6: Add r1, r1, r2, ic0 11: NewClass r0, c1, c0, r1, r0 17: LoadUndefined r1 19: Ret r1 diff --git a/tests/js_bytecode/eval/completion.exp b/tests/js_bytecode/eval/completion.exp index 2ea26371..7d3aa559 100644 --- a/tests/js_bytecode/eval/completion.exp +++ b/tests/js_bytecode/eval/completion.exp @@ -117,10 +117,10 @@ 0: LoadConstant r0, c0 3: LoadImmediate r1, 1 6: LoadImmediate r2, 2 - 9: Add r0, r1, r2, fb0 + 9: Add r0, r1, r2, ic0 14: LoadDynamic r1, c1 17: LoadDynamic r2, c2 - 20: Add r0, r1, r2, fb1 + 20: Add r0, r1, r2, ic1 25: LoadConstant r0, c3 28: Ret r0 Constant Table: diff --git a/tests/js_bytecode/eval/dynamic_lookup_out_of_eval.exp b/tests/js_bytecode/eval/dynamic_lookup_out_of_eval.exp index a9afae92..ba30eebd 100644 --- a/tests/js_bytecode/eval/dynamic_lookup_out_of_eval.exp +++ b/tests/js_bytecode/eval/dynamic_lookup_out_of_eval.exp @@ -114,7 +114,7 @@ Parameters: 0, Registers: 3 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r2, r0, r1, fb0 + 6: Add r2, r0, r1, ic0 11: Ret r2 } diff --git a/tests/js_bytecode/eval/forces_dynamic.exp b/tests/js_bytecode/eval/forces_dynamic.exp index f0b67378..aad980dd 100644 --- a/tests/js_bytecode/eval/forces_dynamic.exp +++ b/tests/js_bytecode/eval/forces_dynamic.exp @@ -77,11 +77,11 @@ 115: CheckTdz r0, c2 118: LoadDynamic r0, c5 121: LoadImmediate r1, 5 - 124: Add r0, r0, r1, fb0 + 124: Add r0, r0, r1, ic0 129: LoadDynamic r0, c4 132: LoadDynamic r0, c5 135: LoadImmediate r1, 6 - 138: Add r0, r0, r1, fb1 + 138: Add r0, r0, r1, ic1 143: LoadUndefined r0 145: Ret r0 Constant Table: diff --git a/tests/js_bytecode/eval/function_constructor.exp b/tests/js_bytecode/eval/function_constructor.exp index f6fec5b6..15200df6 100644 --- a/tests/js_bytecode/eval/function_constructor.exp +++ b/tests/js_bytecode/eval/function_constructor.exp @@ -35,7 +35,7 @@ Parameters: 0, Registers: 2 0: LoadGlobal r0, c0 3: LoadImmediate r1, 1 - 6: Add r0, r0, r1, fb0 + 6: Add r0, r0, r1, ic0 11: LoadUndefined r0 13: Ret r0 Constant Table: @@ -44,9 +44,9 @@ [BytecodeFunction: anonymous] { Parameters: 2, Registers: 2 - 0: Add r0, a0, a1, fb0 + 0: Add r0, a0, a1, ic0 5: LoadGlobal r1, c0 - 8: Add r0, r0, r1, fb1 + 8: Add r0, r0, r1, ic1 13: LoadUndefined r0 15: Ret r0 Constant Table: diff --git a/tests/js_bytecode/example_program/fib.exp b/tests/js_bytecode/example_program/fib.exp index 68bce83a..04232726 100644 --- a/tests/js_bytecode/example_program/fib.exp +++ b/tests/js_bytecode/example_program/fib.exp @@ -22,14 +22,14 @@ .L0: 15: LoadGlobal r0, c0 18: LoadImmediate r1, 1 - 21: Sub r1, a0, r1 - 25: Call r0, r0, r1, 1 - 30: LoadGlobal r1, c0 - 33: LoadImmediate r2, 2 - 36: Sub r2, a0, r2 - 40: Call r1, r1, r2, 1 - 45: Add r0, r0, r1, fb0 - 50: Ret r0 + 21: Sub r1, a0, r1, ic0 + 26: Call r0, r0, r1, 1 + 31: LoadGlobal r1, c0 + 34: LoadImmediate r2, 2 + 37: Sub r2, a0, r2, ic1 + 42: Call r1, r1, r2, 1 + 47: Add r0, r0, r1, ic2 + 52: Ret r0 Constant Table: 0: [String: fib] } diff --git a/tests/js_bytecode/expression/arrow_function.exp b/tests/js_bytecode/expression/arrow_function.exp index 78fa3da9..cde1d6ca 100644 --- a/tests/js_bytecode/expression/arrow_function.exp +++ b/tests/js_bytecode/expression/arrow_function.exp @@ -17,10 +17,10 @@ Parameters: 0, Registers: 3 0: NewClosure r1, c0 3: LoadImmediate r2, 2 - 6: Add r1, r1, r2, fb0 + 6: Add r1, r1, r2, ic0 11: NewClosure r1, c1 14: LoadImmediate r2, 4 - 17: Add r1, r1, r2, fb1 + 17: Add r1, r1, r2, ic1 22: NewClosure r0, c2 25: LoadUndefined r1 27: Ret r1 @@ -40,7 +40,7 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 9 3: LoadImmediate r1, 3 - 6: Add r1, r0, r1, fb0 + 6: Add r1, r0, r1, ic0 11: Ret r1 } diff --git a/tests/js_bytecode/expression/assign.exp b/tests/js_bytecode/expression/assign.exp index 39edb2d1..4c6541d0 100644 --- a/tests/js_bytecode/expression/assign.exp +++ b/tests/js_bytecode/expression/assign.exp @@ -270,7 +270,7 @@ 9: NewClosure r1, c3 12: SetNamedProperty r0, c2, r1 16: NewClosure r1, c4 - 19: Add r0, r0, r1, fb0 + 19: Add r0, r0, r1, ic0 24: LoadUndefined r1 26: Ret r1 Constant Table: @@ -309,12 +309,12 @@ Parameters: 1, Registers: 3 0: LoadImmediate r0, 2 3: LoadImmediate r1, 3 - 6: Add a0, a0, r1, fb0 + 6: Add a0, a0, r1, ic0 11: LoadImmediate r1, 4 - 14: Add r0, r0, r1, fb1 + 14: Add r0, r0, r1, ic1 19: LoadGlobal r1, c0 22: LoadImmediate r2, 5 - 25: Add r1, r1, r2, fb2 + 25: Add r1, r1, r2, ic2 30: StoreGlobal r1, c0 33: LoadUndefined r1 35: Ret r1 @@ -328,29 +328,29 @@ 3: LoadGlobal r1, c0 6: Mov r2, a0 9: LoadImmediate r3, 3 - 12: Add a0, r2, r3, fb0 + 12: Add a0, r2, r3, ic0 17: Mov r2, a0 20: Call r1, r1, r2, 1 25: LoadGlobal r1, c0 28: Mov r2, r0 31: LoadImmediate r3, 4 - 34: Add r0, r2, r3, fb1 + 34: Add r0, r2, r3, ic1 39: Mov r2, r0 42: Call r1, r1, r2, 1 47: LoadGlobal r1, c0 50: LoadGlobal r2, c1 53: LoadImmediate r3, 5 - 56: Add r2, r2, r3, fb2 + 56: Add r2, r2, r3, ic2 61: StoreGlobal r2, c1 64: Call r1, r1, r2, 1 69: Mov r1, r0 72: Mov r2, a0 75: LoadGlobal r3, c1 78: LoadImmediate r4, 6 - 81: Add r3, r3, r4, fb3 + 81: Add r3, r3, r4, ic3 86: StoreGlobal r3, c1 - 89: Add a0, r2, r3, fb4 - 94: Add r0, r1, a0, fb5 + 89: Add a0, r2, r3, ic4 + 94: Add r0, r1, a0, ic5 99: LoadUndefined r1 101: Ret r1 Constant Table: @@ -381,44 +381,44 @@ [BytecodeFunction: operatorIdAllOperators] { Parameters: 1, Registers: 1 0: LoadImmediate r0, 1 - 3: Add a0, a0, r0, fb0 + 3: Add a0, a0, r0, ic0 8: LoadImmediate r0, 2 - 11: Sub a0, a0, r0 - 15: LoadImmediate r0, 3 - 18: Mul a0, a0, r0 - 22: LoadImmediate r0, 4 - 25: Div a0, a0, r0 - 29: LoadImmediate r0, 5 - 32: Rem a0, a0, r0 - 36: LoadImmediate r0, 6 - 39: Exp a0, a0, r0 - 43: LoadImmediate r0, 7 - 46: BitAnd a0, a0, r0 - 50: LoadImmediate r0, 8 - 53: BitOr a0, a0, r0 - 57: LoadImmediate r0, 9 - 60: BitXor a0, a0, r0 - 64: LoadImmediate r0, 10 - 67: ShiftLeft a0, a0, r0 - 71: LoadImmediate r0, 11 - 74: ShiftRightArithmetic a0, a0, r0 - 78: LoadImmediate r0, 12 - 81: ShiftRightLogical a0, a0, r0 - 85: LoadUndefined r0 - 87: Ret r0 + 11: Sub a0, a0, r0, ic1 + 16: LoadImmediate r0, 3 + 19: Mul a0, a0, r0 + 23: LoadImmediate r0, 4 + 26: Div a0, a0, r0 + 30: LoadImmediate r0, 5 + 33: Rem a0, a0, r0 + 37: LoadImmediate r0, 6 + 40: Exp a0, a0, r0 + 44: LoadImmediate r0, 7 + 47: BitAnd a0, a0, r0 + 51: LoadImmediate r0, 8 + 54: BitOr a0, a0, r0 + 58: LoadImmediate r0, 9 + 61: BitXor a0, a0, r0 + 65: LoadImmediate r0, 10 + 68: ShiftLeft a0, a0, r0 + 72: LoadImmediate r0, 11 + 75: ShiftRightArithmetic a0, a0, r0 + 79: LoadImmediate r0, 12 + 82: ShiftRightLogical a0, a0, r0 + 86: LoadUndefined r0 + 88: Ret r0 } [BytecodeFunction: operatorMemberAssign] { Parameters: 2, Registers: 5 0: GetNamedProperty r0, a0, c0 4: LoadImmediate r1, 1 - 7: Add r0, r0, r1, fb0 + 7: Add r0, r0, r1, ic0 12: SetNamedProperty a0, c0, r0 16: LoadGlobal r0, c1 19: Mov r2, a0 22: GetNamedProperty r1, r2, c0 26: LoadImmediate r3, 2 - 29: Add r1, r1, r3, fb1 + 29: Add r1, r1, r3, ic1 34: SetNamedProperty r2, c0, r1 38: Call r0, r0, r1, 1 43: Mov r1, a0 @@ -426,21 +426,21 @@ 50: Mov r3, a0 53: GetNamedProperty r2, r3, c2 57: LoadImmediate r4, 3 - 60: Add r2, r2, r4, fb2 + 60: Add r2, r2, r4, ic2 65: SetNamedProperty r3, c2, r2 - 69: Add r0, r0, r2, fb3 + 69: Add r0, r0, r2, ic3 74: SetNamedProperty r1, c0, r0 78: LoadGlobal r0, c1 81: Mov r2, a0 84: GetNamedProperty r1, r2, c0 88: Mov r3, a0 - 91: Add r1, r1, r3, fb4 + 91: Add r1, r1, r3, ic4 96: SetNamedProperty r2, c0, r1 100: Call r0, r0, r1, 1 105: Mov r1, a0 108: GetNamedProperty r0, r1, c0 112: LoadImmediate r2, 4 - 115: Add r0, r0, r2, fb5 + 115: Add r0, r0, r2, ic5 120: SetNamedProperty r1, c0, r0 124: Mov a1, r0 127: LoadUndefined r0 @@ -455,54 +455,54 @@ Parameters: 1, Registers: 2 0: GetNamedProperty r0, a0, c0 4: LoadImmediate r1, 1 - 7: Add r0, r0, r1, fb0 + 7: Add r0, r0, r1, ic0 12: SetNamedProperty a0, c0, r0 16: GetNamedProperty r0, a0, c0 20: LoadImmediate r1, 2 - 23: Sub r0, r0, r1 - 27: SetNamedProperty a0, c0, r0 - 31: GetNamedProperty r0, a0, c0 - 35: LoadImmediate r1, 3 - 38: Mul r0, r0, r1 - 42: SetNamedProperty a0, c0, r0 - 46: GetNamedProperty r0, a0, c0 - 50: LoadImmediate r1, 4 - 53: Div r0, r0, r1 - 57: SetNamedProperty a0, c0, r0 - 61: GetNamedProperty r0, a0, c0 - 65: LoadImmediate r1, 5 - 68: Rem r0, r0, r1 - 72: SetNamedProperty a0, c0, r0 - 76: GetNamedProperty r0, a0, c0 - 80: LoadImmediate r1, 6 - 83: Exp r0, r0, r1 - 87: SetNamedProperty a0, c0, r0 - 91: GetNamedProperty r0, a0, c0 - 95: LoadImmediate r1, 7 - 98: BitAnd r0, r0, r1 - 102: SetNamedProperty a0, c0, r0 - 106: GetNamedProperty r0, a0, c0 - 110: LoadImmediate r1, 8 - 113: BitOr r0, r0, r1 - 117: SetNamedProperty a0, c0, r0 - 121: GetNamedProperty r0, a0, c0 - 125: LoadImmediate r1, 9 - 128: BitXor r0, r0, r1 - 132: SetNamedProperty a0, c0, r0 - 136: GetNamedProperty r0, a0, c0 - 140: LoadImmediate r1, 10 - 143: ShiftLeft r0, r0, r1 - 147: SetNamedProperty a0, c0, r0 - 151: GetNamedProperty r0, a0, c0 - 155: LoadImmediate r1, 11 - 158: ShiftRightArithmetic r0, r0, r1 - 162: SetNamedProperty a0, c0, r0 - 166: GetNamedProperty r0, a0, c0 - 170: LoadImmediate r1, 12 - 173: ShiftRightLogical r0, r0, r1 - 177: SetNamedProperty a0, c0, r0 - 181: LoadUndefined r0 - 183: Ret r0 + 23: Sub r0, r0, r1, ic1 + 28: SetNamedProperty a0, c0, r0 + 32: GetNamedProperty r0, a0, c0 + 36: LoadImmediate r1, 3 + 39: Mul r0, r0, r1 + 43: SetNamedProperty a0, c0, r0 + 47: GetNamedProperty r0, a0, c0 + 51: LoadImmediate r1, 4 + 54: Div r0, r0, r1 + 58: SetNamedProperty a0, c0, r0 + 62: GetNamedProperty r0, a0, c0 + 66: LoadImmediate r1, 5 + 69: Rem r0, r0, r1 + 73: SetNamedProperty a0, c0, r0 + 77: GetNamedProperty r0, a0, c0 + 81: LoadImmediate r1, 6 + 84: Exp r0, r0, r1 + 88: SetNamedProperty a0, c0, r0 + 92: GetNamedProperty r0, a0, c0 + 96: LoadImmediate r1, 7 + 99: BitAnd r0, r0, r1 + 103: SetNamedProperty a0, c0, r0 + 107: GetNamedProperty r0, a0, c0 + 111: LoadImmediate r1, 8 + 114: BitOr r0, r0, r1 + 118: SetNamedProperty a0, c0, r0 + 122: GetNamedProperty r0, a0, c0 + 126: LoadImmediate r1, 9 + 129: BitXor r0, r0, r1 + 133: SetNamedProperty a0, c0, r0 + 137: GetNamedProperty r0, a0, c0 + 141: LoadImmediate r1, 10 + 144: ShiftLeft r0, r0, r1 + 148: SetNamedProperty a0, c0, r0 + 152: GetNamedProperty r0, a0, c0 + 156: LoadImmediate r1, 11 + 159: ShiftRightArithmetic r0, r0, r1 + 163: SetNamedProperty a0, c0, r0 + 167: GetNamedProperty r0, a0, c0 + 171: LoadImmediate r1, 12 + 174: ShiftRightLogical r0, r0, r1 + 178: SetNamedProperty a0, c0, r0 + 182: LoadUndefined r0 + 184: Ret r0 Constant Table: 0: [String: foo] } diff --git a/tests/js_bytecode/expression/binary.exp b/tests/js_bytecode/expression/binary.exp index 1ea655ce..e1783b9c 100644 --- a/tests/js_bytecode/expression/binary.exp +++ b/tests/js_bytecode/expression/binary.exp @@ -15,31 +15,31 @@ [BytecodeFunction: test1] { Parameters: 2, Registers: 1 - 0: Add r0, a0, a1, fb0 - 5: Sub r0, a0, a1 - 9: Mul r0, a0, a1 - 13: Div r0, a0, a1 - 17: Rem r0, a0, a1 - 21: Exp r0, a0, a1 - 25: LooseEqual r0, a0, a1 - 29: LooseNotEqual r0, a0, a1 - 33: StrictEqual r0, a0, a1 - 37: StrictNotEqual r0, a0, a1 - 41: LessThan r0, a0, a1 - 45: LessThanOrEqual r0, a0, a1 - 49: GreaterThan r0, a0, a1 - 53: GreaterThanOrEqual r0, a0, a1 - 57: BitAnd r0, a0, a1 - 61: BitOr r0, a0, a1 - 65: BitXor r0, a0, a1 - 69: ShiftLeft r0, a0, a1 - 73: ShiftRightArithmetic r0, a0, a1 - 77: ShiftRightLogical r0, a0, a1 - 81: LoadConstant r0, c0 - 84: In r0, a1, r0 - 88: InstanceOf r0, a0, a1 - 92: LoadUndefined r0 - 94: Ret r0 + 0: Add r0, a0, a1, ic0 + 5: Sub r0, a0, a1, ic1 + 10: Mul r0, a0, a1 + 14: Div r0, a0, a1 + 18: Rem r0, a0, a1 + 22: Exp r0, a0, a1 + 26: LooseEqual r0, a0, a1 + 30: LooseNotEqual r0, a0, a1 + 34: StrictEqual r0, a0, a1 + 38: StrictNotEqual r0, a0, a1 + 42: LessThan r0, a0, a1 + 46: LessThanOrEqual r0, a0, a1 + 50: GreaterThan r0, a0, a1 + 54: GreaterThanOrEqual r0, a0, a1 + 58: BitAnd r0, a0, a1 + 62: BitOr r0, a0, a1 + 66: BitXor r0, a0, a1 + 70: ShiftLeft r0, a0, a1 + 74: ShiftRightArithmetic r0, a0, a1 + 78: ShiftRightLogical r0, a0, a1 + 82: LoadConstant r0, c0 + 85: In r0, a1, r0 + 89: InstanceOf r0, a0, a1 + 93: LoadUndefined r0 + 95: Ret r0 Constant Table: 0: [String: x] } diff --git a/tests/js_bytecode/expression/calls/basic.exp b/tests/js_bytecode/expression/calls/basic.exp index e36917e8..f5f39aa8 100644 --- a/tests/js_bytecode/expression/calls/basic.exp +++ b/tests/js_bytecode/expression/calls/basic.exp @@ -34,7 +34,7 @@ 9: Mov r3, a0 12: LoadGlobal r4, c0 15: Call r1, r1, r2, 3 - 20: Add r0, r0, r1, fb0 + 20: Add r0, r0, r1, ic0 25: LoadUndefined r0 27: Ret r0 Constant Table: diff --git a/tests/js_bytecode/expression/calls/member.exp b/tests/js_bytecode/expression/calls/member.exp index c68e18df..b3e4caec 100644 --- a/tests/js_bytecode/expression/calls/member.exp +++ b/tests/js_bytecode/expression/calls/member.exp @@ -32,7 +32,7 @@ 23: CallWithReceiver r1, r1, a0, r2, 3 29: LoadImmediate r1, 1 32: LoadImmediate r2, 2 - 35: Add r0, r1, r2, fb0 + 35: Add r0, r1, r2, ic0 40: GetNamedProperty r1, r0, c0 44: LoadImmediate r2, 4 47: CallWithReceiver r1, r1, r0, r2, 1 @@ -49,7 +49,7 @@ 7: CallWithReceiver r1, r1, a0, r1, 0 13: LoadImmediate r1, 0 16: LoadImmediate r2, 9 - 19: Add r1, r1, r2, fb0 + 19: Add r1, r1, r2, ic0 24: LoadConstant r2, c0 27: GetProperty r2, r1, r2 31: LoadImmediate r3, 1 @@ -58,7 +58,7 @@ 40: CallWithReceiver r1, r2, r1, r3, 3 46: LoadImmediate r1, 1 49: LoadImmediate r2, 2 - 52: Add r0, r1, r2, fb1 + 52: Add r0, r1, r2, ic1 57: LoadConstant r1, c0 60: GetProperty r1, r0, r1 64: LoadImmediate r2, 4 diff --git a/tests/js_bytecode/expression/conditional.exp b/tests/js_bytecode/expression/conditional.exp index 7581e3d7..dbdc5aa2 100644 --- a/tests/js_bytecode/expression/conditional.exp +++ b/tests/js_bytecode/expression/conditional.exp @@ -24,30 +24,30 @@ .L1: 14: LoadImmediate r0, 1 17: LoadImmediate r1, 2 - 20: Add r0, r0, r1, fb0 + 20: Add r0, r0, r1, ic0 25: JumpToBooleanFalse r0, 16 (.L2) 28: LoadImmediate r1, 3 31: LoadImmediate r2, 4 - 34: Add r0, r1, r2, fb1 + 34: Add r0, r1, r2, ic1 39: Jump 13 (.L3) .L2: 41: LoadImmediate r1, 5 44: LoadImmediate r2, 6 - 47: Add r0, r1, r2, fb2 + 47: Add r0, r1, r2, ic2 .L3: 52: LoadGlobal r0, c0 55: LoadImmediate r1, 1 58: JumpToBooleanFalse r1, 16 (.L4) 61: LoadImmediate r2, 2 64: LoadImmediate r3, 3 - 67: Add r1, r2, r3, fb3 + 67: Add r1, r2, r3, ic3 72: Jump 21 (.L5) .L4: 74: LoadImmediate r2, 4 77: LoadImmediate r3, 5 - 80: Add r2, r2, r3, fb4 + 80: Add r2, r2, r3, ic4 85: LoadImmediate r3, 6 - 88: Add r1, r2, r3, fb5 + 88: Add r1, r2, r3, ic5 .L5: 93: Call r0, r0, r1, 1 98: LoadUndefined r0 diff --git a/tests/js_bytecode/expression/delete.exp b/tests/js_bytecode/expression/delete.exp index 380d45ca..41783b99 100644 --- a/tests/js_bytecode/expression/delete.exp +++ b/tests/js_bytecode/expression/delete.exp @@ -121,7 +121,7 @@ 3: LoadTrue r0 5: LoadImmediate r0, 1 8: LoadImmediate r1, 2 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: LoadTrue r0 18: LoadUndefined r0 20: Ret r0 @@ -234,7 +234,7 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1, fb0 + 6: Add r0, r0, r1, ic0 11: ThrowNewError 0, c0 14: Ret r0 Constant Table: diff --git a/tests/js_bytecode/expression/function.exp b/tests/js_bytecode/expression/function.exp index 1b376b26..9099d4e6 100644 --- a/tests/js_bytecode/expression/function.exp +++ b/tests/js_bytecode/expression/function.exp @@ -37,10 +37,10 @@ Parameters: 0, Registers: 3 0: NewClosure r1, c0 3: LoadImmediate r2, 2 - 6: Add r1, r1, r2, fb0 + 6: Add r1, r1, r2, ic0 11: NewClosure r1, c1 14: LoadImmediate r2, 4 - 17: Add r1, r1, r2, fb1 + 17: Add r1, r1, r2, ic1 22: NewClosure r0, c2 25: LoadUndefined r1 27: Ret r1 diff --git a/tests/js_bytecode/expression/logical.exp b/tests/js_bytecode/expression/logical.exp index 05971cfe..0417946f 100644 --- a/tests/js_bytecode/expression/logical.exp +++ b/tests/js_bytecode/expression/logical.exp @@ -53,7 +53,7 @@ 2: JumpFalse r0, 14 (.L0) 5: LoadImmediate r1, 1 8: LoadImmediate r2, 2 - 11: Add r0, r1, r2, fb0 + 11: Add r0, r1, r2, ic0 .L0: 16: Ret r0 } @@ -62,11 +62,11 @@ Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 3: LoadImmediate r2, 2 - 6: Add r0, r1, r2, fb0 + 6: Add r0, r1, r2, ic0 11: JumpToBooleanFalse r0, 14 (.L0) 14: LoadImmediate r1, 3 17: LoadImmediate r2, 4 - 20: Add r0, r1, r2, fb1 + 20: Add r0, r1, r2, ic1 .L0: 25: Ret r0 } @@ -77,7 +77,7 @@ 2: JumpTrue r0, 14 (.L0) 5: LoadImmediate r1, 1 8: LoadImmediate r2, 2 - 11: Add r0, r1, r2, fb0 + 11: Add r0, r1, r2, ic0 .L0: 16: Ret r0 } @@ -86,11 +86,11 @@ Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 3: LoadImmediate r2, 2 - 6: Add r0, r1, r2, fb0 + 6: Add r0, r1, r2, ic0 11: JumpToBooleanTrue r0, 14 (.L0) 14: LoadImmediate r1, 3 17: LoadImmediate r2, 4 - 20: Add r0, r1, r2, fb1 + 20: Add r0, r1, r2, ic1 .L0: 25: Ret r0 } @@ -99,11 +99,11 @@ Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 3: LoadImmediate r2, 2 - 6: Add r0, r1, r2, fb0 + 6: Add r0, r1, r2, ic0 11: JumpNotNullish r0, 14 (.L0) 14: LoadImmediate r1, 3 17: LoadImmediate r2, 4 - 20: Add r0, r1, r2, fb1 + 20: Add r0, r1, r2, ic1 .L0: 25: Ret r0 } diff --git a/tests/js_bytecode/expression/member.exp b/tests/js_bytecode/expression/member.exp index 9cff57da..7cfd6d42 100644 --- a/tests/js_bytecode/expression/member.exp +++ b/tests/js_bytecode/expression/member.exp @@ -34,10 +34,10 @@ 3: GetProperty r0, a0, r0 7: LoadImmediate r0, 1 10: LoadImmediate r1, 2 - 13: Add r0, r0, r1, fb0 + 13: Add r0, r0, r1, ic0 18: LoadImmediate r1, 3 21: LoadImmediate r2, 4 - 24: Add r1, r1, r2, fb1 + 24: Add r1, r1, r2, ic1 29: GetProperty r0, r0, r1 33: LoadUndefined r0 35: Ret r0 diff --git a/tests/js_bytecode/expression/new.exp b/tests/js_bytecode/expression/new.exp index 853c5ba8..4b7a6bd9 100644 --- a/tests/js_bytecode/expression/new.exp +++ b/tests/js_bytecode/expression/new.exp @@ -42,7 +42,7 @@ 9: Mov r3, a0 12: LoadGlobal r4, c0 15: Construct r1, r1, r1, r2, 3 - 21: Add r0, r0, r1, fb0 + 21: Add r0, r0, r1, ic0 26: LoadUndefined r0 28: Ret r0 Constant Table: diff --git a/tests/js_bytecode/expression/new_target.exp b/tests/js_bytecode/expression/new_target.exp index a045db40..2a76d8fc 100644 --- a/tests/js_bytecode/expression/new_target.exp +++ b/tests/js_bytecode/expression/new_target.exp @@ -20,7 +20,7 @@ [BytecodeFunction: simpleNewTarget] { Parameters: 0, Registers: 2 0: LoadImmediate r1, 1 - 3: Add r1, r0, r1, fb0 + 3: Add r1, r0, r1, ic0 8: Ret r1 } @@ -31,7 +31,7 @@ 6: NewClosure r0, c1 9: LoadFromScope r0, 0, 0 13: LoadImmediate r1, 1 - 16: Add r0, r0, r1, fb0 + 16: Add r0, r0, r1, ic0 21: Ret r0 Constant Table: 0: [ScopeNames] @@ -49,7 +49,7 @@ Parameters: 0, Registers: 3 0: NewClosure r0, c0 3: LoadImmediate r2, 3 - 6: Add r2, r1, r2, fb0 + 6: Add r2, r1, r2, ic0 11: Ret r2 Constant Table: 0: [BytecodeFunction: inner] @@ -59,6 +59,6 @@ Parameters: 0, Registers: 3 0: LoadImmediate r0, 1 3: LoadImmediate r2, 2 - 6: Add r2, r1, r2, fb0 + 6: Add r2, r1, r2, ic0 11: Ret r2 } diff --git a/tests/js_bytecode/expression/object/basic.exp b/tests/js_bytecode/expression/object/basic.exp index 26445e5d..3d431097 100644 --- a/tests/js_bytecode/expression/object/basic.exp +++ b/tests/js_bytecode/expression/object/basic.exp @@ -76,7 +76,7 @@ 5: DefineNamedProperty r0, c0, r1 9: LoadImmediate r1, 2 12: LoadImmediate r2, 3 - 15: Add r1, r1, r2, fb0 + 15: Add r1, r1, r2, ic0 20: DefineNamedProperty r0, c1, r1 24: Ret r0 Constant Table: @@ -108,7 +108,7 @@ 19: DefineProperty r0, r1, r2, 0 24: LoadImmediate r1, 4 27: LoadImmediate r2, 5 - 30: Add r1, r1, r2, fb0 + 30: Add r1, r1, r2, ic0 35: LoadImmediate r2, 6 38: DefineProperty r0, r1, r2, 0 43: Ret r0 @@ -122,7 +122,7 @@ 2: CopyDataProperties r0, a0, a0, 0 7: LoadImmediate r1, 1 10: LoadImmediate r2, 2 - 13: Add r1, r1, r2, fb0 + 13: Add r1, r1, r2, ic0 18: CopyDataProperties r0, r1, r1, 0 23: Ret r0 } @@ -132,7 +132,7 @@ 0: NewObject r0 2: LoadImmediate r1, 1 5: LoadImmediate r2, 2 - 8: Add r1, r1, r2, fb0 + 8: Add r1, r1, r2, ic0 13: SetPrototypeOf r0, r1 16: Ret r0 Constant Table: diff --git a/tests/js_bytecode/expression/object/named_evalution.exp b/tests/js_bytecode/expression/object/named_evalution.exp index b4995b77..f307256c 100644 --- a/tests/js_bytecode/expression/object/named_evalution.exp +++ b/tests/js_bytecode/expression/object/named_evalution.exp @@ -81,7 +81,7 @@ 0: NewObject r0 2: LoadImmediate r1, 1 5: LoadImmediate r2, 2 - 8: Add r1, r1, r2, fb0 + 8: Add r1, r1, r2, ic0 13: NewClosure r2, c0 16: DefineProperty r0, r1, r2, 1 21: LoadImmediate r1, 3 diff --git a/tests/js_bytecode/expression/super_member.exp b/tests/js_bytecode/expression/super_member.exp index edc6ab37..9571df12 100644 --- a/tests/js_bytecode/expression/super_member.exp +++ b/tests/js_bytecode/expression/super_member.exp @@ -36,7 +36,7 @@ 0: LoadFromScope r0, 0, 0 4: LoadImmediate r1, 1 7: LoadImmediate r2, 2 - 10: Add r1, r1, r2, fb0 + 10: Add r1, r1, r2, ic0 15: GetSuperProperty r0, r0, , r1 20: Ret r0 } diff --git a/tests/js_bytecode/expression/tagged_template.exp b/tests/js_bytecode/expression/tagged_template.exp index a81086a8..25c50f65 100644 --- a/tests/js_bytecode/expression/tagged_template.exp +++ b/tests/js_bytecode/expression/tagged_template.exp @@ -41,14 +41,14 @@ Parameters: 0, Registers: 5 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1, fb0 + 6: Add r0, r0, r1, ic0 11: LoadConstant r1, c0 14: LoadImmediate r2, 3 17: LoadImmediate r3, 4 - 20: Add r2, r2, r3, fb1 + 20: Add r2, r2, r3, ic1 25: LoadImmediate r3, 5 28: LoadImmediate r4, 6 - 31: Add r3, r3, r4, fb2 + 31: Add r3, r3, r4, ic2 36: Call r0, r0, r1, 3 41: Ret r0 Constant Table: @@ -98,7 +98,7 @@ 13: CallWithReceiver r1, r1, a0, r2, 3 19: LoadImmediate r1, 1 22: LoadImmediate r2, 2 - 25: Add r0, r1, r2, fb0 + 25: Add r0, r1, r2, ic0 30: GetNamedProperty r1, r0, c0 34: LoadConstant r2, c2 37: LoadImmediate r3, 3 @@ -121,7 +121,7 @@ 16: CallWithReceiver r1, r1, a0, r2, 3 22: LoadImmediate r1, 1 25: LoadImmediate r2, 2 - 28: Add r0, r1, r2, fb0 + 28: Add r0, r1, r2, ic0 33: LoadConstant r1, c0 36: GetProperty r1, r0, r1 40: LoadConstant r2, c2 diff --git a/tests/js_bytecode/expression/template_literal.exp b/tests/js_bytecode/expression/template_literal.exp index b16656b6..7361e0bf 100644 --- a/tests/js_bytecode/expression/template_literal.exp +++ b/tests/js_bytecode/expression/template_literal.exp @@ -56,12 +56,12 @@ 0: LoadImmediate r1, 1 3: ToString r0, r1 6: LoadConstant r1, c0 - 9: Add r0, r0, r1, fb0 + 9: Add r0, r0, r1, ic0 14: Mov a0, r0 17: LoadImmediate r1, 1 20: ToString r0, r1 23: LoadConstant r1, c0 - 26: Add r0, r0, r1, fb1 + 26: Add r0, r0, r1, ic1 31: Ret r0 Constant Table: 0: [String: test] @@ -72,7 +72,7 @@ 0: LoadConstant r0, c0 3: LoadImmediate r1, 1 6: ToString r1, r1 - 9: Add r0, r0, r1, fb0 + 9: Add r0, r0, r1, ic0 14: Ret r0 Constant Table: 0: [String: test] @@ -84,10 +84,10 @@ 3: ToString r0, r1 6: LoadImmediate r1, 2 9: ToString r1, r1 - 12: Add r0, r0, r1, fb0 + 12: Add r0, r0, r1, ic0 17: LoadImmediate r1, 3 20: ToString r1, r1 - 23: Add r0, r0, r1, fb1 + 23: Add r0, r0, r1, ic1 28: Ret r0 } @@ -96,14 +96,14 @@ 0: LoadConstant r0, c0 3: LoadImmediate r1, 1 6: ToString r1, r1 - 9: Add r0, r0, r1, fb0 + 9: Add r0, r0, r1, ic0 14: LoadConstant r1, c1 - 17: Add r0, r0, r1, fb1 + 17: Add r0, r0, r1, ic1 22: LoadImmediate r1, 2 25: ToString r1, r1 - 28: Add r0, r0, r1, fb2 + 28: Add r0, r0, r1, ic2 33: LoadConstant r1, c2 - 36: Add r0, r0, r1, fb3 + 36: Add r0, r0, r1, ic3 41: Ret r0 Constant Table: 0: [String: a] @@ -117,13 +117,13 @@ 3: ToString a1, a1 6: LoadConstant r0, c0 9: ToString r1, a0 - 12: Add r0, r0, r1, fb0 + 12: Add r0, r0, r1, ic0 17: LoadConstant r1, c1 - 20: Add r0, r0, r1, fb1 + 20: Add r0, r0, r1, ic1 25: ToString r1, a1 - 28: Add r0, r0, r1, fb2 + 28: Add r0, r0, r1, ic2 33: LoadConstant r1, c2 - 36: Add r0, r0, r1, fb3 + 36: Add r0, r0, r1, ic3 41: Ret r0 Constant Table: 0: [String: a] diff --git a/tests/js_bytecode/expression/this.exp b/tests/js_bytecode/expression/this.exp index df945187..100f202a 100644 --- a/tests/js_bytecode/expression/this.exp +++ b/tests/js_bytecode/expression/this.exp @@ -23,7 +23,7 @@ Parameters: 0, Registers: 3 0: Mov r0, 3: LoadImmediate r1, 1 - 6: Add r1, , r1, fb0 + 6: Add r1, , r1, ic0 11: LoadGlobal r1, c0 14: Mov r2, 17: Call r1, r1, r2, 1 diff --git a/tests/js_bytecode/function/async.exp b/tests/js_bytecode/function/async.exp index 0e8c4ae7..898b4cb3 100644 --- a/tests/js_bytecode/function/async.exp +++ b/tests/js_bytecode/function/async.exp @@ -61,7 +61,7 @@ 2: LoadImmediate r1, 1 5: LoadImmediate r1, 2 8: LoadImmediate r2, 3 - 11: Add r1, r1, r2, fb0 + 11: Add r1, r1, r2, ic0 16: Await r1, r2, r0, r1 21: JumpTrue r2, 5 (.L0) 24: Throw r1 @@ -82,7 +82,7 @@ 2: JumpNotUndefined a0, 14 (.L0) 5: LoadImmediate r1, 1 8: LoadImmediate r2, 2 - 11: Add a0, r1, r2, fb0 + 11: Add a0, r1, r2, ic0 .L0: 16: LoadImmediate r1, 3 19: LoadUndefined r1 diff --git a/tests/js_bytecode/function/basic.exp b/tests/js_bytecode/function/basic.exp index 51274007..18a50043 100644 --- a/tests/js_bytecode/function/basic.exp +++ b/tests/js_bytecode/function/basic.exp @@ -23,7 +23,7 @@ [BytecodeFunction: test1] { Parameters: 2, Registers: 1 - 0: Add r0, a0, a1, fb0 + 0: Add r0, a0, a1, ic0 5: Ret r0 } diff --git a/tests/js_bytecode/function/generator.exp b/tests/js_bytecode/function/generator.exp index 3e2ab717..96d2a650 100644 --- a/tests/js_bytecode/function/generator.exp +++ b/tests/js_bytecode/function/generator.exp @@ -211,7 +211,7 @@ .L2: 65: Throw r2 .L3: - 67: Add r1, r1, r2, fb0 + 67: Add r1, r1, r2, ic0 72: Ret r1 Constant Table: 0: [String: value] diff --git a/tests/js_bytecode/function/parameters.exp b/tests/js_bytecode/function/parameters.exp index 71a35ee5..29b7f315 100644 --- a/tests/js_bytecode/function/parameters.exp +++ b/tests/js_bytecode/function/parameters.exp @@ -115,9 +115,9 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadFromScope r1, 1, 0 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: LoadFromScope r1, 2, 0 - 17: Add r0, r0, r1, fb1 + 17: Add r0, r0, r1, ic1 22: Ret r0 } @@ -130,7 +130,7 @@ .L0: 11: Mov r0, a1 14: CheckTdz r0, c0 - 17: Add r1, a0, r0, fb0 + 17: Add r1, a0, r0, ic0 22: LoadUndefined r1 24: Ret r1 Constant Table: @@ -153,7 +153,7 @@ 32: LoadFromScope r1, 0, 0 36: LoadFromScope r2, 1, 0 40: CheckTdz r2, c1 - 43: Add r1, r1, r2, fb0 + 43: Add r1, r1, r2, ic0 48: LoadUndefined r1 50: Ret r1 Constant Table: @@ -167,7 +167,7 @@ 0: LoadFromScope r0, 0, 0 4: LoadFromScope r1, 1, 0 8: CheckTdz r1, c0 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: Ret r0 Constant Table: 0: [String: b] diff --git a/tests/js_bytecode/module/dynamic_import.exp b/tests/js_bytecode/module/dynamic_import.exp index e97113f3..ac03b51b 100644 --- a/tests/js_bytecode/module/dynamic_import.exp +++ b/tests/js_bytecode/module/dynamic_import.exp @@ -2,11 +2,11 @@ Parameters: 0, Registers: 3 0: LoadImmediate r1, 1 3: LoadImmediate r2, 2 - 6: Add r1, r1, r2, fb0 + 6: Add r1, r1, r2, ic0 11: LoadUndefined r2 13: DynamicImport r0, r1, r2 17: LoadImmediate r1, 3 - 20: Add r0, r0, r1, fb1 + 20: Add r0, r0, r1, ic1 25: LoadImmediate r1, 4 28: NewObject r2 30: DynamicImport r0, r1, r2 diff --git a/tests/js_bytecode/module/export_default_expression.exp b/tests/js_bytecode/module/export_default_expression.exp index dc1ec6de..4f87351c 100644 --- a/tests/js_bytecode/module/export_default_expression.exp +++ b/tests/js_bytecode/module/export_default_expression.exp @@ -2,7 +2,7 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadImmediate r1, 2 - 6: Add r0, r0, r1, fb0 + 6: Add r0, r0, r1, ic0 11: StoreToModule r0, 1, 0 15: LoadUndefined r0 17: Ret r0 diff --git a/tests/js_bytecode/module/exported_bindings.exp b/tests/js_bytecode/module/exported_bindings.exp index 6a145a81..7dc60c84 100644 --- a/tests/js_bytecode/module/exported_bindings.exp +++ b/tests/js_bytecode/module/exported_bindings.exp @@ -40,13 +40,13 @@ Parameters: 0, Registers: 3 0: LoadFromModule r1, 1, 0 4: LoadFromModule r2, 2, 0 - 8: Add r1, r1, r2, fb0 + 8: Add r1, r1, r2, ic0 13: LoadFromModule r2, 3, 0 - 17: Add r1, r1, r2, fb1 + 17: Add r1, r1, r2, ic1 22: LoadFromModule r2, 4, 0 - 26: Add r1, r1, r2, fb2 + 26: Add r1, r1, r2, ic2 31: LoadFromModule r2, 5, 0 - 35: Add r1, r1, r2, fb3 + 35: Add r1, r1, r2, ic3 40: PushLexicalScope c0 42: LoadEmpty r1 44: StoreToScope r1, 0, 0 @@ -68,7 +68,7 @@ 0: LoadFromModule r0, 3, 1 4: LoadFromScope r1, 0, 0 8: CheckTdz r1, c0 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: LoadUndefined r0 18: Ret r0 Constant Table: @@ -79,9 +79,9 @@ Parameters: 0, Registers: 2 0: LoadFromModule r0, 6, 0 4: LoadFromModule r1, 7, 0 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: LoadGlobal r1, c0 - 16: Add r0, r0, r1, fb1 + 16: Add r0, r0, r1, ic1 21: LoadUndefined r0 23: Ret r0 Constant Table: diff --git a/tests/js_bytecode/module/import_meta.exp b/tests/js_bytecode/module/import_meta.exp index 7c87b3a0..134c2d5f 100644 --- a/tests/js_bytecode/module/import_meta.exp +++ b/tests/js_bytecode/module/import_meta.exp @@ -2,7 +2,7 @@ Parameters: 0, Registers: 2 0: ImportMeta r0 2: LoadImmediate r1, 1 - 5: Add r0, r0, r1, fb0 + 5: Add r0, r0, r1, ic0 10: LoadUndefined r0 12: Ret r0 } diff --git a/tests/js_bytecode/module/import_named/import_named.exp b/tests/js_bytecode/module/import_named/import_named.exp index 2949e93f..8c1cd2e7 100644 --- a/tests/js_bytecode/module/import_named/import_named.exp +++ b/tests/js_bytecode/module/import_named/import_named.exp @@ -11,11 +11,11 @@ Parameters: 0, Registers: 3 0: LoadFromModule r1, 1, 0 4: LoadFromModule r2, 2, 0 - 8: Add r1, r1, r2, fb0 + 8: Add r1, r1, r2, ic0 13: LoadFromModule r2, 3, 0 - 17: Add r1, r1, r2, fb1 + 17: Add r1, r1, r2, ic1 22: LoadFromModule r2, 4, 0 - 26: Add r1, r1, r2, fb2 + 26: Add r1, r1, r2, ic2 31: PushLexicalScope c0 33: LoadEmpty r1 35: StoreToScope r1, 0, 0 @@ -37,7 +37,7 @@ 0: LoadFromModule r0, 1, 1 4: LoadFromScope r1, 0, 0 8: CheckTdz r1, c0 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: LoadUndefined r0 18: Ret r0 Constant Table: diff --git a/tests/js_bytecode/module/reexport_named/importing.exp b/tests/js_bytecode/module/reexport_named/importing.exp index f4706170..aef6ae66 100644 --- a/tests/js_bytecode/module/reexport_named/importing.exp +++ b/tests/js_bytecode/module/reexport_named/importing.exp @@ -11,9 +11,9 @@ Parameters: 0, Registers: 2 0: LoadFromModule r0, 1, 0 4: LoadFromModule r1, 2, 0 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: LoadFromModule r1, 3, 0 - 17: Add r0, r0, r1, fb1 + 17: Add r0, r0, r1, ic1 22: LoadUndefined r0 24: Ret r0 } diff --git a/tests/js_bytecode/module/reexport_star/importing.exp b/tests/js_bytecode/module/reexport_star/importing.exp index b0891723..17c4435a 100644 --- a/tests/js_bytecode/module/reexport_star/importing.exp +++ b/tests/js_bytecode/module/reexport_star/importing.exp @@ -11,7 +11,7 @@ Parameters: 0, Registers: 2 0: LoadFromModule r0, 1, 0 4: LoadFromModule r1, 2, 0 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: LoadUndefined r0 15: Ret r0 } diff --git a/tests/js_bytecode/module/top_level_await.exp b/tests/js_bytecode/module/top_level_await.exp index 1ce61c14..751d0104 100644 --- a/tests/js_bytecode/module/top_level_await.exp +++ b/tests/js_bytecode/module/top_level_await.exp @@ -3,7 +3,7 @@ 0: Mov r0, a0 3: LoadImmediate r1, 1 6: LoadImmediate r2, 2 - 9: Add r1, r1, r2, fb0 + 9: Add r1, r1, r2, ic0 14: LoadImmediate r1, 3 17: Await r1, r2, r0, r1 22: JumpTrue r2, 5 (.L0) @@ -11,7 +11,7 @@ .L0: 27: LoadImmediate r1, 4 30: LoadImmediate r2, 5 - 33: Add r1, r1, r2, fb1 + 33: Add r1, r1, r2, ic1 38: LoadUndefined r1 40: ResolvePromise r0, r1 43: Ret r0 diff --git a/tests/js_bytecode/module/toplevel.exp b/tests/js_bytecode/module/toplevel.exp index d91e3e29..e731a3b4 100644 --- a/tests/js_bytecode/module/toplevel.exp +++ b/tests/js_bytecode/module/toplevel.exp @@ -16,7 +16,7 @@ 43: NewClosure r1, c2 46: LoadImmediate r2, 100 49: LoadFromScope r3, 1, 0 - 53: Add r2, r2, r3, fb0 + 53: Add r2, r2, r3, ic0 58: LoadUndefined r2 60: Ret r2 Constant Table: @@ -42,12 +42,12 @@ 0: LoadFromScope r0, 1, 0 4: LoadFromScope r1, 2, 0 8: CheckTdz r1, c0 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: LoadFromScope r1, 3, 0 20: CheckTdz r1, c1 - 23: Add r0, r0, r1, fb1 + 23: Add r0, r0, r1, ic1 28: LoadFromScope r1, 4, 0 - 32: Add r0, r0, r1, fb2 + 32: Add r0, r0, r1, ic2 37: LoadUndefined r0 39: Ret r0 Constant Table: diff --git a/tests/js_bytecode/scope/captured.exp b/tests/js_bytecode/scope/captured.exp index d6ea563e..49b3b19c 100644 --- a/tests/js_bytecode/scope/captured.exp +++ b/tests/js_bytecode/scope/captured.exp @@ -71,7 +71,7 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadImmediate r1, 2 - 7: Add r0, r0, r1, fb0 + 7: Add r0, r0, r1, ic0 12: Ret r0 } @@ -94,7 +94,7 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadFromScope r1, 1, 0 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: Ret r0 } @@ -114,7 +114,7 @@ 35: CheckTdz r1, c2 38: LoadFromScope r2, 1, 0 42: CheckTdz r2, c3 - 45: Add r1, r1, r2, fb0 + 45: Add r1, r1, r2, ic0 50: LoadUndefined r1 52: Ret r1 Constant Table: @@ -130,7 +130,7 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 1, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: Ret r0 Constant Table: 0: [String: c1] @@ -173,9 +173,9 @@ 0: NewClosure r0, c0 3: LoadGlobal r1, c1 6: LoadGlobal r2, c2 - 9: Add r1, r1, r2, fb0 + 9: Add r1, r1, r2, ic0 14: LoadGlobal r2, c3 - 17: Add r1, r1, r2, fb1 + 17: Add r1, r1, r2, ic1 22: LoadImmediate r1, 3 25: StoreGlobal r1, c1 28: LoadImmediate r1, 5 @@ -197,9 +197,9 @@ 8: StoreToScope r1, 0, 0 12: LoadGlobal r1, c2 15: LoadGlobal r2, c3 - 18: Add r1, r1, r2, fb0 + 18: Add r1, r1, r2, ic0 23: LoadGlobal r2, c4 - 26: Add r1, r1, r2, fb1 + 26: Add r1, r1, r2, ic1 31: LoadUndefined r1 33: Ret r1 Constant Table: @@ -214,11 +214,11 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadGlobal r1, c0 - 7: Add r0, r0, r1, fb0 + 7: Add r0, r0, r1, ic0 12: LoadGlobal r1, c1 - 15: Add r0, r0, r1, fb1 + 15: Add r0, r0, r1, ic1 20: LoadGlobal r1, c2 - 23: Add r0, r0, r1, fb2 + 23: Add r0, r0, r1, ic2 28: Ret r0 Constant Table: 0: [String: globalVar1] @@ -247,7 +247,7 @@ 8: StoreToScope r1, 0, 0 12: LoadFromScope r1, 0, 1 16: LoadFromScope r2, 0, 0 - 20: Add r1, r1, r2, fb0 + 20: Add r1, r1, r2, ic0 25: LoadUndefined r1 27: Ret r1 Constant Table: @@ -263,9 +263,9 @@ 8: StoreToScope r1, 0, 0 12: LoadFromScope r1, 0, 2 16: LoadFromScope r2, 0, 1 - 20: Add r1, r1, r2, fb0 + 20: Add r1, r1, r2, ic0 25: LoadFromScope r2, 0, 0 - 29: Add r1, r1, r2, fb1 + 29: Add r1, r1, r2, ic1 34: LoadUndefined r1 36: Ret r1 Constant Table: @@ -278,10 +278,10 @@ 0: LoadImmediate r0, 4 3: LoadFromScope r1, 0, 2 7: LoadFromScope r2, 0, 1 - 11: Add r1, r1, r2, fb0 + 11: Add r1, r1, r2, ic0 16: LoadFromScope r2, 0, 0 - 20: Add r1, r1, r2, fb1 - 25: Add r1, r1, r0, fb2 + 20: Add r1, r1, r2, ic1 + 25: Add r1, r1, r0, ic2 30: Ret r1 } @@ -326,9 +326,9 @@ 22: StoreToScope r1, 2, 0 26: LoadFromScope r1, 0, 0 30: LoadFromScope r2, 1, 0 - 34: Add r1, r1, r2, fb0 + 34: Add r1, r1, r2, ic0 39: LoadFromScope r2, 2, 0 - 43: Add r1, r1, r2, fb1 + 43: Add r1, r1, r2, ic1 48: Ret r1 Constant Table: 0: [ScopeNames] @@ -339,9 +339,9 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadFromScope r1, 1, 0 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: LoadFromScope r1, 2, 0 - 17: Add r0, r0, r1, fb1 + 17: Add r0, r0, r1, ic1 22: Ret r0 } @@ -384,13 +384,13 @@ 0: LoadFromScope r0, 0, 3 4: LoadFromScope r1, 0, 2 8: CheckTdz r1, c0 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: LoadFromScope r1, 0, 1 20: CheckTdz r1, c1 - 23: Add r0, r0, r1, fb1 + 23: Add r0, r0, r1, ic1 28: LoadFromScope r1, 0, 0 32: CheckTdz r1, c2 - 35: Add r0, r0, r1, fb2 + 35: Add r0, r0, r1, ic2 40: Ret r0 Constant Table: 0: [String: v2] diff --git a/tests/js_bytecode/scope/captured_this.exp b/tests/js_bytecode/scope/captured_this.exp index 81e8f5d6..eb27601a 100644 --- a/tests/js_bytecode/scope/captured_this.exp +++ b/tests/js_bytecode/scope/captured_this.exp @@ -21,7 +21,7 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 1 3: LoadFromScope r1, 1, 0 - 7: Add r0, r0, r1, fb0 + 7: Add r0, r0, r1, ic0 12: Ret r0 } @@ -44,7 +44,7 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 2 3: LoadFromScope r1, 0, 0 - 7: Add r0, r0, r1, fb0 + 7: Add r0, r0, r1, ic0 12: Ret r0 } @@ -52,7 +52,7 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 3 3: NewClosure r1, c0 - 6: Add r0, r0, r1, fb0 + 6: Add r0, r0, r1, ic0 11: Ret r0 Constant Table: 0: [BytecodeFunction: ] @@ -62,7 +62,7 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 4 3: NewClosure r1, c0 - 6: Add r0, r0, r1, fb0 + 6: Add r0, r0, r1, ic0 11: Ret r0 Constant Table: 0: [BytecodeFunction: ] @@ -72,7 +72,7 @@ Parameters: 0, Registers: 2 0: LoadImmediate r0, 5 3: LoadFromScope r1, 0, 0 - 7: Add r0, r0, r1, fb0 + 7: Add r0, r0, r1, ic0 12: Ret r0 } diff --git a/tests/js_bytecode/scope/catch.exp b/tests/js_bytecode/scope/catch.exp index 5e25200a..59164c63 100644 --- a/tests/js_bytecode/scope/catch.exp +++ b/tests/js_bytecode/scope/catch.exp @@ -85,7 +85,7 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: Ret r0 Constant Table: 0: [String: x] @@ -135,7 +135,7 @@ 15: StoreToScope r3, 0, 0 19: NewClosure r1, c1 22: LoadImmediate r3, 1 - 25: Add r3, r3, r0, fb0 + 25: Add r3, r3, r0, ic0 30: StoreToScope r3, 0, 0 34: PopScope .L0: diff --git a/tests/js_bytecode/scope/for.exp b/tests/js_bytecode/scope/for.exp index 2f0a77f3..9ffbe107 100644 --- a/tests/js_bytecode/scope/for.exp +++ b/tests/js_bytecode/scope/for.exp @@ -26,7 +26,7 @@ 10: JumpFalse r4, 26 (.L1) 13: LoadEmpty r3 15: CheckTdz r3, c0 - 18: Add r4, r2, r3, fb0 + 18: Add r4, r2, r3, ic0 23: LoadImmediate r3, 0 26: ToNumeric r2, r2 29: Mov r4, r2 @@ -40,7 +40,7 @@ 46: JumpFalse r4, 26 (.L3) 49: LoadEmpty r1 51: CheckTdz r1, c0 - 54: Add r4, r0, r1, fb1 + 54: Add r4, r0, r1, ic1 59: LoadImmediate r1, 0 62: ToNumeric r0, r0 65: Mov r4, r0 @@ -106,7 +106,7 @@ 53: LoadFromScope r1, 0, 0 57: CheckTdz r1, c1 60: LoadImmediate r2, 1 - 63: Add r1, r1, r2, fb0 + 63: Add r1, r1, r2, ic0 68: LoadFromScope r2, 0, 0 72: CheckTdz r2, c1 75: StoreToScope r1, 0, 0 @@ -128,7 +128,7 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: Ret r0 Constant Table: 0: [String: x] diff --git a/tests/js_bytecode/scope/for_break.exp b/tests/js_bytecode/scope/for_break.exp index b0ae6c69..86e2cc91 100644 --- a/tests/js_bytecode/scope/for_break.exp +++ b/tests/js_bytecode/scope/for_break.exp @@ -78,10 +78,10 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: LoadFromScope r1, 0, 0 23: CheckTdz r1, c2 - 26: Add r0, r0, r1, fb1 + 26: Add r0, r0, r1, ic1 31: Ret r0 Constant Table: 0: [String: x] @@ -137,7 +137,7 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: Ret r0 Constant Table: 0: [String: x] @@ -192,10 +192,10 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: LoadFromScope r1, 0, 0 20: CheckTdz r1, c1 - 23: Add r0, r0, r1, fb1 + 23: Add r0, r0, r1, ic1 28: Ret r0 Constant Table: 0: [String: y] @@ -242,10 +242,10 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 1 4: LoadFromScope r1, 1, 1 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: LoadFromScope r1, 0, 0 17: CheckTdz r1, c0 - 20: Add r0, r0, r1, fb1 + 20: Add r0, r0, r1, ic1 25: Ret r0 Constant Table: 0: [String: z] diff --git a/tests/js_bytecode/scope/for_continue.exp b/tests/js_bytecode/scope/for_continue.exp index 93e99f72..a3149ed3 100644 --- a/tests/js_bytecode/scope/for_continue.exp +++ b/tests/js_bytecode/scope/for_continue.exp @@ -76,10 +76,10 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: LoadFromScope r1, 0, 0 23: CheckTdz r1, c2 - 26: Add r0, r0, r1, fb1 + 26: Add r0, r0, r1, ic1 31: Ret r0 Constant Table: 0: [String: x] @@ -133,7 +133,7 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: Ret r0 Constant Table: 0: [String: x] @@ -189,10 +189,10 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: LoadFromScope r1, 0, 0 20: CheckTdz r1, c1 - 23: Add r0, r0, r1, fb1 + 23: Add r0, r0, r1, ic1 28: Ret r0 Constant Table: 0: [String: y] @@ -240,10 +240,10 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 1 4: LoadFromScope r1, 1, 1 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: LoadFromScope r1, 0, 0 17: CheckTdz r1, c0 - 20: Add r0, r0, r1, fb1 + 20: Add r0, r0, r1, ic1 25: Ret r0 Constant Table: 0: [String: z] diff --git a/tests/js_bytecode/scope/for_in.exp b/tests/js_bytecode/scope/for_in.exp index 516ffd57..e4ac9adf 100644 --- a/tests/js_bytecode/scope/for_in.exp +++ b/tests/js_bytecode/scope/for_in.exp @@ -32,7 +32,7 @@ 14: Mov r0, r3 17: LoadEmpty r1 19: CheckTdz r1, c0 - 22: Add r3, r0, r1, fb0 + 22: Add r3, r0, r1, ic0 27: LoadImmediate r1, 0 30: Jump -22 (.L0) .L1: @@ -83,7 +83,7 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: Ret r0 Constant Table: 0: [String: x] diff --git a/tests/js_bytecode/scope/for_in_break.exp b/tests/js_bytecode/scope/for_in_break.exp index e90504d0..07aa3441 100644 --- a/tests/js_bytecode/scope/for_in_break.exp +++ b/tests/js_bytecode/scope/for_in_break.exp @@ -83,10 +83,10 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: LoadFromScope r1, 0, 0 23: CheckTdz r1, c2 - 26: Add r0, r0, r1, fb1 + 26: Add r0, r0, r1, ic1 31: Ret r0 Constant Table: 0: [String: x] @@ -147,7 +147,7 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: Ret r0 Constant Table: 0: [String: x] @@ -204,10 +204,10 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: LoadFromScope r1, 0, 0 20: CheckTdz r1, c1 - 23: Add r0, r0, r1, fb1 + 23: Add r0, r0, r1, ic1 28: Ret r0 Constant Table: 0: [String: y] @@ -256,10 +256,10 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 1 4: LoadFromScope r1, 1, 1 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: LoadFromScope r1, 0, 0 17: CheckTdz r1, c0 - 20: Add r0, r0, r1, fb1 + 20: Add r0, r0, r1, ic1 25: Ret r0 Constant Table: 0: [String: z] diff --git a/tests/js_bytecode/scope/for_in_continue.exp b/tests/js_bytecode/scope/for_in_continue.exp index 2116b7ac..2acef933 100644 --- a/tests/js_bytecode/scope/for_in_continue.exp +++ b/tests/js_bytecode/scope/for_in_continue.exp @@ -82,10 +82,10 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: LoadFromScope r1, 0, 0 23: CheckTdz r1, c2 - 26: Add r0, r0, r1, fb1 + 26: Add r0, r0, r1, ic1 31: Ret r0 Constant Table: 0: [String: x] @@ -145,7 +145,7 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: Ret r0 Constant Table: 0: [String: x] @@ -202,10 +202,10 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: LoadFromScope r1, 0, 0 20: CheckTdz r1, c1 - 23: Add r0, r0, r1, fb1 + 23: Add r0, r0, r1, ic1 28: Ret r0 Constant Table: 0: [String: y] @@ -254,10 +254,10 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 1 4: LoadFromScope r1, 1, 1 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: LoadFromScope r1, 0, 0 17: CheckTdz r1, c0 - 20: Add r0, r0, r1, fb1 + 20: Add r0, r0, r1, ic1 25: Ret r0 Constant Table: 0: [String: z] diff --git a/tests/js_bytecode/scope/for_of.exp b/tests/js_bytecode/scope/for_of.exp index 09ab533f..55577060 100644 --- a/tests/js_bytecode/scope/for_of.exp +++ b/tests/js_bytecode/scope/for_of.exp @@ -32,7 +32,7 @@ 17: Mov r6, 20: LoadEmpty r1 22: CheckTdz r1, c0 - 25: Add r7, r0, r1, fb0 + 25: Add r7, r0, r1, ic0 30: LoadImmediate r1, 0 33: Jump 12 (.L1) 35: LoadImmediate r4, 0 @@ -101,7 +101,7 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: Ret r0 Constant Table: 0: [String: x] diff --git a/tests/js_bytecode/scope/for_of_break.exp b/tests/js_bytecode/scope/for_of_break.exp index b67dfa57..7e576d6d 100644 --- a/tests/js_bytecode/scope/for_of_break.exp +++ b/tests/js_bytecode/scope/for_of_break.exp @@ -96,10 +96,10 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: LoadFromScope r1, 0, 0 23: CheckTdz r1, c2 - 26: Add r0, r0, r1, fb1 + 26: Add r0, r0, r1, ic1 31: Ret r0 Constant Table: 0: [String: x] @@ -179,10 +179,10 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: LoadFromScope r1, 0, 0 20: CheckTdz r1, c1 - 23: Add r0, r0, r1, fb1 + 23: Add r0, r0, r1, ic1 28: Ret r0 Constant Table: 0: [String: y] diff --git a/tests/js_bytecode/scope/for_of_continue.exp b/tests/js_bytecode/scope/for_of_continue.exp index 4bd077f7..e9c6146b 100644 --- a/tests/js_bytecode/scope/for_of_continue.exp +++ b/tests/js_bytecode/scope/for_of_continue.exp @@ -83,10 +83,10 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: LoadFromScope r1, 0, 0 23: CheckTdz r1, c2 - 26: Add r0, r0, r1, fb1 + 26: Add r0, r0, r1, ic1 31: Ret r0 Constant Table: 0: [String: x] @@ -153,10 +153,10 @@ 0: LoadFromScope r0, 0, 2 4: LoadFromScope r1, 0, 1 8: CheckTdz r1, c0 - 11: Add r0, r0, r1, fb0 + 11: Add r0, r0, r1, ic0 16: LoadFromScope r1, 0, 0 20: CheckTdz r1, c1 - 23: Add r0, r0, r1, fb1 + 23: Add r0, r0, r1, ic1 28: Ret r0 Constant Table: 0: [String: y] diff --git a/tests/js_bytecode/scope/function.exp b/tests/js_bytecode/scope/function.exp index 167d399c..3aa44a12 100644 --- a/tests/js_bytecode/scope/function.exp +++ b/tests/js_bytecode/scope/function.exp @@ -23,7 +23,7 @@ 2: LoadEmpty r1 4: CheckTdz r0, c0 7: CheckTdz r1, c1 - 10: Add r2, r0, r1, fb0 + 10: Add r2, r0, r1, ic0 15: LoadImmediate r0, 1 18: LoadImmediate r1, 2 21: LoadUndefined r2 @@ -90,10 +90,10 @@ Parameters: 0, Registers: 2 0: LoadFromScope r0, 0, 0 4: LoadFromScope r1, 1, 0 - 8: Add r0, r0, r1, fb0 + 8: Add r0, r0, r1, ic0 13: LoadFromScope r1, 2, 0 - 17: Add r0, r0, r1, fb1 + 17: Add r0, r0, r1, ic1 22: LoadFromScope r1, 3, 0 - 26: Add r0, r0, r1, fb2 + 26: Add r0, r0, r1, ic2 31: Ret r0 } diff --git a/tests/js_bytecode/scope/function_body.exp b/tests/js_bytecode/scope/function_body.exp index 405f480f..0f7c6900 100644 --- a/tests/js_bytecode/scope/function_body.exp +++ b/tests/js_bytecode/scope/function_body.exp @@ -39,7 +39,7 @@ .L1: 12: LoadImmediate r0, 2 15: LoadImmediate r1, 3 - 18: Add r1, r0, r1, fb0 + 18: Add r1, r0, r1, ic0 23: LoadUndefined r1 25: Ret r1 } @@ -56,7 +56,7 @@ .L1: 18: LoadImmediate r0, 2 21: LoadImmediate r1, 3 - 24: Add r1, r0, r1, fb0 + 24: Add r1, r0, r1, ic0 29: LoadUndefined r1 31: Ret r1 Constant Table: diff --git a/tests/js_bytecode/scope/labeled_break.exp b/tests/js_bytecode/scope/labeled_break.exp index 3d088e54..1ed6e952 100644 --- a/tests/js_bytecode/scope/labeled_break.exp +++ b/tests/js_bytecode/scope/labeled_break.exp @@ -122,10 +122,10 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: LoadFromScope r1, 0, 0 23: CheckTdz r1, c2 - 26: Add r0, r0, r1, fb1 + 26: Add r0, r0, r1, ic1 31: Ret r0 Constant Table: 0: [String: x] diff --git a/tests/js_bytecode/scope/switch.exp b/tests/js_bytecode/scope/switch.exp index 369fcfc3..05cc8e38 100644 --- a/tests/js_bytecode/scope/switch.exp +++ b/tests/js_bytecode/scope/switch.exp @@ -39,7 +39,7 @@ .L0: 39: CheckTdz r0, c0 42: CheckTdz r1, c1 - 45: Add r2, r0, r1, fb0 + 45: Add r2, r0, r1, ic0 .L1: 50: LoadTrue r0 .L2: @@ -137,7 +137,7 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: Ret r0 Constant Table: 0: [String: x] diff --git a/tests/js_bytecode/scope/with.exp b/tests/js_bytecode/scope/with.exp index e718a699..3c8521f9 100644 --- a/tests/js_bytecode/scope/with.exp +++ b/tests/js_bytecode/scope/with.exp @@ -54,7 +54,7 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 1, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: Ret r0 Constant Table: 0: [String: x] @@ -75,20 +75,20 @@ 31: PushWithScope r1, c1 34: LoadDynamic r1, c2 37: LoadImmediate r2, 2 - 40: Add r1, r1, r2, fb0 + 40: Add r1, r1, r2, ic0 45: LoadImmediate r1, 0 48: StoreDynamic r1, c2 51: LoadImmediate r0, 3 54: LoadImmediate r1, 4 - 57: Add r1, r0, r1, fb1 + 57: Add r1, r0, r1, ic1 62: LoadDynamic r1, c3 65: LoadImmediate r2, 5 - 68: Add r1, r1, r2, fb2 + 68: Add r1, r1, r2, ic2 73: LoadImmediate r1, 6 - 76: Add r1, r0, r1, fb3 + 76: Add r1, r0, r1, ic3 81: LoadDynamic r1, c3 84: LoadImmediate r2, 7 - 87: Add r1, r1, r2, fb4 + 87: Add r1, r1, r2, ic4 92: PopScope 93: LoadUndefined r1 95: Ret r1 diff --git a/tests/js_bytecode/statement/const_let_declaration.exp b/tests/js_bytecode/statement/const_let_declaration.exp index e17b9a41..7a44fa49 100644 --- a/tests/js_bytecode/statement/const_let_declaration.exp +++ b/tests/js_bytecode/statement/const_let_declaration.exp @@ -36,7 +36,7 @@ 108: CheckTdz r0, c16 111: LoadFromScope r1, 5, 0 115: CheckTdz r1, c17 - 118: Add r0, r0, r1, fb0 + 118: Add r0, r0, r1, ic0 123: StoreToScope r0, 9, 0 127: LoadFromScope r0, 11, 0 131: CheckTdz r0, c18 @@ -90,7 +90,7 @@ 0: LoadImmediate r2, 3 3: LoadImmediate r0, 1 6: LoadImmediate r1, 2 - 9: Add r2, r0, r1, fb0 + 9: Add r2, r0, r1, ic0 14: Ret r2 } @@ -102,7 +102,7 @@ 6: LoadImmediate r5, 3 9: CheckTdz r1, c0 12: CheckTdz r2, c1 - 15: Add r0, r1, r2, fb0 + 15: Add r0, r1, r2, ic0 20: LoadImmediate r1, 1 23: LoadImmediate r2, 1 26: CheckTdz r4, c2 @@ -110,7 +110,7 @@ 32: LoadImmediate r4, 2 35: CheckTdz r1, c0 38: CheckTdz r2, c1 - 41: Add r5, r1, r2, fb1 + 41: Add r5, r1, r2, ic1 46: Ret r5 Constant Table: 0: [String: c1] @@ -136,7 +136,7 @@ Parameters: 0, Registers: 2 0: LoadUndefined r0 2: LoadImmediate r1, 2 - 5: Add r1, r0, r1, fb0 + 5: Add r1, r0, r1, ic0 10: LoadUndefined r1 12: Ret r1 } diff --git a/tests/js_bytecode/statement/lexical_declaration.exp b/tests/js_bytecode/statement/lexical_declaration.exp index 7e92f184..efb642d8 100644 --- a/tests/js_bytecode/statement/lexical_declaration.exp +++ b/tests/js_bytecode/statement/lexical_declaration.exp @@ -57,10 +57,10 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 1, 0 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: LoadFromScope r1, 2, 0 23: CheckTdz r1, c2 - 26: Add r0, r0, r1, fb1 + 26: Add r0, r0, r1, ic1 31: Ret r0 Constant Table: 0: [String: l1] diff --git a/tests/js_bytecode/statement/try/catch.exp b/tests/js_bytecode/statement/try/catch.exp index edda8ad2..cffc8c88 100644 --- a/tests/js_bytecode/statement/try/catch.exp +++ b/tests/js_bytecode/statement/try/catch.exp @@ -41,7 +41,7 @@ 9: Jump 13 (.L0) 11: Mov , r1 14: LoadImmediate r2, 3 - 17: Add r2, r2, r0, fb0 + 17: Add r2, r2, r0, ic0 .L0: 22: LoadImmediate r1, 4 25: LoadUndefined r1 diff --git a/tests/js_bytecode/statement/try/finally_break.exp b/tests/js_bytecode/statement/try/finally_break.exp index 88e3879c..6e0d622f 100644 --- a/tests/js_bytecode/statement/try/finally_break.exp +++ b/tests/js_bytecode/statement/try/finally_break.exp @@ -262,10 +262,10 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: LoadFromScope r1, 0, 0 23: CheckTdz r1, c2 - 26: Add r0, r0, r1, fb1 + 26: Add r0, r0, r1, ic1 31: Ret r0 Constant Table: 0: [String: s1] diff --git a/tests/js_bytecode/statement/try/finally_continue.exp b/tests/js_bytecode/statement/try/finally_continue.exp index 61c7a6ae..3f3de124 100644 --- a/tests/js_bytecode/statement/try/finally_continue.exp +++ b/tests/js_bytecode/statement/try/finally_continue.exp @@ -262,10 +262,10 @@ 4: CheckTdz r0, c0 7: LoadFromScope r1, 0, 1 11: CheckTdz r1, c1 - 14: Add r0, r0, r1, fb0 + 14: Add r0, r0, r1, ic0 19: LoadFromScope r1, 0, 0 23: CheckTdz r1, c2 - 26: Add r0, r0, r1, fb1 + 26: Add r0, r0, r1, ic1 31: Ret r0 Constant Table: 0: [String: s1] diff --git a/tests/js_bytecode/statement/var_declaration.exp b/tests/js_bytecode/statement/var_declaration.exp index 8e934927..905407ea 100644 --- a/tests/js_bytecode/statement/var_declaration.exp +++ b/tests/js_bytecode/statement/var_declaration.exp @@ -33,7 +33,7 @@ 0: LoadImmediate r2, 3 3: LoadImmediate r0, 1 6: LoadImmediate r1, 2 - 9: Add r2, r0, r1, fb0 + 9: Add r2, r0, r1, ic0 14: Ret r2 } @@ -50,9 +50,9 @@ 0: LoadImmediate r0, 1 3: LoadImmediate r4, 1 6: LoadImmediate r5, 2 - 9: Add r4, r4, r5, fb0 + 9: Add r4, r4, r5, ic0 14: LoadImmediate r5, 3 - 17: Add r1, r4, r5, fb1 + 17: Add r1, r4, r5, ic1 22: Mov r2, a0 25: LoadGlobal r3, c0 28: LoadUndefined r4 diff --git a/tests/js_bytecode/statement/with.exp b/tests/js_bytecode/statement/with.exp index c1a945fc..ad094fa6 100644 --- a/tests/js_bytecode/statement/with.exp +++ b/tests/js_bytecode/statement/with.exp @@ -60,13 +60,13 @@ 30: StoreDynamic r0, c2 33: LoadDynamic r0, c2 36: LoadImmediate r1, 2 - 39: Add r0, r0, r1, fb0 + 39: Add r0, r0, r1, ic0 44: LoadImmediate r0, 3 47: StoreDynamic r0, c2 50: PopScope 51: LoadDynamic r0, c2 54: LoadImmediate r1, 4 - 57: Add r0, r0, r1, fb1 + 57: Add r0, r0, r1, ic1 62: LoadImmediate r0, 5 65: StoreDynamic r0, c2 68: LoadUndefined r0 From 4c813c5ab51cc84d1c91c44b59b63277b5724a77 Mon Sep 17 00:00:00 2001 From: vrindisbacher Date: Fri, 22 May 2026 16:59:05 -0700 Subject: [PATCH 08/11] change to ICBackend model --- src/js/runtime/ic/fgc.rs | 19 ++-- src/js/runtime/ic/generate.rs | 126 +++++++++--------------- src/js/runtime/ic/stubs/binary_arith.rs | 26 +++-- src/js/runtime/ic/stubs/emitter.rs | 29 ++++++ src/js/runtime/ic/stubs/executor.rs | 81 +++++++++++++++ src/js/runtime/ic/stubs/mod.rs | 44 ++++++++- 6 files changed, 224 insertions(+), 101 deletions(-) create mode 100644 src/js/runtime/ic/stubs/emitter.rs create mode 100644 src/js/runtime/ic/stubs/executor.rs diff --git a/src/js/runtime/ic/fgc.rs b/src/js/runtime/ic/fgc.rs index adf6d258..75a448ce 100644 --- a/src/js/runtime/ic/fgc.rs +++ b/src/js/runtime/ic/fgc.rs @@ -1,31 +1,26 @@ /// FGC: Fast Guarded Computation /// -/// Maps fast path computations -/// -/// For example, in the `add` case, Arg would be -/// (Value, Value) for the two values being added -/// and the BailReason would be some reason related -/// to integers +/// A monadic type that's used by executors for IC Stubs pub enum FGC { - Yay(Arg), + Ok(Arg), Bail(BailReason), } impl FGC { #[inline] pub fn new(arg: Arg) -> FGC { - Self::Yay(arg) + Self::Ok(arg) } /// Check something about the inner `val` /// returning a new BailReason if the check fails - #[inline] + #[inline(always)] pub fn check(self, f: F, b: BailReason) -> FGC where F: FnOnce(&Arg) -> bool, { match self { - FGC::Yay(ref v) => { + FGC::Ok(ref v) => { if !f(v) { Self::Bail(b) } else { @@ -39,13 +34,13 @@ impl FGC { /// Apply some operation to the inner value /// of FBC - this only bails if the inner value /// of the FBC monad is already the Bail variant - #[inline] + #[inline(always)] pub fn map(self, f: F) -> FGC where F: FnOnce(Arg) -> NewArg, { match self { - FGC::Yay(v) => FGC::Yay(f(v)), + FGC::Ok(v) => FGC::Ok(f(v)), FGC::Bail(br) => FGC::Bail(br), } } diff --git a/src/js/runtime/ic/generate.rs b/src/js/runtime/ic/generate.rs index 7634a59a..c9fdaebe 100644 --- a/src/js/runtime/ic/generate.rs +++ b/src/js/runtime/ic/generate.rs @@ -1,30 +1,27 @@ -use crate::runtime::eval::common::{sub_bigint_fast, sub_number_fast, sub_smi_fast}; -use crate::runtime::ic::stubs::binary_arith::{AddICStub, BailReason, SubICStub}; -use crate::runtime::Context; -use crate::runtime::{ - alloc_error::AllocResult, - eval::common::{ - add_bigint_fast, add_number_fast, add_smi_fast, add_string_fast, is_bigint, is_number, - is_smi, is_string, - }, - ic::fgc::FGC, - Handle, Value, +use crate::runtime::ic::stubs::binary_arith::{ + AddICStub, BailReason, BinaryArithICStubEmitter, BinaryArithICStubExecutor, SubICStub, }; +use crate::runtime::ic::stubs::{ICBackend, ICGuard, ICOp, Operand}; +use crate::runtime::{alloc_error::AllocResult, Context, Handle, Value}; -macro_rules! binop_handler { - ($name:ident, $check:ident, $bail:ident, $fast:expr) => { - fn $name( - cx: Context, - left: Handle, - right: Handle, - ) -> FGC>, BailReason> { - FGC::new((left, right)) - .check(|(l, r)| $check(*l) && $check(*r), BailReason::$bail) - .map(|(l, r)| $fast(cx, l, r)) +macro_rules! define_stub { + ($name:ident, $guard:ident, $bail:ident, $op:ident) => { + fn $name(b: B) -> B::Output { + b.guard(ICGuard::$guard(Operand::Left, BailReason::$bail)) + .guard(ICGuard::$guard(Operand::Right, BailReason::$bail)) + .exec(ICOp::$op) } }; } +define_stub!(add_smi_stub, Smi, ExpectedSmi, AddSmi); +define_stub!(add_number_stub, Number, ExpectedNumber, AddNumber); +define_stub!(add_bigint_stub, BigInt, ExpectedBigInt, AddBigInt); +define_stub!(concat_string_stub, String, ExpectedString, ConcatString); +define_stub!(sub_smi_stub, Smi, ExpectedSmi, SubSmi); +define_stub!(sub_number_stub, Number, ExpectedNumber, SubNumber); +define_stub!(sub_bigint_stub, BigInt, ExpectedBigInt, SubBigInt); + pub struct ICStubGenerator<'cx> { cx: &'cx Context, } @@ -34,84 +31,53 @@ impl<'cx> ICStubGenerator<'cx> { Self { cx } } - pub fn new_stub_for_sub( + pub fn new_stub_for_add( &self, left: &Value, right: &Value, result: &Value, - ) -> Option>> { - let handler = if left.is_smi() && right.is_smi() { - if result.is_smi() { - Self::sub_smi_handler + ) -> Option>> { + let (execute, emit): (BinaryArithICStubExecutor, BinaryArithICStubEmitter) = + if left.is_smi() && right.is_smi() { + if result.is_smi() { + (add_smi_stub, add_smi_stub) + } else { + (add_number_stub, add_number_stub) + } + } else if left.is_number() && right.is_number() { + (add_number_stub, add_number_stub) + } else if left.is_string() && right.is_string() { + (concat_string_stub, concat_string_stub) + } else if left.is_bigint() && right.is_bigint() { + (add_bigint_stub, add_bigint_stub) } else { - Self::sub_number_handler - } - } else if left.is_number() && right.is_number() { - Self::sub_number_handler - } else if left.is_bigint() && right.is_bigint() { - Self::sub_bigint_handler - } else { - return None; - }; - Some(SubICStub::new(self.cx, handler)) - } + return None; + }; - // IC Stubs for `Sub` on each type - binop_handler!(sub_smi_handler, is_smi, ExpectedSmi, |cx, l, r| Ok(sub_smi_fast(cx, l, r))); - binop_handler!(sub_number_handler, is_number, ExpectedSmi, |cx, l, r| Ok(sub_number_fast( - cx, l, r - ))); - binop_handler!(sub_bigint_handler, is_bigint, ExpectedSmi, |cx, l, r| sub_bigint_fast( - cx, l, r - )); + Some(AddICStub::new(self.cx, execute, emit)) + } - pub fn new_stub_for_add( + pub fn new_stub_for_sub( &self, left: &Value, right: &Value, result: &Value, - ) -> Option>> { - let handler: fn( - Context, - Handle, - Handle, - ) -> FGC>, BailReason> = { + ) -> Option>> { + let (execute, emit): (BinaryArithICStubExecutor, BinaryArithICStubEmitter) = if left.is_smi() && right.is_smi() { if result.is_smi() { - Self::add_smi_handler + (sub_smi_stub, sub_smi_stub) } else { - Self::add_number_handler + (sub_number_stub, sub_number_stub) } } else if left.is_number() && right.is_number() { - Self::add_number_handler - } else if left.is_string() && right.is_string() { - Self::concat_string_handler + (sub_number_stub, sub_number_stub) } else if left.is_bigint() && right.is_bigint() { - Self::add_bigint_handler + (sub_bigint_stub, sub_bigint_stub) } else { return None; - } - }; - - Some(AddICStub::new(self.cx, handler)) - } - - // IC Stubs for `Add` on each type - binop_handler!(add_smi_handler, is_smi, ExpectedSmi, |cx, l, r| Ok(add_smi_fast(cx, l, r))); - binop_handler!(add_number_handler, is_number, ExpectedSmi, |cx, l, r| Ok(add_number_fast( - cx, l, r - ))); - binop_handler!(add_bigint_handler, is_bigint, ExpectedSmi, |cx, l, r| add_bigint_fast( - cx, l, r - )); + }; - fn concat_string_handler( - cx: Context, - left: Handle, - right: Handle, - ) -> FGC>, BailReason> { - FGC::new((left, right)) - .check(|(l, r)| is_string(*l) && is_string(*r), BailReason::ExpectedString) - .map(|(l, r)| add_string_fast(cx, l.as_string(), r.as_string())) + Some(SubICStub::new(self.cx, execute, emit)) } } diff --git a/src/js/runtime/ic/stubs/binary_arith.rs b/src/js/runtime/ic/stubs/binary_arith.rs index b6e8e59c..9ea912e1 100644 --- a/src/js/runtime/ic/stubs/binary_arith.rs +++ b/src/js/runtime/ic/stubs/binary_arith.rs @@ -5,7 +5,10 @@ use crate::{ alloc_error::AllocResult, gc::{HeapItem, HeapVisitor}, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::fgc::FGC, + ic::{ + fgc::FGC, + stubs::{emitter::Emitter, executor::BinaryExecutor}, + }, Context, Handle, HeapPtr, Value, }, set_uninit, @@ -18,8 +21,10 @@ pub enum BailReason { ExpectedString, } -pub type BinaryArithICStubHandler = - fn(Context, Handle, Handle) -> FGC>, BailReason>; +pub type BinaryArithICStubExecutor = + fn(BinaryExecutor) -> FGC>, BailReason>; + +pub type BinaryArithICStubEmitter = fn(Emitter) -> Emitter; pub type ICStubExecutionResult = Result>, BailReason>; @@ -39,7 +44,9 @@ pub struct BinaryArithICStub { /// pointer to the next stub next: Option>>, /// The actual fast path computation - handler: BinaryArithICStubHandler, + executor: BinaryArithICStubExecutor, + /// The emitter for this stub + emitter: BinaryArithICStubEmitter, /// A zero sized marker that makes the IC stub chain typesafe _phantom: PhantomData, } @@ -51,9 +58,9 @@ impl BinaryArithICStub { left: Handle, right: Handle, ) -> ICStubExecutionResult { - let intermediate = (self.handler)(cx, left, right); + let intermediate = (self.executor)(BinaryExecutor::new(cx, left, right)); match intermediate { - FGC::Yay(r) => Ok(r), + FGC::Ok(r) => Ok(r), FGC::Bail(br) => Err(br), } } @@ -61,13 +68,16 @@ impl BinaryArithICStub { // New always makes the next head `None` pub fn new( cx: &Context, - handler: BinaryArithICStubHandler, + executor: BinaryArithICStubExecutor, + emitter: BinaryArithICStubEmitter, ) -> AllocResult>> { let mut object = cx.alloc_uninit::>()?; set_uninit!(object.descriptor, cx.base_descriptors.get(HeapItemKind::AddICStub)); set_uninit!(object.next, None); - set_uninit!(object.handler, handler); + set_uninit!(object.executor, executor); + set_uninit!(object.emitter, emitter); + set_uninit!(object._phantom, PhantomData); Ok(object.to_handle()) } diff --git a/src/js/runtime/ic/stubs/emitter.rs b/src/js/runtime/ic/stubs/emitter.rs new file mode 100644 index 00000000..a0944d99 --- /dev/null +++ b/src/js/runtime/ic/stubs/emitter.rs @@ -0,0 +1,29 @@ +use crate::runtime::ic::stubs::{ICBackend, ICGuard, ICInstruction, ICOp}; + +pub struct Emitter { + ops: Vec, +} + +impl Emitter { + pub fn new() -> Self { + Emitter { ops: Vec::new() } + } + + pub fn into_ops(self) -> Vec { + self.ops + } +} + +impl ICBackend for Emitter { + type Output = Emitter; + + fn guard(mut self, guard: ICGuard) -> Self { + self.ops.push(ICInstruction::Guard(guard)); + self + } + + fn exec(mut self, op: ICOp) -> Emitter { + self.ops.push(ICInstruction::Exec(op)); + self + } +} diff --git a/src/js/runtime/ic/stubs/executor.rs b/src/js/runtime/ic/stubs/executor.rs new file mode 100644 index 00000000..392d33a9 --- /dev/null +++ b/src/js/runtime/ic/stubs/executor.rs @@ -0,0 +1,81 @@ +use crate::runtime::{ + alloc_error::AllocResult, + eval::common::{ + add_bigint_fast, add_number_fast, add_smi_fast, add_string_fast, is_bigint, is_number, + is_smi, is_string, sub_bigint_fast, sub_number_fast, sub_smi_fast, + }, + ic::{ + fgc::FGC, + stubs::{binary_arith::BailReason, ICBackend, ICGuard, ICOp, Operand}, + }, + Context, Handle, Value, +}; + +pub struct BinaryExecutor { + cx: Context, + state: FGC<(Handle, Handle), BailReason>, +} + +impl BinaryExecutor { + #[inline(always)] + pub fn new(cx: Context, left: Handle, right: Handle) -> Self { + BinaryExecutor { cx, state: FGC::new((left, right)) } + } +} + +impl ICBackend for BinaryExecutor { + type Output = FGC>, BailReason>; + + #[inline(always)] + fn guard(self, guard: ICGuard) -> Self { + BinaryExecutor { + cx: self.cx, + state: match guard { + ICGuard::Smi(op, bail) => self.state.check( + |(l, r)| match op { + Operand::Left => is_smi(*l), + Operand::Right => is_smi(*r), + }, + bail, + ), + ICGuard::Number(op, bail) => self.state.check( + |(l, r)| match op { + Operand::Left => is_number(*l), + Operand::Right => is_number(*r), + }, + bail, + ), + ICGuard::String(op, bail) => self.state.check( + |(l, r)| match op { + Operand::Left => is_string(*l), + Operand::Right => is_string(*r), + }, + bail, + ), + ICGuard::BigInt(op, bail) => self.state.check( + |(l, r)| match op { + Operand::Left => is_bigint(*l), + Operand::Right => is_bigint(*r), + }, + bail, + ), + }, + } + } + + #[inline(always)] + fn exec(self, op: ICOp) -> FGC>, BailReason> { + let BinaryExecutor { cx, state } = self; + match op { + ICOp::AddSmi => state.map(move |(l, r)| Ok(add_smi_fast(cx, l, r))), + ICOp::AddNumber => state.map(move |(l, r)| Ok(add_number_fast(cx, l, r))), + ICOp::AddBigInt => state.map(move |(l, r)| add_bigint_fast(cx, l, r)), + ICOp::ConcatString => { + state.map(move |(l, r)| add_string_fast(cx, l.as_string(), r.as_string())) + } + ICOp::SubSmi => state.map(move |(l, r)| Ok(sub_smi_fast(cx, l, r))), + ICOp::SubNumber => state.map(move |(l, r)| Ok(sub_number_fast(cx, l, r))), + ICOp::SubBigInt => state.map(move |(l, r)| sub_bigint_fast(cx, l, r)), + } + } +} diff --git a/src/js/runtime/ic/stubs/mod.rs b/src/js/runtime/ic/stubs/mod.rs index 18d5d68f..fdebcb5d 100644 --- a/src/js/runtime/ic/stubs/mod.rs +++ b/src/js/runtime/ic/stubs/mod.rs @@ -1 +1,43 @@ -pub mod binary_arith; \ No newline at end of file +use crate::runtime::ic::stubs::binary_arith::BailReason; + +pub mod binary_arith; +pub mod emitter; +pub mod executor; + +pub enum Operand { + Left, + Right, +} + +pub enum ICGuard { + Smi(Operand, BailReason), + Number(Operand, BailReason), + String(Operand, BailReason), + BigInt(Operand, BailReason), +} + +pub enum ICOp { + AddSmi, + AddNumber, + AddBigInt, + ConcatString, + SubSmi, + SubNumber, + SubBigInt, +} + +pub enum ICInstruction { + Guard(ICGuard), + Exec(ICOp), +} + +/// A trait used to generalize ICStubs to +/// something that can both be used to +/// execute IC Stubs (highly optimized) +/// by the compiler or to emit an IR +/// representing +pub trait ICBackend: Sized { + type Output; + fn guard(self, guard: ICGuard) -> Self; + fn exec(self, op: ICOp) -> Self::Output; +} From 56d8b0c63dc877c53a3d085f6ca5f038665e82f4 Mon Sep 17 00:00:00 2001 From: vrindisbacher Date: Sat, 23 May 2026 08:52:45 -0700 Subject: [PATCH 09/11] implement more arith ops, use macros --- Cargo.lock | 7 + src/js/Cargo.toml | 1 + src/js/runtime/bytecode/generator.rs | 44 +++++- src/js/runtime/bytecode/instruction.rs | 7 +- src/js/runtime/bytecode/operand.rs | 6 +- src/js/runtime/bytecode/stack_frame.rs | 40 ++++- src/js/runtime/bytecode/vm.rs | 195 +++++++++++------------- src/js/runtime/eval/common.rs | 75 ++++++++- src/js/runtime/eval/expression.rs | 32 ++-- src/js/runtime/ic/generate.rs | 61 +++++++- src/js/runtime/ic/stubs/binary_arith.rs | 26 ++-- src/js/runtime/ic/stubs/executor.rs | 24 +-- src/js/runtime/ic/stubs/mod.rs | 6 + src/js/runtime/ic/vector.rs | 10 +- 14 files changed, 369 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05078a8b..a04e5230 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,6 +76,7 @@ dependencies = [ "indexmap-allocator-api", "num-bigint", "num-traits", + "paste", "rand", "ryu-js", "supports-color", @@ -769,6 +770,12 @@ version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "plotters" version = "0.3.7" diff --git a/src/js/Cargo.toml b/src/js/Cargo.toml index 388a1b50..9da08915 100644 --- a/src/js/Cargo.toml +++ b/src/js/Cargo.toml @@ -18,6 +18,7 @@ hashbrown.workspace = true indexmap-allocator-api.workspace = true num-bigint.workspace = true num-traits.workspace = true +paste = "1.0.15" rand.workspace = true ryu-js.workspace = true supports-color.workspace = true diff --git a/src/js/runtime/bytecode/generator.rs b/src/js/runtime/bytecode/generator.rs index dad95dfc..b711b630 100644 --- a/src/js/runtime/bytecode/generator.rs +++ b/src/js/runtime/bytecode/generator.rs @@ -34,7 +34,7 @@ use crate::{ bytecode::{ function::{dump_bytecode_function, BytecodeFunction}, instruction::DefinePropertyFlags, - operand::{AddICSlotIndex, SubICSlotIndex}, + operand::{AddICSlotIndex, DivICSlotIndex, MulICSlotIndex, SubICSlotIndex}, source_map::BytecodeSourceMap, }, class_names::{ClassNames, HomeObjectLocation, Method}, @@ -3382,8 +3382,26 @@ impl<'a> BytecodeFunctionGenerator<'a> { pos, ) } - ast::BinaryOperator::Multiply => self.writer.mul_instruction(dest, left, right, pos), - ast::BinaryOperator::Divide => self.writer.div_instruction(dest, left, right, pos), + ast::BinaryOperator::Multiply => { + let slot_offset = self.add_ic_stub(); + self.writer.mul_instruction( + dest, + left, + right, + MulICSlotIndex::new(slot_offset), + pos, + ) + } + ast::BinaryOperator::Divide => { + let slot_offset = self.add_ic_stub(); + self.writer.div_instruction( + dest, + left, + right, + DivICSlotIndex::new(slot_offset), + pos, + ) + } ast::BinaryOperator::Remainder => self.writer.rem_instruction(dest, left, right, pos), ast::BinaryOperator::Exponent => self.writer.exp_instruction(dest, left, right, pos), ast::BinaryOperator::EqEq => { @@ -4804,9 +4822,25 @@ impl<'a> BytecodeFunctionGenerator<'a> { ) } ast::AssignmentOperator::Multiply => { - self.writer.mul_instruction(dest, left, right, pos) + let slot_offset = self.add_ic_stub(); + self.writer.mul_instruction( + dest, + left, + right, + MulICSlotIndex::new(slot_offset), + pos, + ) + } + ast::AssignmentOperator::Divide => { + let slot_offset = self.add_ic_stub(); + self.writer.div_instruction( + dest, + left, + right, + DivICSlotIndex::new(slot_offset), + pos, + ) } - ast::AssignmentOperator::Divide => self.writer.div_instruction(dest, left, right, pos), ast::AssignmentOperator::Remainder => { self.writer.rem_instruction(dest, left, right, pos) } diff --git a/src/js/runtime/bytecode/instruction.rs b/src/js/runtime/bytecode/instruction.rs index 9f17d20e..36422ff2 100644 --- a/src/js/runtime/bytecode/instruction.rs +++ b/src/js/runtime/bytecode/instruction.rs @@ -13,7 +13,10 @@ use super::{ use crate::{ count, replace_expr, - runtime::{bytecode::operand::{AddICSlotIndex, SubICSlotIndex}, debug_print::DebugPrinter}, + runtime::{ + bytecode::operand::{AddICSlotIndex, DivICSlotIndex, MulICSlotIndex, SubICSlotIndex}, + debug_print::DebugPrinter, + }, }; /// Generic properties of instructions. @@ -595,6 +598,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] ic_stub_offset: MulICSlotIndex, } } @@ -607,6 +611,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] ic_stub_offset: DivICSlotIndex, } } diff --git a/src/js/runtime/bytecode/operand.rs b/src/js/runtime/bytecode/operand.rs index 9e87b79d..ee7b3c50 100644 --- a/src/js/runtime/bytecode/operand.rs +++ b/src/js/runtime/bytecode/operand.rs @@ -126,6 +126,8 @@ operand_type!(ConstantIndex, UNSIGNED); // Indices into ICs operand_type!(AddICSlotIndex, UNSIGNED); operand_type!(SubICSlotIndex, UNSIGNED); +operand_type!(MulICSlotIndex, UNSIGNED); +operand_type!(DivICSlotIndex, UNSIGNED); pub enum OperandType { Register, @@ -134,6 +136,8 @@ pub enum OperandType { ConstantIndex, AddICSlotIndex, SubICSlotIndex, + MulICSlotIndex, + DivICSlotIndex, } /// Registers may be either registers local to a function or arguments to that function. Registers @@ -340,7 +344,7 @@ macro_rules! define_ic_slot_index_impl { } } -define_ic_slot_index_impl!(AddICSlotIndex, SubICSlotIndex); +define_ic_slot_index_impl!(AddICSlotIndex, SubICSlotIndex, MulICSlotIndex, DivICSlotIndex); impl fmt::Display for ConstantIndex { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/js/runtime/bytecode/stack_frame.rs b/src/js/runtime/bytecode/stack_frame.rs index 5845bc30..37a82ef4 100644 --- a/src/js/runtime/bytecode/stack_frame.rs +++ b/src/js/runtime/bytecode/stack_frame.rs @@ -1,11 +1,11 @@ use crate::runtime::{ bytecode::{ - operand::{AddICSlotIndex, SubICSlotIndex}, + operand::{AddICSlotIndex, DivICSlotIndex, MulICSlotIndex, SubICSlotIndex}, width::{UnsignedWidthRepr, Width}, }, gc::HeapVisitor, ic::{ - stubs::binary_arith::{AddICStub, SubICStub}, + stubs::binary_arith::{AddICStub, DivICStub, MulICStub, SubICStub}, vector::{ICEntry, ICVector}, }, scope::Scope, @@ -217,6 +217,42 @@ impl StackFrame { *self.ic_vector().slots().get_unchecked(slot) } + #[inline] + pub fn insert_div_ic_stub( + &mut self, + slot: DivICSlotIndex, + mut stub: Handle, + ) { + let head = self + .ic_vector_mut() + .slots_mut() + .get_unchecked_mut(slot.value().to_usize()); + match head { + Some(ICEntry::Div(ptr)) => stub.set_next(Some(*ptr)), + Some(_) => unreachable!("DivICStub head was a different type than expected."), + None => stub.set_next(None), + } + *head = Some(ICEntry::Div(*stub)); + } + + #[inline] + pub fn insert_mul_ic_stub( + &mut self, + slot: MulICSlotIndex, + mut stub: Handle, + ) { + let head = self + .ic_vector_mut() + .slots_mut() + .get_unchecked_mut(slot.value().to_usize()); + match head { + Some(ICEntry::Mul(ptr)) => stub.set_next(Some(*ptr)), + Some(_) => unreachable!("MulICStub head was a different type than expected."), + None => stub.set_next(None), + } + *head = Some(ICEntry::Mul(*stub)); + } + #[inline] pub fn insert_sub_ic_stub( &mut self, diff --git a/src/js/runtime/bytecode/vm.rs b/src/js/runtime/bytecode/vm.rs index f14857f5..4445d663 100644 --- a/src/js/runtime/bytecode/vm.rs +++ b/src/js/runtime/bytecode/vm.rs @@ -18,7 +18,7 @@ use crate::{ array_object::{array_create, ArrayObject}, async_generator_object::{async_generator_complete_step, AsyncGeneratorObject}, boxed_value::BoxedValue, - bytecode::operand::{AddICSlotIndex, SubICSlotIndex}, + bytecode::operand::{AddICSlotIndex, DivICSlotIndex, MulICSlotIndex, SubICSlotIndex}, class_names::{new_class, ClassNames}, error::{ err_assign_constant, err_cannot_set_property, err_not_defined, reference_error, @@ -44,7 +44,7 @@ use crate::{ heap_item_descriptor::HeapItemKind, ic::{ generate::ICStubGenerator, - stubs::binary_arith::{AddICStub, SubICStub}, + stubs::binary_arith::{AddICStub, DivICStub, MulICStub, SubICStub}, vector::{ICEntry, ICVector}, }, intrinsics::{ @@ -178,6 +178,39 @@ const MAX_STACK_DEPTH: usize = 4096; #[cfg(debug_assertions)] const MAX_STACK_DEPTH: usize = 80; +macro_rules! def_ic_stub_methods { + ($($op:ident),*) => { + $( + paste::paste! { + #[inline] + fn []( + &self, + slot_index: [<$op ICSlotIndex>], + ) -> Option]>> { + match self + .stack_frame() + .get_ic_stub(slot_index.value().to_usize())? + { + ICEntry::$op(heap_ptr) => Some(heap_ptr), + _ => unreachable!( + concat!("Expected ", stringify!([<$op ICStub>]), " but got different stub kind") + ), + } + } + + #[inline] + fn []( + &mut self, + slot_index: [<$op ICSlotIndex>], + slot: Handle<[<$op ICStub>]>, + ) { + self.stack_frame().[](slot_index, slot); + } + } + )* + }; +} + impl VM { #[inline] fn cx(&self) -> Context { @@ -226,51 +259,8 @@ impl VM { self.stack.as_ptr_range().end } - #[inline] - fn get_add_ic_stub( - &self, - slot_index: AddICSlotIndex, - ) -> Option> { - match self - .stack_frame() - .get_ic_stub(slot_index.value().to_usize())? - { - ICEntry::Add(heap_ptr) => Some(heap_ptr), - _ => unreachable!("Expected AddICStub but got different stub kind"), - } - } - - #[inline] - fn get_sub_ic_stub( - &self, - slot_index: SubICSlotIndex, - ) -> Option> { - match self - .stack_frame() - .get_ic_stub(slot_index.value().to_usize())? - { - ICEntry::Sub(heap_ptr) => Some(heap_ptr), - _ => unreachable!("Expected SubICStub but got different stub kind"), - } - } - - #[inline] - fn insert_sub_ic_stub( - &mut self, - slot_index: SubICSlotIndex, - slot: Handle, - ) { - self.stack_frame().insert_sub_ic_stub(slot_index, slot); - } - - #[inline] - fn insert_add_ic_stub( - &mut self, - slot_index: AddICSlotIndex, - slot: Handle, - ) { - self.stack_frame().insert_add_ic_stub(slot_index, slot); - } + // IC stub getters and setters + def_ic_stub_methods!(Add, Sub, Mul, Div); pub fn stack_trace_top(&self) -> Option { self.stack_trace_top @@ -290,6 +280,35 @@ impl VM { } } +macro_rules! eval_with_ic { + ($self:ident, $op:ident, $instr:expr, + $left_value:expr, $right_value:expr, $dest:expr, + $body:block) => { + paste::paste! {{ + let slot_index = $instr.ic_stub_offset(); + + if let Some(stub) = $self.[](slot_index) { + match stub.try_execute($self.cx(), $left_value, $right_value) { + Some(result) => { + $self.write_register($dest, *result?); + return Ok(()); + } + None => {} + } + }; + + let result = { $body }; + + let gen = ICStubGenerator::new(&$self.cx); + if let Some(new_stub) = + gen.[](&$left_value, &$right_value, &result) + { + $self.[](slot_index, new_stub?); + } + }} + }; +} + impl VM { pub fn new(cx: Context) -> Self { // Allocate uninitialized memory for stack @@ -2790,34 +2809,12 @@ impl VM { let left_value = self.read_register_to_handle(instr.left()); let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - let slot_index = instr.ic_stub_offset(); - - // Get the IC Stub at the head of the linked list and try to execute each one - if let Some(stub) = self.get_add_ic_stub(slot_index) { - match stub.try_execute(self.cx(), left_value, right_value) { - Some(result) => { - // write to register - self.write_register(dest, *result?); - // exit - a stub succeeded and we're done - return Ok(()); - } - // fall through to the slow path - None => {} - } - }; - - // May allocate - let result = eval_add(self.cx(), left_value, right_value)?; - // compile the stub from the left_value, right_value and result - let gen = ICStubGenerator::new(&self.cx); - // May allocate - if let Some(new_stub) = gen.new_stub_for_add(&left_value, &right_value, &result) { - // add the stub to the slot - self.insert_add_ic_stub(slot_index, new_stub?); - } - - self.write_register(dest, *result); + eval_with_ic!(self, Add, instr, left_value, right_value, dest, { + let result = eval_add(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) @@ -2829,34 +2826,12 @@ impl VM { let left_value = self.read_register_to_handle(instr.left()); let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - let slot_index = instr.ic_stub_offset(); - // Get the IC Stub at the head of the linked list and try to execute each one - if let Some(stub) = self.get_sub_ic_stub(slot_index) { - match stub.try_execute(self.cx(), left_value, right_value) { - Some(result) => { - // write to register - self.write_register(dest, *result?); - // exit - a stub succeeded and we're done - return Ok(()); - } - // fall through to the slow path - None => {} - } - }; - - // May allocate - let result = eval_subtract(self.cx(), left_value, right_value)?; - - // compile the stub from the left_value, right_value and result - let gen = ICStubGenerator::new(&self.cx); - // May allocate - if let Some(new_stub) = gen.new_stub_for_sub(&left_value, &right_value, &result) { - // add the stub to the slot - self.insert_sub_ic_stub(slot_index, new_stub?); - } - - self.write_register(dest, *result); + eval_with_ic!(self, Sub, instr, left_value, right_value, dest, { + let result = eval_subtract(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) @@ -2869,10 +2844,11 @@ impl VM { let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - // May allocate - let result = eval_multiply(self.cx(), left_value, right_value)?; - - self.write_register(dest, *result); + eval_with_ic!(self, Mul, instr, left_value, right_value, dest, { + let result = eval_multiply(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) @@ -2885,10 +2861,11 @@ impl VM { let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - // May allocate - let result = eval_divide(self.cx(), left_value, right_value)?; - - self.write_register(dest, *result); + eval_with_ic!(self, Div, instr, left_value, right_value, dest, { + let result = eval_divide(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) diff --git a/src/js/runtime/eval/common.rs b/src/js/runtime/eval/common.rs index ed608419..7ffa72e4 100644 --- a/src/js/runtime/eval/common.rs +++ b/src/js/runtime/eval/common.rs @@ -1,5 +1,8 @@ +use num_bigint::BigInt; + use crate::runtime::{ - alloc_error::AllocResult, string_value::StringValue, value::BigIntValue, Context, Handle, Value, + alloc_error::AllocResult, error::range_error, string_value::StringValue, value::BigIntValue, + Context, EvalResult, Handle, Value, }; /// Common operations that are used by IC Stubs and the interpreter @@ -105,3 +108,73 @@ pub fn sub_bigint_fast( let result = left_num.as_bigint().bigint() - right_num.as_bigint().bigint(); Ok(BigIntValue::new(cx, result)?.into()) } + +/// Muls two smis +#[inline] +pub fn mul_smi_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + cx.smi(left_num.as_smi() * right_num.as_smi()) +} + +/// Muls two numbers +#[inline] +pub fn mul_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + cx.number(left_num.as_number() * right_num.as_number()) +} + +/// Muls two bigints +#[inline] +pub fn mul_bigint_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> AllocResult> { + let result = left_num.as_bigint().bigint() * right_num.as_bigint().bigint(); + Ok(BigIntValue::new(cx, result)?.into()) +} + +/// Divs two smis +#[inline] +pub fn div_smi_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + match left_num.as_smi().checked_div(right_num.as_smi()) { + Some(r) => cx.smi(r), + None => div_number_fast(cx, left_num, right_num), + } +} + +/// Divs two numbers +#[inline] +pub fn div_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + cx.number(left_num.as_number() / right_num.as_number()) +} + +/// Divs two smis +#[inline] +pub fn div_bigint_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let bigint_right = right_num.as_bigint().bigint(); + if bigint_right.eq(&BigInt::default()) { + return range_error(cx, "BigInt division by zero"); + } + + let result = left_num.as_bigint().bigint() / bigint_right; + Ok(BigIntValue::new(cx, result)?.into()) +} diff --git a/src/js/runtime/eval/expression.rs b/src/js/runtime/eval/expression.rs index c961d555..6b05eb8b 100644 --- a/src/js/runtime/eval/expression.rs +++ b/src/js/runtime/eval/expression.rs @@ -14,8 +14,9 @@ use crate::{ array_object::array_create_in_realm, error::{range_error, type_error}, eval::common::{ - add_bigint_fast, add_number_fast, add_string_fast, is_bigint, is_string, - sub_bigint_fast, sub_number_fast, + add_bigint_fast, add_number_fast, add_string_fast, div_bigint_fast, div_number_fast, + is_bigint, is_string, mul_bigint_fast, mul_number_fast, sub_bigint_fast, + sub_number_fast, }, eval_result::EvalResult, heap_item_descriptor::HeapItemKind, @@ -197,16 +198,15 @@ pub fn eval_multiply( let left_num = to_numeric(cx, left_value)?; let right_num = to_numeric(cx, right_value)?; - let left_is_bigint = left_num.is_bigint(); - if left_is_bigint != right_num.is_bigint() { + let left_is_bigint = is_bigint(left_num); + if left_is_bigint != is_bigint(right_num) { return type_error(cx, "BigInt cannot be converted to number"); } if left_is_bigint { - let result = left_num.as_bigint().bigint() * right_num.as_bigint().bigint(); - Ok(BigIntValue::new(cx, result)?.into()) + Ok(mul_bigint_fast(cx, left_value, right_value)?) } else { - Ok(cx.number(left_num.as_number() * right_num.as_number())) + Ok(mul_number_fast(cx, left_value, right_value)) } } @@ -218,21 +218,15 @@ pub fn eval_divide( let left_num = to_numeric(cx, left_value)?; let right_num = to_numeric(cx, right_value)?; - let left_is_bigint = left_num.is_bigint(); - if left_is_bigint != right_num.is_bigint() { + let left_is_bigint = is_bigint(left_num); + if left_is_bigint != is_bigint(right_num) { return type_error(cx, "BigInt cannot be converted to number"); } if left_is_bigint { - let bigint_right = right_num.as_bigint().bigint(); - if bigint_right.eq(&BigInt::default()) { - return range_error(cx, "BigInt division by zero"); - } - - let result = left_num.as_bigint().bigint() / bigint_right; - Ok(BigIntValue::new(cx, result)?.into()) + div_bigint_fast(cx, left_num, right_num) } else { - Ok(cx.number(left_num.as_number() / right_num.as_number())) + Ok(div_number_fast(cx, left_num, right_num)) } } @@ -244,8 +238,8 @@ pub fn eval_remainder( let left_num = to_numeric(cx, left_value)?; let right_num = to_numeric(cx, right_value)?; - let left_is_bigint = left_num.is_bigint(); - if left_is_bigint != right_num.is_bigint() { + let left_is_bigint = is_bigint(left_num); + if left_is_bigint != is_bigint(right_num) { return type_error(cx, "BigInt cannot be converted to number"); } diff --git a/src/js/runtime/ic/generate.rs b/src/js/runtime/ic/generate.rs index c9fdaebe..53f0416c 100644 --- a/src/js/runtime/ic/generate.rs +++ b/src/js/runtime/ic/generate.rs @@ -1,5 +1,6 @@ use crate::runtime::ic::stubs::binary_arith::{ - AddICStub, BailReason, BinaryArithICStubEmitter, BinaryArithICStubExecutor, SubICStub, + AddICStub, BailReason, BinaryArithICStubEmitter, BinaryArithICStubExecutor, DivICStub, + MulICStub, SubICStub, }; use crate::runtime::ic::stubs::{ICBackend, ICGuard, ICOp, Operand}; use crate::runtime::{alloc_error::AllocResult, Context, Handle, Value}; @@ -14,13 +15,23 @@ macro_rules! define_stub { }; } +// add define_stub!(add_smi_stub, Smi, ExpectedSmi, AddSmi); define_stub!(add_number_stub, Number, ExpectedNumber, AddNumber); define_stub!(add_bigint_stub, BigInt, ExpectedBigInt, AddBigInt); define_stub!(concat_string_stub, String, ExpectedString, ConcatString); +// sub define_stub!(sub_smi_stub, Smi, ExpectedSmi, SubSmi); define_stub!(sub_number_stub, Number, ExpectedNumber, SubNumber); define_stub!(sub_bigint_stub, BigInt, ExpectedBigInt, SubBigInt); +// mul +define_stub!(mul_smi_stub, Smi, ExpectedSmi, MulSmi); +define_stub!(mul_number_stub, Number, ExpectedNumber, MulNumber); +define_stub!(mul_bigint_stub, BigInt, ExpectedBigInt, MulBigInt); +// div +define_stub!(div_smi_stub, Smi, ExpectedSmi, DivSmi); +define_stub!(div_number_stub, Number, ExpectedNumber, DivNumber); +define_stub!(div_bigint_stub, BigInt, ExpectedBigInt, DivBigInt); pub struct ICStubGenerator<'cx> { cx: &'cx Context, @@ -80,4 +91,52 @@ impl<'cx> ICStubGenerator<'cx> { Some(SubICStub::new(self.cx, execute, emit)) } + + pub fn new_stub_for_mul( + &self, + left: &Value, + right: &Value, + result: &Value, + ) -> Option>> { + let (execute, emit): (BinaryArithICStubExecutor, BinaryArithICStubEmitter) = + if left.is_smi() && right.is_smi() { + if result.is_smi() { + (mul_smi_stub, mul_smi_stub) + } else { + (mul_number_stub, mul_number_stub) + } + } else if left.is_number() && right.is_number() { + (mul_number_stub, mul_number_stub) + } else if left.is_bigint() && right.is_bigint() { + (mul_bigint_stub, mul_bigint_stub) + } else { + return None; + }; + + Some(MulICStub::new(self.cx, execute, emit)) + } + + pub fn new_stub_for_div( + &self, + left: &Value, + right: &Value, + result: &Value, + ) -> Option>> { + let (execute, emit): (BinaryArithICStubExecutor, BinaryArithICStubEmitter) = + if left.is_smi() && right.is_smi() { + if result.is_smi() { + (div_smi_stub, div_smi_stub) + } else { + (div_number_stub, div_number_stub) + } + } else if left.is_number() && right.is_number() { + (div_number_stub, div_number_stub) + } else if left.is_bigint() && right.is_bigint() { + (div_bigint_stub, div_bigint_stub) + } else { + return None; + }; + + Some(DivICStub::new(self.cx, execute, emit)) + } } diff --git a/src/js/runtime/ic/stubs/binary_arith.rs b/src/js/runtime/ic/stubs/binary_arith.rs index 9ea912e1..4769e005 100644 --- a/src/js/runtime/ic/stubs/binary_arith.rs +++ b/src/js/runtime/ic/stubs/binary_arith.rs @@ -9,7 +9,7 @@ use crate::{ fgc::FGC, stubs::{emitter::Emitter, executor::BinaryExecutor}, }, - Context, Handle, HeapPtr, Value, + Context, EvalResult, Handle, HeapPtr, Value, }, set_uninit, }; @@ -22,21 +22,23 @@ pub enum BailReason { } pub type BinaryArithICStubExecutor = - fn(BinaryExecutor) -> FGC>, BailReason>; + fn(BinaryExecutor) -> FGC>, BailReason>; pub type BinaryArithICStubEmitter = fn(Emitter) -> Emitter; -pub type ICStubExecutionResult = Result>, BailReason>; +pub type ICStubExecutionResult = Result>, BailReason>; -/// Zero sized type marking the Add Op -pub struct AddOp; -/// Zero sized type marking the Sub Op -pub struct SubOp; +macro_rules! def_op { + ($(($op_name:ident, $ic_name:ident)),*) => { + $( + pub struct $op_name; + pub type $ic_name = BinaryArithICStub<$op_name>; + )* + } +} -/// Stub definition for Add -pub type AddICStub = BinaryArithICStub; -/// Stub definition for Sub -pub type SubICStub = BinaryArithICStub; +// Zero sized types marking ops and IC Stubs aliases +def_op!((AddOp, AddICStub), (SubOp, SubICStub), (MulOp, MulICStub), (DivOp, DivICStub)); #[repr(C)] pub struct BinaryArithICStub { @@ -93,7 +95,7 @@ impl BinaryArithICStub { cx: Context, left: Handle, right: Handle, - ) -> Option>> { + ) -> Option>> { // try to execute each individual stub in the linked list let mut curr = Some(self); while let Some(stub) = curr { diff --git a/src/js/runtime/ic/stubs/executor.rs b/src/js/runtime/ic/stubs/executor.rs index 392d33a9..c3f9a252 100644 --- a/src/js/runtime/ic/stubs/executor.rs +++ b/src/js/runtime/ic/stubs/executor.rs @@ -1,14 +1,14 @@ use crate::runtime::{ - alloc_error::AllocResult, eval::common::{ - add_bigint_fast, add_number_fast, add_smi_fast, add_string_fast, is_bigint, is_number, - is_smi, is_string, sub_bigint_fast, sub_number_fast, sub_smi_fast, + add_bigint_fast, add_number_fast, add_smi_fast, add_string_fast, div_bigint_fast, + div_number_fast, div_smi_fast, is_bigint, is_number, is_smi, is_string, mul_bigint_fast, + mul_number_fast, mul_smi_fast, sub_bigint_fast, sub_number_fast, sub_smi_fast, }, ic::{ fgc::FGC, stubs::{binary_arith::BailReason, ICBackend, ICGuard, ICOp, Operand}, }, - Context, Handle, Value, + Context, EvalResult, Handle, Value, }; pub struct BinaryExecutor { @@ -24,7 +24,7 @@ impl BinaryExecutor { } impl ICBackend for BinaryExecutor { - type Output = FGC>, BailReason>; + type Output = FGC>, BailReason>; #[inline(always)] fn guard(self, guard: ICGuard) -> Self { @@ -64,18 +64,24 @@ impl ICBackend for BinaryExecutor { } #[inline(always)] - fn exec(self, op: ICOp) -> FGC>, BailReason> { + fn exec(self, op: ICOp) -> FGC>, BailReason> { let BinaryExecutor { cx, state } = self; match op { ICOp::AddSmi => state.map(move |(l, r)| Ok(add_smi_fast(cx, l, r))), ICOp::AddNumber => state.map(move |(l, r)| Ok(add_number_fast(cx, l, r))), - ICOp::AddBigInt => state.map(move |(l, r)| add_bigint_fast(cx, l, r)), + ICOp::AddBigInt => state.map(move |(l, r)| Ok(add_bigint_fast(cx, l, r)?)), ICOp::ConcatString => { - state.map(move |(l, r)| add_string_fast(cx, l.as_string(), r.as_string())) + state.map(move |(l, r)| Ok(add_string_fast(cx, l.as_string(), r.as_string())?)) } ICOp::SubSmi => state.map(move |(l, r)| Ok(sub_smi_fast(cx, l, r))), ICOp::SubNumber => state.map(move |(l, r)| Ok(sub_number_fast(cx, l, r))), - ICOp::SubBigInt => state.map(move |(l, r)| sub_bigint_fast(cx, l, r)), + ICOp::SubBigInt => state.map(move |(l, r)| Ok(sub_bigint_fast(cx, l, r)?)), + ICOp::MulSmi => state.map(move |(l, r)| Ok(mul_smi_fast(cx, l, r))), + ICOp::MulNumber => state.map(move |(l, r)| Ok(mul_number_fast(cx, l, r))), + ICOp::MulBigInt => state.map(move |(l, r)| Ok(mul_bigint_fast(cx, l, r)?)), + ICOp::DivSmi => state.map(move |(l, r)| Ok(div_smi_fast(cx, l, r))), + ICOp::DivNumber => state.map(move |(l, r)| Ok(div_number_fast(cx, l, r))), + ICOp::DivBigInt => state.map(move |(l, r)| Ok(div_bigint_fast(cx, l, r)?)), } } } diff --git a/src/js/runtime/ic/stubs/mod.rs b/src/js/runtime/ic/stubs/mod.rs index fdebcb5d..fcff7b7e 100644 --- a/src/js/runtime/ic/stubs/mod.rs +++ b/src/js/runtime/ic/stubs/mod.rs @@ -24,6 +24,12 @@ pub enum ICOp { SubSmi, SubNumber, SubBigInt, + MulSmi, + MulNumber, + MulBigInt, + DivSmi, + DivNumber, + DivBigInt, } pub enum ICInstruction { diff --git a/src/js/runtime/ic/vector.rs b/src/js/runtime/ic/vector.rs index 3d71691d..698d1ba7 100644 --- a/src/js/runtime/ic/vector.rs +++ b/src/js/runtime/ic/vector.rs @@ -5,7 +5,7 @@ use crate::{ collections::InlineArray, gc::{HeapItem, HeapVisitor}, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::stubs::binary_arith::{AddICStub, SubICStub}, + ic::stubs::binary_arith::{AddICStub, DivICStub, MulICStub, SubICStub}, Context, Handle, HeapPtr, }, set_uninit, @@ -15,8 +15,8 @@ use crate::{ pub enum ICEntry { Add(HeapPtr), Sub(HeapPtr), - // Mul(HeapPtr), - // Div(HeapPtr), + Mul(HeapPtr), + Div(HeapPtr), } #[repr(C)] @@ -85,8 +85,8 @@ impl HeapItem for HeapPtr { match ptr { ICEntry::Add(heap_ptr) => visitor.visit_pointer(heap_ptr), ICEntry::Sub(heap_ptr) => visitor.visit_pointer(heap_ptr), - // ICEntry::Mul(heap_ptr) => visitor.visit_pointer(heap_ptr), - // ICEntry::Div(heap_ptr) => visitor.visit_pointer(heap_ptr), + ICEntry::Mul(heap_ptr) => visitor.visit_pointer(heap_ptr), + ICEntry::Div(heap_ptr) => visitor.visit_pointer(heap_ptr), } } } From bb053cdaabc8f075acf4862e163aa55b8be5cbb4 Mon Sep 17 00:00:00 2001 From: vrindisbacher Date: Sat, 23 May 2026 10:34:17 -0700 Subject: [PATCH 10/11] more arith IC Stubs --- src/js/runtime/bytecode/generator.rs | 183 ++++++++++-- src/js/runtime/bytecode/instruction.rs | 10 +- src/js/runtime/bytecode/operand.rs | 31 +- src/js/runtime/bytecode/stack_frame.rs | 147 +++++----- src/js/runtime/bytecode/vm.rs | 99 ++++--- src/js/runtime/eval/common.rs | 370 +++++++++++++++++++++++- src/js/runtime/eval/expression.rs | 141 +++------ src/js/runtime/gc/heap_item.rs | 31 +- src/js/runtime/heap_item_descriptor.rs | 23 +- src/js/runtime/ic/generate.rs | 186 ++++++------ src/js/runtime/ic/stubs/binary_arith.rs | 30 +- src/js/runtime/ic/stubs/executor.rs | 70 ++++- src/js/runtime/ic/stubs/mod.rs | 23 ++ src/js/runtime/ic/vector.rs | 21 +- 14 files changed, 990 insertions(+), 375 deletions(-) diff --git a/src/js/runtime/bytecode/generator.rs b/src/js/runtime/bytecode/generator.rs index b711b630..820ef044 100644 --- a/src/js/runtime/bytecode/generator.rs +++ b/src/js/runtime/bytecode/generator.rs @@ -34,7 +34,12 @@ use crate::{ bytecode::{ function::{dump_bytecode_function, BytecodeFunction}, instruction::DefinePropertyFlags, - operand::{AddICSlotIndex, DivICSlotIndex, MulICSlotIndex, SubICSlotIndex}, + operand::{ + AddICSlotIndex, BitAndICSlotIndex, BitOrICSlotIndex, BitXorICSlotIndex, + DivICSlotIndex, ExpICSlotIndex, MulICSlotIndex, RemICSlotIndex, + ShiftLeftICSlotIndex, ShiftRightArithICSlotIndex, ShiftRightLogicalICSlotIndex, + SubICSlotIndex, + }, source_map::BytecodeSourceMap, }, class_names::{ClassNames, HomeObjectLocation, Method}, @@ -3402,8 +3407,26 @@ impl<'a> BytecodeFunctionGenerator<'a> { pos, ) } - ast::BinaryOperator::Remainder => self.writer.rem_instruction(dest, left, right, pos), - ast::BinaryOperator::Exponent => self.writer.exp_instruction(dest, left, right, pos), + ast::BinaryOperator::Remainder => { + let slot_offset = self.add_ic_stub(); + self.writer.rem_instruction( + dest, + left, + right, + RemICSlotIndex::new(slot_offset), + pos, + ) + } + ast::BinaryOperator::Exponent => { + let slot_offset = self.add_ic_stub(); + self.writer.exp_instruction( + dest, + left, + right, + ExpICSlotIndex::new(slot_offset), + pos, + ) + } ast::BinaryOperator::EqEq => { self.writer.loose_equal_instruction(dest, left, right, pos) } @@ -3426,18 +3449,66 @@ impl<'a> BytecodeFunctionGenerator<'a> { ast::BinaryOperator::GreaterThanOrEqual => self .writer .greater_than_or_equal_instruction(dest, left, right, pos), - ast::BinaryOperator::And => self.writer.bit_and_instruction(dest, left, right, pos), - ast::BinaryOperator::Or => self.writer.bit_or_instruction(dest, left, right, pos), - ast::BinaryOperator::Xor => self.writer.bit_xor_instruction(dest, left, right, pos), + ast::BinaryOperator::And => { + let slot_offset = self.add_ic_stub(); + self.writer.bit_and_instruction( + dest, + left, + right, + BitAndICSlotIndex::new(slot_offset), + pos, + ) + } + ast::BinaryOperator::Or => { + let slot_offset = self.add_ic_stub(); + self.writer.bit_or_instruction( + dest, + left, + right, + BitOrICSlotIndex::new(slot_offset), + pos, + ) + } + ast::BinaryOperator::Xor => { + let slot_offset = self.add_ic_stub(); + self.writer.bit_xor_instruction( + dest, + left, + right, + BitXorICSlotIndex::new(slot_offset), + pos, + ) + } ast::BinaryOperator::ShiftLeft => { - self.writer.shift_left_instruction(dest, left, right, pos) + let slot_offset = self.add_ic_stub(); + self.writer.shift_left_instruction( + dest, + left, + right, + ShiftLeftICSlotIndex::new(slot_offset), + pos, + ) + } + ast::BinaryOperator::ShiftRightArithmetic => { + let slot_offset = self.add_ic_stub(); + self.writer.shift_right_arithmetic_instruction( + dest, + left, + right, + ShiftRightArithICSlotIndex::new(slot_offset), + pos, + ) + } + ast::BinaryOperator::ShiftRightLogical => { + let slot_offset = self.add_ic_stub(); + self.writer.shift_right_logical_instruction( + dest, + left, + right, + ShiftRightLogicalICSlotIndex::new(slot_offset), + pos, + ) } - ast::BinaryOperator::ShiftRightArithmetic => self - .writer - .shift_right_arithmetic_instruction(dest, left, right, pos), - ast::BinaryOperator::ShiftRightLogical => self - .writer - .shift_right_logical_instruction(dest, left, right, pos), ast::BinaryOperator::In => self.writer.in_instruction(dest, right, left, pos), ast::BinaryOperator::InPrivate => unreachable!(), ast::BinaryOperator::InstanceOf => { @@ -4842,23 +4913,85 @@ impl<'a> BytecodeFunctionGenerator<'a> { ) } ast::AssignmentOperator::Remainder => { - self.writer.rem_instruction(dest, left, right, pos) + let slot_offset = self.add_ic_stub(); + self.writer.rem_instruction( + dest, + left, + right, + RemICSlotIndex::new(slot_offset), + pos, + ) } ast::AssignmentOperator::Exponent => { - self.writer.exp_instruction(dest, left, right, pos) + let slot_offset = self.add_ic_stub(); + self.writer.exp_instruction( + dest, + left, + right, + ExpICSlotIndex::new(slot_offset), + pos, + ) + } + ast::AssignmentOperator::And => { + let slot_offset = self.add_ic_stub(); + self.writer.bit_and_instruction( + dest, + left, + right, + BitAndICSlotIndex::new(slot_offset), + pos, + ) + } + ast::AssignmentOperator::Or => { + let slot_offset = self.add_ic_stub(); + self.writer.bit_or_instruction( + dest, + left, + right, + BitOrICSlotIndex::new(slot_offset), + pos, + ) + } + ast::AssignmentOperator::Xor => { + let slot_offset = self.add_ic_stub(); + self.writer.bit_xor_instruction( + dest, + left, + right, + BitXorICSlotIndex::new(slot_offset), + pos, + ) } - ast::AssignmentOperator::And => self.writer.bit_and_instruction(dest, left, right, pos), - ast::AssignmentOperator::Or => self.writer.bit_or_instruction(dest, left, right, pos), - ast::AssignmentOperator::Xor => self.writer.bit_xor_instruction(dest, left, right, pos), ast::AssignmentOperator::ShiftLeft => { - self.writer.shift_left_instruction(dest, left, right, pos) + let slot_offset = self.add_ic_stub(); + self.writer.shift_left_instruction( + dest, + left, + right, + ShiftLeftICSlotIndex::new(slot_offset), + pos, + ) + } + ast::AssignmentOperator::ShiftRightArithmetic => { + let slot_offset = self.add_ic_stub(); + self.writer.shift_right_arithmetic_instruction( + dest, + left, + right, + ShiftRightArithICSlotIndex::new(slot_offset), + pos, + ) + } + ast::AssignmentOperator::ShiftRightLogical => { + let slot_offset = self.add_ic_stub(); + self.writer.shift_right_logical_instruction( + dest, + left, + right, + ShiftRightLogicalICSlotIndex::new(slot_offset), + pos, + ) } - ast::AssignmentOperator::ShiftRightArithmetic => self - .writer - .shift_right_arithmetic_instruction(dest, left, right, pos), - ast::AssignmentOperator::ShiftRightLogical => self - .writer - .shift_right_logical_instruction(dest, left, right, pos), ast::AssignmentOperator::Equals => unreachable!("bytecode for simple assignment"), ast::AssignmentOperator::LogicalAnd | ast::AssignmentOperator::LogicalOr diff --git a/src/js/runtime/bytecode/instruction.rs b/src/js/runtime/bytecode/instruction.rs index 36422ff2..e3640876 100644 --- a/src/js/runtime/bytecode/instruction.rs +++ b/src/js/runtime/bytecode/instruction.rs @@ -14,7 +14,7 @@ use super::{ use crate::{ count, replace_expr, runtime::{ - bytecode::operand::{AddICSlotIndex, DivICSlotIndex, MulICSlotIndex, SubICSlotIndex}, + bytecode::operand::{AddICSlotIndex, BitAndICSlotIndex, BitOrICSlotIndex, BitXorICSlotIndex, DivICSlotIndex, ExpICSlotIndex, MulICSlotIndex, RemICSlotIndex, ShiftLeftICSlotIndex, ShiftRightArithICSlotIndex, ShiftRightLogicalICSlotIndex, SubICSlotIndex}, debug_print::DebugPrinter, }, }; @@ -625,6 +625,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] ic_stub_offset: RemICSlotIndex, } } @@ -637,6 +638,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] ic_stub_offset: ExpICSlotIndex, } } @@ -649,6 +651,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] ic_stub_offset: BitAndICSlotIndex, } } @@ -661,6 +664,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] ic_stub_offset: BitOrICSlotIndex, } } @@ -673,6 +677,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] ic_stub_offset: BitXorICSlotIndex, } } @@ -685,6 +690,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] ic_stub_offset: ShiftLeftICSlotIndex, } } @@ -698,6 +704,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] ic_stub_offset: ShiftRightArithICSlotIndex, } } @@ -711,6 +718,7 @@ define_instructions!( [0] dest: Register, [1] left: Register, [2] right: Register, + [3] ic_stub_offset: ShiftRightLogicalICSlotIndex, } } diff --git a/src/js/runtime/bytecode/operand.rs b/src/js/runtime/bytecode/operand.rs index ee7b3c50..dd381cd4 100644 --- a/src/js/runtime/bytecode/operand.rs +++ b/src/js/runtime/bytecode/operand.rs @@ -128,6 +128,14 @@ operand_type!(AddICSlotIndex, UNSIGNED); operand_type!(SubICSlotIndex, UNSIGNED); operand_type!(MulICSlotIndex, UNSIGNED); operand_type!(DivICSlotIndex, UNSIGNED); +operand_type!(RemICSlotIndex, UNSIGNED); +operand_type!(ExpICSlotIndex, UNSIGNED); +operand_type!(BitAndICSlotIndex, UNSIGNED); +operand_type!(BitOrICSlotIndex, UNSIGNED); +operand_type!(BitXorICSlotIndex, UNSIGNED); +operand_type!(ShiftLeftICSlotIndex, UNSIGNED); +operand_type!(ShiftRightArithICSlotIndex, UNSIGNED); +operand_type!(ShiftRightLogicalICSlotIndex, UNSIGNED); pub enum OperandType { Register, @@ -138,6 +146,14 @@ pub enum OperandType { SubICSlotIndex, MulICSlotIndex, DivICSlotIndex, + RemICSlotIndex, + ExpICSlotIndex, + BitAndICSlotIndex, + BitOrICSlotIndex, + BitXorICSlotIndex, + ShiftLeftICSlotIndex, + ShiftRightArithICSlotIndex, + ShiftRightLogicalICSlotIndex, } /// Registers may be either registers local to a function or arguments to that function. Registers @@ -344,7 +360,20 @@ macro_rules! define_ic_slot_index_impl { } } -define_ic_slot_index_impl!(AddICSlotIndex, SubICSlotIndex, MulICSlotIndex, DivICSlotIndex); +define_ic_slot_index_impl!( + AddICSlotIndex, + SubICSlotIndex, + MulICSlotIndex, + DivICSlotIndex, + RemICSlotIndex, + ExpICSlotIndex, + BitAndICSlotIndex, + BitOrICSlotIndex, + BitXorICSlotIndex, + ShiftLeftICSlotIndex, + ShiftRightArithICSlotIndex, + ShiftRightLogicalICSlotIndex, +); impl fmt::Display for ConstantIndex { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/js/runtime/bytecode/stack_frame.rs b/src/js/runtime/bytecode/stack_frame.rs index 37a82ef4..8123c90c 100644 --- a/src/js/runtime/bytecode/stack_frame.rs +++ b/src/js/runtime/bytecode/stack_frame.rs @@ -1,11 +1,18 @@ use crate::runtime::{ bytecode::{ - operand::{AddICSlotIndex, DivICSlotIndex, MulICSlotIndex, SubICSlotIndex}, + operand::{ + AddICSlotIndex, BitAndICSlotIndex, BitOrICSlotIndex, BitXorICSlotIndex, DivICSlotIndex, + ExpICSlotIndex, MulICSlotIndex, RemICSlotIndex, ShiftLeftICSlotIndex, + ShiftRightArithICSlotIndex, ShiftRightLogicalICSlotIndex, SubICSlotIndex, + }, width::{UnsignedWidthRepr, Width}, }, gc::HeapVisitor, ic::{ - stubs::binary_arith::{AddICStub, DivICStub, MulICStub, SubICStub}, + stubs::binary_arith::{ + AddICStub, BitAndICStub, BitOrICStub, BitXorICStub, DivICStub, ExpICStub, MulICStub, + RemICStub, ShiftLeftICStub, ShiftRightArithICStub, ShiftRightLogicalICStub, SubICStub, + }, vector::{ICEntry, ICVector}, }, scope::Scope, @@ -14,6 +21,37 @@ use crate::runtime::{ use super::{constant_table::ConstantTable, function::Closure}; +macro_rules! def_insert_ic_stub { + ($($op:ident),*) => { + $( + paste::paste! { + #[inline] + pub fn []( + &mut self, + slot: [<$op ICSlotIndex>], + mut stub: Handle<[<$op ICStub>]>, + ) { + let Some(ic_vector) = self.ic_vector_mut().as_mut() else { + debug_assert!(false, concat!("IC vector should exist when inserting ", stringify!([<$op ICStub>]))); + return; + }; + let head = ic_vector + .slots_mut() + .get_unchecked_mut(slot.value().to_usize()); + match head { + Some(ICEntry::$op(ptr)) => stub.set_next(Some(*ptr)), + Some(_) => unreachable!( + concat!(stringify!([<$op ICStub>]), " head was a different type than expected.") + ), + None => stub.set_next(None), + } + *head = Some(ICEntry::$op(*stub)); + } + } + )* + }; +} + /// Stack frame layout: /// /// Stack grows downwards towards lower addresses. @@ -202,91 +240,21 @@ impl StackFrame { } #[inline] - pub fn ic_vector(&self) -> HeapPtr { - let ptr = unsafe { *self.fp.add(IC_VECTOR_SLOT_INDEX) }; - HeapPtr::from_ptr(ptr as *mut ICVector) - } - - #[inline] - pub fn ic_vector_mut(&self) -> &mut HeapPtr { - unsafe { &mut *(self.fp.add(IC_VECTOR_SLOT_INDEX) as *mut HeapPtr) } - } - - #[inline] - pub fn get_ic_stub(&self, slot: usize) -> Option { - *self.ic_vector().slots().get_unchecked(slot) - } - - #[inline] - pub fn insert_div_ic_stub( - &mut self, - slot: DivICSlotIndex, - mut stub: Handle, - ) { - let head = self - .ic_vector_mut() - .slots_mut() - .get_unchecked_mut(slot.value().to_usize()); - match head { - Some(ICEntry::Div(ptr)) => stub.set_next(Some(*ptr)), - Some(_) => unreachable!("DivICStub head was a different type than expected."), - None => stub.set_next(None), + pub fn ic_vector(&self) -> Option> { + unsafe { + std::mem::transmute::>>( + *self.fp.add(IC_VECTOR_SLOT_INDEX), + ) } - *head = Some(ICEntry::Div(*stub)); } #[inline] - pub fn insert_mul_ic_stub( - &mut self, - slot: MulICSlotIndex, - mut stub: Handle, - ) { - let head = self - .ic_vector_mut() - .slots_mut() - .get_unchecked_mut(slot.value().to_usize()); - match head { - Some(ICEntry::Mul(ptr)) => stub.set_next(Some(*ptr)), - Some(_) => unreachable!("MulICStub head was a different type than expected."), - None => stub.set_next(None), - } - *head = Some(ICEntry::Mul(*stub)); + pub fn ic_vector_mut(&mut self) -> &mut Option> { + unsafe { &mut *(self.fp.add(IC_VECTOR_SLOT_INDEX) as *mut Option>) } } - #[inline] - pub fn insert_sub_ic_stub( - &mut self, - slot: SubICSlotIndex, - mut stub: Handle, - ) { - let head = self - .ic_vector_mut() - .slots_mut() - .get_unchecked_mut(slot.value().to_usize()); - match head { - Some(ICEntry::Sub(ptr)) => stub.set_next(Some(*ptr)), - Some(_) => unreachable!("SubICStub head was a different type than expected."), - None => stub.set_next(None), - } - *head = Some(ICEntry::Sub(*stub)); - } - - #[inline] - pub fn insert_add_ic_stub( - &mut self, - slot: AddICSlotIndex, - mut stub: Handle, - ) { - let head = self - .ic_vector_mut() - .slots_mut() - .get_unchecked_mut(slot.value().to_usize()); - match head { - Some(ICEntry::Add(ptr)) => stub.set_next(Some(*ptr)), - Some(_) => unreachable!("SubICStub head was a different type than expected."), - None => stub.set_next(None), - } - *head = Some(ICEntry::Add(*stub)); + pub fn get_ic_stub(&self, slot: usize) -> Option { + *self.ic_vector()?.slots().get_unchecked(slot) } /// The callee function in this stack frame. @@ -375,9 +343,24 @@ impl StackFrame { visitor.visit_pointer(self.closure_mut()); visitor.visit_pointer(self.constant_table_mut()); - visitor.visit_pointer(self.ic_vector_mut()); + visitor.visit_pointer_opt(self.ic_vector_mut()); visitor.visit_pointer(self.scope_mut()); } + + def_insert_ic_stub!( + Add, + Sub, + Mul, + Div, + Rem, + Exp, + BitAnd, + BitOr, + BitXor, + ShiftLeft, + ShiftRightArith, + ShiftRightLogical + ); } pub struct StackFrameIter { diff --git a/src/js/runtime/bytecode/vm.rs b/src/js/runtime/bytecode/vm.rs index 4445d663..16c84024 100644 --- a/src/js/runtime/bytecode/vm.rs +++ b/src/js/runtime/bytecode/vm.rs @@ -18,7 +18,11 @@ use crate::{ array_object::{array_create, ArrayObject}, async_generator_object::{async_generator_complete_step, AsyncGeneratorObject}, boxed_value::BoxedValue, - bytecode::operand::{AddICSlotIndex, DivICSlotIndex, MulICSlotIndex, SubICSlotIndex}, + bytecode::operand::{ + AddICSlotIndex, BitAndICSlotIndex, BitOrICSlotIndex, BitXorICSlotIndex, DivICSlotIndex, + ExpICSlotIndex, MulICSlotIndex, RemICSlotIndex, ShiftLeftICSlotIndex, + ShiftRightArithICSlotIndex, ShiftRightLogicalICSlotIndex, SubICSlotIndex, + }, class_names::{new_class, ClassNames}, error::{ err_assign_constant, err_cannot_set_property, err_not_defined, reference_error, @@ -44,7 +48,11 @@ use crate::{ heap_item_descriptor::HeapItemKind, ic::{ generate::ICStubGenerator, - stubs::binary_arith::{AddICStub, DivICStub, MulICStub, SubICStub}, + stubs::binary_arith::{ + AddICStub, BitAndICStub, BitOrICStub, BitXorICStub, DivICStub, ExpICStub, + MulICStub, RemICStub, ShiftLeftICStub, ShiftRightArithICStub, + ShiftRightLogicalICStub, SubICStub, + }, vector::{ICEntry, ICVector}, }, intrinsics::{ @@ -260,7 +268,20 @@ impl VM { } // IC stub getters and setters - def_ic_stub_methods!(Add, Sub, Mul, Div); + def_ic_stub_methods!( + Add, + Sub, + Mul, + Div, + Rem, + Exp, + BitAnd, + BitOr, + BitXor, + ShiftLeft, + ShiftRightArith, + ShiftRightLogical + ); pub fn stack_trace_top(&self) -> Option { self.stack_trace_top @@ -2878,10 +2899,11 @@ impl VM { let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - // May allocate - let result = eval_remainder(self.cx(), left_value, right_value)?; - - self.write_register(dest, *result); + eval_with_ic!(self, Rem, instr, left_value, right_value, dest, { + let result = eval_remainder(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) @@ -2894,10 +2916,11 @@ impl VM { let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - // May allocate - let result = eval_exponentiation(self.cx(), left_value, right_value)?; - - self.write_register(dest, *result); + eval_with_ic!(self, Exp, instr, left_value, right_value, dest, { + let result = eval_exponentiation(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) @@ -2910,10 +2933,11 @@ impl VM { let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - // May allocate - let result = eval_bitwise_and(self.cx(), left_value, right_value)?; - - self.write_register(dest, *result); + eval_with_ic!(self, BitAnd, instr, left_value, right_value, dest, { + let result = eval_bitwise_and(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) @@ -2926,10 +2950,11 @@ impl VM { let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - // May allocate - let result = eval_bitwise_or(self.cx(), left_value, right_value)?; - - self.write_register(dest, *result); + eval_with_ic!(self, BitOr, instr, left_value, right_value, dest, { + let result = eval_bitwise_or(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) @@ -2942,10 +2967,11 @@ impl VM { let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - // May allocate - let result = eval_bitwise_xor(self.cx(), left_value, right_value)?; - - self.write_register(dest, *result); + eval_with_ic!(self, BitXor, instr, left_value, right_value, dest, { + let result = eval_bitwise_xor(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) @@ -2958,10 +2984,11 @@ impl VM { let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - // May allocate - let result = eval_shift_left(self.cx(), left_value, right_value)?; - - self.write_register(dest, *result); + eval_with_ic!(self, ShiftLeft, instr, left_value, right_value, dest, { + let result = eval_shift_left(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) @@ -2977,10 +3004,11 @@ impl VM { let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - // May allocate - let result = eval_shift_right_arithmetic(self.cx(), left_value, right_value)?; - - self.write_register(dest, *result); + eval_with_ic!(self, ShiftRightArith, instr, left_value, right_value, dest, { + let result = eval_shift_right_arithmetic(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) @@ -2996,10 +3024,11 @@ impl VM { let right_value = self.read_register_to_handle(instr.right()); let dest = instr.dest(); - // May allocate - let result = eval_shift_right_logical(self.cx(), left_value, right_value)?; - - self.write_register(dest, *result); + eval_with_ic!(self, ShiftRightLogical, instr, left_value, right_value, dest, { + let result = eval_shift_right_logical(self.cx(), left_value, right_value)?; + self.write_register(dest, *result); + result + }); Ok(()) }) diff --git a/src/js/runtime/eval/common.rs b/src/js/runtime/eval/common.rs index 7ffa72e4..fb57aff7 100644 --- a/src/js/runtime/eval/common.rs +++ b/src/js/runtime/eval/common.rs @@ -1,8 +1,20 @@ +use std::convert::TryInto; + +use icu_collections::codepointtrie::TrieValue; use num_bigint::BigInt; -use crate::runtime::{ - alloc_error::AllocResult, error::range_error, string_value::StringValue, value::BigIntValue, - Context, EvalResult, Handle, Value, +use crate::{ + must, + runtime::{ + alloc_error::AllocResult, + error::range_error, + eval::expression::eval_bigint_left_shift, + numeric_operations::number_exponentiate, + string_value::StringValue, + type_utilities::{to_int32, to_uint32}, + value::BigIntValue, + Context, EvalResult, Handle, Value, + }, }; /// Common operations that are used by IC Stubs and the interpreter @@ -116,7 +128,10 @@ pub fn mul_smi_fast( left_num: Handle, right_num: Handle, ) -> Handle { - cx.smi(left_num.as_smi() * right_num.as_smi()) + match left_num.as_smi().checked_mul(right_num.as_smi()) { + Some(r) => cx.smi(r), + None => mul_number_fast(cx, left_num, right_num), + } } /// Muls two numbers @@ -147,10 +162,14 @@ pub fn div_smi_fast( left_num: Handle, right_num: Handle, ) -> Handle { - match left_num.as_smi().checked_div(right_num.as_smi()) { - Some(r) => cx.smi(r), - None => div_number_fast(cx, left_num, right_num), + let l = left_num.as_smi(); + let r = right_num.as_smi(); + if r != 0 && l % r == 0 { + if let Some(result) = l.checked_div(r) { + return cx.smi(result); + } } + div_number_fast(cx, left_num, right_num) } /// Divs two numbers @@ -178,3 +197,340 @@ pub fn div_bigint_fast( let result = left_num.as_bigint().bigint() / bigint_right; Ok(BigIntValue::new(cx, result)?.into()) } + +/// rems two smis +#[inline] +pub fn rem_smi_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + match left_num.as_smi().checked_rem(right_num.as_smi()) { + Some(r) => cx.smi(r), + None => rem_number_fast(cx, left_num, right_num), + } +} + +/// rems two numbers +#[inline] +pub fn rem_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + cx.number(left_num.as_number() % right_num.as_number()) +} + +/// rems two bigints +#[inline] +pub fn rem_bigint_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let bigint_right = right_num.as_bigint().bigint(); + if bigint_right.eq(&BigInt::default()) { + return range_error(cx, "BigInt division by zero"); + } + + let bigint_left = left_num.as_bigint().bigint(); + if bigint_left.eq(&BigInt::default()) { + return Ok(BigIntValue::new(cx, BigInt::default())?.into()); + } + + let result = bigint_left % bigint_right; + Ok(BigIntValue::new(cx, result)?.into()) +} + +/// exps two smis +#[inline] +pub fn exp_smi_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + let base = left_num.as_smi(); + let exp = right_num.as_smi(); + + // Negative exponent: fractional result, bail to number + if exp < 0 { + return exp_number_fast(cx, left_num, right_num); + } + + match base.checked_pow(exp.to_u32()) { + Some(r) => cx.smi(r), + None => exp_number_fast(cx, left_num, right_num), + } +} + +/// exps two numbers +#[inline] +pub fn exp_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + // NOTE: Can probably make more fast paths for number_exponentiate + cx.number(number_exponentiate(left_num.as_number(), right_num.as_number())) +} + +/// exps two bigints +#[inline] +pub fn exp_bigint_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let base_bignum = left_num.as_bigint().bigint(); + let exponent_bignum = right_num.as_bigint().bigint(); + + if exponent_bignum.lt(&BigInt::default()) { + return range_error(cx, "BigInt negative exponent"); + } else if exponent_bignum.eq(&BigInt::default()) && base_bignum.eq(&BigInt::default()) { + return Ok(BigIntValue::new(cx, 1.into())?.into()); + } + + if let Ok(exponent_u32) = exponent_bignum.try_into() { + let result = base_bignum.pow(exponent_u32); + Ok(BigIntValue::new(cx, result)?.into()) + } else { + // This guarantees a bigint that is too large + range_error(cx, "BigInt is too large") + } +} + +/// bitwise_ands two smis +#[inline] +pub fn bitwise_and_smi_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + cx.smi(left_num.as_smi() & right_num.as_smi()) +} + +/// bitwise_ands two numbers +#[inline] +pub fn bitwise_and_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let left_smi = must!(to_int32(cx, left_num)); + let right_smi = must!(to_int32(cx, right_num)); + + Ok(cx.smi(left_smi & right_smi)) +} + +/// bitwise_ands two bigints +#[inline] +pub fn bitwise_and_bigint_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let result = left_num.as_bigint().bigint() & right_num.as_bigint().bigint(); + Ok(BigIntValue::new(cx, result)?.into()) +} + +/// bitwise_ors two smis +#[inline] +pub fn bitwise_or_smi_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + cx.smi(left_num.as_smi() | right_num.as_smi()) +} + +/// bitwise_ors two numbers +#[inline] +pub fn bitwise_or_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let left_smi = must!(to_int32(cx, left_num)); + let right_smi = must!(to_int32(cx, right_num)); + + Ok(cx.smi(left_smi | right_smi)) +} + +/// bitwise_ors two bigints +#[inline] +pub fn bitwise_or_bigint_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let result = left_num.as_bigint().bigint() | right_num.as_bigint().bigint(); + Ok(BigIntValue::new(cx, result)?.into()) +} + +/// bitwise_xors two smis +#[inline] +pub fn bitwise_xor_smi_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> Handle { + cx.smi(left_num.as_smi() ^ right_num.as_smi()) +} + +/// bitwise_xors two numbers +#[inline] +pub fn bitwise_xor_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let left_smi = must!(to_int32(cx, left_num)); + let right_smi = must!(to_int32(cx, right_num)); + + Ok(cx.smi(left_smi ^ right_smi)) +} + +/// bitwise_xors two bigints +#[inline] +pub fn bitwise_xor_bigint_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let result = left_num.as_bigint().bigint() ^ right_num.as_bigint().bigint(); + Ok(BigIntValue::new(cx, result)?.into()) +} + +/// shift_lefts two smis +#[inline] +pub fn shift_left_smi_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let left_smi = left_num.as_smi(); + let right_smi = right_num.as_smi(); + + if right_smi < 0 { + shift_left_number_fast(cx, left_num, right_num) + } else { + let shift = (right_smi as u32) & 0x1F; + Ok(cx.smi(left_smi.wrapping_shl(shift))) + } +} + +/// shift_lefts two numbers +#[inline] +pub fn shift_left_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let left_smi = must!(to_int32(cx, left_num)); + let right_u32 = must!(to_uint32(cx, right_num)); + + // Shift modulus 32 + let shift = right_u32 & 0x1F; + Ok(cx.smi(left_smi << shift)) +} + +/// shift_lefts two bigints +#[inline] +pub fn shift_left_bigint_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let result = eval_bigint_left_shift( + cx, + &left_num.as_bigint().bigint(), + &right_num.as_bigint().bigint(), + )?; + + Ok(BigIntValue::new(cx, result)?.into()) +} + +/// shift_right_ariths two smis +#[inline] +pub fn shift_right_arith_smi_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let left_smi = left_num.as_smi(); + let right_smi = right_num.as_smi(); + + if right_smi < 0 { + shift_right_arith_number_fast(cx, left_num, right_num) + } else { + let shift = (right_smi as u32) & 0x1F; + Ok(cx.smi(left_smi >> shift)) + } +} + +/// shift_right_ariths two numbers +#[inline] +pub fn shift_right_arith_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let left_smi = must!(to_int32(cx, left_num)); + let right_u32 = must!(to_uint32(cx, right_num)); + + // Shift modulus 32 + let shift = right_u32 & 0x1F; + + Ok(cx.smi(left_smi >> shift)) +} + +/// shift_right_ariths two bigints +#[inline] +pub fn shift_right_arith_bigint_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let result = eval_bigint_left_shift( + cx, + &left_num.as_bigint().bigint(), + &-right_num.as_bigint().bigint(), + )?; + + Ok(BigIntValue::new(cx, result)?.into()) +} + +/// shift_right_logicals two smis +#[inline] +pub fn shift_right_logical_smi_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let left_smi = left_num.as_smi(); + let right_smi = right_num.as_smi(); + + if right_smi < 0 || left_smi < 0 { + shift_right_logical_number_fast(cx, left_num, right_num) + } else { + let shift = (right_smi as u32) & 0x1F; + let result = (left_smi as u32) >> shift; + Ok(cx.number(result as f64)) + } +} + +/// shift_right_logicals two numbers +#[inline] +pub fn shift_right_logical_number_fast( + cx: Context, + left_num: Handle, + right_num: Handle, +) -> EvalResult> { + let left_smi = must!(to_uint32(cx, left_num)); + let right_u32 = must!(to_uint32(cx, right_num)); + + // Shift modulus 32 + let shift = right_u32 & 0x1F; + + Ok(Value::from(left_smi >> shift).to_handle(cx)) +} diff --git a/src/js/runtime/eval/expression.rs b/src/js/runtime/eval/expression.rs index 6b05eb8b..44605970 100644 --- a/src/js/runtime/eval/expression.rs +++ b/src/js/runtime/eval/expression.rs @@ -14,20 +14,23 @@ use crate::{ array_object::array_create_in_realm, error::{range_error, type_error}, eval::common::{ - add_bigint_fast, add_number_fast, add_string_fast, div_bigint_fast, div_number_fast, - is_bigint, is_string, mul_bigint_fast, mul_number_fast, sub_bigint_fast, - sub_number_fast, + add_bigint_fast, add_number_fast, add_string_fast, bitwise_and_bigint_fast, + bitwise_and_number_fast, bitwise_or_bigint_fast, bitwise_or_number_fast, + bitwise_xor_bigint_fast, bitwise_xor_number_fast, div_bigint_fast, div_number_fast, + exp_bigint_fast, exp_number_fast, is_bigint, is_string, mul_bigint_fast, + mul_number_fast, rem_bigint_fast, rem_number_fast, shift_left_bigint_fast, + shift_left_number_fast, shift_right_arith_bigint_fast, shift_right_arith_number_fast, + shift_right_logical_number_fast, sub_bigint_fast, sub_number_fast, }, eval_result::EvalResult, heap_item_descriptor::HeapItemKind, - numeric_operations::number_exponentiate, object_value::ObjectValue, property_descriptor::PropertyDescriptor, property_key::PropertyKey, string_value::StringValue, type_utilities::{ is_less_than, to_boolean, to_int32, to_numeric, to_object, to_primitive, - to_property_key, to_string, to_uint32, ToPrimitivePreferredType, + to_property_key, to_string, ToPrimitivePreferredType, }, value::{BigIntValue, Value, BOOL_TAG, NULL_TAG, UNDEFINED_TAG}, Context, Handle, Realm, @@ -204,9 +207,9 @@ pub fn eval_multiply( } if left_is_bigint { - Ok(mul_bigint_fast(cx, left_value, right_value)?) + Ok(mul_bigint_fast(cx, left_num, right_num)?) } else { - Ok(mul_number_fast(cx, left_value, right_value)) + Ok(mul_number_fast(cx, left_num, right_num)) } } @@ -244,20 +247,9 @@ pub fn eval_remainder( } if left_is_bigint { - let bigint_right = right_num.as_bigint().bigint(); - if bigint_right.eq(&BigInt::default()) { - return range_error(cx, "BigInt division by zero"); - } - - let bigint_left = left_num.as_bigint().bigint(); - if bigint_left.eq(&BigInt::default()) { - return Ok(BigIntValue::new(cx, BigInt::default())?.into()); - } - - let result = bigint_left % bigint_right; - Ok(BigIntValue::new(cx, result)?.into()) + rem_bigint_fast(cx, left_num, right_num) } else { - Ok(cx.number(left_num.as_number() % right_num.as_number())) + Ok(rem_number_fast(cx, left_num, right_num)) } } @@ -269,30 +261,15 @@ pub fn eval_exponentiation( let left_num = to_numeric(cx, left_value)?; let right_num = to_numeric(cx, right_value)?; - let left_is_bigint = left_num.is_bigint(); - if left_is_bigint != right_num.is_bigint() { + let left_is_bigint = is_bigint(left_num); + if left_is_bigint != is_bigint(right_num) { return type_error(cx, "BigInt cannot be converted to number"); } if left_is_bigint { - let base_bignum = left_num.as_bigint().bigint(); - let exponent_bignum = right_num.as_bigint().bigint(); - - if exponent_bignum.lt(&BigInt::default()) { - return range_error(cx, "BigInt negative exponent"); - } else if exponent_bignum.eq(&BigInt::default()) && base_bignum.eq(&BigInt::default()) { - return Ok(BigIntValue::new(cx, 1.into())?.into()); - } - - if let Ok(exponent_u32) = exponent_bignum.try_into() { - let result = base_bignum.pow(exponent_u32); - Ok(BigIntValue::new(cx, result)?.into()) - } else { - // This guarantees a bigint that is too large - range_error(cx, "BigInt is too large") - } + exp_bigint_fast(cx, left_num, right_num) } else { - Ok(cx.number(number_exponentiate(left_num.as_number(), right_num.as_number()))) + Ok(exp_number_fast(cx, left_num, right_num)) } } @@ -362,19 +339,15 @@ pub fn eval_bitwise_and( let left_num = to_numeric(cx, left_value)?; let right_num = to_numeric(cx, right_value)?; - let left_is_bigint = left_num.is_bigint(); - if left_is_bigint != right_num.is_bigint() { + let left_is_bigint = is_bigint(left_num); + if left_is_bigint != is_bigint(right_num) { return type_error(cx, "BigInt cannot be converted to number"); } if left_is_bigint { - let result = left_num.as_bigint().bigint() & right_num.as_bigint().bigint(); - Ok(BigIntValue::new(cx, result)?.into()) + bitwise_and_bigint_fast(cx, left_num, right_num) } else { - let left_smi = must!(to_int32(cx, left_num)); - let right_smi = must!(to_int32(cx, right_num)); - - Ok(cx.smi(left_smi & right_smi)) + bitwise_and_number_fast(cx, left_num, right_num) } } @@ -386,19 +359,15 @@ pub fn eval_bitwise_or( let left_num = to_numeric(cx, left_value)?; let right_num = to_numeric(cx, right_value)?; - let left_is_bigint = left_num.is_bigint(); - if left_is_bigint != right_num.is_bigint() { + let left_is_bigint = is_bigint(left_num); + if left_is_bigint != is_bigint(right_num) { return type_error(cx, "BigInt cannot be converted to number"); } if left_is_bigint { - let result = left_num.as_bigint().bigint() | right_num.as_bigint().bigint(); - Ok(BigIntValue::new(cx, result)?.into()) + bitwise_or_bigint_fast(cx, left_num, right_num) } else { - let left_smi = must!(to_int32(cx, left_num)); - let right_smi = must!(to_int32(cx, right_num)); - - Ok(cx.smi(left_smi | right_smi)) + bitwise_or_number_fast(cx, left_num, right_num) } } @@ -410,19 +379,15 @@ pub fn eval_bitwise_xor( let left_num = to_numeric(cx, left_value)?; let right_num = to_numeric(cx, right_value)?; - let left_is_bigint = left_num.is_bigint(); - if left_is_bigint != right_num.is_bigint() { + let left_is_bigint = is_bigint(left_num); + if left_is_bigint != is_bigint(right_num) { return type_error(cx, "BigInt cannot be converted to number"); } if left_is_bigint { - let result = left_num.as_bigint().bigint() ^ right_num.as_bigint().bigint(); - Ok(BigIntValue::new(cx, result)?.into()) + bitwise_xor_bigint_fast(cx, left_num, right_num) } else { - let left_smi = must!(to_int32(cx, left_num)); - let right_smi = must!(to_int32(cx, right_num)); - - Ok(cx.smi(left_smi ^ right_smi)) + bitwise_xor_number_fast(cx, left_num, right_num) } } @@ -440,21 +405,9 @@ pub fn eval_shift_left( } if left_is_bigint { - let result = eval_bigint_left_shift( - cx, - &left_num.as_bigint().bigint(), - &right_num.as_bigint().bigint(), - )?; - - Ok(BigIntValue::new(cx, result)?.into()) + shift_left_bigint_fast(cx, left_num, right_num) } else { - let left_smi = must!(to_int32(cx, left_num)); - let right_u32 = must!(to_uint32(cx, right_num)); - - // Shift modulus 32 - let shift = right_u32 & 0x1F; - - Ok(cx.smi(left_smi << shift)) + shift_left_number_fast(cx, left_num, right_num) } } @@ -466,32 +419,20 @@ pub fn eval_shift_right_arithmetic( let left_num = to_numeric(cx, left_value)?; let right_num = to_numeric(cx, right_value)?; - let left_is_bigint = left_num.is_bigint(); - if left_is_bigint != right_num.is_bigint() { + let left_is_bigint = is_bigint(left_num); + if left_is_bigint != is_bigint(right_num) { return type_error(cx, "BigInt cannot be converted to number"); } if left_is_bigint { - let result = eval_bigint_left_shift( - cx, - &left_num.as_bigint().bigint(), - &-right_num.as_bigint().bigint(), - )?; - - Ok(BigIntValue::new(cx, result)?.into()) + shift_right_arith_bigint_fast(cx, left_num, right_num) } else { - let left_smi = must!(to_int32(cx, left_num)); - let right_u32 = must!(to_uint32(cx, right_num)); - - // Shift modulus 32 - let shift = right_u32 & 0x1F; - - Ok(cx.smi(left_smi >> shift)) + shift_right_arith_number_fast(cx, left_num, right_num) } } /// BigInt::leftShift (https://tc39.es/ecma262/#sec-numeric-types-bigint-leftShift) -fn eval_bigint_left_shift(cx: Context, left: &BigInt, right: &BigInt) -> EvalResult { +pub fn eval_bigint_left_shift(cx: Context, left: &BigInt, right: &BigInt) -> EvalResult { let bigint_2: BigInt = 2.into(); if right.lt(&BigInt::default()) { @@ -533,18 +474,12 @@ pub fn eval_shift_right_logical( let left_num = to_numeric(cx, left_value)?; let right_num = to_numeric(cx, right_value)?; - let left_is_bigint = left_num.is_bigint(); - if left_is_bigint || right_num.is_bigint() { + let left_is_bigint = is_bigint(left_num); + if left_is_bigint || is_bigint(right_num) { return type_error(cx, "BigInt cannot be converted to number"); } - let left_smi = must!(to_uint32(cx, left_num)); - let right_u32 = must!(to_uint32(cx, right_num)); - - // Shift modulus 32 - let shift = right_u32 & 0x1F; - - Ok(Value::from(left_smi >> shift).to_handle(cx)) + shift_right_logical_number_fast(cx, left_num, right_num) } /// InstanceofOperator (https://tc39.es/ecma262/#sec-instanceofoperator) diff --git a/src/js/runtime/gc/heap_item.rs b/src/js/runtime/gc/heap_item.rs index 7a9ae802..8cd2caf6 100644 --- a/src/js/runtime/gc/heap_item.rs +++ b/src/js/runtime/gc/heap_item.rs @@ -24,7 +24,10 @@ use crate::runtime::{ global_names::GlobalNames, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, ic::{ - stubs::binary_arith::{AddICStub, SubICStub}, + stubs::binary_arith::{ + AddICStub, BitAndICStub, BitOrICStub, BitXorICStub, DivICStub, ExpICStub, MulICStub, + RemICStub, ShiftLeftICStub, ShiftRightArithICStub, ShiftRightLogicalICStub, SubICStub, + }, vector::ICVector, }, interned_strings::InternedStringsSetField, @@ -224,6 +227,18 @@ impl HeapPtr { HeapItemKind::ICVector => self.cast::().byte_size(), HeapItemKind::AddICStub => self.cast::().byte_size(), HeapItemKind::SubICStub => self.cast::().byte_size(), + HeapItemKind::MulICStub => self.cast::().byte_size(), + HeapItemKind::DivICStub => self.cast::().byte_size(), + HeapItemKind::RemICStub => self.cast::().byte_size(), + HeapItemKind::ExpICStub => self.cast::().byte_size(), + HeapItemKind::BitAndICStub => self.cast::().byte_size(), + HeapItemKind::BitOrICStub => self.cast::().byte_size(), + HeapItemKind::BitXorICStub => self.cast::().byte_size(), + HeapItemKind::ShiftLeftICStub => self.cast::().byte_size(), + HeapItemKind::ShiftRightArithICStub => self.cast::().byte_size(), + HeapItemKind::ShiftRightLogicalICStub => { + self.cast::().byte_size() + } HeapItemKind::Last => unreachable!("No objects are created with this descriptor"), } } @@ -390,6 +405,20 @@ impl HeapPtr { HeapItemKind::ICVector => self.cast::().visit_pointers(visitor), HeapItemKind::AddICStub => self.cast::().visit_pointers(visitor), HeapItemKind::SubICStub => self.cast::().visit_pointers(visitor), + HeapItemKind::MulICStub => self.cast::().visit_pointers(visitor), + HeapItemKind::DivICStub => self.cast::().visit_pointers(visitor), + HeapItemKind::RemICStub => self.cast::().visit_pointers(visitor), + HeapItemKind::ExpICStub => self.cast::().visit_pointers(visitor), + HeapItemKind::BitAndICStub => self.cast::().visit_pointers(visitor), + HeapItemKind::BitOrICStub => self.cast::().visit_pointers(visitor), + HeapItemKind::BitXorICStub => self.cast::().visit_pointers(visitor), + HeapItemKind::ShiftLeftICStub => self.cast::().visit_pointers(visitor), + HeapItemKind::ShiftRightArithICStub => { + self.cast::().visit_pointers(visitor) + } + HeapItemKind::ShiftRightLogicalICStub => self + .cast::() + .visit_pointers(visitor), HeapItemKind::Last => unreachable!("No objects are created with this descriptor"), } } diff --git a/src/js/runtime/heap_item_descriptor.rs b/src/js/runtime/heap_item_descriptor.rs index 25ae3d7c..a6866bcc 100644 --- a/src/js/runtime/heap_item_descriptor.rs +++ b/src/js/runtime/heap_item_descriptor.rs @@ -159,10 +159,21 @@ pub enum HeapItemKind { // Vectors ValueVec, - // IC Vectors and IC Stubs + // IC Vector ICVector, + // IC Stubs AddICStub, SubICStub, + MulICStub, + DivICStub, + RemICStub, + ExpICStub, + BitAndICStub, + BitOrICStub, + BitXorICStub, + ShiftLeftICStub, + ShiftRightArithICStub, + ShiftRightLogicalICStub, // Numerical value is the number of kinds in the enum Last, @@ -401,6 +412,16 @@ impl BaseDescriptors { other_heap_item_descriptor!(HeapItemKind::ICVector); other_heap_item_descriptor!(HeapItemKind::AddICStub); other_heap_item_descriptor!(HeapItemKind::SubICStub); + other_heap_item_descriptor!(HeapItemKind::MulICStub); + other_heap_item_descriptor!(HeapItemKind::DivICStub); + other_heap_item_descriptor!(HeapItemKind::RemICStub); + other_heap_item_descriptor!(HeapItemKind::ExpICStub); + other_heap_item_descriptor!(HeapItemKind::BitAndICStub); + other_heap_item_descriptor!(HeapItemKind::BitOrICStub); + other_heap_item_descriptor!(HeapItemKind::BitXorICStub); + other_heap_item_descriptor!(HeapItemKind::ShiftLeftICStub); + other_heap_item_descriptor!(HeapItemKind::ShiftRightArithICStub); + other_heap_item_descriptor!(HeapItemKind::ShiftRightLogicalICStub); Ok(base_descriptors) } diff --git a/src/js/runtime/ic/generate.rs b/src/js/runtime/ic/generate.rs index 53f0416c..764b8ede 100644 --- a/src/js/runtime/ic/generate.rs +++ b/src/js/runtime/ic/generate.rs @@ -1,6 +1,7 @@ use crate::runtime::ic::stubs::binary_arith::{ - AddICStub, BailReason, BinaryArithICStubEmitter, BinaryArithICStubExecutor, DivICStub, - MulICStub, SubICStub, + AddICStub, BailReason, BinaryArithICStubEmitter, BinaryArithICStubExecutor, BitAndICStub, + BitOrICStub, BitXorICStub, DivICStub, ExpICStub, MulICStub, RemICStub, ShiftLeftICStub, + ShiftRightArithICStub, ShiftRightLogicalICStub, SubICStub, }; use crate::runtime::ic::stubs::{ICBackend, ICGuard, ICOp, Operand}; use crate::runtime::{alloc_error::AllocResult, Context, Handle, Value}; @@ -15,6 +16,47 @@ macro_rules! define_stub { }; } +macro_rules! def_new_stub_for { + ($($op:ident, $smi:ident, $number:ident $(, $bigint:ident)? $(+ $string:ident)?);* $(;)?) => { + $( + paste::paste! { + pub fn []( + &self, + left: &Value, + right: &Value, + result: &Value, + ) -> Option]>>> { + let (execute, emit): (BinaryArithICStubExecutor, BinaryArithICStubEmitter) = + if left.is_smi() && right.is_smi() { + if result.is_smi() { + ($smi, $smi) + } else { + ($number, $number) + } + } else if left.is_number() && right.is_number() { + ($number, $number) + } + $( + else if left.is_string() && right.is_string() { + ($string, $string) + } + )? + $( + else if left.is_bigint() && right.is_bigint() { + ($bigint, $bigint) + } + )? + else { + return None; + }; + + Some([<$op ICStub>]::new(self.cx, execute, emit)) + } + } + )* + }; +} + // add define_stub!(add_smi_stub, Smi, ExpectedSmi, AddSmi); define_stub!(add_number_stub, Number, ExpectedNumber, AddNumber); @@ -32,6 +74,37 @@ define_stub!(mul_bigint_stub, BigInt, ExpectedBigInt, MulBigInt); define_stub!(div_smi_stub, Smi, ExpectedSmi, DivSmi); define_stub!(div_number_stub, Number, ExpectedNumber, DivNumber); define_stub!(div_bigint_stub, BigInt, ExpectedBigInt, DivBigInt); +// rem +define_stub!(rem_smi_stub, Smi, ExpectedSmi, RemSmi); +define_stub!(rem_number_stub, Number, ExpectedNumber, RemNumber); +define_stub!(rem_bigint_stub, BigInt, ExpectedBigInt, RemBigInt); +// exp +define_stub!(exp_smi_stub, Smi, ExpectedSmi, ExpSmi); +define_stub!(exp_number_stub, Number, ExpectedNumber, ExpNumber); +define_stub!(exp_bigint_stub, BigInt, ExpectedBigInt, ExpBigInt); +// bit and +define_stub!(bit_and_smi_stub, Smi, ExpectedSmi, BitAndSmi); +define_stub!(bit_and_number_stub, Number, ExpectedNumber, BitAndNumber); +define_stub!(bit_and_bigint_stub, BigInt, ExpectedBigInt, BitAndBigInt); +// bit or +define_stub!(bit_or_smi_stub, Smi, ExpectedSmi, BitOrSmi); +define_stub!(bit_or_number_stub, Number, ExpectedNumber, BitOrNumber); +define_stub!(bit_or_bigint_stub, BigInt, ExpectedBigInt, BitOrBigInt); +// bit xor +define_stub!(bit_xor_smi_stub, Smi, ExpectedSmi, BitXorSmi); +define_stub!(bit_xor_number_stub, Number, ExpectedNumber, BitXorNumber); +define_stub!(bit_xor_bigint_stub, BigInt, ExpectedBigInt, BitXorBigInt); +// shift left +define_stub!(shift_left_smi_stub, Smi, ExpectedSmi, ShiftLeftSmi); +define_stub!(shift_left_number_stub, Number, ExpectedNumber, ShiftLeftNumber); +define_stub!(shift_left_bigint_stub, BigInt, ExpectedBigInt, ShiftLeftBigInt); +// shift right arith +define_stub!(shift_right_arith_smi_stub, Smi, ExpectedSmi, ShiftRightArithSmi); +define_stub!(shift_right_arith_number_stub, Number, ExpectedNumber, ShiftRightArithNumber); +define_stub!(shift_right_arith_bigint_stub, BigInt, ExpectedBigInt, ShiftRightArithBigInt); +// shift right logical +define_stub!(shift_right_logical_smi_stub, Smi, ExpectedSmi, ShiftRightLogicalSmi); +define_stub!(shift_right_logical_number_stub, Number, ExpectedNumber, ShiftRightLogicalNumber); pub struct ICStubGenerator<'cx> { cx: &'cx Context, @@ -42,101 +115,18 @@ impl<'cx> ICStubGenerator<'cx> { Self { cx } } - pub fn new_stub_for_add( - &self, - left: &Value, - right: &Value, - result: &Value, - ) -> Option>> { - let (execute, emit): (BinaryArithICStubExecutor, BinaryArithICStubEmitter) = - if left.is_smi() && right.is_smi() { - if result.is_smi() { - (add_smi_stub, add_smi_stub) - } else { - (add_number_stub, add_number_stub) - } - } else if left.is_number() && right.is_number() { - (add_number_stub, add_number_stub) - } else if left.is_string() && right.is_string() { - (concat_string_stub, concat_string_stub) - } else if left.is_bigint() && right.is_bigint() { - (add_bigint_stub, add_bigint_stub) - } else { - return None; - }; - - Some(AddICStub::new(self.cx, execute, emit)) - } - - pub fn new_stub_for_sub( - &self, - left: &Value, - right: &Value, - result: &Value, - ) -> Option>> { - let (execute, emit): (BinaryArithICStubExecutor, BinaryArithICStubEmitter) = - if left.is_smi() && right.is_smi() { - if result.is_smi() { - (sub_smi_stub, sub_smi_stub) - } else { - (sub_number_stub, sub_number_stub) - } - } else if left.is_number() && right.is_number() { - (sub_number_stub, sub_number_stub) - } else if left.is_bigint() && right.is_bigint() { - (sub_bigint_stub, sub_bigint_stub) - } else { - return None; - }; - - Some(SubICStub::new(self.cx, execute, emit)) - } - - pub fn new_stub_for_mul( - &self, - left: &Value, - right: &Value, - result: &Value, - ) -> Option>> { - let (execute, emit): (BinaryArithICStubExecutor, BinaryArithICStubEmitter) = - if left.is_smi() && right.is_smi() { - if result.is_smi() { - (mul_smi_stub, mul_smi_stub) - } else { - (mul_number_stub, mul_number_stub) - } - } else if left.is_number() && right.is_number() { - (mul_number_stub, mul_number_stub) - } else if left.is_bigint() && right.is_bigint() { - (mul_bigint_stub, mul_bigint_stub) - } else { - return None; - }; - - Some(MulICStub::new(self.cx, execute, emit)) - } - - pub fn new_stub_for_div( - &self, - left: &Value, - right: &Value, - result: &Value, - ) -> Option>> { - let (execute, emit): (BinaryArithICStubExecutor, BinaryArithICStubEmitter) = - if left.is_smi() && right.is_smi() { - if result.is_smi() { - (div_smi_stub, div_smi_stub) - } else { - (div_number_stub, div_number_stub) - } - } else if left.is_number() && right.is_number() { - (div_number_stub, div_number_stub) - } else if left.is_bigint() && right.is_bigint() { - (div_bigint_stub, div_bigint_stub) - } else { - return None; - }; - - Some(DivICStub::new(self.cx, execute, emit)) + def_new_stub_for! { + Add, add_smi_stub, add_number_stub, add_bigint_stub + concat_string_stub; + Sub, sub_smi_stub, sub_number_stub, sub_bigint_stub; + Mul, mul_smi_stub, mul_number_stub, mul_bigint_stub; + Div, div_smi_stub, div_number_stub, div_bigint_stub; + Rem, rem_smi_stub, rem_number_stub, rem_bigint_stub; + Exp, exp_smi_stub, exp_number_stub, exp_bigint_stub; + BitAnd, bit_and_smi_stub, bit_and_number_stub, bit_and_bigint_stub; + BitOr, bit_or_smi_stub, bit_or_number_stub, bit_or_bigint_stub; + BitXor, bit_xor_smi_stub, bit_xor_number_stub, bit_xor_bigint_stub; + ShiftLeft, shift_left_smi_stub, shift_left_number_stub, shift_left_bigint_stub; + ShiftRightArith, shift_right_arith_smi_stub, shift_right_arith_number_stub, shift_right_arith_bigint_stub; + ShiftRightLogical, shift_right_logical_smi_stub, shift_right_logical_number_stub; } } diff --git a/src/js/runtime/ic/stubs/binary_arith.rs b/src/js/runtime/ic/stubs/binary_arith.rs index 4769e005..67cfa5d5 100644 --- a/src/js/runtime/ic/stubs/binary_arith.rs +++ b/src/js/runtime/ic/stubs/binary_arith.rs @@ -33,15 +33,35 @@ macro_rules! def_op { $( pub struct $op_name; pub type $ic_name = BinaryArithICStub<$op_name>; + impl BinaryArithOp for $op_name { + fn heap_item_kind() -> HeapItemKind { HeapItemKind::$ic_name } + } )* } } // Zero sized types marking ops and IC Stubs aliases -def_op!((AddOp, AddICStub), (SubOp, SubICStub), (MulOp, MulICStub), (DivOp, DivICStub)); +def_op!( + (AddOp, AddICStub), + (SubOp, SubICStub), + (MulOp, MulICStub), + (DivOp, DivICStub), + (RemOp, RemICStub), + (ExpOp, ExpICStub), + (BitAndOp, BitAndICStub), + (BitOrOp, BitOrICStub), + (BitXorOp, BitXorICStub), + (ShiftLeftOp, ShiftLeftICStub), + (ShiftRightArithOp, ShiftRightArithICStub), + (ShiftRightLogicalOp, ShiftRightLogicalICStub) +); + +pub trait BinaryArithOp { + fn heap_item_kind() -> HeapItemKind; +} #[repr(C)] -pub struct BinaryArithICStub { +pub struct BinaryArithICStub { descriptor: HeapPtr, /// pointer to the next stub next: Option>>, @@ -53,7 +73,7 @@ pub struct BinaryArithICStub { _phantom: PhantomData, } -impl BinaryArithICStub { +impl BinaryArithICStub { fn execute_code( &self, cx: Context, @@ -75,7 +95,7 @@ impl BinaryArithICStub { ) -> AllocResult>> { let mut object = cx.alloc_uninit::>()?; - set_uninit!(object.descriptor, cx.base_descriptors.get(HeapItemKind::AddICStub)); + set_uninit!(object.descriptor, cx.base_descriptors.get(Op::heap_item_kind())); set_uninit!(object.next, None); set_uninit!(object.executor, executor); set_uninit!(object.emitter, emitter); @@ -112,7 +132,7 @@ impl BinaryArithICStub { } /// GC Integration for AddICStub -impl HeapItem for HeapPtr> { +impl HeapItem for HeapPtr> { fn byte_size(&self) -> usize { size_of::>() } diff --git a/src/js/runtime/ic/stubs/executor.rs b/src/js/runtime/ic/stubs/executor.rs index c3f9a252..4770aa1d 100644 --- a/src/js/runtime/ic/stubs/executor.rs +++ b/src/js/runtime/ic/stubs/executor.rs @@ -1,8 +1,15 @@ use crate::runtime::{ eval::common::{ - add_bigint_fast, add_number_fast, add_smi_fast, add_string_fast, div_bigint_fast, - div_number_fast, div_smi_fast, is_bigint, is_number, is_smi, is_string, mul_bigint_fast, - mul_number_fast, mul_smi_fast, sub_bigint_fast, sub_number_fast, sub_smi_fast, + add_bigint_fast, add_number_fast, add_smi_fast, add_string_fast, bitwise_and_bigint_fast, + bitwise_and_number_fast, bitwise_and_smi_fast, bitwise_or_bigint_fast, + bitwise_or_number_fast, bitwise_or_smi_fast, bitwise_xor_bigint_fast, + bitwise_xor_number_fast, bitwise_xor_smi_fast, div_bigint_fast, div_number_fast, + div_smi_fast, exp_bigint_fast, exp_number_fast, exp_smi_fast, is_bigint, is_number, is_smi, + is_string, mul_bigint_fast, mul_number_fast, mul_smi_fast, rem_bigint_fast, + rem_number_fast, rem_smi_fast, shift_left_bigint_fast, shift_left_number_fast, + shift_left_smi_fast, shift_right_arith_bigint_fast, shift_right_arith_number_fast, + shift_right_arith_smi_fast, shift_right_logical_number_fast, shift_right_logical_smi_fast, + sub_bigint_fast, sub_number_fast, sub_smi_fast, }, ic::{ fgc::FGC, @@ -11,6 +18,15 @@ use crate::runtime::{ Context, EvalResult, Handle, Value, }; +macro_rules! ic_op { + ($state:expr, $cx:expr, $func:ident) => { + $state.map(move |(l, r)| Ok($func($cx, l, r))) + }; + ($state:expr, $cx:expr, $func:ident?) => { + $state.map(move |(l, r)| $func($cx, l, r).map_err(Into::into)) + }; +} + pub struct BinaryExecutor { cx: Context, state: FGC<(Handle, Handle), BailReason>, @@ -66,22 +82,46 @@ impl ICBackend for BinaryExecutor { #[inline(always)] fn exec(self, op: ICOp) -> FGC>, BailReason> { let BinaryExecutor { cx, state } = self; + match op { - ICOp::AddSmi => state.map(move |(l, r)| Ok(add_smi_fast(cx, l, r))), - ICOp::AddNumber => state.map(move |(l, r)| Ok(add_number_fast(cx, l, r))), - ICOp::AddBigInt => state.map(move |(l, r)| Ok(add_bigint_fast(cx, l, r)?)), + ICOp::AddSmi => ic_op!(state, cx, add_smi_fast), + ICOp::AddNumber => ic_op!(state, cx, add_number_fast), + ICOp::AddBigInt => ic_op!(state, cx, add_bigint_fast?), ICOp::ConcatString => { state.map(move |(l, r)| Ok(add_string_fast(cx, l.as_string(), r.as_string())?)) } - ICOp::SubSmi => state.map(move |(l, r)| Ok(sub_smi_fast(cx, l, r))), - ICOp::SubNumber => state.map(move |(l, r)| Ok(sub_number_fast(cx, l, r))), - ICOp::SubBigInt => state.map(move |(l, r)| Ok(sub_bigint_fast(cx, l, r)?)), - ICOp::MulSmi => state.map(move |(l, r)| Ok(mul_smi_fast(cx, l, r))), - ICOp::MulNumber => state.map(move |(l, r)| Ok(mul_number_fast(cx, l, r))), - ICOp::MulBigInt => state.map(move |(l, r)| Ok(mul_bigint_fast(cx, l, r)?)), - ICOp::DivSmi => state.map(move |(l, r)| Ok(div_smi_fast(cx, l, r))), - ICOp::DivNumber => state.map(move |(l, r)| Ok(div_number_fast(cx, l, r))), - ICOp::DivBigInt => state.map(move |(l, r)| Ok(div_bigint_fast(cx, l, r)?)), + ICOp::SubSmi => ic_op!(state, cx, sub_smi_fast), + ICOp::SubNumber => ic_op!(state, cx, sub_number_fast), + ICOp::SubBigInt => ic_op!(state, cx, sub_bigint_fast?), + ICOp::MulSmi => ic_op!(state, cx, mul_smi_fast), + ICOp::MulNumber => ic_op!(state, cx, mul_number_fast), + ICOp::MulBigInt => ic_op!(state, cx, mul_bigint_fast?), + ICOp::DivSmi => ic_op!(state, cx, div_smi_fast), + ICOp::DivNumber => ic_op!(state, cx, div_number_fast), + ICOp::DivBigInt => ic_op!(state, cx, div_bigint_fast?), + ICOp::RemSmi => ic_op!(state, cx, rem_smi_fast), + ICOp::RemNumber => ic_op!(state, cx, rem_number_fast), + ICOp::RemBigInt => ic_op!(state, cx, rem_bigint_fast?), + ICOp::ExpSmi => ic_op!(state, cx, exp_smi_fast), + ICOp::ExpNumber => ic_op!(state, cx, exp_number_fast), + ICOp::ExpBigInt => ic_op!(state, cx, exp_bigint_fast?), + ICOp::BitAndSmi => ic_op!(state, cx, bitwise_and_smi_fast), + ICOp::BitAndNumber => ic_op!(state, cx, bitwise_and_number_fast?), + ICOp::BitAndBigInt => ic_op!(state, cx, bitwise_and_bigint_fast?), + ICOp::BitOrSmi => ic_op!(state, cx, bitwise_or_smi_fast), + ICOp::BitOrNumber => ic_op!(state, cx, bitwise_or_number_fast?), + ICOp::BitOrBigInt => ic_op!(state, cx, bitwise_or_bigint_fast?), + ICOp::BitXorSmi => ic_op!(state, cx, bitwise_xor_smi_fast), + ICOp::BitXorNumber => ic_op!(state, cx, bitwise_xor_number_fast?), + ICOp::BitXorBigInt => ic_op!(state, cx, bitwise_xor_bigint_fast?), + ICOp::ShiftLeftSmi => ic_op!(state, cx, shift_left_smi_fast?), + ICOp::ShiftLeftNumber => ic_op!(state, cx, shift_left_number_fast?), + ICOp::ShiftLeftBigInt => ic_op!(state, cx, shift_left_bigint_fast?), + ICOp::ShiftRightArithSmi => ic_op!(state, cx, shift_right_arith_smi_fast?), + ICOp::ShiftRightArithNumber => ic_op!(state, cx, shift_right_arith_number_fast?), + ICOp::ShiftRightArithBigInt => ic_op!(state, cx, shift_right_arith_bigint_fast?), + ICOp::ShiftRightLogicalSmi => ic_op!(state, cx, shift_right_logical_smi_fast?), + ICOp::ShiftRightLogicalNumber => ic_op!(state, cx, shift_right_logical_number_fast?), } } } diff --git a/src/js/runtime/ic/stubs/mod.rs b/src/js/runtime/ic/stubs/mod.rs index fcff7b7e..69e62dcf 100644 --- a/src/js/runtime/ic/stubs/mod.rs +++ b/src/js/runtime/ic/stubs/mod.rs @@ -30,6 +30,29 @@ pub enum ICOp { DivSmi, DivNumber, DivBigInt, + RemSmi, + RemNumber, + RemBigInt, + ExpSmi, + ExpNumber, + ExpBigInt, + BitAndSmi, + BitAndNumber, + BitAndBigInt, + BitOrSmi, + BitOrNumber, + BitOrBigInt, + BitXorSmi, + BitXorNumber, + BitXorBigInt, + ShiftLeftSmi, + ShiftLeftNumber, + ShiftLeftBigInt, + ShiftRightArithSmi, + ShiftRightArithNumber, + ShiftRightArithBigInt, + ShiftRightLogicalSmi, + ShiftRightLogicalNumber, } pub enum ICInstruction { diff --git a/src/js/runtime/ic/vector.rs b/src/js/runtime/ic/vector.rs index 698d1ba7..64f16487 100644 --- a/src/js/runtime/ic/vector.rs +++ b/src/js/runtime/ic/vector.rs @@ -5,7 +5,10 @@ use crate::{ collections::InlineArray, gc::{HeapItem, HeapVisitor}, heap_item_descriptor::{HeapItemDescriptor, HeapItemKind}, - ic::stubs::binary_arith::{AddICStub, DivICStub, MulICStub, SubICStub}, + ic::stubs::binary_arith::{ + AddICStub, BitAndICStub, BitOrICStub, BitXorICStub, DivICStub, ExpICStub, MulICStub, + RemICStub, ShiftLeftICStub, ShiftRightArithICStub, ShiftRightLogicalICStub, SubICStub, + }, Context, Handle, HeapPtr, }, set_uninit, @@ -17,6 +20,14 @@ pub enum ICEntry { Sub(HeapPtr), Mul(HeapPtr), Div(HeapPtr), + Rem(HeapPtr), + Exp(HeapPtr), + BitAnd(HeapPtr), + BitOr(HeapPtr), + BitXor(HeapPtr), + ShiftLeft(HeapPtr), + ShiftRightArith(HeapPtr), + ShiftRightLogical(HeapPtr), } #[repr(C)] @@ -87,6 +98,14 @@ impl HeapItem for HeapPtr { ICEntry::Sub(heap_ptr) => visitor.visit_pointer(heap_ptr), ICEntry::Mul(heap_ptr) => visitor.visit_pointer(heap_ptr), ICEntry::Div(heap_ptr) => visitor.visit_pointer(heap_ptr), + ICEntry::Rem(heap_ptr) => visitor.visit_pointer(heap_ptr), + ICEntry::Exp(heap_ptr) => visitor.visit_pointer(heap_ptr), + ICEntry::BitAnd(heap_ptr) => visitor.visit_pointer(heap_ptr), + ICEntry::BitOr(heap_ptr) => visitor.visit_pointer(heap_ptr), + ICEntry::BitXor(heap_ptr) => visitor.visit_pointer(heap_ptr), + ICEntry::ShiftLeft(heap_ptr) => visitor.visit_pointer(heap_ptr), + ICEntry::ShiftRightArith(heap_ptr) => visitor.visit_pointer(heap_ptr), + ICEntry::ShiftRightLogical(heap_ptr) => visitor.visit_pointer(heap_ptr), } } } From 9ddca9969d4a67e65863794d0eb8765288a4bf6e Mon Sep 17 00:00:00 2001 From: vrindisbacher Date: Sat, 23 May 2026 11:32:56 -0700 Subject: [PATCH 11/11] snapshot tests --- tests/js_bytecode/expression/assign.exp | 122 +++++++++++------------ tests/js_bytecode/expression/binary.exp | 50 +++++----- tests/js_bytecode/expression/logical.exp | 48 ++++----- 3 files changed, 110 insertions(+), 110 deletions(-) diff --git a/tests/js_bytecode/expression/assign.exp b/tests/js_bytecode/expression/assign.exp index 4c6541d0..0ae526e5 100644 --- a/tests/js_bytecode/expression/assign.exp +++ b/tests/js_bytecode/expression/assign.exp @@ -385,27 +385,27 @@ 8: LoadImmediate r0, 2 11: Sub a0, a0, r0, ic1 16: LoadImmediate r0, 3 - 19: Mul a0, a0, r0 - 23: LoadImmediate r0, 4 - 26: Div a0, a0, r0 - 30: LoadImmediate r0, 5 - 33: Rem a0, a0, r0 - 37: LoadImmediate r0, 6 - 40: Exp a0, a0, r0 - 44: LoadImmediate r0, 7 - 47: BitAnd a0, a0, r0 - 51: LoadImmediate r0, 8 - 54: BitOr a0, a0, r0 - 58: LoadImmediate r0, 9 - 61: BitXor a0, a0, r0 - 65: LoadImmediate r0, 10 - 68: ShiftLeft a0, a0, r0 - 72: LoadImmediate r0, 11 - 75: ShiftRightArithmetic a0, a0, r0 - 79: LoadImmediate r0, 12 - 82: ShiftRightLogical a0, a0, r0 - 86: LoadUndefined r0 - 88: Ret r0 + 19: Mul a0, a0, r0, ic2 + 24: LoadImmediate r0, 4 + 27: Div a0, a0, r0, ic3 + 32: LoadImmediate r0, 5 + 35: Rem a0, a0, r0, ic4 + 40: LoadImmediate r0, 6 + 43: Exp a0, a0, r0, ic5 + 48: LoadImmediate r0, 7 + 51: BitAnd a0, a0, r0, ic6 + 56: LoadImmediate r0, 8 + 59: BitOr a0, a0, r0, ic7 + 64: LoadImmediate r0, 9 + 67: BitXor a0, a0, r0, ic8 + 72: LoadImmediate r0, 10 + 75: ShiftLeft a0, a0, r0, ic9 + 80: LoadImmediate r0, 11 + 83: ShiftRightArithmetic a0, a0, r0, ic10 + 88: LoadImmediate r0, 12 + 91: ShiftRightLogical a0, a0, r0, ic11 + 96: LoadUndefined r0 + 98: Ret r0 } [BytecodeFunction: operatorMemberAssign] { @@ -463,46 +463,46 @@ 28: SetNamedProperty a0, c0, r0 32: GetNamedProperty r0, a0, c0 36: LoadImmediate r1, 3 - 39: Mul r0, r0, r1 - 43: SetNamedProperty a0, c0, r0 - 47: GetNamedProperty r0, a0, c0 - 51: LoadImmediate r1, 4 - 54: Div r0, r0, r1 - 58: SetNamedProperty a0, c0, r0 - 62: GetNamedProperty r0, a0, c0 - 66: LoadImmediate r1, 5 - 69: Rem r0, r0, r1 - 73: SetNamedProperty a0, c0, r0 - 77: GetNamedProperty r0, a0, c0 - 81: LoadImmediate r1, 6 - 84: Exp r0, r0, r1 - 88: SetNamedProperty a0, c0, r0 - 92: GetNamedProperty r0, a0, c0 - 96: LoadImmediate r1, 7 - 99: BitAnd r0, r0, r1 - 103: SetNamedProperty a0, c0, r0 - 107: GetNamedProperty r0, a0, c0 - 111: LoadImmediate r1, 8 - 114: BitOr r0, r0, r1 - 118: SetNamedProperty a0, c0, r0 - 122: GetNamedProperty r0, a0, c0 - 126: LoadImmediate r1, 9 - 129: BitXor r0, r0, r1 - 133: SetNamedProperty a0, c0, r0 - 137: GetNamedProperty r0, a0, c0 - 141: LoadImmediate r1, 10 - 144: ShiftLeft r0, r0, r1 - 148: SetNamedProperty a0, c0, r0 - 152: GetNamedProperty r0, a0, c0 - 156: LoadImmediate r1, 11 - 159: ShiftRightArithmetic r0, r0, r1 - 163: SetNamedProperty a0, c0, r0 - 167: GetNamedProperty r0, a0, c0 - 171: LoadImmediate r1, 12 - 174: ShiftRightLogical r0, r0, r1 - 178: SetNamedProperty a0, c0, r0 - 182: LoadUndefined r0 - 184: Ret r0 + 39: Mul r0, r0, r1, ic2 + 44: SetNamedProperty a0, c0, r0 + 48: GetNamedProperty r0, a0, c0 + 52: LoadImmediate r1, 4 + 55: Div r0, r0, r1, ic3 + 60: SetNamedProperty a0, c0, r0 + 64: GetNamedProperty r0, a0, c0 + 68: LoadImmediate r1, 5 + 71: Rem r0, r0, r1, ic4 + 76: SetNamedProperty a0, c0, r0 + 80: GetNamedProperty r0, a0, c0 + 84: LoadImmediate r1, 6 + 87: Exp r0, r0, r1, ic5 + 92: SetNamedProperty a0, c0, r0 + 96: GetNamedProperty r0, a0, c0 + 100: LoadImmediate r1, 7 + 103: BitAnd r0, r0, r1, ic6 + 108: SetNamedProperty a0, c0, r0 + 112: GetNamedProperty r0, a0, c0 + 116: LoadImmediate r1, 8 + 119: BitOr r0, r0, r1, ic7 + 124: SetNamedProperty a0, c0, r0 + 128: GetNamedProperty r0, a0, c0 + 132: LoadImmediate r1, 9 + 135: BitXor r0, r0, r1, ic8 + 140: SetNamedProperty a0, c0, r0 + 144: GetNamedProperty r0, a0, c0 + 148: LoadImmediate r1, 10 + 151: ShiftLeft r0, r0, r1, ic9 + 156: SetNamedProperty a0, c0, r0 + 160: GetNamedProperty r0, a0, c0 + 164: LoadImmediate r1, 11 + 167: ShiftRightArithmetic r0, r0, r1, ic10 + 172: SetNamedProperty a0, c0, r0 + 176: GetNamedProperty r0, a0, c0 + 180: LoadImmediate r1, 12 + 183: ShiftRightLogical r0, r0, r1, ic11 + 188: SetNamedProperty a0, c0, r0 + 192: LoadUndefined r0 + 194: Ret r0 Constant Table: 0: [String: foo] } diff --git a/tests/js_bytecode/expression/binary.exp b/tests/js_bytecode/expression/binary.exp index e1783b9c..8faca09d 100644 --- a/tests/js_bytecode/expression/binary.exp +++ b/tests/js_bytecode/expression/binary.exp @@ -15,31 +15,31 @@ [BytecodeFunction: test1] { Parameters: 2, Registers: 1 - 0: Add r0, a0, a1, ic0 - 5: Sub r0, a0, a1, ic1 - 10: Mul r0, a0, a1 - 14: Div r0, a0, a1 - 18: Rem r0, a0, a1 - 22: Exp r0, a0, a1 - 26: LooseEqual r0, a0, a1 - 30: LooseNotEqual r0, a0, a1 - 34: StrictEqual r0, a0, a1 - 38: StrictNotEqual r0, a0, a1 - 42: LessThan r0, a0, a1 - 46: LessThanOrEqual r0, a0, a1 - 50: GreaterThan r0, a0, a1 - 54: GreaterThanOrEqual r0, a0, a1 - 58: BitAnd r0, a0, a1 - 62: BitOr r0, a0, a1 - 66: BitXor r0, a0, a1 - 70: ShiftLeft r0, a0, a1 - 74: ShiftRightArithmetic r0, a0, a1 - 78: ShiftRightLogical r0, a0, a1 - 82: LoadConstant r0, c0 - 85: In r0, a1, r0 - 89: InstanceOf r0, a0, a1 - 93: LoadUndefined r0 - 95: Ret r0 + 0: Add r0, a0, a1, ic0 + 5: Sub r0, a0, a1, ic1 + 10: Mul r0, a0, a1, ic2 + 15: Div r0, a0, a1, ic3 + 20: Rem r0, a0, a1, ic4 + 25: Exp r0, a0, a1, ic5 + 30: LooseEqual r0, a0, a1 + 34: LooseNotEqual r0, a0, a1 + 38: StrictEqual r0, a0, a1 + 42: StrictNotEqual r0, a0, a1 + 46: LessThan r0, a0, a1 + 50: LessThanOrEqual r0, a0, a1 + 54: GreaterThan r0, a0, a1 + 58: GreaterThanOrEqual r0, a0, a1 + 62: BitAnd r0, a0, a1, ic6 + 67: BitOr r0, a0, a1, ic7 + 72: BitXor r0, a0, a1, ic8 + 77: ShiftLeft r0, a0, a1, ic9 + 82: ShiftRightArithmetic r0, a0, a1, ic10 + 87: ShiftRightLogical r0, a0, a1, ic11 + 92: LoadConstant r0, c0 + 95: In r0, a1, r0 + 99: InstanceOf r0, a0, a1 + 103: LoadUndefined r0 + 105: Ret r0 Constant Table: 0: [String: x] } diff --git a/tests/js_bytecode/expression/logical.exp b/tests/js_bytecode/expression/logical.exp index 0417946f..eaeaf031 100644 --- a/tests/js_bytecode/expression/logical.exp +++ b/tests/js_bytecode/expression/logical.exp @@ -126,15 +126,15 @@ 33: LoadImmediate r1, 6 .L2: 36: LoadImmediate r2, 10 - 39: Mul r1, r1, r2 - 43: LoadGlobal r1, c0 - 46: LoadImmediate r2, 7 - 49: JumpToBooleanFalse r2, 6 (.L3) - 52: LoadImmediate r2, 8 + 39: Mul r1, r1, r2, ic0 + 44: LoadGlobal r1, c0 + 47: LoadImmediate r2, 7 + 50: JumpToBooleanFalse r2, 6 (.L3) + 53: LoadImmediate r2, 8 .L3: - 55: Call r1, r1, r2, 1 - 60: LoadUndefined r1 - 62: Ret r1 + 56: Call r1, r1, r2, 1 + 61: LoadUndefined r1 + 63: Ret r1 Constant Table: 0: [String: use] } @@ -157,15 +157,15 @@ 33: LoadImmediate r1, 6 .L2: 36: LoadImmediate r2, 10 - 39: Mul r1, r1, r2 - 43: LoadGlobal r1, c0 - 46: LoadImmediate r2, 7 - 49: JumpToBooleanTrue r2, 6 (.L3) - 52: LoadImmediate r2, 8 + 39: Mul r1, r1, r2, ic0 + 44: LoadGlobal r1, c0 + 47: LoadImmediate r2, 7 + 50: JumpToBooleanTrue r2, 6 (.L3) + 53: LoadImmediate r2, 8 .L3: - 55: Call r1, r1, r2, 1 - 60: LoadUndefined r1 - 62: Ret r1 + 56: Call r1, r1, r2, 1 + 61: LoadUndefined r1 + 63: Ret r1 Constant Table: 0: [String: use] } @@ -188,15 +188,15 @@ 33: LoadImmediate r1, 6 .L2: 36: LoadImmediate r2, 10 - 39: Mul r1, r1, r2 - 43: LoadGlobal r1, c0 - 46: LoadImmediate r2, 7 - 49: JumpNotNullish r2, 6 (.L3) - 52: LoadImmediate r2, 8 + 39: Mul r1, r1, r2, ic0 + 44: LoadGlobal r1, c0 + 47: LoadImmediate r2, 7 + 50: JumpNotNullish r2, 6 (.L3) + 53: LoadImmediate r2, 8 .L3: - 55: Call r1, r1, r2, 1 - 60: LoadUndefined r1 - 62: Ret r1 + 56: Call r1, r1, r2, 1 + 61: LoadUndefined r1 + 63: Ret r1 Constant Table: 0: [String: use] }