-
Notifications
You must be signed in to change notification settings - Fork 122
Compacting GC: merge threading and marking #2641
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
Changes from all commits
1c79268
e46d16e
9e3eb55
7700a5c
35522c0
b7b83dc
6e316c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,12 +32,12 @@ fn test_<M: Memory>(mem: &mut M, n_objs: u32) -> TestCaseResult { | |
| alloc_mark_stack(mem); | ||
|
|
||
| for obj in &objs { | ||
| push_mark_stack(mem, *obj as usize); | ||
| push_mark_stack(mem, *obj as usize, obj.wrapping_sub(1)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is that an unskew?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really, I just wanted a value derived from Also explained this a little bit below. Do you have any ideas on how to update this test better?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, never mind, I didn't realize this was just dummy data.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (should have looked at the context)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given the signature (from below) Aren't the arguments above the wrong way round? Or is this a different push_mark_stack? I.e. shouldn't this call be:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this part is a bit hacky. Now that push needs a pointer + tag (u32) I needed to come up with something for the tag here. The mark stack doesn't care about the tag so just randomly used
Yeah I think making them distinct makes sense. I'll do that in a separate PR. |
||
| } | ||
|
|
||
| for obj in objs.iter().rev() { | ||
| for obj in objs.iter().copied().rev() { | ||
| let popped = pop_mark_stack(); | ||
| if popped != Some(*obj as usize) { | ||
| if popped != Some((obj as usize, obj.wrapping_sub(1))) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
| free_mark_stack(); | ||
| return Err(TestCaseError::Fail( | ||
| format!( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ | |
| //! otherwise things will break as we push. This invariant is checked in debug builds. | ||
|
|
||
| use crate::memory::{alloc_blob, Memory}; | ||
| use crate::types::{Blob, Words}; | ||
| use crate::types::{Blob, Tag, Words}; | ||
|
|
||
| use core::ptr::null_mut; | ||
|
|
||
|
|
@@ -50,20 +50,25 @@ unsafe fn grow_stack<M: Memory>(mem: &mut M) { | |
| (*STACK_BLOB_PTR).len = new_cap.to_bytes(); | ||
| } | ||
|
|
||
| pub unsafe fn push_mark_stack<M: Memory>(mem: &mut M, obj: usize) { | ||
| pub unsafe fn push_mark_stack<M: Memory>(mem: &mut M, obj: usize, obj_tag: Tag) { | ||
| // We add 2 words in a push, and `STACK_PTR` and `STACK_TOP` are both multiples of 2, so we can | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the size of the mark stack ever an issue? If so, would it be worth compressing the 4-tag bits into something smaller than a word or word alignment more important?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I had some benchmarks on mark stack sizes when I first implemented this GC, but those benchmarks were not realistic (more like micro benchmarks) so I should run that again on CanCan. In the worst case stack size will be |
||
| // do simple equality check here | ||
| if STACK_PTR == STACK_TOP { | ||
| grow_stack(mem); | ||
| } | ||
|
|
||
| *STACK_PTR = obj; | ||
| STACK_PTR = STACK_PTR.add(1); | ||
| *(STACK_PTR.add(1)) = obj_tag as usize; | ||
| STACK_PTR = STACK_PTR.add(2); | ||
| } | ||
|
|
||
| pub unsafe fn pop_mark_stack() -> Option<usize> { | ||
| pub unsafe fn pop_mark_stack() -> Option<(usize, Tag)> { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess you could return a sentinal, not an option, for perf, but perhaps not worth the effort.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe Rust even does that automatically? It does for some types, but the list doens't mention tuples :https://doc.rust-lang.org/std/option/#representation
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| if STACK_PTR == STACK_BASE { | ||
| None | ||
| } else { | ||
| STACK_PTR = STACK_PTR.sub(1); | ||
| Some(*STACK_PTR) | ||
| STACK_PTR = STACK_PTR.sub(2); | ||
| let p = *STACK_PTR; | ||
| let tag = *STACK_PTR.add(1); | ||
| Some((p, tag as u32)) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed this as it doesn't allow garbage in heap (as we don't want garbage after a GC). I should probably modify this to take a "post GC" parameter and check for garbage depending on that.