Merge branch 'revert-177-revert-175-eamsden/gc-top-frame' into eamsden/integrate-pma-tmp-fix-gc

This commit is contained in:
Edward Amsden 2023-12-13 22:39:11 -06:00
commit 59180a704b
6 changed files with 105 additions and 6 deletions

16
.github/scripts/arch/get-runner-arch vendored Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
# This could be improved by separately looking up OS and architecture
# but it will do for now.
for kv in "X64-Linux,x86_64-linux" "X64-macOS,x86_64-darwin" "ARM64-macOS,aarch64-darwin"; do
KEY=${kv%,*};
VAL=${kv#*,};
if [ "$KEY" = "${1}-${2}" ]
then
echo "nix-arch=${VAL}"
exit 0
fi
done
echo "Unknown Github runner arch-os pair: ${1}-${2}"
exit 1

View File

@ -15,12 +15,48 @@ jobs:
steps:
- uses: actions/checkout@v3
# Determine proper nix platform attribute for runner
- name: Determine Nix platform
id: set-nix-platform
working-directory: .
run:
.github/scripts/arch/get-runner-arch ${{ runner.arch }} ${{ runner.os }} > $GITHUB_OUTPUT
# Install nix, required by nix-shell-action
- uses: cachix/install-nix-action@v23
name: Install Nix
with:
extra_nix_config: "extra-experimental-features = nix-command flakes"
- name: Set cache key for dev env
id: set-cache-key
run: |
echo "Determining devshell path for platform ${{ steps.set-nix-platform.outputs.nix-arch }}"
echo "nix-devshell-path=$(nix eval --raw ".#devShells.${{ steps.set-nix-platform.outputs.nix-arch }}.default.outPath")" >> $GITHUB_OUTPUT
- name: Cache nix build artifacts
id: nix-cache
uses: actions/cache@v3
with:
path: |
nix-devshell.nixstore
key: nix-${{ steps.set-cache-key.outputs.nix-devshell-path }}
- name: Restore cached nix artifacts
if: steps.nix-cache.outputs.cache-hit == 'true'
working-directory: .
run: |
pwd
ls
nix-store --import < nix-devshell.nixstore
- name: Cache rust build artifacts
id: cache_rust
uses: Swatinem/rust-cache@v2
with:
key: rust-${{ steps.set-cache-key.outputs.nix-devshell-path }}
workspaces: "rust/ares -> target"
# Check formatting
- name: Format
run: |
@ -46,3 +82,12 @@ jobs:
run: |
nix develop --command bash -c "cargo test --verbose -- --test-threads=1"
- name: Build nix cache export
if: steps.nix-cache.outputs.cache-hit != 'true'
run: |
pwd
nix eval --json ".#devShells.${{ steps.set-nix-platform.outputs.nix-arch }}.default.buildInputs" 2>/dev/null
nix eval --json ".#devShells.${{ steps.set-nix-platform.outputs.nix-arch }}.default.buildInputs" 2>/dev/null | jq -r '.[]' | xargs nix-store --query --requisites
nix-store --export $(nix eval --json ".#devShells.${{ steps.set-nix-platform.outputs.nix-arch }}.default.buildInputs" 2>/dev/null | jq -r '.[]' | xargs nix-store --query --requisites) > ../../nix-devshell.nixstore
ls -lh

View File

@ -338,6 +338,7 @@ impl<T: Copy + Preserve> Hamt<T> {
let chunk = mug & 0x1F; // 5 bits
mug >>= 5;
match stem.entry(chunk) {
// No entry found at mug chunk index; add Leaf to current Stem
None => {
let new_leaf_buffer = stack.struct_alloc(1);
*new_leaf_buffer = (*n, t);
@ -362,6 +363,7 @@ impl<T: Copy + Preserve> Hamt<T> {
};
break Hamt(stem_ret);
}
// Stem found at mug chunk index; insert into found Stem
Some((Left(next_stem), idx)) => {
let new_buffer = stack.struct_alloc(stem.size());
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
@ -375,7 +377,9 @@ impl<T: Copy + Preserve> Hamt<T> {
depth += 1;
continue;
}
// Leaf found at mug chunk index
Some((Right(leaf), idx)) => {
// Override existing value for key, if one exists
for (ldx, pair) in leaf.to_mut_slice().iter_mut().enumerate() {
if unifying_equality(stack, n, &mut pair.0) {
let new_leaf_buffer = stack.struct_alloc(leaf.len);
@ -397,6 +401,8 @@ impl<T: Copy + Preserve> Hamt<T> {
break 'insert Hamt(stem_ret);
}
}
// No existing pair in this Leaf matches the key, and we've maxxed out the
// Hamt depth; add the the key-value pair to the list of pairs for this Leaf
if depth >= 5 {
let new_leaf_buffer = stack.struct_alloc(leaf.len + 1);
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
@ -415,15 +421,19 @@ impl<T: Copy + Preserve> Hamt<T> {
buffer: new_buffer,
};
break 'insert Hamt(stem_ret);
// No existing pair in this Leaf matches the key, but we haven't maxxed out
// the Hamt depth yet. If we haven't hit the depth limit yet, we shouldn't
// be making a linked list of pairs. Turn the Leaf into a Stem and insert
// the new pair into the new Stem (also insert the pair in the existing
// Leaf, too).
} else {
// if we haven't hit depth limit yet we shouldn't be chaining
// we'll make a fake node pointing to the old leaf and "insert into" that
// Make a fake node pointing to the old leaf and "insert into it" the
// next time around
assert!(leaf.len == 1);
let fake_buffer = stack.struct_alloc(1);
*fake_buffer = Entry { leaf };
// get the mug chunk for the noun at *the next level* so
// we can build a fake stem for it
// Get the mug chunk for the Noun at the *next* level so that we can
// build a fake stem for it
let fake_mug = mug_u32(stack, (*leaf.buffer).0);
let fake_chunk = (fake_mug >> ((depth + 1) * 5)) & 0x1F;
let next_stem = Stem {

View File

@ -830,7 +830,7 @@ struct HotMem {
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) {
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;

View File

@ -159,7 +159,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
}

View File

@ -31,6 +31,24 @@ const CELL_TAG: u64 = u64::MAX & INDIRECT_MASK;
/** Tag mask for a cell. */
const CELL_MASK: u64 = !(u64::MAX >> 3);
/* A note on forwarding pointers:
*
* Forwarding pointers are only used temporarily during copies between NockStack frames and between
* the NockStack and the PMA. Since unifying equality checks can create structural sharing between
* Noun objects, forwarding pointers act as a signal that a Noun has already been copied to the
* "to" space. The old Noun object in the "from" space is given a forwarding pointer so that any
* future refernces to the same structure know that it has already been copied and that they should
* retain the structural sharing relationship by referencing the new copy in the "to" copy space.
*
* The Nouns in the "from" space marked with forwarding pointers are dangling pointers after a copy
* operation. No code outside of the copying code checks for forwarding pointers. This invariant
* must be enforced in two ways:
* 1. The current frame must be immediately popped after preserving data, when
* copying from a junior NockStack frame to a senior NockStack frame.
* 2. All persistent derived state (e.g. Hot state, Warm state) must be preserved
* and the root NockStack frame flipped after saving data to the PMA.
*/
/** Tag for a forwarding pointer */
const FORWARDING_TAG: u64 = u64::MAX & CELL_MASK;