Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incremental GC (Intermediate Version) #3678

Closed
wants to merge 189 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
189 commits
Select commit Hold shift + click to select a range
f8dd690
Merge remote-tracking branch 'origin/osa1/write_barriers' into luc/ge…
luc-blaeser Oct 10, 2022
0677ff6
enhance Makefile
luc-blaeser Oct 20, 2022
c3fc867
Adjust write barrier for current code base
luc-blaeser Oct 10, 2022
6a04433
adjust write barrier to object level
luc-blaeser Oct 20, 2022
a1e853a
Also change to object level in the write barrier sanity checks
luc-blaeser Oct 20, 2022
0033c56
static elimination of unnecessary write barriers
luc-blaeser Oct 20, 2022
b95b795
reduce to object-level barrier
luc-blaeser Oct 21, 2022
b3546f1
reduce snapshot frequency, such that CI does not time out
luc-blaeser Oct 21, 2022
93f7904
Activate write barrier in CI and testing
luc-blaeser Oct 21, 2022
a3fe2dd
Revert "enhance Makefile"
luc-blaeser Oct 21, 2022
8dd8de3
reduce changes to copying GC
luc-blaeser Oct 21, 2022
a6edba5
adjust tests for memory snapshot and remembered set used in write bar…
luc-blaeser Oct 21, 2022
b95050c
update code documentation
luc-blaeser Oct 21, 2022
3a87e89
adjust perf test results for write barrier
luc-blaeser Oct 21, 2022
500a200
bug fix: no repeated sub-expression evaluation on write barriers
luc-blaeser Oct 21, 2022
c5ec02a
adjust perf-delta nix
luc-blaeser Oct 21, 2022
6e29183
extend static elimination of unnecessary barriers
luc-blaeser Oct 24, 2022
d9d5db8
improve static elimination of barriers
luc-blaeser Oct 24, 2022
3c9744c
further optimization of all barrier locations
luc-blaeser Oct 24, 2022
f3cdc73
fix sanity check to exclude true literal
luc-blaeser Oct 24, 2022
ad9b12c
remove empty tuple (failing cases in separate test branch)
luc-blaeser Oct 24, 2022
5a41c8d
fix array element type lookup for generic cases
luc-blaeser Oct 26, 2022
6bbebe2
change back to field-level barrier
luc-blaeser Oct 31, 2022
e52a73b
update specific instruction numbers in benchmark test
luc-blaeser Oct 31, 2022
559769b
remove unnecessary barriers on uninitialized fields of new objects
luc-blaeser Oct 31, 2022
c316129
Merge branch 'master' into luc/write-barrier
luc-blaeser Oct 31, 2022
5bcb705
update specific runtime instruction numbers in benchmark test
luc-blaeser Oct 31, 2022
d11bb07
in-place mark bit
luc-blaeser Nov 9, 2022
f86dc6a
add mark stack
luc-blaeser Nov 10, 2022
221cd09
update benchmark
luc-blaeser Nov 10, 2022
05a9279
Update code documentation
luc-blaeser Nov 10, 2022
06c2b60
reformat
luc-blaeser Nov 10, 2022
00c8d00
Fix debug assert in compacting GC
luc-blaeser Nov 11, 2022
6c43b3d
Merge branch 'master' into luc/mark-bit
luc-blaeser Nov 11, 2022
8031cfa
Merge branch 'master' into luc/mark-bit
luc-blaeser Nov 11, 2022
af0ae39
Merge branch 'luc/write-barrier' into luc/incremental-gc
luc-blaeser Nov 18, 2022
18d08ac
Merge branch 'luc/mark-bit' into luc/incremental-gc
luc-blaeser Nov 18, 2022
3e2b0e4
fix combined merge
luc-blaeser Nov 18, 2022
4c742ea
code refactoring
luc-blaeser Nov 18, 2022
59a8cb0
code restructuring
luc-blaeser Nov 18, 2022
07b8be9
add incremental gc option
luc-blaeser Nov 18, 2022
5403b49
remove remembered set, prepare for incremental gc mark
luc-blaeser Nov 18, 2022
d130303
prepare incremental gc
luc-blaeser Nov 18, 2022
d3cb3d8
starting with incremental gc
luc-blaeser Nov 18, 2022
668eed6
code refactoring
luc-blaeser Nov 18, 2022
28d0a27
Merge branch 'master' into luc/incremental-gc
luc-blaeser Nov 21, 2022
216e875
adjust mark scheme on allocation
luc-blaeser Nov 21, 2022
feeb486
refactor GC phases
luc-blaeser Nov 21, 2022
45d97b7
Incremental mark phase
luc-blaeser Nov 21, 2022
3d3a6c3
tune incremental GC run
luc-blaeser Nov 21, 2022
403ef1c
Mark completeness check
luc-blaeser Nov 21, 2022
94eba61
fix missing marking of new allocation
luc-blaeser Nov 21, 2022
d481be1
Remove log messages
luc-blaeser Nov 21, 2022
7c3d335
add unit test
luc-blaeser Nov 21, 2022
92dd36a
fix array slicing clearing in compiler
luc-blaeser Nov 21, 2022
f3cc3f6
Segregated free list, work in progress
luc-blaeser Nov 22, 2022
446b007
continue segregated free list
luc-blaeser Nov 22, 2022
a880586
continue segregated free list
luc-blaeser Nov 22, 2022
045ef03
add unit test for free list
luc-blaeser Nov 22, 2022
9bf4a01
add sanity check for free list
luc-blaeser Nov 22, 2022
e6f6838
fix error in free list split
luc-blaeser Nov 22, 2022
19a1662
continue segregated free list implementation
luc-blaeser Nov 23, 2022
1e89142
separating levels of heap allocation
luc-blaeser Nov 23, 2022
dcfeffb
update compiler for segregated free list
luc-blaeser Nov 23, 2022
99a216b
code refactoring
luc-blaeser Nov 23, 2022
b1f0c16
refine size classes
luc-blaeser Nov 23, 2022
9df4876
start sweep phase
luc-blaeser Nov 23, 2022
8bdb72e
more sanity checks
luc-blaeser Nov 23, 2022
0cbb3c1
fix bug in test case
luc-blaeser Nov 23, 2022
6a87555
fix concurrent marking logic
luc-blaeser Nov 23, 2022
e224e28
reformat
luc-blaeser Nov 23, 2022
dddfd29
adjust marking new allocations
luc-blaeser Nov 24, 2022
dab7339
fix test case, add more sanity checks
luc-blaeser Nov 24, 2022
7a91cc3
adjust gc scheduling
luc-blaeser Nov 24, 2022
7355c04
adjust compiler to mark new allocations
luc-blaeser Nov 24, 2022
791bc5f
fix compiler bug
luc-blaeser Nov 24, 2022
3a68b8c
adjust free list, add unit test for overflow list
luc-blaeser Nov 24, 2022
f20a82d
adjust unit tests that check exact heap sizes
luc-blaeser Nov 24, 2022
a0ac0d3
Merge branch 'master' into luc/incremental-gc
luc-blaeser Nov 28, 2022
d7674db
continue merge generational with incremental gc
luc-blaeser Nov 28, 2022
38c65c4
update benchmark cases
luc-blaeser Nov 28, 2022
945d7e7
split too large test case
luc-blaeser Nov 28, 2022
c352140
fix issue for mark new allocation
luc-blaeser Nov 28, 2022
8b76370
adjust assertion check
luc-blaeser Nov 28, 2022
66ade5e
adjust memory sanity check
luc-blaeser Nov 28, 2022
395d4b3
avoid fragmentation issue in test
luc-blaeser Nov 28, 2022
513ef9b
adjust increment counter
luc-blaeser Nov 28, 2022
38e0f40
Adjust memory sanity check
luc-blaeser Nov 28, 2022
1ee3ebd
Adjust memory sanity check
luc-blaeser Nov 29, 2022
c784bda
Incremental free block merging
luc-blaeser Nov 29, 2022
977c3b2
More incremental mark phase
luc-blaeser Nov 29, 2022
44433e3
Differentiate increments
luc-blaeser Nov 29, 2022
61b8655
Adjust allocation statistics
luc-blaeser Nov 29, 2022
04a584a
update memory statistics
luc-blaeser Nov 29, 2022
3f25db5
GC increment on mutator allocation
luc-blaeser Nov 29, 2022
236164c
Tune GC increment limit
luc-blaeser Nov 29, 2022
3b9389f
Update empty-actor.mo
luc-blaeser Nov 29, 2022
ea0e12d
Support incremental array marking in sanity check
luc-blaeser Nov 30, 2022
66544fe
Fix mark completeness check
luc-blaeser Nov 30, 2022
e20977e
Adjust statistics
luc-blaeser Nov 30, 2022
2688c94
adjust statistics test case
luc-blaeser Nov 30, 2022
c3e04b0
adjust statistics test case
luc-blaeser Nov 30, 2022
5f5e6d7
Adjust test case that takes too long
luc-blaeser Nov 30, 2022
afc816d
Skip ic-ref-run where taking too long
luc-blaeser Nov 30, 2022
35da50d
adjust tests not to exceed batch limit
luc-blaeser Nov 30, 2022
1baa5dd
Stop GC on upgrade
luc-blaeser Nov 30, 2022
3533984
Merge branch 'master' into luc/incremental-gc
luc-blaeser Dec 1, 2022
bfd26f1
Adjust upgrade mode
luc-blaeser Dec 1, 2022
6b886ba
Adjust benchmark cases
luc-blaeser Dec 1, 2022
c73b527
Refactor write barrier
luc-blaeser Dec 1, 2022
e5de2d2
simplify memory allocation design
luc-blaeser Dec 1, 2022
b9f85ec
restructure test for generational and incremental GC
luc-blaeser Dec 1, 2022
2115ff3
unify gc and memory initialization
luc-blaeser Dec 1, 2022
079a77d
refactor incremental GC initialization
luc-blaeser Dec 1, 2022
05c07e0
redesign allocation increment
luc-blaeser Dec 1, 2022
2f1286b
unify blob allocation across GCs
luc-blaeser Dec 1, 2022
489c1ac
Update comments
luc-blaeser Dec 1, 2022
bc69b5d
Fix compiler issue about GC selection
luc-blaeser Dec 1, 2022
454281c
Redesign incremental GC
luc-blaeser Dec 1, 2022
22a3fd1
code refactoring
luc-blaeser Dec 1, 2022
de6301e
Some code cleanup
luc-blaeser Dec 1, 2022
536f307
Ignore checker message
luc-blaeser Dec 1, 2022
aa43a9b
code refactoring
luc-blaeser Dec 1, 2022
7154c6d
Code refactoring
luc-blaeser Dec 1, 2022
f418c2e
Code refactoring
luc-blaeser Dec 1, 2022
476561c
Undo design change for simplification
luc-blaeser Dec 2, 2022
27f8f7d
Merge branch 'master' into luc/incremental-gc
luc-blaeser Dec 2, 2022
6d9e4c4
Redesign incremental GC
luc-blaeser Dec 2, 2022
cd1ecd5
Adjust increments, refactoring
luc-blaeser Dec 2, 2022
892d250
Adjust benchmark test
luc-blaeser Dec 2, 2022
38a98e8
skip overly long running ic-ref-ref tests
luc-blaeser Dec 2, 2022
4cb47fd
Redesign: get limits and roots from memory
luc-blaeser Dec 2, 2022
f5991df
Take memory redesign for limits to separate branch
luc-blaeser Dec 2, 2022
da89e2e
Change assertions to debug assertions
luc-blaeser Dec 2, 2022
7d9c65d
tune incremental gc, update statistics
luc-blaeser Dec 2, 2022
0c6ffaf
Remove print lines
luc-blaeser Dec 2, 2022
424b7b3
use heap occupation for GC scheduling
luc-blaeser Dec 5, 2022
a14a4cb
adjust scheduling heuristics
luc-blaeser Dec 5, 2022
629d8b0
enable GC increment on write barrier
luc-blaeser Dec 5, 2022
76413fd
conditional compilation of mark new allocation
luc-blaeser Dec 5, 2022
d88e3e5
Optimize free list allocation lookup
luc-blaeser Dec 5, 2022
edfd8fb
Use binary search for free list selection
luc-blaeser Dec 5, 2022
51f5f39
Optimize free list when empty
luc-blaeser Dec 5, 2022
593f7e8
reformat
luc-blaeser Dec 6, 2022
ccbeec2
adjust size classes
luc-blaeser Dec 6, 2022
a29d382
Fix bug in compiler
luc-blaeser Dec 6, 2022
5a7b564
update benchmark numbers
luc-blaeser Dec 6, 2022
19ac17b
fix bug in incremental GC
luc-blaeser Dec 6, 2022
2875db3
Bug fix in mark stack
luc-blaeser Dec 6, 2022
e461804
Skip too slow ic-ref-run
luc-blaeser Dec 6, 2022
4852485
Reducing number of size classes for performance
luc-blaeser Dec 6, 2022
f07587d
Simplification: Remove fast forwarding
luc-blaeser Dec 6, 2022
2c5b02a
Simplification and optimization: Remove binary search
luc-blaeser Dec 6, 2022
241b6d5
Simplify free list allocation
luc-blaeser Dec 7, 2022
eee64d6
Simplify free list, remove double linking
luc-blaeser Dec 7, 2022
90413c3
Optimization: Remove allocation and barrier increments
luc-blaeser Dec 7, 2022
603bfde
Tune increments for smooth pauses
luc-blaeser Dec 7, 2022
b7a7681
Tune GC increments, shorter pauses
luc-blaeser Dec 7, 2022
fd840e0
Optimize write barrier
luc-blaeser Dec 7, 2022
e2b164b
Adjust mark stack blob to 4096 bytes
luc-blaeser Dec 7, 2022
cac2a0e
Reintroduce allocation increment
luc-blaeser Dec 7, 2022
9fcc7db
Reintroduce doubly linked free list
luc-blaeser Dec 7, 2022
b65a2ad
Code refactoring, optimization
luc-blaeser Dec 7, 2022
16d18a9
Merge branch 'master' into luc/incremental-gc
luc-blaeser Dec 8, 2022
f189576
Tuning GC increments
luc-blaeser Dec 8, 2022
b5677b6
Tuning incremental GC
luc-blaeser Dec 8, 2022
408b2f7
Adjust incremental GC scheduling heuristics
luc-blaeser Dec 9, 2022
ce75453
Merge branch 'master' into luc/incremental-gc
luc-blaeser Dec 9, 2022
4164c2b
Tuning GC increment limits
luc-blaeser Dec 9, 2022
079d761
Adjust free block linking initialization
luc-blaeser Dec 9, 2022
296070f
Adjust GC increment limits
luc-blaeser Dec 9, 2022
e0f53f7
Adjust increment limits
luc-blaeser Dec 9, 2022
b8c4cfa
Optimize free list allocation
luc-blaeser Dec 9, 2022
1ac798c
Tuning GC increment limits
luc-blaeser Dec 9, 2022
f7ced8a
Bug fix in free list optimization
luc-blaeser Dec 9, 2022
d9263b4
Tune incremental GC scheduling
luc-blaeser Dec 9, 2022
e9426a1
Exclude slow ic-ref-run test
luc-blaeser Dec 9, 2022
53ae8f9
Tune incremental GC scheduling
luc-blaeser Dec 9, 2022
8e71c2b
Tuning GC increment
luc-blaeser Dec 9, 2022
245f6c2
Adjust GC increment
luc-blaeser Dec 9, 2022
cf8f775
Adjust GC increments
luc-blaeser Dec 9, 2022
1dff8e3
Adjust GC increments
luc-blaeser Dec 9, 2022
6bcd6d8
Introduce allocation incremen
luc-blaeser Dec 9, 2022
1f02301
Simplify GC increment
luc-blaeser Dec 9, 2022
f94add7
Merge branch 'master' into luc/incremental-gc
luc-blaeser Dec 12, 2022
2eee9db
Update benchmark results
luc-blaeser Dec 12, 2022
494f260
Tune GC
luc-blaeser Dec 12, 2022
f3b67aa
Merge branch 'master' into luc/incremental-gc
luc-blaeser Dec 22, 2022
30dbc5e
Merge branch 'master' into luc/incremental-gc-intermediate
luc-blaeser Jan 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion default.nix
Expand Up @@ -367,6 +367,11 @@ rec {
EXTRA_MOC_ARGS = "--sanity-checks --compacting-gc";
});

