mirror of
https://github.com/urbit/ares.git
synced 2024-11-26 09:57:56 +03:00
[ares] Add noun acyclicality check
This commit is contained in:
parent
dabafb685d
commit
903ffe694c
@ -1,4 +1,5 @@
|
||||
use crate::noun::{CellMemory, IndirectAtom, Noun, NounAllocator, Cell};
|
||||
use crate::assert_acyclic;
|
||||
use either::Either::{self, Left, Right};
|
||||
use libc::{c_void, memcmp};
|
||||
use memmap::MmapMut;
|
||||
@ -422,6 +423,7 @@ impl NockStack {
|
||||
}
|
||||
}
|
||||
*self.previous_stack_pointer_pointer_east() = other_stack_pointer;
|
||||
assert_acyclic!(*noun);
|
||||
}
|
||||
|
||||
/** Copy a result noun and its subnouns from a west frame to its parent east frame
|
||||
@ -532,6 +534,7 @@ impl NockStack {
|
||||
}
|
||||
}
|
||||
*self.previous_stack_pointer_pointer_west() = other_stack_pointer;
|
||||
assert_acyclic!(*noun);
|
||||
}
|
||||
|
||||
/** Pop a frame from the (east) stack, providing a result, which will be copied to the return target
|
||||
@ -733,6 +736,8 @@ pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Nou
|
||||
}
|
||||
stack.restore_prev_stack_pointer_from_local(0);
|
||||
stack.pop_no_copy();
|
||||
assert_acyclic!(*a);
|
||||
assert_acyclic!(*b);
|
||||
(*a).raw_equals(*b)
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::assert_acyclic;
|
||||
use crate::mem::*;
|
||||
use crate::noun::{Allocated, Atom, DirectAtom, Noun};
|
||||
use either::Either::*;
|
||||
@ -177,6 +178,7 @@ pub fn mug_u32_one(noun: Noun) -> Option<u32> {
|
||||
}
|
||||
|
||||
pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 {
|
||||
assert_acyclic!(noun);
|
||||
stack.push(1);
|
||||
unsafe {
|
||||
stack.save_prev_stack_pointer_to_local(0);
|
||||
|
@ -30,6 +30,50 @@ const FORWARDING_TAG: u64 = u64::MAX & CELL_MASK;
|
||||
/** Tag mask for a forwarding pointer */
|
||||
const FORWARDING_MASK: u64 = CELL_MASK;
|
||||
|
||||
#[cfg(feature = "check_acyclic")]
|
||||
#[macro_export]
|
||||
macro_rules! assert_acyclic {
|
||||
( $x:expr ) => {
|
||||
assert!(acyclic_noun($x));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "check_acyclic"))]
|
||||
#[macro_export]
|
||||
macro_rules! assert_acyclic {
|
||||
( $x:expr ) => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn acyclic_noun(noun: Noun) -> bool {
|
||||
let mut seen = IntMap::new();
|
||||
acyclic_noun_go(noun, &mut seen)
|
||||
}
|
||||
|
||||
fn acyclic_noun_go(noun: Noun, seen: &mut IntMap<()>) -> bool {
|
||||
match noun.as_either_atom_cell() {
|
||||
Either::Left(_atom) => true,
|
||||
Either::Right(cell) => {
|
||||
if let Some(_) = seen.get(cell.0) {
|
||||
false
|
||||
} else {
|
||||
seen.insert(cell.0, ());
|
||||
if acyclic_noun_go(cell.head(), seen) {
|
||||
if acyclic_noun_go(cell.tail(), seen) {
|
||||
seen.remove(cell.0);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Test if a noun is a direct atom. */
|
||||
fn is_direct_atom(noun: u64) -> bool {
|
||||
noun & DIRECT_MASK == DIRECT_TAG
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::assert_acyclic;
|
||||
use crate::mem::unifying_equality;
|
||||
use crate::mem::NockStack;
|
||||
use crate::mug::mug_u32;
|
||||
@ -34,6 +35,7 @@ pub fn cue(stack: &mut NockStack, buffer: Atom) -> Noun {
|
||||
loop {
|
||||
if unsafe { stack.prev_stack_pointer_equals_local(0) } {
|
||||
let mut result = unsafe { *(stack.local_noun_pointer(1)) };
|
||||
assert_acyclic!(result);
|
||||
unsafe {
|
||||
stack.pop(&mut result);
|
||||
};
|
||||
@ -46,9 +48,15 @@ pub fn cue(stack: &mut NockStack, buffer: Atom) -> Noun {
|
||||
// 11 bits - cue backreference
|
||||
cursor += 2;
|
||||
unsafe {
|
||||
*dest_ptr = *(backref_map
|
||||
let reffed_noun = *(backref_map
|
||||
.get(rub_backref(&mut cursor, buffer_bitslice))
|
||||
.expect("Invalid backref in cue"));
|
||||
assert_acyclic!(reffed_noun);
|
||||
if let Ok(indirect) = reffed_noun.as_indirect() {
|
||||
debug_assert!(indirect.size() > 0);
|
||||
}
|
||||
*dest_ptr = reffed_noun;
|
||||
assert_acyclic!(reffed_noun);
|
||||
stack.reclaim_in_previous_frame::<*mut Noun>();
|
||||
}
|
||||
continue;
|
||||
@ -61,6 +69,8 @@ pub fn cue(stack: &mut NockStack, buffer: Atom) -> Noun {
|
||||
*dest_ptr = cell.as_noun();
|
||||
backref_map.insert(backref as u64, *dest_ptr);
|
||||
stack.reclaim_in_previous_frame::<*mut Noun>();
|
||||
(*cell_mem_ptr).tail = DirectAtom::new_unchecked(0xEDBEEF).as_atom().as_noun();
|
||||
(*cell_mem_ptr).head = DirectAtom::new_unchecked(0xDEBEEF).as_atom().as_noun();
|
||||
*(stack.alloc_in_previous_frame::<*mut Noun>()) =
|
||||
&mut ((*cell_mem_ptr).tail);
|
||||
*(stack.alloc_in_previous_frame::<*mut Noun>()) =
|
||||
|
Loading…
Reference in New Issue
Block a user