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

Better rooting strategies #1

Open
withoutboats opened this issue Oct 11, 2018 · 1 comment
Open

Better rooting strategies #1

withoutboats opened this issue Oct 11, 2018 · 1 comment

Comments

@withoutboats
Copy link
Owner

withoutboats commented Oct 11, 2018

Currently shifgrethor's GC implementation uses an intrusively doubly linked list of roots. This is copied from other previous GC implementations in Rust (its been pointed out to me that this is mostly because GC implementations have been by Mozilla people, and this is how Spidermonkey tracks dynamic roots).

This rooting strategy has some downsides. One is that you have to trace around the entire program while rooting: it has essentially the worst memory locality possible. Another is that every root is three times as large as a normal pointer.

In languages without an unmanaged heap, roots are often tracked through stack maps: compile time generated records of which addresses in each stack frame are roots. The tracer walks the stack using the map associated with each stack frame to find the roots in that frame. This strategy has some problems for us: its not clear how to implement this in a library, and Rust has an unmanaged heap, which necessarily can't be mapped at compile time.

I have an idea for a way to manage stack roots that I think is better. Stack roots are by design tied to a particular stack frame with a 'root lifetime, meaning the pointer that they root cannot escape that stackframe. In fact, the Gc pointer you get from a stack root doesn't contain any root metadata at all, there's an entirely separate pointer in the StackRoot type which is only accessed by the GC's tracing algorithm, and never the user.

An alternative design would be to maintain a global stack of roots somewhere in the heap. Every time we make a GC allocation using the StackRoot API, we push a new root onto that stack. When the StackRoot type drops, we pop that root. Instead of bouncing around the real stack, the GC tracer just iterates up the stack of roots.

I think this can be done with an identical API to the one we have now, but it might even be more flexible and require less macro magic. I think maybe we can have a normal StackRoot::new function and I think we can allow returning a stack rooted pointer as long as you return the root with it. This would require the stack of roots to not be strictly a stack, but instead allow out of order nulling of roots, because destructors could run out of order.

@withoutboats
Copy link
Owner Author

Implemented in 17f1803

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

No branches or pull requests

1 participant