Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make stdlib::readback work in lazy mode #106

Merged
merged 2 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
7 changes: 7 additions & 0 deletions src/run/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()) }
}
}
113 changes: 46 additions & 67 deletions src/stdlib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,17 @@ pub struct LogDef<F>(Arc<Mutex<Host>>, F);
impl<F: Fn(Tree) + Clone + Send + Sync + 'static> AsHostedDef for LogDef<F> {
fn call<M: Mode>(def: &Def<Self>, net: &mut Net<M>, 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<Self>` points to
let def: &'static Def<Self> = 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<Self>` points to
let def: &'static Def<Self> = 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);
}
});
}
}

Expand Down Expand Up @@ -172,7 +162,7 @@ impl<T: AsHostedDef> AsDef for HostedDef<T> {

use crate::ast::Tree;

#[derive(Clone)]
#[derive(Copy, Clone)]
pub struct UniqueTreePtr(*mut Tree);
unsafe impl Send for UniqueTreePtr {}
unsafe impl Sync for UniqueTreePtr {}
Expand All @@ -188,18 +178,16 @@ pub struct ReadbackDef<F: FnOnce(DynNetMut) + Send + Sync + 'static> {
host: Arc<Mutex<Host>>,
var_idx: Arc<AtomicUsize>,
tree: UniqueTreePtr,
out: Port,
}

impl<F: FnOnce(DynNetMut) + Send + Sync + 'static> ReadbackDef<F> {
fn maybe_finish<'a, 'b>(net: DynNetMut<'a, 'b>, root: Arc<F>) {
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(),
Expand All @@ -210,7 +198,7 @@ impl<F: FnOnce(DynNetMut) + Send + Sync + 'static> ReadbackDef<F> {
impl<F: FnOnce(DynNetMut) + Send + Sync + 'static> AsBoxDef for ReadbackDef<F> {
fn call<M: Mode>(def: Box<Def<Self>>, net: &mut Net<M>, port: Port) {
match port.tag() {
Tag::Red => {
Tag::Var | Tag::Red => {
unreachable!()
}
Tag::Ref if port != Port::ERA => {
Expand All @@ -221,23 +209,18 @@ impl<F: FnOnce(DynNetMut) + Send + Sync + 'static> AsBoxDef for ReadbackDef<F> {
(*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 {
Expand All @@ -246,19 +229,13 @@ impl<F: FnOnce(DynNetMut) + Send + Sync + 'static> AsBoxDef for ReadbackDef<F> {
};
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 {
Expand All @@ -274,40 +251,42 @@ impl<F: FnOnce(DynNetMut) + Send + Sync + 'static> AsBoxDef for ReadbackDef<F> {
}
_ => 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<Mutex<Host>>, out: Port, f: impl FnOnce(DynNetMut, Tree) + Send + Sync + 'static) -> Port {
let root = Box::leak(Box::new(Tree::default()));
pub fn readback<M: Mode>(
net: &mut Net<M>,
host: Arc<Mutex<Host>>,
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<dyn FnOnce(DynNetMut) + Send + Sync + 'static> = 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)),
}))),
);
}
}
4 changes: 2 additions & 2 deletions tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading