feat: less gc (WIP)
This commit is contained in:
@@ -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) {
|
||||
(Int(a), Int(b)) => Int(a + 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(a)
|
||||
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),
|
||||
(Float(a), Int(b)) => Float(a + b as f64),
|
||||
(Float(a), Float(b)) => Float(a + b),
|
||||
(String(mut a), String(b)) => {
|
||||
Rc::make_mut(&mut a).push_str(&b);
|
||||
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) {
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user