-
Notifications
You must be signed in to change notification settings - Fork 0
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
WIP: Queue Gc's rather than recursively tracing them #1
base: master
Are you sure you want to change the base?
Conversation
@@ -52,6 +52,7 @@ const ROOTS_MAX: usize = ROOTS_MASK; // max allowed value of roots | |||
pub(crate) struct GcBoxHeader { | |||
roots: Cell<usize>, // high bit is used as mark flag | |||
next: Cell<Option<NonNull<GcBox<dyn Trace>>>>, | |||
dyn_trace_ptr: Cell<Option<NonNull<GcBox<dyn Trace>>>>, |
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.
If NonNull<GcBox<dyn Trace>>
's are what it makes sense to put in the "queue" then I wasn't clear on how to get ahold of one at the time of calling Gc
's Trace::trace()
implementation (I seemed to be running into the fact that since there T
can be ?Sized
the compiler is saying it doesn't know how to make a trait object/fat pointer for something it doesn't know the size of or something along those lines?) so I resorted to storing one "up front" at the time of creation of Gc
/GcBox
/GcBoxHeader
Maybe another option to circumvent that would be to push closures (eg Box<dyn Fn()>
) onto a queue instead of NonNull<GcBox<dyn Trace>>
's?
} | ||
|
||
#[repr(C)] // to justify the layout computation in Gc::from_raw | ||
pub(crate) struct GcBox<T: Trace + ?Sized + 'static> { | ||
header: GcBoxHeader, | ||
pub header: GcBoxHeader, |
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.
Just doing dirty stuff to wire it up
while let Some(node) = mark_head { | ||
if (*node.as_ptr()).header.roots() > 0 { | ||
(*node.as_ptr()).trace_inner(); | ||
MARK_QUEUE.with(|queue| { |
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.
My understanding is that this head
is a linked list containing all currently known Gc
's effectively, and what we're interested in doing here is only marking + calling into the nested Trace::trace()
for ones that are rooted, and now we're trying to do that while avoiding "drilling down" into any nested Gc
's that we encounter during tracing (but we still need to accomplish marking them and calling into their nested Trace::trace()
's)
So the basic idea is to modify Gc
's Trace::trace()
implementation to "push itself onto a queue" that then gets processed as a second pass
} | ||
while let Some(node) = { | ||
let value = queue.borrow_mut().pop(); | ||
value |
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.
This is just boilerplate to convince the compiler to drop the mutable borrow before calling into the while
body (I don't know if there's a nicer/more idiomatic way to accomplish that)
This is addressing Manishearth#161
I doubt it would make sense to merge any version of this branch anywhere but am just opening it as a PR for the sake of being able to leave a couple comments