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

Support disjoint objects #663

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft

Support disjoint objects #663

wants to merge 1 commit into from

Conversation

wks
Copy link
Collaborator

@wks wks commented Sep 7, 2022

At this moment, I just drafted the interface for the VM.

The VM binding shall implement Scanning::handle_buffers, and MMTk core shall implement a plan-specific BufferHandler, pass it to the VM binding so it can call back. In Scanning::handle_buffers, the VM calls methods of BufferHandler to (1) retain an existing buffer, or (2) allocate a new buffer (GC thread cannot call Mutator::alloc, so this method should be necessary). I documented the contract (desired behaviour of the VM binding) in the comments.

What remains to be designed/implemented includes

  • Is the current handle_buffers sufficient to support all plans? (non-moving plans like MS, evacuating plans like SemiSpace, and MarkCompact)
  • When is handle_buffers called in each plan?

I think it is sufficient. My expectation is that "if the VM implements the Scanning::handle_buffers method as I specified in its comment, it should always work, regardless of the plan". But each plan may call that handle_buffers at different time to make use of it.

  • MarkSweep is trivial. Any time should be OK.
  • For SemiSpace and Immix, it should be called immediately before scanning an object (no matter if the VM chooses to do edge-enqueuing or object-enqueuing) so that the buffers are evacuated and the pointers to buffers are updated before the object is scanned.
  • For MarkCompact, it is a bit tricky. I think handle_buffers may be called during the forwarding phase (after objects are marked, but before both objects and buffers are copied). MarkCompact can hook into the BufferHandler implementation to work out the space needed to hold new buffers and their locations. But what should happen when the GC actually copies the buffer? Do all the objects and buffers need to be copied in any particular order? How to remember the sizes of buffers?

@steveblackburn
Copy link
Contributor

I don't understand the motivation for has_buffer and handle_buffer.

I think that the contract should be that responsibility lies entirely with the VM to identify any buffer when it scans the parent.

@wks
Copy link
Collaborator Author

wks commented Sep 9, 2022

I don't understand the motivation for has_buffer and handle_buffer.

I think that the contract should be that responsibility lies entirely with the VM to identify any buffer when it scans the parent.

I want to keep Scanning::scan_object(object, edge_visitor) serving the sole purpose of enumerating edges, but not identifying buffers or updating pointers to buffers.

It is useful in some cases. For example, for referencing-counting GC, we sometimes need to increment the RC of all neighbouring objects of an object. In this case, we just enumerate edges with scan_object(object, |edge| { inc_rc(edge.load()) }). It is not a good time to retain buffers or merging/splitting buffers because GC may not be in progress.

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.

2 participants