From 520bb7d75e08d7ca50054212cf62dd03172dea6d Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Mon, 20 Apr 2026 15:10:55 +0800 Subject: [PATCH] optimize: remove {StepResult,TailResult}::ForceThunk --- .gitignore | 2 +- fix-vm/src/dispatch_tailcall.rs | 38 +++----- fix-vm/src/instructions/arithmetic.rs | 72 +++++++------- fix-vm/src/instructions/builtins_misc.rs | 14 +-- fix-vm/src/instructions/calls.rs | 8 +- fix-vm/src/instructions/closures.rs | 6 +- fix-vm/src/instructions/collections.rs | 22 ++--- fix-vm/src/instructions/control.rs | 12 +-- fix-vm/src/instructions/literals.rs | 14 +-- fix-vm/src/instructions/variables.rs | 8 +- fix-vm/src/instructions/with_scope.rs | 10 +- fix-vm/src/lib.rs | 114 ++++++++--------------- 12 files changed, 132 insertions(+), 188 deletions(-) diff --git a/.gitignore b/.gitignore index f65d8f6..9c02aff 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,4 @@ prof.json *.cpuprofile *.cpuprofile.gz *v8.log* -callgrind.out.* +callgrind.* diff --git a/fix-vm/src/dispatch_tailcall.rs b/fix-vm/src/dispatch_tailcall.rs index 0ed564c..7a16f6c 100644 --- a/fix-vm/src/dispatch_tailcall.rs +++ b/fix-vm/src/dispatch_tailcall.rs @@ -2,11 +2,10 @@ use gc_arena::Mutation; -use crate::{BytecodeReader, ForceInfo, StepResult, Vm, VmContext}; +use crate::{BytecodeReader, StepResult, Vm, VmContext}; -pub(crate) enum TailResult<'gc> { +pub(crate) enum TailResult { YieldFuel(u32), - ForceThunk(ForceInfo<'gc>), Done, } @@ -18,7 +17,7 @@ pub(crate) type OpFn<'gc, C> = extern "rust-preserve-none" fn( &DispatchTable<'gc, C>, u32, u32, -) -> TailResult<'gc>; +) -> TailResult; pub(crate) struct DispatchTable<'gc, C: VmContext>(pub(crate) [OpFn<'gc, C>; 256]); @@ -30,7 +29,7 @@ extern "rust-preserve-none" fn op_illegal<'gc, C: VmContext>( _table: &DispatchTable<'gc, C>, pc: u32, _fuel: u32, -) -> TailResult<'gc> { +) -> TailResult { panic!("illegal opcode at pc = {pc}"); } @@ -38,7 +37,6 @@ macro_rules! tail_dispatch_after { ($result:expr, $new_pc:expr, $vm:ident, $mc:ident, $ctx:ident, $bc:ident, $table:ident, $fuel:ident) => {{ match $result { StepResult::Continue => {} - StepResult::ForceThunk(info) => return TailResult::ForceThunk(info), StepResult::Done => return TailResult::Done, } let new_pc: u32 = $new_pc; @@ -60,7 +58,7 @@ macro_rules! tail_fn { table: &DispatchTable<'gc, C>, pc: u32, fuel: u32, - ) -> TailResult<'gc> { + ) -> TailResult { let result = vm.$name(); tail_dispatch_after!(result, pc + 1, vm, mc, ctx, bc, table, fuel) } @@ -74,7 +72,7 @@ macro_rules! tail_fn { table: &DispatchTable<'gc, C>, pc: u32, fuel: u32, - ) -> TailResult<'gc> { + ) -> TailResult { let mut reader = BytecodeReader::from_after_op(bc, pc as usize); let result = vm.$name(&mut reader); tail_dispatch_after!(result, reader.pc() as u32, vm, mc, ctx, bc, table, fuel) @@ -89,7 +87,7 @@ macro_rules! tail_fn { table: &DispatchTable<'gc, C>, pc: u32, fuel: u32, - ) -> TailResult<'gc> { + ) -> TailResult { let mut reader = BytecodeReader::from_after_op(bc, pc as usize); let result = vm.$name(&mut reader, mc); tail_dispatch_after!(result, reader.pc() as u32, vm, mc, ctx, bc, table, fuel) @@ -104,26 +102,12 @@ macro_rules! tail_fn { table: &DispatchTable<'gc, C>, pc: u32, fuel: u32, - ) -> TailResult<'gc> { + ) -> TailResult { let mut reader = BytecodeReader::from_after_op(bc, pc as usize); let result = vm.$name(ctx, &mut reader, mc); tail_dispatch_after!(result, reader.pc() as u32, vm, mc, ctx, bc, table, fuel) } }; - ($name:ident, (mc, inst_start_pc)) => { - extern "rust-preserve-none" fn $name<'gc, C: VmContext>( - vm: &mut Vm<'gc>, - mc: &Mutation<'gc>, - ctx: &mut C, - bc: &[u8], - table: &DispatchTable<'gc, C>, - pc: u32, - fuel: u32, - ) -> TailResult<'gc> { - let result = vm.$name(mc, pc as usize); - tail_dispatch_after!(result, pc + 1, vm, mc, ctx, bc, table, fuel) - } - }; ($name:ident, (ctx)) => { extern "rust-preserve-none" fn $name<'gc, C: VmContext>( vm: &mut Vm<'gc>, @@ -133,7 +117,7 @@ macro_rules! tail_fn { table: &DispatchTable<'gc, C>, pc: u32, fuel: u32, - ) -> TailResult<'gc> { + ) -> TailResult { let result = vm.$name(ctx); tail_dispatch_after!(result, pc + 1, vm, mc, ctx, bc, table, fuel) } @@ -181,7 +165,7 @@ tail_fn!(op_gt, (ctx, reader, mc)); tail_fn!(op_leq, (ctx, reader, mc)); tail_fn!(op_geq, (ctx, reader, mc)); tail_fn!(op_concat, (reader, mc)); -tail_fn!(op_update, (mc, inst_start_pc)); +tail_fn!(op_update, (reader, mc)); tail_fn!(op_neg, ()); tail_fn!(op_not, ()); @@ -303,7 +287,7 @@ pub(crate) fn run_tailcall<'gc, C: VmContext>( ctx: &mut C, bc: &[u8], pc: u32, -) -> TailResult<'gc> { +) -> TailResult { const FUEL: u32 = 1024; let table = &DispatchTable::<'gc, C>::NEW; let op = bc[pc as usize] as usize; diff --git a/fix-vm/src/instructions/arithmetic.rs b/fix-vm/src/instructions/arithmetic.rs index 6bff782..cb46b16 100644 --- a/fix-vm/src/instructions/arithmetic.rs +++ b/fix-vm/src/instructions/arithmetic.rs @@ -11,11 +11,11 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { - if let Some(step) = self.try_force_resolved(1, reader.inst_start_pc(), mc) { + ) -> StepResult { + if let Some(step) = self.try_force(1, reader, mc) { return step; } - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } let rhs = self.pop_stack_forced(); @@ -43,8 +43,8 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { - self.op_arith(mc, i64::wrapping_sub, |a, b| a - b, reader.inst_start_pc()) + ) -> StepResult { + self.op_arith(reader, mc, i64::wrapping_sub, |a, b| a - b) } #[inline(always)] @@ -52,22 +52,22 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { - self.op_arith(mc, i64::wrapping_mul, |a, b| a * b, reader.inst_start_pc()) + ) -> StepResult { + self.op_arith(reader, mc, i64::wrapping_mul, |a, b| a * b) } #[inline(always)] fn op_arith( &mut self, + reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, int_op: fn(i64, i64) -> i64, float_op: fn(f64, f64) -> f64, - inst_start_pc: usize, - ) -> StepResult<'gc> { - if let Some(step) = self.try_force_resolved(1, inst_start_pc, mc) { + ) -> StepResult { + if let Some(step) = self.try_force(1, reader, mc) { return step; } - if let Some(step) = self.try_force_resolved(0, inst_start_pc, mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } let rhs = self.pop_stack_forced(); @@ -87,11 +87,11 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { - if let Some(step) = self.try_force_resolved(1, reader.inst_start_pc(), mc) { + ) -> StepResult { + if let Some(step) = self.try_force(1, reader, mc) { return step; } - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } let rhs = self.pop_stack_forced(); @@ -120,11 +120,11 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { - if let Some(step) = self.try_force_resolved(1, reader.inst_start_pc(), mc) { + ) -> StepResult { + if let Some(step) = self.try_force(1, reader, mc) { return step; } - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } let eq = match self.values_equal(ctx) { @@ -141,11 +141,11 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { - if let Some(step) = self.try_force_resolved(1, reader.inst_start_pc(), mc) { + ) -> StepResult { + if let Some(step) = self.try_force(1, reader, mc) { return step; } - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } let eq = match self.values_equal(ctx) { @@ -162,7 +162,7 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { self.compare_values(ctx, reader, mc, Ordering::is_lt) } @@ -172,7 +172,7 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { self.compare_values(ctx, reader, mc, Ordering::is_gt) } @@ -182,7 +182,7 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { self.compare_values(ctx, reader, mc, Ordering::is_le) } @@ -192,7 +192,7 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { self.compare_values(ctx, reader, mc, Ordering::is_ge) } @@ -202,11 +202,11 @@ impl<'gc> crate::Vm<'gc> { reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, pred: fn(Ordering) -> bool, - ) -> StepResult<'gc> { - if let Some(step) = self.try_force_resolved(1, reader.inst_start_pc(), mc) { + ) -> StepResult { + if let Some(step) = self.try_force(1, reader, mc) { return step; } - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } match self.compare_values_inner(ctx, pred) { @@ -220,11 +220,11 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { - if let Some(step) = self.try_force_resolved(1, reader.inst_start_pc(), mc) { + ) -> StepResult { + if let Some(step) = self.try_force(1, reader, mc) { return step; } - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } let rhs = self.pop_stack_forced(); @@ -249,13 +249,13 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_update( &mut self, + reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - inst_start_pc: usize, - ) -> StepResult<'gc> { - if let Some(step) = self.try_force_resolved(1, inst_start_pc, mc) { + ) -> StepResult { + if let Some(step) = self.try_force(1, reader, mc) { return step; } - if let Some(step) = self.try_force_resolved(0, inst_start_pc, mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } let rhs = self.pop_stack_forced(); @@ -275,12 +275,12 @@ impl<'gc> crate::Vm<'gc> { } #[inline(always)] - pub(crate) fn op_neg(&mut self) -> StepResult<'gc> { + pub(crate) fn op_neg(&mut self) -> StepResult { todo!("implement unary operation"); } #[inline(always)] - pub(crate) fn op_not(&mut self) -> StepResult<'gc> { + pub(crate) fn op_not(&mut self) -> StepResult { todo!("implement unary operation"); } diff --git a/fix-vm/src/instructions/builtins_misc.rs b/fix-vm/src/instructions/builtins_misc.rs index ffdea44..2ee8275 100644 --- a/fix-vm/src/instructions/builtins_misc.rs +++ b/fix-vm/src/instructions/builtins_misc.rs @@ -5,13 +5,13 @@ use crate::{BytecodeReader, PrimOp, StepResult, Value}; impl<'gc> crate::Vm<'gc> { #[inline(always)] - pub(crate) fn op_load_builtins(&mut self) -> StepResult<'gc> { + pub(crate) fn op_load_builtins(&mut self) -> StepResult { self.push_stack(self.builtins); StepResult::Continue } #[inline(always)] - pub(crate) fn op_load_builtin(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult<'gc> { + pub(crate) fn op_load_builtin(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { let Ok(id) = BuiltinId::try_from_primitive(reader.read_u8()) .map_err(|err| panic!("unknown builtin id: {}", err.number)); self.push_stack(Value::new_inline(PrimOp { @@ -22,7 +22,7 @@ impl<'gc> crate::Vm<'gc> { } #[inline(always)] - pub(crate) fn op_mk_pos(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult<'gc> { + pub(crate) fn op_mk_pos(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { let _span_id = reader.read_u32(); todo!("MkPos"); } @@ -31,7 +31,7 @@ impl<'gc> crate::Vm<'gc> { pub(crate) fn op_load_repl_binding( &mut self, reader: &mut BytecodeReader<'_>, - ) -> StepResult<'gc> { + ) -> StepResult { let _name = reader.read_string_id(); todo!("LoadReplBinding"); } @@ -40,7 +40,7 @@ impl<'gc> crate::Vm<'gc> { pub(crate) fn op_load_scoped_binding( &mut self, reader: &mut BytecodeReader<'_>, - ) -> StepResult<'gc> { + ) -> StepResult { let _name = reader.read_string_id(); todo!("LoadScopedBinding"); } @@ -51,7 +51,7 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, _mc: &gc_arena::Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let _parts_count = reader.read_u16() as usize; let _force_string = reader.read_u8() != 0; let mut _operands: smallvec::SmallVec<[crate::OperandData; 4]> = @@ -63,7 +63,7 @@ impl<'gc> crate::Vm<'gc> { } #[inline(always)] - pub(crate) fn op_resolve_path(&mut self, _ctx: &mut impl crate::VmContext) -> StepResult<'gc> { + pub(crate) fn op_resolve_path(&mut self, _ctx: &mut impl crate::VmContext) -> StepResult { todo!("implement ResolvePath"); } } diff --git a/fix-vm/src/instructions/calls.rs b/fix-vm/src/instructions/calls.rs index f308304..c13c448 100644 --- a/fix-vm/src/instructions/calls.rs +++ b/fix-vm/src/instructions/calls.rs @@ -10,8 +10,8 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + ) -> StepResult { + if let Some(step) = self.try_force(0, reader, mc) { return step; } if self.call_depth > 10000 { @@ -50,7 +50,7 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { self.handle_return(reader, ctx, mc) } @@ -59,7 +59,7 @@ impl<'gc> crate::Vm<'gc> { reader: &mut BytecodeReader<'_>, ctx: &C, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let ret_inst_pc = reader.pc() - 1; let Some(CallFrame { pc: ret_pc, diff --git a/fix-vm/src/instructions/closures.rs b/fix-vm/src/instructions/closures.rs index b07da19..78e7412 100644 --- a/fix-vm/src/instructions/closures.rs +++ b/fix-vm/src/instructions/closures.rs @@ -8,7 +8,7 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let entry_point = reader.read_u32(); let thunk = Gc::new( mc, @@ -27,7 +27,7 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let entry_point = reader.read_u32(); let n_locals = reader.read_u32(); let closure = Gc::new( @@ -48,7 +48,7 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let entry_point = reader.read_u32(); let n_locals = reader.read_u32(); let req_count = reader.read_u16() as usize; diff --git a/fix-vm/src/instructions/collections.rs b/fix-vm/src/instructions/collections.rs index b64bb51..3402c33 100644 --- a/fix-vm/src/instructions/collections.rs +++ b/fix-vm/src/instructions/collections.rs @@ -13,7 +13,7 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let count = reader.read_u32() as usize; let mut entries: SmallVec<[AttrEntry; 4]> = SmallVec::with_capacity(count); for _ in 0..count { @@ -42,7 +42,7 @@ impl<'gc> crate::Vm<'gc> { } #[inline(always)] - pub(crate) fn op_make_empty_attrs(&mut self) -> StepResult<'gc> { + pub(crate) fn op_make_empty_attrs(&mut self) -> StepResult { self.push_stack(self.empty_attrs); StepResult::Continue } @@ -53,11 +53,11 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let _span_id = reader.read_u32(); let key = reader.read_string_id(); - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } @@ -98,13 +98,13 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let _span_id = reader.read_u32(); - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } - if let Some(step) = self.try_force_resolved(1, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(1, reader, mc) { return step; } @@ -143,14 +143,14 @@ impl<'gc> crate::Vm<'gc> { pub(crate) fn op_jump_if_select_succeeded( &mut self, reader: &mut BytecodeReader<'_>, - ) -> StepResult<'gc> { + ) -> StepResult { let offset = reader.read_i32(); reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize); StepResult::Continue } #[inline(always)] - pub(crate) fn op_has_attr(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult<'gc> { + pub(crate) fn op_has_attr(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { let _n = reader.read_u16() as usize; todo!("HasAttr"); } @@ -161,7 +161,7 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let count = reader.read_u32() as usize; let mut items: SmallVec<[Value; 4]> = SmallVec::with_capacity(count); for _ in 0..count { @@ -173,7 +173,7 @@ impl<'gc> crate::Vm<'gc> { } #[inline(always)] - pub(crate) fn op_make_empty_list(&mut self) -> StepResult<'gc> { + pub(crate) fn op_make_empty_list(&mut self) -> StepResult { self.push_stack(self.empty_list); StepResult::Continue } diff --git a/fix-vm/src/instructions/control.rs b/fix-vm/src/instructions/control.rs index 387e78d..82600c3 100644 --- a/fix-vm/src/instructions/control.rs +++ b/fix-vm/src/instructions/control.rs @@ -6,9 +6,9 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let offset = reader.read_i32(); - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } let cond = self.pop_stack(); @@ -23,9 +23,9 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let offset = reader.read_i32(); - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } let cond = self.pop_stack(); @@ -36,14 +36,14 @@ impl<'gc> crate::Vm<'gc> { } #[inline(always)] - pub(crate) fn op_jump(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult<'gc> { + pub(crate) fn op_jump(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { let offset = reader.read_i32(); reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize); StepResult::Continue } #[inline(always)] - pub(crate) fn op_assert(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult<'gc> { + pub(crate) fn op_assert(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { let _raw_idx = reader.read_u32(); let _span_id = reader.read_u32(); todo!("implement Assert (force TOS)"); diff --git a/fix-vm/src/instructions/literals.rs b/fix-vm/src/instructions/literals.rs index 019f234..1d6f23f 100644 --- a/fix-vm/src/instructions/literals.rs +++ b/fix-vm/src/instructions/literals.rs @@ -4,7 +4,7 @@ use crate::{BytecodeReader, StepResult, Value}; impl<'gc> crate::Vm<'gc> { #[inline(always)] - pub(crate) fn op_push_smi(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult<'gc> { + pub(crate) fn op_push_smi(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { let val = reader.read_i32(); self.push_stack(Value::new_inline(val)); StepResult::Continue @@ -15,40 +15,40 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let val = reader.read_i64(); self.push_stack(Value::new_gc(Gc::new(mc, val))); StepResult::Continue } #[inline(always)] - pub(crate) fn op_push_float(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult<'gc> { + pub(crate) fn op_push_float(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { let val = reader.read_f64(); self.push_stack(Value::new_float(val)); StepResult::Continue } #[inline(always)] - pub(crate) fn op_push_string(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult<'gc> { + pub(crate) fn op_push_string(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { let sid = reader.read_string_id(); self.push_stack(Value::new_inline(sid)); StepResult::Continue } #[inline(always)] - pub(crate) fn op_push_null(&mut self) -> StepResult<'gc> { + pub(crate) fn op_push_null(&mut self) -> StepResult { self.push_stack(Value::new_inline(crate::Null)); StepResult::Continue } #[inline(always)] - pub(crate) fn op_push_true(&mut self) -> StepResult<'gc> { + pub(crate) fn op_push_true(&mut self) -> StepResult { self.push_stack(Value::new_inline(true)); StepResult::Continue } #[inline(always)] - pub(crate) fn op_push_false(&mut self) -> StepResult<'gc> { + pub(crate) fn op_push_false(&mut self) -> StepResult { self.push_stack(Value::new_inline(false)); StepResult::Continue } diff --git a/fix-vm/src/instructions/variables.rs b/fix-vm/src/instructions/variables.rs index 9ebfdb9..20ed49d 100644 --- a/fix-vm/src/instructions/variables.rs +++ b/fix-vm/src/instructions/variables.rs @@ -2,14 +2,14 @@ use crate::{BytecodeReader, Mutation, StepResult, Value}; impl<'gc> crate::Vm<'gc> { #[inline(always)] - pub(crate) fn op_load_local(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult<'gc> { + pub(crate) fn op_load_local(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { let idx = reader.read_u32() as usize; self.push_stack(self.env.borrow().locals[idx]); StepResult::Continue } #[inline(always)] - pub(crate) fn op_load_outer(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult<'gc> { + pub(crate) fn op_load_outer(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { let layer = reader.read_u8(); let idx = reader.read_u32() as usize; let mut cur = self.env; @@ -27,7 +27,7 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let idx = reader.read_u32() as usize; let val = self.pop_stack(); self.env.borrow_mut(mc).locals[idx] = val; @@ -39,7 +39,7 @@ impl<'gc> crate::Vm<'gc> { &mut self, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let count = reader.read_u32() as usize; self.env .borrow_mut(mc) diff --git a/fix-vm/src/instructions/with_scope.rs b/fix-vm/src/instructions/with_scope.rs index 685b781..05a5032 100644 --- a/fix-vm/src/instructions/with_scope.rs +++ b/fix-vm/src/instructions/with_scope.rs @@ -11,7 +11,7 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let env = reader.read_operand_data(ctx).resolve(mc, self); let scope = Gc::new( mc, @@ -25,7 +25,7 @@ impl<'gc> crate::Vm<'gc> { } #[inline(always)] - pub(crate) fn op_pop_with(&mut self) -> StepResult<'gc> { + pub(crate) fn op_pop_with(&mut self) -> StepResult { let Some(scope) = self.with_env else { unreachable!("no with_scope to pop"); }; @@ -34,7 +34,7 @@ impl<'gc> crate::Vm<'gc> { } #[inline(always)] - pub(crate) fn op_prepare_with(&mut self) -> StepResult<'gc> { + pub(crate) fn op_prepare_with(&mut self) -> StepResult { self.call_stack.push(CallFrame { pc: usize::MAX, stack_depth: 0, @@ -51,7 +51,7 @@ impl<'gc> crate::Vm<'gc> { ctx: &mut impl crate::VmContext, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> StepResult { let name = reader.read_string_id(); let Some(&WithEnv { env, prev }) = self.with_env.as_deref() else { @@ -65,7 +65,7 @@ impl<'gc> crate::Vm<'gc> { ))); }; self.push_stack(env); - if let Some(step) = self.try_force_resolved(0, reader.inst_start_pc(), mc) { + if let Some(step) = self.try_force(0, reader, mc) { return step; } diff --git a/fix-vm/src/lib.rs b/fix-vm/src/lib.rs index 54c0f0a..4bd4f8a 100644 --- a/fix-vm/src/lib.rs +++ b/fix-vm/src/lib.rs @@ -131,21 +131,12 @@ impl VmContextExt for T { } } -pub(crate) enum StepResult<'gc> { +#[repr(u8)] +pub(crate) enum StepResult { Continue, - ForceThunk(ForceInfo<'gc>), Done, } -pub(crate) struct ForceInfo<'gc> { - pub(crate) thunk: Gc<'gc, Thunk<'gc>>, - pub(crate) stack_depth: usize, - pub(crate) inst_start_pc: usize, - pub(crate) ip: usize, - pub(crate) env: GcEnv<'gc>, - pub(crate) with_env: Option>, -} - #[derive(Collect)] #[collect(no_drop)] pub struct Vm<'gc> { @@ -279,19 +270,19 @@ impl<'gc> Vm<'gc> { } #[inline(always)] - pub(crate) fn finish_ok(&mut self, val: fix_common::Value) -> StepResult<'gc> { + pub(crate) fn finish_ok(&mut self, val: fix_common::Value) -> StepResult { self.result = Some(Ok(val)); StepResult::Done } #[inline(always)] - pub(crate) fn finish_err(&mut self, err: Box) -> StepResult<'gc> { + pub(crate) fn finish_err(&mut self, err: Box) -> StepResult { self.result = Some(Err(err)); StepResult::Done } #[inline(always)] - pub(crate) fn finish_vm_err(&mut self, err: VmError) -> StepResult<'gc> { + pub(crate) fn finish_vm_err(&mut self, err: VmError) -> StepResult { self.finish_err(err.into_error()) } @@ -338,65 +329,42 @@ impl<'gc> Vm<'gc> { pub(crate) fn try_force( &mut self, depth: usize, - inst_start_pc: usize, + reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, - ) -> StepResult<'gc> { + ) -> Option { let val = self.peek_stack(depth); - if let Some(thunk) = val.as_gc::() { - let mut state = thunk.borrow_mut(mc); - match *state { - ThunkState::Pending { ip, env, with_env } => { - *state = ThunkState::Blackhole; - drop(state); - StepResult::ForceThunk(ForceInfo { - thunk, - stack_depth: depth, - inst_start_pc, - ip, - env, - with_env, - }) - } - ThunkState::Evaluated(v) => { - self.replace_stack(depth, v.relax()); - StepResult::Continue - } - ThunkState::Apply { .. } => todo!("force apply"), - ThunkState::Blackhole => { - self.finish_err(Error::eval_error("infinite recursion encountered")) - } + let Some(thunk) = val.as_gc::() else { + return None; + }; + let mut state = thunk.borrow_mut(mc); + match *state { + ThunkState::Pending { ip, env, with_env } => { + *state = ThunkState::Blackhole; + drop(state); + self.call_stack.push(CallFrame { + thunk: Some(thunk), + stack_depth: depth, + pc: reader.inst_start_pc(), + env: self.env, + with_env: self.with_env, + }); + self.env = env; + self.with_env = with_env; + reader.set_pc(ip); + Some(StepResult::Continue) + } + ThunkState::Evaluated(v) => { + drop(state); + self.replace_stack(depth, v.relax()); + None + } + ThunkState::Apply { .. } => todo!("force apply"), + ThunkState::Blackhole => { + drop(state); + Some(self.finish_err(Error::eval_error("infinite recursion encountered"))) } - } else { - StepResult::Continue } } - - #[inline(always)] - pub(crate) fn try_force_resolved( - &mut self, - depth: usize, - inst_start_pc: usize, - mc: &Mutation<'gc>, - ) -> Option> { - match self.try_force(depth, inst_start_pc, mc) { - StepResult::Continue => None, - other => Some(other), - } - } - - #[inline(always)] - pub(crate) fn apply_force_thunk(&mut self, info: ForceInfo<'gc>) -> usize { - self.call_stack.push(CallFrame { - thunk: Some(info.thunk), - stack_depth: info.stack_depth, - pc: info.inst_start_pc, - env: self.env, - with_env: self.with_env, - }); - self.env = info.env; - self.with_env = info.with_env; - info.ip - } } #[allow(dead_code)] @@ -476,10 +444,6 @@ impl<'gc> Vm<'gc> { TailResult::YieldFuel(new_pc) => Action::Continue { pc: new_pc as usize, }, - TailResult::ForceThunk(info) => { - let new_pc = self.apply_force_thunk(info); - Action::Continue { pc: new_pc } - } TailResult::Done => { Action::Done(self.result.take().expect("TailResult::Done without result")) } @@ -552,7 +516,7 @@ impl<'gc> Vm<'gc> { OpLeq => self.op_leq(ctx, &mut reader, mc), OpGeq => self.op_geq(ctx, &mut reader, mc), OpConcat => self.op_concat(&mut reader, mc), - OpUpdate => self.op_update(mc, reader.inst_start_pc()), + OpUpdate => self.op_update(&mut reader, mc), OpNeg => self.op_neg(), OpNot => self.op_not(), @@ -583,10 +547,6 @@ impl<'gc> Vm<'gc> { match result { StepResult::Continue => {} - StepResult::ForceThunk(info) => { - let new_pc = self.apply_force_thunk(info); - reader.set_pc(new_pc); - } StepResult::Done => { return Action::Done( self.result.take().expect("StepResult::Done without result"),