mirror of
https://github.com/urbit/ares.git
synced 2024-12-24 13:55:23 +03:00
Merge branch 'status' into mink-scry
This commit is contained in:
commit
13f110241c
2
.github/workflows/ares-shared.yml
vendored
2
.github/workflows/ares-shared.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
-A clippy::missing_safety_doc
|
||||
|
||||
- name: Build
|
||||
run: cargo build --release --verbose
|
||||
run: cargo build --release --verbose --features check_all
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --verbose -- --test-threads=1
|
||||
|
@ -42,4 +42,9 @@ opt-level = 3
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 3
|
||||
|
||||
# run with e.g. 'cargo build --features check_forwarding,check_acyclic'
|
||||
[features]
|
||||
check_all = [ "check_acyclic", "check_forwarding", "check_junior" ]
|
||||
check_acyclic = []
|
||||
check_forwarding = []
|
||||
check_junior = []
|
||||
|
@ -1,3 +1,6 @@
|
||||
use crate::assert_acyclic;
|
||||
use crate::assert_no_forwarding_pointers;
|
||||
use crate::assert_no_junior_pointers;
|
||||
use crate::hamt::Hamt;
|
||||
use crate::jets::JetErr;
|
||||
use crate::mem::unifying_equality;
|
||||
@ -290,9 +293,17 @@ impl From<JetErr> for NockErr {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn debug_assertions(stack: &mut NockStack, noun: Noun) {
|
||||
assert_acyclic!(noun);
|
||||
assert_no_forwarding_pointers!(noun);
|
||||
assert_no_junior_pointers!(stack, noun);
|
||||
}
|
||||
|
||||
/** Interpret nock */
|
||||
pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Result<Noun, Tone> {
|
||||
let terminator = Arc::clone(&TERMINATOR);
|
||||
let orig_subject = subject; // for debugging
|
||||
let virtual_frame: *const u64 = context.stack.get_frame_pointer();
|
||||
let mut res: Noun = D(0);
|
||||
|
||||
@ -322,15 +333,30 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
let work: NockWork = *context.stack.top();
|
||||
match work {
|
||||
NockWork::Done => {
|
||||
debug_assertions(context.stack, orig_subject);
|
||||
debug_assertions(context.stack, subject);
|
||||
debug_assertions(context.stack, res);
|
||||
|
||||
context.stack.preserve(context.cache);
|
||||
context.stack.preserve(&mut res);
|
||||
context.stack.frame_pop();
|
||||
|
||||
debug_assertions(context.stack, orig_subject);
|
||||
debug_assertions(context.stack, res);
|
||||
|
||||
break Ok(res);
|
||||
}
|
||||
NockWork::Ret => {
|
||||
debug_assertions(context.stack, orig_subject);
|
||||
debug_assertions(context.stack, subject);
|
||||
debug_assertions(context.stack, res);
|
||||
|
||||
context.stack.preserve(context.cache);
|
||||
context.stack.preserve(&mut res);
|
||||
context.stack.frame_pop();
|
||||
|
||||
debug_assertions(context.stack, orig_subject);
|
||||
debug_assertions(context.stack, res);
|
||||
}
|
||||
NockWork::WorkCons(mut cons) => match cons.todo {
|
||||
TodoCons::ComputeHead => {
|
||||
@ -388,6 +414,11 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
vale.todo = Todo2::RestoreSubject;
|
||||
std::mem::swap(&mut vale.subject, &mut subject);
|
||||
*context.stack.top() = NockWork::Work2(vale);
|
||||
|
||||
debug_assertions(context.stack, orig_subject);
|
||||
debug_assertions(context.stack, subject);
|
||||
debug_assertions(context.stack, res);
|
||||
|
||||
mean_frame_push(context.stack, 0);
|
||||
*context.stack.push() = NockWork::Ret;
|
||||
push_formula(context.stack, res, true)?;
|
||||
@ -396,6 +427,10 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
Todo2::RestoreSubject => {
|
||||
subject = vale.subject;
|
||||
context.stack.pop::<NockWork>();
|
||||
|
||||
debug_assertions(context.stack, orig_subject);
|
||||
debug_assertions(context.stack, subject);
|
||||
debug_assertions(context.stack, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -540,6 +575,11 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
kale.todo = Todo9::RestoreSubject;
|
||||
kale.core = subject;
|
||||
*context.stack.top() = NockWork::Work9(kale);
|
||||
|
||||
debug_assertions(context.stack, orig_subject);
|
||||
debug_assertions(context.stack, subject);
|
||||
debug_assertions(context.stack, res);
|
||||
|
||||
subject = res;
|
||||
mean_frame_push(context.stack, 0);
|
||||
*context.stack.push() = NockWork::Ret;
|
||||
@ -553,6 +593,10 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
Todo9::RestoreSubject => {
|
||||
subject = kale.core;
|
||||
context.stack.pop::<NockWork>();
|
||||
|
||||
debug_assertions(context.stack, orig_subject);
|
||||
debug_assertions(context.stack, subject);
|
||||
debug_assertions(context.stack, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::assert_acyclic;
|
||||
use crate::assert_no_forwarding_pointers;
|
||||
use crate::assert_no_junior_pointers;
|
||||
use crate::noun::{Atom, Cell, CellMemory, IndirectAtom, Noun, NounAllocator};
|
||||
use crate::snapshot::pma::{pma_in_arena, pma_malloc_w};
|
||||
use assert_no_alloc::permit_alloc;
|
||||
@ -356,6 +358,10 @@ impl NockStack {
|
||||
}
|
||||
|
||||
unsafe fn copy(&mut self, noun: &mut Noun) {
|
||||
assert_acyclic!(*noun);
|
||||
assert_no_forwarding_pointers!(*noun);
|
||||
assert_no_junior_pointers!(self, *noun);
|
||||
|
||||
self.pre_copy();
|
||||
assert!(self.stack_is_empty());
|
||||
let noun_ptr = noun as *mut Noun;
|
||||
@ -443,7 +449,10 @@ impl NockStack {
|
||||
}
|
||||
}
|
||||
// Set saved previous allocation pointer its new value after this allocation
|
||||
|
||||
assert_acyclic!(*noun);
|
||||
assert_no_forwarding_pointers!(*noun);
|
||||
assert_no_junior_pointers!(self, *noun);
|
||||
}
|
||||
|
||||
pub unsafe fn copy_pma(&mut self, noun: &mut Noun) {
|
||||
@ -517,7 +526,6 @@ impl NockStack {
|
||||
},
|
||||
}
|
||||
}
|
||||
assert_acyclic!(*noun);
|
||||
}
|
||||
|
||||
pub unsafe fn frame_pop(&mut self) {
|
||||
@ -679,6 +687,88 @@ impl NockStack {
|
||||
unsafe { self.stack_pointer == self.alloc_pointer.add(RESERVED) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn no_junior_pointers(&self, noun: Noun) -> bool {
|
||||
unsafe {
|
||||
if let Ok(c) = noun.as_cell() {
|
||||
let mut fp: *mut u64;
|
||||
let mut sp = self.stack_pointer;
|
||||
let mut ap = self.alloc_pointer;
|
||||
let mut pfp = *(self.prev_frame_pointer_pointer());
|
||||
let mut psp = *(self.prev_stack_pointer_pointer());
|
||||
let mut pap = *(self.prev_alloc_pointer_pointer());
|
||||
|
||||
let mut dbg_stack = Vec::new();
|
||||
|
||||
// Detemine range
|
||||
let (rlo, rhi) = loop {
|
||||
if psp.is_null() {
|
||||
psp = ((self.start as u64) + ((self.size << 3) as u64)) as *mut u64;
|
||||
}
|
||||
let (lo, hi) = if sp < ap { (ap, psp) } else { (psp, ap) };
|
||||
let ptr = c.to_raw_pointer() as *mut u64;
|
||||
if ptr >= lo && ptr < hi {
|
||||
break if sp < ap { (sp, ap) } else { (ap, sp) };
|
||||
} else {
|
||||
fp = pfp;
|
||||
sp = psp;
|
||||
ap = pap;
|
||||
if sp < ap {
|
||||
pfp = *(fp.sub(FRAME + 1)) as *mut u64;
|
||||
psp = *(fp.sub(STACK + 1)) as *mut u64;
|
||||
pap = *(fp.sub(ALLOC + 1)) as *mut u64;
|
||||
} else {
|
||||
pfp = *(fp.add(FRAME)) as *mut u64;
|
||||
psp = *(fp.add(STACK)) as *mut u64;
|
||||
pap = *(fp.add(ALLOC)) as *mut u64;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
dbg_stack.push(c.head());
|
||||
dbg_stack.push(c.tail());
|
||||
while let Some(n) = dbg_stack.pop() {
|
||||
if let Ok(a) = n.as_allocated() {
|
||||
let ptr = a.to_raw_pointer();
|
||||
if ptr >= rlo && ptr < rhi {
|
||||
eprintln!(
|
||||
"\rserf: Noun {:x} has Noun {:x} in junior of range {:p}-{:p}",
|
||||
(noun.raw << 3),
|
||||
(n.raw << 3),
|
||||
rlo,
|
||||
rhi
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if let Some(c) = a.cell() {
|
||||
dbg_stack.push(c.tail());
|
||||
dbg_stack.push(c.head());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "check_junior")]
|
||||
#[macro_export]
|
||||
macro_rules! assert_no_junior_pointers {
|
||||
( $x:expr, $y:expr ) => {
|
||||
assert_no_alloc::permit_alloc(|| {
|
||||
assert!($x.no_junior_pointers($y));
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "check_junior"))]
|
||||
#[macro_export]
|
||||
macro_rules! assert_no_junior_pointers {
|
||||
( $x:expr, $y:expr ) => {};
|
||||
}
|
||||
|
||||
pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool {
|
||||
@ -705,6 +795,13 @@ pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Nou
|
||||
* senior noun, *never vice versa*, to avoid introducing references from more senior frames
|
||||
* into more junior frames, which would result in incorrect operation of the copier.
|
||||
*/
|
||||
assert_acyclic!(*a);
|
||||
assert_acyclic!(*b);
|
||||
assert_no_forwarding_pointers!(*a);
|
||||
assert_no_forwarding_pointers!(*b);
|
||||
assert_no_junior_pointers!(stack, *a);
|
||||
assert_no_junior_pointers!(stack, *b);
|
||||
|
||||
// If the nouns are already word-equal we have nothing to do
|
||||
if (*a).raw_equals(*b) {
|
||||
return true;
|
||||
@ -800,8 +897,14 @@ pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Nou
|
||||
}
|
||||
}
|
||||
stack.frame_pop();
|
||||
|
||||
assert_acyclic!(*a);
|
||||
assert_acyclic!(*b);
|
||||
assert_no_forwarding_pointers!(*a);
|
||||
assert_no_forwarding_pointers!(*b);
|
||||
assert_no_junior_pointers!(stack, *a);
|
||||
assert_no_junior_pointers!(stack, *b);
|
||||
|
||||
(*a).raw_equals(*b)
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::assert_acyclic;
|
||||
use crate::assert_no_forwarding_pointers;
|
||||
use crate::assert_no_junior_pointers;
|
||||
use crate::mem::*;
|
||||
use crate::noun::{Allocated, Atom, DirectAtom, Noun};
|
||||
use either::Either::*;
|
||||
@ -119,7 +121,11 @@ pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 {
|
||||
if let Some(mug) = get_mug(noun) {
|
||||
return mug;
|
||||
}
|
||||
|
||||
assert_acyclic!(noun);
|
||||
assert_no_forwarding_pointers!(noun);
|
||||
assert_no_junior_pointers!(stack, noun);
|
||||
|
||||
stack.frame_push(0);
|
||||
unsafe {
|
||||
*(stack.push()) = noun;
|
||||
@ -171,6 +177,11 @@ pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 {
|
||||
unsafe {
|
||||
stack.frame_pop();
|
||||
}
|
||||
|
||||
assert_acyclic!(noun);
|
||||
assert_no_forwarding_pointers!(noun);
|
||||
assert_no_junior_pointers!(stack, noun);
|
||||
|
||||
get_mug(noun).expect("Noun should have a mug once it is mugged.")
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,9 @@ pub const NO: Noun = D(1);
|
||||
#[macro_export]
|
||||
macro_rules! assert_acyclic {
|
||||
( $x:expr ) => {
|
||||
assert!(crate::noun::acyclic_noun($x));
|
||||
assert_no_alloc::permit_alloc(|| {
|
||||
assert!(crate::noun::acyclic_noun($x));
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
@ -82,6 +84,42 @@ fn acyclic_noun_go(noun: Noun, seen: &mut IntMap<()>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "check_forwarding")]
|
||||
#[macro_export]
|
||||
macro_rules! assert_no_forwarding_pointers {
|
||||
( $x:expr ) => {
|
||||
assert_no_alloc::permit_alloc(|| {
|
||||
assert!(crate::noun::no_forwarding_pointers($x));
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "check_forwarding"))]
|
||||
#[macro_export]
|
||||
macro_rules! assert_no_forwarding_pointers {
|
||||
( $x:expr ) => {};
|
||||
}
|
||||
|
||||
pub fn no_forwarding_pointers(noun: Noun) -> bool {
|
||||
let mut dbg_stack = Vec::new();
|
||||
dbg_stack.push(noun);
|
||||
|
||||
while !dbg_stack.is_empty() {
|
||||
if let Some(noun) = dbg_stack.pop() {
|
||||
if unsafe { noun.raw & FORWARDING_MASK == FORWARDING_TAG } {
|
||||
return false;
|
||||
} else if let Ok(cell) = noun.as_cell() {
|
||||
dbg_stack.push(cell.tail());
|
||||
dbg_stack.push(cell.head());
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/** Test if a noun is a direct atom. */
|
||||
fn is_direct_atom(noun: u64) -> bool {
|
||||
noun & DIRECT_MASK == DIRECT_TAG
|
||||
@ -835,6 +873,14 @@ impl Allocated {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cell(&self) -> Option<Cell> {
|
||||
if self.is_cell() {
|
||||
unsafe { Some(self.cell) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_noun(&self) -> Noun {
|
||||
Noun { allocated: *self }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user