feat: lookup at downgrade time
works, but leaks memory
This commit is contained in:
@@ -2,11 +2,10 @@ use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use derive_more::Constructor;
|
||||
use gc_arena::{Collect, Gc, Mutation};
|
||||
use gc_arena::Collect;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::env::VmEnv;
|
||||
use crate::vm::VM;
|
||||
|
||||
use super::super::public as p;
|
||||
@@ -58,14 +57,6 @@ impl<'gc> AttrSet<'gc> {
|
||||
self.data.get(&sym).is_some()
|
||||
}
|
||||
|
||||
pub fn capture(&mut self, env: Gc<'gc, VmEnv<'gc>>, mc: &Mutation<'gc>) {
|
||||
self.data.iter().for_each(|(_, v)| {
|
||||
if let Value::Thunk(ref thunk) = v.clone() {
|
||||
thunk.capture_env(env, mc);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn update(&mut self, other: &AttrSet<'gc>) {
|
||||
for (k, v) in other.data.iter() {
|
||||
self.push_attr_force(*k, v.clone())
|
||||
|
||||
@@ -2,15 +2,13 @@ use std::cell::Cell;
|
||||
|
||||
use gc_arena::lock::{GcRefLock, RefLock};
|
||||
use gc_arena::{Collect, Gc, Mutation};
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::bytecode::Func as BFunc;
|
||||
use crate::env::VmEnv;
|
||||
use crate::error::Result;
|
||||
use crate::ir;
|
||||
use crate::jit::JITFunc;
|
||||
use crate::ty::internal::{Thunk, Value};
|
||||
use crate::ty::internal::Value;
|
||||
use crate::vm::VM;
|
||||
|
||||
#[derive(Debug, Clone, Collect)]
|
||||
@@ -75,45 +73,7 @@ impl<'gc> Func<'gc> {
|
||||
vm: &'gc VM<'gc>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> Result<Value<'gc>> {
|
||||
use Param::*;
|
||||
|
||||
let mut env = self.env;
|
||||
env = match self.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
|
||||
.as_inner()
|
||||
.iter()
|
||||
.map(|(k, _)| k)
|
||||
.sorted()
|
||||
.ne(formals.iter().map(|(k, _)| k).sorted())
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
for (formal, default) in formals {
|
||||
let arg = arg
|
||||
.select(formal)
|
||||
.or_else(|| {
|
||||
default
|
||||
.map(|idx| Value::Thunk(Thunk::new(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 = self.env.enter_arg(arg, mc);
|
||||
let compiled = self
|
||||
.compiled
|
||||
.borrow_mut(mc)
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
use hashbrown::HashSet;
|
||||
|
||||
use derive_more::Constructor;
|
||||
use gc_arena::Collect;
|
||||
use rpds::Vector;
|
||||
use gc_arena::{Collect, Gc, Mutation};
|
||||
|
||||
use crate::ty::public as p;
|
||||
use crate::vm::VM;
|
||||
use crate::env::VmEnv;
|
||||
|
||||
use super::Value;
|
||||
|
||||
#[derive(Constructor, Clone, PartialEq)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct List<'gc> {
|
||||
data: Vector<Value<'gc>>,
|
||||
data: Vec<Value<'gc>>,
|
||||
}
|
||||
|
||||
unsafe impl<'gc> Collect<'gc> for List<'gc> {
|
||||
@@ -23,22 +21,40 @@ unsafe impl<'gc> Collect<'gc> for List<'gc> {
|
||||
}
|
||||
|
||||
impl<'gc> List<'gc> {
|
||||
pub fn empty() -> Self {
|
||||
pub fn new() -> Self {
|
||||
List {
|
||||
data: Vector::new(),
|
||||
data: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
List {
|
||||
data: Vec::with_capacity(cap),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, elem: Value<'gc>) {
|
||||
self.data.push_back_mut(elem);
|
||||
self.data.push(elem);
|
||||
}
|
||||
|
||||
pub fn concat(&mut self, other: &List<'gc>) {
|
||||
for elem in other.data.iter() {
|
||||
self.data.push_back_mut(elem.clone());
|
||||
self.data.push(elem.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn capture(&mut self, env: Gc<'gc, VmEnv<'gc>>, mc: &Mutation<'gc>) {
|
||||
self.data.iter().for_each(|v| {
|
||||
if let Value::Thunk(ref thunk) = v.clone() {
|
||||
thunk.capture_env(env, mc);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> Vec<Value<'gc>> {
|
||||
self.data
|
||||
}
|
||||
|
||||
pub fn to_public(&self, vm: &VM<'gc>, seen: &mut HashSet<Value<'gc>>) -> p::Value {
|
||||
p::Value::List(p::List::new(
|
||||
self.data
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
use std::cell::Cell;
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ops::Deref;
|
||||
|
||||
use derive_more::{IsVariant, Unwrap};
|
||||
@@ -35,66 +33,49 @@ 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: MaybeUninit<T>,
|
||||
_marker: PhantomData<Cell<&'gc ()>>,
|
||||
}
|
||||
|
||||
unsafe impl<'gc, T: Clone + Collect<'gc>> Collect<'gc> for CoWInner<'gc, T> {
|
||||
fn trace<Tr: gc_arena::collect::Trace<'gc>>(&self, cc: &mut Tr) {
|
||||
unsafe { self.data.assume_init_ref() }.trace(cc);
|
||||
}
|
||||
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)),
|
||||
inner: Gc::new(mc, CoWInner::new(data, mc)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_cyclic(datafn: impl FnOnce(Self) -> T, mc: &Mutation<'gc>) -> Self {
|
||||
let inner = Gc::new(
|
||||
mc,
|
||||
CoWInner {
|
||||
ref_count: Cell::new(1),
|
||||
data: MaybeUninit::uninit(),
|
||||
_marker: PhantomData,
|
||||
},
|
||||
);
|
||||
let data = datafn(CoW { inner });
|
||||
unsafe { std::mem::transmute::<_, &mut MaybeUninit<_>>(&inner.data) }.write(data);
|
||||
Self { inner }
|
||||
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(&mut self, mc: &Mutation<'gc>) -> &mut T {
|
||||
pub fn make_mut<U>(&mut self, f: impl FnOnce(&mut T) -> U, mc: &Mutation<'gc>) -> U {
|
||||
if self.inner.ref_count.get() == 1 {
|
||||
unsafe { std::mem::transmute(self.inner.data.assume_init_ref()) }
|
||||
f(&mut *self.inner.data.borrow_mut(mc))
|
||||
} else {
|
||||
unsafe {
|
||||
*self = CoW::new(self.inner.data.assume_init_ref().clone(), mc);
|
||||
std::mem::transmute(self.inner.data.assume_init_ref())
|
||||
}
|
||||
*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
|
||||
&*self.as_ref() as *const T
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gc, T: Clone + Collect<'gc>> AsRef<T> for CoW<'gc, T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
unsafe { self.inner.data.assume_init_ref() }
|
||||
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 {
|
||||
self.as_ref()
|
||||
unsafe { self.as_ptr().as_ref() }.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,11 +93,10 @@ impl<'gc, T: Clone + Collect<'gc>> Drop for CoW<'gc, T> {
|
||||
}
|
||||
|
||||
impl<'gc, T: Clone + Collect<'gc>> CoWInner<'gc, T> {
|
||||
fn new(data: T) -> Self {
|
||||
fn new(data: T, mc: &Mutation<'gc>) -> Self {
|
||||
Self {
|
||||
ref_count: Cell::new(1),
|
||||
data: MaybeUninit::new(data),
|
||||
_marker: PhantomData,
|
||||
data: Gc::new(mc, RefLock::new(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,7 +133,7 @@ impl Hash for Value<'_> {
|
||||
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_ref() as *const self::PartialPrimOp).hash(state),
|
||||
PartialPrimOp(x) => x.as_ptr().hash(state),
|
||||
Func(x) => (x.as_ref() as *const self::Func).hash(state),
|
||||
}
|
||||
}
|
||||
@@ -206,22 +186,6 @@ pub enum ValueAsRef<'v, 'gc> {
|
||||
Func(&'v Func<'gc>),
|
||||
}
|
||||
|
||||
#[derive(IsVariant, Unwrap)]
|
||||
pub enum ValueAsMut<'v, 'gc> {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
String(&'v str),
|
||||
Null,
|
||||
Thunk(&'v Thunk<'gc>),
|
||||
AttrSet(&'v mut AttrSet<'gc>),
|
||||
List(&'v mut List<'gc>),
|
||||
Catchable(&'v str),
|
||||
PrimOp(&'v PrimOp),
|
||||
PartialPrimOp(&'v mut PartialPrimOp<'gc>),
|
||||
Func(&'v Func<'gc>),
|
||||
}
|
||||
|
||||
impl<'gc, 'v> Value<'gc> {
|
||||
pub fn as_ref(&'v self) -> ValueAsRef<'v, 'gc> {
|
||||
use Value::*;
|
||||
@@ -241,25 +205,6 @@ impl<'gc, 'v> Value<'gc> {
|
||||
Func(x) => R::Func(x),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mut(&'v mut self, mc: &Mutation<'gc>) -> ValueAsMut<'v, 'gc> {
|
||||
use Value::*;
|
||||
use ValueAsMut as M;
|
||||
match self {
|
||||
Int(x) => M::Int(*x),
|
||||
Float(x) => M::Float(*x),
|
||||
Bool(x) => M::Bool(*x),
|
||||
String(x) => M::String(x),
|
||||
Null => M::Null,
|
||||
Thunk(x) => M::Thunk(x),
|
||||
AttrSet(x) => M::AttrSet(x.make_mut(mc)),
|
||||
List(x) => M::List(x.make_mut(mc)),
|
||||
Catchable(x) => M::Catchable(x),
|
||||
PrimOp(x) => M::PrimOp(x),
|
||||
PartialPrimOp(x) => M::PartialPrimOp(x.make_mut(mc)),
|
||||
Func(x) => M::Func(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'gc> Value<'gc> {
|
||||
pub fn ok(self) -> Result<Self> {
|
||||
@@ -382,7 +327,7 @@ impl<'gc> Value<'gc> {
|
||||
(Float(a), Float(b)) => Float(a + b),
|
||||
(String(a), String(b)) => {
|
||||
let mut a = a.clone();
|
||||
a.make_mut(mc).push_str(b.as_str());
|
||||
a.make_mut(|a| a.push_str(b.as_str()), mc);
|
||||
String(a)
|
||||
}
|
||||
(Value::Catchable(_), _) => return,
|
||||
@@ -426,7 +371,7 @@ impl<'gc> Value<'gc> {
|
||||
match (self.coerce_to_string(), other.coerce_to_string()) {
|
||||
(Value::String(a), Value::String(b)) => {
|
||||
let mut a = a.clone();
|
||||
a.make_mut(mc).push_str(b.as_str())
|
||||
a.make_mut(|a| a.push_str(b.as_str()), mc);
|
||||
}
|
||||
(_, Value::Catchable(_)) => *self = other,
|
||||
(Value::Catchable(_), _) => (),
|
||||
@@ -437,7 +382,7 @@ impl<'gc> Value<'gc> {
|
||||
|
||||
pub fn push(&mut self, elem: Self, mc: &Mutation<'gc>) -> &mut Self {
|
||||
if let Value::List(list) = self {
|
||||
list.make_mut(mc).push(elem);
|
||||
list.make_mut(|list| list.push(elem), mc);
|
||||
} else if let Value::Catchable(_) = self {
|
||||
} else if let Value::Catchable(_) = elem {
|
||||
*self = elem;
|
||||
@@ -454,7 +399,7 @@ impl<'gc> Value<'gc> {
|
||||
}
|
||||
match (self, other) {
|
||||
(Value::List(a), Value::List(b)) => {
|
||||
a.make_mut(mc).concat(b.as_ref());
|
||||
a.make_mut(|a| a.concat(&b), mc);
|
||||
}
|
||||
(Value::Catchable(_), _) => (),
|
||||
_ => todo!(),
|
||||
@@ -463,7 +408,7 @@ impl<'gc> Value<'gc> {
|
||||
|
||||
pub fn push_attr(&mut self, sym: usize, val: Self, mc: &Mutation<'gc>) -> &mut Self {
|
||||
if let Value::AttrSet(attrs) = self {
|
||||
attrs.make_mut(mc).push_attr(sym, val);
|
||||
attrs.make_mut(|attrs| attrs.push_attr(sym, val), mc)
|
||||
} else if let Value::Catchable(_) = self {
|
||||
} else if let Value::Catchable(_) = val {
|
||||
*self = val
|
||||
@@ -480,7 +425,7 @@ impl<'gc> Value<'gc> {
|
||||
}
|
||||
match (self, other) {
|
||||
(Value::AttrSet(a), Value::AttrSet(b)) => {
|
||||
a.make_mut(mc).update(b.as_ref());
|
||||
a.make_mut(|a| a.update(&b), mc)
|
||||
}
|
||||
(Value::Catchable(_), _) => (),
|
||||
_ => todo!(),
|
||||
@@ -556,7 +501,7 @@ impl<'gc> Value<'gc> {
|
||||
Int(x) => Value::Const(Const::Int(*x)),
|
||||
Float(x) => Value::Const(Const::Float(*x)),
|
||||
Bool(x) => Value::Const(Const::Bool(*x)),
|
||||
String(x) => Value::Const(Const::String(x.as_ref().into())),
|
||||
String(x) => Value::Const(Const::String(x.as_str().into())),
|
||||
Null => Value::Const(Const::Null),
|
||||
Thunk(_) => Value::Thunk,
|
||||
PrimOp(primop) => Value::PrimOp(primop.name),
|
||||
|
||||
@@ -73,13 +73,17 @@ impl<'gc> PartialPrimOp<'gc> {
|
||||
mc: &Mutation<'gc>,
|
||||
) -> Result<Value<'gc>> {
|
||||
let func = self.func;
|
||||
let self_mut = self.make_mut(mc);
|
||||
self_mut.args.push(arg);
|
||||
self_mut.arity -= 1;
|
||||
if self_mut.arity > 0 {
|
||||
Value::PartialPrimOp(self.clone()).ok()
|
||||
} else {
|
||||
func(std::mem::take(&mut self_mut.args), vm, mc)
|
||||
}
|
||||
let Some(ret) = self.make_mut(|self_mut| {
|
||||
self_mut.args.push(arg);
|
||||
self_mut.arity -= 1;
|
||||
if self_mut.arity == 0 {
|
||||
Some(func(std::mem::take(&mut self_mut.args), vm, mc))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}, mc) else {
|
||||
return Value::PartialPrimOp(self.clone()).ok();
|
||||
};
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
// TODO: Contextful String
|
||||
|
||||
use ecow::EcoString;
|
||||
use rpds::List;
|
||||
|
||||
pub struct StringContext {
|
||||
context: List<()>,
|
||||
context: Vec<()>,
|
||||
}
|
||||
|
||||
impl StringContext {
|
||||
pub fn new() -> StringContext {
|
||||
StringContext {
|
||||
context: List::new(),
|
||||
context: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user