feat: less clone, avoid evaluating not depended thunk

This commit is contained in:
2025-06-18 09:32:00 +08:00
parent 3e9f0a72a0
commit d875951c09
14 changed files with 409 additions and 192 deletions

View File

@@ -39,7 +39,7 @@ fn main() -> Result<()> {
} }
let expr = root.tree().expr().unwrap(); let expr = root.tree().expr().unwrap();
let downgraded = unwrap!(downgrade(expr)); let downgraded = unwrap!(downgrade(expr));
println!("{:?}", downgraded.graph); println!("{:?}", downgraded);
} }
Err(ReadlineError::Interrupted) => { Err(ReadlineError::Interrupted) => {
println!("CTRL-C"); println!("CTRL-C");

View File

@@ -3,11 +3,11 @@ use std::rc::Rc;
use hashbrown::HashSet; use hashbrown::HashSet;
use priority_queue::PriorityQueue; use priority_queue::PriorityQueue;
use crate::env::VmEnv; use crate::env::Env;
use crate::error::Result; use crate::error::Result;
use crate::eval::Evaluate; use crate::eval::Evaluate;
use crate::ir::{Dep, Downgraded, Ir, SccNode}; use crate::ir::{Dep, Downgraded, Ir, SccNode};
use crate::ty::internal::{self as i, ThunkRef}; use crate::ty::internal as i;
use crate::ty::public::Value; use crate::ty::public::Value;
#[cfg(test)] #[cfg(test)]
@@ -43,38 +43,46 @@ impl Engine {
} }
pub fn eval(&mut self, graph: Vec<SccNode>) -> Result<Value> { pub fn eval(&mut self, graph: Vec<SccNode>) -> Result<Value> {
let mut env = VmEnv::new(); let mut env = Env::new();
let last = graph.last().unwrap().members[0]; let last = graph.last().unwrap().members[0];
for SccNode { members, .. } in graph.into_iter() { for SccNode { members, .. } in graph.into_iter() {
// TODO: if members.len() == 1 {
assert!(members.len() == 1); for member in members.into_iter() {
let val = self.thunks[member].clone().eval(self, &mut env)?;
env.insert_cache(member, val);
}
} else {
todo!();
for member in members.into_iter() { for member in members.into_iter() {
let val = self.thunks[member].clone().eval(self, &mut env)?; let val = self.thunks[member].clone().eval(self, &mut env)?;
env.insert_cache(member, val); env.insert_cache(member, val);
} }
} }
}
env.lookup_cache(last, |_| unreachable!()).map(|mut val| { env.lookup_cache(last, |_| unreachable!()).map(|mut val| {
Ok(val Ok(val
.force(self, &mut env)?
.to_public(self, &mut HashSet::new())) .to_public(self, &mut HashSet::new()))
})? })?
} }
pub fn eval_thunk(&mut self, idx: usize, env: &mut VmEnv) -> Result<i::Value> { pub fn eval_thunk(&mut self, idx: usize, env: &mut Env) -> Result<i::Value> {
self.thunks[idx].clone().eval(self, env) let self_mut = unsafe { &mut *(self as *mut Self) };
self.thunks[idx].eval(self_mut, env)
} }
pub fn eval_func_deps(&mut self, idx: usize, env: &mut VmEnv) -> Result<()> { pub fn eval_func_deps(&mut self, idx: usize, env: &mut Env) -> Result<()> {
for dep in self.func_deps[idx - self.func_offset].clone() { for dep in self.func_deps[idx - self.func_offset].clone() {
match dep { match dep {
Dep::Arg(idx) => { Dep::Arg(idx) => {
if let i::Value::Thunk(ThunkRef { idx }) = env.lookup_arg(idx) { if let i::Value::Thunk(idx) = env.lookup_arg(idx) {
let val = self.thunks[idx].clone().eval(self, env)?; let self_mut = unsafe { &mut *(self as *mut Self) };
let val = self.thunks[idx].eval(self_mut, env)?;
env.insert_cache(idx, val) env.insert_cache(idx, val)
} }
} }
Dep::Thunk(idx) => { Dep::Thunk(idx) => {
let val = self.thunks[idx].clone().eval(self, env)?; let self_mut = unsafe { &mut *(self as *mut Self) };
let val = self.thunks[idx].eval(self_mut, env)?;
env.insert_cache(idx, val) env.insert_cache(idx, val)
} }
} }
@@ -86,7 +94,7 @@ impl Engine {
enum Thunk { enum Thunk {
Expr(Ir), Expr(Ir),
Compiling, Compiling,
Compiled(fn(Rc<VmEnv>) -> Value), Compiled(fn(Rc<Env>) -> Value),
} }
impl Thunk { impl Thunk {

View File

@@ -154,7 +154,7 @@ fn test_attrs() {
"rec { a = 1; b = a; }", "rec { a = 1; b = a; }",
attrs! { attrs! {
symbol!("a") => int!(1), symbol!("a") => int!(1),
symbol!("b") => thunk!() symbol!("b") => int!(1)
}, },
); );
test_expr("{ a = 1; }.a", int!(1)); test_expr("{ a = 1; }.a", int!(1));
@@ -196,6 +196,7 @@ fn test_let() {
r#"let b = "c"; in { a.b = 1; } // { a."a${b}" = 2; }"#, r#"let b = "c"; in { a.b = 1; } // { a."a${b}" = 2; }"#,
attrs! { symbol!("a") => attrs!{ symbol!("ac") => int!(2) } }, attrs! { symbol!("a") => attrs!{ symbol!("ac") => int!(2) } },
); );
test_expr("let f = (let f = n: let a = n; f = x: a + x; in f; in f 1); in f 0", int!(1));
} }
#[test] #[test]

View File

@@ -6,10 +6,10 @@ use hashbrown::HashMap;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::stack::Stack; use crate::stack::Stack;
use crate::ty::internal::{EnvRef, Value}; use crate::ty::internal::Value;
#[derive(Clone)] #[derive(Clone)]
pub struct VmEnv { pub struct Env {
cache: Vec<HashMap<usize, Value>>, cache: Vec<HashMap<usize, Value>>,
with: Vec<Rc<HashMap<EcoString, Value>>>, with: Vec<Rc<HashMap<EcoString, Value>>>,
args: Vec<Value>, args: Vec<Value>,
@@ -38,7 +38,7 @@ pub enum Type {
With, With,
} }
impl VmEnv { impl Env {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
cache: Vec::from([HashMap::new()]), cache: Vec::from([HashMap::new()]),
@@ -66,7 +66,7 @@ impl VmEnv {
pub fn lookup_cache( pub fn lookup_cache(
&mut self, &mut self,
idx: usize, idx: usize,
f: impl FnOnce(&mut VmEnv) -> Result<Value>, f: impl FnOnce(&mut Env) -> Result<Value>,
) -> Result<Value> { ) -> Result<Value> {
for level in self.cache.iter().rev() { for level in self.cache.iter().rev() {
if let Some(ret) = level.get(&idx) { if let Some(ret) = level.get(&idx) {
@@ -99,6 +99,10 @@ impl VmEnv {
self.args.split_off(self.args.len() - len) self.args.split_off(self.args.len() - len)
} }
pub fn reserve_args(&mut self, len: usize) {
self.args.reserve(len);
}
pub fn enter_args(&mut self, args: Vec<Value>) { pub fn enter_args(&mut self, args: Vec<Value>) {
self.args.extend(args); self.args.extend(args);
} }

View File

@@ -4,38 +4,204 @@ use crate::ir::*;
use crate::ty::common as c; use crate::ty::common as c;
use crate::ty::internal::Value; use crate::ty::internal::Value;
use super::JITContext; use super::{JITContext, ValueTag};
pub trait JITCompile { pub trait JITCompile {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc>; fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc>;
} }
impl JITCompile for Attrs { impl JITCompile for Attrs {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for List { impl JITCompile for List {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for HasAttr { impl JITCompile for HasAttr {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for BinOp { impl JITCompile for BinOp {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() use ValueTag::*;
use BinOpKind::*;
let lhs = self.lhs.compile(ctx, func);
let rhs = self.rhs.compile(ctx, func);
let lhs_tag = ctx.get_tag(lhs);
let rhs_tag = ctx.get_tag(rhs);
let tag = ctx
.builder
.build_int_add(
lhs_tag.const_shl(ctx.helpers.const_int(8)),
rhs_tag,
"calc_tag",
)
.unwrap();
let ret = ctx.context.append_basic_block(func, "fallback");
let res = ctx
.builder
.build_alloca(ctx.helpers.value_type, "res_alloca")
.unwrap();
match self.kind {
Add => {
let int_int = ctx.context.append_basic_block(func, "int_int");
let int_float = ctx.context.append_basic_block(func, "int_float");
let float_int = ctx.context.append_basic_block(func, "float_int");
let float_float = ctx.context.append_basic_block(func, "float_float");
let fallback = ctx.context.append_basic_block(func, "fallback");
ctx.builder
.build_switch(
tag,
fallback,
&[
(
ctx.helpers.const_int(((Int as i64) << 8) + Int as i64),
int_int,
),
(
ctx.helpers.const_int(((Int as i64) << 8) + Float as i64),
int_float,
),
(
ctx.helpers.const_int(((Float as i64) << 8) + Int as i64),
float_int,
),
(
ctx.helpers.const_int(((Float as i64) << 8) + Float as i64),
float_float,
),
],
)
.unwrap();
ctx.builder.position_at_end(int_int);
let val = ctx
.builder
.build_int_add(ctx.get_int(lhs), ctx.get_int(rhs), "add")
.unwrap();
ctx.builder
.build_store(
res,
ctx.helpers.value_type.const_named_struct(&[
ctx.helpers.const_int(Int as i64).into(),
val.into(),
]),
)
.unwrap();
ctx.builder.position_at_end(int_float);
let val = ctx
.builder
.build_float_add(
ctx.builder
.build_signed_int_to_float(
ctx.get_int(lhs),
ctx.helpers.float_type,
"lhs_to_float",
)
.unwrap(),
ctx.get_float(rhs),
"add",
)
.unwrap();
ctx.builder
.build_store(
res,
ctx.helpers.value_type.const_named_struct(&[
ctx.helpers.const_int(Float as i64).into(),
val.into(),
]),
)
.unwrap();
ctx.builder.position_at_end(float_int);
let val = ctx
.builder
.build_float_add(
ctx.get_float(lhs),
ctx.builder
.build_signed_int_to_float(
ctx.get_int(rhs),
ctx.helpers.float_type,
"rhs_to_float",
)
.unwrap(),
"add",
)
.unwrap();
ctx.builder
.build_store(
res,
ctx.helpers.value_type.const_named_struct(&[
ctx.helpers.const_int(Float as i64).into(),
val.into(),
]),
)
.unwrap();
ctx.builder.position_at_end(int_int);
let val = ctx
.builder
.build_float_add(ctx.get_float(lhs), ctx.get_float(rhs), "add")
.unwrap();
ctx.builder
.build_store(
res,
ctx.helpers.value_type.const_named_struct(&[
ctx.helpers.const_int(Float as i64).into(),
val.into(),
]),
)
.unwrap();
ctx.builder.position_at_end(fallback);
}
Or => {
let bool_bool = ctx.context.append_basic_block(func, "int_int");
let fallback = ctx.context.append_basic_block(func, "fallback");
ctx.builder
.build_switch(
tag,
fallback,
&[
(
ctx.helpers.const_int(((Bool as i64) << 8) + Bool as i64),
bool_bool,
),
],
)
.unwrap();
ctx.builder.position_at_end(bool_bool);
let val = ctx
.builder
.build_or(ctx.get_bool(lhs), ctx.get_bool(rhs), "or")
.unwrap();
ctx.builder
.build_store(
res,
ctx.helpers.value_type.const_named_struct(&[
ctx.helpers.const_int(Bool as i64).into(),
val.into(),
]),
)
.unwrap();
ctx.builder.position_at_end(fallback);
}
_ => todo!()
}
ctx.builder.position_at_end(ret);
ctx.builder
.build_load(ctx.helpers.value_type, res, "load_res")
.unwrap()
.try_into()
.unwrap()
} }
} }
impl JITCompile for UnOp { impl JITCompile for UnOp {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!(); todo!();
let rhs = self.rhs.compile(ctx, func); let rhs = self.rhs.compile(ctx, func);
let tag = ctx.get_tag(rhs); let tag = ctx.get_tag(rhs);
@@ -57,55 +223,55 @@ impl JITCompile for UnOp {
} }
impl JITCompile for Select { impl JITCompile for Select {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for If { impl JITCompile for If {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for LoadFunc { impl JITCompile for LoadFunc {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for Call { impl JITCompile for Call {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for Let { impl JITCompile for Let {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for With { impl JITCompile for With {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for Assert { impl JITCompile for Assert {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for ConcatStrings { impl JITCompile for ConcatStrings {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for Const { impl JITCompile for Const {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
use c::Const::*; use c::Const::*;
match self.val { match self.val {
Bool(x) => ctx.helpers.new_bool(x), Bool(x) => ctx.helpers.new_bool(x),
@@ -117,37 +283,37 @@ impl JITCompile for Const {
} }
impl JITCompile for String { impl JITCompile for String {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for Var { impl JITCompile for Var {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for Arg { impl JITCompile for Arg {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for LetVar { impl JITCompile for LetVar {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for Thunk { impl JITCompile for Thunk {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }
impl JITCompile for Path { impl JITCompile for Path {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> { fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!() todo!()
} }
} }

View File

@@ -7,8 +7,9 @@ use inkwell::module::Module;
use inkwell::types::{FloatType, FunctionType, IntType, PointerType, StructType}; use inkwell::types::{FloatType, FunctionType, IntType, PointerType, StructType};
use inkwell::values::{BasicValueEnum, FloatValue, FunctionValue, IntValue, StructValue}; use inkwell::values::{BasicValueEnum, FloatValue, FunctionValue, IntValue, StructValue};
use crate::env::VmEnv; use crate::env::Env;
use crate::eval::Engine; use crate::eval::Engine;
use crate::ty::internal::Value;
use super::{JITContext, JITValue, JITValueData, ValueTag}; use super::{JITContext, JITValue, JITValueData, ValueTag};
@@ -54,7 +55,7 @@ impl<'ctx> Helpers<'ctx> {
let new_thunk = module.add_function( let new_thunk = module.add_function(
"new_thunk", "new_thunk",
value_type.fn_type(&[ptr_type.into()], false), value_type.fn_type(&[ptr_type.into(), ptr_type.into()], false),
None, None,
); );
let debug = module.add_function( let debug = module.add_function(
@@ -102,7 +103,7 @@ impl<'ctx> Helpers<'ctx> {
let call = module.add_function( let call = module.add_function(
"call", "call",
value_type.fn_type( value_type.fn_type(
&[value_type.into(), value_type.into(), ptr_type.into()], &[value_type.into(), ptr_type.into(), ptr_type.into(), ptr_type.into()],
false, false,
), ),
None, None,
@@ -234,11 +235,11 @@ extern "C" fn helper_debug(value: JITValue) {
dbg!(value.tag); dbg!(value.tag);
} }
extern "C" fn helper_capture_env(thunk: JITValue, env: *const VmEnv) { extern "C" fn helper_capture_env(thunk: JITValue, env: *const Env) {
todo!() todo!()
} }
extern "C" fn helper_neg(rhs: JITValue, _env: *const VmEnv) -> JITValue { extern "C" fn helper_neg(rhs: JITValue, _env: *const Env) -> JITValue {
use ValueTag::*; use ValueTag::*;
match rhs.tag { match rhs.tag {
Int => JITValue { Int => JITValue {
@@ -257,7 +258,7 @@ extern "C" fn helper_neg(rhs: JITValue, _env: *const VmEnv) -> JITValue {
} }
} }
extern "C" fn helper_not(rhs: JITValue, _env: *const VmEnv) -> JITValue { extern "C" fn helper_not(rhs: JITValue, _env: *const Env) -> JITValue {
use ValueTag::*; use ValueTag::*;
match rhs.tag { match rhs.tag {
Bool => JITValue { Bool => JITValue {
@@ -338,21 +339,22 @@ extern "C" fn helper_or(lhs: JITValue, rhs: JITValue) -> JITValue {
} }
} }
extern "C" fn helper_call(func: JITValue, arg: JITValue, engine: *mut Engine) -> JITValue { extern "C" fn helper_call(func: JITValue, args: Box<[JITValue]>, engine: NonNull<Engine>, env: NonNull<Env>) -> JITValue {
let func = Value::from(func);
todo!() todo!()
} }
extern "C" fn helper_arg(idx: usize, env: *const VmEnv) -> JITValue { extern "C" fn helper_arg(idx: usize, env: *const Env) -> JITValue {
let env = unsafe { env.as_ref() }.unwrap(); let env = unsafe { env.as_ref() }.unwrap();
let val: JITValue = env.lookup_arg(idx).clone().into(); let val: JITValue = env.lookup_arg(idx).clone().into();
val val
} }
extern "C" fn helper_lookup_let(level: usize, idx: usize, env: *const VmEnv) -> JITValue { extern "C" fn helper_lookup_let(level: usize, idx: usize, env: *const Env) -> JITValue {
todo!() todo!()
} }
extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue { extern "C" fn helper_lookup(sym: usize, env: *const Env) -> JITValue {
todo!() todo!()
} }

View File

@@ -7,11 +7,11 @@ use inkwell::context::Context;
use inkwell::execution_engine::ExecutionEngine; use inkwell::execution_engine::ExecutionEngine;
use inkwell::module::Module; use inkwell::module::Module;
use inkwell::values::{ use inkwell::values::{
AnyValue, AsValueRef, BasicMetadataValueEnum, BasicValueEnum, IntValue, StructValue, AnyValue, BasicMetadataValueEnum, FloatValue, IntValue, StructValue
}; };
use crate::env::VmEnv; use crate::env::Env;
use crate::ir::{Ir, UnOpKind}; use crate::ir::Ir;
use crate::ty::internal::Value; use crate::ty::internal::Value;
mod compile; mod compile;
@@ -60,10 +60,10 @@ impl From<JITValue> for Value {
match value.tag { match value.tag {
Int => Value::Int(unsafe { value.data.int }), Int => Value::Int(unsafe { value.data.int }),
Null => Value::Null, Null => Value::Null,
/* Function => Value::Func(unsafe { Rc::from_raw(value.data.ptr as *const _) }), Function => Value::Func(unsafe { value.data.int as usize}),
Thunk => Value::Thunk(self::Thunk { Thunk => Value::Thunk(unsafe {
thunk: unsafe { Rc::from_raw(value.data.ptr as *const _) }, value.data.int as usize
}), */ }),
_ => todo!("not implemented for {:?}", value.tag), _ => todo!("not implemented for {:?}", value.tag),
} }
} }
@@ -94,7 +94,7 @@ impl From<Value> for JITValue {
} }
pub struct JITFunc<'ctx>(F, PhantomData<&'ctx mut ()>); pub struct JITFunc<'ctx>(F, PhantomData<&'ctx mut ()>);
type F = unsafe extern "C" fn(*const VmEnv) -> JITValue; type F = unsafe extern "C" fn(*const Env) -> JITValue;
impl From<F> for JITFunc<'_> { impl From<F> for JITFunc<'_> {
fn from(value: F) -> Self { fn from(value: F) -> Self {
@@ -144,6 +144,60 @@ impl<'ctx> JITContext<'ctx> {
todo!() todo!()
} }
pub fn get_float(&self, val: StructValue<'ctx>) -> FloatValue<'ctx> {
let alloca = self
.builder
.build_alloca(self.helpers.int_type, "get_value_alloca")
.unwrap();
self.builder.build_store(alloca, val).unwrap();
self.builder
.build_load(
self.helpers.float_type,
self.builder
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
.unwrap(),
"get_value",
)
.unwrap()
.into_float_value()
}
pub fn get_int(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
let alloca = self
.builder
.build_alloca(self.helpers.int_type, "get_value_alloca")
.unwrap();
self.builder.build_store(alloca, val).unwrap();
self.builder
.build_load(
self.helpers.int_type,
self.builder
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
.unwrap(),
"get_value",
)
.unwrap()
.into_int_value()
}
pub fn get_bool(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
let alloca = self
.builder
.build_alloca(self.helpers.bool_type, "get_value_alloca")
.unwrap();
self.builder.build_store(alloca, val).unwrap();
self.builder
.build_load(
self.helpers.bool_type,
self.builder
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
.unwrap(),
"get_value",
)
.unwrap()
.into_int_value()
}
pub fn get_tag(&self, val: StructValue<'ctx>) -> IntValue<'ctx> { pub fn get_tag(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
let alloca = self let alloca = self
.builder .builder
@@ -152,9 +206,9 @@ impl<'ctx> JITContext<'ctx> {
self.builder.build_store(alloca, val).unwrap(); self.builder.build_store(alloca, val).unwrap();
self.builder self.builder
.build_load( .build_load(
self.context.bool_type(), self.helpers.int_type,
self.builder self.builder
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_tag_gep") .build_struct_gep(self.helpers.value_type, alloca, 0, "get_tag_gep")
.unwrap(), .unwrap(),
"get_tag", "get_tag",
) )

View File

@@ -1,30 +1,30 @@
use ecow::EcoVec; use ecow::EcoVec;
use crate::engine::Engine; use crate::engine::Engine;
use crate::env::VmEnv; use crate::env::Env;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::ir::{self, DynAttr}; use crate::ir::{self, DynAttr};
use crate::ty::common::Const; use crate::ty::common::Const;
use crate::ty::internal::{AttrSet, EnvRef, List, ThunkRef, Value}; use crate::ty::internal::{AttrSet, List, Value};
use crate::ty::public::Symbol; use crate::ty::public::Symbol;
pub mod jit; pub mod jit;
pub trait Evaluate { pub trait Evaluate {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value>; fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value>;
} }
impl Evaluate for ir::Attrs { impl Evaluate for ir::Attrs {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
let mut attrs = AttrSet::new( let mut attrs = AttrSet::new(
self.stcs self.stcs
.into_iter() .iter()
.map(|(k, v)| Ok((k, v.eval(engine, env)?))) .map(|(k, v)| Ok((k.clone(), v.eval(engine, env)?)))
.collect::<Result<_>>()?, .collect::<Result<_>>()?,
); );
for DynAttr(k, v) in self.dyns { for DynAttr(k, v) in self.dyns.iter() {
let mut k = k.eval(engine, env)?; let mut k = k.eval(engine, env)?;
k.force(engine, env)?.coerce_to_string(); k.coerce_to_string();
attrs.push_attr(k.unwrap_string(), v.eval(engine, env)?); attrs.push_attr(k.unwrap_string(), v.eval(engine, env)?);
} }
Value::AttrSet(attrs.into()).ok() Value::AttrSet(attrs.into()).ok()
@@ -32,10 +32,10 @@ impl Evaluate for ir::Attrs {
} }
impl Evaluate for ir::List { impl Evaluate for ir::List {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
Value::List(List::from( Value::List(List::from(
self.items self.items
.into_iter() .iter()
.map(|val| val.eval(engine, env)) .map(|val| val.eval(engine, env))
.collect::<Result<EcoVec<_>>>()?, .collect::<Result<EcoVec<_>>>()?,
)) ))
@@ -44,16 +44,16 @@ impl Evaluate for ir::List {
} }
impl Evaluate for ir::HasAttr { impl Evaluate for ir::HasAttr {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
use ir::Attr::*; use ir::Attr::*;
let mut val = self.lhs.eval(engine, env)?; let mut val = self.lhs.eval(engine, env)?;
val.has_attr(self.rhs.into_iter().map(|attr| { val.has_attr(self.rhs.iter().map(|attr| {
Ok(match attr { Ok(match attr {
Str(ident) => ident, Str(ident) => ident.clone(),
Strs(expr) => expr.eval(engine, env)?.unwrap_string(), Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
Dynamic(expr) => { Dynamic(expr) => {
let mut val = expr.eval(engine, env)?; let mut val = expr.eval(engine, env)?;
val.force(engine, env)?.coerce_to_string(); val.coerce_to_string();
val.unwrap_string() val.unwrap_string()
} }
}) })
@@ -63,12 +63,10 @@ impl Evaluate for ir::HasAttr {
} }
impl Evaluate for ir::BinOp { impl Evaluate for ir::BinOp {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
use ir::BinOpKind::*; use ir::BinOpKind::*;
let mut lhs = self.lhs.eval(engine, env)?; let mut lhs = self.lhs.eval(engine, env)?;
let mut rhs = self.rhs.eval(engine, env)?; let mut rhs = self.rhs.eval(engine, env)?;
lhs.force(engine, env)?;
rhs.force(engine, env)?;
match self.kind { match self.kind {
Add => lhs.add(rhs), Add => lhs.add(rhs),
Sub => { Sub => {
@@ -115,10 +113,9 @@ impl Evaluate for ir::BinOp {
} }
impl Evaluate for ir::UnOp { impl Evaluate for ir::UnOp {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
use ir::UnOpKind::*; use ir::UnOpKind::*;
let mut rhs = self.rhs.eval(engine, env)?; let mut rhs = self.rhs.eval(engine, env)?;
rhs.force(engine, env)?;
match self.kind { match self.kind {
Neg => rhs.neg(), Neg => rhs.neg(),
Not => rhs.not(), Not => rhs.not(),
@@ -128,19 +125,19 @@ impl Evaluate for ir::UnOp {
} }
impl Evaluate for ir::Select { impl Evaluate for ir::Select {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
use ir::Attr::*; use ir::Attr::*;
let mut val = self.expr.eval(engine, env)?; let mut val = self.expr.eval(engine, env)?;
if let Some(default) = self.default { if let Some(default) = &self.default {
let default = default.eval(engine, env)?; let default = default.eval(engine, env)?;
val.force(engine, env)?.select_with_default( val.select_with_default(
self.attrpath.into_iter().map(|attr| { self.attrpath.iter().map(|attr| {
Ok(match attr { Ok(match attr {
Str(ident) => ident, Str(ident) => ident.clone(),
Strs(expr) => expr.eval(engine, env)?.unwrap_string(), Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
Dynamic(expr) => { Dynamic(expr) => {
let mut val = expr.eval(engine, env)?; let mut val = expr.eval(engine, env)?;
val.force(engine, env)?.coerce_to_string(); val.coerce_to_string();
val.unwrap_string() val.unwrap_string()
} }
}) })
@@ -148,14 +145,14 @@ impl Evaluate for ir::Select {
default, default,
)?; )?;
} else { } else {
val.force(engine, env)? val
.select(self.attrpath.into_iter().map(|attr| { .select(self.attrpath.iter().map(|attr| {
Ok(match attr { Ok(match attr {
Str(ident) => ident, Str(ident) => ident.clone(),
Strs(expr) => expr.eval(engine, env)?.unwrap_string(), Strs(expr) => expr.eval(engine, env)?.unwrap_string(),
Dynamic(expr) => { Dynamic(expr) => {
let mut val = expr.eval(engine, env)?; let mut val = expr.eval(engine, env)?;
val.force(engine, env)?.coerce_to_string(); val.coerce_to_string();
val.unwrap_string() val.unwrap_string()
} }
}) })
@@ -166,7 +163,7 @@ impl Evaluate for ir::Select {
} }
impl Evaluate for ir::If { impl Evaluate for ir::If {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
// TODO: Error Handling // TODO: Error Handling
let cond = self.cond.eval(engine, env)?.unwrap_bool(); let cond = self.cond.eval(engine, env)?.unwrap_bool();
if cond { if cond {
@@ -178,19 +175,18 @@ impl Evaluate for ir::If {
} }
impl Evaluate for ir::LoadFunc { impl Evaluate for ir::LoadFunc {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
let idx = engine.func_offset + self.idx; let idx = engine.func_offset + self.idx;
Value::Func(idx).ok() Value::Func(idx).ok()
} }
} }
impl Evaluate for ir::Call { impl Evaluate for ir::Call {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
let mut func = self.func.eval(engine, env)?; let mut func = self.func.eval(engine, env)?;
func.force(engine, env)?;
func.call( func.call(
self.args self.args
.into_iter() .iter()
.map(|arg| arg.eval(engine, env)) .map(|arg| arg.eval(engine, env))
.collect::<Result<_>>()?, .collect::<Result<_>>()?,
engine, engine,
@@ -205,13 +201,13 @@ impl Evaluate for ir::Call {
} }
impl Evaluate for ir::Let { impl Evaluate for ir::Let {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
unreachable!() unreachable!()
} }
} }
impl Evaluate for ir::With { impl Evaluate for ir::With {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
let namespace = self.namespace.eval(engine, env)?; let namespace = self.namespace.eval(engine, env)?;
// TODO: Error Handling // TODO: Error Handling
env.enter_with(namespace.unwrap_attr_set().into_inner()); env.enter_with(namespace.unwrap_attr_set().into_inner());
@@ -222,19 +218,19 @@ impl Evaluate for ir::With {
} }
impl Evaluate for ir::Assert { impl Evaluate for ir::Assert {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
todo!() todo!()
} }
} }
impl Evaluate for ir::ConcatStrings { impl Evaluate for ir::ConcatStrings {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
let mut parts = self let mut parts = self
.parts .parts
.into_iter() .iter()
.map(|part| { .map(|part| {
let mut part = part.eval(engine, env)?; let mut part = part.eval(engine, env)?;
part.force(engine, env)?.coerce_to_string(); part.coerce_to_string();
part.ok() part.ok()
}) })
.collect::<Result<Vec<_>>>()? .collect::<Result<Vec<_>>>()?
@@ -250,13 +246,13 @@ impl Evaluate for ir::ConcatStrings {
} }
impl Evaluate for ir::String { impl Evaluate for ir::String {
fn eval(self, _: &mut Engine, _: &mut VmEnv) -> Result<Value> { fn eval(&self, _: &mut Engine, _: &mut Env) -> Result<Value> {
Value::String(self.val).ok() Value::String(self.val.clone()).ok()
} }
} }
impl Evaluate for ir::Const { impl Evaluate for ir::Const {
fn eval(self, _: &mut Engine, _: &mut VmEnv) -> Result<Value> { fn eval(&self, _: &mut Engine, _: &mut Env) -> Result<Value> {
match self.val { match self.val {
Const::Null => Value::Null, Const::Null => Value::Null,
Const::Int(x) => Value::Int(x), Const::Int(x) => Value::Int(x),
@@ -268,33 +264,34 @@ impl Evaluate for ir::Const {
} }
impl Evaluate for ir::Var { impl Evaluate for ir::Var {
fn eval(self, _: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, _: &mut Engine, env: &mut Env) -> Result<Value> {
env.lookup_with(&self.sym).ok_or_else(|| { env.lookup_with(&self.sym).ok_or_else(|| {
Error::EvalError(format!("variable {} not found", Symbol::from(self.sym))) Error::EvalError(format!("variable {} not found", Symbol::from(self.sym.clone())))
}) })
} }
} }
impl Evaluate for ir::Arg { impl Evaluate for ir::Arg {
fn eval(self, _: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, _: &mut Engine, env: &mut Env) -> Result<Value> {
env.lookup_arg(self.level).clone().ok() env.lookup_arg(self.level).clone().ok()
} }
} }
impl Evaluate for ir::LetVar { impl Evaluate for ir::LetVar {
fn eval(self, _: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, _: &mut Engine, env: &mut Env) -> Result<Value> {
unreachable!() unreachable!()
} }
} }
impl Evaluate for ir::Thunk { impl Evaluate for ir::Thunk {
fn eval(self, _: &mut Engine, _: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
Value::Thunk(ThunkRef::new(self.idx)).ok() env.lookup_cache(self.idx, |env| engine.eval_thunk(self.idx, env))
// Value::Thunk(self.idx).ok()
} }
} }
impl Evaluate for ir::MaybeThunk { impl Evaluate for ir::MaybeThunk {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
match self { match self {
ir::MaybeThunk::Const(cnst) => cnst.eval(engine, env), ir::MaybeThunk::Const(cnst) => cnst.eval(engine, env),
ir::MaybeThunk::String(string) => string.eval(engine, env), ir::MaybeThunk::String(string) => string.eval(engine, env),
@@ -304,7 +301,7 @@ impl Evaluate for ir::MaybeThunk {
} }
impl Evaluate for ir::Path { impl Evaluate for ir::Path {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
todo!() todo!()
} }
} }

View File

@@ -9,7 +9,7 @@ use crate::{
use super::{Dep, Func, Ir, LoadFunc, MaybeThunk, SccAnalyzer, SccNode, Thunk}; use super::{Dep, Func, Ir, LoadFunc, MaybeThunk, SccAnalyzer, SccNode, Thunk};
#[derive(Clone, Copy, Unwrap)] #[derive(Clone, Copy, Unwrap, Debug)]
pub enum Index { pub enum Index {
Thunk(usize), Thunk(usize),
Func(usize), Func(usize),
@@ -169,9 +169,11 @@ impl DowngradeContext {
} }
pub fn new_dep(&mut self, this: Index, dep: Dep) -> Result<()> { pub fn new_dep(&mut self, this: Index, dep: Dep) -> Result<()> {
#[cfg(debug_assertions)]
println!("{this:?} => {dep:?}");
match this { match this {
Index::Thunk(idx) => { Index::Thunk(idx) => {
if dep == Dep::Thunk(idx) { if dep == Dep::Thunk(idx) && !matches!(self.thunks[idx].0, Ir::List(_)) {
return Err(Error::DowngradeError( return Err(Error::DowngradeError(
"infinite recursion encountered".into(), "infinite recursion encountered".into(),
)); ));

View File

@@ -8,7 +8,7 @@ use rnix::ast::{self, Expr};
use crate::builtins::ir_env; use crate::builtins::ir_env;
use crate::engine::Engine; use crate::engine::Engine;
use crate::env::VmEnv; use crate::env::Env as VmEnv;
use crate::error::*; use crate::error::*;
use crate::eval::Evaluate; use crate::eval::Evaluate;
use crate::eval::jit::{JITCompile, JITContext}; use crate::eval::jit::{JITCompile, JITContext};
@@ -90,7 +90,7 @@ macro_rules! ir {
} }
impl JITCompile for Ir { impl JITCompile for Ir {
fn compile<'ctx>(self, ctx: &JITContext<'ctx>, func: FunctionValue<'ctx>) -> StructValue<'ctx>{ fn compile<'ctx>(&self, ctx: &JITContext<'ctx>, func: FunctionValue<'ctx>) -> StructValue<'ctx>{
match self { match self {
$(Ir::$ty(ir) => ir.compile(ctx, func),)* $(Ir::$ty(ir) => ir.compile(ctx, func),)*
} }
@@ -98,7 +98,7 @@ macro_rules! ir {
} }
impl Evaluate for Ir { impl Evaluate for Ir {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> { fn eval(&self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
match self { match self {
$(Ir::$ty(ir) => ir.eval(engine, env),)* $(Ir::$ty(ir) => ir.eval(engine, env),)*
} }
@@ -1060,7 +1060,11 @@ impl Let {
env: &Env<'a, 'env>, env: &Env<'a, 'env>,
) -> Result<Ir> { ) -> Result<Ir> {
let map = self.bindings.clone(); let map = self.bindings.clone();
let env = env.enter_let(&map); let mut env = env.enter_let(&map);
self.bindings.into_iter().map(|(_, ir)| {
ir.resolve(self_idx, ctx, &mut env)?;
Ok(())
}).collect::<Result<()>>()?;
self.expr.resolve(self_idx, ctx, &env)?.ok() self.expr.resolve(self_idx, ctx, &env)?.ok()
} }
} }

View File

@@ -18,6 +18,7 @@ pub enum Dep {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct SccGraph { pub struct SccGraph {
nodes: HashMap<usize, SccNode>, nodes: HashMap<usize, SccNode>,
root: usize,
} }
impl SccGraph { impl SccGraph {
@@ -38,6 +39,7 @@ impl SccGraph {
}, },
); );
} }
graph.root = thunk_to_scc[&(ctx.thunks.len() - 1)];
for (from_node_id, from_deps) in ctx.thunk_deps.iter().enumerate() { for (from_node_id, from_deps) in ctx.thunk_deps.iter().enumerate() {
let from_scc_id = thunk_to_scc[&from_node_id]; let from_scc_id = thunk_to_scc[&from_node_id];
@@ -58,28 +60,51 @@ impl SccGraph {
} }
fn sorted(self) -> Vec<SccNode> { fn sorted(self) -> Vec<SccNode> {
let mut in_degrees: HashMap<usize, usize> = self.nodes.keys().map(|&id| (id, 0)).collect(); let mut reachable = HashSet::new();
for node in self.nodes.values() { let mut stack = vec![self.root];
in_degrees.insert(node.id, node.deps.len()); reachable.insert(self.root);
while let Some(id) = stack.pop() {
if let Some(node) = self.nodes.get(&id) {
for &dep_id in &node.deps {
if reachable.insert(dep_id) {
stack.push(dep_id);
}
}
}
} }
let mut in_degrees: HashMap<usize, usize> = HashMap::new();
let mut reverse_adj: HashMap<usize, Vec<usize>> = HashMap::new(); let mut reverse_adj: HashMap<usize, Vec<usize>> = HashMap::new();
for (node_id, node) in &self.nodes {
for &id in &reachable {
in_degrees.insert(id, 0);
}
for &id in &reachable {
if let Some(node) = self.nodes.get(&id) {
for &dep_id in &node.deps { for &dep_id in &node.deps {
reverse_adj.entry(dep_id).or_default().push(*node_id); if reachable.contains(&dep_id) {
reverse_adj.entry(dep_id).or_default().push(id);
*in_degrees.get_mut(&id).unwrap() += 1;
}
}
} }
} }
let mut queue: std::collections::VecDeque<usize> = in_degrees let mut queue: std::collections::VecDeque<usize> = in_degrees
.iter() .iter()
.filter_map(|(&id, &deg)| if deg == 0 { Some(id) } else { None }) .filter(|(_, deg)| **deg == 0)
.map(|(&id, _)| id)
.collect(); .collect();
queue.make_contiguous().sort(); queue.make_contiguous().sort();
let mut sorted_order = Vec::new(); let mut sorted_order = Vec::new();
while let Some(u) = queue.pop_front() { while let Some(u) = queue.pop_front() {
sorted_order.push(self.nodes[&u].clone()); if let Some(node) = self.nodes.get(&u) {
sorted_order.push(node.clone());
}
if let Some(dependents) = reverse_adj.get(&u) { if let Some(dependents) = reverse_adj.get(&u) {
for &v in dependents { for &v in dependents {
@@ -93,8 +118,8 @@ impl SccGraph {
} }
} }
if sorted_order.len() != self.nodes.len() { if sorted_order.len() != reachable.len() {
panic!("Cycle detected in SCC graph, which is impossible!"); panic!("Cycle detected in the reachable part of SCC graph!");
} }
sorted_order sorted_order

View File

@@ -1,15 +1,15 @@
use std::rc::Rc; use std::rc::Rc;
use crate::env::VmEnv; use crate::env::Env;
use crate::ir; use crate::ir;
pub struct Func<'gc> { pub struct Func<'gc> {
pub func: &'gc ir::Func, pub func: &'gc ir::Func,
pub env: Rc<VmEnv>, pub env: Rc<Env>,
} }
impl<'gc> Func<'gc> { impl<'gc> Func<'gc> {
pub fn new(func: &'gc ir::Func, env: Rc<VmEnv>) -> Self { pub fn new(func: &'gc ir::Func, env: Rc<Env>) -> Self {
Self { func, env } Self { func, env }
} }
} }

View File

@@ -5,7 +5,7 @@ use ecow::EcoVec;
use hashbrown::HashSet; use hashbrown::HashSet;
use crate::engine::Engine; use crate::engine::Engine;
use crate::env::VmEnv; use crate::env::Env;
use crate::ty::public as p; use crate::ty::public as p;
use super::Value; use super::Value;

View File

@@ -10,7 +10,7 @@ use super::common::*;
use super::public as p; use super::public as p;
use crate::engine::Engine; use crate::engine::Engine;
use crate::env::{VmEnv, VmEnvWeak}; use crate::env::{Env, VmEnvWeak};
use crate::error::*; use crate::error::*;
mod attrset; mod attrset;
@@ -23,45 +23,6 @@ pub use attrset::*;
pub use list::List; pub use list::List;
pub use primop::*; pub use primop::*;
#[derive(Clone)]
pub enum EnvRef {
Strong(VmEnv),
Weak(VmEnvWeak),
}
#[derive(Clone, Debug)]
pub struct ThunkRef {
pub idx: usize,
// pub env: Option<EnvRef>,
}
impl ThunkRef {
pub fn new(idx: usize) -> Self {
ThunkRef {
idx, /* env: None */
}
}
/*
pub fn capture(&mut self, env: EnvRef) {
let _ = self.env.insert(env);
}
pub fn upgrade(&mut self) {
replace_with_or_abort(&mut self.env, |env| {
env.map(|env| EnvRef::Strong(env.upgraded()))
});
} */
}
/*
impl EnvRef {
pub fn upgraded(self) -> VmEnv {
match self {
EnvRef::Weak(weak) => weak.upgrade(),
EnvRef::Strong(strong) => strong,
}
}
} */
#[derive(IsVariant, Unwrap, Clone, Debug)] #[derive(IsVariant, Unwrap, Clone, Debug)]
pub enum Value { pub enum Value {
Int(i64), Int(i64),
@@ -69,7 +30,7 @@ pub enum Value {
Bool(bool), Bool(bool),
String(EcoString), String(EcoString),
Null, Null,
Thunk(ThunkRef), Thunk(usize),
AttrSet(Rc<AttrSet>), AttrSet(Rc<AttrSet>),
List(List), List(List),
Catchable(EcoString), Catchable(EcoString),
@@ -129,7 +90,7 @@ pub enum ValueAsRef<'v> {
Bool(bool), Bool(bool),
String(&'v EcoString), String(&'v EcoString),
Null, Null,
Thunk(&'v ThunkRef), Thunk(usize),
AttrSet(&'v AttrSet), AttrSet(&'v AttrSet),
List(&'v List), List(&'v List),
Catchable(&'v str), Catchable(&'v str),
@@ -149,7 +110,7 @@ impl Value {
Bool(x) => R::Bool(*x), Bool(x) => R::Bool(*x),
String(x) => R::String(x), String(x) => R::String(x),
Null => R::Null, Null => R::Null,
Thunk(x) => R::Thunk(x), Thunk(x) => R::Thunk(*x),
AttrSet(x) => R::AttrSet(x), AttrSet(x) => R::AttrSet(x),
List(x) => R::List(x), List(x) => R::List(x),
Catchable(x) => R::Catchable(x), Catchable(x) => R::Catchable(x),
@@ -192,7 +153,7 @@ impl Value {
} }
} }
pub fn call(&mut self, args: Vec<Self>, engine: &mut Engine, env: &mut VmEnv) -> Result<()> { pub fn call(&mut self, args: Vec<Self>, engine: &mut Engine, env: &mut Env) -> Result<()> {
use Value::*; use Value::*;
for arg in args.iter() { for arg in args.iter() {
if matches!(arg, Value::Catchable(_)) { if matches!(arg, Value::Catchable(_)) {
@@ -206,6 +167,7 @@ impl Value {
PartialFunc(idx, old) => { PartialFunc(idx, old) => {
let idx = *idx; let idx = *idx;
let len = args.len() + old.len(); let len = args.len() + old.len();
env.reserve_args(len);
env.enter_args(std::mem::take(old)); env.enter_args(std::mem::take(old));
env.enter_cache_level(|env| { env.enter_cache_level(|env| {
let mut args = args.into_iter().peekable(); let mut args = args.into_iter().peekable();
@@ -240,6 +202,7 @@ impl Value {
&mut Func(idx) => { &mut Func(idx) => {
let len = args.len(); let len = args.len();
let mut args = args.into_iter().peekable(); let mut args = args.into_iter().peekable();
env.reserve_args(len);
env.enter_cache_level(|env| { env.enter_cache_level(|env| {
env.enter_arg(args.next().unwrap()); env.enter_arg(args.next().unwrap());
let mut ret = engine.eval_thunk(idx, env)?; let mut ret = engine.eval_thunk(idx, env)?;
@@ -510,18 +473,9 @@ impl Value {
self self
} }
pub fn force(&mut self, engine: &mut Engine, env: &mut VmEnv) -> Result<&mut Self> { pub fn force(&mut self, engine: &mut Engine, env: &mut Env) -> Result<&mut Self> {
if let Value::Thunk(thunk) = self { if let &mut Value::Thunk(idx) = self {
unsafe { *self = env.lookup_cache(idx, |env| engine.eval_thunk(idx, env))?
let old = std::ptr::read(thunk);
match env.lookup_cache(old.idx, |env| engine.eval_thunk(old.idx, env)) {
Ok(ok) => std::ptr::write(self, ok),
Err(err) => {
std::ptr::write(self, Self::Null);
return Err(err);
}
}
}
} }
Ok(self) Ok(self)
} }