feat: lookup at downgrade time
works, but leaks memory
This commit is contained in:
106
src/vm/mod.rs
106
src/vm/mod.rs
@@ -3,7 +3,6 @@ use std::cell::RefCell;
|
||||
use gc_arena::{Arena, Collect, Gc, Mutation, Rootable};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use inkwell::context::Context;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::builtins::vm_env;
|
||||
use crate::bytecode::{BinOp, Func as F, OpCode, OpCodes, Program, UnOp};
|
||||
@@ -88,49 +87,9 @@ pub fn eval<T, F: for<'gc> FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>)
|
||||
}
|
||||
Consq::PopEnv => _ = root.envs.pop().unwrap(),
|
||||
Consq::Call => {
|
||||
use Param::*;
|
||||
let arg = root.stack.pop();
|
||||
let func = root.stack.pop().unwrap_func();
|
||||
let env = func.env;
|
||||
let env = match func.func.param.clone() {
|
||||
Ident(ident) => env.enter_arg(ident, arg, mc),
|
||||
Formals {
|
||||
formals,
|
||||
ellipsis,
|
||||
alias,
|
||||
} => {
|
||||
let arg = arg.unwrap_attr_set();
|
||||
let mut new =
|
||||
HashMap::with_capacity(formals.len() + alias.iter().len());
|
||||
if !ellipsis
|
||||
&& arg
|
||||
.iter()
|
||||
.map(|(k, _)| k)
|
||||
.sorted()
|
||||
.ne(formals.iter().map(|(k, _)| k).sorted())
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
for (formal, default) in formals {
|
||||
// TODO: rec env
|
||||
let arg = arg
|
||||
.select(formal)
|
||||
.or_else(|| {
|
||||
default.map(|idx| {
|
||||
Value::Thunk(
|
||||
Thunk::new(root.vm.get_thunk(idx), mc),
|
||||
)
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
new.insert(formal, arg);
|
||||
}
|
||||
if let Some(alias) = alias {
|
||||
new.insert(alias, Value::AttrSet(arg));
|
||||
}
|
||||
env.enter_let(Gc::new(mc, new), mc)
|
||||
}
|
||||
};
|
||||
let env = func.env.enter_arg(arg, mc);
|
||||
let count = func.count.get();
|
||||
func.count.set(count + 1);
|
||||
if count >= 1 {
|
||||
@@ -200,13 +159,12 @@ fn single_op<'gc, const CAP: usize>(
|
||||
let Some(val) = stack.tos().as_ref().unwrap_thunk().get_value() else {
|
||||
return Ok(Consq::Force);
|
||||
};
|
||||
stack.pop();
|
||||
stack.push(val)?;
|
||||
*stack.tos_mut() = val;
|
||||
}
|
||||
OpCode::InsertValue => {
|
||||
let val = stack.pop();
|
||||
stack.pop().unwrap_thunk().insert_value(val.clone(), mc);
|
||||
let _ = stack.push(val);
|
||||
stack.tos().as_ref().unwrap_thunk().insert_value(val.clone(), mc);
|
||||
*stack.tos_mut() = val;
|
||||
}
|
||||
OpCode::Jmp { step } => return Ok(Consq::Jmp(step)),
|
||||
OpCode::JmpIfFalse { step } => {
|
||||
@@ -218,7 +176,7 @@ fn single_op<'gc, const CAP: usize>(
|
||||
let arg = stack.pop();
|
||||
let func = stack.tos_mut();
|
||||
if func.is_func() {
|
||||
stack.push(arg)?;
|
||||
let _ = stack.push(arg);
|
||||
return Ok(Consq::Call);
|
||||
}
|
||||
func.call(arg, vm, mc)?;
|
||||
@@ -227,6 +185,9 @@ fn single_op<'gc, const CAP: usize>(
|
||||
let func = vm.get_func(idx);
|
||||
stack.push(Value::Func(Gc::new(mc, Func::new(func, *env, mc))))?;
|
||||
}
|
||||
OpCode::Arg { level } => {
|
||||
stack.push(env.lookup_arg(level))?;
|
||||
}
|
||||
OpCode::UnOp { op } => {
|
||||
use UnOp::*;
|
||||
let value = stack.tos_mut();
|
||||
@@ -262,8 +223,8 @@ fn single_op<'gc, const CAP: usize>(
|
||||
OpCode::Path => {
|
||||
todo!()
|
||||
}
|
||||
OpCode::List => {
|
||||
stack.push(Value::List(CoW::new(List::empty(), mc)))?;
|
||||
OpCode::List { cap } => {
|
||||
stack.push(Value::List(CoW::new(List::with_capacity(cap), mc)))?;
|
||||
}
|
||||
OpCode::PushElem => {
|
||||
let elem = stack.pop();
|
||||
@@ -272,22 +233,14 @@ fn single_op<'gc, const CAP: usize>(
|
||||
OpCode::AttrSet { cap } => {
|
||||
stack.push(Value::AttrSet(CoW::new(AttrSet::with_capacity(cap), mc)))?;
|
||||
}
|
||||
OpCode::FinalizeRec => {
|
||||
let mut new = HashMap::new();
|
||||
stack
|
||||
.tos()
|
||||
OpCode::FinalizeLet => {
|
||||
let mut list = stack.pop().unwrap_list();
|
||||
let map = list
|
||||
.as_ref()
|
||||
.unwrap_attr_set()
|
||||
.as_inner()
|
||||
.iter()
|
||||
.map(|(&k, v)| (k, v.clone()))
|
||||
.collect_into(&mut new);
|
||||
*env = env.enter_let(Gc::new(mc, new), mc);
|
||||
stack
|
||||
.tos_mut()
|
||||
.as_mut(mc)
|
||||
.unwrap_attr_set()
|
||||
.capture(*env, mc);
|
||||
.clone()
|
||||
.into_inner();
|
||||
*env = env.enter_let(map, mc);
|
||||
list.make_mut(|list| list.capture(*env, mc), mc);
|
||||
}
|
||||
OpCode::PushStaticAttr { name } => {
|
||||
let val = stack.pop();
|
||||
@@ -296,7 +249,7 @@ fn single_op<'gc, const CAP: usize>(
|
||||
OpCode::PushDynamicAttr => {
|
||||
let val = stack.pop();
|
||||
let sym = stack.pop();
|
||||
let sym = vm.new_sym(sym.unwrap_string().as_ref());
|
||||
let sym = vm.new_sym::<&str>(&sym.unwrap_string());
|
||||
stack.tos_mut().push_attr(sym, val, mc);
|
||||
}
|
||||
OpCode::Select { sym } => {
|
||||
@@ -309,14 +262,14 @@ fn single_op<'gc, const CAP: usize>(
|
||||
OpCode::SelectDynamic => {
|
||||
let mut val = stack.pop();
|
||||
val.coerce_to_string();
|
||||
let sym = vm.new_sym(val.unwrap_string().as_ref());
|
||||
let sym = vm.new_sym::<&str>(&val.unwrap_string());
|
||||
stack.tos_mut().select(sym, vm)?;
|
||||
}
|
||||
OpCode::SelectDynamicOrDefault => {
|
||||
let default = stack.pop();
|
||||
let mut val = stack.pop();
|
||||
val.coerce_to_string();
|
||||
let sym = vm.new_sym(val.unwrap_string().as_ref());
|
||||
let sym = vm.new_sym::<&str>(&val.unwrap_string());
|
||||
stack.tos_mut().select_with_default(sym, default)?;
|
||||
}
|
||||
OpCode::HasAttr { sym } => {
|
||||
@@ -325,25 +278,18 @@ fn single_op<'gc, const CAP: usize>(
|
||||
OpCode::HasDynamicAttr => {
|
||||
let mut val = stack.pop();
|
||||
val.coerce_to_string();
|
||||
let sym = vm.new_sym(val.unwrap_string().as_ref());
|
||||
let sym = vm.new_sym::<&str>(&val.unwrap_string());
|
||||
stack.tos_mut().has_attr(sym);
|
||||
}
|
||||
OpCode::LookUp { sym } => {
|
||||
stack.push(
|
||||
env.lookup_slow(&sym)
|
||||
env.lookup_with(&sym)
|
||||
.ok_or_else(|| Error::EvalError(format!("{} not found", vm.get_sym(sym))))?
|
||||
.clone(),
|
||||
)?;
|
||||
}
|
||||
OpCode::EnterLetEnv => {
|
||||
let mut new = HashMap::new();
|
||||
stack
|
||||
.pop()
|
||||
.unwrap_attr_set()
|
||||
.iter()
|
||||
.map(|(&k, v)| (k, v.clone()))
|
||||
.collect_into(&mut new);
|
||||
*env = env.enter_let(Gc::new(mc, new), mc);
|
||||
OpCode::LookUpLet { level, idx } => {
|
||||
stack.push(env.lookup_let(level, idx))?;
|
||||
}
|
||||
OpCode::LeaveEnv => *env = env.leave(),
|
||||
OpCode::EnterWithEnv => {
|
||||
@@ -401,7 +347,7 @@ impl<'gc> VM<'gc> {
|
||||
self.symbols.borrow()[idx].clone().into()
|
||||
}
|
||||
|
||||
pub fn new_sym(&self, sym: impl Into<EcoString>) -> usize {
|
||||
pub fn new_sym<T: Into<EcoString>>(&self, sym: T) -> usize {
|
||||
let sym = sym.into();
|
||||
if let Some(&idx) = self.symmap.borrow().get(&sym) {
|
||||
idx
|
||||
@@ -420,7 +366,7 @@ impl<'gc> VM<'gc> {
|
||||
|
||||
pub fn compile_func(&'gc self, func: &'gc F) -> JITFunc<'gc> {
|
||||
self.jit
|
||||
.compile_seq(func.opcodes.iter().copied(), self)
|
||||
.compile_seq(func.opcodes.iter().copied().rev(), self)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user