incremental_gc_subdir = dir: deps:
(test_subdir dir deps).overrideAttrs (args: {
EXTRA_MOC_ARGS = "--sanity-checks --incremental-gc";
});

generational_gc_subdir = dir: deps:
(test_subdir dir deps).overrideAttrs (args: {
EXTRA_MOC_ARGS = "--sanity-checks --generational-gc";
Expand Down Expand Up @@ -484,11 +489,12 @@ rec {
run-dbg = snty_subdir "run" [ moc ] ;
ic-ref-run = test_subdir "run-drun" [ moc ic-ref-run ];
ic-ref-run-compacting-gc = compacting_gc_subdir "run-drun" [ moc ic-ref-run ] ;
ic-ref-run-generational-gc = generational_gc_subdir "run-drun" [ moc ic-ref-run ] ;
ic-ref-run-incremental-gc = incremental_gc_subdir "run-drun" [ moc ic-ref-run ] ;
drun = test_subdir "run-drun" [ moc nixpkgs.drun ];
drun-dbg = snty_subdir "run-drun" [ moc nixpkgs.drun ];
drun-compacting-gc = compacting_gc_subdir "run-drun" [ moc nixpkgs.drun ] ;
drun-generational-gc = generational_gc_subdir "run-drun" [ moc nixpkgs.drun ] ;
drun-incremental-gc = incremental_gc_subdir "run-drun" [ moc nixpkgs.drun ] ;
fail = test_subdir "fail" [ moc ];
repl = test_subdir "repl" [ moc ];
ld = test_subdir "ld" ([ mo-ld ] ++ ldTestDeps);
Expand Down
3 changes: 2 additions & 1 deletion doc/md/compiler-ref.md
Expand Up @@ -34,8 +34,9 @@ You can use the following options with the `moc` command.
| `-help`,`--help` | Displays usage information. |
| `--hide-warnings` | Hides compiler warnings. |
| `-Werror` | Treat warnings as errors. |
| `--idl` | Compile binary and emit Candid IDL specification to `.did` file. |
| `-i` | Runs the compiler in an interactive read–eval–print loop (REPL) shell so you can evaluate program execution (implies -r). |
| `--incremental-gc` | Use incremental GC |
| `--idl` | Compile binary and emit Candid IDL specification to `.did` file. |
| `--map` | Outputs a JavaScript source map. |
| `--max-stable-pages <n>` | Set maximum number of pages available for library `ExperimentStableMemory.mo` (default 65536). |
| `-no-system-api` | Disables system API imports. |
Expand Down
139 changes: 95 additions & 44 deletions rts/motoko-rts-tests/src/gc.rs
Expand Up @@ -8,6 +8,7 @@
mod compacting;
mod generational;
mod heap;
mod incremental;
mod random;
mod utils;

Expand All @@ -17,7 +18,8 @@ use motoko_rts::gc::generational::write_barrier::{LAST_HP, REMEMBERED_SET};
use utils::{get_scalar_value, read_word, unskew_pointer, ObjectIdx, GC, GC_IMPLS, WORD_SIZE};

use motoko_rts::gc::copying::copying_gc_internal;
use motoko_rts::gc::generational::{GenerationalGC, Limits, Roots, Strategy};
use motoko_rts::gc::generational::{GenerationalGC, Strategy};
use motoko_rts::gc::incremental::IncrementalGC;
use motoko_rts::gc::mark_compact::compacting_gc_internal;
use motoko_rts::types::*;

Expand All @@ -26,6 +28,10 @@ use std::fmt::Write;
use fxhash::{FxHashMap, FxHashSet};

pub fn test() {
unsafe {
incremental::test();
}

println!("Testing garbage collection ...");

println!(" Testing pre-defined heaps...");
Expand Down Expand Up @@ -113,6 +119,11 @@ fn test_gc(
roots: &[ObjectIdx],
continuation_table: &[ObjectIdx],
) {
if gc == GC::Incremental {
unsafe {
IncrementalGC::<MotokoHeap>::initialize();
}
}
let mut heap = MotokoHeap::new(refs, roots, continuation_table, gc);

// Check `create_dynamic_heap` sanity
Expand All @@ -125,6 +136,7 @@ fn test_gc(
heap.heap_base_offset(),
heap.heap_ptr_offset(),
heap.continuation_table_ptr_offset(),
false,
);

for round in 0..3 {
Expand All @@ -134,16 +146,22 @@ fn test_gc(
let heap_ptr_offset = heap.heap_ptr_offset();
let continuation_table_ptr_offset = heap.continuation_table_ptr_offset();
check_dynamic_heap(
check_all_reclaimed, // after gc
check_all_reclaimed, // check for unreachable objects
refs,
roots,
continuation_table,
&**heap.heap(),
heap_base_offset,
heap_ptr_offset,
continuation_table_ptr_offset,
gc == GC::Incremental,
);
}
if gc == GC::Incremental {
unsafe {
IncrementalGC::<MotokoHeap>::initialize();
}
}
}

/// Check the dynamic heap:
Expand All @@ -164,6 +182,7 @@ fn check_dynamic_heap(
heap_base_offset: usize,
heap_ptr_offset: usize,
continuation_table_ptr_offset: usize,
incremental: bool,
) {
let objects_map: FxHashMap<ObjectIdx, &[ObjectIdx]> = objects
.iter()
Expand Down Expand Up @@ -193,49 +212,65 @@ fn check_dynamic_heap(
continue;
}

let tag = read_word(heap, offset);
offset += WORD_SIZE;

assert_eq!(tag, TAG_ARRAY);

let n_fields = read_word(heap, offset);
offset += WORD_SIZE;
let raw_tag = read_word(heap, offset);
if incremental && !is_marked(raw_tag) && raw_tag > TAG_FREE_BLOCK_MIN {
// skip free block
let size = Words(raw_tag - TAG_FREE_BLOCK_MIN);
offset += size.to_bytes().as_usize();
} else {
let tag = unmark(raw_tag);
offset += WORD_SIZE;
if incremental && tag == TAG_BLOB {
// in-heap mark stack blobs
let length = read_word(heap, offset);
offset += WORD_SIZE + length as usize;
} else {
if incremental {
assert!(tag == TAG_ARRAY || tag >= TAG_ARRAY_SLICE_MIN);
} else {
assert_eq!(tag, TAG_ARRAY);
}

// There should be at least one field for the index
assert!(n_fields >= 1);
let n_fields = read_word(heap, offset);
offset += WORD_SIZE;

let object_idx = get_scalar_value(read_word(heap, offset));
offset += WORD_SIZE;
let old = seen.insert(object_idx, address);
if let Some(old) = old {
panic!(
"Object with index {} seen multiple times: {:#x}, {:#x}",
object_idx, old, address
);
}
// There should be at least one field for the index
assert!(n_fields >= 1);

let object_expected_pointees = objects_map.get(&object_idx).unwrap_or_else(|| {
panic!("Object with index {} is not in the objects map", object_idx)
});
let object_idx = get_scalar_value(read_word(heap, offset));
offset += WORD_SIZE;
let old = seen.insert(object_idx, address);
if let Some(old) = old {
panic!(
"Object with index {} seen multiple times: {:#x}, {:#x}",
object_idx, old, address
);
}

for field_idx in 1..n_fields {
let field = read_word(heap, offset);
offset += WORD_SIZE;
// Get index of the object pointed by the field
let pointee_address = field.wrapping_add(1); // unskew
let pointee_offset = (pointee_address as usize) - (heap.as_ptr() as usize);
let pointee_idx_offset = pointee_offset as usize + 2 * WORD_SIZE; // skip header + length
let pointee_idx = get_scalar_value(read_word(heap, pointee_idx_offset));
let expected_pointee_idx = object_expected_pointees[(field_idx - 1) as usize];
assert_eq!(
pointee_idx,
expected_pointee_idx,
"Object with index {} points to {} in field {}, but expected to point to {}",
object_idx,
pointee_idx,
field_idx - 1,
expected_pointee_idx,
);
let object_expected_pointees = objects_map.get(&object_idx).unwrap_or_else(|| {
panic!("Object with index {} is not in the objects map", object_idx)
});

for field_idx in 1..n_fields {
let field = read_word(heap, offset);
offset += WORD_SIZE;
// Get index of the object pointed by the field
let pointee_address = field.wrapping_add(1); // unskew
let pointee_offset = (pointee_address as usize) - (heap.as_ptr() as usize);
let pointee_idx_offset = pointee_offset as usize + 2 * WORD_SIZE; // skip header + length
let pointee_idx = get_scalar_value(read_word(heap, pointee_idx_offset));
let expected_pointee_idx = object_expected_pointees[(field_idx - 1) as usize];
assert_eq!(
pointee_idx,
expected_pointee_idx,
"Object with index {} points to {} in field {}, but expected to point to {}",
object_idx,
pointee_idx,
field_idx - 1,
expected_pointee_idx,
);
}
}
}
}

Expand Down Expand Up @@ -317,7 +352,7 @@ fn compute_reachable_objects(
}

fn check_continuation_table(mut offset: usize, continuation_table: &[ObjectIdx], heap: &[u8]) {
assert_eq!(read_word(heap, offset), TAG_ARRAY);
assert_eq!(unmark(read_word(heap, offset)), TAG_ARRAY);
offset += WORD_SIZE;

assert_eq!(read_word(heap, offset), continuation_table.len() as u32);
Expand Down Expand Up @@ -394,12 +429,12 @@ impl GC {
REMEMBERED_SET = Some(RememberedSet::new(heap));
LAST_HP = heap_1.last_ptr_address() as u32;

let limits = Limits {
let limits = motoko_rts::gc::generational::Limits {
base: heap_base as usize,
last_free: heap_1.last_ptr_address(),
free: heap_1.heap_ptr_address(),
};
let roots = Roots {
let roots = motoko_rts::gc::generational::Roots {
static_roots,
continuation_table_ptr_loc: continuation_table_ptr_address,
};
Expand All @@ -416,6 +451,22 @@ impl GC {
}
round >= 2
}

GC::Incremental => unsafe {
const INCREMENTS_UNTIL_COMPLETION: usize = 16;
for _ in 0..INCREMENTS_UNTIL_COMPLETION {
let limits = motoko_rts::gc::incremental::Limits {
base: heap_base as usize,
free: heap_1.heap_ptr_address(),
};
let roots = motoko_rts::gc::incremental::Roots {
static_roots,
continuation_table: *continuation_table_ptr_address,
};
IncrementalGC::instance(heap).empty_call_stack_increment(limits, roots);
}
false
},
}
}
}
4 changes: 3 additions & 1 deletion rts/motoko-rts-tests/src/gc/generational.rs
@@ -1,8 +1,10 @@
mod mark_stack;
mod remembered_set;

pub fn test() {
println!("Testing generational GC components ...");
println!("Testing generational GC ...");
unsafe {
mark_stack::test();
remembered_set::test();
}
}
2 changes: 1 addition & 1 deletion rts/motoko-rts-tests/src/gc/generational/mark_stack.rs
Expand Up @@ -10,7 +10,7 @@ use motoko_rts::types::*;
use proptest::test_runner::{Config, TestCaseError, TestCaseResult, TestRunner};

pub unsafe fn test() {
println!(" Testing generational GC mark stack ...");
println!(" Testing mark stack ...");

test_push_pop();
test_grow_stack();
Expand Down
Expand Up @@ -9,7 +9,7 @@ use motoko_rts::types::{Value, Words};
const GROW_LIMIT: u32 = INITIAL_TABLE_LENGTH * OCCUPATION_THRESHOLD_PERCENT / 100;

pub unsafe fn test() {
println!("Testing remembered set ...");
println!(" Testing remembered set ...");

test_remembered_set(0);
test_remembered_set(1);
Expand All @@ -31,8 +31,6 @@ unsafe fn test_remembered_set(amount: u32) {
}

unsafe fn test_insert_iterate(amount: u32) {
println!(" Testing insert/iterate {amount}");

let mut mem = TestMemory::new(Words(2 * amount + 1024 * 1024));

let mut remembered_set = RememberedSet::new(&mut mem);
Expand All @@ -54,8 +52,6 @@ unsafe fn test_insert_iterate(amount: u32) {
}

unsafe fn test_duplicates(amount: u32) {
println!(" Testing duplicates {amount}");

let mut mem = TestMemory::new(Words(2 * amount + 1024 * 1024));

let mut remembered_set = RememberedSet::new(&mut mem);
Expand All @@ -72,8 +68,6 @@ unsafe fn test_duplicates(amount: u32) {
}

unsafe fn test_collisions(amount: u32) {
println!(" Testing collisions {amount}");

let mut mem = TestMemory::new(Words(2 * amount + 1024 * 1024));

let mut remembered_set = RememberedSet::new(&mut mem);
Expand Down
12 changes: 10 additions & 2 deletions rts/motoko-rts-tests/src/gc/heap.rs
Expand Up @@ -20,7 +20,11 @@ pub struct MotokoHeap {
}

impl Memory for MotokoHeap {
unsafe fn alloc_words(&mut self, n: Words<u32>) -> Value {
unsafe fn allocate(&mut self, n: Words<u32>) -> Value {
self.grow_heap(n)
}

unsafe fn grow_heap(&mut self, n: Words<u32>) -> Value {
self.inner.borrow_mut().alloc_words(n)
}
}
Expand Down Expand Up @@ -235,7 +239,7 @@ impl MotokoHeapInner {
// MarkCompact assumes that the dynamic heap starts at a 32-byte multiple
let realign = match gc {
GC::Copying => 0,
GC::MarkCompact | GC::Generational => {
GC::MarkCompact | GC::Generational | GC::Incremental => {
(32 - (heap.as_ptr() as usize + static_heap_size_bytes) % 32) % 32
}
};
Expand Down Expand Up @@ -338,6 +342,10 @@ fn heap_size_for_gc(
);
size + ROUNDS * REMEMBERED_SET_MAXIMUM_SIZE
}
GC::Incremental => {
const MARK_STACK_SIZE: usize = 1024 * 1024;
total_heap_size_bytes + MARK_STACK_SIZE
}
}
}

Expand Down
10 changes: 10 additions & 0 deletions rts/motoko-rts-tests/src/gc/incremental.rs
@@ -0,0 +1,10 @@
mod free_list;
mod mark_bit;
mod mark_stack;

pub unsafe fn test() {
println!("Testing incremental GC ...");
free_list::test();
mark_bit::test();
mark_stack::test();
}