diff --git a/crates/kernel/src/builtins/bf_objects.rs b/crates/kernel/src/builtins/bf_objects.rs index 4e1b3773..9b665147 100644 --- a/crates/kernel/src/builtins/bf_objects.rs +++ b/crates/kernel/src/builtins/bf_objects.rs @@ -30,7 +30,7 @@ use crate::bf_declare; use crate::builtins::BfRet::{Ret, VmInstr}; use crate::builtins::{world_state_bf_err, BfCallState, BfErr, BfRet, BuiltinFunction}; use crate::tasks::VerbCall; -use crate::vm::ExecutionResult::ContinueVerb; +use crate::vm::ExecutionResult::DispatchVerb; lazy_static! { static ref INITIALIZE_SYM: Symbol = Symbol::mk("initialize"); @@ -158,7 +158,7 @@ fn bf_create(bf_args: &mut BfCallState<'_>) -> Result { let bf_frame = bf_args.bf_frame_mut(); bf_frame.bf_trampoline = Some(BF_CREATE_OBJECT_TRAMPOLINE_DONE); bf_frame.bf_trampoline_arg = Some(v_obj(new_obj.clone())); - Ok(VmInstr(ContinueVerb { + Ok(VmInstr(DispatchVerb { permissions: bf_args.task_perms_who(), resolved_verb, binary, @@ -269,7 +269,7 @@ fn bf_recycle(bf_args: &mut BfCallState<'_>) -> Result { bf_frame.bf_trampoline = Some(BF_RECYCLE_TRAMPOLINE_CALL_EXITFUNC); bf_frame.bf_trampoline_arg = Some(contents); - return Ok(VmInstr(ContinueVerb { + return Ok(VmInstr(DispatchVerb { permissions: bf_args.task_perms_who(), resolved_verb, binary, @@ -338,7 +338,7 @@ fn bf_recycle(bf_args: &mut BfCallState<'_>) -> Result { bf_frame.bf_trampoline = Some(BF_RECYCLE_TRAMPOLINE_CALL_EXITFUNC); // Call :exitfunc on the head object. - return Ok(VmInstr(ContinueVerb { + return Ok(VmInstr(DispatchVerb { permissions: bf_args.task_perms_who(), resolved_verb, binary, @@ -440,7 +440,7 @@ fn bf_move(bf_args: &mut BfCallState<'_>) -> Result { let bf_frame = bf_args.bf_frame_mut(); bf_frame.bf_trampoline = Some(BF_MOVE_TRAMPOLINE_MOVE_CALL_EXITFUNC); bf_frame.bf_trampoline_arg = None; - return Ok(VmInstr(ContinueVerb { + return Ok(VmInstr(DispatchVerb { permissions: bf_args.task_perms_who(), resolved_verb, binary, @@ -518,7 +518,7 @@ fn bf_move(bf_args: &mut BfCallState<'_>) -> Result { bf_frame.bf_trampoline = Some(BF_MOVE_TRAMPOLINE_CALL_ENTERFUNC); bf_frame.bf_trampoline_arg = None; - let continuation = ContinueVerb { + let continuation = DispatchVerb { permissions: bf_args.task_perms_who(), resolved_verb, binary, @@ -565,7 +565,7 @@ fn bf_move(bf_args: &mut BfCallState<'_>) -> Result { bf_frame.bf_trampoline = Some(BF_MOVE_TRAMPOLINE_DONE); bf_frame.bf_trampoline_arg = None; - return Ok(VmInstr(ContinueVerb { + return Ok(VmInstr(DispatchVerb { permissions: bf_args.task_perms_who(), resolved_verb, binary, diff --git a/crates/kernel/src/tasks/vm_host.rs b/crates/kernel/src/tasks/vm_host.rs index 2152c3f2..3524936a 100644 --- a/crates/kernel/src/tasks/vm_host.rs +++ b/crates/kernel/src/tasks/vm_host.rs @@ -248,22 +248,47 @@ impl VmHost { // Grant the loop its next tick slice. self.vm_exec_state.tick_slice = self.max_ticks - self.vm_exec_state.tick_count; - let pre_exec_tick_count = self.vm_exec_state.tick_count; - // Actually invoke the VM, asking it to loop until it's ready to yield back to us. let mut result = self.run_interpreter(&exec_params, world_state, session.clone()); - - let post_exec_tick_count = self.vm_exec_state.tick_count; - trace!( - task_id, - executed_ticks = post_exec_tick_count - pre_exec_tick_count, - ?result, - "Executed ticks", - ); while self.is_running() { match result { ExecutionResult::More => return ContinueOk, - ExecutionResult::ContinueVerb { + ExecutionResult::PushError(e) => { + result = self.vm_exec_state.push_error(e); + continue; + } + ExecutionResult::RaiseError(e) => { + result = self.vm_exec_state.raise_error(e); + continue; + } + ExecutionResult::Return(value) => { + result = self + .vm_exec_state + .unwind_stack(FinallyReason::Return(value)); + continue; + } + ExecutionResult::Unwind(fr) => { + result = self.vm_exec_state.unwind_stack(fr); + continue; + } + ExecutionResult::Pass(pass_args) => { + result = self + .vm_exec_state + .prepare_pass_verb(world_state, &pass_args); + continue; + } + ExecutionResult::PrepareVerbDispatch { + this, + verb_name, + args, + } => { + result = self + .vm_exec_state + .verb_dispatch(&exec_params, world_state, this, verb_name, args) + .unwrap_or_else(|e| ExecutionResult::PushError(e)); + continue; + } + ExecutionResult::DispatchVerb { permissions, resolved_verb, binary, @@ -310,7 +335,19 @@ impl VmHost { ); continue; } - ExecutionResult::DispatchFork(fork_request) => { + ExecutionResult::DispatchFork(delay, task_id, fv_offset) => { + let a = self.vm_exec_state.top().clone(); + let parent_task_id = self.vm_exec_state.task_id; + let new_activation = a.clone(); + let fork_request = Fork { + player: a.player.clone(), + progr: a.permissions.clone(), + parent_task_id, + delay, + activation: new_activation, + fork_vector_offset: fv_offset, + task_id, + }; return DispatchFork(fork_request); } ExecutionResult::Suspend(delay) => { @@ -371,23 +408,31 @@ impl VmHost { } // Pick the right kind of execution flow depending on the activation -- builtin or MOO? - // (To avoid borrow issues on the exec state, we won't actually pull the frame out, just look - // at its type and execute the right function which will have to unpack the frame itself. - // this is a bit not-ideal but it's the best I can do right now.) - let result = match &self.vm_exec_state.top().frame { - Frame::Moo(_) => { - return moo_frame_execute( - vm_exec_params, - &mut self.vm_exec_state, + let mut tick_count = self.vm_exec_state.tick_count; + let tick_slice = self.vm_exec_state.tick_slice; + let activation = self.vm_exec_state.top_mut(); + + let (result, new_tick_count) = match &mut activation.frame { + Frame::Moo(fr) => { + let result = moo_frame_execute( + tick_slice, + &mut tick_count, + activation.permissions.clone(), + fr, world_state, - session.clone(), ); + (result, tick_count) } Frame::Bf(_) => { - self.vm_exec_state - .reenter_builtin_function(vm_exec_params, world_state, session) + let result = self.vm_exec_state.reenter_builtin_function( + vm_exec_params, + world_state, + session, + ); + (result, tick_count) } }; + self.vm_exec_state.tick_count = new_tick_count; result } diff --git a/crates/kernel/src/vm/mod.rs b/crates/kernel/src/vm/mod.rs index 4cfb2500..953885d0 100644 --- a/crates/kernel/src/vm/mod.rs +++ b/crates/kernel/src/vm/mod.rs @@ -27,7 +27,7 @@ use moor_compiler::{BuiltinId, Name}; use moor_compiler::{Offset, Program}; use moor_values::matching::command_parse::ParsedCommand; use moor_values::model::VerbDef; -use moor_values::{Obj, Var}; +use moor_values::{Error, List, Obj, Symbol, Var}; pub use vm_call::VerbExecutionRequest; pub use vm_unwind::FinallyReason; @@ -83,12 +83,30 @@ pub struct VmExecParams { pub enum ExecutionResult { /// Execution of this call stack is complete. Complete(Var), + /// An error occurred during execution, that we might need to push to the stack and + /// potentially resume or unwind, depending on the context. + PushError(Error), + /// An error occurred during execution, that should definitely be treated as a proper "raise" + /// and unwind event unless there's a catch handler in place + RaiseError(Error), + /// An explicit stack unwind (for a reason other than a return. + Unwind(FinallyReason), + /// Explicit return, unwind stack + Return(Var), + /// Create the frames necessary to perform a `pass` up the inheritance chain. + Pass(List), /// All is well. The task should let the VM continue executing. More, /// An exception was raised during execution. Exception(FinallyReason), - /// Request dispatch to another verb - ContinueVerb { + /// Begin preparing to call a verb, by looking up the verb and preparing the dispatch. + PrepareVerbDispatch { + this: Var, + verb_name: Symbol, + args: List, + }, + /// Perform the verb dispatch, building the stack frame and executing it. + DispatchVerb { /// The applicable permissions context. permissions: Obj, /// The requested verb. @@ -101,7 +119,7 @@ pub enum ExecutionResult { command: Option, }, /// Request dispatch of a new task as a fork - DispatchFork(Fork), + DispatchFork(Option, Option, Offset), /// Request dispatch of a builtin function with the given arguments. ContinueBuiltin { builtin: BuiltinId, diff --git a/crates/kernel/src/vm/moo_execute.rs b/crates/kernel/src/vm/moo_execute.rs index 64b41201..9d5167c7 100644 --- a/crates/kernel/src/vm/moo_execute.rs +++ b/crates/kernel/src/vm/moo_execute.rs @@ -12,16 +12,13 @@ // this program. If not, see . // -use crate::tasks::sessions::Session; -use crate::vm::activation::Frame; -use crate::vm::moo_frame::{CatchType, ScopeType}; +use crate::vm::moo_frame::{CatchType, MooStackFrame, ScopeType}; use crate::vm::vm_unwind::FinallyReason; -use crate::vm::{ExecutionResult, Fork, VMExecState, VmExecParams}; +use crate::vm::ExecutionResult; use lazy_static::lazy_static; -use moor_compiler::{to_literal, Op, ScatterLabel}; +use moor_compiler::{Op, ScatterLabel}; use moor_values::model::WorldState; use std::ops::Add; -use std::sync::Arc; use std::time::Duration; use moor_values::Error::{E_ARGS, E_DIV, E_INVARG, E_INVIND, E_TYPE, E_VARNF}; @@ -54,7 +51,7 @@ macro_rules! binary_var_op { Ok(result) => $f.poke(0, result), Err(err_code) => { $f.pop(); - return $state.push_error(err_code); + return ExecutionResult::PushError(err_code); } } }; @@ -62,22 +59,14 @@ macro_rules! binary_var_op { /// Main VM opcode execution for MOO stack frames. The actual meat of the MOO virtual machine. pub fn moo_frame_execute( - exec_params: &VmExecParams, - state: &mut VMExecState, + tick_slice: usize, + tick_count: &mut usize, + permissions: Obj, + f: &mut MooStackFrame, world_state: &mut dyn WorldState, - session: Arc, ) -> ExecutionResult { - let opcodes = { - // Check the frame type to verify it's MOO, before doing anything else - let a = state.top_mut(); - let Frame::Moo(ref mut f) = a.frame else { - panic!("Unsupported VM stack frame type"); - }; - - // We clone the main vector here to avoid borrowing issues with the frame later, as we - // need to modify the program counter. - f.program.main_vector.clone() - }; + // To avoid borrowing issues when mutating the frame elsewhere... + let opcodes = f.program.main_vector.clone(); // Special case for empty opcodes set, just return v_none() immediately. if opcodes.is_empty() { @@ -95,15 +84,9 @@ pub fn moo_frame_execute( // and the variable `tick_slice_count` that slice's progress. // `max_ticks` on the task is the total limit which is checked above us, outside this loop. let mut tick_slice_count = 0; - while tick_slice_count < state.tick_slice { + while tick_slice_count < tick_slice { tick_slice_count += 1; - state.tick_count += 1; - - // Borrow the top of the activation stack for the lifetime of this execution. - let a = state.top_mut(); - let Frame::Moo(ref mut f) = a.frame else { - panic!("Unsupported VM stack frame type"); - }; + *tick_count += 1; // Otherwise, start poppin' opcodes. // We panic here if we run out of opcodes, as that means there's a bug in either the @@ -169,7 +152,7 @@ pub fn moo_frame_execute( // didn't 'throw' and unwind the stack -- we need to get out of the loop. // So we preemptively jump (here and below for List) and then raise the error. f.jump(end_label); - return state.raise_error(E_TYPE); + return ExecutionResult::RaiseError(E_TYPE); }; let count = *count as usize; let Variant::List(l) = list.variant() else { @@ -177,7 +160,7 @@ pub fn moo_frame_execute( f.pop(); f.jump(end_label); - return state.raise_error(E_TYPE); + return ExecutionResult::RaiseError(E_TYPE); }; // If we've exhausted the list, pop the count and list and jump out. @@ -239,7 +222,7 @@ pub fn moo_frame_execute( // the loop (with a messed up stack) otherwise. f.jump(end_label); - return state.raise_error(E_TYPE); + return ExecutionResult::RaiseError(E_TYPE); } }; (from.clone(), next_val) @@ -292,7 +275,7 @@ pub fn moo_frame_execute( let (tail, list) = (f.pop(), f.peek_top_mut()); if !list.is_sequence() || list.type_code() == VarType::TYPE_STR { f.pop(); - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); } // TODO: quota check SVO_MAX_LIST_CONCAT -> E_QUOTA in list add and append let result = list.push(&tail); @@ -302,7 +285,7 @@ pub fn moo_frame_execute( } Err(e) => { f.pop(); - return state.push_error(e); + return ExecutionResult::PushError(e); } } } @@ -312,12 +295,12 @@ pub fn moo_frame_execute( // Don't allow strings here. if list.type_code() == VarType::TYPE_STR { f.pop(); - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); } if !tail.is_sequence() || !list.is_sequence() { f.pop(); - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); } let new_list = list.append(&tail); match new_list { @@ -326,7 +309,7 @@ pub fn moo_frame_execute( } Err(e) => { f.pop(); - return state.push_error(e); + return ExecutionResult::PushError(e); } } } @@ -339,7 +322,7 @@ pub fn moo_frame_execute( } Err(e) => { f.pop(); - return state.push_error(e); + return ExecutionResult::PushError(e); } } } @@ -359,7 +342,7 @@ pub fn moo_frame_execute( } Err(e) => { f.pop(); - return state.push_error(e); + return ExecutionResult::PushError(e); } } } @@ -368,20 +351,20 @@ pub fn moo_frame_execute( let contents = f.pop(); // Contents must be a list let Variant::List(contents) = contents.variant() else { - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); }; let mut slots = Vec::with_capacity(*num_slots); for _ in 0..*num_slots { let (k, v) = (f.pop(), f.pop()); let Variant::Str(k) = k.variant() else { - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); }; let sym = Symbol::mk_case_insensitive(k.as_string()); slots.push((sym, v)); } let delegate = f.pop(); let Variant::Obj(delegate) = delegate.variant() else { - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); }; // Slots should be v_str -> value, num_slots times @@ -423,7 +406,7 @@ pub fn moo_frame_execute( } Err(e) => { f.pop(); - return state.push_error(e); + return ExecutionResult::PushError(e); } } } @@ -439,7 +422,7 @@ pub fn moo_frame_execute( // `inf`. let divargs = f.peek_range(2); if matches!(divargs[1].variant(), Variant::Int(0) | Variant::Float(0.0)) { - return state.push_error(E_DIV); + return ExecutionResult::PushError(E_DIV); }; binary_var_op!(self, f, state, div); } @@ -452,7 +435,7 @@ pub fn moo_frame_execute( Op::Mod => { let divargs = f.peek_range(2); if matches!(divargs[1].variant(), Variant::Int(0) | Variant::Float(0.0)) { - return state.push_error(E_DIV); + return ExecutionResult::PushError(E_DIV); }; binary_var_op!(self, f, state, modulus); } @@ -481,14 +464,14 @@ pub fn moo_frame_execute( match v.negative() { Err(e) => { f.pop(); - return state.push_error(e); + return ExecutionResult::PushError(e); } Ok(v) => f.poke(0, v), } } Op::Push(ident) => { let Some(v) = f.get_env(ident) else { - return state.push_error(E_VARNF); + return ExecutionResult::PushError(E_VARNF); }; f.push(v.clone()); } @@ -503,7 +486,7 @@ pub fn moo_frame_execute( Ok(v) => f.push(v), Err(e) => { f.pop(); - return state.push_error(e); + return ExecutionResult::PushError(e); } } } @@ -515,7 +498,7 @@ pub fn moo_frame_execute( Ok(v) => f.poke(0, v), Err(e) => { f.pop(); - return state.push_error(e); + return ExecutionResult::PushError(e); } } } @@ -524,7 +507,7 @@ pub fn moo_frame_execute( let result = base.range(&from, &to, IndexMode::OneBased); if let Err(e) = result { f.pop(); - return state.push_error(e); + return ExecutionResult::PushError(e); } f.poke(0, result.unwrap()); } @@ -533,7 +516,7 @@ pub fn moo_frame_execute( let result = base.range_set(&from, &to, &value, IndexMode::OneBased); if let Err(e) = result { f.pop(); - return state.push_error(e); + return ExecutionResult::PushError(e); } f.poke(0, result.unwrap()); } @@ -541,23 +524,23 @@ pub fn moo_frame_execute( let v = f.peek_abs(offset.0 as usize); match v.len() { Ok(l) => f.push(v_int(l as i64)), - Err(e) => return state.push_error(e), + Err(e) => return ExecutionResult::PushError(e), } } Op::GetProp => { let (propname, obj) = (f.pop(), f.peek_top()); let Variant::Str(propname) = propname.variant() else { - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); }; - let value = get_property(world_state, &a.permissions, obj, propname); + let value = get_property(world_state, &permissions, obj, propname); match value { Ok(v) => { f.poke(0, v); } Err(e) => { - return state.push_error(e); + return ExecutionResult::PushError(e); } } } @@ -565,16 +548,16 @@ pub fn moo_frame_execute( let (propname, obj) = f.peek2(); let Variant::Str(propname) = propname.variant() else { - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); }; - let value = get_property(world_state, &a.permissions, obj, propname); + let value = get_property(world_state, &permissions, obj, propname); match value { Ok(v) => { f.push(v); } Err(e) => { - return state.push_error(e); + return ExecutionResult::PushError(e); } } } @@ -584,20 +567,20 @@ pub fn moo_frame_execute( let (propname, obj) = match (propname.variant(), obj.variant()) { (Variant::Str(propname), Variant::Obj(obj)) => (propname, obj), (_, _) => { - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); } }; let propname = Symbol::mk_case_insensitive(propname.as_string()); let update_result = - world_state.update_property(&a.permissions, obj, propname, &rhs.clone()); + world_state.update_property(&permissions, obj, propname, &rhs.clone()); match update_result { Ok(()) => { f.poke(0, rhs); } Err(e) => { - return state.push_error(e.to_error_code()); + return ExecutionResult::PushError(e.to_error_code()); } } } @@ -609,70 +592,56 @@ pub fn moo_frame_execute( Variant::Int(time) => *time as f64, Variant::Float(time) => *time, _ => { - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); } }; if time < 0.0 { - return state.push_error(E_INVARG); + return ExecutionResult::PushError(E_INVARG); } let delay = (time != 0.0).then(|| Duration::from_secs_f64(time)); - let new_activation = a.clone(); - let fork = Fork { - player: a.player.clone(), - progr: a.permissions.clone(), - parent_task_id: state.task_id, - delay, - activation: new_activation, - fork_vector_offset: *fv_offset, - task_id: *id, - }; - return ExecutionResult::DispatchFork(fork); + + return ExecutionResult::DispatchFork(delay, *id, *fv_offset); } Op::Pass => { let args = f.pop(); let Variant::List(args) = args.variant() else { - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); }; - return state.prepare_pass_verb(world_state, args); + return ExecutionResult::Pass(args.clone()); } Op::CallVerb => { let (args, verb, obj) = (f.pop(), f.pop(), f.pop()); let (Variant::List(l), Variant::Str(s)) = (args.variant(), verb.variant()) else { - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); }; let verb = Symbol::mk_case_insensitive(s.as_string()); - let result = state.verb_dispatch(exec_params, world_state, obj, verb, l.clone()); - match result { - Ok(r) => return r, - Err(e) => { - return state.push_error(e); - } - } + return ExecutionResult::PrepareVerbDispatch { + this: obj, + verb_name: verb, + args: l.clone(), + }; } Op::Return => { let ret_val = f.pop(); - return state.unwind_stack(FinallyReason::Return(ret_val)); + return ExecutionResult::Return(ret_val); } Op::Return0 => { - return state.unwind_stack(FinallyReason::Return(v_int(0))); + return ExecutionResult::Return(v_int(0)); } Op::Done => { - return state.unwind_stack(FinallyReason::Return(v_none())); + return ExecutionResult::Return(v_none()); } Op::FuncCall { id } => { // Pop arguments, should be a list. let args = f.pop(); let Variant::List(args) = args.variant() else { - return state.push_error(E_ARGS); + return ExecutionResult::PushError(E_ARGS); + }; + return ExecutionResult::ContinueBuiltin { + builtin: *id, + arguments: args.iter().collect(), }; - return state.call_builtin_function( - *id, - args.iter().collect(), - exec_params, - world_state, - session, - ); } Op::PushCatchLabel(label) => { // Get the error codes, which is either a list of error codes or Any. @@ -728,12 +697,7 @@ pub fn moo_frame_execute( let handler = f.pop_scope().expect("Missing handler for try/catch/except"); let ScopeType::TryCatch(..) = handler.scope_type else { - panic!( - "Handler is not a catch handler; {}:{} line {}", - to_literal(&a.this), - a.verb_name, - f.find_line_no(f.pc - 1).unwrap() - ); + panic!("Handler is not a catch handler",); }; if is_catch { @@ -757,7 +721,7 @@ pub fn moo_frame_execute( FinallyReason::Raise(_) | FinallyReason::Return(_) | FinallyReason::Exit { .. } => { - return state.unwind_stack(why); + return ExecutionResult::Unwind(why); } } } @@ -775,7 +739,7 @@ pub fn moo_frame_execute( continue; } Op::Exit { stack, label } => { - return state.unwind_stack(FinallyReason::Exit { + return ExecutionResult::Unwind(FinallyReason::Exit { stack: *stack, label: *label, }); @@ -803,7 +767,7 @@ pub fn moo_frame_execute( let rhs = f.peek_top(); let Variant::List(rhs_values) = rhs.variant() else { f.pop(); - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); }; rhs_values.clone() }; @@ -811,7 +775,7 @@ pub fn moo_frame_execute( let len = rhs_values.len(); if len < nreq || !have_rest && len > nargs { f.pop(); - return state.push_error(E_ARGS); + return ExecutionResult::PushError(E_ARGS); } let mut nopt_avail = len - nreq; let nrest = if have_rest && len >= nargs { @@ -837,7 +801,7 @@ pub fn moo_frame_execute( } ScatterLabel::Required(id) => { let Some(arg) = args_iter.next() else { - return state.push_error(E_ARGS); + return ExecutionResult::PushError(E_ARGS); }; f.set_env(id, arg.clone()); @@ -846,7 +810,7 @@ pub fn moo_frame_execute( if nopt_avail > 0 { nopt_avail -= 1; let Some(arg) = args_iter.next() else { - return state.push_error(E_ARGS); + return ExecutionResult::PushError(E_ARGS); }; f.set_env(id, arg.clone()); } else if jump_where.is_none() && jump_to.is_some() { @@ -863,7 +827,7 @@ pub fn moo_frame_execute( Op::CheckListForSplice => { if !f.peek_top().is_sequence() { f.pop(); - return state.push_error(E_TYPE); + return ExecutionResult::PushError(E_TYPE); } } } diff --git a/crates/kernel/src/vm/moo_frame.rs b/crates/kernel/src/vm/moo_frame.rs index b980e66f..deface41 100644 --- a/crates/kernel/src/vm/moo_frame.rs +++ b/crates/kernel/src/vm/moo_frame.rs @@ -176,12 +176,12 @@ impl MooStackFrame { program, environment, environment_width, - valstack: vec![], - scope_stack: vec![], pc: 0, temp: v_none(), - catch_stack: vec![], - finally_stack: vec![], + valstack: Default::default(), + scope_stack: Default::default(), + catch_stack: Default::default(), + finally_stack: Default::default(), } } @@ -306,7 +306,6 @@ impl MooStackFrame { // If this is a lexical scope, expand the environment to accommodate the new variables. // (This is just updating environment_width) let environment_width = environment_width as usize; - assert!(environment_width <= self.environment.len()); self.environment_width += environment_width; let end_pos = self.program.jump_labels[end_label.0 as usize].position.0 as usize; diff --git a/crates/kernel/src/vm/vm_call.rs b/crates/kernel/src/vm/vm_call.rs index 6ba1c3fd..17118e5a 100644 --- a/crates/kernel/src/vm/vm_call.rs +++ b/crates/kernel/src/vm/vm_call.rs @@ -178,7 +178,7 @@ impl VMExecState { // Permissions for the activation are the verb's owner. let permissions = resolved_verb.owner(); - ExecutionResult::ContinueVerb { + ExecutionResult::DispatchVerb { permissions, resolved_verb, binary, @@ -231,7 +231,7 @@ impl VMExecState { caller, }; - ExecutionResult::ContinueVerb { + ExecutionResult::DispatchVerb { permissions: permissions.clone(), resolved_verb, binary,