feat: less clone, avoid evaluating not depended thunk
This commit is contained in:
@@ -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(),
|
||||
));
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, °)| 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
|
||||
|
||||
Reference in New Issue
Block a user