diff --git a/Cargo.lock b/Cargo.lock index 7fe20073..021431c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -280,7 +280,7 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hvm-core" -version = "0.2.21" +version = "0.2.22" dependencies = [ "arrayvec", "clap", diff --git a/Cargo.toml b/Cargo.toml index dff6ed6e..40f9ab9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hvm-core" -version = "0.2.21" +version = "0.2.22" edition = "2021" description = "HVM-Core is a massively parallel Interaction Combinator evaluator." license = "MIT" diff --git a/src/run/node.rs b/src/run/node.rs index 60b27e2e..fb0116d2 100644 --- a/src/run/node.rs +++ b/src/run/node.rs @@ -60,4 +60,11 @@ impl<'a, M: Mode> Net<'a, M> { self.link_port_port(port, Port::new_var(wire.addr())); wire } + + /// Creates a wire pointing to a trg (this is a no-op if it is already a + /// wire); sometimes necessary to avoid deadlock. + #[inline(always)] + pub fn wire_to_trg(&mut self, trg: Trg) -> Wire { + if trg.is_wire() { trg.as_wire() } else { self.create_wire_to(trg.as_port()) } + } } diff --git a/src/stdlib.rs b/src/stdlib.rs index 6e284ab6..76147b38 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -44,27 +44,17 @@ pub struct LogDef(Arc>, F); impl AsHostedDef for LogDef { fn call(def: &Def, net: &mut Net, port: Port) { let (arg, seq) = net.do_ctr(0, Trg::port(port)); - let (wire, port) = net.create_wire(); - if M::LAZY { - net.link_trg_port(arg, port); - net.link_trg_port(seq, Port::new_ref(unsafe { &*IDENTITY })); - net.normal_from(wire.clone()); - def.data.1(def.data.0.lock().unwrap().readback_tree(&wire)); - net.link_wire_port(wire, Port::ERA); - } else { - // SAFETY: the function inside `readback` won't live longer than - // the net, and thus won't live longer than the host, where the - // `&Def` points to - let def: &'static Def = unsafe { core::mem::transmute(def) }; - let readback = readback(def.data.0.clone(), port, |net, tree| { - (def.data.1)(tree); - dispatch_dyn_net!(net => { - net.link_wire_port(wire, Port::ERA); - net.link_trg_port(seq, Port::new_ref(unsafe { &*IDENTITY })); - }); + let seq = net.wire_to_trg(seq); + // SAFETY: the function inside `readback` won't live longer than + // the net, and thus won't live longer than the host, where the + // `&Def` points to + let def: &'static Def = unsafe { core::mem::transmute(def) }; + readback(net, def.data.0.clone(), arg, |net, tree| { + (def.data.1)(tree); + dispatch_dyn_net!(net => { + net.link_wire_port(seq, Port::new_ref(unsafe { &*IDENTITY })); }); - net.link_trg_port(arg, readback); - } + }); } } @@ -172,7 +162,7 @@ impl AsDef for HostedDef { use crate::ast::Tree; -#[derive(Clone)] +#[derive(Copy, Clone)] pub struct UniqueTreePtr(*mut Tree); unsafe impl Send for UniqueTreePtr {} unsafe impl Sync for UniqueTreePtr {} @@ -188,7 +178,6 @@ pub struct ReadbackDef { host: Arc>, var_idx: Arc, tree: UniqueTreePtr, - out: Port, } impl ReadbackDef { @@ -196,10 +185,9 @@ impl ReadbackDef { let Some(root) = Arc::into_inner(root) else { return }; (root)(net) } - fn with(&self, tree: *mut Tree, out: Port) -> Port { + fn with(&self, tree: *mut Tree) -> Port { Port::new_ref(Box::leak(BoxDef::new_boxed(LabSet::ALL, Self { tree: UniqueTreePtr(tree), - out, root: self.root.clone(), var_idx: self.var_idx.clone(), host: self.host.clone(), @@ -210,7 +198,7 @@ impl ReadbackDef { impl AsBoxDef for ReadbackDef { fn call(def: Box>, net: &mut Net, port: Port) { match port.tag() { - Tag::Red => { + Tag::Var | Tag::Red => { unreachable!() } Tag::Ref if port != Port::ERA => { @@ -221,23 +209,18 @@ impl AsBoxDef for ReadbackDef { (*def.data.tree.0) = var.clone(); (*other.data.0.tree.0) = var; } - net.link_port_port(def.data.out, other.data.0.out); Self::maybe_finish(DynNetMut::from(&mut *net), other.data.0.root); } else if let Some(back) = def.data.host.lock().unwrap().back.get(&port.addr()) { unsafe { *(def.data.tree.0) = Tree::Ref { nam: back.clone() } }; - net.link_port_port(def.data.out, port); } else { unsafe { *(def.data.tree.0) = Tree::Era }; - net.link_port_port(def.data.out, port); } } Tag::Ref => { unsafe { *(def.data.tree.0) = Tree::Era }; - net.link_port_port(def.data.out, port); } Tag::Num => { unsafe { *(def.data.tree.0) = Tree::Num { val: port.num() } }; - net.link_port_port(def.data.out, port) } Tag::Mat => { unsafe { @@ -246,19 +229,13 @@ impl AsBoxDef for ReadbackDef { }; let Tree::Mat { zero, succ, out } = (unsafe { &mut *(def.data.tree.0) }) else { unreachable!() }; let old = port.clone().consume_node(); - let new = net.create_node(Tag::Mat, old.lab); let old_sel = old.p1.load_target().consume_node(); - let new_sel = net.create_node(Tag::Ctr, old_sel.lab); - net.link_port_port(def.data.out.clone(), new.p0); - net.link_port_port(new.p1, new_sel.p0); - net.link_wire_port(old.p2, def.data.with(out.as_mut(), new.p2)); - net.link_wire_port(old_sel.p1, def.data.with(zero.as_mut(), new_sel.p1)); - net.link_wire_port(old_sel.p2, def.data.with(succ.as_mut(), new_sel.p2)); + net.link_wire_port(old.p2, def.data.with(out.as_mut())); + net.link_wire_port(old_sel.p1, def.data.with(zero.as_mut())); + net.link_wire_port(old_sel.p2, def.data.with(succ.as_mut())); } - Tag::Var => net.link_port_port(def.data.out, port), tag @ (Tag::Op | Tag::Ctr) => { let old = port.clone().consume_node(); - let new = net.create_node(tag, old.lab); let (lhs, rhs): (*mut Tree, *mut Tree) = match tag { Tag::Op => { unsafe { @@ -274,40 +251,42 @@ impl AsBoxDef for ReadbackDef { } _ => unreachable!(), }; - net.link_port_port(def.data.out.clone(), new.p0); - net.link_wire_port(old.p1, def.data.with(lhs, new.p1)); - net.link_wire_port(old.p2, def.data.with(rhs, new.p2)); + net.link_wire_port(old.p1, def.data.with(lhs)); + net.link_wire_port(old.p2, def.data.with(rhs)); } } Self::maybe_finish(DynNetMut::from(net), def.data.root); } } -// public api: -// readback: Wire -> FnOnce(Tree) -> Port -// readback_and_wait: Net -> Wire -> Tree - -pub fn readback(host: Arc>, out: Port, f: impl FnOnce(DynNetMut, Tree) + Send + Sync + 'static) -> Port { - let root = Box::leak(Box::new(Tree::default())); +pub fn readback( + net: &mut Net, + host: Arc>, + from: Trg, + f: impl FnOnce(DynNetMut, Tree) + Send + Sync + 'static, +) { + let root = UniqueTreePtr(Box::leak(Box::new(Tree::default()))); - let root_ptr = UniqueTreePtr(root); - let root = UniqueTreePtr(root); + if M::LAZY { + let from = net.wire_to_trg(from); + net.normal_from(from.clone()); + let tree = host.lock().unwrap().readback_tree(&from); + net.link_wire_port(from, Port::ERA); + f(DynNetMut::from(net), tree); + } else { + let closure: Box = Box::new(move |net| { + let root = unsafe { root.to_box() }; + f(net, *root); + }); - use crate::run; - let closure: Box< - dyn for<'a, 'b> FnOnce(run::DynNetInner<&'a mut run::Net<'b, run::Lazy>, &'a mut run::Net<'b, run::Strict>>) - + Send - + Sync - + 'static, - > = Box::new(move |net| { - let root = unsafe { root.to_box() }; - f(net, *root); - }); - Port::new_ref(Box::leak(BoxDef::new_boxed(LabSet::ALL, ReadbackDef { - root: Arc::new(closure), - host, - tree: root_ptr, - var_idx: Arc::new(AtomicUsize::from(0)), - out, - }))) + net.link_trg_port( + from, + Port::new_ref(Box::leak(BoxDef::new_boxed(LabSet::ALL, ReadbackDef { + root: Arc::new(closure), + host, + tree: root, + var_idx: Arc::new(AtomicUsize::from(0)), + }))), + ); + } } diff --git a/tests/snapshots/tests__pre_reduce_run@log.hvmc.snap b/tests/snapshots/tests__pre_reduce_run@log.hvmc.snap index 3af9ec61..47f7b5c1 100644 --- a/tests/snapshots/tests__pre_reduce_run@log.hvmc.snap +++ b/tests/snapshots/tests__pre_reduce_run@log.hvmc.snap @@ -12,9 +12,9 @@ RWTS : 0 - DREF : 0 - OPER : 0 run: -RWTS : 8 +RWTS : 7 - ANNI : 2 - COMM : 0 -- ERAS : 1 +- ERAS : 0 - DREF : 5 - OPER : 0 diff --git a/tests/snapshots/tests__run@log.hvmc.snap b/tests/snapshots/tests__run@log.hvmc.snap index e1d4ea7b..5d5c16e6 100644 --- a/tests/snapshots/tests__run@log.hvmc.snap +++ b/tests/snapshots/tests__run@log.hvmc.snap @@ -4,9 +4,9 @@ expression: output input_file: tests/programs/log.hvmc --- #2 -RWTS : 8 +RWTS : 7 - ANNI : 2 - COMM : 0 -- ERAS : 1 +- ERAS : 0 - DREF : 5 - OPER : 0