mirror of
https://github.com/urbit/ares.git
synced 2024-11-28 19:32:00 +03:00
Test cleanup, tests for stack push and frame push
This commit is contained in:
parent
8aef2652dd
commit
e200121c57
@ -855,6 +855,12 @@ pub enum FromNounError {
|
|||||||
AllocationError(#[from] crate::mem::AllocationError),
|
AllocationError(#[from] crate::mem::AllocationError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromNounError {
|
||||||
|
pub fn is_alloc_error(&self) -> bool {
|
||||||
|
matches!(self, FromNounError::AllocationError(_))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type NounableResult<T> = std::result::Result<T, FromNounError>;
|
pub type NounableResult<T> = std::result::Result<T, FromNounError>;
|
||||||
|
|
||||||
pub trait Nounable {
|
pub trait Nounable {
|
||||||
|
@ -44,7 +44,7 @@ pub struct MemoryState {
|
|||||||
|
|
||||||
/// Error type for when a potential allocation would cause an OOM error
|
/// Error type for when a potential allocation would cause an OOM error
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct OutOfMemoryError(pub MemoryState);
|
pub struct OutOfMemoryError(pub MemoryState, pub Allocation,);
|
||||||
|
|
||||||
/// Error type for allocation errors in [NockStack]
|
/// Error type for allocation errors in [NockStack]
|
||||||
#[derive(Debug, Clone, Error)]
|
#[derive(Debug, Clone, Error)]
|
||||||
@ -63,7 +63,7 @@ impl From<AllocationError> for std::io::Error {
|
|||||||
|
|
||||||
pub type AllocResult<T> = core::result::Result<T, AllocationError>;
|
pub type AllocResult<T> = core::result::Result<T, AllocationError>;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum ArenaOrientation {
|
pub enum ArenaOrientation {
|
||||||
/// stack_pointer < alloc_pointer
|
/// stack_pointer < alloc_pointer
|
||||||
/// stack_pointer increases on push
|
/// stack_pointer increases on push
|
||||||
@ -77,7 +77,7 @@ pub enum ArenaOrientation {
|
|||||||
East,
|
East,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum AllocationType {
|
pub enum AllocationType {
|
||||||
/// alloc pointer moves
|
/// alloc pointer moves
|
||||||
Alloc,
|
Alloc,
|
||||||
@ -188,8 +188,8 @@ impl NockStack {
|
|||||||
AllocationError::CannotAllocateInPreCopy(self.memory_state(size))
|
AllocationError::CannotAllocateInPreCopy(self.memory_state(size))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn out_of_memory(&self, words: Option<usize>) -> AllocationError {
|
fn out_of_memory(&self, alloc: Allocation, words: Option<usize>) -> AllocationError {
|
||||||
AllocationError::OutOfMemory(OutOfMemoryError(self.memory_state(words)))
|
AllocationError::OutOfMemory(OutOfMemoryError(self.memory_state(words), alloc))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_alloc_config(&self, alloc_type: AllocationType) -> Allocation {
|
pub(crate) fn get_alloc_config(&self, alloc_type: AllocationType) -> Allocation {
|
||||||
@ -239,6 +239,9 @@ impl NockStack {
|
|||||||
// Types of size: word (words: usize)
|
// Types of size: word (words: usize)
|
||||||
/// Check if an allocation of `size` would cause an OOM error
|
/// Check if an allocation of `size` would cause an OOM error
|
||||||
pub fn alloc_would_oom_(&self, alloc: Allocation, words: usize) -> Result<(), AllocationError> {
|
pub fn alloc_would_oom_(&self, alloc: Allocation, words: usize) -> Result<(), AllocationError> {
|
||||||
|
let memory_state = self.memory_state(Some(words));
|
||||||
|
println!("alloc_would_oom_: self.memory_state(): {:#?}, self:is_west(): {}", memory_state, self.is_west());
|
||||||
|
println!("alloc_would_oom_: alloc: {:#?}", alloc);
|
||||||
if self.pc {
|
if self.pc {
|
||||||
return Err(self.cannot_alloc_in_pc(Some(words)));
|
return Err(self.cannot_alloc_in_pc(Some(words)));
|
||||||
}
|
}
|
||||||
@ -299,14 +302,14 @@ impl NockStack {
|
|||||||
if target_point <= limit_point {
|
if target_point <= limit_point {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(self.out_of_memory(Some(words)))
|
Err(self.out_of_memory(alloc, Some(words)))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Direction::Decreasing => {
|
Direction::Decreasing => {
|
||||||
if target_point >= limit_point {
|
if target_point >= limit_point {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(self.out_of_memory(Some(words)))
|
Err(self.out_of_memory(alloc, Some(words)))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -534,11 +537,7 @@ impl NockStack {
|
|||||||
|
|
||||||
/** Bump the alloc pointer for an east frame to make space for an allocation */
|
/** Bump the alloc pointer for an east frame to make space for an allocation */
|
||||||
unsafe fn raw_alloc_east(&mut self, words: usize) -> AllocResult<*mut u64> {
|
unsafe fn raw_alloc_east(&mut self, words: usize) -> AllocResult<*mut u64> {
|
||||||
// println!("allocating struct, words: {}, is_west: {}", words, self.is_west());
|
|
||||||
// println!("pc: {}, sp: {}, ap: {}", self.pc, self.stack_pointer as usize, self.alloc_pointer as usize);
|
|
||||||
// let alloc = self.get_alloc_config(AllocationType::Alloc);
|
|
||||||
let () = self.alloc_would_oom(AllocationType::Alloc, words)?;
|
let () = self.alloc_would_oom(AllocationType::Alloc, words)?;
|
||||||
// println!("memory_state: {:#?}, alloc: {alloc:#?}, alloc_would_oom: {:?}\n", self.memory_state(Some(words)), would_oom);
|
|
||||||
if self.pc {
|
if self.pc {
|
||||||
panic!("Allocation during cleanup phase is prohibited.");
|
panic!("Allocation during cleanup phase is prohibited.");
|
||||||
}
|
}
|
||||||
@ -981,7 +980,7 @@ impl NockStack {
|
|||||||
// TODO: Basic alloc function
|
// TODO: Basic alloc function
|
||||||
unsafe fn push_east<T>(&mut self) -> AllocResult<*mut T> {
|
unsafe fn push_east<T>(&mut self) -> AllocResult<*mut T> {
|
||||||
let words = word_size_of::<T>();
|
let words = word_size_of::<T>();
|
||||||
let () = self.alloc_would_oom_(Allocation { orientation: ArenaOrientation::West, alloc_type: AllocationType::Push, pc: self.pc }, words)?;
|
let () = self.alloc_would_oom_(Allocation { orientation: ArenaOrientation::East, alloc_type: AllocationType::Push, pc: self.pc }, words)?;
|
||||||
let ap = if self.pc {
|
let ap = if self.pc {
|
||||||
*(self.prev_alloc_pointer_pointer())
|
*(self.prev_alloc_pointer_pointer())
|
||||||
} else {
|
} else {
|
||||||
@ -1320,28 +1319,23 @@ mod test {
|
|||||||
jets::cold::{test::{make_noun_list, make_test_stack}, NounList, Nounable}, mem::NockStack, noun::D, unifying_equality::test::unifying_equality,
|
jets::cold::{test::{make_noun_list, make_test_stack}, NounList, Nounable}, mem::NockStack, noun::D, unifying_equality::test::unifying_equality,
|
||||||
};
|
};
|
||||||
|
|
||||||
// cargo test -- test_noun_list_alloc --nocapture
|
fn test_noun_list_alloc_fn(stack_size: usize, item_count: u64) -> crate::jets::cold::NounableResult<()> {
|
||||||
#[test]
|
|
||||||
fn test_noun_list_alloc() {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// fails at 512, works at 1024
|
// fails at 512, works at 1024
|
||||||
const STACK_SIZE: usize = 1;
|
// const STACK_SIZE: usize = 1;
|
||||||
println!("TEST_SIZE: {}", STACK_SIZE);
|
// println!("TEST_SIZE: {}", STACK_SIZE);
|
||||||
let mut stack = make_test_stack(STACK_SIZE);
|
let mut stack = make_test_stack(stack_size);
|
||||||
// Stack size 1 works until 15 elements, 14 passes, 15 fails.
|
// Stack size 1 works until 15 elements, 14 passes, 15 fails.
|
||||||
const ITEM_COUNT: u64 = 15;
|
// const ITEM_COUNT: u64 = 15;
|
||||||
let vec = Vec::from_iter(0..ITEM_COUNT);
|
let vec = Vec::from_iter(0..item_count);
|
||||||
let items = vec.iter().map(|&x| D(x)).collect::<Vec<Noun>>();
|
let items = vec.iter().map(|&x| D(x)).collect::<Vec<Noun>>();
|
||||||
let slice = vec.as_slice();
|
let slice = vec.as_slice();
|
||||||
let noun_list = make_noun_list(&mut stack, slice).unwrap();
|
let noun_list = make_noun_list(&mut stack, slice)?;
|
||||||
assert!(!noun_list.0.is_null());
|
assert!(!noun_list.0.is_null());
|
||||||
// This always reports 16, what gives?
|
let noun = noun_list.into_noun(&mut stack)?;
|
||||||
// let space_needed = noun_list.space_needed(&mut stack);
|
|
||||||
// assert!(space_needed <= TEST_SIZE, "space_needed = {}, TEST_SIZE: {}", space_needed, TEST_SIZE);
|
|
||||||
let noun = noun_list.into_noun(&mut stack).unwrap();
|
|
||||||
let new_noun_list: NounList =
|
let new_noun_list: NounList =
|
||||||
<NounList as Nounable>::from_noun::<NockStack>(&mut stack, &noun).unwrap();
|
<NounList as Nounable>::from_noun::<NockStack>(&mut stack, &noun)?;
|
||||||
let mut item_count = 0;
|
let mut tracking_item_count = 0;
|
||||||
println!("items: {:?}", items);
|
println!("items: {:?}", items);
|
||||||
for (a, b) in new_noun_list.zip(items.iter()) {
|
for (a, b) in new_noun_list.zip(items.iter()) {
|
||||||
let a_ptr = a;
|
let a_ptr = a;
|
||||||
@ -1354,9 +1348,76 @@ mod test {
|
|||||||
a_val,
|
a_val,
|
||||||
b
|
b
|
||||||
);
|
);
|
||||||
item_count += 1;
|
tracking_item_count += 1;
|
||||||
}
|
}
|
||||||
assert_eq!(item_count, ITEM_COUNT as usize);
|
assert_eq!(tracking_item_count, item_count as usize);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// cargo test -p sword test_noun_list_alloc -- --nocapture
|
||||||
|
#[test]
|
||||||
|
fn test_noun_list_alloc() {
|
||||||
|
let should_fail_to_alloc = test_noun_list_alloc_fn(1, 15);
|
||||||
|
assert!(should_fail_to_alloc.map_err(|err| err.is_alloc_error()).unwrap_err());
|
||||||
|
let should_succeed = test_noun_list_alloc_fn(1, 14);
|
||||||
|
assert!(should_succeed.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
// cargo test -p sword test_frame_push -- --nocapture
|
||||||
|
#[test]
|
||||||
|
fn test_frame_push() {
|
||||||
|
// fails at 100, passes at 99, top_slots default to 100?
|
||||||
|
const PASSES: usize = 99;
|
||||||
|
const FAILS: usize = 100;
|
||||||
|
let stack_size = 1;
|
||||||
|
let mut stack = make_test_stack(stack_size);
|
||||||
|
let frame_push_res = stack.frame_push(FAILS);
|
||||||
|
assert!(frame_push_res.is_err());
|
||||||
|
let mut stack = make_test_stack(stack_size);
|
||||||
|
let frame_push_res = stack.frame_push(PASSES);
|
||||||
|
assert!(frame_push_res.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
// cargo test -p sword test_stack_push -- --nocapture
|
||||||
|
#[test]
|
||||||
|
fn test_stack_push() {
|
||||||
|
let stack_size = 1;
|
||||||
|
let mut stack = make_test_stack(stack_size);
|
||||||
|
let mut counter = 0;
|
||||||
|
// Fails at 102, probably because top_slots is 100?
|
||||||
|
while counter < 102 {
|
||||||
|
let push_res = unsafe { stack.push::<u64>() };
|
||||||
|
assert!(push_res.is_ok(), "Failed to push, counter: {}", counter);
|
||||||
|
counter += 1;
|
||||||
|
}
|
||||||
|
let push_res = unsafe { stack.push::<u64>() };
|
||||||
|
assert!(push_res.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
// cargo test -p sword test_frame_and_stack_push -- --nocapture
|
||||||
|
#[test]
|
||||||
|
fn test_frame_and_stack_push() {
|
||||||
|
let stack_size = 1;
|
||||||
|
let mut stack = make_test_stack(stack_size);
|
||||||
|
let mut counter = 0;
|
||||||
|
while counter < 20 {
|
||||||
|
let frame_push_res = stack.frame_push(1);
|
||||||
|
assert!(frame_push_res.is_ok(), "Failed to frame_push, counter: {}", counter);
|
||||||
|
let push_res: Result<*mut u64, AllocationError> = unsafe { stack.push::<u64>() };
|
||||||
|
assert!(push_res.is_ok(), "Failed to push, counter: {}", counter);
|
||||||
|
counter += 1;
|
||||||
|
}
|
||||||
|
let frame_push_res = stack.frame_push(1);
|
||||||
|
assert!(frame_push_res.is_err());
|
||||||
|
// a single stack u64 push won't cause an error but a frame push will
|
||||||
|
let push_res = unsafe { stack.push::<u64>() };
|
||||||
|
assert!(push_res.is_ok());
|
||||||
|
// pushing an array of 1 u64 will NOT cause an error
|
||||||
|
let push_res = unsafe { stack.push::<[u64; 1]>() };
|
||||||
|
assert!(push_res.is_ok());
|
||||||
|
// pushing an array of 2 u64s WILL cause an error
|
||||||
|
let push_res = unsafe { stack.push::<[u64; 2]>() };
|
||||||
|
assert!(push_res.is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user