this was using the lightweight stack, but this presented the following
issue: NockStack::copy() can be called during the Hamt::preserve() call,
and the lightweight stack may not be empty. NockStack::copy() presumes
that the lightweight stack is empty when it is called, and thus tried to
pop elements that preserve() had pushed onto it.
NockStack::copy() should probably assert that the lightweight stack is
empty when its called
if these functions are callled with a non-empty lightweight stack, they
will try to pop things that they shouldn't.
all other stack_is_empty() callsites happen in a fresh stack frame, so
we already know the lightweight stack will be empty.
- using patch.crates-io does not work because it only applies to the local crate development and not as a setting for consumers of the package
thanks to @drbeefsupreme for the original fix
Co-authored-by: <drbeefsupreme@discordja.net>
see docs/stack.md for information about this change.
split: replace Polarity enum with pointer check
we can check polarity with West === FP < AP,
East === FP > AP.
we panic when the pointers are equal.
split: pre_copy step before preserve() calls
we need to save the stored frame_pointer and alloc_pointer before
preserve calls, which will otherwise overwrite them.
split: copy_west(), now with stack_pointer!
when copying, we can forget the lightweight stack in the current frame
and start a new one adjacent to from-space used for traversing nouns
in from-space.
split: working split stack
this commit works with hurray.jam and decrement.jam.
there's at least one thing left: I don't think the implementation of
hamt::preserve() is correct, but hurray.jam and decrement.jam don't use
it so it doesn't detect it. the comment there explains whats wrong.
I also need to double check copy_pma() still.
This is the commit message #52:
split: hamt::preserve() and free_alloc
hamt::preserve() needs to allocate in the current frame after we've
already said we can no longer allocate (once pre_copy() has been
called). so does e.g. copy_west(), since it moves the lightweight
stack into this same area. we can unify this interface but I want
to explore the ergonomics of making this free allocation stuff usable
for the programmer without having to think about whether or not
pre_copy() has already been called.
split: add boolean for pre_copy()
alternative: use an enum to say whether the lightweight stack grows
westward or eastward, and that the reserved slots for the previous
frame's pointers are adjacent to the frame_pointer or alloc_pointer. not
sure which is the better choice yet.
split: panic when allocating at the wrong time
when pc == false, we aren't in copying mode (basically when we're
copying allocations to the previous frame to get ready to pop the
frame). therefore we should panic if we try to allocate in the previous
frame.
similarly, when pc == true, we're no longer allowed to allocate in the
current frame, but we can allocate in the previous frame. therefore we
should panic if we try to allocate in the current frame.
split: use prev_stack_pointer_pointer()
we'd like the programmer to not have to think about whether the frame is
in copying mode or not, so every time we want the previous frame's stack
pointer we should just called prev_stack_pointer_pointer() instead of
trying to remember if we need slot_pointer or free_slot.
we still use slot_pointer and free_slot for pushing and popping stack
frames, since we're in the midst of changing the pointers that would
determine where prev_stack_pointer_pointer() would look.
split: polarity of lw stack changes in pre_copy
It was waiting until copy_west/copy_east to do this - this makes it more
clear that the lightweight stack is different after pre_copy() is called
split: simplify is_west
asking this to panic in case of equality is assigning it too much
responsibility. it should just say whether or not a frame is west.
This is the commit message #76:
split: copy_pma isn't in cleanup mode
we don't need to move the lightweight stack since we're not allocating
in a previous frame, but into the PMA
split: revise pre_copy() usage
pre_copy() is no longer public. instead, it is called at the start of
any NockStack method which could potentially be the first function called when
getting ready to pop a stack frame (preserve() and functions that
allocate in the previous frame).
main: trailing bytes of cued jamfile are zeroes
this was already the case, but it was doing so incorrectly.
write_bytes(dest.add(word_len as usize - 1), 0, 8)
copies 64 bytes of zeroes starting at the last word of the indirect
atom. this went unnoticed before split stack since allocation happened
at the west end of the memory arena. now that allocation starts at the
east end, this was causing an overflow. so the correct line is
write_bytes(dest.add(word_len as usize - 1), 0, 1)
split: memory in NockStack::new not mutable
it was before split stack, now its unnecessary and throws a compiler
warning. im confused as to why it was ever there at all, though