mirror of
https://github.com/urbit/ares.git
synced 2024-12-23 13:25:03 +03:00
Merge pull request #178 from urbit/revert-177-revert-175-eamsden/gc-top-frame
2stackz: gc top frame by flipping polarity (take 2)
This commit is contained in:
commit
4ff2f1e161
@ -2,7 +2,7 @@ use crate::jets::*;
|
||||
use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun, D, T};
|
||||
use ares_macros::tas;
|
||||
use either::Either::{self, Left, Right};
|
||||
use std::ptr::null_mut;
|
||||
use std::ptr::{copy_nonoverlapping, null_mut};
|
||||
|
||||
/** Root for Hoon %k.139
|
||||
*/
|
||||
@ -826,3 +826,27 @@ struct HotMem {
|
||||
jet: Jet,
|
||||
next: Hot,
|
||||
}
|
||||
|
||||
impl Preserve for Hot {
|
||||
unsafe fn preserve(&mut self, stack: &mut NockStack) {
|
||||
let mut it = self;
|
||||
while !it.0.is_null() && stack.is_in_frame(it.0) {
|
||||
let dest_mem = stack.struct_alloc_in_previous_frame(1);
|
||||
copy_nonoverlapping(it.0, dest_mem, 1);
|
||||
it.0 = dest_mem;
|
||||
(*it.0).a_path.preserve(stack);
|
||||
(*it.0).axis.preserve(stack);
|
||||
it = &mut (*it.0).next;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn assert_in_stack(&self, stack: &NockStack) {
|
||||
let mut it = self;
|
||||
while !it.0.is_null() {
|
||||
stack.assert_struct_is_in(it.0, 1);
|
||||
(*it.0).a_path.assert_in_stack(stack);
|
||||
(*it.0).axis.assert_in_stack(stack);
|
||||
it = &mut (*it.0).next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ impl NockStack {
|
||||
unsafe {
|
||||
*frame_pointer.sub(FRAME + 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) = ptr::null::<u64>() as u64; // "alloc pointer" from "previous" frame
|
||||
*frame_pointer.sub(ALLOC + 1) = start as u64; // "alloc pointer" from "previous" frame
|
||||
};
|
||||
NockStack {
|
||||
start,
|
||||
@ -88,7 +88,43 @@ impl NockStack {
|
||||
}
|
||||
}
|
||||
|
||||
/** Resets the NockStack. */
|
||||
/** Resets the NockStack but flipping the top-frame polarity and unsetting PC. Sets the alloc
|
||||
* pointer to the "previous" alloc pointer stored in the top frame to keep things "preserved"
|
||||
* from the top frame. This allows us to do a copying GC on the top frame without erroneously
|
||||
* "popping" the top frame.
|
||||
*/
|
||||
pub unsafe fn flip_top_frame(&mut self, top_slots: usize) {
|
||||
// Assert that we are at the top
|
||||
assert!((*self.prev_frame_pointer_pointer()).is_null());
|
||||
assert!((*self.prev_stack_pointer_pointer()).is_null());
|
||||
let new_alloc_pointer = *(self.prev_alloc_pointer_pointer());
|
||||
|
||||
if self.is_west() {
|
||||
// new top frame will be east
|
||||
let new_frame_pointer = self.start.add(self.size).sub(RESERVED + top_slots) as *mut u64;
|
||||
*new_frame_pointer.add(FRAME) = ptr::null::<u64>() as u64;
|
||||
*new_frame_pointer.add(STACK) = ptr::null::<u64>() as u64;
|
||||
*new_frame_pointer.add(ALLOC) = self.start.add(self.size) as u64;
|
||||
self.frame_pointer = new_frame_pointer;
|
||||
self.stack_pointer = new_frame_pointer;
|
||||
self.alloc_pointer = new_alloc_pointer;
|
||||
self.pc = false;
|
||||
assert!(!self.is_west());
|
||||
} else {
|
||||
// new top frame will be west
|
||||
let new_frame_pointer = self.start.add(RESERVED + top_slots) as *mut u64;
|
||||
*new_frame_pointer.sub(FRAME + 1) = ptr::null::<u64>() as u64;
|
||||
*new_frame_pointer.sub(STACK + 1) = ptr::null::<u64>() as u64;
|
||||
*new_frame_pointer.sub(ALLOC + 1) = self.start as u64;
|
||||
self.frame_pointer = new_frame_pointer;
|
||||
self.stack_pointer = new_frame_pointer;
|
||||
self.alloc_pointer = new_alloc_pointer;
|
||||
self.pc = false;
|
||||
assert!(self.is_west());
|
||||
}
|
||||
}
|
||||
|
||||
/** Resets the NockStack. The top frame is west as in the initial creation of the NockStack. */
|
||||
pub fn reset(&mut self, top_slots: usize) {
|
||||
self.frame_pointer = unsafe { self.start.add(RESERVED + top_slots) } as *mut u64;
|
||||
self.stack_pointer = self.frame_pointer;
|
||||
@ -97,7 +133,8 @@ impl NockStack {
|
||||
unsafe {
|
||||
*self.frame_pointer.sub(FRAME + 1) = ptr::null::<u64>() as u64; // "frame pointer" from "previous" frame
|
||||
*self.frame_pointer.sub(STACK + 1) = ptr::null::<u64>() as u64; // "stack pointer" from "previous" frame
|
||||
*self.frame_pointer.sub(ALLOC + 1) = ptr::null::<u64>() as u64; // "alloc pointer" from "previous" frame
|
||||
*self.frame_pointer.sub(ALLOC + 1) = self.start as u64; // "alloc pointer" from "previous" frame
|
||||
assert!(self.is_west());
|
||||
};
|
||||
}
|
||||
|
||||
@ -123,7 +160,17 @@ impl NockStack {
|
||||
let ptr_u64 = ptr as *const u64;
|
||||
let prev = *self.prev_stack_pointer_pointer();
|
||||
if self.is_west() {
|
||||
ptr_u64 >= self.alloc_pointer && ptr_u64 < prev
|
||||
// If we are in a top/west frame, the stack pointer will be null, so our allocation
|
||||
// arena was the alloc pointer to the top of the NockStack arena
|
||||
if prev.is_null() {
|
||||
ptr_u64 >= self.alloc_pointer && ptr_u64 < self.start.add(self.size)
|
||||
} else {
|
||||
ptr_u64 >= self.alloc_pointer && ptr_u64 < prev
|
||||
}
|
||||
// If we are in a top/east frame, the stack pointer will be null, so our allocation arena
|
||||
// was the alloc pointer to the bottom of the NockStack arena
|
||||
} else if prev.is_null() {
|
||||
ptr_u64 >= self.start && ptr_u64 < self.alloc_pointer
|
||||
} else {
|
||||
ptr_u64 >= prev && ptr_u64 < self.alloc_pointer
|
||||
}
|
||||
|
@ -224,7 +224,6 @@ pub fn serf(constant_hot_state: &[HotEntry]) -> io::Result<()> {
|
||||
// Reset the local cache and scry handler stack
|
||||
context.nock_context.cache = Hamt::<Noun>::new();
|
||||
context.nock_context.scry_stack = D(0);
|
||||
context.nock_context.stack.frame_push(0);
|
||||
|
||||
let tag = slot(writ, 2)?.as_direct().unwrap();
|
||||
match tag.data() {
|
||||
@ -269,13 +268,15 @@ pub fn serf(constant_hot_state: &[HotEntry]) -> io::Result<()> {
|
||||
clear_interrupt();
|
||||
|
||||
// Persist data that should survive between events
|
||||
// XX: Such data should go in the PMA once that's available
|
||||
// XX: Such data should go in the PMA once that's available, except
|
||||
// the warm and hot state which should survive between events but not interpreter runs
|
||||
unsafe {
|
||||
let stack = &mut context.nock_context.stack;
|
||||
stack.preserve(&mut context.arvo);
|
||||
stack.preserve(&mut context.nock_context.cold);
|
||||
stack.preserve(&mut context.nock_context.warm);
|
||||
stack.frame_pop();
|
||||
stack.preserve(&mut context.nock_context.hot);
|
||||
stack.flip_top_frame(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user