ForceMode

This commit is contained in:
2026-04-26 14:51:34 +08:00
parent ac76d4a9e4
commit bc16596dd3
5 changed files with 175 additions and 35 deletions
+102 -24
View File
@@ -5,9 +5,7 @@ use num_enum::TryFromPrimitive as _;
use smallvec::SmallVec;
use crate::value::*;
use crate::{
BytecodeReader, CallFrame, Step, Vm, VmRuntimeCtx, VmRuntimeCtxExt,
};
use crate::{BytecodeReader, CallFrame, Step, Vm, VmRuntimeCtx, VmRuntimeCtxExt};
impl<'gc> Vm<'gc> {
#[allow(clippy::too_many_lines)]
@@ -34,7 +32,12 @@ impl<'gc> Vm<'gc> {
FilterCallPred => self.primop_filter_call_pred(reader, mc),
FilterCheck => self.primop_filter_check(reader, mc),
_ => todo!("dispatch builtin phase"),
ForceResultShallow => self.primop_force_result_shallow(ctx, reader, mc),
ForceResultShallowPush => self.primop_force_result_shallow_push(ctx, reader, mc),
ForceResultShallowLoop => self.primop_force_result_shallow_loop(reader, mc),
ForceResultDeepFinish => self.primop_force_result_deep_finish(ctx, reader, mc),
phase => todo!("primop phase {phase:?}"),
}
}
@@ -143,9 +146,7 @@ impl<'gc> Vm<'gc> {
// stack: [msg] - force msg, then abort with it
self.force_slot(0, reader, mc)?;
let msg_val = self.peek_forced(0);
let msg = ctx
.get_string(msg_val)
.unwrap_or("<non-string-value>");
let msg = ctx.get_string(msg_val).unwrap_or("<non-string-value>");
self.finish_err(Error::eval_error(format!(
"evaluation aborted with the following error message: '{msg}'"
)))
@@ -222,12 +223,7 @@ impl<'gc> Vm<'gc> {
self.push(item);
// force item at TOS, resume at DeepSeqLoop after force
self.force_slot_to_pc(
0,
reader,
mc,
PrimOpPhase::DeepSeqLoop.ip() as usize,
)?;
self.force_slot_to_pc(0, reader, mc, PrimOpPhase::DeepSeqLoop.ip() as usize)?;
reader.set_pc(PrimOpPhase::DeepSeqLoop.ip() as usize);
Step::Continue(())
}
@@ -281,11 +277,98 @@ impl<'gc> Vm<'gc> {
Step::Continue(())
}
fn is_value_in_seen(
&self,
seen: Gc<'gc, List<'gc>>,
val: Value<'gc>,
) -> bool {
pub(crate) fn primop_force_result_shallow(
&mut self,
ctx: &mut impl VmRuntimeCtx,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
self.force_slot(0, reader, mc)?;
let val = self.peek_forced(0);
let (count, has_children) = if let Some(attrs) = val.as_gc::<AttrSet>() {
let len = attrs.len();
(len, len > 0)
} else if let Some(list) = val.as_gc::<List<'gc>>() {
let len = list.inner.borrow().len();
(len, len > 0)
} else {
(0, false)
};
if !has_children {
let val = self.pop();
return self.finish_ok(ctx.convert_value(val));
}
self.push(Value::new_inline(0i32));
self.push(Value::new_inline(count as i32));
reader.set_pc(PrimOpPhase::ForceResultShallowPush.ip() as usize);
Step::Continue(())
}
pub(crate) fn primop_force_result_shallow_push(
&mut self,
ctx: &mut impl VmRuntimeCtx,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
#[allow(clippy::unwrap_used)]
let idx = self.peek(1).as_inline::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let len = self.peek(0).as_inline::<i32>().unwrap();
if idx == len {
let _ = self.pop(); // len
let _ = self.pop(); // idx
let val = self.pop();
return self.finish_ok(ctx.convert_value(val));
}
let val = self.peek_forced(2);
let child = if let Some(attrs) = val.as_gc::<AttrSet>() {
attrs.get(idx as usize).map(|&(_, v)| v)
} else if let Some(list) = val.as_gc::<List<'gc>>() {
list.inner.borrow().get(idx as usize).copied()
} else {
None
};
if let Some(child) = child {
self.replace(1, Value::new_inline(idx + 1));
self.push(child);
self.force_slot_to_pc(
0,
reader,
mc,
PrimOpPhase::ForceResultShallowLoop.ip() as usize,
)?;
reader.set_pc(PrimOpPhase::ForceResultShallowLoop.ip() as usize);
}
Step::Continue(())
}
pub(crate) fn primop_force_result_shallow_loop(
&mut self,
reader: &mut BytecodeReader<'_>,
_mc: &Mutation<'gc>,
) -> Step {
let _ = self.pop(); // forced child
reader.set_pc(PrimOpPhase::ForceResultShallowPush.ip() as usize);
Step::Continue(())
}
pub(crate) fn primop_force_result_deep_finish(
&mut self,
ctx: &mut impl VmRuntimeCtx,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
let val = self.try_force::<StrictValue>(reader, mc)?;
self.finish_ok(ctx.convert_value(val.relax()))
}
fn is_value_in_seen(&self, seen: Gc<'gc, List<'gc>>, val: Value<'gc>) -> bool {
if !is_container(val) {
return false;
}
@@ -298,12 +381,7 @@ impl<'gc> Vm<'gc> {
false
}
fn add_value_to_seen(
&self,
seen: Gc<'gc, List<'gc>>,
mc: &Mutation<'gc>,
val: Value<'gc>,
) {
fn add_value_to_seen(&self, seen: Gc<'gc, List<'gc>>, mc: &Mutation<'gc>, val: Value<'gc>) {
if is_container(val) {
seen.unlock(mc).borrow_mut().push(val);
}