feat: less gc (WIP)
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -324,6 +324,7 @@ dependencies = [
|
|||||||
"inkwell",
|
"inkwell",
|
||||||
"itertools",
|
"itertools",
|
||||||
"regex",
|
"regex",
|
||||||
|
"replace_with",
|
||||||
"rnix",
|
"rnix",
|
||||||
"rustyline",
|
"rustyline",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
@@ -398,6 +399,12 @@ version = "0.8.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "replace_with"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rnix"
|
name = "rnix"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ derive_more = { version = "2.0", features = ["full"] }
|
|||||||
ecow = "0.2"
|
ecow = "0.2"
|
||||||
regex = "1.11"
|
regex = "1.11"
|
||||||
hashbrown = "0.15"
|
hashbrown = "0.15"
|
||||||
|
replace_with = "0.1"
|
||||||
inkwell = { version = "0.6.0", features = ["llvm18-1"] }
|
inkwell = { version = "0.6.0", features = ["llvm18-1"] }
|
||||||
gc-arena = { git = "https://github.com/kyren/gc-arena", rev = "d651e3b4363d525a2d502c2305bc73e291835c84", features= ["hashbrown"] }
|
gc-arena = { git = "https://github.com/kyren/gc-arena", rev = "d651e3b4363d525a2d502c2305bc73e291835c84", features= ["hashbrown"] }
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use gc_arena::{Gc, Mutation};
|
use gc_arena::{Gc, Mutation};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use crate::env::VmEnv;
|
use crate::env::VmEnv;
|
||||||
use crate::ir::{DowngradeContext, Ir};
|
use crate::ir::{DowngradeContext, Ir};
|
||||||
use crate::ty::common::Const;
|
use crate::ty::common::Const;
|
||||||
use crate::ty::internal::{AttrSet, CoW, PrimOp, Value};
|
use crate::ty::internal::{AttrSet, PrimOp, Value};
|
||||||
use crate::vm::VM;
|
use crate::vm::VM;
|
||||||
|
|
||||||
pub fn ir_env(ctx: &mut DowngradeContext) -> HashMap<usize, Ir> {
|
pub fn ir_env(ctx: &mut DowngradeContext) -> HashMap<usize, Ir> {
|
||||||
@@ -21,7 +23,7 @@ pub fn vm_env<'gc>(vm: &VM, mc: &Mutation<'gc>) -> Gc<'gc, VmEnv<'gc>> {
|
|||||||
let Ok([mut first, second]): Result<[Value; 2], _> = args.try_into() else {
|
let Ok([mut first, second]): Result<[Value; 2], _> = args.try_into() else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
first.add(second, mc);
|
first.add(second);
|
||||||
first.ok()
|
first.ok()
|
||||||
}),
|
}),
|
||||||
PrimOp::new("sub", 2, |args, _, mc| {
|
PrimOp::new("sub", 2, |args, _, mc| {
|
||||||
@@ -29,7 +31,7 @@ pub fn vm_env<'gc>(vm: &VM, mc: &Mutation<'gc>) -> Gc<'gc, VmEnv<'gc>> {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
second.neg();
|
second.neg();
|
||||||
first.add(second, mc);
|
first.add(second);
|
||||||
first.ok()
|
first.ok()
|
||||||
}),
|
}),
|
||||||
PrimOp::new("mul", 2, |args, _, _| {
|
PrimOp::new("mul", 2, |args, _, _| {
|
||||||
@@ -75,15 +77,15 @@ pub fn vm_env<'gc>(vm: &VM, mc: &Mutation<'gc>) -> Gc<'gc, VmEnv<'gc>> {
|
|||||||
|
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
for primop in primops {
|
for primop in primops {
|
||||||
let primop = Gc::new(mc, primop);
|
let primop = Rc::new(primop);
|
||||||
env_map.insert(
|
env_map.insert(
|
||||||
vm.new_sym(format!("__{}", primop.name)),
|
vm.new_sym(format!("__{}", primop.name)),
|
||||||
Value::PrimOp(primop),
|
Value::PrimOp(primop.clone()),
|
||||||
);
|
);
|
||||||
map.insert(vm.new_sym(primop.name), Value::PrimOp(primop));
|
map.insert(vm.new_sym(primop.name), Value::PrimOp(primop));
|
||||||
}
|
}
|
||||||
let sym = vm.new_sym("builtins");
|
let sym = vm.new_sym("builtins");
|
||||||
let mut attrs = CoW::new(AttrSet::new(map), mc);
|
/* let mut attrs = CoW::new(AttrSet::new(map), mc);
|
||||||
unsafe {
|
unsafe {
|
||||||
attrs.make_cyclic(|attrs, this| {
|
attrs.make_cyclic(|attrs, this| {
|
||||||
let _ = attrs.push_attr(sym, Value::AttrSet(this));
|
let _ = attrs.push_attr(sym, Value::AttrSet(this));
|
||||||
@@ -91,7 +93,7 @@ pub fn vm_env<'gc>(vm: &VM, mc: &Mutation<'gc>) -> Gc<'gc, VmEnv<'gc>> {
|
|||||||
}
|
}
|
||||||
let builtins = Value::AttrSet(attrs);
|
let builtins = Value::AttrSet(attrs);
|
||||||
|
|
||||||
env_map.insert(sym, builtins);
|
env_map.insert(sym, builtins); */
|
||||||
// TODO:
|
// TODO:
|
||||||
// VmEnv::new(Gc::new(mc, env_map), mc)
|
// VmEnv::new(Gc::new(mc, env_map), mc)
|
||||||
VmEnv::new(Vec::new(), mc)
|
VmEnv::new(Vec::new(), mc)
|
||||||
|
|||||||
22
src/env.rs
22
src/env.rs
@@ -11,7 +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>>,
|
jit_store: Vec<Box<V>>,
|
||||||
last: Option<Gc<'gc, Env<'gc, K, V>>>,
|
last: Option<Gc<'gc, Env<'gc, K, V>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: Vec::new(),
|
args: Vec::new(),
|
||||||
gc_alloced: Vec::new(),
|
jit_store: Vec::new(),
|
||||||
last: None,
|
last: None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -92,7 +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(),
|
jit_store: Vec::new(),
|
||||||
args
|
args
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -110,7 +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(),
|
jit_store: Vec::new(),
|
||||||
last: Some(self),
|
last: Some(self),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -128,17 +128,21 @@ 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(),
|
jit_store: Vec::new(),
|
||||||
last: Some(self),
|
last: Some(self),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn alloc_gc(&mut self, val: V, mc: &Mutation<'gc>) -> &'gc V {
|
pub fn jit_store(&'gc mut self, val: V) -> &'gc V {
|
||||||
let gc = Gc::new(mc, val);
|
self.jit_store.push(Box::new(val));
|
||||||
self.gc_alloced.push(gc);
|
&self.jit_store[self.jit_store.len() - 1]
|
||||||
gc.as_ref()
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn jit_stored(&self) -> usize {
|
||||||
|
self.jit_store.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn leave(&self) -> Gc<'gc, Self> {
|
pub fn leave(&self) -> Gc<'gc, Self> {
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ extern "C" fn helper_call<'gc>(
|
|||||||
ValueTag::Function => {
|
ValueTag::Function => {
|
||||||
let func = Value::from(func).unwrap_func();
|
let func = Value::from(func).unwrap_func();
|
||||||
let env = unsafe { &mut *env };
|
let env = unsafe { &mut *env };
|
||||||
env.alloc_gc(func.call_compile(arg, vm, mc).unwrap(), mc).into()
|
func.call_compile(arg, vm, mc).unwrap().clone().into()
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
@@ -369,19 +369,19 @@ extern "C" fn helper_call<'gc>(
|
|||||||
|
|
||||||
extern "C" fn helper_arg(idx: usize, env: *const VmEnv) -> JITValue {
|
extern "C" fn helper_arg(idx: usize, env: *const VmEnv) -> JITValue {
|
||||||
let env = unsafe { env.as_ref() }.unwrap();
|
let env = unsafe { env.as_ref() }.unwrap();
|
||||||
let val: JITValue = env.lookup_arg(idx).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 VmEnv) -> JITValue {
|
||||||
let env = unsafe { env.as_ref() }.unwrap();
|
let env = unsafe { env.as_ref() }.unwrap();
|
||||||
let val: JITValue = env.lookup_let(level, idx).into();
|
let val: JITValue = env.lookup_let(level, idx).clone().into();
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue {
|
extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue {
|
||||||
let env = unsafe { env.as_ref() }.unwrap();
|
let env = unsafe { env.as_ref() }.unwrap();
|
||||||
let val: JITValue = env.lookup_with(&sym).unwrap().into();
|
let val: JITValue = env.lookup_with(&sym).unwrap().clone().into();
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +399,7 @@ extern "C" fn helper_force<'gc>(
|
|||||||
let mc = unsafe { mc.as_ref() }.unwrap();
|
let mc = unsafe { mc.as_ref() }.unwrap();
|
||||||
let thunk = Value::from(thunk).unwrap_thunk();
|
let thunk = Value::from(thunk).unwrap_thunk();
|
||||||
if let Some(val) = thunk.get_value() {
|
if let Some(val) = thunk.get_value() {
|
||||||
return val.into();
|
return val.clone().into();
|
||||||
}
|
}
|
||||||
let (opcodes, env) = thunk.suspend(mc).unwrap();
|
let (opcodes, env) = thunk.suspend(mc).unwrap();
|
||||||
let func = unsafe { jit.as_ref() }
|
let func = unsafe { jit.as_ref() }
|
||||||
@@ -414,9 +414,9 @@ extern "C" fn helper_force<'gc>(
|
|||||||
extern "C" fn helper_new_thunk<'gc>(opcodes: *const OpCodes, env: *mut VmEnv<'gc>, mc: *const Mutation<'gc>) -> JITValue {
|
extern "C" fn helper_new_thunk<'gc>(opcodes: *const OpCodes, env: *mut VmEnv<'gc>, mc: *const Mutation<'gc>) -> JITValue {
|
||||||
let mc = unsafe { &*mc };
|
let mc = unsafe { &*mc };
|
||||||
let env = unsafe { &mut *env };
|
let env = unsafe { &mut *env };
|
||||||
env.alloc_gc(Value::Thunk(Thunk::new(
|
Value::Thunk(Thunk::new(
|
||||||
unsafe { opcodes.as_ref() }.unwrap(),
|
unsafe { opcodes.as_ref() }.unwrap(),
|
||||||
mc
|
mc
|
||||||
)), mc)
|
))
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use gc_arena::{Collect, Gc, Mutation};
|
use gc_arena::{Collect, Gc, Mutation};
|
||||||
@@ -63,7 +64,7 @@ impl<'gc> From<JITValue> for Value<'gc> {
|
|||||||
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 { Gc::from_ptr(value.data.ptr as *const _) }),
|
Function => Value::Func(unsafe { Rc::from_raw(value.data.ptr as *const _) }),
|
||||||
Thunk => Value::Thunk(self::Thunk {
|
Thunk => Value::Thunk(self::Thunk {
|
||||||
thunk: unsafe { Gc::from_ptr(value.data.ptr as *const _) },
|
thunk: unsafe { Gc::from_ptr(value.data.ptr as *const _) },
|
||||||
}),
|
}),
|
||||||
@@ -72,19 +73,21 @@ 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 {
|
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) => {
|
||||||
tag: ValueTag::Function,
|
JITValue {
|
||||||
data: JITValueData {
|
tag: ValueTag::Function,
|
||||||
ptr: Gc::as_ptr(func) as *const _,
|
data: JITValueData {
|
||||||
},
|
ptr: Rc::into_raw(func) as *const _,
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
Value::Thunk(thunk) => JITValue {
|
Value::Thunk(thunk) => JITValue {
|
||||||
tag: ValueTag::Thunk,
|
tag: ValueTag::Thunk,
|
||||||
data: JITValueData {
|
data: JITValueData {
|
||||||
|
|||||||
@@ -12,12 +12,17 @@ use super::super::public as p;
|
|||||||
use super::Value;
|
use super::Value;
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Constructor, Clone, PartialEq, Collect)]
|
#[derive(Constructor, Clone, PartialEq)]
|
||||||
#[collect(no_drop)]
|
|
||||||
pub struct AttrSet<'gc> {
|
pub struct AttrSet<'gc> {
|
||||||
data: HashMap<usize, Value<'gc>>,
|
data: HashMap<usize, Value<'gc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<'gc> Collect<'gc> for AttrSet<'gc> {
|
||||||
|
fn trace<T: gc_arena::collect::Trace<'gc>>(&self, cc: &mut T) {
|
||||||
|
self.data.trace(cc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'gc> From<HashMap<usize, Value<'gc>>> for AttrSet<'gc> {
|
impl<'gc> From<HashMap<usize, Value<'gc>>> for AttrSet<'gc> {
|
||||||
fn from(data: HashMap<usize, Value<'gc>>) -> Self {
|
fn from(data: HashMap<usize, Value<'gc>>) -> Self {
|
||||||
Self { data }
|
Self { data }
|
||||||
|
|||||||
@@ -7,12 +7,17 @@ use crate::env::VmEnv;
|
|||||||
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Collect)]
|
#[derive(Clone, PartialEq)]
|
||||||
#[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<T: gc_arena::collect::Trace<'gc>>(&self, cc: &mut T) {
|
||||||
|
self.data.trace(cc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'gc> List<'gc> {
|
impl<'gc> List<'gc> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
List {
|
List {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::ops::Deref;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use derive_more::{IsVariant, Unwrap};
|
use derive_more::{IsVariant, Unwrap};
|
||||||
use gc_arena::Mutation;
|
use gc_arena::Mutation;
|
||||||
use gc_arena::lock::RefLock;
|
use gc_arena::lock::RefLock;
|
||||||
use gc_arena::{Collect, Gc, lock::GcRefLock};
|
use gc_arena::{Collect, Gc, lock::GcRefLock};
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
|
use replace_with::replace_with_or_abort;
|
||||||
|
|
||||||
use super::common::*;
|
use super::common::*;
|
||||||
use super::public as p;
|
use super::public as p;
|
||||||
@@ -27,95 +27,22 @@ pub use func::*;
|
|||||||
pub use list::List;
|
pub use list::List;
|
||||||
pub use primop::*;
|
pub use primop::*;
|
||||||
|
|
||||||
#[derive(Collect)]
|
|
||||||
#[collect(unsafe_drop)]
|
|
||||||
pub struct CoW<'gc, T: Clone + Collect<'gc>> {
|
|
||||||
inner: Gc<'gc, CoWInner<'gc, T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Collect)]
|
|
||||||
#[collect(no_drop)]
|
|
||||||
struct CoWInner<'gc, T: Clone + Collect<'gc>> {
|
|
||||||
ref_count: Cell<usize>,
|
|
||||||
data: GcRefLock<'gc, T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(mutable_transmutes)]
|
|
||||||
impl<'gc, T: Clone + Collect<'gc>> CoW<'gc, T> {
|
|
||||||
pub fn new(data: T, mc: &Mutation<'gc>) -> Self {
|
|
||||||
Self {
|
|
||||||
inner: Gc::new(mc, CoWInner::new(data, mc)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn make_cyclic(&mut self, f: impl FnOnce(&mut T, Self), mc: &Mutation<'gc>) {
|
|
||||||
let inner = self.inner;
|
|
||||||
self.make_mut(|self_mut| f(self_mut, Self { inner }), mc);
|
|
||||||
self.inner.ref_count.set(self.inner.ref_count.get() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_mut<U>(&mut self, f: impl FnOnce(&mut T) -> U, mc: &Mutation<'gc>) -> U {
|
|
||||||
if self.inner.ref_count.get() == 1 {
|
|
||||||
f(&mut *self.inner.data.borrow_mut(mc))
|
|
||||||
} else {
|
|
||||||
*self = CoW::new(self.inner.data.borrow().clone(), mc);
|
|
||||||
f(&mut *self.inner.data.borrow_mut(mc))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ptr(&self) -> *const T {
|
|
||||||
&*self.as_ref() as *const T
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ref(&self) -> std::cell::Ref<'_, T> {
|
|
||||||
self.inner.data.borrow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'gc, T: Clone + Collect<'gc>> Deref for CoW<'gc, T> {
|
|
||||||
type Target = T;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
unsafe { self.as_ptr().as_ref() }.unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'gc, T: Clone + Collect<'gc>> Clone for CoW<'gc, T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
self.inner.ref_count.set(self.inner.ref_count.get() + 1);
|
|
||||||
Self { inner: self.inner }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'gc, T: Clone + Collect<'gc>> Drop for CoW<'gc, T> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.inner.ref_count.set(self.inner.ref_count.get() - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'gc, T: Clone + Collect<'gc>> CoWInner<'gc, T> {
|
|
||||||
fn new(data: T, mc: &Mutation<'gc>) -> Self {
|
|
||||||
Self {
|
|
||||||
ref_count: Cell::new(1),
|
|
||||||
data: Gc::new(mc, RefLock::new(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(IsVariant, Unwrap, Clone, Collect)]
|
#[derive(IsVariant, Unwrap, Clone, Collect)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
|
// #[derive(IsVariant, Unwrap, Clone)]
|
||||||
pub enum Value<'gc> {
|
pub enum Value<'gc> {
|
||||||
Int(i64),
|
Int(i64),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
String(CoW<'gc, String>),
|
String(Rc<String>),
|
||||||
Null,
|
Null,
|
||||||
Thunk(Thunk<'gc>),
|
Thunk(Thunk<'gc>),
|
||||||
AttrSet(CoW<'gc, AttrSet<'gc>>),
|
AttrSet(Rc<AttrSet<'gc>>),
|
||||||
List(CoW<'gc, List<'gc>>),
|
List(Rc<List<'gc>>),
|
||||||
Catchable(Gc<'gc, String>),
|
Catchable(Rc<String>),
|
||||||
PrimOp(Gc<'gc, PrimOp>),
|
PrimOp(Rc<PrimOp>),
|
||||||
PartialPrimOp(CoW<'gc, PartialPrimOp<'gc>>),
|
PartialPrimOp(Rc<PartialPrimOp<'gc>>),
|
||||||
Func(Gc<'gc, Func<'gc>>),
|
Func(Rc<Func<'gc>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for Value<'_> {
|
impl Hash for Value<'_> {
|
||||||
@@ -123,18 +50,9 @@ impl Hash for Value<'_> {
|
|||||||
use Value::*;
|
use Value::*;
|
||||||
std::mem::discriminant(self).hash(state);
|
std::mem::discriminant(self).hash(state);
|
||||||
match self {
|
match self {
|
||||||
Int(x) => x.hash(state),
|
AttrSet(x) => Rc::as_ptr(x).hash(state),
|
||||||
Float(x) => x.to_bits().hash(state),
|
List(x) => Rc::as_ptr(x).hash(state),
|
||||||
Bool(x) => x.hash(state),
|
_ => 0.hash(state),
|
||||||
Null => (),
|
|
||||||
String(x) => x.as_ptr().hash(state),
|
|
||||||
Thunk(x) => (x as *const self::Thunk).hash(state),
|
|
||||||
AttrSet(x) => x.as_ptr().hash(state),
|
|
||||||
List(x) => x.as_ptr().hash(state),
|
|
||||||
Catchable(x) => x.hash(state),
|
|
||||||
PrimOp(x) => (x.as_ref() as *const self::PrimOp).hash(state),
|
|
||||||
PartialPrimOp(x) => x.as_ptr().hash(state),
|
|
||||||
Func(x) => (x.as_ref() as *const self::Func).hash(state),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,8 +79,8 @@ impl<'gc> PartialEq for Value<'gc> {
|
|||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(AttrSet(a), AttrSet(b)) => a.as_ptr().eq(&b.as_ptr()),
|
(AttrSet(a), AttrSet(b)) => Rc::as_ptr(a).eq(&Rc::as_ptr(b)),
|
||||||
(List(a), List(b)) => a.as_ptr().eq(&b.as_ptr()),
|
(List(a), List(b)) => Rc::as_ptr(a).eq(&Rc::as_ptr(b)),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,22 +236,23 @@ impl<'gc> Value<'gc> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, other: Self, mc: &Mutation<'gc>) {
|
pub fn add(&mut self, other: Self) {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
*self = match (&*self, other) {
|
replace_with_or_abort(self, |a| {
|
||||||
(Int(a), Int(b)) => Int(a + b),
|
match (a, other) {
|
||||||
(Int(a), Float(b)) => Float(*a as f64 + b),
|
(Int(a), Int(b)) => Int(a + b),
|
||||||
(Float(a), Int(b)) => Float(a + b as f64),
|
(Int(a), Float(b)) => Float(a as f64 + b),
|
||||||
(Float(a), Float(b)) => Float(a + b),
|
(Float(a), Int(b)) => Float(a + b as f64),
|
||||||
(String(a), String(b)) => {
|
(Float(a), Float(b)) => Float(a + b),
|
||||||
let mut a = a.clone();
|
(String(mut a), String(b)) => {
|
||||||
a.make_mut(|a| a.push_str(b.as_str()), mc);
|
Rc::make_mut(&mut a).push_str(&b);
|
||||||
String(a)
|
String(a)
|
||||||
|
}
|
||||||
|
(a @ Value::Catchable(_), _) => a,
|
||||||
|
(_, x @ Value::Catchable(_)) => x,
|
||||||
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
(Value::Catchable(_), _) => return,
|
});
|
||||||
(_, x @ Value::Catchable(_)) => x,
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mul(&mut self, other: Self) {
|
pub fn mul(&mut self, other: Self) {
|
||||||
@@ -367,11 +286,10 @@ impl<'gc> Value<'gc> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn concat_string(&mut self, mut other: Self, mc: &Mutation<'gc>) -> &mut Self {
|
pub fn concat_string(&mut self, mut other: Self) -> &mut Self {
|
||||||
match (self.coerce_to_string(), other.coerce_to_string()) {
|
match (self.coerce_to_string(), other.coerce_to_string()) {
|
||||||
(Value::String(a), Value::String(b)) => {
|
(Value::String(a), Value::String(b)) => {
|
||||||
let mut a = a.clone();
|
Rc::make_mut(a).push_str(b.as_str());
|
||||||
a.make_mut(|a| a.push_str(b.as_str()), mc);
|
|
||||||
}
|
}
|
||||||
(_, Value::Catchable(_)) => *self = other,
|
(_, Value::Catchable(_)) => *self = other,
|
||||||
(Value::Catchable(_), _) => (),
|
(Value::Catchable(_), _) => (),
|
||||||
@@ -380,9 +298,9 @@ impl<'gc> Value<'gc> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, elem: Self, mc: &Mutation<'gc>) -> &mut Self {
|
pub fn push(&mut self, elem: Self) -> &mut Self {
|
||||||
if let Value::List(list) = self {
|
if let Value::List(list) = self {
|
||||||
list.make_mut(|list| list.push(elem), mc);
|
Rc::make_mut(list).push(elem);
|
||||||
} else if let Value::Catchable(_) = self {
|
} else if let Value::Catchable(_) = self {
|
||||||
} else if let Value::Catchable(_) = elem {
|
} else if let Value::Catchable(_) = elem {
|
||||||
*self = elem;
|
*self = elem;
|
||||||
@@ -392,23 +310,23 @@ impl<'gc> Value<'gc> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn concat(&mut self, other: Self, mc: &Mutation<'gc>) {
|
pub fn concat(&mut self, other: Self) {
|
||||||
if let x @ Value::Catchable(_) = other {
|
if let x @ Value::Catchable(_) = other {
|
||||||
*self = x;
|
*self = x;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::List(a), Value::List(b)) => {
|
(Value::List(a), Value::List(b)) => {
|
||||||
a.make_mut(|a| a.concat(&b), mc);
|
Rc::make_mut(a).concat(&b);
|
||||||
}
|
}
|
||||||
(Value::Catchable(_), _) => (),
|
(Value::Catchable(_), _) => (),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_attr(&mut self, sym: usize, val: Self, mc: &Mutation<'gc>) -> &mut Self {
|
pub fn push_attr(&mut self, sym: usize, val: Self) -> &mut Self {
|
||||||
if let Value::AttrSet(attrs) = self {
|
if let Value::AttrSet(attrs) = self {
|
||||||
attrs.make_mut(|attrs| attrs.push_attr(sym, val), mc)
|
Rc::make_mut(attrs).push_attr(sym, val);
|
||||||
} else if let Value::Catchable(_) = self {
|
} else if let Value::Catchable(_) = self {
|
||||||
} else if let Value::Catchable(_) = val {
|
} else if let Value::Catchable(_) = val {
|
||||||
*self = val
|
*self = val
|
||||||
@@ -418,14 +336,14 @@ impl<'gc> Value<'gc> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, other: Self, mc: &Mutation<'gc>) {
|
pub fn update(&mut self, other: Self) {
|
||||||
if let x @ Value::Catchable(_) = other {
|
if let x @ Value::Catchable(_) = other {
|
||||||
*self = x;
|
*self = x;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::AttrSet(a), Value::AttrSet(b)) => {
|
(Value::AttrSet(a), Value::AttrSet(b)) => {
|
||||||
a.make_mut(|a| a.update(&b), mc)
|
Rc::make_mut(a).update(&b);
|
||||||
}
|
}
|
||||||
(Value::Catchable(_), _) => (),
|
(Value::Catchable(_), _) => (),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use gc_arena::Collect;
|
use gc_arena::Collect;
|
||||||
use gc_arena::Mutation;
|
use gc_arena::Mutation;
|
||||||
@@ -5,7 +7,6 @@ use gc_arena::Mutation;
|
|||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::vm::VM;
|
use crate::vm::VM;
|
||||||
|
|
||||||
use super::CoW;
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Constructor, Collect)]
|
#[derive(Debug, Clone, Constructor, Collect)]
|
||||||
@@ -27,14 +28,13 @@ impl PrimOp {
|
|||||||
let mut args = Vec::with_capacity(self.arity);
|
let mut args = Vec::with_capacity(self.arity);
|
||||||
args.push(arg);
|
args.push(arg);
|
||||||
if self.arity > 1 {
|
if self.arity > 1 {
|
||||||
Value::PartialPrimOp(CoW::new(
|
Value::PartialPrimOp(Rc::new(
|
||||||
PartialPrimOp {
|
PartialPrimOp {
|
||||||
name: self.name,
|
name: self.name,
|
||||||
arity: self.arity - 1,
|
arity: self.arity - 1,
|
||||||
args,
|
args,
|
||||||
func: self.func,
|
func: self.func,
|
||||||
},
|
},
|
||||||
mc,
|
|
||||||
))
|
))
|
||||||
.ok()
|
.ok()
|
||||||
} else {
|
} else {
|
||||||
@@ -67,13 +67,14 @@ impl PartialEq for PartialPrimOp<'_> {
|
|||||||
|
|
||||||
impl<'gc> PartialPrimOp<'gc> {
|
impl<'gc> PartialPrimOp<'gc> {
|
||||||
pub fn call(
|
pub fn call(
|
||||||
self: &mut CoW<'gc, Self>,
|
self: &mut Rc<Self>,
|
||||||
arg: Value<'gc>,
|
arg: Value<'gc>,
|
||||||
vm: &VM,
|
vm: &VM,
|
||||||
mc: &Mutation<'gc>,
|
mc: &Mutation<'gc>,
|
||||||
) -> Result<Value<'gc>> {
|
) -> Result<Value<'gc>> {
|
||||||
let func = self.func;
|
let func = self.func;
|
||||||
let Some(ret) = self.make_mut(|self_mut| {
|
let Some(ret) = ({
|
||||||
|
let self_mut = Rc::make_mut(self);
|
||||||
self_mut.args.push(arg);
|
self_mut.args.push(arg);
|
||||||
self_mut.arity -= 1;
|
self_mut.arity -= 1;
|
||||||
if self_mut.arity == 0 {
|
if self_mut.arity == 0 {
|
||||||
@@ -81,7 +82,7 @@ impl<'gc> PartialPrimOp<'gc> {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}, mc) else {
|
}) else {
|
||||||
return Value::PartialPrimOp(self.clone()).ok();
|
return Value::PartialPrimOp(self.clone()).ok();
|
||||||
};
|
};
|
||||||
ret
|
ret
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use gc_arena::arena::CollectionPhase;
|
use gc_arena::arena::CollectionPhase;
|
||||||
use gc_arena::{Arena, Collect, Gc, Mutation, Rootable};
|
use gc_arena::{Arena, Collect, Gc, Mutation, Rootable};
|
||||||
@@ -123,7 +124,6 @@ pub fn eval<T, F: for<'gc> FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arena.collect_debt();
|
|
||||||
arena.mutate_root(|mc, root| {
|
arena.mutate_root(|mc, root| {
|
||||||
assert_eq!(root.stack.len(), 1);
|
assert_eq!(root.stack.len(), 1);
|
||||||
let ret = root.stack.pop();
|
let ret = root.stack.pop();
|
||||||
@@ -158,7 +158,7 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
Const::Int(x) => Value::Int(x),
|
Const::Int(x) => Value::Int(x),
|
||||||
Const::Float(x) => Value::Float(x),
|
Const::Float(x) => Value::Float(x),
|
||||||
Const::Bool(x) => Value::Bool(x),
|
Const::Bool(x) => Value::Bool(x),
|
||||||
Const::String(x) => Value::String(CoW::new(x.into(), mc)),
|
Const::String(x) => Value::String(Rc::new(x.into())),
|
||||||
Const::Null => Value::Null,
|
Const::Null => Value::Null,
|
||||||
})?,
|
})?,
|
||||||
OpCode::LoadThunk { idx } => stack.push(Value::Thunk(Thunk::new(vm.get_thunk(idx), mc)))?,
|
OpCode::LoadThunk { idx } => stack.push(Value::Thunk(Thunk::new(vm.get_thunk(idx), mc)))?,
|
||||||
@@ -199,7 +199,7 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
}
|
}
|
||||||
OpCode::Func { idx } => {
|
OpCode::Func { idx } => {
|
||||||
let func = vm.get_func(idx);
|
let func = vm.get_func(idx);
|
||||||
stack.push(Value::Func(Gc::new(mc, Func::new(func, *env, mc))))?;
|
stack.push(Value::Func(Rc::new(Func::new(func, *env, mc))))?;
|
||||||
}
|
}
|
||||||
OpCode::Arg { level } => {
|
OpCode::Arg { level } => {
|
||||||
stack.push(env.lookup_arg(level).clone())?;
|
stack.push(env.lookup_arg(level).clone())?;
|
||||||
@@ -217,10 +217,10 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
let mut rhs = stack.pop();
|
let mut rhs = stack.pop();
|
||||||
let lhs = stack.tos_mut();
|
let lhs = stack.tos_mut();
|
||||||
match op {
|
match op {
|
||||||
Add => lhs.add(rhs, mc),
|
Add => lhs.add(rhs),
|
||||||
Sub => {
|
Sub => {
|
||||||
rhs.neg();
|
rhs.neg();
|
||||||
lhs.add(rhs, mc);
|
lhs.add(rhs);
|
||||||
}
|
}
|
||||||
Mul => lhs.mul(rhs),
|
Mul => lhs.mul(rhs),
|
||||||
Div => lhs.div(rhs)?,
|
Div => lhs.div(rhs)?,
|
||||||
@@ -228,26 +228,26 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
Or => lhs.or(rhs),
|
Or => lhs.or(rhs),
|
||||||
Eq => Value::eq(lhs, rhs),
|
Eq => Value::eq(lhs, rhs),
|
||||||
Lt => lhs.lt(rhs),
|
Lt => lhs.lt(rhs),
|
||||||
Con => lhs.concat(rhs, mc),
|
Con => lhs.concat(rhs),
|
||||||
Upd => lhs.update(rhs, mc),
|
Upd => lhs.update(rhs),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OpCode::ConcatString => {
|
OpCode::ConcatString => {
|
||||||
let rhs = stack.pop();
|
let rhs = stack.pop();
|
||||||
stack.tos_mut().concat_string(rhs, mc);
|
stack.tos_mut().concat_string(rhs);
|
||||||
}
|
}
|
||||||
OpCode::Path => {
|
OpCode::Path => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
OpCode::List { cap } => {
|
OpCode::List { cap } => {
|
||||||
stack.push(Value::List(CoW::new(List::with_capacity(cap), mc)))?;
|
stack.push(Value::List(Rc::new(List::with_capacity(cap))))?;
|
||||||
}
|
}
|
||||||
OpCode::PushElem => {
|
OpCode::PushElem => {
|
||||||
let elem = stack.pop();
|
let elem = stack.pop();
|
||||||
stack.tos_mut().push(elem, mc);
|
stack.tos_mut().push(elem);
|
||||||
}
|
}
|
||||||
OpCode::AttrSet { cap } => {
|
OpCode::AttrSet { cap } => {
|
||||||
stack.push(Value::AttrSet(CoW::new(AttrSet::with_capacity(cap), mc)))?;
|
stack.push(Value::AttrSet(Rc::new(AttrSet::with_capacity(cap))))?;
|
||||||
}
|
}
|
||||||
OpCode::FinalizeLet => {
|
OpCode::FinalizeLet => {
|
||||||
let mut list = stack.pop().unwrap_list();
|
let mut list = stack.pop().unwrap_list();
|
||||||
@@ -256,17 +256,17 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
.clone()
|
.clone()
|
||||||
.into_inner();
|
.into_inner();
|
||||||
*env = env.enter_let(map, mc);
|
*env = env.enter_let(map, mc);
|
||||||
list.make_mut(|list| list.capture(*env, mc), mc);
|
Rc::make_mut(&mut list).capture(*env, mc);
|
||||||
}
|
}
|
||||||
OpCode::PushStaticAttr { name } => {
|
OpCode::PushStaticAttr { name } => {
|
||||||
let val = stack.pop();
|
let val = stack.pop();
|
||||||
stack.tos_mut().push_attr(name, val, mc);
|
stack.tos_mut().push_attr(name, val);
|
||||||
}
|
}
|
||||||
OpCode::PushDynamicAttr => {
|
OpCode::PushDynamicAttr => {
|
||||||
let val = stack.pop();
|
let val = stack.pop();
|
||||||
let sym = stack.pop();
|
let sym = stack.pop();
|
||||||
let sym = vm.new_sym::<&str>(&sym.unwrap_string());
|
let sym = vm.new_sym::<&str>(&sym.unwrap_string());
|
||||||
stack.tos_mut().push_attr(sym, val, mc);
|
stack.tos_mut().push_attr(sym, val);
|
||||||
}
|
}
|
||||||
OpCode::Select { sym } => {
|
OpCode::Select { sym } => {
|
||||||
stack.tos_mut().select(sym, vm)?;
|
stack.tos_mut().select(sym, vm)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user