feat: less gc (WIP)
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -324,6 +324,7 @@ dependencies = [
|
||||
"inkwell",
|
||||
"itertools",
|
||||
"regex",
|
||||
"replace_with",
|
||||
"rnix",
|
||||
"rustyline",
|
||||
"thiserror 2.0.12",
|
||||
@@ -398,6 +399,12 @@ version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "replace_with"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884"
|
||||
|
||||
[[package]]
|
||||
name = "rnix"
|
||||
version = "0.12.0"
|
||||
|
||||
@@ -27,6 +27,7 @@ derive_more = { version = "2.0", features = ["full"] }
|
||||
ecow = "0.2"
|
||||
regex = "1.11"
|
||||
hashbrown = "0.15"
|
||||
replace_with = "0.1"
|
||||
inkwell = { version = "0.6.0", features = ["llvm18-1"] }
|
||||
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 hashbrown::HashMap;
|
||||
|
||||
use crate::env::VmEnv;
|
||||
use crate::ir::{DowngradeContext, Ir};
|
||||
use crate::ty::common::Const;
|
||||
use crate::ty::internal::{AttrSet, CoW, PrimOp, Value};
|
||||
use crate::ty::internal::{AttrSet, PrimOp, Value};
|
||||
use crate::vm::VM;
|
||||
|
||||
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 {
|
||||
unreachable!()
|
||||
};
|
||||
first.add(second, mc);
|
||||
first.add(second);
|
||||
first.ok()
|
||||
}),
|
||||
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!()
|
||||
};
|
||||
second.neg();
|
||||
first.add(second, mc);
|
||||
first.add(second);
|
||||
first.ok()
|
||||
}),
|
||||
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();
|
||||
for primop in primops {
|
||||
let primop = Gc::new(mc, primop);
|
||||
let primop = Rc::new(primop);
|
||||
env_map.insert(
|
||||
vm.new_sym(format!("__{}", primop.name)),
|
||||
Value::PrimOp(primop),
|
||||
Value::PrimOp(primop.clone()),
|
||||
);
|
||||
map.insert(vm.new_sym(primop.name), Value::PrimOp(primop));
|
||||
}
|
||||
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 {
|
||||
attrs.make_cyclic(|attrs, 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);
|
||||
|
||||
env_map.insert(sym, builtins);
|
||||
env_map.insert(sym, builtins); */
|
||||
// TODO:
|
||||
// VmEnv::new(Gc::new(mc, env_map), 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>>,
|
||||
with: Gc<'gc, With<'gc, K, V>>,
|
||||
args: Vec<V>,
|
||||
gc_alloced: Vec<Gc<'gc, V>>,
|
||||
jit_store: Vec<Box<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(),
|
||||
gc_alloced: Vec::new(),
|
||||
jit_store: Vec::new(),
|
||||
last: None,
|
||||
},
|
||||
)
|
||||
@@ -92,7 +92,7 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
||||
let_: self.let_,
|
||||
with: self.with,
|
||||
last: Some(self),
|
||||
gc_alloced: Vec::new(),
|
||||
jit_store: Vec::new(),
|
||||
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),
|
||||
with: self.with,
|
||||
args: self.args.clone(),
|
||||
gc_alloced: Vec::new(),
|
||||
jit_store: Vec::new(),
|
||||
last: Some(self),
|
||||
},
|
||||
)
|
||||
@@ -128,17 +128,21 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
||||
let_: self.let_,
|
||||
with: self.with.enter(map, mc),
|
||||
args: self.args.clone(),
|
||||
gc_alloced: Vec::new(),
|
||||
jit_store: Vec::new(),
|
||||
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 jit_store(&'gc mut self, val: V) -> &'gc V {
|
||||
self.jit_store.push(Box::new(val));
|
||||
&self.jit_store[self.jit_store.len() - 1]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn jit_stored(&self) -> usize {
|
||||
self.jit_store.len()
|
||||
}
|
||||
|
||||
pub fn leave(&self) -> Gc<'gc, Self> {
|
||||
|
||||
@@ -361,7 +361,7 @@ extern "C" fn helper_call<'gc>(
|
||||
ValueTag::Function => {
|
||||
let func = Value::from(func).unwrap_func();
|
||||
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!(),
|
||||
}
|
||||
@@ -369,19 +369,19 @@ extern "C" fn helper_call<'gc>(
|
||||
|
||||
extern "C" fn helper_arg(idx: usize, env: *const VmEnv) -> JITValue {
|
||||
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
|
||||
}
|
||||
|
||||
extern "C" fn helper_lookup_let(level: usize, idx: usize, env: *const VmEnv) -> JITValue {
|
||||
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
|
||||
}
|
||||
|
||||
extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ extern "C" fn helper_force<'gc>(
|
||||
let mc = unsafe { mc.as_ref() }.unwrap();
|
||||
let thunk = Value::from(thunk).unwrap_thunk();
|
||||
if let Some(val) = thunk.get_value() {
|
||||
return val.into();
|
||||
return val.clone().into();
|
||||
}
|
||||
let (opcodes, env) = thunk.suspend(mc).unwrap();
|
||||
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 {
|
||||
let mc = unsafe { &*mc };
|
||||
let env = unsafe { &mut *env };
|
||||
env.alloc_gc(Value::Thunk(Thunk::new(
|
||||
Value::Thunk(Thunk::new(
|
||||
unsafe { opcodes.as_ref() }.unwrap(),
|
||||
mc
|
||||
)), mc)
|
||||
))
|
||||
.into()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use std::ops::Deref;
|
||||
|
||||
use gc_arena::{Collect, Gc, Mutation};
|
||||
@@ -63,7 +64,7 @@ impl<'gc> From<JITValue> for Value<'gc> {
|
||||
match value.tag {
|
||||
Int => Value::Int(unsafe { value.data.int }),
|
||||
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: 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 {
|
||||
fn from(value: &Value) -> Self {
|
||||
impl From<Value<'_>> for JITValue {
|
||||
fn from(value: Value) -> Self {
|
||||
match value {
|
||||
&Value::Int(int) => JITValue {
|
||||
Value::Int(int) => JITValue {
|
||||
tag: ValueTag::Int,
|
||||
data: JITValueData { int },
|
||||
},
|
||||
&Value::Func(func) => JITValue {
|
||||
Value::Func(func) => {
|
||||
JITValue {
|
||||
tag: ValueTag::Function,
|
||||
data: JITValueData {
|
||||
ptr: Gc::as_ptr(func) as *const _,
|
||||
},
|
||||
ptr: Rc::into_raw(func) as *const _,
|
||||
},
|
||||
}
|
||||
}
|
||||
Value::Thunk(thunk) => JITValue {
|
||||
tag: ValueTag::Thunk,
|
||||
data: JITValueData {
|
||||
|
||||
@@ -12,12 +12,17 @@ use super::super::public as p;
|
||||
use super::Value;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Constructor, Clone, PartialEq, Collect)]
|
||||
#[collect(no_drop)]
|
||||
#[derive(Constructor, Clone, PartialEq)]
|
||||
pub struct AttrSet<'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> {
|
||||
fn from(data: HashMap<usize, Value<'gc>>) -> Self {
|
||||
Self { data }
|
||||
|
||||
@@ -7,12 +7,17 @@ use crate::env::VmEnv;
|
||||
|
||||
use super::Value;
|
||||
|
||||
#[derive(Clone, PartialEq, Collect)]
|
||||
#[collect(no_drop)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct List<'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> {
|
||||
pub fn new() -> Self {
|
||||
List {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::cell::Cell;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use derive_more::{IsVariant, Unwrap};
|
||||
use gc_arena::Mutation;
|
||||
use gc_arena::lock::RefLock;
|
||||
use gc_arena::{Collect, Gc, lock::GcRefLock};
|
||||
use hashbrown::HashSet;
|
||||
use replace_with::replace_with_or_abort;
|
||||
|
||||
use super::common::*;
|
||||
use super::public as p;
|
||||
@@ -27,95 +27,22 @@ pub use func::*;
|
||||
pub use list::List;
|
||||
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)]
|
||||
#[collect(no_drop)]
|
||||
// #[derive(IsVariant, Unwrap, Clone)]
|
||||
pub enum Value<'gc> {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
String(CoW<'gc, String>),
|
||||
String(Rc<String>),
|
||||
Null,
|
||||
Thunk(Thunk<'gc>),
|
||||
AttrSet(CoW<'gc, AttrSet<'gc>>),
|
||||
List(CoW<'gc, List<'gc>>),
|
||||
Catchable(Gc<'gc, String>),
|
||||
PrimOp(Gc<'gc, PrimOp>),
|
||||
PartialPrimOp(CoW<'gc, PartialPrimOp<'gc>>),
|
||||
Func(Gc<'gc, Func<'gc>>),
|
||||
AttrSet(Rc<AttrSet<'gc>>),
|
||||
List(Rc<List<'gc>>),
|
||||
Catchable(Rc<String>),
|
||||
PrimOp(Rc<PrimOp>),
|
||||
PartialPrimOp(Rc<PartialPrimOp<'gc>>),
|
||||
Func(Rc<Func<'gc>>),
|
||||
}
|
||||
|
||||
impl Hash for Value<'_> {
|
||||
@@ -123,18 +50,9 @@ impl Hash for Value<'_> {
|
||||
use Value::*;
|
||||
std::mem::discriminant(self).hash(state);
|
||||
match self {
|
||||
Int(x) => x.hash(state),
|
||||
Float(x) => x.to_bits().hash(state),
|
||||
Bool(x) => x.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),
|
||||
AttrSet(x) => Rc::as_ptr(x).hash(state),
|
||||
List(x) => Rc::as_ptr(x).hash(state),
|
||||
_ => 0.hash(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,8 +79,8 @@ impl<'gc> PartialEq for Value<'gc> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
use Value::*;
|
||||
match (self, other) {
|
||||
(AttrSet(a), AttrSet(b)) => a.as_ptr().eq(&b.as_ptr()),
|
||||
(List(a), List(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)) => Rc::as_ptr(a).eq(&Rc::as_ptr(b)),
|
||||
_ => 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::*;
|
||||
*self = match (&*self, other) {
|
||||
replace_with_or_abort(self, |a| {
|
||||
match (a, other) {
|
||||
(Int(a), Int(b)) => Int(a + b),
|
||||
(Int(a), Float(b)) => Float(*a as f64 + b),
|
||||
(Int(a), Float(b)) => Float(a as f64 + b),
|
||||
(Float(a), Int(b)) => Float(a + b as f64),
|
||||
(Float(a), Float(b)) => Float(a + b),
|
||||
(String(a), String(b)) => {
|
||||
let mut a = a.clone();
|
||||
a.make_mut(|a| a.push_str(b.as_str()), mc);
|
||||
(String(mut a), String(b)) => {
|
||||
Rc::make_mut(&mut a).push_str(&b);
|
||||
String(a)
|
||||
}
|
||||
(Value::Catchable(_), _) => return,
|
||||
(a @ Value::Catchable(_), _) => a,
|
||||
(_, x @ Value::Catchable(_)) => x,
|
||||
_ => todo!(),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn mul(&mut self, other: Self) {
|
||||
@@ -367,11 +286,10 @@ impl<'gc> Value<'gc> {
|
||||
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()) {
|
||||
(Value::String(a), Value::String(b)) => {
|
||||
let mut a = a.clone();
|
||||
a.make_mut(|a| a.push_str(b.as_str()), mc);
|
||||
Rc::make_mut(a).push_str(b.as_str());
|
||||
}
|
||||
(_, Value::Catchable(_)) => *self = other,
|
||||
(Value::Catchable(_), _) => (),
|
||||
@@ -380,9 +298,9 @@ impl<'gc> Value<'gc> {
|
||||
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 {
|
||||
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(_) = elem {
|
||||
*self = elem;
|
||||
@@ -392,23 +310,23 @@ impl<'gc> Value<'gc> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn concat(&mut self, other: Self, mc: &Mutation<'gc>) {
|
||||
pub fn concat(&mut self, other: Self) {
|
||||
if let x @ Value::Catchable(_) = other {
|
||||
*self = x;
|
||||
return;
|
||||
}
|
||||
match (self, other) {
|
||||
(Value::List(a), Value::List(b)) => {
|
||||
a.make_mut(|a| a.concat(&b), mc);
|
||||
Rc::make_mut(a).concat(&b);
|
||||
}
|
||||
(Value::Catchable(_), _) => (),
|
||||
_ => 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 {
|
||||
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(_) = val {
|
||||
*self = val
|
||||
@@ -418,14 +336,14 @@ impl<'gc> Value<'gc> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn update(&mut self, other: Self, mc: &Mutation<'gc>) {
|
||||
pub fn update(&mut self, other: Self) {
|
||||
if let x @ Value::Catchable(_) = other {
|
||||
*self = x;
|
||||
return;
|
||||
}
|
||||
match (self, other) {
|
||||
(Value::AttrSet(a), Value::AttrSet(b)) => {
|
||||
a.make_mut(|a| a.update(&b), mc)
|
||||
Rc::make_mut(a).update(&b);
|
||||
}
|
||||
(Value::Catchable(_), _) => (),
|
||||
_ => todo!(),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use derive_more::Constructor;
|
||||
use gc_arena::Collect;
|
||||
use gc_arena::Mutation;
|
||||
@@ -5,7 +7,6 @@ use gc_arena::Mutation;
|
||||
use crate::error::Result;
|
||||
use crate::vm::VM;
|
||||
|
||||
use super::CoW;
|
||||
use super::Value;
|
||||
|
||||
#[derive(Debug, Clone, Constructor, Collect)]
|
||||
@@ -27,14 +28,13 @@ impl PrimOp {
|
||||
let mut args = Vec::with_capacity(self.arity);
|
||||
args.push(arg);
|
||||
if self.arity > 1 {
|
||||
Value::PartialPrimOp(CoW::new(
|
||||
Value::PartialPrimOp(Rc::new(
|
||||
PartialPrimOp {
|
||||
name: self.name,
|
||||
arity: self.arity - 1,
|
||||
args,
|
||||
func: self.func,
|
||||
},
|
||||
mc,
|
||||
))
|
||||
.ok()
|
||||
} else {
|
||||
@@ -67,13 +67,14 @@ impl PartialEq for PartialPrimOp<'_> {
|
||||
|
||||
impl<'gc> PartialPrimOp<'gc> {
|
||||
pub fn call(
|
||||
self: &mut CoW<'gc, Self>,
|
||||
self: &mut Rc<Self>,
|
||||
arg: Value<'gc>,
|
||||
vm: &VM,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> Result<Value<'gc>> {
|
||||
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.arity -= 1;
|
||||
if self_mut.arity == 0 {
|
||||
@@ -81,7 +82,7 @@ impl<'gc> PartialPrimOp<'gc> {
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}, mc) else {
|
||||
}) else {
|
||||
return Value::PartialPrimOp(self.clone()).ok();
|
||||
};
|
||||
ret
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use gc_arena::arena::CollectionPhase;
|
||||
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| {
|
||||
assert_eq!(root.stack.len(), 1);
|
||||
let ret = root.stack.pop();
|
||||
@@ -158,7 +158,7 @@ fn single_op<'gc, const CAP: usize>(
|
||||
Const::Int(x) => Value::Int(x),
|
||||
Const::Float(x) => Value::Float(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,
|
||||
})?,
|
||||
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 } => {
|
||||
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 } => {
|
||||
stack.push(env.lookup_arg(level).clone())?;
|
||||
@@ -217,10 +217,10 @@ fn single_op<'gc, const CAP: usize>(
|
||||
let mut rhs = stack.pop();
|
||||
let lhs = stack.tos_mut();
|
||||
match op {
|
||||
Add => lhs.add(rhs, mc),
|
||||
Add => lhs.add(rhs),
|
||||
Sub => {
|
||||
rhs.neg();
|
||||
lhs.add(rhs, mc);
|
||||
lhs.add(rhs);
|
||||
}
|
||||
Mul => lhs.mul(rhs),
|
||||
Div => lhs.div(rhs)?,
|
||||
@@ -228,26 +228,26 @@ fn single_op<'gc, const CAP: usize>(
|
||||
Or => lhs.or(rhs),
|
||||
Eq => Value::eq(lhs, rhs),
|
||||
Lt => lhs.lt(rhs),
|
||||
Con => lhs.concat(rhs, mc),
|
||||
Upd => lhs.update(rhs, mc),
|
||||
Con => lhs.concat(rhs),
|
||||
Upd => lhs.update(rhs),
|
||||
}
|
||||
}
|
||||
OpCode::ConcatString => {
|
||||
let rhs = stack.pop();
|
||||
stack.tos_mut().concat_string(rhs, mc);
|
||||
stack.tos_mut().concat_string(rhs);
|
||||
}
|
||||
OpCode::Path => {
|
||||
todo!()
|
||||
}
|
||||
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 => {
|
||||
let elem = stack.pop();
|
||||
stack.tos_mut().push(elem, mc);
|
||||
stack.tos_mut().push(elem);
|
||||
}
|
||||
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 => {
|
||||
let mut list = stack.pop().unwrap_list();
|
||||
@@ -256,17 +256,17 @@ fn single_op<'gc, const CAP: usize>(
|
||||
.clone()
|
||||
.into_inner();
|
||||
*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 } => {
|
||||
let val = stack.pop();
|
||||
stack.tos_mut().push_attr(name, val, mc);
|
||||
stack.tos_mut().push_attr(name, val);
|
||||
}
|
||||
OpCode::PushDynamicAttr => {
|
||||
let val = stack.pop();
|
||||
let sym = stack.pop();
|
||||
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 } => {
|
||||
stack.tos_mut().select(sym, vm)?;
|
||||
|
||||
Reference in New Issue
Block a user