implement primop (filter)

This commit is contained in:
2026-04-25 21:08:54 +08:00
parent 4f3cd0ef4c
commit d77dcc8929
18 changed files with 558 additions and 129 deletions
+61 -69
View File
@@ -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,64 @@ 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 new_app = PrimOpApp {
arity: app.arity - 1,
..*app
};
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 +103,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 +112,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;