feat: SCC analysis (thunk capture WIP)

This commit is contained in:
2025-06-17 11:53:54 +08:00
parent b2d2490327
commit 7f6848c9e5
19 changed files with 501 additions and 458 deletions

View File

@@ -1,14 +1,13 @@
use std::rc::Rc;
use hashbrown::HashSet;
use lru::LruCache;
use priority_queue::PriorityQueue;
use crate::env::VmEnv;
use crate::error::Result;
use crate::eval::Evaluate;
use crate::ir::{Downgraded, Ir};
use crate::ty::internal as i;
use crate::ir::{Dep, Downgraded, Ir, SccNode};
use crate::ty::internal::{self as i, ThunkRef};
use crate::ty::public::Value;
#[cfg(test)]
@@ -18,40 +17,63 @@ type ThunkIdx = usize;
type EnvIdx = usize;
pub struct Engine {
thunks: Box<[Ir]>,
pub thunks: Box<[Ir]>,
pub func_offset: usize,
pub func_deps: Vec<HashSet<Dep>>,
tasks: PriorityQueue<CompileTask, usize>,
lru: LruCache<(ThunkIdx, EnvIdx), i::Value>,
}
pub fn eval(downgraded: Downgraded) -> Result<Value> {
let mut engine = Engine::new(downgraded.thunks, downgraded.func_offset);
engine
.eval()
.map(|mut val| {
Ok(val
.force(&mut engine)?
.to_public(&engine, &mut HashSet::new()))
})?
let mut engine = Engine::new(downgraded.thunks, downgraded.func_offset, downgraded.func_deps);
engine.eval(downgraded.graph)
}
impl Engine {
pub fn new(thunks: Box<[Ir]>, func_offset: usize) -> Self {
pub fn new(thunks: Box<[Ir]>, func_offset: usize, func_deps: Vec<HashSet<Dep>>) -> Self {
Self {
lru: LruCache::new(thunks.len().try_into().unwrap()),
tasks: PriorityQueue::new(),
thunks,
func_offset,
tasks: PriorityQueue::new(),
func_deps
}
}
pub fn eval(&mut self) -> Result<i::Value> {
self.thunks.last().unwrap().clone().eval(self, &mut VmEnv::new())
pub fn eval(&mut self, graph: Vec<SccNode>) -> Result<Value> {
let mut env = VmEnv::new();
let last = graph.last().unwrap().members[0];
for SccNode { members, .. } in graph.into_iter() {
// TODO:
assert!(members.len() == 1);
for member in members.into_iter() {
let val = self.thunks[member].clone().eval(self, &mut env)?;
env.insert_cache(member, val);
}
}
env.lookup_cache(last, |_| unreachable!())
.map(|mut val| Ok(val.force(self, &mut env)?.to_public(self, &mut HashSet::new())))?
}
pub fn eval_thunk(&mut self, idx: usize, env: &mut VmEnv) -> Result<i::Value> {
self.thunks[idx].clone().eval(self, env)
}
pub fn eval_func_deps(&mut self, idx: usize, env: &mut VmEnv) -> Result<()> {
for dep in self.func_deps[idx - self.func_offset].clone() {
match dep {
Dep::Arg(idx) => {
if let i::Value::Thunk(ThunkRef { idx }) = env.lookup_arg(idx) {
let val = self.thunks[idx].clone().eval(self, env)?;
env.insert_cache(idx, val)
}
},
Dep::Thunk(idx) =>{
let val = self.thunks[idx].clone().eval(self, env)?;
env.insert_cache(idx, val)
}
}
}
Ok(())
}
}
enum Thunk {