mirror of
https://github.com/urbit/ares.git
synced 2024-11-22 06:32:47 +03:00
Make Nock 11 tail recursive; use slots for mean stack
This commit is contained in:
parent
d02e2bc75b
commit
147aabb524
@ -22,7 +22,7 @@
|
||||
:: %mean hint
|
||||
~_ [%leaf "I am a %mean hint via ~_ from +wack"]
|
||||
:: %hela hint
|
||||
:: ~> %hela
|
||||
~> %hela
|
||||
:: %memo hint
|
||||
~+
|
||||
?~ m +(n)
|
||||
@ -34,7 +34,7 @@
|
||||
!.
|
||||
|= [m=@ud n=@ud]
|
||||
:: %hela hint
|
||||
:: ~> %hela
|
||||
~> %hela
|
||||
:: %memo hint
|
||||
~+
|
||||
?~ m +(n)
|
||||
|
@ -189,6 +189,7 @@ struct Nock11D {
|
||||
tag: Atom,
|
||||
hint: Noun,
|
||||
body: Noun,
|
||||
tail: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@ -202,6 +203,7 @@ struct Nock11S {
|
||||
todo: Todo11S,
|
||||
tag: Atom,
|
||||
body: Noun,
|
||||
tail: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@ -242,16 +244,18 @@ pub fn interpret(
|
||||
formula: Noun,
|
||||
) -> Result<Noun, NockErr> {
|
||||
let mut res: Noun = D(0);
|
||||
let mut trace: Noun;
|
||||
let mut cache = Hamt::<Noun>::new();
|
||||
// XX: Should this come after initial frame_push()?
|
||||
let virtual_frame = stack.get_frame_pointer();
|
||||
|
||||
stack.frame_push(0);
|
||||
// Setup stack for Nock computation
|
||||
unsafe {
|
||||
stack.frame_push(1);
|
||||
// Bottom of mean stack
|
||||
*(stack.local_noun_pointer(0)) = D(0);
|
||||
*stack.push() = NockWork::Done;
|
||||
push_formula(stack, formula, true)?;
|
||||
};
|
||||
push_formula(stack, formula, true)?;
|
||||
|
||||
// DO NOT REMOVE THIS ASSERTION
|
||||
//
|
||||
// If you need to allocate for debugging, wrap the debugging code in
|
||||
@ -328,7 +332,7 @@ pub fn interpret(
|
||||
vale.todo = Todo2::RestoreSubject;
|
||||
std::mem::swap(&mut vale.subject, &mut subject);
|
||||
*stack.top() = NockWork::Work2(vale);
|
||||
stack.frame_push(0);
|
||||
mean_frame_push(stack, 0);
|
||||
*stack.push() = NockWork::Ret;
|
||||
push_formula(stack, res, true)?;
|
||||
}
|
||||
@ -475,7 +479,7 @@ pub fn interpret(
|
||||
kale.core = subject;
|
||||
*stack.top() = NockWork::Work9(kale);
|
||||
subject = res;
|
||||
stack.frame_push(0);
|
||||
mean_frame_push(stack, 0);
|
||||
*stack.push() = NockWork::Ret;
|
||||
push_formula(stack, formula, true)?;
|
||||
}
|
||||
@ -536,8 +540,12 @@ pub fn interpret(
|
||||
stack.pop::<NockWork>();
|
||||
} else {
|
||||
dint.todo = Todo11D::Done;
|
||||
*stack.top() = NockWork::Work11D(dint);
|
||||
push_formula(stack, dint.body, false)?;
|
||||
if dint.tail {
|
||||
stack.pop::<NockWork>();
|
||||
} else {
|
||||
*stack.top() = NockWork::Work11D(dint);
|
||||
}
|
||||
push_formula(stack, dint.body, dint.tail)?;
|
||||
}
|
||||
}
|
||||
Todo11D::Done => {
|
||||
@ -565,8 +573,12 @@ pub fn interpret(
|
||||
stack.pop::<NockWork>();
|
||||
} else {
|
||||
sint.todo = Todo11S::Done;
|
||||
*stack.top() = NockWork::Work11S(sint);
|
||||
push_formula(stack, sint.body, false)?;
|
||||
if sint.tail {
|
||||
stack.pop::<NockWork>();
|
||||
} else {
|
||||
*stack.top() = NockWork::Work11S(sint);
|
||||
}
|
||||
push_formula(stack, sint.body, sint.tail)?;
|
||||
}
|
||||
}
|
||||
Todo11S::Done => {
|
||||
@ -584,11 +596,7 @@ pub fn interpret(
|
||||
|
||||
match tone {
|
||||
Ok(res) => Ok(res),
|
||||
Err(_err) => {
|
||||
trace = stack.get_mean_stack();
|
||||
exit_early(stack, virtual_frame, &mut trace, &mut cache);
|
||||
Err(NockErr::Error(trace))
|
||||
}
|
||||
Err(_err) => Err(exit_early(stack, virtual_frame, &mut cache)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -751,6 +759,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
|
||||
todo: Todo11S::ComputeResult,
|
||||
tag: tag_atom,
|
||||
body: arg_cell.tail(),
|
||||
tail: tail && is_hint_tail(tag_atom),
|
||||
});
|
||||
}
|
||||
Right(hint_cell) => {
|
||||
@ -760,6 +769,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
|
||||
tag: tag_atom,
|
||||
hint: hint_cell.tail(),
|
||||
body: arg_cell.tail(),
|
||||
tail: tail && is_hint_tail(tag_atom),
|
||||
});
|
||||
} else {
|
||||
// Hint tag must be an atom
|
||||
@ -791,18 +801,46 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn exit_early(
|
||||
stack: &mut NockStack,
|
||||
virtual_frame: *const u64,
|
||||
trace: &mut Noun,
|
||||
cache: &mut Hamt<Noun>,
|
||||
) {
|
||||
fn exit_early(stack: &mut NockStack, virtual_frame: *const u64, cache: &mut Hamt<Noun>) -> NockErr {
|
||||
unsafe {
|
||||
let mut trace = *(stack.local_noun_pointer(0));
|
||||
while stack.get_frame_pointer() != virtual_frame {
|
||||
stack.preserve(trace);
|
||||
stack.preserve(&mut trace);
|
||||
stack.preserve(cache);
|
||||
stack.frame_pop();
|
||||
}
|
||||
NockErr::Error(trace)
|
||||
}
|
||||
}
|
||||
|
||||
/** Push frame onto NockStack while preserving the mean stack.
|
||||
*/
|
||||
fn mean_frame_push(stack: &mut NockStack, slots: usize) {
|
||||
unsafe {
|
||||
let trace = *(stack.local_noun_pointer(0));
|
||||
stack.frame_push(slots + 1);
|
||||
*(stack.local_noun_pointer(0)) = trace;
|
||||
}
|
||||
}
|
||||
|
||||
/** Push onto the mean stack.
|
||||
*/
|
||||
fn mean_push(stack: &mut NockStack, noun: Noun) {
|
||||
unsafe {
|
||||
let cur_trace = *(stack.local_noun_pointer(0));
|
||||
let new_trace = T(stack, &[noun, cur_trace]);
|
||||
*(stack.local_noun_pointer(0)) = new_trace;
|
||||
}
|
||||
}
|
||||
|
||||
/** Pop off of the mean stack.
|
||||
*/
|
||||
fn mean_pop(stack: &mut NockStack) {
|
||||
unsafe {
|
||||
*(stack.local_noun_pointer(0)) = (*(stack.local_noun_pointer(0)))
|
||||
.as_cell()
|
||||
.expect("serf: unexpected end of mean stack\r")
|
||||
.tail();
|
||||
}
|
||||
}
|
||||
|
||||
@ -876,6 +914,19 @@ pub fn inc(stack: &mut NockStack, atom: Atom) -> Atom {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_hint_tail(tag: Atom) -> bool {
|
||||
// XX: handle IndirectAtom tags
|
||||
match tag.direct() {
|
||||
#[allow(clippy::match_like_matches_macro)]
|
||||
Some(dtag) => match dtag.data() {
|
||||
tas!(b"fast") => false,
|
||||
tas!(b"memo") => false,
|
||||
_ => true,
|
||||
},
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
/** Match dynamic hints before the hint formula is evaluated */
|
||||
fn match_hint_pre_hint(
|
||||
stack: &mut NockStack,
|
||||
@ -956,30 +1007,14 @@ fn match_hint_pre_nock(
|
||||
}
|
||||
}
|
||||
tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => {
|
||||
let trace = Cell::new(stack, tag.as_noun(), res?).as_noun();
|
||||
stack.trace_push(trace);
|
||||
let noun = T(stack, &[tag.as_noun(), res?]);
|
||||
mean_push(stack, noun);
|
||||
}
|
||||
//
|
||||
// u3_serf_writ -> u3_serf_work -> _serf_work -> _serf_poke -> u3m_soft -> u3dc -> u3v_do -> u3v_wish -> +wish in Arvo
|
||||
// |
|
||||
// V
|
||||
// mook
|
||||
//
|
||||
// No +wish in toy Arvo; missing +slap and a ton of parsing functions needed by +ream
|
||||
//
|
||||
// u3t_slog = print on thing directly
|
||||
// u3t_slog_trace = print stack trace = - convert tone to toon
|
||||
// - presume toon is [%2 tang]
|
||||
// - print each tank in tang one at at time using u3t_slog
|
||||
// u3t_slog_hela = print entire stack trace = - weld stacks from all roads together
|
||||
// - call u3t_slog_trace on combined stack
|
||||
// u3t_slog_nara = print home road stack trace = call u3t_slog_trace on home road stack
|
||||
//
|
||||
tas!(b"hela") => {
|
||||
// XX: should this be virtualized?
|
||||
// pretty sure we should be bailing on error
|
||||
// might need to switch return type to Result<Option<Noun>, NockErr>
|
||||
let stak = stack.get_mean_stack();
|
||||
let stak = unsafe { *(stack.local_noun_pointer(0)) };
|
||||
let tone = Cell::new(stack, D(2), stak);
|
||||
|
||||
if let Ok(toon) = mook(stack, newt, tone, true) {
|
||||
@ -1034,8 +1069,7 @@ fn match_hint_post_nock(
|
||||
*cache = cache.insert(stack, &mut key, res);
|
||||
}
|
||||
tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => {
|
||||
// In the future, we should only do this if 11 is not in tail position
|
||||
stack.trace_pop();
|
||||
mean_pop(stack);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::assert_acyclic;
|
||||
use crate::noun::{Atom, Cell, CellMemory, DirectAtom, IndirectAtom, Noun, NounAllocator};
|
||||
use crate::noun::{Atom, Cell, CellMemory, IndirectAtom, Noun, NounAllocator};
|
||||
use crate::snapshot::pma::{pma_in_arena, pma_malloc_w};
|
||||
use either::Either::{self, Left, Right};
|
||||
use ibig::Stack;
|
||||
@ -46,8 +46,6 @@ pub struct NockStack {
|
||||
stack_pointer: *mut u64,
|
||||
/** Alloc pointer for the current stack frame. */
|
||||
alloc_pointer: *mut u64,
|
||||
/** Pointer to top of mean stack; mean stack references previous frames */
|
||||
mean_stack: *mut Noun,
|
||||
/** MMap which must be kept alive as long as this NockStack is */
|
||||
memory: MmapMut,
|
||||
/** Whether or not pre_copy() has been called on the current stack frame. */
|
||||
@ -68,16 +66,13 @@ impl NockStack {
|
||||
let memory = MmapMut::map_anon(size << 3).expect("Mapping memory for nockstack failed");
|
||||
let start = memory.as_ptr() as *const u64;
|
||||
// Here, frame_pointer < alloc_pointer, so the initial frame is West
|
||||
let frame_pointer = unsafe { start.add(RESERVED + top_slots + 1) } as *mut u64;
|
||||
let frame_pointer = unsafe { start.add(RESERVED + top_slots) } as *mut u64;
|
||||
let stack_pointer = frame_pointer;
|
||||
let alloc_pointer = unsafe { start.add(size) } as *mut u64;
|
||||
// The extra 1 in frame_pointer is for the base of the mean stack
|
||||
let mean_stack = start as *mut Noun;
|
||||
unsafe {
|
||||
*frame_pointer.sub(1) = ptr::null::<u64>() as u64; // "frame pointer" from "previous" frame
|
||||
*frame_pointer.sub(STACK + 1) = ptr::null::<u64>() as u64; // "stack pointer" from "previous" frame
|
||||
*frame_pointer.sub(ALLOC + 1) = start as u64; // "alloc pointer" from "previous" frame
|
||||
*mean_stack = DirectAtom::new_unchecked(0).as_noun();
|
||||
};
|
||||
NockStack {
|
||||
start,
|
||||
@ -85,7 +80,6 @@ impl NockStack {
|
||||
frame_pointer,
|
||||
stack_pointer,
|
||||
alloc_pointer,
|
||||
mean_stack,
|
||||
memory,
|
||||
pc: false,
|
||||
}
|
||||
@ -96,11 +90,6 @@ impl NockStack {
|
||||
self.frame_pointer
|
||||
}
|
||||
|
||||
/** Current frame pointer of this NockStack */
|
||||
pub fn get_mean_stack(&self) -> Noun {
|
||||
unsafe { *self.mean_stack }
|
||||
}
|
||||
|
||||
/** Checks if the current stack frame has West polarity */
|
||||
#[inline]
|
||||
pub fn is_west(&self) -> bool {
|
||||
@ -677,23 +666,6 @@ impl NockStack {
|
||||
unsafe { self.stack_pointer == self.alloc_pointer.add(RESERVED) }
|
||||
}
|
||||
}
|
||||
|
||||
/** Push onto the mean stack (for tracing) */
|
||||
pub fn trace_push(&mut self, mon: Noun) {
|
||||
unsafe {
|
||||
*(self.mean_stack) = Cell::new(self, mon, *self.mean_stack).as_noun();
|
||||
}
|
||||
}
|
||||
|
||||
/** Pop from the mean stack (for tracing) */
|
||||
pub fn trace_pop(&mut self) {
|
||||
unsafe {
|
||||
*(self.mean_stack) = (*self.mean_stack)
|
||||
.as_cell()
|
||||
.expect("mean stack should be non-null when popped")
|
||||
.tail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool {
|
||||
|
Loading…
Reference in New Issue
Block a user