From 4f3cd0ef4cb88de55fd35af15742f24fae2bed18 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sat, 25 Apr 2026 17:54:59 +0800 Subject: [PATCH] refactor: split VmContext --- fix-vm/src/bytecode_reader.rs | 9 +- fix-vm/src/dispatch_tailcall.rs | 20 +- fix-vm/src/instructions/arithmetic.rs | 27 +- fix-vm/src/instructions/builtins_misc.rs | 6 +- fix-vm/src/instructions/calls.rs | 10 +- fix-vm/src/instructions/collections.rs | 19 +- fix-vm/src/instructions/with_scope.rs | 6 +- fix-vm/src/lib.rs | 43 +-- fix/src/lib.rs | 318 ++++++++++++----------- 9 files changed, 243 insertions(+), 215 deletions(-) diff --git a/fix-vm/src/bytecode_reader.rs b/fix-vm/src/bytecode_reader.rs index 8261e2e..6f7f51e 100644 --- a/fix-vm/src/bytecode_reader.rs +++ b/fix-vm/src/bytecode_reader.rs @@ -3,7 +3,7 @@ use fix_common::StringId; use num_enum::TryFromPrimitive; use string_interner::Symbol as _; -use crate::OperandData; +use crate::{OperandData, VmRuntimeCtx}; pub(crate) struct BytecodeReader<'a> { bytecode: &'a [u8], @@ -94,7 +94,7 @@ impl<'a> BytecodeReader<'a> { } #[inline(always)] - pub(crate) fn read_operand_data(&mut self, ctx: &C) -> OperandData { + pub(crate) fn read_operand_data(&mut self, ctx: &C) -> OperandData { let tag = self.read_u8(); let Ok(ty) = OperandType::try_from_primitive(tag) .map_err(|err| panic!("unknown operand tag: {:#04x}", err.number)); @@ -117,10 +117,7 @@ impl<'a> BytecodeReader<'a> { } #[inline(always)] - pub(crate) fn read_attr_key_data( - &mut self, - ctx: &C, - ) -> crate::AttrKeyData { + pub(crate) fn read_attr_key_data(&mut self, ctx: &C) -> crate::AttrKeyData { use fix_codegen::AttrKeyType; let tag = self.read_u8(); let ty = AttrKeyType::try_from_primitive(tag) diff --git a/fix-vm/src/dispatch_tailcall.rs b/fix-vm/src/dispatch_tailcall.rs index 0f48746..1d6a492 100644 --- a/fix-vm/src/dispatch_tailcall.rs +++ b/fix-vm/src/dispatch_tailcall.rs @@ -2,7 +2,7 @@ use gc_arena::Mutation; -use crate::{Break, BytecodeReader, Step, Vm, VmContext}; +use crate::{Break, BytecodeReader, Step, Vm, VmRuntimeCtx}; pub(crate) enum TailResult { YieldFuel(u32), @@ -19,9 +19,9 @@ pub(crate) type OpFn<'gc, C> = extern "rust-preserve-none" fn( u32, ) -> TailResult; -pub(crate) struct DispatchTable<'gc, C: VmContext>(pub(crate) [OpFn<'gc, C>; 256]); +pub(crate) struct DispatchTable<'gc, C: VmRuntimeCtx>(pub(crate) [OpFn<'gc, C>; 256]); -extern "rust-preserve-none" fn op_illegal<'gc, C: VmContext>( +extern "rust-preserve-none" fn op_illegal<'gc, C: VmRuntimeCtx>( _vm: &mut Vm<'gc>, _mc: &Mutation<'gc>, _ctx: &mut C, @@ -50,7 +50,7 @@ macro_rules! tail_dispatch_after { macro_rules! tail_fn { ($name:ident, ()) => { - extern "rust-preserve-none" fn $name<'gc, C: VmContext>( + extern "rust-preserve-none" fn $name<'gc, C: VmRuntimeCtx>( vm: &mut Vm<'gc>, mc: &Mutation<'gc>, ctx: &mut C, @@ -64,7 +64,7 @@ macro_rules! tail_fn { } }; ($name:ident, (reader)) => { - extern "rust-preserve-none" fn $name<'gc, C: VmContext>( + extern "rust-preserve-none" fn $name<'gc, C: VmRuntimeCtx>( vm: &mut Vm<'gc>, mc: &Mutation<'gc>, ctx: &mut C, @@ -79,7 +79,7 @@ macro_rules! tail_fn { } }; ($name:ident, (reader, mc)) => { - extern "rust-preserve-none" fn $name<'gc, C: VmContext>( + extern "rust-preserve-none" fn $name<'gc, C: VmRuntimeCtx>( vm: &mut Vm<'gc>, mc: &Mutation<'gc>, ctx: &mut C, @@ -94,7 +94,7 @@ macro_rules! tail_fn { } }; ($name:ident, (ctx, reader, mc)) => { - extern "rust-preserve-none" fn $name<'gc, C: VmContext>( + extern "rust-preserve-none" fn $name<'gc, C: VmRuntimeCtx>( vm: &mut Vm<'gc>, mc: &Mutation<'gc>, ctx: &mut C, @@ -109,7 +109,7 @@ macro_rules! tail_fn { } }; ($name:ident, (ctx)) => { - extern "rust-preserve-none" fn $name<'gc, C: VmContext>( + extern "rust-preserve-none" fn $name<'gc, C: VmRuntimeCtx>( vm: &mut Vm<'gc>, mc: &Mutation<'gc>, ctx: &mut C, @@ -198,7 +198,7 @@ tail_fn!(op_load_scoped_binding, (reader)); macro_rules! table { ($($variant:ident => $fn:ident),* $(,)?) => { - impl<'gc, C: VmContext> DispatchTable<'gc, C> { + impl<'gc, C: VmRuntimeCtx> DispatchTable<'gc, C> { pub(crate) const NEW: Self = { let mut arr: [OpFn<'gc, C>; 256] = [op_illegal; 256]; $( arr[fix_codegen::Op::$variant as usize] = $fn; )* @@ -291,7 +291,7 @@ table! { Illegal => op_illegal, } -pub(crate) fn run_tailcall<'gc, C: VmContext>( +pub(crate) fn run_tailcall<'gc, C: VmRuntimeCtx>( vm: &mut Vm<'gc>, mc: &Mutation<'gc>, ctx: &mut C, diff --git a/fix-vm/src/instructions/arithmetic.rs b/fix-vm/src/instructions/arithmetic.rs index f7de037..710353d 100644 --- a/fix-vm/src/instructions/arithmetic.rs +++ b/fix-vm/src/instructions/arithmetic.rs @@ -3,13 +3,13 @@ use std::cmp::Ordering; use gc_arena::{Gc, Mutation}; use crate::value::*; -use crate::{BytecodeReader, NixNum, Step, VmContextExt, VmError}; +use crate::{BytecodeReader, NixNum, Step, VmError, VmRuntimeCtx, VmRuntimeCtxExt as _}; impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_add( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, ) -> Step { @@ -82,7 +82,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_eq( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, ) -> Step { @@ -98,7 +98,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_neq( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, ) -> Step { @@ -114,7 +114,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_lt( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, ) -> Step { @@ -124,7 +124,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_gt( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, ) -> Step { @@ -134,7 +134,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_leq( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, ) -> Step { @@ -144,7 +144,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_geq( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, ) -> Step { @@ -153,7 +153,7 @@ impl<'gc> crate::Vm<'gc> { fn compare_values( &mut self, - ctx: &impl crate::VmContext, + ctx: &impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, pred: fn(Ordering) -> bool, @@ -202,7 +202,7 @@ impl<'gc> crate::Vm<'gc> { pub(crate) fn values_equal( &mut self, - ctx: &impl crate::VmContext, + ctx: &impl VmRuntimeCtx, lhs: StrictValue<'gc>, rhs: StrictValue<'gc>, ) -> crate::VmResult { @@ -257,7 +257,7 @@ impl<'gc> crate::Vm<'gc> { fn compare_values_inner( &mut self, - ctx: &impl crate::VmContext, + ctx: &impl VmRuntimeCtx, pred: fn(Ordering) -> bool, lhs: StrictValue<'gc>, rhs: StrictValue<'gc>, @@ -276,10 +276,7 @@ impl<'gc> crate::Vm<'gc> { self.push(Value::new_inline(pred(ord))); return Ok(()); } - if let (Some(a), Some(b)) = ( - VmContextExt::get_string(ctx, lhs), - VmContextExt::get_string(ctx, rhs), - ) { + if let (Some(a), Some(b)) = (ctx.get_string(lhs), ctx.get_string(rhs)) { self.push(Value::new_inline(pred(a.cmp(b)))); return Ok(()); } diff --git a/fix-vm/src/instructions/builtins_misc.rs b/fix-vm/src/instructions/builtins_misc.rs index c40a130..c6e5e4a 100644 --- a/fix-vm/src/instructions/builtins_misc.rs +++ b/fix-vm/src/instructions/builtins_misc.rs @@ -1,7 +1,7 @@ use fix_builtins::BuiltinId; use num_enum::TryFromPrimitive; -use crate::{BytecodeReader, PrimOp, Step, Value}; +use crate::{BytecodeReader, PrimOp, Step, Value, VmRuntimeCtx}; impl<'gc> crate::Vm<'gc> { #[inline(always)] @@ -42,7 +42,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_concat_strings( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, _mc: &gc_arena::Mutation<'gc>, ) -> Step { @@ -57,7 +57,7 @@ impl<'gc> crate::Vm<'gc> { } #[inline(always)] - pub(crate) fn op_resolve_path(&mut self, _ctx: &mut impl crate::VmContext) -> Step { + pub(crate) fn op_resolve_path(&mut self, _ctx: &mut impl VmRuntimeCtx) -> Step { todo!("implement ResolvePath"); } } diff --git a/fix-vm/src/instructions/calls.rs b/fix-vm/src/instructions/calls.rs index 8df2d89..9fd9120 100644 --- a/fix-vm/src/instructions/calls.rs +++ b/fix-vm/src/instructions/calls.rs @@ -2,13 +2,15 @@ use fix_error::Error; use gc_arena::{Gc, Mutation, RefLock}; use crate::value::*; -use crate::{BytecodeReader, CallFrame, Closure, Env, Step, ThunkState, VmContextExt}; +use crate::{ + BytecodeReader, CallFrame, Closure, Env, Step, ThunkState, VmRuntimeCtx, VmRuntimeCtxExt, +}; impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_call( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, ) -> Step { @@ -45,14 +47,14 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_return( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &Mutation<'gc>, ) -> Step { self.handle_return(reader, ctx, mc) } - pub(crate) fn handle_return( + pub(crate) fn handle_return( &mut self, reader: &mut BytecodeReader<'_>, ctx: &C, diff --git a/fix-vm/src/instructions/collections.rs b/fix-vm/src/instructions/collections.rs index 4daf482..579bbbb 100644 --- a/fix-vm/src/instructions/collections.rs +++ b/fix-vm/src/instructions/collections.rs @@ -5,14 +5,15 @@ use smallvec::SmallVec; use crate::value::NixType; use crate::{ - AttrKeyData, AttrSet, BytecodeReader, List, OperandData, Step, StrictValue, Value, VmContextExt, + AttrKeyData, AttrSet, BytecodeReader, List, OperandData, Step, StrictValue, Value, + VmRuntimeCtx, VmRuntimeCtxExt, }; impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_make_attrs( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, ) -> Step { @@ -52,7 +53,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_select_static( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, ) -> Step { @@ -73,7 +74,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_select_dynamic( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, ) -> Step { @@ -102,7 +103,7 @@ impl<'gc> crate::Vm<'gc> { fn select_skip( &mut self, key: StringId, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, ) -> Step { use fix_codegen::Op::*; @@ -168,7 +169,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_has_attr_path_static( &mut self, - _ctx: &mut impl crate::VmContext, + _ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, ) -> Step { @@ -192,7 +193,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_has_attr_path_dynamic( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, ) -> Step { @@ -255,7 +256,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_has_attr_dynamic( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, ) -> Step { @@ -288,7 +289,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_make_list( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, ) -> Step { diff --git a/fix-vm/src/instructions/with_scope.rs b/fix-vm/src/instructions/with_scope.rs index 26e5610..be881a8 100644 --- a/fix-vm/src/instructions/with_scope.rs +++ b/fix-vm/src/instructions/with_scope.rs @@ -3,13 +3,13 @@ use fix_error::Error; use gc_arena::Gc; use crate::value::*; -use crate::{BytecodeReader, CallFrame, Step, WithEnv}; +use crate::{BytecodeReader, CallFrame, Step, VmRuntimeCtx, WithEnv}; impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_push_with( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, ) -> Step { @@ -49,7 +49,7 @@ impl<'gc> crate::Vm<'gc> { #[inline(always)] pub(crate) fn op_lookup_with( &mut self, - ctx: &mut impl crate::VmContext, + ctx: &mut impl VmRuntimeCtx, reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, ) -> Step { diff --git a/fix-vm/src/lib.rs b/fix-vm/src/lib.rs index df32b42..c5b1076 100644 --- a/fix-vm/src/lib.rs +++ b/fix-vm/src/lib.rs @@ -64,15 +64,26 @@ pub enum ForceMode { } pub trait VmContext { - fn intern_string(&mut self, s: impl AsRef) -> StringId; - fn resolve_string(&self, id: StringId) -> &str; - fn bytecode(&self) -> &[u8]; - fn get_const(&self, id: u32) -> StaticValue; - - fn compile(&mut self, source: Source); + fn split(&mut self) -> (&mut impl VmCode, &mut impl VmRuntimeCtx); } -pub(crate) trait VmContextExt: VmContext { +pub trait VmRuntimeCtx { + fn intern_string(&mut self, s: impl AsRef) -> StringId; + fn resolve_string(&self, id: StringId) -> &str; + fn get_const(&self, id: u32) -> StaticValue; + fn add_const(&mut self, val: StaticValue) -> u32; +} + +pub trait VmCode { + fn bytecode(&self) -> &[u8]; + fn compile( + &mut self, + source: Source, + ctx: &mut impl VmRuntimeCtx, + ) -> fix_error::Result; +} + +pub(crate) trait VmRuntimeCtxExt: VmRuntimeCtx { fn get_string<'a, 'gc: 'a>(&'a self, val: StrictValue<'gc>) -> Option<&'a str>; fn get_string_id<'a, 'gc: 'a>( &'a mut self, @@ -81,7 +92,7 @@ pub(crate) trait VmContextExt: VmContext { fn convert_value(&self, val: Value) -> fix_common::Value; } -impl VmContextExt for T { +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::() { Some(self.resolve_string(sid)) @@ -213,7 +224,7 @@ pub(crate) enum AttrKeyData { Dynamic(OperandData), } -fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmContext) -> Value<'gc> { +fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmRuntimeCtx) -> Value<'gc> { let mut entries = SmallVec::with_capacity(BUILTINS.len()); for (idx, &(name, arity)) in BUILTINS.iter().enumerate() { @@ -268,7 +279,7 @@ fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmContext) -> Value<'gc } impl<'gc> Vm<'gc> { - fn new(force_mode: ForceMode, mc: &Mutation<'gc>, ctx: &mut impl VmContext) -> Self { + fn new(force_mode: ForceMode, mc: &Mutation<'gc>, ctx: &mut impl VmRuntimeCtx) -> Self { let builtins = init_builtins(mc, ctx); Vm { stack: Vec::with_capacity(8192), @@ -448,15 +459,15 @@ impl Vm<'_> { ip: InstructionPtr, force_mode: ForceMode, ) -> Result { - let mut arena: Arena]> = - Arena::new(|mc| Vm::new(force_mode, mc, ctx)); + let (code, runtime) = ctx.split(); + let mut arena: Arena]> = Arena::new(|mc| Vm::new(force_mode, mc, runtime)); const COLLECTOR_GRANULARITY: f64 = 1024.0; let mut pc = ip.0; - let bytecode: Vec = ctx.bytecode().to_vec(); loop { - match arena.mutate_root(|mc, root| root.dispatch_batch(&bytecode, ctx, pc, mc)) { + let bytecode = code.bytecode(); + match arena.mutate_root(|mc, root| root.dispatch_batch(bytecode, runtime, pc, mc)) { Action::Continue { pc: new_pc } => { pc = new_pc; if arena.metrics().allocation_debt() > COLLECTOR_GRANULARITY { @@ -477,7 +488,7 @@ impl<'gc> Vm<'gc> { const DEFAULT_FUEL_AMOUNT: u32 = 1024; #[inline(always)] - fn dispatch_batch( + fn dispatch_batch( &mut self, bytecode: &[u8], ctx: &mut C, @@ -507,7 +518,7 @@ impl<'gc> Vm<'gc> { fn execute_batch( &mut self, bytecode: &[u8], - ctx: &mut impl VmContext, + ctx: &mut impl VmRuntimeCtx, pc: usize, mc: &Mutation<'gc>, ) -> Action { diff --git a/fix/src/lib.rs b/fix/src/lib.rs index ca08dab..d539585 100644 --- a/fix/src/lib.rs +++ b/fix/src/lib.rs @@ -8,33 +8,33 @@ use fix_common::{StringId, Symbol}; use fix_error::{Error, Result, Source}; use fix_ir::downgrade::{Downgrade as _, DowngradeContext}; use fix_ir::{Ir, IrRef, MaybeThunk, RawIrRef, ThunkId}; -use fix_vm::{ForceMode, StaticValue, Vm, VmContext}; +use fix_vm::{ForceMode, StaticValue, Vm, VmCode, VmContext, VmRuntimeCtx}; use ghost_cell::{GhostCell, GhostToken}; use hashbrown::{HashMap, HashSet}; use string_interner::{DefaultStringInterner, Symbol as _}; -// mod fetcher; -// mod nar; -// mod nix_utils; -// mod store; -// mod string_context; mod derivation; pub mod logging; #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +pub struct RuntimeState { + pub strings: DefaultStringInterner, + pub constants: Constants, +} + +pub struct CodeState { + pub bytecode: Vec, + pub sources: Vec, + pub spans: Vec<(usize, rnix::TextRange)>, + pub thunk_count: usize, + pub global_env: HashMap>>, +} + pub struct Evaluator { - bytecode: Vec, - constants: Constants, - strings: DefaultStringInterner, - - sources: Vec, - spans: Vec<(usize, rnix::TextRange)>, - // FIXME: remove? - thunk_count: usize, - - global_env: HashMap>>, + pub runtime: RuntimeState, + pub code: CodeState, } impl Default for Evaluator { @@ -48,14 +48,17 @@ impl Evaluator { let mut strings = DefaultStringInterner::new(); let global_env = fix_ir::new_global_env(&mut strings); Self { - sources: Vec::new(), - spans: Vec::new(), - strings, - thunk_count: 0, - bytecode: Vec::new(), - constants: Constants::default(), - - global_env, + runtime: RuntimeState { + strings, + constants: Constants::default(), + }, + code: CodeState { + sources: Vec::new(), + spans: Vec::new(), + thunk_count: 0, + bytecode: Vec::new(), + global_env, + }, } } @@ -85,8 +88,13 @@ impl Evaluator { extra_scope: Option>, force_mode: ForceMode, ) -> Result { - let root = self.downgrade(source, extra_scope)?; - let ip = fix_codegen::compile_bytecode(root.as_ref(), self); + let ip = { + let mut compiler = CompilerCtx { + code: &mut self.code, + runtime: &mut self.runtime, + }; + compiler.compile_bytecode(source, extra_scope)? + }; Vm::run(self, ip, force_mode) } @@ -100,55 +108,81 @@ impl Evaluator { } pub fn compile_bytecode(&mut self, source: Source) -> Result { - let root = self.downgrade(source, None)?; - let ip = fix_codegen::compile_bytecode(root.as_ref(), self); - Ok(ip) + let mut compiler = CompilerCtx { + code: &mut self.code, + runtime: &mut self.runtime, + }; + compiler.compile_bytecode(source, None) } pub fn disassemble_colored(&self, ip: InstructionPtr) -> String { Disassembler::new(ip, self).disassemble_colored() } +} - fn downgrade_ctx<'a, 'bump, 'id>( - &'a mut self, - bump: &'bump Bump, - token: GhostToken<'id>, - extra_scope: Option>, - ) -> DowngradeCtx<'a, 'id, 'bump> { - let Self { - global_env, - sources, - thunk_count, - strings, - .. - } = self; - DowngradeCtx { - bump, - token, - strings, - source: sources.last().expect("no current source").clone(), - scopes: [Scope::Global(global_env)] - .into_iter() - .chain(extra_scope) - .collect(), - with_scope_count: 0, - arg_count: 0, - thunk_count, - thunk_scopes: vec![ThunkScope::new_in(bump)], - } +impl VmRuntimeCtx for RuntimeState { + fn intern_string(&mut self, s: impl AsRef) -> StringId { + StringId(self.strings.get_or_intern(s)) + } + fn resolve_string(&self, id: StringId) -> &str { + #[allow(clippy::unwrap_used)] + self.strings.resolve(id.0).unwrap() + } + fn get_const(&self, id: u32) -> StaticValue { + #[allow(clippy::unwrap_used)] + self.constants.get(id).unwrap() + } + fn add_const(&mut self, val: StaticValue) -> u32 { + self.constants.insert(val) + } +} + +impl VmCode for CodeState { + fn bytecode(&self) -> &[u8] { + &self.bytecode + } + fn compile( + &mut self, + source: Source, + runtime: &mut impl VmRuntimeCtx, + ) -> Result { + let mut compiler = CompilerCtx { + code: self, + runtime, + }; + compiler.compile_bytecode(source, None) + } +} + +impl VmContext for Evaluator { + fn split(&mut self) -> (&mut impl VmCode, &mut impl VmRuntimeCtx) { + (&mut self.code, &mut self.runtime) + } +} + +struct CompilerCtx<'a, R: VmRuntimeCtx> { + code: &'a mut CodeState, + runtime: &'a mut R, +} + +impl<'a, R: VmRuntimeCtx> CompilerCtx<'a, R> { + fn compile_bytecode( + &mut self, + source: Source, + extra_scope: Option, + ) -> Result { + let root = self.downgrade(source, extra_scope)?; + let ip = fix_codegen::compile_bytecode(root.as_ref(), self); + Ok(ip) } - fn downgrade<'a>( - &'a mut self, - source: Source, - extra_scope: Option>, - ) -> Result { + fn downgrade(&mut self, source: Source, extra_scope: Option) -> Result { tracing::debug!("Parsing Nix expression"); - self.sources.push(source.clone()); + self.code.sources.push(source.clone()); let root = rnix::Root::parse(&source.src); - handle_parse_error(root.errors(), source).map_or(Ok(()), Err)?; + handle_parse_error(root.errors(), source.clone()).map_or(Ok(()), Err)?; tracing::debug!("Downgrading Nix expression"); let expr = root @@ -157,38 +191,63 @@ impl Evaluator { .ok_or_else(|| Error::parse_error("unexpected EOF".into()))?; let bump = Bump::new(); GhostToken::new(|token| { - let ir = self - .downgrade_ctx(&bump, token, extra_scope) - .downgrade_toplevel(expr)?; + let downgrade_ctx = DowngradeCtx::new( + &bump, + token, + self.runtime, + &self.code.global_env, + extra_scope, + &mut self.code.thunk_count, + source, + ); + let ir = downgrade_ctx.downgrade_toplevel(expr)?; let ir = unsafe { std::mem::transmute::, RawIrRef<'static>>(ir) }; Ok(OwnedIr { _bump: bump, ir }) }) } } -impl VmContext for Evaluator { - fn intern_string(&mut self, s: impl AsRef) -> StringId { - StringId(self.strings.get_or_intern(s)) - } - fn resolve_string(&self, id: StringId) -> &str { - #[allow(clippy::unwrap_used)] - self.strings.resolve(id.0).unwrap() - } - fn bytecode(&self) -> &[u8] { - &self.bytecode - } - fn get_const(&self, id: u32) -> StaticValue { - #[allow(clippy::unwrap_used)] - self.constants.get(id).unwrap() +impl<'a, R: VmRuntimeCtx> BytecodeContext for CompilerCtx<'a, R> { + fn intern_string(&mut self, s: &str) -> StringId { + self.runtime.intern_string(s) } - fn compile(&mut self, _source: Source) { - todo!(); + fn register_span(&mut self, range: rnix::TextRange) -> u32 { + let id = self.code.spans.len(); + let source_id = self + .code + .sources + .len() + .checked_sub(1) + .expect("current_source not set"); + self.code.spans.push((source_id, range)); + id as u32 + } + + fn get_code(&self) -> &[u8] { + &self.code.bytecode + } + + fn get_code_mut(&mut self) -> &mut Vec { + &mut self.code.bytecode + } + + fn add_constant(&mut self, val: fix_codegen::Const) -> u32 { + use fix_codegen::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), + PrimOp { id, arity } => StaticValue::new_primop(id, arity), + Null => StaticValue::default(), + }; + self.runtime.add_const(val) } } #[derive(Default)] -struct Constants { +pub struct Constants { data: Vec, dedup: HashMap, } @@ -236,10 +295,10 @@ fn handle_parse_error<'a>( None } -struct DowngradeCtx<'ctx, 'id, 'ir> { +struct DowngradeCtx<'ctx, 'id, 'ir, R: VmRuntimeCtx> { bump: &'ir Bump, token: GhostToken<'id>, - strings: &'ctx mut DefaultStringInterner, + runtime: &'ctx mut R, source: Source, scopes: Vec>, with_scope_count: u32, @@ -262,11 +321,11 @@ fn should_thunk<'id>(ir: IrRef<'id, '_>, token: &GhostToken<'id>) -> bool { ) } -impl<'ctx, 'id, 'ir> DowngradeCtx<'ctx, 'id, 'ir> { +impl<'ctx, 'id, 'ir, R: VmRuntimeCtx> DowngradeCtx<'ctx, 'id, 'ir, R> { fn new( bump: &'ir Bump, token: GhostToken<'id>, - symbols: &'ctx mut DefaultStringInterner, + runtime: &'ctx mut R, global: &'ctx HashMap>>, extra_scope: Option>, thunk_count: &'ctx mut usize, @@ -275,7 +334,7 @@ impl<'ctx, 'id, 'ir> DowngradeCtx<'ctx, 'id, 'ir> { Self { bump, token, - strings: symbols, + runtime, source, scopes: std::iter::once(Scope::Global(global)) .chain(extra_scope) @@ -288,7 +347,9 @@ impl<'ctx, 'id, 'ir> DowngradeCtx<'ctx, 'id, 'ir> { } } -impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id, 'ir> { +impl<'ctx: 'ir, 'id, 'ir, R: VmRuntimeCtx> DowngradeContext<'id, 'ir> + for DowngradeCtx<'ctx, 'id, 'ir, R> +{ fn new_expr(&self, expr: Ir<'ir, IrRef<'id, 'ir>>) -> IrRef<'id, 'ir> { IrRef::new(self.bump.alloc(GhostCell::new(expr))) } @@ -317,11 +378,11 @@ impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id, } fn intern_string(&mut self, sym: impl AsRef) -> StringId { - StringId(self.strings.get_or_intern(sym)) + self.runtime.intern_string(sym) } fn resolve_sym(&self, id: StringId) -> Symbol<'_> { - self.strings.resolve(id.0).expect("no symbol found").into() + self.runtime.resolve_string(id).into() } fn lookup(&self, sym: StringId, span: rnix::TextRange) -> Result { @@ -383,9 +444,9 @@ impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id, self.source.clone() } - fn with_let_scope(&mut self, keys: &[StringId], f: F) -> Result + fn with_let_scope(&mut self, keys: &[StringId], f: F) -> Result where - F: FnOnce(&mut Self) -> Result<(bumpalo::collections::Vec<'ir, IrRef<'id, 'ir>>, R)>, + F: FnOnce(&mut Self) -> Result<(bumpalo::collections::Vec<'ir, IrRef<'id, 'ir>>, Ret)>, { let base = *self.thunk_count; *self.thunk_count = self @@ -407,9 +468,9 @@ impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id, Ok(ret) } - fn with_param_scope(&mut self, sym: StringId, f: F) -> R + fn with_param_scope(&mut self, sym: StringId, f: F) -> Ret where - F: FnOnce(&mut Self) -> R, + F: FnOnce(&mut Self) -> Ret, { self.scopes.push(Scope::Param { sym, @@ -419,9 +480,9 @@ impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id, f(guard.as_ctx()) } - fn with_with_scope(&mut self, f: F) -> R + fn with_with_scope(&mut self, f: F) -> Ret where - F: FnOnce(&mut Self) -> R, + F: FnOnce(&mut Self) -> Ret, { self.with_scope_count += 1; let ret = f(self); @@ -429,15 +490,15 @@ impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id, ret } - fn with_thunk_scope( + fn with_thunk_scope( &mut self, f: F, ) -> ( - R, + Ret, bumpalo::collections::Vec<'ir, (ThunkId, IrRef<'id, 'ir>)>, ) where - F: FnOnce(&mut Self) -> R, + F: FnOnce(&mut Self) -> Ret, { self.thunk_scopes.push(ThunkScope::new_in(self.bump)); let ret = f(self); @@ -455,7 +516,7 @@ impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id, } } -impl<'id, 'ir, 'ctx: 'ir> DowngradeCtx<'ctx, 'id, 'ir> { +impl<'id, 'ir, 'ctx: 'ir, R: VmRuntimeCtx> DowngradeCtx<'ctx, 'id, 'ir, R> { fn downgrade_toplevel(mut self, root: rnix::ast::Expr) -> Result> { let body = root.downgrade(&mut self)?; let thunks = self @@ -496,18 +557,18 @@ enum Scope<'ctx> { Param { sym: StringId, abs_layer: usize }, } -struct ScopeGuard<'a, 'ctx, 'id, 'ir> { - ctx: &'a mut DowngradeCtx<'ctx, 'id, 'ir>, +struct ScopeGuard<'a, 'ctx, 'id, 'ir, R: VmRuntimeCtx> { + ctx: &'a mut DowngradeCtx<'ctx, 'id, 'ir, R>, } -impl Drop for ScopeGuard<'_, '_, '_, '_> { +impl<'a, 'ctx, 'id, 'ir, R: VmRuntimeCtx> Drop for ScopeGuard<'a, 'ctx, 'id, 'ir, R> { fn drop(&mut self) { self.ctx.scopes.pop(); } } -impl<'id, 'ir, 'ctx> ScopeGuard<'_, 'ctx, 'id, 'ir> { - fn as_ctx(&mut self) -> &mut DowngradeCtx<'ctx, 'id, 'ir> { +impl<'a, 'ctx, 'id, 'ir, R: VmRuntimeCtx> ScopeGuard<'a, 'ctx, 'id, 'ir, R> { + fn as_ctx(&mut self) -> &mut DowngradeCtx<'ctx, 'id, 'ir, R> { self.ctx } } @@ -518,9 +579,6 @@ struct OwnedIr { } impl OwnedIr { - /// # Safety - /// - /// `ir` must be allocated from `bump`. unsafe fn new(ir: RawIrRef<'_>, bump: Bump) -> Self { Self { _bump: bump, @@ -533,52 +591,14 @@ impl OwnedIr { } } -impl BytecodeContext for Evaluator { - fn intern_string(&mut self, s: &str) -> StringId { - StringId(self.strings.get_or_intern(s)) - } - - fn register_span(&mut self, range: rnix::TextRange) -> u32 { - let id = self.spans.len(); - let source_id = self - .sources - .len() - .checked_sub(1) - .expect("current_source not set"); - self.spans.push((source_id, range)); - id as u32 - } - - fn get_code(&self) -> &[u8] { - &self.bytecode - } - - fn get_code_mut(&mut self) -> &mut Vec { - &mut self.bytecode - } - - fn add_constant(&mut self, val: fix_codegen::Const) -> u32 { - use fix_codegen::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), - PrimOp { id, arity } => StaticValue::new_primop(id, arity), - Null => StaticValue::default(), - }; - self.constants.insert(val) - } -} - impl DisassemblerContext for Evaluator { fn get_code(&self) -> &[u8] { - &self.bytecode + &self.code.bytecode } #[allow(clippy::unwrap_used)] fn resolve_string(&self, id: u32) -> &str { let id = string_interner::symbol::SymbolU32::try_from_usize(id as usize).unwrap(); - self.strings.resolve(id).unwrap() + self.runtime.strings.resolve(id).unwrap() } }