feat(gc): WIP
This commit is contained in:
22
src/env.rs
22
src/env.rs
@@ -11,6 +11,7 @@ pub struct Env<'gc, K: Hash + Eq + Collect<'gc>, V: Collect<'gc>> {
|
|||||||
let_: Gc<'gc, LetEnv<'gc, V>>,
|
let_: Gc<'gc, LetEnv<'gc, V>>,
|
||||||
with: Gc<'gc, With<'gc, K, V>>,
|
with: Gc<'gc, With<'gc, K, V>>,
|
||||||
args: Vec<V>,
|
args: Vec<V>,
|
||||||
|
gc_alloced: Vec<Gc<'gc, V>>,
|
||||||
last: Option<Gc<'gc, Env<'gc, K, V>>>,
|
last: Option<Gc<'gc, Env<'gc, K, V>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,16 +60,17 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: Vec::new(),
|
args: Vec::new(),
|
||||||
|
gc_alloced: Vec::new(),
|
||||||
last: None,
|
last: None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_arg(&self, level: usize) -> V {
|
pub fn lookup_arg(&self, level: usize) -> &V {
|
||||||
self.args[self.args.len() - level - 1].clone()
|
&self.args[self.args.len() - level - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_let(&self, level: usize, idx: usize) -> V {
|
pub fn lookup_let(&self, level: usize, idx: usize) -> &V {
|
||||||
self.let_.lookup(level, idx)
|
self.let_.lookup(level, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +92,7 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
|||||||
let_: self.let_,
|
let_: self.let_,
|
||||||
with: self.with,
|
with: self.with,
|
||||||
last: Some(self),
|
last: Some(self),
|
||||||
|
gc_alloced: Vec::new(),
|
||||||
args
|
args
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -107,6 +110,7 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
|||||||
let_: self.let_.enter_let(map, mc),
|
let_: self.let_.enter_let(map, mc),
|
||||||
with: self.with,
|
with: self.with,
|
||||||
args: self.args.clone(),
|
args: self.args.clone(),
|
||||||
|
gc_alloced: Vec::new(),
|
||||||
last: Some(self),
|
last: Some(self),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -124,11 +128,19 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
|||||||
let_: self.let_,
|
let_: self.let_,
|
||||||
with: self.with.enter(map, mc),
|
with: self.with.enter(map, mc),
|
||||||
args: self.args.clone(),
|
args: self.args.clone(),
|
||||||
|
gc_alloced: Vec::new(),
|
||||||
last: Some(self),
|
last: Some(self),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn alloc_gc(&mut self, val: V, mc: &Mutation<'gc>) -> &'gc V {
|
||||||
|
let gc = Gc::new(mc, val);
|
||||||
|
self.gc_alloced.push(gc);
|
||||||
|
gc.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn leave(&self) -> Gc<'gc, Self> {
|
pub fn leave(&self) -> Gc<'gc, Self> {
|
||||||
self.last.unwrap()
|
self.last.unwrap()
|
||||||
}
|
}
|
||||||
@@ -145,13 +157,13 @@ impl<'gc, V: Clone + Collect<'gc>> LetEnv<'gc, V> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup(&self, level: usize, idx: usize) -> V {
|
pub fn lookup(&self, level: usize, idx: usize) -> &V {
|
||||||
let mut cur = self;
|
let mut cur = self;
|
||||||
for _ in 0..level {
|
for _ in 0..level {
|
||||||
let last = cur.last.unwrap();
|
let last = cur.last.unwrap();
|
||||||
cur = last.as_ref();
|
cur = last.as_ref();
|
||||||
}
|
}
|
||||||
cur.map[idx].clone()
|
&cur.map[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter_let(
|
pub fn enter_let(
|
||||||
|
|||||||
@@ -56,7 +56,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(), ptr_type.into()], false),
|
value_type.fn_type(&[ptr_type.into(), ptr_type.into(), ptr_type.into()], false),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
let debug = module.add_function(
|
let debug = module.add_function(
|
||||||
@@ -110,6 +110,7 @@ impl<'ctx> Helpers<'ctx> {
|
|||||||
value_type.into(),
|
value_type.into(),
|
||||||
ptr_type.into(),
|
ptr_type.into(),
|
||||||
ptr_type.into(),
|
ptr_type.into(),
|
||||||
|
ptr_type.into(),
|
||||||
],
|
],
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
@@ -350,6 +351,7 @@ extern "C" fn helper_call<'gc>(
|
|||||||
func: JITValue,
|
func: JITValue,
|
||||||
arg: JITValue,
|
arg: JITValue,
|
||||||
vm: *const VM<'gc>,
|
vm: *const VM<'gc>,
|
||||||
|
env: *mut VmEnv<'gc>,
|
||||||
mc: *const Mutation<'gc>,
|
mc: *const Mutation<'gc>,
|
||||||
) -> JITValue {
|
) -> JITValue {
|
||||||
let vm = unsafe { vm.as_ref() }.unwrap();
|
let vm = unsafe { vm.as_ref() }.unwrap();
|
||||||
@@ -358,7 +360,8 @@ extern "C" fn helper_call<'gc>(
|
|||||||
match func.tag {
|
match func.tag {
|
||||||
ValueTag::Function => {
|
ValueTag::Function => {
|
||||||
let func = Value::from(func).unwrap_func();
|
let func = Value::from(func).unwrap_func();
|
||||||
func.call_compile(arg, vm, mc).unwrap().into()
|
let env = unsafe { &mut *env };
|
||||||
|
env.alloc_gc(func.call_compile(arg, vm, mc).unwrap(), mc).into()
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
@@ -403,15 +406,17 @@ extern "C" fn helper_force<'gc>(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.compile_seq(opcodes.iter().copied().rev(), vm)
|
.compile_seq(opcodes.iter().copied().rev(), vm)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let val = unsafe { func.call(env.as_ref() as *const _, mc as *const _) };
|
let val = unsafe { func(env.as_ref() as *const _, mc as *const _) };
|
||||||
thunk.insert_value(val.into(), mc);
|
thunk.insert_value(val.into(), mc);
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_new_thunk(opcodes: *const OpCodes, mc: *const Mutation) -> JITValue {
|
extern "C" fn helper_new_thunk<'gc>(opcodes: *const OpCodes, env: *mut VmEnv<'gc>, mc: *const Mutation<'gc>) -> JITValue {
|
||||||
Value::Thunk(Thunk::new(
|
let mc = unsafe { &*mc };
|
||||||
|
let env = unsafe { &mut *env };
|
||||||
|
env.alloc_gc(Value::Thunk(Thunk::new(
|
||||||
unsafe { opcodes.as_ref() }.unwrap(),
|
unsafe { opcodes.as_ref() }.unwrap(),
|
||||||
unsafe { mc.as_ref() }.unwrap(),
|
mc
|
||||||
))
|
)), mc)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use gc_arena::{Collect, Gc, Mutation};
|
use gc_arena::{Collect, Gc, Mutation};
|
||||||
use inkwell::OptimizationLevel;
|
use inkwell::OptimizationLevel;
|
||||||
use inkwell::builder::Builder;
|
use inkwell::builder::Builder;
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
use inkwell::execution_engine::{ExecutionEngine, JitFunction};
|
use inkwell::execution_engine::ExecutionEngine;
|
||||||
use inkwell::module::Module;
|
use inkwell::module::Module;
|
||||||
use inkwell::values::{BasicValueEnum, FunctionValue, PointerValue};
|
use inkwell::values::{BasicValueEnum, FunctionValue, PointerValue};
|
||||||
|
|
||||||
@@ -72,37 +73,13 @@ impl<'gc> From<JITValue> for Value<'gc> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Value<'_>> for JITValue {
|
impl From<&Value<'_>> for JITValue {
|
||||||
fn from(value: &Value<'_>) -> Self {
|
fn from(value: &Value) -> Self {
|
||||||
match *value {
|
|
||||||
Value::Int(int) => JITValue {
|
|
||||||
tag: ValueTag::Int,
|
|
||||||
data: JITValueData { int },
|
|
||||||
},
|
|
||||||
Value::Func(func) => JITValue {
|
|
||||||
tag: ValueTag::Function,
|
|
||||||
data: JITValueData {
|
|
||||||
ptr: Gc::as_ptr(func) as *const _,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Value::Thunk(ref thunk) => JITValue {
|
|
||||||
tag: ValueTag::Thunk,
|
|
||||||
data: JITValueData {
|
|
||||||
ptr: Gc::as_ptr(thunk.thunk) as *const _,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Value<'_>> for JITValue {
|
|
||||||
fn from(value: Value) -> Self {
|
|
||||||
match value {
|
match value {
|
||||||
Value::Int(int) => JITValue {
|
&Value::Int(int) => JITValue {
|
||||||
tag: ValueTag::Int,
|
tag: ValueTag::Int,
|
||||||
data: JITValueData { int },
|
data: JITValueData { int },
|
||||||
},
|
},
|
||||||
Value::Func(func) => JITValue {
|
&Value::Func(func) => JITValue {
|
||||||
tag: ValueTag::Function,
|
tag: ValueTag::Function,
|
||||||
data: JITValueData {
|
data: JITValueData {
|
||||||
ptr: Gc::as_ptr(func) as *const _,
|
ptr: Gc::as_ptr(func) as *const _,
|
||||||
@@ -119,33 +96,25 @@ impl From<Value<'_>> for JITValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct JITFunc<'gc>(
|
pub struct JITFunc<'gc>(F<'gc>, PhantomData<fn(&'gc F<'gc>) -> &'gc F<'gc>>);
|
||||||
JitFunction<'gc, unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue>,
|
type F<'gc> = unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue;
|
||||||
);
|
|
||||||
|
|
||||||
unsafe impl<'gc> Collect<'gc> for JITFunc<'gc> {
|
unsafe impl<'gc> Collect<'gc> for JITFunc<'gc> {
|
||||||
fn trace<T: gc_arena::collect::Trace<'gc>>(&self, _: &mut T) {}
|
fn trace<T: gc_arena::collect::Trace<'gc>>(&self, _: &mut T) {}
|
||||||
const NEEDS_TRACE: bool = false;
|
const NEEDS_TRACE: bool = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc>
|
impl<'gc> From<F<'gc>> for JITFunc<'gc>
|
||||||
From<
|
|
||||||
JitFunction<'gc, unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue>,
|
|
||||||
> for JITFunc<'gc>
|
|
||||||
{
|
{
|
||||||
fn from(
|
fn from(
|
||||||
value: JitFunction<
|
value: F<'gc>
|
||||||
'gc,
|
|
||||||
unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue,
|
|
||||||
>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(value)
|
Self(value, PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> Deref for JITFunc<'gc> {
|
impl<'gc> Deref for JITFunc<'gc> {
|
||||||
type Target =
|
type Target = F<'gc>;
|
||||||
JitFunction<'gc, unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue>;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
@@ -223,7 +192,7 @@ impl<'gc> JITContext<'gc> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let name = func_.get_name().to_str().unwrap();
|
let name = func_.get_name().to_str().unwrap();
|
||||||
let func = self.execution_engine.get_function(name).unwrap();
|
let func = self.execution_engine.get_function(name).unwrap();
|
||||||
Ok(func.into())
|
Ok(JITFunc(func.as_raw(), PhantomData))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
@@ -325,6 +294,7 @@ impl<'gc> JITContext<'gc> {
|
|||||||
self.helpers.new_thunk,
|
self.helpers.new_thunk,
|
||||||
&[
|
&[
|
||||||
self.new_ptr(vm.get_thunk(idx) as *const _).into(),
|
self.new_ptr(vm.get_thunk(idx) as *const _).into(),
|
||||||
|
env.into(),
|
||||||
mc.into(),
|
mc.into(),
|
||||||
],
|
],
|
||||||
"call_capture_env",
|
"call_capture_env",
|
||||||
@@ -477,7 +447,6 @@ impl<'gc> JITContext<'gc> {
|
|||||||
.left()
|
.left()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)?,
|
)?,
|
||||||
|
|
||||||
OpCode::LookUp { sym } => stack.push(
|
OpCode::LookUp { sym } => stack.push(
|
||||||
self.builder
|
self.builder
|
||||||
.build_direct_call(
|
.build_direct_call(
|
||||||
@@ -503,7 +472,7 @@ impl<'gc> JITContext<'gc> {
|
|||||||
.builder
|
.builder
|
||||||
.build_direct_call(
|
.build_direct_call(
|
||||||
self.helpers.call,
|
self.helpers.call,
|
||||||
&[func.into(), arg.into(), self.new_ptr(vm).into(), mc.into()],
|
&[func.into(), arg.into(), self.new_ptr(vm).into(), env.into(), mc.into()],
|
||||||
"call",
|
"call",
|
||||||
)?
|
)?
|
||||||
.try_as_basic_value()
|
.try_as_basic_value()
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ impl<'gc> Func<'gc> {
|
|||||||
.borrow_mut(mc)
|
.borrow_mut(mc)
|
||||||
.get_or_insert_with(|| vm.compile_func(self.func))
|
.get_or_insert_with(|| vm.compile_func(self.func))
|
||||||
.clone();
|
.clone();
|
||||||
let ret = unsafe { compiled.call(env.as_ref() as *const VmEnv, mc as *const _) };
|
let ret = unsafe { compiled(env.as_ref() as *const VmEnv, mc as *const _) };
|
||||||
Ok(ret.into())
|
Ok(ret.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,19 +7,12 @@ use crate::env::VmEnv;
|
|||||||
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq, Collect)]
|
||||||
|
#[collect(no_drop)]
|
||||||
pub struct List<'gc> {
|
pub struct List<'gc> {
|
||||||
data: Vec<Value<'gc>>,
|
data: Vec<Value<'gc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'gc> Collect<'gc> for List<'gc> {
|
|
||||||
fn trace<Tr: gc_arena::collect::Trace<'gc>>(&self, cc: &mut Tr) {
|
|
||||||
for v in self.data.iter() {
|
|
||||||
v.trace(cc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'gc> List<'gc> {
|
impl<'gc> List<'gc> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
List {
|
List {
|
||||||
|
|||||||
@@ -562,9 +562,9 @@ impl<'gc> Thunk<'gc> {
|
|||||||
*self.thunk.borrow_mut(mc) = _Thunk::Value(value);
|
*self.thunk.borrow_mut(mc) = _Thunk::Value(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_value(&self) -> Option<Value<'gc>> {
|
pub fn get_value(&self) -> Option<&Value<'gc>> {
|
||||||
if let _Thunk::Value(val) = &*self.thunk.borrow() {
|
if let _Thunk::Value(val) = unsafe { &*self.thunk.as_ptr() } {
|
||||||
Some(val.clone())
|
Some(val)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use gc_arena::arena::CollectionPhase;
|
||||||
use gc_arena::{Arena, Collect, Gc, Mutation, Rootable};
|
use gc_arena::{Arena, Collect, Gc, Mutation, Rootable};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
@@ -21,6 +22,7 @@ use ecow::EcoString;
|
|||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
const STACK_SIZE: usize = 8 * 1024 / size_of::<Value>();
|
const STACK_SIZE: usize = 8 * 1024 / size_of::<Value>();
|
||||||
|
const COLLECTOR_GRANULARITY: f64 = 1024.0;
|
||||||
|
|
||||||
#[derive(Collect)]
|
#[derive(Collect)]
|
||||||
#[collect(require_static)]
|
#[collect(require_static)]
|
||||||
@@ -59,6 +61,7 @@ pub fn run(mut prog: Program) -> Result<p::Value> {
|
|||||||
Ok(val.to_public(&root.vm, &mut HashSet::new()))
|
Ok(val.to_public(&root.vm, &mut HashSet::new()))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval<T, F: for<'gc> FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>) -> Result<T>>(
|
pub fn eval<T, F: for<'gc> FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>) -> Result<T>>(
|
||||||
opcodes: Box<[OpCode]>,
|
opcodes: Box<[OpCode]>,
|
||||||
arena: &mut Arena<impl for<'gc> Rootable<'gc, Root = GcRoot<'gc>>>,
|
arena: &mut Arena<impl for<'gc> Rootable<'gc, Root = GcRoot<'gc>>>,
|
||||||
@@ -85,21 +88,23 @@ pub fn eval<T, F: for<'gc> FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>)
|
|||||||
opcodes.extend(code);
|
opcodes.extend(code);
|
||||||
root.envs.push(env);
|
root.envs.push(env);
|
||||||
}
|
}
|
||||||
Consq::PopEnv => _ = root.envs.pop().unwrap(),
|
Consq::PopEnv => {
|
||||||
|
let _ = root.envs.pop().unwrap();
|
||||||
|
}
|
||||||
Consq::Call => {
|
Consq::Call => {
|
||||||
let arg = root.stack.pop();
|
let arg = root.stack.pop();
|
||||||
let func = root.stack.pop().unwrap_func();
|
let func = root.stack.pop().unwrap_func();
|
||||||
let env = func.env.enter_arg(arg, mc);
|
let env = func.env.enter_arg(arg, mc);
|
||||||
let count = func.count.get();
|
let count = func.count.get();
|
||||||
func.count.set(count + 1);
|
func.count.set(count + 1);
|
||||||
if count >= 1 {
|
if count > 1 {
|
||||||
let compiled = func
|
let compiled = func
|
||||||
.compiled
|
.compiled
|
||||||
.borrow_mut(mc)
|
.borrow_mut(mc)
|
||||||
.get_or_insert_with(|| root.vm.compile_func(func.func))
|
.get_or_insert_with(|| root.vm.compile_func(func.func))
|
||||||
.clone();
|
.clone();
|
||||||
let ret =
|
let ret =
|
||||||
unsafe { compiled.call(env.as_ref() as *const VmEnv, mc as *const _) };
|
unsafe { compiled(env.as_ref() as *const VmEnv, mc as *const _) };
|
||||||
root.stack.push(ret.into())?;
|
root.stack.push(ret.into())?;
|
||||||
} else {
|
} else {
|
||||||
root.envs.push(env);
|
root.envs.push(env);
|
||||||
@@ -110,7 +115,13 @@ pub fn eval<T, F: for<'gc> FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>)
|
|||||||
}
|
}
|
||||||
Result::Ok(())
|
Result::Ok(())
|
||||||
})?;
|
})?;
|
||||||
arena.finish_cycle();
|
if arena.metrics().allocation_debt() > COLLECTOR_GRANULARITY {
|
||||||
|
if arena.collection_phase() == CollectionPhase::Sweeping {
|
||||||
|
arena.collect_debt();
|
||||||
|
} else if let Some(marked) = arena.mark_debt() {
|
||||||
|
marked.start_sweeping();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
arena.collect_debt();
|
arena.collect_debt();
|
||||||
arena.mutate_root(|mc, root| {
|
arena.mutate_root(|mc, root| {
|
||||||
@@ -128,6 +139,11 @@ enum Consq {
|
|||||||
NoOp,
|
NoOp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CycleAction {
|
||||||
|
Collect,
|
||||||
|
NoOp
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn single_op<'gc, const CAP: usize>(
|
fn single_op<'gc, const CAP: usize>(
|
||||||
vm: &'gc VM<'gc>,
|
vm: &'gc VM<'gc>,
|
||||||
@@ -159,7 +175,7 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
let Some(val) = stack.tos().as_ref().unwrap_thunk().get_value() else {
|
let Some(val) = stack.tos().as_ref().unwrap_thunk().get_value() else {
|
||||||
return Ok(Consq::Force);
|
return Ok(Consq::Force);
|
||||||
};
|
};
|
||||||
*stack.tos_mut() = val;
|
*stack.tos_mut() = val.clone();
|
||||||
}
|
}
|
||||||
OpCode::InsertValue => {
|
OpCode::InsertValue => {
|
||||||
let val = stack.pop();
|
let val = stack.pop();
|
||||||
@@ -186,7 +202,7 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
stack.push(Value::Func(Gc::new(mc, Func::new(func, *env, mc))))?;
|
stack.push(Value::Func(Gc::new(mc, Func::new(func, *env, mc))))?;
|
||||||
}
|
}
|
||||||
OpCode::Arg { level } => {
|
OpCode::Arg { level } => {
|
||||||
stack.push(env.lookup_arg(level))?;
|
stack.push(env.lookup_arg(level).clone())?;
|
||||||
}
|
}
|
||||||
OpCode::UnOp { op } => {
|
OpCode::UnOp { op } => {
|
||||||
use UnOp::*;
|
use UnOp::*;
|
||||||
@@ -289,7 +305,7 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
OpCode::LookUpLet { level, idx } => {
|
OpCode::LookUpLet { level, idx } => {
|
||||||
stack.push(env.lookup_let(level, idx))?;
|
stack.push(env.lookup_let(level, idx).clone())?;
|
||||||
}
|
}
|
||||||
OpCode::LeaveEnv => *env = env.leave(),
|
OpCode::LeaveEnv => *env = env.leave(),
|
||||||
OpCode::EnterWithEnv => {
|
OpCode::EnterWithEnv => {
|
||||||
|
|||||||
Reference in New Issue
Block a user