feat: less clone, avoid evaluating not depended thunk

This commit is contained in:
2025-06-18 09:32:00 +08:00
parent 3e9f0a72a0
commit d875951c09
14 changed files with 409 additions and 192 deletions

View File

@@ -9,7 +9,7 @@ use crate::{
use super::{Dep, Func, Ir, LoadFunc, MaybeThunk, SccAnalyzer, SccNode, Thunk};
#[derive(Clone, Copy, Unwrap)]
#[derive(Clone, Copy, Unwrap, Debug)]
pub enum Index {
Thunk(usize),
Func(usize),
@@ -169,9 +169,11 @@ impl DowngradeContext {
}
pub fn new_dep(&mut self, this: Index, dep: Dep) -> Result<()> {
#[cfg(debug_assertions)]
println!("{this:?} => {dep:?}");
match this {
Index::Thunk(idx) => {
if dep == Dep::Thunk(idx) {
if dep == Dep::Thunk(idx) && !matches!(self.thunks[idx].0, Ir::List(_)) {
return Err(Error::DowngradeError(
"infinite recursion encountered".into(),
));

View File

@@ -8,7 +8,7 @@ use rnix::ast::{self, Expr};
use crate::builtins::ir_env;
use crate::engine::Engine;
use crate::env::VmEnv;
use crate::env::Env as VmEnv;
use crate::error::*;
use crate::eval::Evaluate;
use crate::eval::jit::{JITCompile, JITContext};
@@ -90,7 +90,7 @@ macro_rules! ir {
}
impl JITCompile for Ir {
fn compile<'ctx>(self, ctx: &JITContext<'ctx>, func: FunctionValue<'ctx>) -> StructValue<'ctx>{
fn compile<'ctx>(&self, ctx: &JITContext<'ctx>, func: FunctionValue<'ctx>) -> StructValue<'ctx>{
match self {
$(Ir::$ty(ir) => ir.compile(ctx, func),)*
}
@@ -98,7 +98,7 @@ macro_rules! ir {
}
impl Evaluate for Ir {
fn eval(self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
fn eval(&self, engine: &mut Engine, env: &mut VmEnv) -> Result<Value> {
match self {
$(Ir::$ty(ir) => ir.eval(engine, env),)*
}
@@ -1060,7 +1060,11 @@ impl Let {
env: &Env<'a, 'env>,
) -> Result<Ir> {
let map = self.bindings.clone();
let env = env.enter_let(&map);
let mut env = env.enter_let(&map);
self.bindings.into_iter().map(|(_, ir)| {
ir.resolve(self_idx, ctx, &mut env)?;
Ok(())
}).collect::<Result<()>>()?;
self.expr.resolve(self_idx, ctx, &env)?.ok()
}
}

View File

@@ -18,6 +18,7 @@ pub enum Dep {
#[derive(Default, Debug)]
pub struct SccGraph {
nodes: HashMap<usize, SccNode>,
root: usize,
}
impl SccGraph {
@@ -38,6 +39,7 @@ impl SccGraph {
},
);
}
graph.root = thunk_to_scc[&(ctx.thunks.len() - 1)];
for (from_node_id, from_deps) in ctx.thunk_deps.iter().enumerate() {
let from_scc_id = thunk_to_scc[&from_node_id];
@@ -58,28 +60,51 @@ impl SccGraph {
}
fn sorted(self) -> Vec<SccNode> {
let mut in_degrees: HashMap<usize, usize> = self.nodes.keys().map(|&id| (id, 0)).collect();
for node in self.nodes.values() {
in_degrees.insert(node.id, node.deps.len());
let mut reachable = HashSet::new();
let mut stack = vec![self.root];
reachable.insert(self.root);
while let Some(id) = stack.pop() {
if let Some(node) = self.nodes.get(&id) {
for &dep_id in &node.deps {
if reachable.insert(dep_id) {
stack.push(dep_id);
}
}
}
}
let mut in_degrees: HashMap<usize, usize> = HashMap::new();
let mut reverse_adj: HashMap<usize, Vec<usize>> = HashMap::new();
for (node_id, node) in &self.nodes {
for &dep_id in &node.deps {
reverse_adj.entry(dep_id).or_default().push(*node_id);
for &id in &reachable {
in_degrees.insert(id, 0);
}
for &id in &reachable {
if let Some(node) = self.nodes.get(&id) {
for &dep_id in &node.deps {
if reachable.contains(&dep_id) {
reverse_adj.entry(dep_id).or_default().push(id);
*in_degrees.get_mut(&id).unwrap() += 1;
}
}
}
}
let mut queue: std::collections::VecDeque<usize> = in_degrees
.iter()
.filter_map(|(&id, &deg)| if deg == 0 { Some(id) } else { None })
.filter(|(_, deg)| **deg == 0)
.map(|(&id, _)| id)
.collect();
queue.make_contiguous().sort();
let mut sorted_order = Vec::new();
while let Some(u) = queue.pop_front() {
sorted_order.push(self.nodes[&u].clone());
if let Some(node) = self.nodes.get(&u) {
sorted_order.push(node.clone());
}
if let Some(dependents) = reverse_adj.get(&u) {
for &v in dependents {
@@ -93,8 +118,8 @@ impl SccGraph {
}
}
if sorted_order.len() != self.nodes.len() {
panic!("Cycle detected in SCC graph, which is impossible!");
if sorted_order.len() != reachable.len() {
panic!("Cycle detected in the reachable part of SCC graph!");
}
sorted_order