diff --git a/fix-runtime/src/machine.rs b/fix-runtime/src/machine.rs index 93dc3cf..84194ee 100644 --- a/fix-runtime/src/machine.rs +++ b/fix-runtime/src/machine.rs @@ -75,6 +75,7 @@ pub trait Machine<'gc> { pc: ret_pc, thunk: _, env, + depth: None, }) = self.pop_call_frame() else { unreachable!() diff --git a/fix-runtime/src/state.rs b/fix-runtime/src/state.rs index 189bc4a..dba96d5 100644 --- a/fix-runtime/src/state.rs +++ b/fix-runtime/src/state.rs @@ -59,8 +59,9 @@ pub struct ErrorFrame { #[collect(no_drop)] pub struct CallFrame<'gc> { pub pc: usize, - pub thunk: Option>>, pub env: GcEnv<'gc>, + pub thunk: Option>>, + pub depth: Option, } #[derive(Debug)] diff --git a/fix-runtime/src/value.rs b/fix-runtime/src/value.rs index 7945ebb..61e5287 100644 --- a/fix-runtime/src/value.rs +++ b/fix-runtime/src/value.rs @@ -26,11 +26,11 @@ pub trait ValueVariant<'gc>: private::Cealed { private_bounds, reason = "Storable is a sealed implementation detail of the value system" )] - type Ty: Storable + 'gc; + type Ty: Storable<'gc>; const TYPE: NixType; } -trait Storable: private::Cealed { +trait Storable<'gc>: TryFrom> + Into> + private::Cealed + 'gc { fn is(raw: &RawBox) -> bool; fn to_raw_box(self) -> RawBox; @@ -46,7 +46,7 @@ macro_rules! define_value_types { gc { $($gtype:ty => $gtag:path, $gty:path, $gname:literal;)* } ) => { $( - impl Storable for $itype { + impl Storable<'_> for $itype { #[inline(always)] fn is(value: &RawBox) -> bool { value.tag() == Some($itag) @@ -80,7 +80,7 @@ macro_rules! define_value_types { } )* $( - impl Storable for Gc<'_, $gtype> { + impl<'gc> Storable<'gc> for Gc<'gc, unelide_lifetimes!('gc; $gtype)> { #[inline(always)] fn is(value: &RawBox) -> bool { value.tag() == Some($gtag) @@ -202,7 +202,7 @@ define_value_types! { impl private::Cealed for f64 {} -impl Storable for f64 { +impl Storable<'_> for f64 { #[inline(always)] fn is(value: &RawBox) -> bool { value.is_float() @@ -224,7 +224,14 @@ impl<'gc> ValueVariant<'gc> for f64 { const TYPE: NixType = NixType::Float; } -impl<'gc, T: Storable + 'gc> From for Value<'gc> { +impl<'gc> TryFrom> for f64 { + type Error = (); + fn try_from(value: Value<'gc>) -> Result { + value.downcast::().ok_or(()) + } +} + +impl<'gc, T: Storable<'gc>> From for Value<'gc> { fn from(value: T) -> Self { Value::new(value) } @@ -260,7 +267,7 @@ impl<'gc> Value<'gc> { private_bounds, reason = "Storable is a sealed implementation detail of the value system" )] - pub fn new(val: T) -> Self { + pub fn new>(val: T) -> Self { Self { raw: val.to_raw_box(), _marker: PhantomData, @@ -380,7 +387,7 @@ impl StaticValue { private_bounds, reason = "Storable is a sealed implementation detail of the value system" )] - pub fn new(val: T) -> Self { + pub fn new>(val: T) -> Self { Self(Value::new(val)) } @@ -597,14 +604,6 @@ pub struct Env<'gc> { } pub type GcEnv<'gc> = GcRefLock<'gc, Env<'gc>>; -#[derive(Collect, Debug)] -#[collect(no_drop)] -pub struct WithEnv<'gc> { - pub env: Value<'gc>, - pub prev: Option>, -} -pub type GcWithEnv<'gc> = Gc<'gc, WithEnv<'gc>>; - impl<'gc> Env<'gc> { pub fn empty() -> Self { Env { @@ -722,6 +721,13 @@ impl<'gc> From> for Value<'gc> { } } +impl<'gc> TryFrom> for StrictValue<'gc> { + type Error = Gc<'gc, Thunk<'gc>>; + fn try_from(value: Value<'gc>) -> Result { + value.restrict() + } +} + impl fmt::Debug for StrictValue<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.0, f) diff --git a/fix-vm/src/instructions/calls.rs b/fix-vm/src/instructions/calls.rs index 3a67345..e4b009a 100644 --- a/fix-vm/src/instructions/calls.rs +++ b/fix-vm/src/instructions/calls.rs @@ -34,6 +34,7 @@ pub(crate) fn call<'gc, M: Machine<'gc>>( pc: resume_pc, thunk: None, env: m.env(), + depth: None, }); reader.set_pc(Continuation::CallPattern.ip() as usize); return Step::Continue(()); @@ -47,6 +48,7 @@ pub(crate) fn call<'gc, M: Machine<'gc>>( pc: resume_pc, thunk: None, env: m.env(), + depth: None, }); reader.set_pc(ip as usize); m.set_env(new_env); @@ -57,6 +59,7 @@ pub(crate) fn call<'gc, M: Machine<'gc>>( pc: resume_pc, thunk: None, env: m.env(), + depth: None, }); reader.set_pc(primop.dispatch_ip as usize) } else { @@ -77,6 +80,7 @@ pub(crate) fn call<'gc, M: Machine<'gc>>( pc: resume_pc, thunk: None, env: m.env(), + depth: None, }); reader.set_pc(app.primop.dispatch_ip as usize) } else { @@ -101,6 +105,7 @@ pub(crate) fn call<'gc, M: Machine<'gc>>( pc: resume_pc, thunk: None, env: m.env(), + depth: None, }); m.push(arg); m.push(func.relax()); @@ -140,6 +145,7 @@ pub(crate) fn op_return<'gc, M: Machine<'gc>>( pc: ret_pc, thunk, env, + depth, }) = m.pop_call_frame() else { match m.force_mode() { @@ -156,6 +162,7 @@ pub(crate) fn op_return<'gc, M: Machine<'gc>>( pc: Continuation::ForceResultDeepFinish.ip() as usize, thunk: None, env: m.env(), + depth: None, }); m.inc_call_depth(); reader.set_pc(Continuation::PDeepSeq.ip() as usize); @@ -166,6 +173,9 @@ pub(crate) fn op_return<'gc, M: Machine<'gc>>( reader.set_pc(ret_pc); if let Some(outer_thunk) = thunk { *outer_thunk.borrow_mut(mc) = ThunkState::Evaluated(val); + if let Some(depth) = depth { + m.replace(depth, val.relax()); + } } else { m.dec_call_depth(); m.push(val.relax()) diff --git a/fix-vm/src/instructions/with_scope.rs b/fix-vm/src/instructions/with_scope.rs index 510785d..aac8eb4 100644 --- a/fix-vm/src/instructions/with_scope.rs +++ b/fix-vm/src/instructions/with_scope.rs @@ -41,6 +41,7 @@ pub(crate) fn op_lookup_with<'gc, M: Machine<'gc>>( thunk: Some(thunk), pc: resume_pc, env: m.env(), + depth: None, }); m.set_env(env); reader.set_pc(ip); @@ -52,6 +53,7 @@ pub(crate) fn op_lookup_with<'gc, M: Machine<'gc>>( thunk: Some(thunk), pc: resume_pc, env: m.env(), + depth: None, }); m.push(func); return m.call(reader, mc, arg, resume_pc); diff --git a/fix-vm/src/lib.rs b/fix-vm/src/lib.rs index d105113..09524f7 100644 --- a/fix-vm/src/lib.rs +++ b/fix-vm/src/lib.rs @@ -211,6 +211,7 @@ impl<'gc> Machine<'gc> for Vm<'gc> { thunk: Some(thunk), pc: resume_pc, env: self.env, + depth: Some(depth), }); self.env = env; reader.set_pc(ip); @@ -225,6 +226,7 @@ impl<'gc> Machine<'gc> for Vm<'gc> { thunk: Some(thunk), pc: resume_pc, env: self.env, + depth: Some(depth), }); self.push(func); self.call(reader, mc, arg, resume_pc) diff --git a/fix-vm/src/primops/eq.rs b/fix-vm/src/primops/eq.rs index 25ae70b..f87fbe5 100644 --- a/fix-vm/src/primops/eq.rs +++ b/fix-vm/src/primops/eq.rs @@ -166,6 +166,7 @@ fn enter_eq_machine<'gc, M: Machine<'gc>>( pc: resume_pc, thunk: None, env: m.env(), + depth: None, }); m.inc_call_depth(); m.push(Value::new(negate)); diff --git a/fix-vm/src/primops/io.rs b/fix-vm/src/primops/io.rs index 40e58bc..2173167 100644 --- a/fix-vm/src/primops/io.rs +++ b/fix-vm/src/primops/io.rs @@ -46,6 +46,7 @@ pub fn import<'gc, M: Machine<'gc>>( pc: Continuation::PImportFinalize.ip() as usize, thunk: None, env, + depth: None, }); m.set_pending_load(PendingLoad { @@ -79,6 +80,7 @@ pub fn import_finalize<'gc, M: Machine<'gc>>( pc: ret_pc, thunk: _, env, + depth: None, }) = m.pop_call_frame() else { unreachable!() @@ -120,6 +122,7 @@ pub fn scoped_import<'gc, M: Machine<'gc>>( pc: Continuation::PScopedImportFinalize.ip() as usize, thunk: None, env, + depth: None, }); m.set_pending_load(PendingLoad {