Restructure node graph execution to be safer (#1277)

* Reorganize file structure

* Remove all unsafe code

* Add testcase for debugging ub

* Convert into proper test with fail condition

* General cleanup

* Fix tests

* Add feature guard for deallocation

* Use raw pointer for storing values to avoid violating aliasing rules

* Add comment explaining the disabling of simd128

* Fix brush node

* Fix formatting
This commit is contained in:
Dennis Kobert
2023-06-03 01:18:44 +02:00
committed by Keavon Chambers
parent 5558deba5e
commit 26473a8002
29 changed files with 363 additions and 299 deletions

View File

@@ -892,7 +892,7 @@ impl<'a> Iterator for RecursiveNodeIter<'a> {
#[cfg(test)]
mod test {
use std::{cell::Cell, sync::atomic::AtomicU64};
use std::sync::atomic::AtomicU64;
use super::*;
use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput};
@@ -1193,7 +1193,7 @@ mod test {
.collect(),
..Default::default()
};
let mut new_ids = 101..;
let _new_ids = 101..;
network.flatten_with_fns(1, |self_id, inner_id| self_id * 10 + inner_id, || 10000);
network.flatten_with_fns(2, |self_id, inner_id| self_id * 10 + inner_id, || 10001);
network.remove_dead_nodes();

View File

@@ -1,5 +1,5 @@
use super::DocumentNode;
use crate::executor::Any;
use crate::graphene_compiler::Any;
pub use crate::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus};
use crate::proto::{Any as DAny, FutureAny};

View File

@@ -8,5 +8,5 @@ pub use graphene_core::{concrete, generic, NodeIdentifier, Type, TypeDescriptor}
pub mod document;
pub mod proto;
pub mod executor;
pub mod graphene_compiler;
pub mod imaginate_input;

View File

@@ -1,5 +1,8 @@
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::ops::Deref;
use std::sync::Arc;
use std::hash::Hash;
use xxhash_rust::xxh3::Xxh3;
@@ -18,9 +21,59 @@ pub type Any<'n> = Box<dyn DynAny<'n> + 'n>;
pub type FutureAny<'n> = DynFuture<'n, Any<'n>>;
pub type TypeErasedNode<'n> = dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n;
pub type TypeErasedPinnedRef<'n> = Pin<&'n (dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n)>;
pub type TypeErasedRef<'n> = &'n (dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n);
pub type TypeErasedBox<'n> = Box<dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n>;
pub type TypeErasedPinned<'n> = Pin<Box<dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n>>;
pub type NodeConstructor = for<'a> fn(Vec<TypeErasedPinnedRef<'static>>) -> DynFuture<'static, TypeErasedPinned<'static>>;
pub type NodeConstructor = for<'a> fn(Vec<Arc<NodeContainer>>) -> DynFuture<'static, TypeErasedBox<'static>>;
#[derive(Clone)]
pub struct NodeContainer {
#[cfg(feature = "dealloc_nodes")]
pub node: *mut TypeErasedNode<'static>,
#[cfg(not(feature = "dealloc_nodes"))]
pub node: TypeErasedRef<'static>,
}
impl Deref for NodeContainer {
type Target = TypeErasedNode<'static>;
#[cfg(feature = "dealloc_nodes")]
fn deref(&self) -> &Self::Target {
unsafe { &*(self.node as *const TypeErasedNode) }
#[cfg(not(feature = "dealloc_nodes"))]
self.node
}
#[cfg(not(feature = "dealloc_nodes"))]
fn deref(&self) -> &Self::Target {
self.node
}
}
#[cfg(feature = "dealloc_nodes")]
impl Drop for NodeContainer {
fn drop(&mut self) {
unsafe { self.dealloc_unchecked() }
}
}
impl core::fmt::Debug for NodeContainer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NodeContainer").finish()
}
}
impl NodeContainer {
pub fn new(node: TypeErasedBox<'static>) -> Arc<Self> {
let node = Box::leak(node);
Arc::new(Self { node })
}
#[cfg(feature = "dealloc_nodes")]
unsafe fn dealloc_unchecked(&mut self) {
std::mem::drop(Box::from_raw(self.node));
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Default, PartialEq, Clone, Hash, Eq)]
@@ -406,7 +459,7 @@ impl ProtoNetwork {
}
/// The `TypingContext` is used to store the types of the nodes indexed by their stable node id.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[derive(Default, Clone)]
pub struct TypingContext {
lookup: Cow<'static, HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>>>,
inferred: HashMap<NodeId, NodeIOTypes>,
@@ -539,7 +592,7 @@ impl TypingContext {
dbg!(&self.inferred);
Err(format!(
"No implementations found for {identifier} with \ninput: {input:?} and \nparameters: {parameters:?}.\nOther Implementations found: {:?}",
impls,
impls.keys().collect::<Vec<_>>(),
))
}
[(org_nio, output)] => {