refactor vm
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
use fix_error::Error;
|
||||
|
||||
use crate::{
|
||||
BytecodeReader, CallFrame, Closure, Env, StepResult, ThunkState,
|
||||
};
|
||||
use crate::VmContextExt;
|
||||
use gc_arena::{Gc, Mutation, RefLock};
|
||||
|
||||
impl<'gc> crate::Vm<'gc> {
|
||||
#[inline(always)]
|
||||
pub(crate) fn op_call(
|
||||
&mut self,
|
||||
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) {
|
||||
return step;
|
||||
}
|
||||
if self.call_depth > 10000 {
|
||||
return StepResult::Done(Err(Error::eval_error(
|
||||
"stack overflow; max-call-depth exceeded",
|
||||
)));
|
||||
}
|
||||
self.call_depth += 1;
|
||||
let func = self.pop_stack();
|
||||
let arg = reader.read_operand_data(ctx).resolve(mc, self);
|
||||
if let Some(closure) = func.as_gc::<Closure>() {
|
||||
let ip = closure.ip;
|
||||
let n_locals = closure.n_locals;
|
||||
let env = closure.env;
|
||||
if let Some(ref _pattern) = closure.pattern {
|
||||
todo!("pattern call")
|
||||
} else {
|
||||
let new_env = Gc::new(mc, RefLock::new(Env::with_arg(arg, n_locals, env)));
|
||||
self.call_stack.push(CallFrame {
|
||||
pc: reader.pc(),
|
||||
stack_depth: 0,
|
||||
thunk: None,
|
||||
env: self.env,
|
||||
with_env: self.with_env,
|
||||
});
|
||||
reader.set_pc(ip as usize);
|
||||
self.env = new_env;
|
||||
}
|
||||
} else {
|
||||
todo!("call other types: {func:?}")
|
||||
}
|
||||
StepResult::Continue
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn op_return(
|
||||
&mut self,
|
||||
ctx: &mut impl crate::VmContext,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult<'gc> {
|
||||
match self.handle_return(reader, ctx, mc) {
|
||||
Some(result) => StepResult::Done(result),
|
||||
None => StepResult::Continue,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn handle_return<C: crate::VmContext>(
|
||||
&mut self,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
ctx: &C,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> Option<std::result::Result<fix_common::Value, Box<Error>>> {
|
||||
let ret_inst_pc = reader.pc() - 1;
|
||||
let Some(CallFrame {
|
||||
pc: ret_pc,
|
||||
stack_depth,
|
||||
thunk,
|
||||
env,
|
||||
with_env,
|
||||
}) = self.call_stack.pop()
|
||||
else {
|
||||
let val = self.pop_stack();
|
||||
return Some(Ok(ctx.convert_value(val)));
|
||||
};
|
||||
reader.set_pc(ret_pc);
|
||||
if let Some(outer_thunk) = thunk {
|
||||
let val = self.pop_stack();
|
||||
match val.restrict() {
|
||||
Ok(val) => {
|
||||
*outer_thunk.borrow_mut(mc) = ThunkState::Evaluated(val);
|
||||
if reader
|
||||
.bytecode()
|
||||
.get(ret_pc)
|
||||
.copied()
|
||||
== Some(fix_codegen::Op::Return as u8)
|
||||
{
|
||||
self.push_stack(val.relax());
|
||||
}
|
||||
}
|
||||
Err(inner_thunk) => {
|
||||
let mut state = inner_thunk.borrow_mut(mc);
|
||||
match *state {
|
||||
ThunkState::Pending {
|
||||
ip: inner_ip,
|
||||
env: inner_env,
|
||||
with_env: inner_with_env,
|
||||
} => {
|
||||
self.call_stack.push(CallFrame {
|
||||
pc: ret_pc,
|
||||
stack_depth,
|
||||
thunk: Some(outer_thunk),
|
||||
env,
|
||||
with_env,
|
||||
});
|
||||
self.call_stack.push(CallFrame {
|
||||
pc: ret_inst_pc,
|
||||
stack_depth: 0,
|
||||
thunk: Some(inner_thunk),
|
||||
env: inner_env,
|
||||
with_env: inner_with_env,
|
||||
});
|
||||
*state = ThunkState::Blackhole;
|
||||
reader.set_pc(inner_ip);
|
||||
self.env = inner_env;
|
||||
self.with_env = inner_with_env;
|
||||
return None;
|
||||
}
|
||||
ThunkState::Evaluated(val) => {
|
||||
*outer_thunk.borrow_mut(mc) = ThunkState::Evaluated(val);
|
||||
if reader
|
||||
.bytecode()
|
||||
.get(ret_pc)
|
||||
.copied()
|
||||
== Some(fix_codegen::Op::Return as u8)
|
||||
{
|
||||
self.push_stack(val.relax());
|
||||
}
|
||||
}
|
||||
ThunkState::Apply { func: _, arg: _ } => todo!("force Apply thunk"),
|
||||
ThunkState::Blackhole => {
|
||||
return Some(Err(Error::eval_error(
|
||||
"infinite recursion encountered",
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.call_depth -= 1;
|
||||
}
|
||||
self.env = env;
|
||||
self.with_env = with_env;
|
||||
None
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user