mirror of
https://github.com/urbit/ares.git
synced 2024-11-26 09:57:56 +03:00
Merge branch 'as/serf-guard' into msl/guard
- compiles - tests fail - doesn't run
This commit is contained in:
commit
1e44565c53
@ -36,18 +36,18 @@ signal-hook = "0.3"
|
||||
static_assertions = "1.1.0"
|
||||
|
||||
[build-dependencies]
|
||||
autotools = "0.2.6"
|
||||
cc = "1.0.79"
|
||||
autotools = "0.2"
|
||||
cc = "1.0"
|
||||
|
||||
[[bin]]
|
||||
name = "ares"
|
||||
path = "src/main.rs"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
opt-level = 3
|
||||
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 0
|
||||
opt-level = 3
|
||||
|
||||
# run with e.g. 'cargo build --features check_forwarding,check_acyclic'
|
||||
[features]
|
||||
|
114
rust/ares/src/guard.rs
Normal file
114
rust/ares/src/guard.rs
Normal file
@ -0,0 +1,114 @@
|
||||
use crate::interpreter::{Error, Mote, Result};
|
||||
use crate::noun::D;
|
||||
use ares_guard::*;
|
||||
use assert_no_alloc::permit_alloc;
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi::c_void;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GuardError {
|
||||
InvalidSignal,
|
||||
MemoryProtection,
|
||||
NullPointer,
|
||||
OutOfMemory,
|
||||
Setup,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl From<u32> for GuardError {
|
||||
fn from(value: u32) -> Self {
|
||||
match value {
|
||||
GUARD_NULL => Self::NullPointer,
|
||||
GUARD_SIGNAL => Self::InvalidSignal,
|
||||
GUARD_OOM => Self::OutOfMemory,
|
||||
x if (x & GUARD_MPROTECT) != 0 => Self::MemoryProtection,
|
||||
x if (x & (GUARD_MALLOC | GUARD_SIGACTION)) != 0 => Self::Setup,
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CCallback<'closure> {
|
||||
pub function: unsafe extern "C" fn(*mut c_void) -> *mut c_void,
|
||||
pub input: *mut c_void,
|
||||
// without this it's too easy to accidentally drop the closure too soon
|
||||
_lifetime: PhantomData<&'closure mut c_void>,
|
||||
}
|
||||
|
||||
impl<'closure> CCallback<'closure> {
|
||||
pub fn new<F>(closure: &'closure mut F) -> Self
|
||||
where
|
||||
F: FnMut() -> Result,
|
||||
{
|
||||
let function: unsafe extern "C" fn(*mut c_void) -> *mut c_void = Self::call_closure::<F>;
|
||||
|
||||
// debug_assert_eq!(
|
||||
// std::mem::size_of::<&'closure mut F>(),
|
||||
// std::mem::size_of::<*const c_void>()
|
||||
// );
|
||||
// debug_assert_eq!(
|
||||
// std::mem::size_of_val(&function),
|
||||
// std::mem::size_of::<*const c_void>()
|
||||
// );
|
||||
|
||||
Self {
|
||||
function,
|
||||
input: closure as *mut F as *mut c_void,
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn call_closure<F>(input: *mut c_void) -> *mut c_void
|
||||
where
|
||||
F: FnMut() -> Result,
|
||||
{
|
||||
let cb: &mut F = input.cast::<F>().as_mut().unwrap();
|
||||
let v = (*cb)();
|
||||
permit_alloc(|| {
|
||||
let v_box = Box::new(v);
|
||||
let v_ptr = Box::into_raw(v_box);
|
||||
v_ptr as *mut c_void
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_with_guard<F: FnMut() -> Result>(
|
||||
stack_pp: *const *const u64,
|
||||
alloc_pp: *const *const u64,
|
||||
closure: &mut F,
|
||||
) -> Result {
|
||||
let cb = CCallback::new(closure);
|
||||
let mut ret_p: *mut c_void = std::ptr::null_mut();
|
||||
let ret_pp = &mut ret_p as *mut *mut c_void;
|
||||
|
||||
unsafe {
|
||||
let res = guard(
|
||||
Some(cb.function as unsafe extern "C" fn(*mut c_void) -> *mut c_void),
|
||||
cb.input,
|
||||
stack_pp as *const usize,
|
||||
alloc_pp as *const usize,
|
||||
ret_pp,
|
||||
);
|
||||
|
||||
// eprintln!("\r BEFORE:");
|
||||
// eprintln!("\r ret = {:?}", ret);
|
||||
// eprintln!("\r ret_p = {:p}, {:?}", ret_p as *mut Result, *(ret_p as *mut Result));
|
||||
// eprintln!("\r ret_pp = {:p}, {:p}, {:?}", ret_pp, *ret_pp, **(ret_pp as *mut *mut Result));
|
||||
if res == 0 {
|
||||
// TODO: come back to this
|
||||
permit_alloc(|| {
|
||||
let result_box = Box::from_raw(ret_p as *mut Result);
|
||||
*result_box
|
||||
})
|
||||
} else {
|
||||
let err = GuardError::from(u32::try_from(res).unwrap());
|
||||
match err {
|
||||
GuardError::OutOfMemory => Err(Error::NonDeterministic(Mote::Meme, D(0))),
|
||||
_ => {
|
||||
panic!("serf: guard: unexpected error {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
use crate::assert_acyclic;
|
||||
use crate::assert_no_forwarding_pointers;
|
||||
use crate::assert_no_junior_pointers;
|
||||
use crate::guard::call_with_guard;
|
||||
use crate::hamt::Hamt;
|
||||
use crate::jets::cold;
|
||||
use crate::jets::cold::Cold;
|
||||
@ -15,13 +16,10 @@ use crate::noun::{Atom, Cell, IndirectAtom, Noun, Slots, D, T};
|
||||
use crate::serf::TERMINATOR;
|
||||
use crate::trace::{write_nock_trace, TraceInfo, TraceStack};
|
||||
use crate::unifying_equality::unifying_equality;
|
||||
use ares_guard::*;
|
||||
use ares_macros::tas;
|
||||
use assert_no_alloc::{assert_no_alloc, ensure_alloc_counters, permit_alloc};
|
||||
use assert_no_alloc::{assert_no_alloc, ensure_alloc_counters};
|
||||
use bitvec::prelude::{BitSlice, Lsb0};
|
||||
use either::*;
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi::{c_ulonglong, c_void};
|
||||
use std::result;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
@ -327,26 +325,6 @@ pub enum Error {
|
||||
NonDeterministic(Mote, Noun), // mote, trace
|
||||
}
|
||||
|
||||
pub enum GuardError {
|
||||
GuardSound = GUARD_SOUND as isize,
|
||||
GuardArmor = GUARD_ARMOR as isize,
|
||||
GuardWeird = GUARD_WEIRD as isize,
|
||||
GuardSpent = GUARD_SPENT as isize,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for GuardError {
|
||||
type Error = ();
|
||||
fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
|
||||
match value {
|
||||
GUARD_SOUND => Ok(GuardError::GuardSound),
|
||||
GUARD_ARMOR => Ok(GuardError::GuardArmor),
|
||||
GUARD_WEIRD => Ok(GuardError::GuardWeird),
|
||||
GUARD_SPENT => Ok(GuardError::GuardSpent),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Preserve for Error {
|
||||
unsafe fn preserve(&mut self, stack: &mut NockStack) {
|
||||
match self {
|
||||
@ -382,6 +360,7 @@ impl From<cold::Error> for Error {
|
||||
pub type Result = result::Result<Noun, Error>;
|
||||
|
||||
const BAIL_EXIT: Result = Err(Error::Deterministic(Mote::Exit, D(0)));
|
||||
const BAIL_FAIL: Result = Err(Error::NonDeterministic(Mote::Fail, D(0)));
|
||||
const BAIL_INTR: Result = Err(Error::NonDeterministic(Mote::Intr, D(0)));
|
||||
|
||||
#[allow(unused_variables)]
|
||||
@ -391,166 +370,8 @@ fn debug_assertions(stack: &mut NockStack, noun: Noun) {
|
||||
assert_no_junior_pointers!(stack, noun);
|
||||
}
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// See: https://users.rust-lang.org/t/passing-a-closure-to-an-external-c-ffi-library/100271/2
|
||||
pub struct BoundsCallback<'closure> {
|
||||
pub function: unsafe extern "C" fn(*mut c_void, *mut c_void) -> *const c_ulonglong,
|
||||
pub bounds_data: *mut c_void,
|
||||
|
||||
// without this it's too easy to accidentally drop the closure too soon
|
||||
_lifetime: PhantomData<&'closure mut c_void>,
|
||||
}
|
||||
|
||||
impl<'closure> BoundsCallback<'closure> {
|
||||
pub fn new<F>(closure: &'closure mut F) -> Self
|
||||
where
|
||||
F: FnMut(*mut c_void) -> *const c_ulonglong,
|
||||
{
|
||||
let function: unsafe extern "C" fn(*mut c_void, *mut c_void) -> *const c_ulonglong =
|
||||
Self::call_closure::<F>;
|
||||
|
||||
debug_assert_eq!(
|
||||
std::mem::size_of::<&'closure mut F>(),
|
||||
std::mem::size_of::<*const c_void>()
|
||||
);
|
||||
debug_assert_eq!(
|
||||
std::mem::size_of_val(&function),
|
||||
std::mem::size_of::<*const c_void>()
|
||||
);
|
||||
|
||||
Self {
|
||||
function,
|
||||
bounds_data: closure as *mut F as *mut c_void,
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn call_closure<F>(
|
||||
bounds_data: *mut c_void,
|
||||
context_p: *mut c_void,
|
||||
) -> *const c_ulonglong
|
||||
where
|
||||
F: FnMut(*mut c_void) -> *const c_ulonglong,
|
||||
{
|
||||
let cb: &mut F = bounds_data.cast::<F>().as_mut().unwrap();
|
||||
(*cb)(context_p)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WorkCallback<'closure> {
|
||||
pub function: unsafe extern "C" fn(*mut c_void, *mut c_void) -> *mut c_void,
|
||||
pub user_data: *mut c_void,
|
||||
|
||||
// without this it's too easy to accidentally drop the closure too soon
|
||||
_lifetime: PhantomData<&'closure mut c_void>,
|
||||
}
|
||||
|
||||
impl<'closure> WorkCallback<'closure> {
|
||||
pub fn new<F>(closure: &'closure mut F) -> Self
|
||||
where
|
||||
F: FnMut(*mut c_void) -> Result,
|
||||
{
|
||||
let function: unsafe extern "C" fn(*mut c_void, *mut c_void) -> *mut c_void =
|
||||
Self::call_closure::<F>;
|
||||
|
||||
debug_assert_eq!(
|
||||
std::mem::size_of::<&'closure mut F>(),
|
||||
std::mem::size_of::<*const c_void>()
|
||||
);
|
||||
debug_assert_eq!(
|
||||
std::mem::size_of_val(&function),
|
||||
std::mem::size_of::<*const c_void>()
|
||||
);
|
||||
|
||||
Self {
|
||||
function,
|
||||
user_data: closure as *mut F as *mut c_void,
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn call_closure<F>(
|
||||
user_data: *mut c_void,
|
||||
context_p: *mut c_void,
|
||||
) -> *mut c_void
|
||||
where
|
||||
F: FnMut(*mut c_void) -> Result,
|
||||
{
|
||||
let cb: &mut F = user_data.cast::<F>().as_mut().unwrap();
|
||||
let v = (*cb)(context_p);
|
||||
permit_alloc(|| {
|
||||
let v_box = Box::new(v);
|
||||
let v_ptr = Box::into_raw(v_box);
|
||||
v_ptr as *mut c_void
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_with_guard<
|
||||
F: FnMut(*mut c_void) -> Result,
|
||||
G: FnMut(*mut c_void) -> *const c_ulonglong,
|
||||
H: FnMut(*mut c_void) -> *const c_ulonglong,
|
||||
>(
|
||||
work_f: &mut F,
|
||||
low_f: &mut G,
|
||||
high_f: &mut H,
|
||||
context_p: *mut Context,
|
||||
) -> Result {
|
||||
let work = WorkCallback::new(work_f);
|
||||
let low = BoundsCallback::new(low_f);
|
||||
let high = BoundsCallback::new(high_f);
|
||||
|
||||
let mut ret: Result = Ok(D(0));
|
||||
let ret_p = &mut ret as *mut _ as *mut c_void;
|
||||
let ret_pp = &ret_p as *const *mut c_void;
|
||||
|
||||
unsafe {
|
||||
let guard_error = guard(
|
||||
Some(work.function as unsafe extern "C" fn(*mut c_void, *mut c_void) -> *mut c_void),
|
||||
work.user_data as *mut c_void,
|
||||
Some(
|
||||
low.function
|
||||
as unsafe extern "C" fn(*mut c_void, *mut c_void) -> *const c_ulonglong,
|
||||
),
|
||||
Some(
|
||||
high.function
|
||||
as unsafe extern "C" fn(*mut c_void, *mut c_void) -> *const c_ulonglong,
|
||||
),
|
||||
high.bounds_data as *mut c_void,
|
||||
context_p as *mut c_void,
|
||||
ret_pp,
|
||||
);
|
||||
|
||||
if let Ok(err) = GuardError::try_from(guard_error) {
|
||||
match err {
|
||||
GuardError::GuardSound => {
|
||||
permit_alloc(|| {
|
||||
let result_box = Box::from_raw(ret_p as *mut Result);
|
||||
let result = *result_box;
|
||||
return result;
|
||||
})
|
||||
}
|
||||
GuardError::GuardArmor => {
|
||||
// XX
|
||||
panic!("guard: couldn't place guard page\r\n");
|
||||
}
|
||||
GuardError::GuardWeird => {
|
||||
return Err(Error::Deterministic(Mote::Exit, D(0)));
|
||||
}
|
||||
GuardError::GuardSpent => {
|
||||
return Err(Error::NonDeterministic(Mote::Meme, D(0)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(Error::Deterministic(Mote::Exit, D(0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Interpret nock */
|
||||
pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Result {
|
||||
// print the addresses of the context.stack.stack_pointer and context.stack.alloc_pointer
|
||||
let terminator = Arc::clone(&TERMINATOR);
|
||||
let orig_subject = subject; // for debugging
|
||||
let snapshot = context.save();
|
||||
@ -559,31 +380,14 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
|
||||
// Setup stack for Nock computation
|
||||
unsafe {
|
||||
(*context).stack.frame_push(2);
|
||||
context.stack.frame_push(2);
|
||||
|
||||
// Bottom of mean stack
|
||||
*((*context).stack.local_noun_pointer(0)) = D(0);
|
||||
*(context.stack.local_noun_pointer(0)) = D(0);
|
||||
// Bottom of trace stack
|
||||
*((*context).stack.local_noun_pointer(1) as *mut *const TraceStack) = std::ptr::null();
|
||||
*(context.stack.local_noun_pointer(1) as *mut *const TraceStack) = std::ptr::null();
|
||||
|
||||
*((*context).stack.push()) = NockWork::Done;
|
||||
};
|
||||
|
||||
let low_f = &mut |context_p: *mut c_void| {
|
||||
let bounds_ctx = unsafe { &mut *(context_p as *mut Context) };
|
||||
if bounds_ctx.stack.is_west() {
|
||||
bounds_ctx.stack.get_stack_pointer() as *const c_ulonglong
|
||||
} else {
|
||||
bounds_ctx.stack.get_alloc_pointer() as *const c_ulonglong
|
||||
}
|
||||
};
|
||||
let high_f = &mut |context_p: *mut c_void| {
|
||||
let bounds_ctx = unsafe { &mut *(context_p as *mut Context) };
|
||||
if bounds_ctx.stack.is_west() {
|
||||
bounds_ctx.stack.get_alloc_pointer() as *const c_ulonglong
|
||||
} else {
|
||||
bounds_ctx.stack.get_stack_pointer() as *const c_ulonglong
|
||||
}
|
||||
*(context.stack.push()) = NockWork::Done;
|
||||
};
|
||||
|
||||
// DO NOT REMOVE THIS ASSERTION
|
||||
@ -599,23 +403,25 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
// (See https://docs.rs/assert_no_alloc/latest/assert_no_alloc/#advanced-use)
|
||||
let nock = assert_no_alloc(|| {
|
||||
ensure_alloc_counters(|| {
|
||||
let work_f = &mut |context_p: *mut c_void| unsafe {
|
||||
let work_ctx = &mut *(context_p as *mut Context);
|
||||
push_formula(&mut work_ctx.stack, formula, true)?;
|
||||
let stack_pp = context.stack.get_stack_pointer_pointer() as *const *const u64;
|
||||
let alloc_pp = context.stack.get_alloc_pointer_pointer() as *const *const u64;
|
||||
let work_f = &mut || unsafe {
|
||||
push_formula(&mut context.stack, formula, true)?;
|
||||
|
||||
loop {
|
||||
let work: NockWork = *work_ctx.stack.top();
|
||||
let work: NockWork = *context.stack.top();
|
||||
match work {
|
||||
NockWork::Done => {
|
||||
write_trace(work_ctx);
|
||||
write_trace(context);
|
||||
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
debug_assertions(stack, orig_subject);
|
||||
debug_assertions(stack, subject);
|
||||
debug_assertions(stack, res);
|
||||
|
||||
stack.preserve(&mut work_ctx.cache);
|
||||
stack.preserve(&mut work_ctx.cold);
|
||||
stack.preserve(&mut work_ctx.warm);
|
||||
stack.preserve(&mut context.cache);
|
||||
stack.preserve(&mut context.cold);
|
||||
stack.preserve(&mut context.warm);
|
||||
stack.preserve(&mut res);
|
||||
stack.frame_pop();
|
||||
|
||||
@ -625,16 +431,16 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
break Ok(res);
|
||||
}
|
||||
NockWork::Ret => {
|
||||
write_trace(work_ctx);
|
||||
write_trace(context);
|
||||
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
debug_assertions(stack, orig_subject);
|
||||
debug_assertions(stack, subject);
|
||||
debug_assertions(stack, res);
|
||||
|
||||
stack.preserve(&mut work_ctx.cache);
|
||||
stack.preserve(&mut work_ctx.cold);
|
||||
stack.preserve(&mut work_ctx.warm);
|
||||
stack.preserve(&mut context.cache);
|
||||
stack.preserve(&mut context.cold);
|
||||
stack.preserve(&mut context.warm);
|
||||
stack.preserve(&mut res);
|
||||
stack.frame_pop();
|
||||
|
||||
@ -644,17 +450,17 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
NockWork::WorkCons(mut cons) => match cons.todo {
|
||||
TodoCons::ComputeHead => {
|
||||
cons.todo = TodoCons::ComputeTail;
|
||||
*work_ctx.stack.top() = NockWork::WorkCons(cons);
|
||||
push_formula(&mut work_ctx.stack, cons.head, false)?;
|
||||
*context.stack.top() = NockWork::WorkCons(cons);
|
||||
push_formula(&mut context.stack, cons.head, false)?;
|
||||
}
|
||||
TodoCons::ComputeTail => {
|
||||
cons.todo = TodoCons::Cons;
|
||||
cons.head = res;
|
||||
*work_ctx.stack.top() = NockWork::WorkCons(cons);
|
||||
push_formula(&mut work_ctx.stack, cons.tail, false)?;
|
||||
*context.stack.top() = NockWork::WorkCons(cons);
|
||||
push_formula(&mut context.stack, cons.tail, false)?;
|
||||
}
|
||||
TodoCons::Cons => {
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
res = T(stack, &[cons.head, res]);
|
||||
stack.pop::<NockWork>();
|
||||
}
|
||||
@ -662,7 +468,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
NockWork::Work0(zero) => {
|
||||
if let Ok(noun) = subject.slot_atom(zero.axis) {
|
||||
res = noun;
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
} else {
|
||||
// Axis invalid for input Noun
|
||||
break BAIL_EXIT;
|
||||
@ -670,27 +476,27 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
}
|
||||
NockWork::Work1(once) => {
|
||||
res = once.noun;
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
}
|
||||
NockWork::Work2(mut vale) => {
|
||||
if (*terminator).load(Ordering::Relaxed) {
|
||||
break Err(Error::NonDeterministic(Mote::Intr, D(0)));
|
||||
break BAIL_INTR;
|
||||
}
|
||||
|
||||
match vale.todo {
|
||||
Todo2::ComputeSubject => {
|
||||
vale.todo = Todo2::ComputeFormula;
|
||||
*work_ctx.stack.top() = NockWork::Work2(vale);
|
||||
push_formula(&mut work_ctx.stack, vale.subject, false)?;
|
||||
*context.stack.top() = NockWork::Work2(vale);
|
||||
push_formula(&mut context.stack, vale.subject, false)?;
|
||||
}
|
||||
Todo2::ComputeFormula => {
|
||||
vale.todo = Todo2::ComputeResult;
|
||||
vale.subject = res;
|
||||
*work_ctx.stack.top() = NockWork::Work2(vale);
|
||||
push_formula(&mut work_ctx.stack, vale.formula, false)?;
|
||||
*context.stack.top() = NockWork::Work2(vale);
|
||||
push_formula(&mut context.stack, vale.formula, false)?;
|
||||
}
|
||||
Todo2::ComputeResult => {
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
if vale.tail {
|
||||
stack.pop::<NockWork>();
|
||||
subject = vale.subject;
|
||||
@ -710,7 +516,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
}
|
||||
}
|
||||
Todo2::RestoreSubject => {
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
|
||||
subject = vale.subject;
|
||||
stack.pop::<NockWork>();
|
||||
@ -724,24 +530,24 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
NockWork::Work3(mut thee) => match thee.todo {
|
||||
Todo3::ComputeChild => {
|
||||
thee.todo = Todo3::ComputeType;
|
||||
*work_ctx.stack.top() = NockWork::Work3(thee);
|
||||
push_formula(&mut work_ctx.stack, thee.child, false)?;
|
||||
*context.stack.top() = NockWork::Work3(thee);
|
||||
push_formula(&mut context.stack, thee.child, false)?;
|
||||
}
|
||||
Todo3::ComputeType => {
|
||||
res = if res.is_cell() { D(0) } else { D(1) };
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
}
|
||||
},
|
||||
NockWork::Work4(mut four) => match four.todo {
|
||||
Todo4::ComputeChild => {
|
||||
four.todo = Todo4::Increment;
|
||||
*work_ctx.stack.top() = NockWork::Work4(four);
|
||||
push_formula(&mut work_ctx.stack, four.child, false)?;
|
||||
*context.stack.top() = NockWork::Work4(four);
|
||||
push_formula(&mut context.stack, four.child, false)?;
|
||||
}
|
||||
Todo4::Increment => {
|
||||
if let Ok(atom) = res.as_atom() {
|
||||
res = inc(&mut work_ctx.stack, atom).as_noun();
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
res = inc(&mut context.stack, atom).as_noun();
|
||||
context.stack.pop::<NockWork>();
|
||||
} else {
|
||||
// Cannot increment (Nock 4) a cell
|
||||
break BAIL_EXIT;
|
||||
@ -751,17 +557,17 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
NockWork::Work5(mut five) => match five.todo {
|
||||
Todo5::ComputeLeftChild => {
|
||||
five.todo = Todo5::ComputeRightChild;
|
||||
*work_ctx.stack.top() = NockWork::Work5(five);
|
||||
push_formula(&mut work_ctx.stack, five.left, false)?;
|
||||
*context.stack.top() = NockWork::Work5(five);
|
||||
push_formula(&mut context.stack, five.left, false)?;
|
||||
}
|
||||
Todo5::ComputeRightChild => {
|
||||
five.todo = Todo5::TestEquals;
|
||||
five.left = res;
|
||||
*work_ctx.stack.top() = NockWork::Work5(five);
|
||||
push_formula(&mut work_ctx.stack, five.right, false)?;
|
||||
*context.stack.top() = NockWork::Work5(five);
|
||||
push_formula(&mut context.stack, five.right, false)?;
|
||||
}
|
||||
Todo5::TestEquals => {
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
let saved_value_ptr = &mut five.left;
|
||||
res = if unifying_equality(stack, &mut res, saved_value_ptr) {
|
||||
D(0)
|
||||
@ -774,11 +580,11 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
NockWork::Work6(mut cond) => match cond.todo {
|
||||
Todo6::ComputeTest => {
|
||||
cond.todo = Todo6::ComputeBranch;
|
||||
*work_ctx.stack.top() = NockWork::Work6(cond);
|
||||
push_formula(&mut work_ctx.stack, cond.test, false)?;
|
||||
*context.stack.top() = NockWork::Work6(cond);
|
||||
push_formula(&mut context.stack, cond.test, false)?;
|
||||
}
|
||||
Todo6::ComputeBranch => {
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
stack.pop::<NockWork>();
|
||||
if let Left(direct) = res.as_either_direct_allocated() {
|
||||
if direct.data() == 0 {
|
||||
@ -798,11 +604,11 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
NockWork::Work7(mut pose) => match pose.todo {
|
||||
Todo7::ComputeSubject => {
|
||||
pose.todo = Todo7::ComputeResult;
|
||||
*work_ctx.stack.top() = NockWork::Work7(pose);
|
||||
push_formula(&mut work_ctx.stack, pose.subject, false)?;
|
||||
*context.stack.top() = NockWork::Work7(pose);
|
||||
push_formula(&mut context.stack, pose.subject, false)?;
|
||||
}
|
||||
Todo7::ComputeResult => {
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
if pose.tail {
|
||||
stack.pop::<NockWork>();
|
||||
subject = res;
|
||||
@ -817,17 +623,17 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
}
|
||||
Todo7::RestoreSubject => {
|
||||
subject = pose.subject;
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
}
|
||||
},
|
||||
NockWork::Work8(mut pins) => match pins.todo {
|
||||
Todo8::ComputeSubject => {
|
||||
pins.todo = Todo8::ComputeResult;
|
||||
*work_ctx.stack.top() = NockWork::Work8(pins);
|
||||
push_formula(&mut work_ctx.stack, pins.pin, false)?;
|
||||
*context.stack.top() = NockWork::Work8(pins);
|
||||
push_formula(&mut context.stack, pins.pin, false)?;
|
||||
}
|
||||
Todo8::ComputeResult => {
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
if pins.tail {
|
||||
subject = T(stack, &[res, subject]);
|
||||
stack.pop::<NockWork>();
|
||||
@ -842,32 +648,32 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
}
|
||||
Todo8::RestoreSubject => {
|
||||
subject = pins.pin;
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
}
|
||||
},
|
||||
NockWork::Work9(mut kale) => {
|
||||
if (*terminator).load(Ordering::Relaxed) {
|
||||
break Err(Error::NonDeterministic(Mote::Intr, D(0)));
|
||||
break BAIL_INTR;
|
||||
}
|
||||
|
||||
match kale.todo {
|
||||
Todo9::ComputeCore => {
|
||||
kale.todo = Todo9::ComputeResult;
|
||||
*work_ctx.stack.top() = NockWork::Work9(kale);
|
||||
push_formula(&mut work_ctx.stack, kale.core, false)?;
|
||||
*context.stack.top() = NockWork::Work9(kale);
|
||||
push_formula(&mut context.stack, kale.core, false)?;
|
||||
}
|
||||
Todo9::ComputeResult => {
|
||||
if let Ok(mut formula) = res.slot_atom(kale.axis) {
|
||||
if !cfg!(feature = "sham_hints") {
|
||||
if let Some((jet, _path)) = work_ctx.warm.find_jet(
|
||||
&mut work_ctx.stack,
|
||||
if let Some((jet, _path)) = context.warm.find_jet(
|
||||
&mut context.stack,
|
||||
&mut res,
|
||||
&mut formula,
|
||||
) {
|
||||
match jet(work_ctx, res) {
|
||||
match jet(context, res) {
|
||||
Ok(jet_res) => {
|
||||
res = jet_res;
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
continue;
|
||||
}
|
||||
Err(JetErr::Punt) => {}
|
||||
@ -878,16 +684,16 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
}
|
||||
};
|
||||
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
if kale.tail {
|
||||
stack.pop::<NockWork>();
|
||||
|
||||
// We could trace on 2 as well, but 2 only comes from Hoon via
|
||||
// '.*', so we can assume it's never directly used to invoke
|
||||
// jetted code.
|
||||
if work_ctx.trace_info.is_some() {
|
||||
if context.trace_info.is_some() {
|
||||
if let Some(path) =
|
||||
work_ctx.cold.matches(stack, &mut res)
|
||||
context.cold.matches(stack, &mut res)
|
||||
{
|
||||
append_trace(stack, path);
|
||||
};
|
||||
@ -912,9 +718,9 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
// We could trace on 2 as well, but 2 only comes from Hoon via
|
||||
// '.*', so we can assume it's never directly used to invoke
|
||||
// jetted code.
|
||||
if work_ctx.trace_info.is_some() {
|
||||
if context.trace_info.is_some() {
|
||||
if let Some(path) =
|
||||
work_ctx.cold.matches(stack, &mut res)
|
||||
context.cold.matches(stack, &mut res)
|
||||
{
|
||||
append_trace(stack, path);
|
||||
};
|
||||
@ -926,7 +732,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
}
|
||||
}
|
||||
Todo9::RestoreSubject => {
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
|
||||
subject = kale.core;
|
||||
stack.pop::<NockWork>();
|
||||
@ -941,35 +747,35 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
match diet.todo {
|
||||
Todo10::ComputeTree => {
|
||||
diet.todo = Todo10::ComputePatch; // should we compute patch then tree?
|
||||
*work_ctx.stack.top() = NockWork::Work10(diet);
|
||||
push_formula(&mut work_ctx.stack, diet.tree, false)?;
|
||||
*context.stack.top() = NockWork::Work10(diet);
|
||||
push_formula(&mut context.stack, diet.tree, false)?;
|
||||
}
|
||||
Todo10::ComputePatch => {
|
||||
diet.todo = Todo10::Edit;
|
||||
diet.tree = res;
|
||||
*work_ctx.stack.top() = NockWork::Work10(diet);
|
||||
push_formula(&mut work_ctx.stack, diet.patch, false)?;
|
||||
*context.stack.top() = NockWork::Work10(diet);
|
||||
push_formula(&mut context.stack, diet.patch, false)?;
|
||||
}
|
||||
Todo10::Edit => {
|
||||
res = edit(
|
||||
&mut work_ctx.stack,
|
||||
&mut context.stack,
|
||||
diet.axis.as_bitslice(),
|
||||
res,
|
||||
diet.tree,
|
||||
);
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
}
|
||||
}
|
||||
}
|
||||
NockWork::Work11D(mut dint) => match dint.todo {
|
||||
Todo11D::ComputeHint => {
|
||||
if let Some(ret) = hint::match_pre_hint(
|
||||
work_ctx, subject, dint.tag, dint.hint, dint.body,
|
||||
context, subject, dint.tag, dint.hint, dint.body,
|
||||
) {
|
||||
match ret {
|
||||
Ok(found) => {
|
||||
res = found;
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
}
|
||||
Err(err) => {
|
||||
break Err(err);
|
||||
@ -977,13 +783,13 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
}
|
||||
} else {
|
||||
dint.todo = Todo11D::ComputeResult;
|
||||
*work_ctx.stack.top() = NockWork::Work11D(dint);
|
||||
push_formula(&mut work_ctx.stack, dint.hint, false)?;
|
||||
*context.stack.top() = NockWork::Work11D(dint);
|
||||
push_formula(&mut context.stack, dint.hint, false)?;
|
||||
}
|
||||
}
|
||||
Todo11D::ComputeResult => {
|
||||
if let Some(ret) = hint::match_pre_nock(
|
||||
work_ctx,
|
||||
context,
|
||||
subject,
|
||||
dint.tag,
|
||||
Some((dint.hint, res)),
|
||||
@ -992,7 +798,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
match ret {
|
||||
Ok(found) => {
|
||||
res = found;
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
}
|
||||
Err(err) => {
|
||||
break Err(err);
|
||||
@ -1000,18 +806,18 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
}
|
||||
} else {
|
||||
if dint.tail {
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
} else {
|
||||
dint.todo = Todo11D::Done;
|
||||
dint.hint = res;
|
||||
*work_ctx.stack.top() = NockWork::Work11D(dint);
|
||||
*context.stack.top() = NockWork::Work11D(dint);
|
||||
}
|
||||
push_formula(&mut work_ctx.stack, dint.body, dint.tail)?;
|
||||
push_formula(&mut context.stack, dint.body, dint.tail)?;
|
||||
}
|
||||
}
|
||||
Todo11D::Done => {
|
||||
if let Some(found) = hint::match_post_nock(
|
||||
work_ctx,
|
||||
context,
|
||||
subject,
|
||||
dint.tag,
|
||||
Some(dint.hint),
|
||||
@ -1020,18 +826,18 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
) {
|
||||
res = found;
|
||||
}
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
}
|
||||
},
|
||||
NockWork::Work11S(mut sint) => match sint.todo {
|
||||
Todo11S::ComputeResult => {
|
||||
if let Some(ret) = hint::match_pre_nock(
|
||||
work_ctx, subject, sint.tag, None, sint.body,
|
||||
context, subject, sint.tag, None, sint.body,
|
||||
) {
|
||||
match ret {
|
||||
Ok(found) => {
|
||||
res = found;
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
}
|
||||
Err(err) => {
|
||||
break Err(err);
|
||||
@ -1039,46 +845,46 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
}
|
||||
} else {
|
||||
if sint.tail {
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
} else {
|
||||
sint.todo = Todo11S::Done;
|
||||
*work_ctx.stack.top() = NockWork::Work11S(sint);
|
||||
*context.stack.top() = NockWork::Work11S(sint);
|
||||
}
|
||||
push_formula(&mut work_ctx.stack, sint.body, sint.tail)?;
|
||||
push_formula(&mut context.stack, sint.body, sint.tail)?;
|
||||
}
|
||||
}
|
||||
Todo11S::Done => {
|
||||
if let Some(found) = hint::match_post_nock(
|
||||
work_ctx, subject, sint.tag, None, sint.body, res,
|
||||
context, subject, sint.tag, None, sint.body, res,
|
||||
) {
|
||||
res = found;
|
||||
}
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.stack.pop::<NockWork>();
|
||||
}
|
||||
},
|
||||
NockWork::Work12(mut scry) => match scry.todo {
|
||||
Todo12::ComputeReff => {
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
scry.todo = Todo12::ComputePath;
|
||||
*stack.top() = NockWork::Work12(scry);
|
||||
push_formula(stack, scry.reff, false)?;
|
||||
}
|
||||
Todo12::ComputePath => {
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
scry.todo = Todo12::Scry;
|
||||
scry.reff = res;
|
||||
*stack.top() = NockWork::Work12(scry);
|
||||
push_formula(stack, scry.path, false)?;
|
||||
}
|
||||
Todo12::Scry => {
|
||||
if let Some(cell) = work_ctx.scry_stack.cell() {
|
||||
if let Some(cell) = context.scry_stack.cell() {
|
||||
scry.path = res;
|
||||
let scry_stack = work_ctx.scry_stack;
|
||||
let scry_stack = context.scry_stack;
|
||||
let scry_handler = cell.head();
|
||||
let scry_gate = scry_handler.as_cell()?;
|
||||
let payload = T(&mut work_ctx.stack, &[scry.reff, res]);
|
||||
let payload = T(&mut context.stack, &[scry.reff, res]);
|
||||
let scry_core = T(
|
||||
&mut work_ctx.stack,
|
||||
&mut context.stack,
|
||||
&[
|
||||
scry_gate.head(),
|
||||
payload,
|
||||
@ -1086,13 +892,13 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
],
|
||||
);
|
||||
let scry_form =
|
||||
T(&mut work_ctx.stack, &[D(9), D(2), D(1), scry_core]);
|
||||
T(&mut context.stack, &[D(9), D(2), D(1), scry_core]);
|
||||
|
||||
work_ctx.scry_stack = cell.tail();
|
||||
context.scry_stack = cell.tail();
|
||||
// Alternately, we could use scry_core as the subject and [9 2 0 1] as
|
||||
// the formula. It's unclear if performance will be better with a purely
|
||||
// static formula.
|
||||
match interpret(work_ctx, D(0), scry_form) {
|
||||
match interpret(context, D(0), scry_form) {
|
||||
Ok(noun) => match noun.as_either_atom_cell() {
|
||||
Left(atom) => {
|
||||
if atom.as_noun().raw_equals(D(0)) {
|
||||
@ -1104,7 +910,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
Right(cell) => {
|
||||
match cell.tail().as_either_atom_cell() {
|
||||
Left(_) => {
|
||||
let stack = &mut work_ctx.stack;
|
||||
let stack = &mut context.stack;
|
||||
let hunk = T(
|
||||
stack,
|
||||
&[
|
||||
@ -1118,8 +924,8 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
}
|
||||
Right(cell) => {
|
||||
res = cell.tail();
|
||||
work_ctx.scry_stack = scry_stack;
|
||||
work_ctx.stack.pop::<NockWork>();
|
||||
context.scry_stack = scry_stack;
|
||||
context.stack.pop::<NockWork>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1133,10 +939,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
break Err(error);
|
||||
}
|
||||
Error::ScryBlocked(_) => {
|
||||
break Err(Error::NonDeterministic(
|
||||
Mote::Fail,
|
||||
D(0),
|
||||
));
|
||||
break BAIL_FAIL;
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -1149,18 +952,15 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
||||
};
|
||||
}
|
||||
};
|
||||
call_with_guard(work_f, low_f, high_f, context as *mut Context)
|
||||
|
||||
call_with_guard(stack_pp, alloc_pp, work_f)
|
||||
})
|
||||
});
|
||||
|
||||
let match_f = &mut |context_p: *mut c_void| unsafe {
|
||||
let match_ctx = &mut *(context_p as *mut Context);
|
||||
match nock {
|
||||
Ok(res) => Ok(res),
|
||||
Err(err) => Err(exit(match_ctx, &snapshot, virtual_frame, err)),
|
||||
Err(err) => Err(exit(context, &snapshot, virtual_frame, err)),
|
||||
}
|
||||
};
|
||||
call_with_guard(match_f, low_f, high_f, context as *mut Context)
|
||||
}
|
||||
|
||||
fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result {
|
||||
|
@ -3,6 +3,7 @@ extern crate num_derive;
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate static_assertions;
|
||||
pub mod guard;
|
||||
pub mod hamt;
|
||||
pub mod interpreter;
|
||||
pub mod jets;
|
||||
|
@ -147,19 +147,19 @@ impl NockStack {
|
||||
self.stack_pointer
|
||||
}
|
||||
|
||||
/** Current stack pointer's address */
|
||||
pub fn get_stack_pointer_pointer(&self) -> *const *mut u64 {
|
||||
&self.stack_pointer as *const *mut u64
|
||||
}
|
||||
|
||||
/** Current alloc pointer of this NockStack */
|
||||
pub fn get_alloc_pointer(&self) -> *const u64 {
|
||||
self.alloc_pointer
|
||||
}
|
||||
|
||||
/** Current alloc pointer's address */
|
||||
/** Current stack pointer of this NockStack */
|
||||
pub fn get_stack_pointer_pointer(&self) -> *const *mut u64 {
|
||||
&self.stack_pointer
|
||||
}
|
||||
|
||||
/** Current alloc pointer of this NockStack */
|
||||
pub fn get_alloc_pointer_pointer(&self) -> *const *mut u64 {
|
||||
&self.alloc_pointer as *const *mut u64
|
||||
&self.alloc_pointer
|
||||
}
|
||||
|
||||
/** Start of the memory range for this NockStack */
|
||||
@ -288,14 +288,8 @@ impl NockStack {
|
||||
if self.pc {
|
||||
panic!("Allocation during cleanup phase is prohibited.");
|
||||
}
|
||||
|
||||
let alloc = self.alloc_pointer.sub(words);
|
||||
if alloc < self.stack_pointer {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
self.alloc_pointer = alloc;
|
||||
alloc
|
||||
}
|
||||
self.alloc_pointer = self.alloc_pointer.sub(words);
|
||||
self.alloc_pointer
|
||||
}
|
||||
|
||||
/** Bump the alloc pointer for an east frame to make space for an allocation */
|
||||
@ -303,16 +297,10 @@ impl NockStack {
|
||||
if self.pc {
|
||||
panic!("Allocation during cleanup phase is prohibited.");
|
||||
}
|
||||
|
||||
let alloc = self.alloc_pointer;
|
||||
let new_ap = self.alloc_pointer.add(words);
|
||||
if new_ap > self.stack_pointer {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
self.alloc_pointer = new_ap;
|
||||
self.alloc_pointer = self.alloc_pointer.add(words);
|
||||
alloc
|
||||
}
|
||||
}
|
||||
|
||||
/** Allocate space for an indirect pointer in a west frame */
|
||||
unsafe fn indirect_alloc_west(&mut self, words: usize) -> *mut u64 {
|
||||
@ -355,24 +343,14 @@ impl NockStack {
|
||||
unsafe fn raw_alloc_in_previous_frame_west(&mut self, words: usize) -> *mut u64 {
|
||||
// note that the allocation is on the east frame, and thus resembles raw_alloc_east
|
||||
let alloc = *self.prev_alloc_pointer_pointer();
|
||||
let new_prev_ap = (*(self.prev_alloc_pointer_pointer())).add(words);
|
||||
if new_prev_ap > self.stack_pointer {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
*(self.prev_alloc_pointer_pointer()) = new_prev_ap;
|
||||
*(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).add(words);
|
||||
alloc
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn raw_alloc_in_previous_frame_east(&mut self, words: usize) -> *mut u64 {
|
||||
// note that the allocation is on the west frame, and thus resembles raw_alloc_west
|
||||
let alloc = (*(self.prev_alloc_pointer_pointer())).sub(words);
|
||||
if alloc < self.stack_pointer {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
*(self.prev_alloc_pointer_pointer()) = alloc;
|
||||
alloc
|
||||
}
|
||||
*(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).sub(words);
|
||||
*(self.prev_alloc_pointer_pointer())
|
||||
}
|
||||
|
||||
/** Allocate space in the previous stack frame. This calls pre_copy() first to ensure that the
|
||||
@ -437,27 +415,16 @@ impl NockStack {
|
||||
* or not pre_copy() has been called.*/
|
||||
unsafe fn pre_copy(&mut self) {
|
||||
if !self.pc {
|
||||
let old_stack_pointer = self.stack_pointer;
|
||||
|
||||
// Change polarity of lightweight stack.
|
||||
if self.is_west() {
|
||||
self.stack_pointer = self.alloc_pointer.sub(RESERVED + 1);
|
||||
if self.stack_pointer < old_stack_pointer {
|
||||
// OOM
|
||||
std::ptr::null::<usize>().read_volatile();
|
||||
}
|
||||
} else {
|
||||
self.stack_pointer = self.alloc_pointer.add(RESERVED);
|
||||
if self.stack_pointer > old_stack_pointer {
|
||||
// OOM
|
||||
std::ptr::null::<usize>().read_volatile();
|
||||
}
|
||||
}
|
||||
self.pc = true;
|
||||
|
||||
*(self.free_slot(FRAME)) = *(self.slot_pointer(FRAME));
|
||||
*(self.free_slot(STACK)) = *(self.slot_pointer(STACK));
|
||||
*(self.free_slot(ALLOC)) = *(self.slot_pointer(ALLOC));
|
||||
self.pc = true;
|
||||
// Change polarity of lightweight stack.
|
||||
if self.is_west() {
|
||||
self.stack_pointer = self.alloc_pointer.sub(RESERVED + 1);
|
||||
} else {
|
||||
self.stack_pointer = self.alloc_pointer.add(RESERVED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -662,22 +629,13 @@ impl NockStack {
|
||||
let current_stack_pointer = self.stack_pointer;
|
||||
let current_alloc_pointer = self.alloc_pointer;
|
||||
unsafe {
|
||||
if self.is_west() {
|
||||
self.frame_pointer = current_alloc_pointer.sub(num_locals + RESERVED);
|
||||
if self.frame_pointer <= current_stack_pointer {
|
||||
// OOM
|
||||
std::ptr::null::<usize>().read_volatile();
|
||||
}
|
||||
self.frame_pointer = if self.is_west() {
|
||||
current_alloc_pointer.sub(num_locals + RESERVED)
|
||||
} else {
|
||||
self.frame_pointer = current_alloc_pointer.add(num_locals + RESERVED);
|
||||
if self.frame_pointer >= current_stack_pointer {
|
||||
// OOM
|
||||
std::ptr::null::<usize>().read_volatile();
|
||||
}
|
||||
}
|
||||
current_alloc_pointer.add(num_locals + RESERVED)
|
||||
};
|
||||
self.alloc_pointer = current_stack_pointer;
|
||||
self.stack_pointer = self.frame_pointer;
|
||||
|
||||
*(self.slot_pointer(FRAME)) = current_frame_pointer as u64;
|
||||
*(self.slot_pointer(STACK)) = current_stack_pointer as u64;
|
||||
*(self.slot_pointer(ALLOC)) = current_alloc_pointer as u64;
|
||||
|
@ -143,7 +143,7 @@ impl Context {
|
||||
snapshot: Option<Snapshot>,
|
||||
constant_hot_state: &[HotEntry],
|
||||
) -> Self {
|
||||
let mut stack = NockStack::new(4096 << 10 << 10, 0);
|
||||
let mut stack = NockStack::new(2048 << 10 << 10, 0);
|
||||
let newt = Newt::new();
|
||||
let cache = Hamt::<Noun>::new(&mut stack);
|
||||
|
||||
@ -401,6 +401,7 @@ fn slam(context: &mut Context, axis: u64, ovo: Noun) -> Result<Noun, Error> {
|
||||
let sam = T(stack, &[D(6), D(0), D(7)]);
|
||||
let fol = T(stack, &[D(8), pul, D(9), D(2), D(10), sam, D(0), D(2)]);
|
||||
let sub = T(stack, &[arvo, ovo]);
|
||||
|
||||
interpret(&mut context.nock_context, sub, fol)
|
||||
}
|
||||
|
||||
@ -604,17 +605,13 @@ fn work_swap(context: &mut Context, job: Noun, goof: Noun) {
|
||||
context.work_swap(ovo, fec);
|
||||
}
|
||||
Err(goof_crud) => {
|
||||
work_bail(context, &[goof_crud, goof]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn work_bail(context: &mut Context, goofs: &[Noun]) {
|
||||
eprintln!("\r serf: bail");
|
||||
let stack = &mut context.nock_context.stack;
|
||||
let lest = T(stack, goofs);
|
||||
let lud = T(stack, &[lest, D(0)]);
|
||||
let lud = T(stack, &[goof_crud, goof, D(0)]);
|
||||
context.work_bail(lud);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn work_trace_name(stack: &mut NockStack, wire: Noun, vent: Atom) -> String {
|
||||
let wpc = path_to_cord(stack, wire);
|
||||
|
11
rust/ares_crypto/Cargo.lock
generated
11
rust/ares_crypto/Cargo.lock
generated
@ -61,7 +61,6 @@ dependencies = [
|
||||
"rand",
|
||||
"sha1",
|
||||
"sha2",
|
||||
"urcrypt-sys",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
@ -611,16 +610,6 @@ version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "urcrypt-sys"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced751f95a527a3458eb67c75e4ae7093d41585edaa7565f5769101502473019"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
@ -6,9 +6,9 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
assert_no_alloc = { path = "../rust-assert-no-alloc" }
|
||||
# use this when debugging requires allocation (e.g. eprintln)
|
||||
# assert_no_alloc = { path = "../rust-assert-no-alloc", features=["warn_debug"] }
|
||||
assert_no_alloc = { path = "../rust-assert-no-alloc" }
|
||||
ibig = "0.3.6"
|
||||
|
||||
# ed25519
|
||||
@ -25,13 +25,14 @@ sha1 = { version = "0.10.6", default-features = false, optional = true }
|
||||
sha2 = { version = "0.10.8", default-features = false, optional = true }
|
||||
|
||||
# test_vs_urcrypt
|
||||
# XX: can be removed once stable
|
||||
rand = { version = "0.8.4", default-features = false, features = ["getrandom"], optional = true }
|
||||
urcrypt-sys = { version = "0.1.1", optional = true }
|
||||
|
||||
[features]
|
||||
# XX turn off test_vs_urcrypt after development
|
||||
default = ["aes_siv", "ed25519", "sha"]
|
||||
aes_siv = ["aes", "aes-siv"]
|
||||
ed25519 = ["curve25519-dalek", "ed25519-dalek", "x25519-dalek"]
|
||||
sha = ["sha1", "sha2"]
|
||||
# XX: can be removed once stable
|
||||
test_vs_urcrypt = ["urcrypt-sys", "rand"]
|
||||
|
@ -8,8 +8,5 @@ edition = "2021"
|
||||
[dependencies]
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = "0.69.1"
|
||||
bindgen = "0.69"
|
||||
cc = "1.0"
|
||||
|
||||
[provile.dev]
|
||||
opt-level = 0
|
@ -1,169 +1,227 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "guard.h"
|
||||
|
||||
#define GD_PAGE_BITS 14ULL
|
||||
#define GD_PAGE_SIZE (1ULL << GD_PAGE_BITS) // 16 KB
|
||||
#define GD_PAGE_MASK (GD_PAGE_SIZE - 1)
|
||||
#define GD_PAGE_ROUND_DOWN(foo) (foo & (~GD_PAGE_MASK))
|
||||
|
||||
#define GD_PAGEBITS 14ULL
|
||||
#define GD_PAGESIZE (1ULL << GD_PAGEBITS) /* 16K */
|
||||
|
||||
static uint64_t *guard_p = 0;
|
||||
static uintptr_t guard_p;
|
||||
static const uintptr_t *stack_pp;
|
||||
static const uintptr_t *alloc_pp;
|
||||
static jmp_buf env_buffer;
|
||||
static void (*prev_sigsegv_handler)(int, siginfo_t *, void *);
|
||||
static const uint64_t *(*low)(void *, void *) = 0;
|
||||
static const uint64_t *(*high)(void *, void *) = 0;
|
||||
static void *bounds = 0;
|
||||
static void *context = 0;
|
||||
static struct sigaction prev_sa;
|
||||
|
||||
static int32_t
|
||||
_prot_page(void *address, int prot)
|
||||
{
|
||||
if (mprotect(address, GD_PAGE_SIZE, prot)) {
|
||||
fprintf(stderr, "guard: prot: mprotect error %d\r\n", errno);
|
||||
fprintf(stderr, "%s\r\n", strerror(errno));
|
||||
return guard_mprotect | errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_mark_page(void *address)
|
||||
{
|
||||
return _prot_page(address, PROT_NONE);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_unmark_page(void *address)
|
||||
{
|
||||
return _prot_page(address, PROT_READ | PROT_WRITE);
|
||||
}
|
||||
|
||||
// Center the guard page.
|
||||
static guard_err
|
||||
// XX: could be a false positive if the new frame results in exact same guard page
|
||||
// solution: we only re-center from the signal handler
|
||||
static int32_t
|
||||
_focus_guard()
|
||||
{
|
||||
const uint64_t *low_p = low(bounds, context);
|
||||
const uint64_t *high_p = high(bounds, context);
|
||||
uintptr_t stack_p = *stack_pp;
|
||||
uintptr_t alloc_p = *alloc_pp;
|
||||
uintptr_t old_guard_p = guard_p;
|
||||
uintptr_t new_guard_p;
|
||||
int32_t err = 0;
|
||||
|
||||
if (low_p >= high_p ) {
|
||||
return guard_spent;
|
||||
fprintf(stderr, "guard: focus: stack pointer at %p\r\n", (void *)stack_p);
|
||||
fprintf(stderr, "guard: focus: alloc pointer at %p\r\n", (void *)alloc_p);
|
||||
|
||||
if (stack_p == 0 || alloc_p == 0) {
|
||||
fprintf(stderr, "guard: focus: stack or alloc pointer is null\r\n");
|
||||
return guard_null;
|
||||
} else if (stack_p == alloc_p) {
|
||||
fprintf(stderr, "guard: focus: stack and alloc pointers equal\r\n");
|
||||
return guard_oom;
|
||||
}
|
||||
|
||||
if (low_p == 0 || high_p == 0) {
|
||||
fprintf(stderr, "guard: low or high bound pointer is null\r\n");
|
||||
return guard_weird;
|
||||
fprintf(stderr, "guard: focus: old guard = %p\r\n", (void *)old_guard_p);
|
||||
|
||||
// Compute new guard page
|
||||
// XX: Should we also check for new_guard_p < min(stack_p, alloc_p)?
|
||||
new_guard_p = GD_PAGE_ROUND_DOWN((stack_p + alloc_p) / 2);
|
||||
fprintf(stderr, "guard: focus: new guard = %p\r\n", (void *)new_guard_p);
|
||||
if (new_guard_p == old_guard_p) {
|
||||
fprintf(stderr, "guard: focus: OOM\r\n");
|
||||
return guard_oom;
|
||||
}
|
||||
|
||||
void *old_guard_p = guard_p;
|
||||
|
||||
guard_p = (uint64_t *)low_p + ((high_p - low_p) / 2);
|
||||
guard_p = (uint64_t *)((uintptr_t)guard_p & ~(GD_PAGESIZE - 1));
|
||||
|
||||
const bool same = old_guard_p == guard_p;
|
||||
const bool left = (uint64_t)(high_p - low_p) > GD_PAGESIZE;
|
||||
if (same && !left) {
|
||||
fprintf(stderr, "guard: spent: %p; left: %u\r\n", (void *)guard_p, left);
|
||||
return guard_spent;
|
||||
// Mark new guard page
|
||||
if ((err = _mark_page((void *)new_guard_p))) {
|
||||
fprintf(stderr, "guard: focus: mark error\r\n");
|
||||
return err;
|
||||
}
|
||||
else {
|
||||
if (mprotect(guard_p, GD_PAGESIZE, PROT_NONE) == -1) {
|
||||
return guard_armor;
|
||||
|
||||
// Update guard page tracker
|
||||
fprintf(stderr, "guard: focus: installed guard page at %p\r\n", (void *)new_guard_p);
|
||||
guard_p = new_guard_p;
|
||||
|
||||
// Unmark the old guard page (if there is one)
|
||||
if (old_guard_p) {
|
||||
if ((err = _unmark_page((void *)old_guard_p))) {
|
||||
fprintf(stderr, "guard: focus: unmark error\r\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_guard_p != NULL &&
|
||||
mprotect(old_guard_p, GD_PAGESIZE, PROT_READ | PROT_WRITE) == -1)
|
||||
{
|
||||
return guard_armor;
|
||||
}
|
||||
|
||||
return guard_sound;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_signal_handler(int sig, siginfo_t *si, void *unused)
|
||||
{
|
||||
uintptr_t sig_addr;
|
||||
int32_t err = 0;
|
||||
|
||||
assert(guard_p);
|
||||
|
||||
fprintf(stderr, "guard: sig_handle: %d received\r\n", sig);
|
||||
|
||||
if (sig != SIGSEGV) {
|
||||
fprintf(stderr, "guard: weird signal: %d\r\n", sig);
|
||||
return;
|
||||
fprintf(stderr, "guard: sig_handle: invalid signal\r\n");
|
||||
// XX: do we even want to jump? if this is fatal error, maybe just die now
|
||||
siglongjmp(env_buffer, guard_signal);
|
||||
}
|
||||
|
||||
if (guard_p == NULL) {
|
||||
fprintf(stderr, "guard: no guard page\r\n");
|
||||
return;
|
||||
}
|
||||
sig_addr = (uintptr_t)si->si_addr;
|
||||
fprintf(stderr, "guard: SIGSEGV address = %p\r\n", (void *)sig_addr);
|
||||
|
||||
if (si == NULL) {
|
||||
fprintf(stderr, "guard: no signal info\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (si->si_addr >= (void *)guard_p &&
|
||||
si->si_addr < (void *)guard_p + GD_PAGESIZE)
|
||||
if (sig_addr >= guard_p &&
|
||||
sig_addr < guard_p + GD_PAGE_SIZE)
|
||||
{
|
||||
fprintf(stderr, "guard: hit: %p\r\n", si->si_addr);
|
||||
guard_err err = _focus_guard();
|
||||
if (err != guard_sound) {
|
||||
fprintf(stderr, "guard: jump\r\n");
|
||||
err = _focus_guard();
|
||||
if (err) {
|
||||
fprintf(stderr, "guard: sig_handle: focus error\r\n");
|
||||
siglongjmp(env_buffer, err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "guard: weird hit: %p\r\n", si->si_addr);
|
||||
return;
|
||||
fprintf(stderr, "guard: page at %p miss\r\n", (void *)guard_p);
|
||||
|
||||
if (prev_sa.sa_sigaction != NULL) {
|
||||
prev_sa.sa_sigaction(sig, si, unused);
|
||||
} else if (prev_sa.sa_handler != NULL) {
|
||||
prev_sa.sa_handler(sig);
|
||||
} else {
|
||||
// There should always be a default SIGSEGV handler
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static guard_err
|
||||
static int32_t
|
||||
_register_handler()
|
||||
{
|
||||
struct sigaction sa;
|
||||
struct sigaction prev_sa;
|
||||
|
||||
// Flag to use sa_sigaction
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
// Must use sa_sigaction; sa-handler takes signal handler as its only argument
|
||||
sa.sa_sigaction = _signal_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaddset(&(sa.sa_mask), SIGSEGV);
|
||||
// Set mask of signals to ignore while running signal handler
|
||||
// TODO: By default the signal that triggered the signal handler is automatically added to the
|
||||
// mask while it's being handled, so unless we plan to add more signals to this then I
|
||||
// don't think it's necessary.
|
||||
// sigemptyset(&sa.sa_mask);
|
||||
// sigaddset(&(sa.sa_mask), SIGSEGV);
|
||||
|
||||
// XX: should assert that prev_sa doesn't have a handler in it, but it's not a pointer so non-trivial
|
||||
if (sigaction(SIGSEGV, &sa, &prev_sa)) {
|
||||
fprintf(stderr, "guard: failed to register handler\r\n");
|
||||
return guard_weird;
|
||||
}
|
||||
prev_sigsegv_handler = prev_sa.sa_sigaction;
|
||||
|
||||
return guard_sound;
|
||||
fprintf(stderr, "guard: register: sigaction error\r\n");
|
||||
fprintf(stderr, "%s\r\n", strerror(errno));
|
||||
return guard_sigaction | errno;
|
||||
}
|
||||
|
||||
guard_err
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
guard(
|
||||
void *(*work_f)(void *, void *),
|
||||
void *work_data,
|
||||
const uint64_t *(*low_f)(void *, void *),
|
||||
const uint64_t *(*high_f)(void *, void *),
|
||||
void *bounds_data,
|
||||
void *context_p,
|
||||
void *const *ret
|
||||
)
|
||||
{
|
||||
guard_err err;
|
||||
callback f,
|
||||
void *closure,
|
||||
const uintptr_t *const s_pp,
|
||||
const uintptr_t *const a_pp,
|
||||
void ** ret
|
||||
) {
|
||||
int32_t err = 0;
|
||||
int32_t td_err;
|
||||
|
||||
low = low_f;
|
||||
high = high_f;
|
||||
bounds= bounds_data;
|
||||
context = context_p;
|
||||
assert(guard_p == 0);
|
||||
fprintf(stderr, "guard: setup: stack pointer at %p\r\n", (void *)(*stack_pp));
|
||||
fprintf(stderr, "guard: setup: alloc pointer at %p\r\n", (void *)(*alloc_pp));
|
||||
|
||||
err = _focus_guard();
|
||||
if (guard_p == NULL && err != guard_sound && err != guard_spent) {
|
||||
fprintf(stderr, "guard: failed to install\r\n");
|
||||
goto fail;
|
||||
guard_p = 0;
|
||||
stack_pp = s_pp;
|
||||
alloc_pp = a_pp;
|
||||
|
||||
// Initialize the guard page
|
||||
if ((err = _focus_guard())) {
|
||||
fprintf(stderr, "guard: setup: _focus_guard error\r\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((err = _register_handler()) != guard_sound) {
|
||||
fprintf(stderr, "guard: failed to register handler\r\n");
|
||||
goto fail;
|
||||
// Register guard page signal handler
|
||||
if ((err = _register_handler())) {
|
||||
fprintf(stderr, "guard: setup: _register_handler error\r\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = sigsetjmp(env_buffer, 1);
|
||||
if (err == guard_start) {
|
||||
*(void **)ret = work_f(work_data, context_p);
|
||||
return guard_sound;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
// Run given closure
|
||||
fprintf(stderr, "guard: run\r\n");
|
||||
if (!(err = sigsetjmp(env_buffer, 1))) {
|
||||
*ret = f(closure);
|
||||
}
|
||||
|
||||
fail:
|
||||
// Restore the previous signal handler.
|
||||
{
|
||||
struct sigaction sa;
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = prev_sigsegv_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaddset(&(sa.sa_mask), SIGSEGV);
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
done:
|
||||
// Clean up
|
||||
if (guard_p != 0) {
|
||||
td_err = _unmark_page((void *)guard_p);
|
||||
}
|
||||
|
||||
fprintf(stderr, "guard: fail: %d\r\n", err);
|
||||
if (sigaction(SIGSEGV, &prev_sa, NULL)) {
|
||||
fprintf(stderr, "guard: teardown: sigaction error\r\n");
|
||||
fprintf(stderr, "%s\r\n", strerror(errno));
|
||||
td_err = guard_sigaction | errno;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
err = td_err;
|
||||
}
|
||||
|
||||
fprintf(stderr, "guard: return\r\n");
|
||||
return err;
|
||||
}
|
||||
|
@ -3,15 +3,22 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* Error codes and flags.
|
||||
*
|
||||
* The flags are bitwise added to the errno of their respective errors.
|
||||
*/
|
||||
typedef enum {
|
||||
guard_start = 0, // setjmp
|
||||
guard_sound = 1, // good/done
|
||||
guard_armor = 2, // mprotect
|
||||
guard_weird = 3, // strange state
|
||||
guard_spent = 4, // out of memory (bail:meme)
|
||||
guard_null = 1, // null stack or alloc pointer
|
||||
guard_signal, // invalid signal
|
||||
guard_oom, // OOM
|
||||
guard_malloc = 0x10000000, // malloc error flag
|
||||
guard_mprotect = 0x20000000, // mprotect error flag
|
||||
guard_sigaction = 0x40000000, // sigaction error flag
|
||||
} guard_err;
|
||||
|
||||
typedef void *(*callback)(void *);
|
||||
|
||||
/**
|
||||
* Execute the given closure `f` within the memory arena between the
|
||||
* `stack` and `alloc` pointers, with guard page protection. Write either
|
||||
@ -40,15 +47,13 @@ typedef enum {
|
||||
* error will be written to the `ret` pointer. The caller is then responsible
|
||||
* for handling this error and aborting with a `bail:meme`.
|
||||
*/
|
||||
guard_err
|
||||
int32_t
|
||||
guard(
|
||||
void *(*work_f)(void *, void *),
|
||||
void *work_data,
|
||||
const uint64_t *(*low_f)(void *, void *),
|
||||
const uint64_t *(*high_f)(void *, void *),
|
||||
void *bounds_data,
|
||||
void *context_p,
|
||||
void *const *ret
|
||||
callback f,
|
||||
void *closure,
|
||||
const uintptr_t *const s_pp,
|
||||
const uintptr_t *const a_pp,
|
||||
void **ret
|
||||
);
|
||||
|
||||
#endif
|
||||
#endif // __GUARD_H__
|
||||
|
@ -4,7 +4,9 @@
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
|
||||
pub const GUARD_SOUND: u32 = guard_err_guard_sound;
|
||||
pub const GUARD_ARMOR: u32 = guard_err_guard_armor;
|
||||
pub const GUARD_WEIRD: u32 = guard_err_guard_weird;
|
||||
pub const GUARD_SPENT: u32 = guard_err_guard_spent;
|
||||
pub const GUARD_NULL: u32 = guard_err_guard_null;
|
||||
pub const GUARD_SIGNAL: u32 = guard_err_guard_signal;
|
||||
pub const GUARD_OOM: u32 = guard_err_guard_oom;
|
||||
pub const GUARD_MALLOC: u32 = guard_err_guard_malloc;
|
||||
pub const GUARD_MPROTECT: u32 = guard_err_guard_mprotect;
|
||||
pub const GUARD_SIGACTION: u32 = guard_err_guard_sigaction;
|
||||
|
@ -76,7 +76,6 @@ STATIC_ASSERT(0, "debugger break instruction unimplemented");
|
||||
/* the opposite of P2BYTES */
|
||||
#define B2PAGES(x) ((size_t)(x) >> BT_PAGEBITS)
|
||||
|
||||
|
||||
#define __packed __attribute__((__packed__))
|
||||
#define UNUSED(x) ((void)(x))
|
||||
|
||||
@ -95,7 +94,6 @@ STATIC_ASSERT(0, "debugger break instruction unimplemented");
|
||||
/* given a pointer p returns the low page-aligned addr */
|
||||
#define LO_ALIGN_PAGE(p) ((BT_page *)(((uintptr_t)p) & ~(BT_PAGESIZE - 1)))
|
||||
|
||||
|
||||
#define BT_MAPADDR ((BYTE *) S(0x1000,0000,0000))
|
||||
|
||||
static inline vaof_t
|
||||
@ -341,7 +339,6 @@ struct BT_state {
|
||||
|
||||
/*
|
||||
|
||||
|
||||
//// ===========================================================================
|
||||
//// btree internal routines
|
||||
|
||||
|
2
rust/rust-assert-no-alloc/.gitignore
vendored
2
rust/rust-assert-no-alloc/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
/target
|
||||
Cargo.lock
|
@ -149,6 +149,14 @@ pub fn reset_violation_count() {
|
||||
ALLOC_VIOLATION_COUNT.with(|c| c.set(0));
|
||||
}
|
||||
|
||||
pub fn reset_counters() {
|
||||
ALLOC_FORBID_COUNT.with(|c| c.set(0));
|
||||
ALLOC_PERMIT_COUNT.with(|c| c.set(0));
|
||||
|
||||
#[cfg(any( all(feature="warn_debug", debug_assertions), all(feature="warn_release", not(debug_assertions)) ))]
|
||||
ALLOC_VIOLATION_COUNT.with(|c| c.set(0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user