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

WIP: Queue Gc's rather than recursively tracing them #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

helixbass
Copy link
Owner

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

@@ -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>>>>,
Copy link
Owner Author

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,
Copy link
Owner Author

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| {
Copy link
Owner Author

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
Copy link
Owner Author

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant