From 561b9bf36ac2d2b80c454a282c7cbb8a22ac3e06 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sat, 10 May 2025 21:31:38 +0800 Subject: [PATCH] chore: tidy --- src/vm/jit.rs | 26 ++++++ src/vm/mod.rs | 221 ++++++++++++++++++++++++++++++++++++++++++++++++- src/vm/test.rs | 2 +- src/vm/vm.rs | 215 ----------------------------------------------- 4 files changed, 244 insertions(+), 220 deletions(-) create mode 100644 src/vm/jit.rs delete mode 100644 src/vm/vm.rs diff --git a/src/vm/jit.rs b/src/vm/jit.rs new file mode 100644 index 0000000..e173e96 --- /dev/null +++ b/src/vm/jit.rs @@ -0,0 +1,26 @@ +use inkwell::OptimizationLevel; +use inkwell::builder::Builder; +use inkwell::context::Context; +use inkwell::execution_engine::ExecutionEngine; +use inkwell::module::Module; + +pub struct JITContext<'ctx> { + context: &'ctx Context, + module: Module<'ctx>, + builder: Builder<'ctx>, + execution_engine: ExecutionEngine<'ctx>, +} + +impl<'ctx> JITContext<'ctx> { + pub fn new(context: &Context) -> JITContext { + let module = context.create_module("nixjit"); + JITContext { + execution_engine: module + .create_jit_execution_engine(OptimizationLevel::None) + .unwrap(), + builder: context.create_builder(), + context, + module, + } + } +} diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 7b7f143..cd5d3db 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,10 +1,223 @@ +use std::sync::Arc; + +use crate::builtins::env; +use crate::bytecode::{BinOp, OpCode, OpCodes, Program, UnOp}; +use crate::error::*; +use crate::ty::common::Symbol; +use crate::ty::internal::*; +use crate::ty::public as p; + +use stack::{STACK_SIZE, Stack}; + +pub use env::{CapturedEnv, Env}; + mod env; +mod jit; mod stack; -mod vm; #[cfg(test)] mod test; -pub use env::{CapturedEnv, Env}; -pub use vm::VM; -pub use vm::run; +pub fn run(prog: Program) -> Result { + let vm = VM::new(prog.thunks, prog.funcs); + Ok(vm.eval(prog.top_level, env())?.to_public(&vm)) +} + +pub struct VM { + thunks: Box<[Thunk]>, + funcs: Box<[Func]>, +} + +impl VM { + fn new(thunks: Box<[OpCodes]>, funcs: Box<[Func]>) -> Self { + let thunks = thunks + .into_iter() + .map(|opcodes| Thunk::new(opcodes)) + .collect(); + VM { thunks, funcs } + } + + pub fn get_thunk(&self, idx: usize) -> Thunk { + self.thunks[idx].clone() + } + + pub fn get_func(&self, idx: usize) -> Func { + self.funcs[idx].clone() + } + + pub fn eval(&self, opcodes: OpCodes, env: Arc) -> Result { + let mut stack = Stack::::new(); + let mut iter = opcodes.into_iter(); + while let Some(opcode) = iter.next() { + let jmp = self.single_op(opcode, &mut stack, env.clone())?; + for _ in 0..jmp { + iter.next().unwrap(); + } + } + assert_eq!(stack.len(), 1); + let mut ret = stack.pop(); + ret.force(self)?; + Ok(ret) + } + + #[inline] + fn single_op( + &self, + opcode: OpCode, + stack: &mut Stack, + env: Arc, + ) -> Result { + match opcode { + OpCode::Illegal => panic!("illegal opcode"), + OpCode::Const { value } => stack.push(Value::Const(value))?, + OpCode::LoadThunk { idx } => { + self.thunks[idx].capture(env); + stack.push(Value::Thunk(self.thunks[idx].clone()))? + } + OpCode::LoadValue { idx } => { + stack.push(self.get_thunk(idx).force(self)?)?; + } + OpCode::ForceValue => { + stack.tos_mut()?.force(self)?; + } + OpCode::Jmp { step } => return Ok(step), + OpCode::JmpIfTrue { step } => { + if let Value::Const(Const::Bool(true)) = stack.pop() { + return Ok(step); + } + } + OpCode::JmpIfFalse { step } => { + if let Value::Const(Const::Bool(false)) = stack.pop() { + return Ok(step); + } + } + OpCode::Call { arity } => { + let mut args = Vec::with_capacity(arity); + for _ in 0..arity { + args.insert(0, stack.pop()); + } + let mut func = stack.pop(); + func.force(self)?; + stack.push(func.call(self, args)?)?; + } + OpCode::Func { idx } => { + let mut func = self.get_func(idx); + func.env = Some(env.captured()); + stack.push(Value::Func(func))?; + } + OpCode::UnOp { op } => { + use UnOp::*; + let mut value = stack.pop(); + value.force(self)?; + stack.push(match op { + Not => value.not(), + })?; + } + OpCode::BinOp { op } => { + use BinOp::*; + let mut rhs = stack.pop(); + let mut lhs = stack.pop(); + lhs.force(self)?; + rhs.force(self)?; + stack.push(match op { + Add => lhs.add(rhs), + And => lhs.and(rhs), + Or => lhs.or(rhs), + Eq => lhs.eq(rhs), + Con => lhs.concat(rhs), + Upd => lhs.update(rhs), + })?; + } + OpCode::ConcatString => { + let mut rhs = stack.pop(); + rhs.force(self)?; + stack.tos_mut()?.concat_string(rhs); + } + OpCode::Path => { + todo!() + } + OpCode::List => { + stack.push(Value::List(List::empty()))?; + } + OpCode::PushElem => { + let elem = stack.pop(); + stack.tos_mut()?.push(elem); + } + OpCode::AttrSet => { + stack.push(Value::AttrSet(AttrSet::empty()))?; + } + OpCode::RecAttrSet => { + let new = env.enter_rec(); + stack.push(Value::RecAttrSet(RecAttrSet::new(new)))?; + } + OpCode::PushStaticAttr { name } => { + let val = stack.pop(); + stack.tos_mut()?.push_attr(Symbol::new(name), val); + } + OpCode::PushDynamicAttr => { + let val = stack.pop(); + let mut sym = stack.pop(); + sym.force(self)?.coerce_to_string(); + let sym = sym.unwrap_const().unwrap_string().into(); + stack.tos_mut()?.push_attr(sym, val); + } + OpCode::Select { sym } => { + stack.tos_mut()?.force(self)?.select(Symbol::new(sym)); + } + OpCode::SelectOrDefault { sym } => { + let default = stack.pop(); + stack + .tos_mut()? + .force(self)? + .select_with_default(Symbol::new(sym), default); + } + OpCode::SelectDynamic => { + let mut val = stack.pop(); + val.force(self)?; + val.coerce_to_string(); + let sym = val.unwrap_const().unwrap_string().into(); + stack.tos_mut()?.force(self)?.select(sym); + } + OpCode::SelectDynamicOrDefault => { + let default = stack.pop(); + let mut val = stack.pop(); + val.force(self)?; + val.coerce_to_string(); + let sym = val.unwrap_const().unwrap_string().into(); + stack + .tos_mut()? + .force(self)? + .select_with_default(sym, default); + } + OpCode::HasAttr { sym } => { + stack.tos_mut()?.force(self)?.has_attr(Symbol::new(sym)); + } + OpCode::HasDynamicAttr => { + let mut val = stack.pop(); + val.coerce_to_string(); + let sym = val.unwrap_const().unwrap_string().into(); + stack.tos_mut()?.force(self)?.has_attr(sym); + } + OpCode::LookUp { sym } => { + stack.push( + env.lookup(Symbol::new(sym.clone())) + .ok_or_else(|| Error::EvalError(format!(r#""{sym}" not found"#)))?, + )?; + } + OpCode::EnterEnv => match stack.pop() { + Value::AttrSet(attrs) => env.enter(attrs.into_inner()), + Value::RecAttrSet(attrs) => env.enter(attrs.into_inner()), + _ => unreachable!(), + }, + OpCode::LeaveEnv => { + env.leave(); + } + OpCode::Assert => { + if !stack.pop().unwrap_const().unwrap_bool() { + todo!() + } + } + } + Ok(0) + } +} diff --git a/src/vm/test.rs b/src/vm/test.rs index 52d533c..9f6eb64 100644 --- a/src/vm/test.rs +++ b/src/vm/test.rs @@ -6,7 +6,7 @@ use crate::ir::downgrade; use crate::ty::common::Symbol; use crate::ty::public::*; -use super::vm::run; +use super::run; #[inline] fn test_expr(expr: &str, expected: Value) { diff --git a/src/vm/vm.rs b/src/vm/vm.rs deleted file mode 100644 index e16d21e..0000000 --- a/src/vm/vm.rs +++ /dev/null @@ -1,215 +0,0 @@ -use std::sync::Arc; - -use crate::builtins::env; -use crate::bytecode::{BinOp, OpCode, OpCodes, Program, UnOp}; -use crate::error::*; -use crate::ty::common::Symbol; -use crate::ty::internal::*; -use crate::ty::public as p; - -use super::env::Env; -use super::stack::{STACK_SIZE, Stack}; - -pub fn run(prog: Program) -> Result { - let vm = VM::new(prog.thunks, prog.funcs); - Ok(vm.eval(prog.top_level, env())?.to_public(&vm)) -} - -pub struct VM { - thunks: Box<[Thunk]>, - funcs: Box<[Func]>, -} - -impl VM { - fn new(thunks: Box<[OpCodes]>, funcs: Box<[Func]>) -> Self { - let thunks = thunks - .into_iter() - .map(|opcodes| Thunk::new(opcodes)) - .collect(); - VM { thunks, funcs } - } - - pub fn get_thunk(&self, idx: usize) -> Thunk { - self.thunks[idx].clone() - } - - pub fn get_func(&self, idx: usize) -> Func { - self.funcs[idx].clone() - } - - pub fn eval(&self, opcodes: OpCodes, env: Arc) -> Result { - let mut stack = Stack::::new(); - let mut iter = opcodes.into_iter(); - while let Some(opcode) = iter.next() { - let jmp = self.single_op(opcode, &mut stack, env.clone())?; - for _ in 0..jmp { - iter.next().unwrap(); - } - } - assert_eq!(stack.len(), 1); - let mut ret = stack.pop(); - ret.force(self)?; - Ok(ret) - } - - #[inline] - fn single_op( - &self, - opcode: OpCode, - stack: &mut Stack, - env: Arc, - ) -> Result { - match opcode { - OpCode::Illegal => panic!("illegal opcode"), - OpCode::Const { value } => stack.push(Value::Const(value))?, - OpCode::LoadThunk { idx } => { - self.thunks[idx].capture(env); - stack.push(Value::Thunk(self.thunks[idx].clone()))? - } - OpCode::LoadValue { idx } => { - stack.push(self.get_thunk(idx).force(self)?)?; - } - OpCode::ForceValue => { - stack.tos_mut()?.force(self)?; - } - OpCode::Jmp { step } => return Ok(step), - OpCode::JmpIfTrue { step } => { - if let Value::Const(Const::Bool(true)) = stack.pop() { - return Ok(step); - } - } - OpCode::JmpIfFalse { step } => { - if let Value::Const(Const::Bool(false)) = stack.pop() { - return Ok(step); - } - } - OpCode::Call { arity } => { - let mut args = Vec::with_capacity(arity); - for _ in 0..arity { - args.insert(0, stack.pop()); - } - let mut func = stack.pop(); - func.force(self)?; - stack.push(func.call(self, args)?)?; - } - OpCode::Func { idx } => { - let mut func = self.get_func(idx); - func.env = Some(env.captured()); - stack.push(Value::Func(func))?; - } - OpCode::UnOp { op } => { - use UnOp::*; - let mut value = stack.pop(); - value.force(self)?; - stack.push(match op { - Not => value.not(), - })?; - } - OpCode::BinOp { op } => { - use BinOp::*; - let mut rhs = stack.pop(); - let mut lhs = stack.pop(); - lhs.force(self)?; - rhs.force(self)?; - stack.push(match op { - Add => lhs.add(rhs), - And => lhs.and(rhs), - Or => lhs.or(rhs), - Eq => lhs.eq(rhs), - Con => lhs.concat(rhs), - Upd => lhs.update(rhs), - })?; - } - OpCode::ConcatString => { - let mut rhs = stack.pop(); - rhs.force(self)?; - stack.tos_mut()?.concat_string(rhs); - } - OpCode::Path => { - todo!() - } - OpCode::List => { - stack.push(Value::List(List::empty()))?; - } - OpCode::PushElem => { - let elem = stack.pop(); - stack.tos_mut()?.push(elem); - } - OpCode::AttrSet => { - stack.push(Value::AttrSet(AttrSet::empty()))?; - } - OpCode::RecAttrSet => { - let new = env.enter_rec(); - stack.push(Value::RecAttrSet(RecAttrSet::new(new)))?; - } - OpCode::PushStaticAttr { name } => { - let val = stack.pop(); - stack.tos_mut()?.push_attr(Symbol::new(name), val); - } - OpCode::PushDynamicAttr => { - let val = stack.pop(); - let mut sym = stack.pop(); - sym.force(self)?.coerce_to_string(); - let sym = sym.unwrap_const().unwrap_string().into(); - stack.tos_mut()?.push_attr(sym, val); - } - OpCode::Select { sym } => { - stack.tos_mut()?.force(self)?.select(Symbol::new(sym)); - } - OpCode::SelectOrDefault { sym } => { - let default = stack.pop(); - stack - .tos_mut()? - .force(self)? - .select_with_default(Symbol::new(sym), default); - } - OpCode::SelectDynamic => { - let mut val = stack.pop(); - val.force(self)?; - val.coerce_to_string(); - let sym = val.unwrap_const().unwrap_string().into(); - stack.tos_mut()?.force(self)?.select(sym); - } - OpCode::SelectDynamicOrDefault => { - let default = stack.pop(); - let mut val = stack.pop(); - val.force(self)?; - val.coerce_to_string(); - let sym = val.unwrap_const().unwrap_string().into(); - stack - .tos_mut()? - .force(self)? - .select_with_default(sym, default); - } - OpCode::HasAttr { sym } => { - stack.tos_mut()?.force(self)?.has_attr(Symbol::new(sym)); - } - OpCode::HasDynamicAttr => { - let mut val = stack.pop(); - val.coerce_to_string(); - let sym = val.unwrap_const().unwrap_string().into(); - stack.tos_mut()?.force(self)?.has_attr(sym); - } - OpCode::LookUp { sym } => { - stack.push( - env.lookup(Symbol::new(sym.clone())) - .ok_or_else(|| Error::EvalError(format!(r#""{sym}" not found"#)))?, - )?; - } - OpCode::EnterEnv => match stack.pop() { - Value::AttrSet(attrs) => env.enter(attrs.into_inner()), - Value::RecAttrSet(attrs) => env.enter(attrs.into_inner()), - _ => unreachable!(), - }, - OpCode::LeaveEnv => { - env.leave(); - } - OpCode::Assert => { - if !stack.pop().unwrap_const().unwrap_bool() { - todo!() - } - } - } - Ok(0) - } -}