feat: no clone in JIT

IMPORTANT: should not drop or create values in JIT anymore
This commit is contained in:
2025-05-21 20:48:56 +08:00
parent 177acfabcf
commit 2a19ddb279
11 changed files with 105 additions and 82 deletions

View File

@@ -6,7 +6,7 @@ use derive_more::Constructor;
use itertools::Itertools;
use crate::error::Result;
use crate::vm::{VmEnv, VM};
use crate::vm::{VM, VmEnv};
use super::super::public as p;
use super::Value;
@@ -42,9 +42,9 @@ impl<'jit: 'vm, 'vm> AttrSet<'jit, 'vm> {
}
pub fn select(&self, sym: usize) -> Option<Value<'jit, 'vm>> {
self.data.get(&sym).cloned().map(|val| match val {
self.data.get(&sym).map(|val| match val {
Value::Builtins(x) => Value::AttrSet(x.upgrade().unwrap()),
val => val,
val => val.clone(),
})
}
@@ -53,8 +53,10 @@ impl<'jit: 'vm, 'vm> AttrSet<'jit, 'vm> {
}
pub fn capture(&mut self, env: &Rc<VmEnv<'jit, 'vm>>) {
self.data.iter().for_each(|(_, v)| if let Value::Thunk(ref thunk) = v.clone() {
thunk.capture(env.clone());
self.data.iter().for_each(|(_, v)| {
if let Value::Thunk(ref thunk) = v.clone() {
thunk.capture(Rc::clone(env));
}
})
}
@@ -77,11 +79,7 @@ impl<'jit: 'vm, 'vm> AttrSet<'jit, 'vm> {
}
pub fn force_deep(&mut self, vm: &'vm VM<'jit>) -> Result<()> {
let mut map: Vec<_> = self
.data
.iter()
.map(|(k, v)| (*k, v.clone()))
.collect();
let mut map: Vec<_> = self.data.iter().map(|(k, v)| (*k, v.clone())).collect();
for (_, v) in map.iter_mut() {
v.force_deep(vm)?;
}

View File

@@ -11,7 +11,7 @@ use crate::error::Result;
use crate::ir;
use crate::jit::JITFunc;
use crate::ty::internal::{Thunk, Value};
use crate::vm::{VmEnv, VM};
use crate::vm::{VM, VmEnv};
#[derive(Debug, Clone)]
pub enum Param {

View File

@@ -11,7 +11,7 @@ use super::public as p;
use crate::bytecode::OpCodes;
use crate::error::*;
use crate::vm::{VmEnv, VM};
use crate::vm::{VM, VmEnv};
mod attrset;
mod func;
@@ -28,7 +28,6 @@ pub use primop::*;
pub enum Value<'jit: 'vm, 'vm> {
Const(Const),
Thunk(Rc<Thunk<'jit, 'vm>>),
ThunkRef(&'vm Thunk<'jit, 'vm>),
AttrSet(Rc<AttrSet<'jit, 'vm>>),
List(Rc<List<'jit, 'vm>>),
Catchable(Catchable),
@@ -45,7 +44,6 @@ impl Hash for Value<'_, '_> {
match self {
Const(x) => x.hash(state),
Thunk(x) => (x.as_ref() as *const self::Thunk).hash(state),
ThunkRef(x) => (*x as *const self::Thunk).hash(state),
AttrSet(x) => (x.as_ref() as *const self::AttrSet).hash(state),
List(x) => (x.as_ref() as *const self::List).hash(state),
Catchable(x) => x.hash(state),
@@ -119,7 +117,6 @@ impl<'v, 'vm: 'v, 'jit: 'vm> Value<'jit, 'vm> {
match self {
Const(x) => R::Const(x),
Thunk(x) => R::Thunk(x),
ThunkRef(x) => R::Thunk(x),
AttrSet(x) => R::AttrSet(x),
List(x) => R::List(x),
Catchable(x) => R::Catchable(x),
@@ -136,7 +133,6 @@ impl<'v, 'vm: 'v, 'jit: 'vm> Value<'jit, 'vm> {
match self {
Const(x) => M::Const(x),
Thunk(x) => M::Thunk(x),
ThunkRef(x) => M::Thunk(x),
AttrSet(x) => M::AttrSet(Rc::make_mut(x)),
List(x) => M::List(Rc::make_mut(x)),
Catchable(x) => M::Catchable(x),
@@ -163,7 +159,6 @@ impl<'jit, 'vm> Value<'jit, 'vm> {
Const(self::Const::String(_)) => "string",
Const(self::Const::Null) => "null",
Thunk(_) => "thunk",
ThunkRef(_) => "thunk",
AttrSet(_) => "set",
List(_) => "list",
Catchable(_) => unreachable!(),
@@ -420,10 +415,7 @@ impl<'jit, 'vm> Value<'jit, 'vm> {
pub fn force(&mut self, vm: &'vm VM<'jit>) -> Result<&mut Self> {
if let Value::Thunk(thunk) = self {
let value = thunk.force(vm)?;
*self = value
} else if let Value::ThunkRef(thunk) = self {
let value = thunk.force(vm)?;
let value = thunk.force(vm)?.clone();
*self = value
}
Ok(self)
@@ -432,12 +424,7 @@ impl<'jit, 'vm> Value<'jit, 'vm> {
pub fn force_deep(&mut self, vm: &'vm VM<'jit>) -> Result<&mut Self> {
match self {
Value::Thunk(thunk) => {
let mut value = thunk.force(vm)?;
let _ = value.force_deep(vm)?;
*self = value;
}
Value::ThunkRef(thunk) => {
let mut value = thunk.force(vm)?;
let mut value = thunk.force(vm)?.clone();
let _ = value.force_deep(vm)?;
*self = value;
}
@@ -461,7 +448,6 @@ impl<'jit, 'vm> Value<'jit, 'vm> {
Catchable(catchable) => Value::Catchable(catchable.clone()),
Const(cnst) => Value::Const(cnst.clone()),
Thunk(_) => Value::Thunk,
ThunkRef(_) => Value::Thunk,
PrimOp(primop) => Value::PrimOp(primop.name),
PartialPrimOp(primop) => Value::PartialPrimOp(primop.name),
Func(_) => Value::Func,
@@ -477,11 +463,17 @@ pub struct Thunk<'jit, 'vm> {
#[derive(Debug, IsVariant, Unwrap, Clone)]
pub enum _Thunk<'jit, 'vm> {
Code(&'vm OpCodes, OnceCell<Rc<VmEnv<'jit, 'vm>>>),
Code(&'vm OpCodes, OnceCell<EnvRef<'jit, 'vm>>),
SuspendedFrom(*const Thunk<'jit, 'vm>),
Value(Value<'jit, 'vm>),
}
#[derive(Debug, IsVariant, Unwrap, Clone)]
pub enum EnvRef<'jit, 'vm> {
Strong(Rc<VmEnv<'jit, 'vm>>),
Weak(Weak<VmEnv<'jit, 'vm>>),
}
impl<'jit, 'vm> Thunk<'jit, 'vm> {
pub fn new(opcodes: &'vm OpCodes) -> Self {
Thunk {
@@ -491,32 +483,48 @@ impl<'jit, 'vm> Thunk<'jit, 'vm> {
pub fn capture(&self, env: Rc<VmEnv<'jit, 'vm>>) {
if let _Thunk::Code(_, envcell) = &*self.thunk.borrow() {
envcell.get_or_init(|| env);
envcell.get_or_init(|| EnvRef::Strong(env));
}
}
pub fn force(&self, vm: &'vm VM<'jit>) -> Result<Value<'jit, 'vm>> {
pub fn capture_weak(&self, env: Weak<VmEnv<'jit, 'vm>>) {
if let _Thunk::Code(_, envcell) = &*self.thunk.borrow() {
envcell.get_or_init(|| EnvRef::Weak(env));
}
}
pub fn force(&self, vm: &'vm VM<'jit>) -> Result<&Value<'jit, 'vm>> {
use _Thunk::*;
match &*self.thunk.borrow() {
_Thunk::Value(value) => return Ok(value.clone()),
_Thunk::SuspendedFrom(from) => {
Value(_) => {
return Ok(match unsafe { &*(&*self.thunk.borrow() as *const _) } {
Value(value) => value,
_ => unreachable!(),
});
}
SuspendedFrom(from) => {
return Err(Error::EvalError(format!(
"thunk {:p} already suspended from {from:p} (infinite recursion encountered)",
self as *const Thunk
)));
}
_Thunk::Code(..) => (),
Code(..) => (),
}
let (opcodes, env) = std::mem::replace(
&mut *self.thunk.borrow_mut(),
_Thunk::SuspendedFrom(self as *const Thunk),
)
.unwrap_code();
let value = vm.eval(opcodes.iter().copied(), env.get().unwrap().clone())?;
let _ = std::mem::replace(
&mut *self.thunk.borrow_mut(),
_Thunk::Value(value.clone()),
);
Ok(value)
let env = match env.get().unwrap() {
EnvRef::Strong(env) => env.clone(),
EnvRef::Weak(env) => env.upgrade().unwrap(),
};
let value = vm.eval(opcodes.iter().copied(), env)?;
let _ = std::mem::replace(&mut *self.thunk.borrow_mut(), _Thunk::Value(value));
Ok(match unsafe { &*(&*self.thunk.borrow() as *const _) } {
Value(value) => value,
_ => unreachable!(),
})
}
pub fn value(&'vm self) -> Option<Value<'jit, 'vm>> {