implement primop (filter)
This commit is contained in:
@@ -8,18 +8,18 @@ use crate::{
|
||||
|
||||
impl<'gc> crate::Vm<'gc> {
|
||||
#[inline(always)]
|
||||
pub(crate) fn op_call(
|
||||
pub(crate) fn call(
|
||||
&mut self,
|
||||
ctx: &mut impl VmRuntimeCtx,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
arg: Value<'gc>,
|
||||
resume_pc: usize,
|
||||
) -> Step {
|
||||
let func = self.try_force::<StrictValue>(reader, mc)?;
|
||||
if self.call_depth > 10000 {
|
||||
return self.finish_err(Error::eval_error("stack overflow; max-call-depth exceeded"));
|
||||
}
|
||||
self.call_depth += 1;
|
||||
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;
|
||||
@@ -29,7 +29,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
} else {
|
||||
let new_env = Gc::new(mc, RefLock::new(Env::with_arg(arg, n_locals, env)));
|
||||
self.call_stack.push(CallFrame {
|
||||
pc: reader.pc(),
|
||||
pc: resume_pc,
|
||||
stack_depth: 0,
|
||||
thunk: None,
|
||||
env: self.env,
|
||||
@@ -38,12 +38,66 @@ impl<'gc> crate::Vm<'gc> {
|
||||
reader.set_pc(ip as usize);
|
||||
self.env = new_env;
|
||||
}
|
||||
} else if let Some(primop) = func.as_inline::<PrimOp>() {
|
||||
if primop.arity == 1 {
|
||||
self.push(arg);
|
||||
self.call_stack.push(CallFrame {
|
||||
pc: resume_pc,
|
||||
stack_depth: 0,
|
||||
thunk: None,
|
||||
env: self.env,
|
||||
with_env: self.with_env,
|
||||
});
|
||||
reader.set_pc(primop.dispatch_ip as usize)
|
||||
} else {
|
||||
let app = PrimOpApp {
|
||||
primop,
|
||||
arity: primop.arity - 1,
|
||||
args: [arg, Value::default(), Value::default()],
|
||||
};
|
||||
self.push(Value::new_gc(Gc::new(mc, app)));
|
||||
}
|
||||
} else if let Some(app) = func.as_gc::<PrimOpApp>() {
|
||||
if app.arity == 1 {
|
||||
for i in 0..app.primop.arity - 1 {
|
||||
self.push(app.args[i as usize]);
|
||||
}
|
||||
self.push(arg);
|
||||
self.call_stack.push(CallFrame {
|
||||
pc: resume_pc,
|
||||
stack_depth: 0,
|
||||
thunk: None,
|
||||
env: self.env,
|
||||
with_env: self.with_env,
|
||||
});
|
||||
reader.set_pc(app.primop.dispatch_ip as usize)
|
||||
} else {
|
||||
let position = (app.primop.arity - app.arity) as usize;
|
||||
let mut new_app = PrimOpApp {
|
||||
arity: app.arity - 1,
|
||||
..*app
|
||||
};
|
||||
new_app.args[position] = arg;
|
||||
self.push(Value::new_gc(Gc::new(mc, new_app)))
|
||||
}
|
||||
} else {
|
||||
todo!("call other types: {func:?}")
|
||||
}
|
||||
Step::Continue(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn op_call(
|
||||
&mut self,
|
||||
ctx: &impl VmRuntimeCtx,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> Step {
|
||||
let arg = reader.read_operand_data(ctx).resolve(mc, self);
|
||||
let pc = reader.pc();
|
||||
self.call(reader, mc, arg, pc)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn op_return(
|
||||
&mut self,
|
||||
@@ -51,16 +105,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> Step {
|
||||
self.handle_return(reader, ctx, mc)
|
||||
}
|
||||
|
||||
pub(crate) fn handle_return<C: VmRuntimeCtx>(
|
||||
&mut self,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
ctx: &C,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> Step {
|
||||
let ret_inst_pc = reader.pc() - 1;
|
||||
let val = self.try_force::<StrictValue>(reader, mc)?;
|
||||
let Some(CallFrame {
|
||||
pc: ret_pc,
|
||||
stack_depth,
|
||||
@@ -69,66 +114,15 @@ impl<'gc> crate::Vm<'gc> {
|
||||
with_env,
|
||||
}) = self.call_stack.pop()
|
||||
else {
|
||||
let val = self.pop();
|
||||
return self.finish_ok(ctx.convert_value(val));
|
||||
return self.finish_ok(ctx.convert_value(val.relax()));
|
||||
};
|
||||
reader.set_pc(ret_pc);
|
||||
if let Some(outer_thunk) = thunk {
|
||||
let val = self.pop();
|
||||
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(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 Step::Continue(());
|
||||
}
|
||||
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(val.relax());
|
||||
}
|
||||
}
|
||||
ThunkState::Apply { func: _, arg: _ } => todo!("force Apply thunk"),
|
||||
ThunkState::Blackhole => {
|
||||
return self
|
||||
.finish_err(Error::eval_error("infinite recursion encountered"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*outer_thunk.borrow_mut(mc) = ThunkState::Evaluated(val);
|
||||
self.replace(stack_depth, val.relax());
|
||||
} else {
|
||||
self.call_depth -= 1;
|
||||
self.push(val.relax())
|
||||
}
|
||||
self.env = env;
|
||||
self.with_env = with_env;
|
||||
|
||||
Reference in New Issue
Block a user