From a1a44a665254bed1c9339c3bb8d2a4501d928911 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sun, 12 Jul 2026 21:09:32 +0800 Subject: [PATCH] runtime, macros: unify NaN-boxed value API under ValueVariant trait --- Cargo.lock | 53 ++++- Cargo.toml | 1 + fix-bytecode/src/disassembler.rs | 2 +- fix-compiler/src/context.rs | 18 +- fix-compiler/src/lib.rs | 2 +- fix-macros/Cargo.toml | 13 ++ fix-macros/src/lib.rs | 39 ++++ fix-runtime/Cargo.toml | 1 + fix-runtime/src/forced.rs | 85 ++----- fix-runtime/src/host.rs | 36 +-- fix-runtime/src/resolve.rs | 11 +- fix-runtime/src/value.rs | 304 +++++++++++-------------- fix-vm/src/instructions/arithmetic.rs | 36 ++- fix-vm/src/instructions/calls.rs | 12 +- fix-vm/src/instructions/closures.rs | 6 +- fix-vm/src/instructions/collections.rs | 18 +- fix-vm/src/instructions/control.rs | 4 +- fix-vm/src/instructions/literals.rs | 14 +- fix-vm/src/instructions/misc.rs | 18 +- fix-vm/src/instructions/with_scope.rs | 6 +- fix-vm/src/lib.rs | 36 ++- fix-vm/src/primops/context.rs | 98 ++++---- fix-vm/src/primops/control.rs | 56 ++--- fix-vm/src/primops/conv.rs | 6 +- fix-vm/src/primops/eq.rs | 43 ++-- fix-vm/src/primops/io.rs | 10 +- fix-vm/src/primops/list.rs | 75 +++--- fix-vm/src/primops/path.rs | 8 +- 28 files changed, 524 insertions(+), 487 deletions(-) create mode 100644 fix-macros/Cargo.toml create mode 100644 fix-macros/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index d37f998..609ad95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -513,6 +513,16 @@ dependencies = [ "string-interner", ] +[[package]] +name = "fix-macros" +version = "0.1.0" +dependencies = [ + "manyhow", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "fix-runtime" version = "0.1.0" @@ -520,6 +530,7 @@ dependencies = [ "fix-bytecode", "fix-error", "fix-lang", + "fix-macros", "gc-arena", "hashbrown 0.16.1", "smallvec", @@ -747,6 +758,29 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "manyhow" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" +dependencies = [ + "manyhow-macros", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "manyhow-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + [[package]] name = "matchers" version = "0.2.0" @@ -995,6 +1029,17 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-utils" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -1006,9 +1051,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] @@ -1275,9 +1320,9 @@ checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" [[package]] name = "syn" -version = "2.0.117" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 685ed17..ff8ad6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "fix-compiler", "fix-error", "fix-lang", + "fix-macros", "fix-runtime", "fix-vm", ] diff --git a/fix-bytecode/src/disassembler.rs b/fix-bytecode/src/disassembler.rs index 0191d2b..c5e27ec 100644 --- a/fix-bytecode/src/disassembler.rs +++ b/fix-bytecode/src/disassembler.rs @@ -2,7 +2,7 @@ use std::fmt::Write; use colored::Colorize as _; -use crate::{InstructionPtr, Op, OperandType, Continuation}; +use crate::{Continuation, InstructionPtr, Op, OperandType}; pub trait DisassemblerContext { fn resolve_string(&self, id: u32) -> &str; diff --git a/fix-compiler/src/context.rs b/fix-compiler/src/context.rs index 7e93a6b..9da2deb 100644 --- a/fix-compiler/src/context.rs +++ b/fix-compiler/src/context.rs @@ -1,5 +1,5 @@ use bumpalo::Bump; -use fix_bytecode::{Const, InstructionPtr, Op, Continuation}; +use fix_bytecode::{Const, Continuation, InstructionPtr, Op}; use fix_error::{Error, Result, Source}; use fix_lang::{StringId, Symbol}; use fix_runtime::{StaticValue, VmCode, VmRuntimeCtx}; @@ -148,16 +148,20 @@ impl<'a, R: VmRuntimeCtx> BytecodeContext for CompilerCtx<'a, R> { fn add_constant(&mut self, val: Const) -> u32 { use Const::*; let val = match val { - Smi(x) => StaticValue::new_inline(x), - Float(x) => StaticValue::new_float(x), - Bool(x) => StaticValue::new_inline(x), - String(x) => StaticValue::new_inline(x), - Path(x) => StaticValue::new_inline(fix_runtime::Path(x)), + Smi(x) => StaticValue::new(x), + Float(x) => StaticValue::new(x), + Bool(x) => StaticValue::new(x), + String(x) => StaticValue::new(x), + Path(x) => StaticValue::new(fix_runtime::Path(x)), PrimOp { id, arity, dispatch_ip, - } => StaticValue::new_primop(id, arity, dispatch_ip), + } => StaticValue::new(fix_runtime::PrimOp { + id, + arity, + dispatch_ip, + }), Null => StaticValue::default(), }; self.runtime.add_const(val) diff --git a/fix-compiler/src/lib.rs b/fix-compiler/src/lib.rs index d98c68a..d3ecb99 100644 --- a/fix-compiler/src/lib.rs +++ b/fix-compiler/src/lib.rs @@ -1,4 +1,4 @@ -use fix_bytecode::{Const, InstructionPtr, Op, OperandType, Continuation}; +use fix_bytecode::{Const, Continuation, InstructionPtr, Op, OperandType}; use fix_lang::{BUILTINS, StringId}; use hashbrown::HashMap; use rnix::TextRange; diff --git a/fix-macros/Cargo.toml b/fix-macros/Cargo.toml new file mode 100644 index 0000000..4ef8705 --- /dev/null +++ b/fix-macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "fix-macros" +version = "0.1.0" +edition = "2024" + +[lib] +proc-macro = true + +[dependencies] +manyhow = "0.11" +proc-macro2 = "1.0" +quote = "1.0" +syn = { version = "2.0", features = ["full", "visit"] } diff --git a/fix-macros/src/lib.rs b/fix-macros/src/lib.rs new file mode 100644 index 0000000..f49dd36 --- /dev/null +++ b/fix-macros/src/lib.rs @@ -0,0 +1,39 @@ +extern crate proc_macro; + +// Adapted from `__unelide_lifetimes` in `gc-arena-derive`. +// Licensed under the MIT license. +// See: https://github.com/kyren/gc-arena +#[proc_macro] +pub fn unelide_lifetimes(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + use quote::ToTokens; + use syn::parse::{Parse, ParseStream}; + use syn::visit_mut::VisitMut; + + struct Input { + lt: syn::Lifetime, + ty: syn::Type, + } + + impl Parse for Input { + fn parse(input: ParseStream) -> syn::Result { + let lt: syn::Lifetime = input.parse()?; + let _: syn::Token!(;) = input.parse()?; + let ty: syn::Type = input.parse()?; + Ok(Self { lt, ty }) + } + } + + struct UnelideLifetimes(syn::Lifetime); + + impl VisitMut for UnelideLifetimes { + fn visit_lifetime_mut(&mut self, i: &mut syn::Lifetime) { + if i.ident == "_" { + *i = self.0.clone(); + } + } + } + + let mut input = syn::parse_macro_input!(input as Input); + UnelideLifetimes(input.lt).visit_type_mut(&mut input.ty); + input.ty.to_token_stream().into() +} diff --git a/fix-runtime/Cargo.toml b/fix-runtime/Cargo.toml index ee63d6e..622d8ed 100644 --- a/fix-runtime/Cargo.toml +++ b/fix-runtime/Cargo.toml @@ -13,3 +13,4 @@ string-interner = { workspace = true } fix-bytecode = { path = "../fix-bytecode" } fix-error = { path = "../fix-error" } fix-lang = { path = "../fix-lang" } +fix-macros = { path = "../fix-macros" } diff --git a/fix-runtime/src/forced.rs b/fix-runtime/src/forced.rs index fbd2f96..10fe5ad 100644 --- a/fix-runtime/src/forced.rs +++ b/fix-runtime/src/forced.rs @@ -1,9 +1,9 @@ use fix_lang::StringId; -use gc_arena::{Gc, Mutation}; +use gc_arena::Mutation; use crate::{ AttrSet, Break, BytecodeReader, Closure, List, Machine, NixNum, NixString, NixType, Null, - PrimOp, PrimOpApp, Step, StrictValue, + PrimOp, PrimOpApp, Step, StrictValue, ValueVariant, }; pub trait Forced<'gc>: Sized { @@ -47,10 +47,10 @@ impl<'gc> Forced<'gc> for StrictValue<'gc> { } } -macro_rules! impl_forced_inline { - ($($ty:ty => $nix_ty:expr),* $(,)?) => { +macro_rules! impl_forced { + ($($ty:ty),* $(,)?) => { $( - impl<'gc> Forced<'gc> for $ty { + impl<'gc> Forced<'gc> for <$ty as ValueVariant>::Ty<'gc> { const WIDTH: usize = 1; #[inline(always)] @@ -63,8 +63,8 @@ macro_rules! impl_forced_inline { ) -> Step { m.force_slot_to_pc(base_depth, reader, mc, resume_pc)?; let v = m.peek_forced(base_depth); - if v.as_inline::<$ty>().is_none() { - let _: Step = m.finish_type_err($nix_ty, v.ty()); + if v.downcast::<$ty>().is_none() { + let _: Step = m.finish_type_err(<$ty as ValueVariant>::TYPE, v.ty()); return Step::Break(Break::Done); } Step::Continue(()) @@ -73,7 +73,7 @@ macro_rules! impl_forced_inline { #[inline(always)] fn pop_converted>(m: &mut M) -> Self { m.pop_forced() - .as_inline::<$ty>() + .downcast::<$ty>() .expect("type checked in force_and_check") } } @@ -81,55 +81,18 @@ macro_rules! impl_forced_inline { }; } -macro_rules! impl_forced_gc { - ($($ty:ty => $nix_ty:expr),* $(,)?) => { - $( - impl<'gc> Forced<'gc> for Gc<'gc, $ty> { - const WIDTH: usize = 1; - - #[inline(always)] - fn force_and_check>( - m: &mut M, - reader: &mut BytecodeReader<'_>, - mc: &Mutation<'gc>, - base_depth: usize, - resume_pc: usize, - ) -> Step { - m.force_slot_to_pc(base_depth, reader, mc, resume_pc)?; - let v = m.peek_forced(base_depth); - if v.as_gc::<$ty>().is_none() { - let _: Step = m.finish_type_err($nix_ty, v.ty()); - return Step::Break(Break::Done); - } - Step::Continue(()) - } - - #[inline(always)] - fn pop_converted>(m: &mut M) -> Self { - m.pop_forced() - .as_gc::<$ty>() - .expect("type checked in force_and_check") - } - } - )* - }; -} - -impl_forced_inline! { - i32 => NixType::Int, - bool => NixType::Bool, - Null => NixType::Null, - StringId => NixType::String, - PrimOp => NixType::PrimOp, -} - -impl_forced_gc! { - i64 => NixType::Int, - NixString => NixType::String, - AttrSet<'gc> => NixType::AttrSet, - List<'gc> => NixType::List, - Closure<'gc> => NixType::Closure, - PrimOpApp<'gc> => NixType::PrimOpApp, +impl_forced! { + i32, + bool, + Null, + StringId, + PrimOp, + i64, + NixString, + AttrSet<'gc>, + List<'gc>, + Closure<'gc>, + PrimOpApp<'gc>, } impl<'gc> Forced<'gc> for NixNum { @@ -145,7 +108,7 @@ impl<'gc> Forced<'gc> for NixNum { ) -> Step { m.force_slot_to_pc(base_depth, reader, mc, resume_pc)?; let v = m.peek_forced(base_depth); - if v.as_num().is_none() { + if v.downcast_num().is_none() { let _: Step = m.finish_type_err(NixType::Int, v.ty()); return Step::Break(Break::Done); } @@ -155,7 +118,7 @@ impl<'gc> Forced<'gc> for NixNum { #[inline(always)] fn pop_converted>(m: &mut M) -> Self { m.pop_forced() - .as_num() + .downcast_num() .expect("type checked in force_and_check") } } @@ -173,7 +136,7 @@ impl<'gc> Forced<'gc> for f64 { ) -> Step { m.force_slot_to_pc(base_depth, reader, mc, resume_pc)?; let v = m.peek_forced(base_depth); - if v.as_float().is_none() { + if v.downcast::().is_none() { let _: Step = m.finish_type_err(NixType::Float, v.ty()); return Step::Break(Break::Done); } @@ -183,7 +146,7 @@ impl<'gc> Forced<'gc> for f64 { #[inline(always)] fn pop_converted>(m: &mut M) -> Self { m.pop_forced() - .as_float() + .downcast::() .expect("type checked in force_and_check") } } diff --git a/fix-runtime/src/host.rs b/fix-runtime/src/host.rs index af75192..30d13ea 100644 --- a/fix-runtime/src/host.rs +++ b/fix-runtime/src/host.rs @@ -44,10 +44,10 @@ pub trait VmRuntimeCtxExt: VmRuntimeCtx { impl VmRuntimeCtxExt for T { fn get_string<'a, 'gc: 'a>(&'a self, val: StrictValue<'gc>) -> Option<&'a str> { - if let Some(sid) = val.as_inline::() { + if let Some(sid) = val.downcast::() { Some(self.resolve_string(sid)) } else { - val.as_gc::().map(|ns| ns.as_ref().as_str()) + val.downcast::().map(|ns| ns.as_ref().as_str()) } } @@ -56,7 +56,7 @@ impl VmRuntimeCtxExt for T { /// would coerce a path to a string (string interpolation, file IO /// builtins, etc.). fn get_string_or_path<'a, 'gc: 'a>(&'a self, val: StrictValue<'gc>) -> Option<&'a str> { - if let Some(p) = val.as_inline::() { + if let Some(p) = val.downcast::() { Some(self.resolve_string(p.0)) } else { self.get_string(val) @@ -67,9 +67,9 @@ impl VmRuntimeCtxExt for T { &'a mut self, val: StrictValue<'gc>, ) -> std::result::Result { - if let Some(sid) = val.as_inline::() { + if let Some(sid) = val.downcast::() { Ok(sid) - } else if let Some(s) = val.as_gc::().map(|ns| ns.as_ref().as_str()) { + } else if let Some(s) = val.downcast::().map(|ns| ns.as_ref().as_str()) { Ok(self.intern_string(s)) } else { Err(val.ty()) @@ -77,7 +77,7 @@ impl VmRuntimeCtxExt for T { } fn get_string_context<'gc>(&self, val: StrictValue<'gc>) -> &'gc StringContext { - if let Some(ns) = val.as_gc::() { + if let Some(ns) = val.downcast::() { ns.as_ref().context() } else { StringContext::empty() @@ -96,24 +96,24 @@ pub(crate) trait ConvertValueWithSeen: VmRuntimeCtx { impl ConvertValueWithSeen for T { fn convert_value_with_seen(&self, val: Value, seen: &mut HashSet) -> fix_lang::Value { use fix_lang::Value; - if let Some(i) = val.as_inline::() { + if let Some(i) = val.downcast::() { Value::Int(i as i64) - } else if let Some(gc_i) = val.as_gc::() { + } else if let Some(gc_i) = val.downcast::() { Value::Int(*gc_i) - } else if let Some(f) = val.as_float() { + } else if let Some(f) = val.downcast::() { Value::Float(f) - } else if let Some(b) = val.as_inline::() { + } else if let Some(b) = val.downcast::() { Value::Bool(b) } else if val.is::() { Value::Null - } else if let Some(sid) = val.as_inline::() { + } else if let Some(sid) = val.downcast::() { let s = self.resolve_string(sid).to_owned(); Value::String(s) - } else if let Some(ns) = val.as_gc::() { + } else if let Some(ns) = val.downcast::() { Value::String(ns.as_str().to_owned()) - } else if let Some(p) = val.as_inline::() { + } else if let Some(p) = val.downcast::() { Value::Path(self.resolve_string(p.0).to_owned()) - } else if let Some(attrs) = val.as_gc::() { + } else if let Some(attrs) = val.downcast::() { let bits = val.to_bits(); if attrs.entries.is_empty() { return Value::AttrSet(Default::default()); @@ -128,7 +128,7 @@ impl ConvertValueWithSeen for T { map.insert(fix_lang::Symbol::from(key), converted); } Value::AttrSet(fix_lang::AttrSet::new(map)) - } else if let Some(list) = val.as_gc::() { + } else if let Some(list) = val.downcast::() { let bits = val.to_bits(); if list.inner.borrow().is_empty() { return Value::List(Default::default()); @@ -146,16 +146,16 @@ impl ConvertValueWithSeen for T { Value::List(fix_lang::List::new(items)) } else if val.is::() { Value::Func - } else if let Some(thunk) = val.as_gc::() { + } else if let Some(thunk) = val.downcast::() { if let ThunkState::Evaluated(v) = *thunk.borrow() { self.convert_value_with_seen(v.relax(), seen) } else { Value::Thunk } - } else if let Some(primop) = val.as_inline::() { + } else if let Some(primop) = val.downcast::() { let name = BUILTINS[primop.id as usize].0; Value::PrimOp(name.strip_prefix("__").unwrap_or(name)) - } else if let Some(app) = val.as_gc::() { + } else if let Some(app) = val.downcast::() { let name = BUILTINS[app.primop.id as usize].0; Value::PrimOpApp(name.strip_prefix("__").unwrap_or(name)) } else { diff --git a/fix-runtime/src/resolve.rs b/fix-runtime/src/resolve.rs index e7f53e5..a20d0b4 100644 --- a/fix-runtime/src/resolve.rs +++ b/fix-runtime/src/resolve.rs @@ -18,16 +18,21 @@ pub fn resolve_operand<'gc, M: Machine<'gc>>( use OperandData::*; match *op { Const(id) => ctx.get_const(id).into(), - BigInt(val) => Value::new_gc(Gc::new(mc, val)), + BigInt(val) => Value::new(Gc::new(mc, val)), Local { layer, idx } => m.local(layer, idx), #[allow(clippy::unwrap_used)] - BuiltinConst(id) => m.builtins().as_gc::().unwrap().lookup(id).unwrap(), + BuiltinConst(id) => m + .builtins() + .downcast::() + .unwrap() + .lookup(id) + .unwrap(), Builtins => m.builtins(), ReplBinding(_id) => todo!(), ScopedImportBinding { slot_id, name } => { let scope = m.scope_slot(slot_id); #[allow(clippy::unwrap_used)] - let attrs = scope.as_gc::().expect("scope must be attrset"); + let attrs = scope.downcast::().expect("scope must be attrset"); #[allow(clippy::unwrap_used)] attrs.lookup(name).expect("scoped binding not found") } diff --git a/fix-runtime/src/value.rs b/fix-runtime/src/value.rs index 0932a29..1d2ae38 100644 --- a/fix-runtime/src/value.rs +++ b/fix-runtime/src/value.rs @@ -19,33 +19,84 @@ mod private { pub trait Cealed {} } +pub trait ValueVariant: private::Cealed { + type Ty<'gc>: 'gc; + const TYPE: NixType; + fn is_value(value: &Value<'_>) -> bool; + /// # Safety + /// + /// [`Self::is_value`] must hold for `value`. + unsafe fn from_raw<'gc>(value: &Value<'gc>) -> Self::Ty<'gc>; +} + /// # Safety /// -/// [`Self::TAG`] must be unique among all implementors. -unsafe trait Storable: private::Cealed { - const TAG: RawTag; +/// Each implementor must round-trip through [`Self::to_raw_box`] / +/// [`Self::from_raw_box`] and must be the sole owner of its NaN-boxed +/// representation (tagged payload or float). +pub(crate) unsafe trait Storable: private::Cealed { + fn to_raw_box(self) -> RawBox; + /// # Safety + /// + /// `raw` must represent a valid `Self`. + unsafe fn from_raw_box(raw: &RawBox) -> Self; } -trait InlineStorable: Storable + RawStore {} -trait GcStorable: Storable {} macro_rules! define_value_types { ( - inline { $($itype:ty => $itag:expr, $iname:literal;)* } - gc { $($gtype:ty => $gtag:expr, $gname:literal;)* } + inline { $($itype:ty => $itag:path, $ity:path, $iname:literal;)* } + gc { $($gtype:ty => $gtag:path, $gty:path, $gname:literal;)* } ) => { $( unsafe impl Storable for $itype { - const TAG: RawTag = $itag; + fn to_raw_box(self) -> RawBox { + RawBox::from_value(RawValue::store($itag, self)) + } + unsafe fn from_raw_box(raw: &RawBox) -> Self { + unsafe { ::from_val(raw.value().unwrap_unchecked()) } + } } - impl InlineStorable for $itype {} impl private::Cealed for $itype {} + impl ValueVariant for $itype { + type Ty<'gc> = $itype; + const TYPE: NixType = $ity; + #[inline(always)] + fn is_value(value: &Value<'_>) -> bool { + value.raw.tag() == Some($itag) + } + #[inline(always)] + unsafe fn from_raw<'gc>(value: &Value<'gc>) -> Self::Ty<'gc> { + unsafe { <$itype as Storable>::from_raw_box(&value.raw) } + } + } )* $( - unsafe impl Storable for $gtype { - const TAG: RawTag = $gtag; + unsafe impl Storable for Gc<'_, $gtype> { + fn to_raw_box(self) -> RawBox { + RawBox::from_value(RawValue::store($gtag, Gc::as_ptr(self))) + } + unsafe fn from_raw_box(raw: &RawBox) -> Self { + unsafe { Gc::from_ptr(<*mut $gtype as RawStore>::from_val(raw.value().unwrap_unchecked())) } + } } - impl GcStorable for $gtype {} + impl private::Cealed for Gc<'_, $gtype> {} impl private::Cealed for $gtype {} + impl ValueVariant for $gtype { + type Ty<'gc> = Gc<'gc, fix_macros::unelide_lifetimes!('gc; $gtype)>; + const TYPE: NixType = $gty; + #[inline(always)] + fn is_value(value: &Value<'_>) -> bool { + value.raw.tag() == Some($gtag) + } + #[inline(always)] + unsafe fn from_raw<'gc>(value: &Value<'gc>) -> Self::Ty<'gc> { + unsafe { + as Storable>::from_raw_box( + &value.raw, + ) + } + } + } )* const _: () = assert!(size_of::>() == 8); @@ -75,10 +126,10 @@ macro_rules! define_value_types { fn trace>(&self, cc: &mut T) { let Some(tag) = self.raw.tag() else { return }; match tag { - $(<$gtype as Storable>::TAG => unsafe { - self.load_gc::<$gtype>().trace(cc) + $($gtag => unsafe { + self.downcast::<$gtype>().unwrap_unchecked().trace(cc) },)* - $(<$itype as Storable>::TAG => (),)* + $($itag => (),)* _ => unreachable!("invalid value tag"), } } @@ -90,10 +141,10 @@ macro_rules! define_value_types { None => write!(f, "Float({:?})", unsafe { self.raw.float().unwrap_unchecked() }), - $(Some(<$itype as Storable>::TAG) => write!(f, "{}({:?})", $iname, unsafe { - self.as_inline::<$itype>().unwrap_unchecked() + $(Some($itag) => write!(f, "{}({:?})", $iname, unsafe { + self.downcast::<$itype>().unwrap_unchecked() }),)* - $(Some(<$gtype as Storable>::TAG) => + $(Some($gtag) => write!(f, "{}(..)", $gname),)* _ => unreachable!("invalid value tag"), } @@ -104,21 +155,45 @@ macro_rules! define_value_types { define_value_types! { inline { - i32 => RawTag::P1, "SmallInt"; - bool => RawTag::P2, "Bool"; - Null => RawTag::P3, "Null"; - StringId => RawTag::P4, "SmallString"; - PrimOp => RawTag::P5, "PrimOp"; - Path => RawTag::P6, "Path"; + i32 => RawTag::P1, NixType::Int, "SmallInt"; + bool => RawTag::P2, NixType::Bool, "Bool"; + Null => RawTag::P3, NixType::Null, "Null"; + StringId => RawTag::P4, NixType::String, "SmallString"; + PrimOp => RawTag::P5, NixType::PrimOp, "PrimOp"; + Path => RawTag::P6, NixType::Path, "Path"; } gc { - i64 => RawTag::P7, "BigInt"; - NixString => RawTag::N1, "String"; - AttrSet<'_> => RawTag::N2, "AttrSet"; - List<'_> => RawTag::N3, "List"; - Thunk<'_> => RawTag::N4, "Thunk"; - Closure<'_> => RawTag::N5, "Closure"; - PrimOpApp<'_> => RawTag::N6, "PrimOpApp"; + i64 => RawTag::P7, NixType::Int, "BigInt"; + NixString => RawTag::N1, NixType::String, "String"; + AttrSet<'_> => RawTag::N2, NixType::AttrSet, "AttrSet"; + List<'_> => RawTag::N3, NixType::List, "List"; + Thunk<'_> => RawTag::N4, NixType::Thunk, "Thunk"; + Closure<'_> => RawTag::N5, NixType::Closure, "Closure"; + PrimOpApp<'_> => RawTag::N6, NixType::Closure, "PrimOpApp"; + } +} + +impl private::Cealed for f64 {} + +unsafe impl Storable for f64 { + fn to_raw_box(self) -> RawBox { + RawBox::from_float(self) + } + unsafe fn from_raw_box(raw: &RawBox) -> Self { + unsafe { raw.float().copied().unwrap_unchecked() } + } +} + +impl ValueVariant for f64 { + type Ty<'gc> = f64; + const TYPE: NixType = NixType::Float; + #[inline(always)] + fn is_value(value: &Value<'_>) -> bool { + value.raw.is_float() + } + #[inline(always)] + unsafe fn from_raw<'gc>(value: &Value<'gc>) -> Self::Ty<'gc> { + unsafe { ::from_raw_box(&value.raw) } } } @@ -135,33 +210,11 @@ pub struct Value<'gc> { impl Default for Value<'_> { #[inline(always)] fn default() -> Self { - Self::new_inline(Null) + Self::new(Null) } } impl<'gc> Value<'gc> { - #[inline(always)] - fn from_raw_value(rv: RawValue) -> Self { - Self { - raw: RawBox::from_value(rv), - _marker: PhantomData, - } - } - - /// Load a GC pointer from a value with a negative tag. - /// - /// # Safety - /// - /// The value must actually store a `Gc<'gc, T>` with the matching type. - #[inline(always)] - unsafe fn load_gc(self) -> Gc<'gc, T> { - unsafe { - let rv = self.raw.value().unwrap_unchecked(); - let ptr: *const T = <*const T as RawStore>::from_val(rv); - Gc::from_ptr(ptr) - } - } - #[inline(always)] const fn tag(self) -> Option { self.raw.tag() @@ -170,80 +223,31 @@ impl<'gc> Value<'gc> { impl<'gc> Value<'gc> { #[inline] - pub fn new_float(val: f64) -> Self { + #[allow(private_bounds)] + pub fn new(val: T) -> Self { Self { - raw: RawBox::from_float(val), + raw: val.to_raw_box(), _marker: PhantomData, } } - #[inline] - #[allow(private_bounds)] - pub fn new_inline(val: T) -> Self { - Self::from_raw_value(RawValue::store(T::TAG, val)) - } - - #[inline] - #[allow(private_bounds)] - pub fn new_gc(gc: Gc<'gc, T>) -> Self { - let ptr = Gc::as_ptr(gc); - Self::from_raw_value(RawValue::store(T::TAG, ptr)) - } - #[inline] pub fn make_int(val: i64, mc: &Mutation<'gc>) -> Self { if val >= i32::MIN as i64 && val <= i32::MAX as i64 { - Value::new_inline(val as i32) + Value::new(val as i32) } else { - Value::new_gc(Gc::new(mc, val)) - } - } -} - -impl<'gc> Value<'gc> { - #[inline] - pub fn is_float(self) -> bool { - self.raw.is_float() - } - - #[inline] - #[allow(private_bounds)] - pub fn is(self) -> bool { - self.tag() == Some(T::TAG) - } -} - -impl<'gc> Value<'gc> { - #[inline] - pub fn as_float(self) -> Option { - self.raw.float().copied() - } - - #[inline] - #[allow(private_bounds)] - pub fn as_inline(self) -> Option { - if self.is::() { - Some(unsafe { - let rv = self.raw.value().unwrap_unchecked(); - T::from_val(rv) - }) - } else { - None + Value::new(Gc::new(mc, val)) } } #[inline] - #[allow(private_bounds)] - pub fn as_gc(self) -> Option> { - if self.is::() { - Some(unsafe { - let rv = self.raw.value().unwrap_unchecked(); - let ptr: *const T = <*const T as RawStore>::from_val(rv); - Gc::from_ptr(ptr) - }) - } else { - None - } + pub fn is(self) -> bool { + T::is_value(&self) + } + + #[inline] + pub fn downcast(self) -> Option> { + self.is::().then(|| unsafe { T::from_raw(&self) }) } #[inline] @@ -252,19 +256,19 @@ impl<'gc> Value<'gc> { } #[inline] - pub fn as_num(self) -> Option { - if let Some(i) = self.as_inline::() { + pub fn downcast_num(self) -> Option { + if let Some(i) = self.downcast::() { Some(NixNum::Int(i as i64)) - } else if let Some(gc_i) = self.as_gc::() { + } else if let Some(gc_i) = self.downcast::() { Some(NixNum::Int(*gc_i)) } else { - self.as_float().map(NixNum::Float) + self.downcast::().map(NixNum::Float) } } #[inline] pub fn restrict(self) -> Result, Gc<'gc, Thunk<'gc>>> { - if let Some(thunk) = self.as_gc::>() { + if let Some(thunk) = self.downcast::() { Err(thunk) } else { Ok(StrictValue(self)) @@ -273,7 +277,7 @@ impl<'gc> Value<'gc> { #[inline] pub fn ty(self) -> NixType { - if self.is_float() { + if self.is::() { NixType::Float } else if self.is::() || self.is::() { NixType::Int @@ -305,30 +309,13 @@ impl<'gc> Value<'gc> { } #[inline] - #[allow(private_bounds)] - pub fn expect_inline(self) -> Result { - self.as_inline::().ok_or_else(|| self.ty()) - } - - #[inline] - #[allow(private_bounds)] - pub fn expect_gc(self) -> Result, NixType> { - self.as_gc::().ok_or_else(|| self.ty()) + pub fn expect(self) -> Result, NixType> { + self.downcast::().ok_or_else(|| self.ty()) } #[inline] pub fn expect_num(self) -> Result { - self.as_num().ok_or_else(|| self.ty()) - } - - #[inline] - pub fn expect_bool(self) -> Result { - self.as_inline::().ok_or_else(|| self.ty()) - } - - #[inline] - pub fn expect_float(self) -> Result { - self.as_float().ok_or_else(|| self.ty()) + self.downcast_num().ok_or_else(|| self.ty()) } } @@ -345,41 +332,22 @@ impl<'gc> From for Value<'gc> { } impl StaticValue { - #[inline] - pub fn new_float(val: f64) -> Self { - Self(Value::new_float(val)) - } #[inline] #[allow(private_bounds)] - pub fn new_inline(val: T) -> Self { - Self(Value::new_inline(val)) + pub fn new(val: T) -> Self { + Self(Value::new(val)) } + #[inline] - pub fn new_primop(id: BuiltinId, arity: u8, dispatch_ip: u32) -> Self { - Self(Value::new_inline(PrimOp { - id, - arity, - dispatch_ip, - })) - } - #[inline] - pub fn is_float(self) -> bool { - self.0.is_float() - } - #[inline] - #[allow(private_bounds)] - pub fn is(self) -> bool { + pub fn is(self) -> bool { self.0.is::() } + #[inline] - pub fn as_float(self) -> Option { - self.0.as_float() - } - #[inline] - #[allow(private_bounds)] - pub fn as_inline(self) -> Option { - self.0.as_inline::() + pub fn downcast(self) -> Option> { + self.0.downcast::() } + #[inline] pub fn to_bits(self) -> u64 { self.0.raw.to_bits() diff --git a/fix-vm/src/instructions/arithmetic.rs b/fix-vm/src/instructions/arithmetic.rs index 8a562f4..cc522d2 100644 --- a/fix-vm/src/instructions/arithmetic.rs +++ b/fix-vm/src/instructions/arithmetic.rs @@ -28,7 +28,7 @@ pub(crate) fn op_add<'gc, M: Machine<'gc>>( let combined = format!("{ls}{rs}"); let canon = canon_path_str(&combined); let sid = ctx.intern_string(canon); - m.push(Value::new_inline(fix_runtime::Path(sid))); + m.push(Value::new(fix_runtime::Path(sid))); return Step::Continue(()); } if let (Some(ls), Some(rs)) = (ctx.get_string(lhs), ctx.get_string_or_path(rhs)) { @@ -39,7 +39,7 @@ pub(crate) fn op_add<'gc, M: Machine<'gc>>( mc, crate::NixString::with_context(format!("{ls}{rs}"), merged), ); - m.push(Value::new_gc(ns)); + m.push(Value::new(ns)); return Step::Continue(()); } let res = numeric_binop(lhs, rhs, mc, i64::wrapping_add, |a, b| a + b); @@ -200,7 +200,7 @@ pub(crate) fn op_concat<'gc, M: Machine<'gc>>( let mut items = smallvec::SmallVec::new(); items.extend_from_slice(&l.inner.borrow()); items.extend_from_slice(&r.inner.borrow()); - m.push(Value::new_gc(Gc::new( + m.push(Value::new(Gc::new( mc, crate::List { inner: RefLock::new(items), @@ -216,7 +216,7 @@ pub(crate) fn op_update<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { let (l, r) = m.force_and_retry::<(Gc, Gc)>(reader, mc)?; - m.push(Value::new_gc(l.merge(&r, mc))); + m.push(Value::new(l.merge(&r, mc))); Step::Continue(()) } @@ -229,7 +229,7 @@ pub(crate) fn op_neg<'gc, M: Machine<'gc>>( let rhs = m.force_and_retry::(reader, mc)?; match rhs { NixNum::Int(int) => m.push(Value::make_int(-int, mc)), - NixNum::Float(float) => m.push(Value::new_float(-float)), + NixNum::Float(float) => m.push(Value::new(-float)), } Step::Continue(()) } @@ -241,7 +241,7 @@ pub(crate) fn op_not<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { let rhs = m.force_and_retry::(reader, mc)?; - m.push(Value::new_inline(!rhs)); + m.push(Value::new(!rhs)); Step::Continue(()) } @@ -263,17 +263,17 @@ fn compare_values_inner<'gc, M: Machine<'gc>>( a.partial_cmp(&(b as f64)).unwrap_or(Ordering::Less) } }; - m.push(Value::new_inline(pred(ord))); + m.push(Value::new(pred(ord))); return Ok(()); } if let (Some(a), Some(b)) = (ctx.get_string(lhs), ctx.get_string(rhs)) { - m.push(Value::new_inline(pred(a.cmp(b)))); + m.push(Value::new(pred(a.cmp(b)))); return Ok(()); } - if let (Some(a), Some(b)) = (lhs.as_inline::(), rhs.as_inline::()) { + if let (Some(a), Some(b)) = (lhs.downcast::(), rhs.downcast::()) { let a = ctx.resolve_string(a.0); let b = ctx.resolve_string(b.0); - m.push(Value::new_inline(pred(a.cmp(b)))); + m.push(Value::new(pred(a.cmp(b)))); return Ok(()); } // TODO: compare other types @@ -285,12 +285,12 @@ fn compare_values_inner<'gc, M: Machine<'gc>>( } pub(crate) fn get_num(val: StrictValue<'_>) -> Option { - if let Some(i) = val.as_inline::() { + if let Some(i) = val.downcast::() { Some(NixNum::Int(i64::from(i))) - } else if let Some(gc_i) = val.as_gc::() { + } else if let Some(gc_i) = val.downcast::() { Some(NixNum::Int(*gc_i)) } else { - val.as_float().map(NixNum::Float) + val.downcast::().map(NixNum::Float) } } @@ -304,13 +304,9 @@ fn numeric_binop<'gc>( ) -> crate::VmResult> { match (get_num(lhs), get_num(rhs)) { (Some(NixNum::Int(a)), Some(NixNum::Int(b))) => Ok(Value::make_int(int_op(a, b), mc)), - (Some(NixNum::Float(a)), Some(NixNum::Float(b))) => Ok(Value::new_float(float_op(a, b))), - (Some(NixNum::Int(a)), Some(NixNum::Float(b))) => { - Ok(Value::new_float(float_op(a as f64, b))) - } - (Some(NixNum::Float(a)), Some(NixNum::Int(b))) => { - Ok(Value::new_float(float_op(a, b as f64))) - } + (Some(NixNum::Float(a)), Some(NixNum::Float(b))) => Ok(Value::new(float_op(a, b))), + (Some(NixNum::Int(a)), Some(NixNum::Float(b))) => Ok(Value::new(float_op(a as f64, b))), + (Some(NixNum::Float(a)), Some(NixNum::Int(b))) => Ok(Value::new(float_op(a, b as f64))), _ => Err(crate::vm_err(format!( "cannot perform arithmetic on non-numbers: {:?}", (lhs.ty(), rhs.ty()) diff --git a/fix-vm/src/instructions/calls.rs b/fix-vm/src/instructions/calls.rs index 6c992e9..199cc3c 100644 --- a/fix-vm/src/instructions/calls.rs +++ b/fix-vm/src/instructions/calls.rs @@ -21,7 +21,7 @@ pub(crate) fn call<'gc, M: Machine<'gc>>( return m.finish_err(Error::eval_error("stack overflow; max-call-depth exceeded")); } m.inc_call_depth(); - if let Some(closure) = func.as_gc::() { + if let Some(closure) = func.downcast::() { if closure.pattern.is_some() { // FIXME: better DX... m.push(func.relax()); @@ -46,7 +46,7 @@ pub(crate) fn call<'gc, M: Machine<'gc>>( }); reader.set_pc(ip as usize); m.set_env(new_env); - } else if let Some(primop) = func.as_inline::() { + } else if let Some(primop) = func.downcast::() { if primop.arity == 1 { m.push(arg); m.push_call_frame(CallFrame { @@ -61,9 +61,9 @@ pub(crate) fn call<'gc, M: Machine<'gc>>( arity: primop.arity - 1, args: [arg, Value::default(), Value::default()], }; - m.push(Value::new_gc(Gc::new(mc, app))); + m.push(Value::new(Gc::new(mc, app))); } - } else if let Some(app) = func.as_gc::() { + } else if let Some(app) = func.downcast::() { if app.arity == 1 { for i in 0..app.primop.arity - 1 { m.push(app.args[i as usize]); @@ -82,9 +82,9 @@ pub(crate) fn call<'gc, M: Machine<'gc>>( ..*app }; new_app.args[position] = arg; - m.push(Value::new_gc(Gc::new(mc, new_app))) + m.push(Value::new(Gc::new(mc, new_app))) } - } else if let Some(attrs) = func.as_gc::() + } else if let Some(attrs) = func.downcast::() && let Some(functor) = attrs.lookup(m.functor_sym()) { // f arg => (f.__functor f) arg diff --git a/fix-vm/src/instructions/closures.rs b/fix-vm/src/instructions/closures.rs index 3e1b01f..2ce39c7 100644 --- a/fix-vm/src/instructions/closures.rs +++ b/fix-vm/src/instructions/closures.rs @@ -17,7 +17,7 @@ pub(crate) fn op_make_thunk<'gc, M: Machine<'gc>>( env: m.env(), }), ); - m.push(Value::new_gc(thunk)); + m.push(Value::new(thunk)); Step::Continue(()) } @@ -38,7 +38,7 @@ pub(crate) fn op_make_closure<'gc, M: Machine<'gc>>( pattern: None, }, ); - m.push(Value::new_gc(closure)); + m.push(Value::new(closure)); Step::Continue(()) } @@ -88,6 +88,6 @@ pub(crate) fn op_make_pattern_closure<'gc, M: Machine<'gc>>( pattern: Some(pattern), }, ); - m.push(Value::new_gc(closure)); + m.push(Value::new(closure)); Step::Continue(()) } diff --git a/fix-vm/src/instructions/collections.rs b/fix-vm/src/instructions/collections.rs index e4d24e3..726380d 100644 --- a/fix-vm/src/instructions/collections.rs +++ b/fix-vm/src/instructions/collections.rs @@ -57,7 +57,7 @@ pub(crate) fn op_make_attrs<'gc, M: Machine<'gc>>( kv.sort_by_key(|(k, _)| *k); let attrs = Gc::new(mc, AttrSet::from_sorted_unchecked(kv)); - m.push(Value::new_gc(attrs)); + m.push(Value::new(attrs)); Step::Continue(()) } @@ -195,7 +195,7 @@ pub(crate) fn op_has_attr_path_static<'gc, M: Machine<'gc>>( let current = m.force_and_retry::(reader, mc)?; match current - .as_gc::() + .downcast::() .and_then(|attrs| attrs.lookup(key)) { Some(v) => { @@ -223,7 +223,7 @@ pub(crate) fn op_has_attr_path_dynamic<'gc, M: Machine<'gc>>( }; match current - .as_gc::() + .downcast::() .and_then(|attrs| attrs.lookup(key_sid)) { Some(v) => { @@ -263,9 +263,9 @@ pub(crate) fn op_has_attr_static<'gc, M: Machine<'gc>>( let key = reader.read_string_id(); let current = m.force_and_retry::(reader, mc)?; - m.push(Value::new_inline( + m.push(Value::new( current - .as_gc::() + .downcast::() .and_then(|attrs| attrs.lookup(key)) .is_some(), )); @@ -289,9 +289,9 @@ pub(crate) fn op_has_attr_dynamic<'gc, M: MachineExt<'gc>>( Err(got) => return m.finish_type_err(NixType::String, got), }; - m.push(Value::new_inline( + m.push(Value::new( current - .as_gc::() + .downcast::() .and_then(|attrs| attrs.lookup(key_sid)) .is_some(), )); @@ -304,7 +304,7 @@ pub(crate) fn op_has_attr_dynamic<'gc, M: MachineExt<'gc>>( #[inline(always)] pub(crate) fn op_has_attr_resolve<'gc, M: Machine<'gc>>(m: &mut M) -> Step { // If we reach here, has_attr check has failed, push false (AttrSet is already popped) - m.push(Value::new_inline(false)); + m.push(Value::new(false)); Step::Continue(()) } @@ -326,7 +326,7 @@ pub(crate) fn op_make_list<'gc, M: Machine<'gc>>( inner: RefLock::new(items), }, ); - m.push(Value::new_gc(list)); + m.push(Value::new(list)); Step::Continue(()) } diff --git a/fix-vm/src/instructions/control.rs b/fix-vm/src/instructions/control.rs index 67fca78..f478e4a 100644 --- a/fix-vm/src/instructions/control.rs +++ b/fix-vm/src/instructions/control.rs @@ -12,7 +12,7 @@ pub(crate) fn op_jump_if_false<'gc, M: Machine<'gc>>( ) -> Step { let offset = reader.read_i32(); let cond = m.force_and_retry::(reader, mc)?; - if cond.as_inline::() == Some(false) { + if cond.downcast::() == Some(false) { reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize); } Step::Continue(()) @@ -26,7 +26,7 @@ pub(crate) fn op_jump_if_true<'gc, M: Machine<'gc>>( ) -> Step { let offset = reader.read_i32(); let cond = m.force_and_retry::(reader, mc)?; - if cond.as_inline::() == Some(true) { + if cond.downcast::() == Some(true) { reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize); } Step::Continue(()) diff --git a/fix-vm/src/instructions/literals.rs b/fix-vm/src/instructions/literals.rs index 802ccd4..293509c 100644 --- a/fix-vm/src/instructions/literals.rs +++ b/fix-vm/src/instructions/literals.rs @@ -9,7 +9,7 @@ pub(crate) fn op_push_smi<'gc, M: Machine<'gc>>( reader: &mut BytecodeReader<'_>, ) -> Step { let val = reader.read_i32(); - m.push(Value::new_inline(val)); + m.push(Value::new(val)); Step::Continue(()) } @@ -20,7 +20,7 @@ pub(crate) fn op_push_bigint<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { let val = reader.read_i64(); - m.push(Value::new_gc(Gc::new(mc, val))); + m.push(Value::new(Gc::new(mc, val))); Step::Continue(()) } @@ -30,7 +30,7 @@ pub(crate) fn op_push_float<'gc, M: Machine<'gc>>( reader: &mut BytecodeReader<'_>, ) -> Step { let val = reader.read_f64(); - m.push(Value::new_float(val)); + m.push(Value::new(val)); Step::Continue(()) } @@ -40,24 +40,24 @@ pub(crate) fn op_push_string<'gc, M: Machine<'gc>>( reader: &mut BytecodeReader<'_>, ) -> Step { let sid = reader.read_string_id(); - m.push(Value::new_inline(sid)); + m.push(Value::new(sid)); Step::Continue(()) } #[inline(always)] pub(crate) fn op_push_null<'gc, M: Machine<'gc>>(m: &mut M) -> Step { - m.push(Value::new_inline(crate::Null)); + m.push(Value::new(crate::Null)); Step::Continue(()) } #[inline(always)] pub(crate) fn op_push_true<'gc, M: Machine<'gc>>(m: &mut M) -> Step { - m.push(Value::new_inline(true)); + m.push(Value::new(true)); Step::Continue(()) } #[inline(always)] pub(crate) fn op_push_false<'gc, M: Machine<'gc>>(m: &mut M) -> Step { - m.push(Value::new_inline(false)); + m.push(Value::new(false)); Step::Continue(()) } diff --git a/fix-vm/src/instructions/misc.rs b/fix-vm/src/instructions/misc.rs index e763eab..8a662d3 100644 --- a/fix-vm/src/instructions/misc.rs +++ b/fix-vm/src/instructions/misc.rs @@ -22,7 +22,7 @@ pub(crate) fn op_load_builtin<'gc, M: Machine<'gc>>( ) -> Step { let Ok(id) = BuiltinId::try_from(reader.read_u8()) .map_err(|err| panic!("unknown builtin id: {}", err.number)); - m.push(Value::new_inline(PrimOp { + m.push(Value::new(PrimOp { id, arity: BUILTINS[id as usize].1, dispatch_ip: Continuation::entry_for_builtin(id).ip(), @@ -49,7 +49,7 @@ pub(crate) fn op_load_scoped_binding<'gc, M: Machine<'gc>>( let slot_id = reader.read_u32(); let name = reader.read_string_id(); let scope = m.scope_slot(slot_id); - let Some(attrs) = scope.as_gc::() else { + let Some(attrs) = scope.downcast::() else { return m.finish_err(Error::eval_error("internal: scope slot is not an attrset")); }; match attrs.lookup(name) { @@ -73,10 +73,10 @@ pub(crate) fn op_coerce_to_string<'gc, M: Machine<'gc>>( let val = m.force_and_retry::(reader, mc)?; if val.is::() || val.is::() { m.push(val.relax()); - } else if let Some(p) = val.as_inline::() { + } else if let Some(p) = val.downcast::() { // Coercing a path to a string yields the canonical path text. // FIXME: copy to store - m.push(Value::new_inline(p.0)); + m.push(Value::new(p.0)); } else { todo!("coerce other types to string: {:?}", val.ty()); } @@ -122,10 +122,10 @@ pub(crate) fn op_concat_strings<'gc, M: Machine<'gc>>( if merged.is_empty() { let sid = ctx.intern_string(result); - m.push(Value::new_inline(sid)); + m.push(Value::new(sid)); } else { let ns = gc_arena::Gc::new(mc, NixString::with_context(result, merged)); - m.push(Value::new_gc(ns)); + m.push(Value::new(ns)); } Step::Continue(()) } @@ -140,8 +140,8 @@ pub(crate) fn op_resolve_path<'gc, M: MachineExt<'gc>>( let path_val = m.force_and_retry::(reader, mc)?; let dir_id = reader.read_string_id(); // Already a path: keep as-is. ResolvePath is idempotent on paths. - if let Some(p) = path_val.as_inline::() { - m.push(Value::new_inline(p)); + if let Some(p) = path_val.downcast::() { + m.push(Value::new(p)); return Step::Continue(()); } let path = match ctx.get_string(path_val) { @@ -158,7 +158,7 @@ pub(crate) fn op_resolve_path<'gc, M: MachineExt<'gc>>( Err(e) => return m.finish_err(e), }; let sid = ctx.intern_string(resolved); - m.push(Value::new_inline(Path(sid))); + m.push(Value::new(Path(sid))); Step::Continue(()) } diff --git a/fix-vm/src/instructions/with_scope.rs b/fix-vm/src/instructions/with_scope.rs index 8cba083..84fba61 100644 --- a/fix-vm/src/instructions/with_scope.rs +++ b/fix-vm/src/instructions/with_scope.rs @@ -13,7 +13,7 @@ pub(crate) fn op_lookup_with<'gc, M: Machine<'gc>>( mc: &gc_arena::Mutation<'gc>, ) -> Step { #[allow(clippy::unwrap_used)] - let counter = m.peek_forced(0).as_inline::().unwrap(); + let counter = m.peek_forced(0).downcast::().unwrap(); let name = reader.read_string_id(); let n = reader.read_u8(); @@ -57,7 +57,7 @@ pub(crate) fn op_lookup_with<'gc, M: Machine<'gc>>( }; if let Some(val) = namespace - .as_gc::() + .downcast::() .and_then(|attrs| attrs.lookup(name)) { m.replace(0, val); @@ -67,7 +67,7 @@ pub(crate) fn op_lookup_with<'gc, M: Machine<'gc>>( Symbol::from(ctx.resolve_string(name)) ))); } else { - m.replace(0, Value::new_inline(counter + 1)); + m.replace(0, Value::new(counter + 1)); reader.set_pc(resume_pc); } diff --git a/fix-vm/src/lib.rs b/fix-vm/src/lib.rs index 680a658..876a881 100644 --- a/fix-vm/src/lib.rs +++ b/fix-vm/src/lib.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; -use fix_bytecode::{InstructionPtr, Continuation}; +use fix_bytecode::{Continuation, InstructionPtr}; use fix_error::{Error, Result, Source}; use fix_lang::{BUILTINS, BuiltinId, StringId}; use gc_arena::metrics::Pacing; @@ -63,7 +63,7 @@ fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmRuntimeCtx) -> Value< let dispatch_ip = Continuation::entry_for_builtin(id).ip(); entries.push(( name, - Value::new_inline(PrimOp { + Value::new(PrimOp { id, arity, dispatch_ip, @@ -74,21 +74,15 @@ fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmRuntimeCtx) -> Value< let consts = [ ( "__currentSystem", - Value::new_inline(ctx.intern_string("x86_64-linux")), + Value::new(ctx.intern_string("x86_64-linux")), ), - ("__langVersion", Value::new_inline(6i32)), - ( - "__nixVersion", - Value::new_inline(ctx.intern_string("2.24.0")), - ), - ( - "__storeDir", - Value::new_inline(ctx.intern_string("/nix/store")), - ), - ("__nixPath", Value::new_gc(Gc::new(mc, List::default()))), - ("null", Value::new_inline(Null)), - ("true", Value::new_inline(true)), - ("false", Value::new_inline(false)), + ("__langVersion", Value::new(6i32)), + ("__nixVersion", Value::new(ctx.intern_string("2.24.0"))), + ("__storeDir", Value::new(ctx.intern_string("/nix/store"))), + ("__nixPath", Value::new(Gc::new(mc, List::default()))), + ("null", Value::new(Null)), + ("true", Value::new(true)), + ("false", Value::new(false)), ]; for (name, val) in consts { @@ -99,12 +93,12 @@ fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmRuntimeCtx) -> Value< let self_ref_thunk = Gc::new(mc, RefLock::new(ThunkState::Blackhole)); let sym = ctx.intern_string("builtins"); - entries.push((sym, Value::new_gc(self_ref_thunk))); + entries.push((sym, Value::new(self_ref_thunk))); entries.sort_by_key(|(k, _)| *k); let builtins_set = Gc::new(mc, AttrSet::from_sorted_unchecked(entries)); - let builtins_value = Value::new_gc(builtins_set); + let builtins_value = Value::new(builtins_set); *self_ref_thunk.borrow_mut(mc) = ThunkState::Evaluated(builtins_value.restrict().expect("builtins is not a thunk")); builtins_value @@ -125,8 +119,8 @@ impl<'gc> Vm<'gc> { scope_slots: Vec::new(), builtins, - empty_list: Value::new_gc(Gc::new(mc, List::default())), - empty_attrs: Value::new_gc(Gc::new(mc, AttrSet::default())), + empty_list: Value::new(Gc::new(mc, List::default())), + empty_attrs: Value::new(Gc::new(mc, AttrSet::default())), force_mode, @@ -202,7 +196,7 @@ impl<'gc> Machine<'gc> for Vm<'gc> { mc: &Mutation<'gc>, resume_pc: usize, ) -> Step { - let Some(thunk) = self.peek(depth).as_gc::() else { + let Some(thunk) = self.peek(depth).downcast::() else { return Step::Continue(()); }; let mut state = thunk.borrow_mut(mc); diff --git a/fix-vm/src/primops/context.rs b/fix-vm/src/primops/context.rs index d03f095..f80e2f0 100644 --- a/fix-vm/src/primops/context.rs +++ b/fix-vm/src/primops/context.rs @@ -22,11 +22,11 @@ pub fn has_context<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { let val = m.force_and_retry::(reader, mc)?; - if !val.is::() && val.as_gc::().is_none() { + if !val.is::() && val.downcast::().is_none() { return m.finish_type_err(NixType::String, val.ty()); } let has_ctx = !ctx.get_string_context(val).is_empty(); - m.return_from_primop(Value::new_inline(has_ctx), reader) + m.return_from_primop(Value::new(has_ctx), reader) } pub fn unsafe_discard_string_context<'gc, M: Machine<'gc>>( @@ -36,14 +36,14 @@ pub fn unsafe_discard_string_context<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { let val = m.force_and_retry::(reader, mc)?; - if let Some(sid) = val.as_inline::() { - return m.return_from_primop(Value::new_inline(sid), reader); + if let Some(sid) = val.downcast::() { + return m.return_from_primop(Value::new(sid), reader); } - let Some(ns) = val.as_gc::() else { + let Some(ns) = val.downcast::() else { return m.finish_type_err(NixType::String, val.ty()); }; let sid = ctx.intern_string(ns.as_str()); - m.return_from_primop(Value::new_inline(sid), reader) + m.return_from_primop(Value::new(sid), reader) } pub fn unsafe_discard_output_dependency<'gc, M: Machine<'gc>>( @@ -53,15 +53,15 @@ pub fn unsafe_discard_output_dependency<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { let val = m.force_and_retry::(reader, mc)?; - if let Some(sid) = val.as_inline::() { - return m.return_from_primop(Value::new_inline(sid), reader); + if let Some(sid) = val.downcast::() { + return m.return_from_primop(Value::new(sid), reader); } - let Some(ns) = val.as_gc::() else { + let Some(ns) = val.downcast::() else { return m.finish_type_err(NixType::String, val.ty()); }; if ns.context().is_empty() { let sid = ctx.intern_string(ns.as_str()); - return m.return_from_primop(Value::new_inline(sid), reader); + return m.return_from_primop(Value::new(sid), reader); } let mut new_ctx = StringContext::new(); @@ -77,7 +77,7 @@ pub fn unsafe_discard_output_dependency<'gc, M: Machine<'gc>>( let s: Box = ns.as_str().into(); let new_ns = Gc::new(mc, NixString::with_context(s, new_ctx)); - m.return_from_primop(Value::new_gc(new_ns), reader) + m.return_from_primop(Value::new(new_ns), reader) } pub fn get_context<'gc, M: Machine<'gc>>( @@ -87,7 +87,7 @@ pub fn get_context<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { let val = m.force_and_retry::(reader, mc)?; - if !val.is::() && val.as_gc::().is_none() { + if !val.is::() && val.downcast::().is_none() { return m.finish_type_err(NixType::String, val.ty()); } let elems = ctx.get_string_context(val); @@ -135,29 +135,29 @@ pub fn get_context<'gc, M: Machine<'gc>>( let mut sub: SmallVec<[(StringId, Value<'gc>); 4]> = SmallVec::new(); if info.all_outputs { - sub.push((ctx.intern_string("allOutputs"), Value::new_inline(true))); + sub.push((ctx.intern_string("allOutputs"), Value::new(true))); } if !info.outputs.is_empty() { let items: smallvec::SmallVec<[Value<'gc>; 4]> = info .outputs .iter() - .map(|o| Value::new_inline(ctx.intern_string(o))) + .map(|o| Value::new(ctx.intern_string(o))) .collect(); let list = VmList::new(mc, items); - sub.push((ctx.intern_string("outputs"), Value::new_gc(list))); + sub.push((ctx.intern_string("outputs"), Value::new(list))); } if info.path { - sub.push((ctx.intern_string("path"), Value::new_inline(true))); + sub.push((ctx.intern_string("path"), Value::new(true))); } sub.sort_by_key(|(k, _)| *k); let sub_attrs = Gc::new(mc, AttrSet::from_sorted_unchecked(sub)); - outer_entries.push((ctx.intern_string(&path), Value::new_gc(sub_attrs))); + outer_entries.push((ctx.intern_string(&path), Value::new(sub_attrs))); } outer_entries.sort_by_key(|(k, _)| *k); let outer = Gc::new(mc, AttrSet::from_sorted_unchecked(outer_entries)); - m.return_from_primop(Value::new_gc(outer), reader) + m.return_from_primop(Value::new(outer), reader) } /// appendContext :: String -> AttrSet -> String @@ -192,9 +192,9 @@ pub fn append_context<'gc, M: Machine<'gc>>( let acc = Gc::new(mc, NixString::with_context("", initial_ctx)); m.push(str_val.relax()); - m.push(Value::new_gc(attrs)); - m.push(Value::new_inline(0i32)); - m.push(Value::new_gc(acc)); + m.push(Value::new(attrs)); + m.push(Value::new(0i32)); + m.push(Value::new(acc)); reader.set_pc(Continuation::PAppendContextLoop.ip() as usize); Step::Continue(()) @@ -207,9 +207,9 @@ pub fn append_context_loop<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { #[allow(clippy::unwrap_used)] - let idx = m.peek(1).as_inline::().unwrap(); + let idx = m.peek(1).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let attrs = m.peek_forced(2).as_gc::().unwrap(); + let attrs = m.peek_forced(2).downcast::().unwrap(); if idx as usize >= attrs.entries.len() { return append_context_finalize(m, ctx, reader, mc); @@ -238,14 +238,14 @@ pub fn append_context_entry_forced<'gc, M: Machine<'gc>>( // Evaluated value into the slot. m.force_slot(0, reader, mc)?; let entry_val = m.peek_forced(0); - let Some(entry_attrs) = entry_val.as_gc::() else { + let Some(entry_attrs) = entry_val.downcast::() else { return m.finish_type_err(NixType::AttrSet, entry_val.ty()); }; #[allow(clippy::unwrap_used)] - let idx = m.peek(2).as_inline::().unwrap(); + let idx = m.peek(2).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let outer = m.peek_forced(3).as_gc::().unwrap(); + let outer = m.peek_forced(3).downcast::().unwrap(); let path_key = outer.entries[idx as usize].0; let path_str_owned: Box = ctx.resolve_string(path_key).into(); if !path_str_owned.starts_with("/nix/store/") { @@ -263,11 +263,11 @@ pub fn append_context_entry_forced<'gc, M: Machine<'gc>>( let outputs_id = ctx.intern_string("outputs"); #[allow(clippy::unwrap_used)] - let acc_gc = m.peek(1).as_gc::().unwrap(); + let acc_gc = m.peek(1).downcast::().unwrap(); let mut new_acc: StringContext = acc_gc.context().iter().cloned().collect(); if let Some(v) = entry_attrs.lookup(path_id) - && v.as_inline::() == Some(true) + && v.downcast::() == Some(true) { new_acc.insert(StringContextElem::Opaque { path: path_str_owned.clone(), @@ -275,7 +275,7 @@ pub fn append_context_entry_forced<'gc, M: Machine<'gc>>( } if let Some(v) = entry_attrs.lookup(all_outputs_id) - && v.as_inline::() == Some(true) + && v.downcast::() == Some(true) { if !path_str_owned.ends_with(".drv") { return m.finish_err(Error::eval_error(format!( @@ -288,7 +288,7 @@ pub fn append_context_entry_forced<'gc, M: Machine<'gc>>( } let new_acc_gc = Gc::new(mc, NixString::with_context("", new_acc)); - m.replace(1, Value::new_gc(new_acc_gc)); + m.replace(1, Value::new(new_acc_gc)); if let Some(outputs_val) = entry_attrs.lookup(outputs_id) { m.replace(0, outputs_val); @@ -304,8 +304,8 @@ pub fn append_context_entry_forced<'gc, M: Machine<'gc>>( let _ = m.pop(); #[allow(clippy::unwrap_used)] - let idx_back = m.peek(1).as_inline::().unwrap(); - m.replace(1, Value::new_inline(idx_back + 1)); + let idx_back = m.peek(1).downcast::().unwrap(); + m.replace(1, Value::new(idx_back + 1)); reader.set_pc(Continuation::PAppendContextLoop.ip() as usize); Step::Continue(()) } @@ -318,20 +318,20 @@ pub fn append_context_outputs_forced<'gc, M: Machine<'gc>>( ) -> Step { m.force_slot(0, reader, mc)?; let list_val = m.peek_forced(0); - let Some(list) = list_val.as_gc::() else { + let Some(list) = list_val.downcast::() else { return m.finish_type_err(NixType::List, list_val.ty()); }; if list.inner.borrow().is_empty() { // Stack: [strVal, attrs, idx, acc, list] -> drop list, bump idx. let _ = m.pop(); #[allow(clippy::unwrap_used)] - let idx_back = m.peek(1).as_inline::().unwrap(); - m.replace(1, Value::new_inline(idx_back + 1)); + let idx_back = m.peek(1).downcast::().unwrap(); + m.replace(1, Value::new(idx_back + 1)); reader.set_pc(Continuation::PAppendContextLoop.ip() as usize); return Step::Continue(()); } - m.push(Value::new_inline(0i32)); + m.push(Value::new(0i32)); reader.set_pc(Continuation::PAppendContextOutputElementLoop.ip() as usize); Step::Continue(()) } @@ -343,9 +343,9 @@ pub fn append_context_output_element_loop<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { #[allow(clippy::unwrap_used)] - let oidx = m.peek(0).as_inline::().unwrap(); + let oidx = m.peek(0).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let list = m.peek_forced(1).as_gc::().unwrap(); + let list = m.peek_forced(1).downcast::().unwrap(); let len = list.inner.borrow().len(); if oidx as usize >= len { // Stack: [strVal, attrs, idx, acc, list, oidx] -> drop oidx & list, @@ -353,8 +353,8 @@ pub fn append_context_output_element_loop<'gc, M: Machine<'gc>>( let _ = m.pop(); let _ = m.pop(); #[allow(clippy::unwrap_used)] - let idx_back = m.peek(1).as_inline::().unwrap(); - m.replace(1, Value::new_inline(idx_back + 1)); + let idx_back = m.peek(1).downcast::().unwrap(); + m.replace(1, Value::new(idx_back + 1)); reader.set_pc(Continuation::PAppendContextLoop.ip() as usize); return Step::Continue(()); } @@ -385,9 +385,9 @@ pub fn append_context_output_element_forced<'gc, M: Machine<'gc>>( let output_name: Box = output_name.into(); #[allow(clippy::unwrap_used)] - let idx = m.peek(4).as_inline::().unwrap(); + let idx = m.peek(4).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let outer = m.peek_forced(5).as_gc::().unwrap(); + let outer = m.peek_forced(5).downcast::().unwrap(); let path_key = outer.entries[idx as usize].0; let path_str: Box = ctx.resolve_string(path_key).into(); if !path_str.ends_with(".drv") { @@ -397,21 +397,21 @@ pub fn append_context_output_element_forced<'gc, M: Machine<'gc>>( } #[allow(clippy::unwrap_used)] - let acc_gc = m.peek(3).as_gc::().unwrap(); + let acc_gc = m.peek(3).downcast::().unwrap(); let mut new_acc: StringContext = acc_gc.context().iter().cloned().collect(); new_acc.insert(StringContextElem::Built { drv_path: path_str, output: output_name, }); let new_acc_gc = Gc::new(mc, NixString::with_context("", new_acc)); - m.replace(3, Value::new_gc(new_acc_gc)); + m.replace(3, Value::new(new_acc_gc)); // Stack: [strVal, attrs, idx, acc, list, oidx, outElem] -> drop outElem, // bump oidx in place. let _ = m.pop(); #[allow(clippy::unwrap_used)] - let oidx = m.peek(0).as_inline::().unwrap(); - m.replace(0, Value::new_inline(oidx + 1)); + let oidx = m.peek(0).downcast::().unwrap(); + m.replace(0, Value::new(oidx + 1)); reader.set_pc(Continuation::PAppendContextOutputElementLoop.ip() as usize); Step::Continue(()) } @@ -424,7 +424,7 @@ fn append_context_finalize<'gc, M: Machine<'gc>>( ) -> Step { // Stack: [strVal, attrs, idx, acc] #[allow(clippy::unwrap_used)] - let acc_gc = m.pop().as_gc::().unwrap(); + let acc_gc = m.pop().downcast::().unwrap(); let _ = m.pop(); // idx let _ = m.pop(); // attrs let str_val_raw = m.pop(); @@ -438,10 +438,10 @@ fn append_context_finalize<'gc, M: Machine<'gc>>( let context: StringContext = acc_gc.context().iter().cloned().collect(); let result = if context.is_empty() { let sid = ctx.intern_string(s_str); - Value::new_inline(sid) + Value::new(sid) } else { let ns = Gc::new(mc, NixString::with_context(s_str, context)); - Value::new_gc(ns) + Value::new(ns) }; m.return_from_primop(result, reader) } diff --git a/fix-vm/src/primops/control.rs b/fix-vm/src/primops/control.rs index ee6ce9d..c36672a 100644 --- a/fix-vm/src/primops/control.rs +++ b/fix-vm/src/primops/control.rs @@ -44,14 +44,14 @@ pub fn deep_seq_force_top<'gc, M: Machine<'gc>>( let e1 = m.peek_forced(1); - let children: SmallVec<_> = if let Some(attrs) = e1.as_gc::() { + let children: SmallVec<_> = if let Some(attrs) = e1.downcast::() { let attrs = &attrs.entries; if attrs.is_empty() { SmallVec::new() } else { attrs.iter().map(|&(_, v)| v).collect() } - } else if let Some(list) = e1.as_gc::>() { + } else if let Some(list) = e1.downcast::() { let inner = list.inner.borrow(); if inner.is_empty() { SmallVec::new() @@ -69,15 +69,15 @@ pub fn deep_seq_force_top<'gc, M: Machine<'gc>>( } let count = children.len() as i32; - let seen: Gc<'gc, List<'gc>> = Gc::new(mc, List::default()); - let worklist: Gc<'gc, List<'gc>> = List::new(mc, children); + let seen = Gc::new(mc, List::default()); + let worklist = List::new(mc, children); let e2 = m.pop(); let _ = m.pop(); m.push(e2); - m.push(Value::new_gc(seen)); - m.push(Value::new_gc(worklist)); - m.push(Value::new_inline(count)); + m.push(Value::new(seen)); + m.push(Value::new(worklist)); + m.push(Value::new(count)); reader.set_pc(Continuation::PDeepSeqPush.ip() as usize); Step::Continue(()) } @@ -89,7 +89,7 @@ pub fn deep_seq_push<'gc, M: Machine<'gc>>( ) -> Step { // stack: [e2, seen, worklist, counter] #[allow(clippy::unwrap_used)] - let counter = m.peek(0).as_inline::().unwrap(); + let counter = m.peek(0).downcast::().unwrap(); if counter == 0 { let _ = m.pop(); // counter let _ = m.pop(); // worklist @@ -99,10 +99,10 @@ pub fn deep_seq_push<'gc, M: Machine<'gc>>( } #[allow(clippy::unwrap_used)] - let worklist = m.peek_forced(1).as_gc::>().unwrap(); + let worklist = m.peek_forced(1).downcast::().unwrap(); #[allow(clippy::unwrap_used)] let item = worklist.unlock(mc).borrow_mut().pop().unwrap(); - m.replace(0, Value::new_inline(counter - 1)); + m.replace(0, Value::new(counter - 1)); m.push(item); // force item at TOS, resume at DeepSeqLoop after force @@ -119,17 +119,17 @@ pub fn deep_seq_loop<'gc, M: Machine<'gc>>( // stack after pop: [e2, seen, worklist, counter] let item = m.pop(); #[allow(clippy::unwrap_used)] - let counter = m.peek(0).as_inline::().unwrap(); + let counter = m.peek(0).downcast::().unwrap(); let mut added: usize = 0; - if let Some(attrs) = item.as_gc::() { + if let Some(attrs) = item.downcast::() { let attrs = &attrs.entries; #[allow(clippy::unwrap_used)] - let seen = m.peek_forced(2).as_gc::>().unwrap(); + let seen = m.peek_forced(2).downcast::().unwrap(); if !is_value_in_seen(seen, item) { add_value_to_seen(seen, mc, item); #[allow(clippy::unwrap_used)] - let worklist = m.peek_forced(1).as_gc::>().unwrap(); + let worklist = m.peek_forced(1).downcast::().unwrap(); { let mut wl = worklist.unlock(mc).borrow_mut(); for &(_, v) in attrs.iter() { @@ -138,13 +138,13 @@ pub fn deep_seq_loop<'gc, M: Machine<'gc>>( added = attrs.len(); } } - } else if let Some(list) = item.as_gc::>() { + } else if let Some(list) = item.downcast::() { #[allow(clippy::unwrap_used)] - let seen = m.peek_forced(2).as_gc::>().unwrap(); + let seen = m.peek_forced(2).downcast::().unwrap(); if !is_value_in_seen(seen, item) { add_value_to_seen(seen, mc, item); #[allow(clippy::unwrap_used)] - let worklist = m.peek_forced(1).as_gc::>().unwrap(); + let worklist = m.peek_forced(1).downcast::().unwrap(); { let inner = list.inner.borrow(); let mut wl = worklist.unlock(mc).borrow_mut(); @@ -156,7 +156,7 @@ pub fn deep_seq_loop<'gc, M: Machine<'gc>>( } } - m.replace(0, Value::new_inline(counter + added as i32)); + m.replace(0, Value::new(counter + added as i32)); reader.set_pc(Continuation::PDeepSeqPush.ip() as usize); Step::Continue(()) } @@ -170,10 +170,10 @@ pub fn force_result_shallow<'gc, M: Machine<'gc>>( m.force_slot(0, reader, mc)?; let val = m.peek_forced(0); - let (count, has_children) = if let Some(attrs) = val.as_gc::() { + let (count, has_children) = if let Some(attrs) = val.downcast::() { let len = attrs.entries.len(); (len, len > 0) - } else if let Some(list) = val.as_gc::>() { + } else if let Some(list) = val.downcast::() { let len = list.inner.borrow().len(); (len, len > 0) } else { @@ -185,8 +185,8 @@ pub fn force_result_shallow<'gc, M: Machine<'gc>>( return m.finish_ok(ctx.convert_value(val)); } - m.push(Value::new_inline(0i32)); - m.push(Value::new_inline(count as i32)); + m.push(Value::new(0i32)); + m.push(Value::new(count as i32)); reader.set_pc(Continuation::ForceResultShallowPush.ip() as usize); Step::Continue(()) } @@ -198,9 +198,9 @@ pub fn force_result_shallow_push<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { #[allow(clippy::unwrap_used)] - let idx = m.peek(1).as_inline::().unwrap(); + let idx = m.peek(1).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let len = m.peek(0).as_inline::().unwrap(); + let len = m.peek(0).downcast::().unwrap(); if idx == len { let _ = m.pop(); // len @@ -210,16 +210,16 @@ pub fn force_result_shallow_push<'gc, M: Machine<'gc>>( } let val = m.peek_forced(2); - let child = if let Some(attrs) = val.as_gc::() { + let child = if let Some(attrs) = val.downcast::() { attrs.entries.get(idx as usize).map(|&(_, v)| v) - } else if let Some(list) = val.as_gc::>() { + } else if let Some(list) = val.downcast::() { list.inner.borrow().get(idx as usize).copied() } else { None }; if let Some(child) = child { - m.replace(1, Value::new_inline(idx + 1)); + m.replace(1, Value::new(idx + 1)); m.push(child); m.force_slot_to_pc( 0, @@ -349,7 +349,7 @@ pub fn call_pattern<'gc, M: Machine<'gc>>( let new_env = Gc::new( mc, - RefLock::new(Env::with_arg(Value::new_gc(attrset), n_locals, env)), + RefLock::new(Env::with_arg(Value::new(attrset), n_locals, env)), ); reader.set_pc(ip as usize); m.set_env(new_env); diff --git a/fix-vm/src/primops/conv.rs b/fix-vm/src/primops/conv.rs index 4dbf8cb..6b36919 100644 --- a/fix-vm/src/primops/conv.rs +++ b/fix-vm/src/primops/conv.rs @@ -16,8 +16,8 @@ pub fn to_string<'gc, M: Machine<'gc>>( if val.is::() || val.is::() { return m.return_from_primop(val.relax(), reader); } - if let Some(p) = val.as_inline::() { - return m.return_from_primop(Value::new_inline(p.0), reader); + if let Some(p) = val.downcast::() { + return m.return_from_primop(Value::new(p.0), reader); } // TODO: derivations / `__toString` / `outPath`, // numbers, lists. @@ -47,5 +47,5 @@ pub fn type_of<'gc, M: Machine<'gc>>( NixType::Thunk => unreachable!("forced"), }; let sid = ctx.intern_string(name); - m.return_from_primop(Value::new_inline(sid), reader) + m.return_from_primop(Value::new(sid), reader) } diff --git a/fix-vm/src/primops/eq.rs b/fix-vm/src/primops/eq.rs index 798ee62..a19d50d 100644 --- a/fix-vm/src/primops/eq.rs +++ b/fix-vm/src/primops/eq.rs @@ -17,11 +17,11 @@ pub fn start_eq<'gc, M: Machine<'gc>>( ) -> Step { match shallow_eq(ctx, lhs, rhs) { ShallowEq::True => { - m.push(Value::new_inline(!negate)); + m.push(Value::new(!negate)); Step::Continue(()) } ShallowEq::False => { - m.push(Value::new_inline(negate)); + m.push(Value::new(negate)); Step::Continue(()) } ShallowEq::RecurseList(la, lb) => { @@ -44,15 +44,15 @@ pub fn eq_step<'gc, M: Machine<'gc>>( ) -> Step { let rhs_q = m .peek(0) - .as_gc::>() + .downcast::() .expect("eq state corrupted: rhs_queue"); let lhs_q = m .peek(1) - .as_gc::>() + .downcast::() .expect("eq state corrupted: lhs_queue"); let result = m .peek(2) - .as_inline::() + .downcast::() .expect("eq state corrupted: result"); if !result || lhs_q.inner.borrow().is_empty() { @@ -92,13 +92,13 @@ fn finalize<'gc, M: Machine<'gc>>(m: &mut M, reader: &mut BytecodeReader<'_>) -> let _ = m.pop(); let result = m .pop() - .as_inline::() + .downcast::() .expect("eq state corrupted: result"); let negate = m .pop() - .as_inline::() + .downcast::() .expect("eq state corrupted: negate"); - m.return_from_primop(Value::new_inline(result ^ negate), reader) + m.return_from_primop(Value::new(result ^ negate), reader) } fn apply_pair<'gc, M: Machine<'gc>>( @@ -111,7 +111,7 @@ fn apply_pair<'gc, M: Machine<'gc>>( match shallow_eq(ctx, lhs, rhs) { ShallowEq::True => {} ShallowEq::False => { - m.replace(2, Value::new_inline(false)); + m.replace(2, Value::new(false)); } ShallowEq::RecurseList(la, lb) => { extend_queues( @@ -140,11 +140,11 @@ where { let rhs_q = m .peek(0) - .as_gc::>() + .downcast::() .expect("eq state corrupted: rhs_queue"); let lhs_q = m .peek(1) - .as_gc::>() + .downcast::() .expect("eq state corrupted: lhs_queue"); let mut lq = lhs_q.unlock(mc).borrow_mut(); let mut rq = rhs_q.unlock(mc).borrow_mut(); @@ -169,10 +169,10 @@ fn enter_eq_machine<'gc, M: Machine<'gc>>( env: m.env(), }); m.inc_call_depth(); - m.push(Value::new_inline(negate)); - m.push(Value::new_inline(true)); - m.push(Value::new_gc(List::new(mc, lhs_init))); - m.push(Value::new_gc(List::new(mc, rhs_init))); + m.push(Value::new(negate)); + m.push(Value::new(true)); + m.push(Value::new(List::new(mc, lhs_init))); + m.push(Value::new(List::new(mc, rhs_init))); reader.set_pc(Continuation::EqStep.ip() as usize); Step::Continue(()) } @@ -189,7 +189,7 @@ fn shallow_eq<'gc>( lhs: StrictValue<'gc>, rhs: StrictValue<'gc>, ) -> ShallowEq<'gc> { - if let (Some(a), Some(b)) = (lhs.as_num(), rhs.as_num()) { + if let (Some(a), Some(b)) = (lhs.downcast_num(), rhs.downcast_num()) { let eq = match (a, b) { (NixNum::Int(a), NixNum::Int(b)) => a == b, (NixNum::Float(a), NixNum::Float(b)) => a == b, @@ -198,25 +198,28 @@ fn shallow_eq<'gc>( }; return bool_outcome(eq); } - if let (Some(a), Some(b)) = (lhs.as_inline::(), rhs.as_inline::()) { + if let (Some(a), Some(b)) = (lhs.downcast::(), rhs.downcast::()) { return bool_outcome(a == b); } if lhs.is::() && rhs.is::() { return ShallowEq::True; } - if let (Some(a), Some(b)) = (lhs.as_inline::(), rhs.as_inline::()) { + if let (Some(a), Some(b)) = (lhs.downcast::(), rhs.downcast::()) { return bool_outcome(a.0 == b.0); } if let (Some(a), Some(b)) = (ctx.get_string(lhs), ctx.get_string(rhs)) { return bool_outcome(a == b); } - if let (Some(a), Some(b)) = (lhs.as_gc::>(), rhs.as_gc::>()) { + if let (Some(a), Some(b)) = (lhs.downcast::(), rhs.downcast::()) { if a.inner.borrow().len() != b.inner.borrow().len() { return ShallowEq::False; } return ShallowEq::RecurseList(a, b); } - if let (Some(a), Some(b)) = (lhs.as_gc::>(), rhs.as_gc::>()) { + if let (Some(a), Some(b)) = ( + lhs.downcast::>(), + rhs.downcast::>(), + ) { let ae = &a.entries; let be = &b.entries; if ae.len() != be.len() { diff --git a/fix-vm/src/primops/io.rs b/fix-vm/src/primops/io.rs index 488f424..9171b44 100644 --- a/fix-vm/src/primops/io.rs +++ b/fix-vm/src/primops/io.rs @@ -40,7 +40,7 @@ pub fn import<'gc, M: Machine<'gc>>( // finalizer can use it as the cache key. The slot we pop here was // freed by `force_and_retry`, so we simply push. let path_sid = ctx.intern_string(abs.to_string_lossy()); - m.push(Value::new_inline(path_sid)); + m.push(Value::new(path_sid)); let env = m.env(); m.push_call_frame(CallFrame { pc: Continuation::PImportFinalize.ip() as usize, @@ -63,7 +63,7 @@ pub fn import_finalize<'gc, M: Machine<'gc>>( // stack: [path_sid, return_value] let val = m.pop(); #[allow(clippy::unwrap_used)] - let path_sid = m.pop().as_inline::().unwrap(); + let path_sid = m.pop().downcast::().unwrap(); // The cache key is keyed by the absolute path string we interned in // `import`. Resolve it back to the host PathBuf. let path_str = ctx.resolve_string(path_sid).to_owned(); @@ -107,7 +107,7 @@ pub fn scoped_import<'gc, M: Machine<'gc>>( }; let keys: HashSet = scope_attrs.entries.iter().map(|&(k, _)| k).collect(); - let slot_id = m.scope_slots_push(Value::new_gc(scope_attrs)); + let slot_id = m.scope_slots_push(Value::new(scope_attrs)); let env = m.env(); m.push_call_frame(CallFrame { @@ -146,7 +146,7 @@ pub fn path_exists<'gc, M: Machine<'gc>>( let path_val = m.force_and_retry::(reader, mc)?; // pathExists requires an absolute path. A `Path` value is // always absolute; a string is accepted only if it starts with `/`. - let (path, is_path_value) = if let Some(p) = path_val.as_inline::() { + let (path, is_path_value) = if let Some(p) = path_val.downcast::() { (ctx.resolve_string(p.0).to_owned(), true) } else if let Some(s) = ctx.get_string(path_val) { (s.to_owned(), false) @@ -171,7 +171,7 @@ pub fn path_exists<'gc, M: Machine<'gc>>( } else { std::fs::symlink_metadata(p).is_ok() }; - m.return_from_primop(Value::new_inline(exists), reader) + m.return_from_primop(Value::new(exists), reader) } /// Convert the user-supplied path string into an absolute, dotted-segment diff --git a/fix-vm/src/primops/list.rs b/fix-vm/src/primops/list.rs index 34194d0..c15687f 100644 --- a/fix-vm/src/primops/list.rs +++ b/fix-vm/src/primops/list.rs @@ -8,7 +8,7 @@ pub fn filter_force_list<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { m.force_slot(0, reader, mc)?; - let list = match m.peek_forced(0).expect_gc::() { + let list = match m.peek_forced(0).expect::() { Ok(list) => list, Err(got) => return m.finish_type_err(NixType::List, got), }; @@ -18,8 +18,8 @@ pub fn filter_force_list<'gc, M: Machine<'gc>>( return m.return_from_primop(val, reader); } // prepare stack layout: [ pred list idx acc ] - m.push(Value::new_inline(0)); - m.push(Value::new_gc(List::new_gc(mc))); + m.push(Value::new(0)); + m.push(Value::new(List::new_gc(mc))); reader.set_pc(Continuation::PFilterCallPred.ip() as usize); Step::Continue(()) } @@ -32,9 +32,9 @@ pub fn filter_call_pred<'gc, M: Machine<'gc>>( m.force_slot(3, reader, mc)?; let pred = m.peek_forced(3); #[allow(clippy::unwrap_used)] - let idx = m.peek(1).as_inline::().unwrap(); + let idx = m.peek(1).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let elem = m.peek_forced(2).as_gc::().unwrap().inner.borrow()[idx as usize]; + let elem = m.peek_forced(2).downcast::().unwrap().inner.borrow()[idx as usize]; m.push(pred.relax()); m.call(reader, mc, elem, Continuation::PFilterCheck.ip() as usize) } @@ -46,12 +46,12 @@ pub fn filter_check<'gc, M: Machine<'gc>>( ) -> Step { let ret = m.force_and_retry::(reader, mc)?; #[allow(clippy::unwrap_used)] - let idx = m.peek(1).as_inline::().unwrap(); + let idx = m.peek(1).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let list = m.peek_forced(2).as_gc::().unwrap(); + let list = m.peek_forced(2).downcast::().unwrap(); let list = list.inner.borrow(); #[allow(clippy::unwrap_used)] - let acc = m.peek_forced(0).as_gc::().unwrap(); + let acc = m.peek_forced(0).downcast::().unwrap(); if ret { let mut acc = acc.unlock(mc).borrow_mut(); acc.push(list[idx as usize]); @@ -63,7 +63,7 @@ pub fn filter_check<'gc, M: Machine<'gc>>( let _ = m.pop(); // pred return m.return_from_primop(acc, reader); } - m.replace(1, Value::new_inline(idx + 1)); + m.replace(1, Value::new(idx + 1)); reader.set_pc(Continuation::PFilterCallPred.ip() as usize); Step::Continue(()) } @@ -83,7 +83,7 @@ pub fn foldl_strict_entry<'gc, M: Machine<'gc>>( ) -> Step { m.force_slot(0, reader, mc)?; let list_val = m.peek_forced(0); - let Some(list) = list_val.as_gc::() else { + let Some(list) = list_val.downcast::() else { return m.finish_type_err(NixType::List, list_val.ty()); }; if list.inner.borrow().is_empty() { @@ -94,7 +94,7 @@ pub fn foldl_strict_entry<'gc, M: Machine<'gc>>( let list_val = m.pop(); let nul_val = m.pop(); m.push(list_val); - m.push(Value::new_inline(0i32)); + m.push(Value::new(0i32)); m.push(nul_val); reader.set_pc(Continuation::PFoldlStrictCall1.ip() as usize); Step::Continue(()) @@ -119,7 +119,12 @@ pub fn foldl_strict_call1<'gc, M: Machine<'gc>>( let op = m.peek_forced(3); let acc = m.peek(0); m.push(op.relax()); - m.call(reader, mc, acc, Continuation::PFoldlStrictCall2.ip() as usize) + m.call( + reader, + mc, + acc, + Continuation::PFoldlStrictCall2.ip() as usize, + ) } pub fn foldl_strict_call2<'gc, M: Machine<'gc>>( @@ -128,9 +133,9 @@ pub fn foldl_strict_call2<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { #[allow(clippy::unwrap_used)] - let idx = m.peek(2).as_inline::().unwrap(); + let idx = m.peek(2).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let list = m.peek_forced(3).as_gc::().unwrap(); + let list = m.peek_forced(3).downcast::().unwrap(); let elem = list.inner.borrow()[idx as usize]; m.call( reader, @@ -148,9 +153,9 @@ pub fn foldl_strict_update<'gc, M: Machine<'gc>>( let result = m.pop(); m.replace(0, result); #[allow(clippy::unwrap_used)] - let idx = m.peek(1).as_inline::().unwrap(); + let idx = m.peek(1).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let list = m.peek_forced(2).as_gc::().unwrap(); + let list = m.peek_forced(2).downcast::().unwrap(); let len = list.inner.borrow().len(); if (idx as usize) + 1 == len { let acc = m.pop(); @@ -159,7 +164,7 @@ pub fn foldl_strict_update<'gc, M: Machine<'gc>>( let _ = m.pop(); // op return m.return_from_primop(acc, reader); } - m.replace(1, Value::new_inline(idx + 1)); + m.replace(1, Value::new(idx + 1)); reader.set_pc(Continuation::PFoldlStrictCall1.ip() as usize); Step::Continue(()) } @@ -170,7 +175,7 @@ pub fn all_entry<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { m.force_slot(0, reader, mc)?; - let list = match m.peek_forced(0).expect_gc::() { + let list = match m.peek_forced(0).expect::() { Ok(list) => list, Err(got) => return m.finish_type_err(NixType::List, got), }; @@ -179,10 +184,10 @@ pub fn all_entry<'gc, M: Machine<'gc>>( if list.inner.borrow().is_empty() { let _list = m.pop(); let _pred = m.pop(); - return m.return_from_primop(Value::new_inline(true), reader); + return m.return_from_primop(Value::new(true), reader); } // prepare stack layout: [ pred list idx ] - m.push(Value::new_inline(0)); + m.push(Value::new(0)); reader.set_pc(Continuation::PAllCallPred.ip() as usize); Step::Continue(()) } @@ -194,9 +199,9 @@ pub fn all_call_pred<'gc, M: Machine<'gc>>( ) -> Step { let pred = m.peek_forced(2); #[allow(clippy::unwrap_used)] - let idx = m.peek(0).as_inline::().unwrap(); + let idx = m.peek(0).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let elem = m.peek_forced(1).as_gc::().unwrap().inner.borrow()[idx as usize]; + let elem = m.peek_forced(1).downcast::().unwrap().inner.borrow()[idx as usize]; m.push(pred.relax()); m.call(reader, mc, elem, Continuation::PAllCheck.ip() as usize) } @@ -208,17 +213,17 @@ pub fn all_check<'gc, M: Machine<'gc>>( ) -> Step { let ret = m.force_and_retry::(reader, mc)?; #[allow(clippy::unwrap_used)] - let idx = m.peek(0).as_inline::().unwrap(); + let idx = m.peek(0).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let list = m.peek_forced(1).as_gc::().unwrap(); + let list = m.peek_forced(1).downcast::().unwrap(); let list = list.inner.borrow(); if idx as usize == list.len() - 1 || !ret { let _ = m.pop(); // idx let _ = m.pop(); // list let _ = m.pop(); // pred - return m.return_from_primop(Value::new_inline(ret), reader); + return m.return_from_primop(Value::new(ret), reader); } - m.replace(0, Value::new_inline(idx + 1)); + m.replace(0, Value::new(idx + 1)); reader.set_pc(Continuation::PAllCallPred.ip() as usize); Step::Continue(()) } @@ -229,7 +234,7 @@ pub fn any_entry<'gc, M: Machine<'gc>>( mc: &Mutation<'gc>, ) -> Step { m.force_slot(0, reader, mc)?; - let list = match m.peek_forced(0).expect_gc::() { + let list = match m.peek_forced(0).expect::() { Ok(list) => list, Err(got) => return m.finish_type_err(NixType::List, got), }; @@ -238,10 +243,10 @@ pub fn any_entry<'gc, M: Machine<'gc>>( if list.inner.borrow().is_empty() { let _list = m.pop(); let _pred = m.pop(); - return m.return_from_primop(Value::new_inline(false), reader); + return m.return_from_primop(Value::new(false), reader); } // prepare stack layout: [ pred list idx ] - m.push(Value::new_inline(0)); + m.push(Value::new(0)); reader.set_pc(Continuation::PAnyCallPred.ip() as usize); Step::Continue(()) } @@ -253,9 +258,9 @@ pub fn any_call_pred<'gc, M: Machine<'gc>>( ) -> Step { let pred = m.peek_forced(2); #[allow(clippy::unwrap_used)] - let idx = m.peek(0).as_inline::().unwrap(); + let idx = m.peek(0).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let elem = m.peek_forced(1).as_gc::().unwrap().inner.borrow()[idx as usize]; + let elem = m.peek_forced(1).downcast::().unwrap().inner.borrow()[idx as usize]; m.push(pred.relax()); m.call(reader, mc, elem, Continuation::PAnyCheck.ip() as usize) } @@ -267,17 +272,17 @@ pub fn any_check<'gc, M: Machine<'gc>>( ) -> Step { let ret = m.force_and_retry::(reader, mc)?; #[allow(clippy::unwrap_used)] - let idx = m.peek(0).as_inline::().unwrap(); + let idx = m.peek(0).downcast::().unwrap(); #[allow(clippy::unwrap_used)] - let list = m.peek_forced(1).as_gc::().unwrap(); + let list = m.peek_forced(1).downcast::().unwrap(); let list = list.inner.borrow(); if idx as usize == list.len() - 1 || ret { let _ = m.pop(); // idx let _ = m.pop(); // list let _ = m.pop(); // pred - return m.return_from_primop(Value::new_inline(ret), reader); + return m.return_from_primop(Value::new(ret), reader); } - m.replace(0, Value::new_inline(idx + 1)); + m.replace(0, Value::new(idx + 1)); reader.set_pc(Continuation::PAnyCallPred.ip() as usize); Step::Continue(()) } diff --git a/fix-vm/src/primops/path.rs b/fix-vm/src/primops/path.rs index b462498..04565ee 100644 --- a/fix-vm/src/primops/path.rs +++ b/fix-vm/src/primops/path.rs @@ -13,8 +13,8 @@ pub fn to_path<'gc, M: Machine<'gc>>( ) -> Step { // coerce to path THEN TO STRING let val = m.force_and_retry::(reader, mc)?; - if let Some(Path(s)) = val.as_inline::() { - return m.return_from_primop(Value::new_inline(s), reader); + if let Some(Path(s)) = val.downcast::() { + return m.return_from_primop(Value::new(s), reader); } let Some(s) = ctx.get_string(val) else { return m.finish_err(Error::eval_error(format!( @@ -29,7 +29,7 @@ pub fn to_path<'gc, M: Machine<'gc>>( } let canon = canon_path_str(s); let sid = ctx.intern_string(canon); - m.return_from_primop(Value::new_inline(sid), reader) + m.return_from_primop(Value::new(sid), reader) } pub fn is_path<'gc, M: Machine<'gc>>( @@ -39,5 +39,5 @@ pub fn is_path<'gc, M: Machine<'gc>>( ) -> Step { let val = m.force_and_retry::(reader, mc)?; let is_path = val.is::(); - m.return_from_primop(Value::new_inline(is_path), reader) + m.return_from_primop(Value::new(is_path), reader) }