-
Notifications
You must be signed in to change notification settings - Fork 75
Optimize object forwarding for single threaded GC #1283
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
base: master
Are you sure you want to change the base?
Conversation
1.74.1 failed to compile because icu4x started to require rust 1.81. Let's fix that separately. |
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.
Two high-level comments:
Firstly, we can skip the BEING_FORWARDED
state without affecting the callers in CopySpace and ImmixSpace. After calling attempt_to_forward
, the caller always calls state_is_forwarded_or_being_forwarded
to test if the return value is FORWARDING_NOT_TRIGGERED_YET
or other states (BEING_FORWARDED
or FORWARDED
), but in fact it can never observe BEING_FORWARDED
even we set the state to BEING_FORWARDED
in attempt_to_forward
. That's because if it is FORWARDING_NOT_TRIGGERED_YET
, the (only) GC worker will immediately try to forward the object, and it will either successfully copy the object and change the state to FORWARDED
, or decide not to copy the object and revert the state to FORWARDING_NOT_TRIGGERED_YET
. Then a subsequent invocation of attempt_to_forward
will either observe FORWARDED
or FORWARDING_NOT_TRIGGERED_YET
. So we can simply omit the store
in attempt_to_forward
.
Secondly, I think the "early exit" style is more readable than the current if-else
style.
.compare_exchange_metadata::<VM, u8>( | ||
if old_value == FORWARDING_NOT_TRIGGERED_YET { | ||
unsafe { | ||
VM::VMObjectModel::LOCAL_FORWARDING_BITS_SPEC.store::<VM, u8>( |
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 store
can be removed. The caller of attempt_to_forward
only needs the old_value
. As long as it is FORWARDING_NOT_TRIGGERED_YET
, the caller will immediately try to forward the object.
debug_assert!( | ||
forwarding_bits == FORWARDING_NOT_TRIGGERED_YET, | ||
forwarding_bits != BEING_FORWARDED, |
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.
We can just assert forwarding_bits == FORWARDED
if we don't use BEING_FORWARDED
.
@@ -21,22 +21,36 @@ const FORWARDING_POINTER_MASK: usize = 0xffff_fffc; | |||
/// Attempt to become the worker thread who will forward the object. | |||
/// The successful worker will set the object forwarding bits to BEING_FORWARDED, preventing other workers from forwarding the same object. | |||
pub fn attempt_to_forward<VM: VMBinding>(object: ObjectReference) -> u8 { | |||
loop { | |||
if cfg!(not(feature = "single_worker")) { |
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.
Having this if-else statement with not(feature = "single_worker")
as the condition makes the code a bit harder to read. Since it is simpler to do it with a single worker, we can rewrite it in the early exit style. For example,
pub fn attempt_to_forward<VM: VMBinding>(object: ObjectReference) -> u8 {
if cfg!(feature = "single_worker") {
return get_forwarding_status::<VM>(object); // Assume we remove BEING_FORWARDED.
}
// old code here
}
The problem is then I think the code for the multi-threaded object forwarding will still be in the generated binary leading to code bloat. I don't know if the Rust/LLVM compiler will remove that code if the |
No description provided.