Skip to content

Support for object pinning #703

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

Merged
merged 17 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/memory_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,45 @@ pub fn add_finalizer<VM: VMBinding>(
mmtk.finalizable_processor.lock().unwrap().add(object);
}

/// Pin an object. MMTk will make sure that the object does not move
/// during GC. Note that action cannot happen in some plans, eg, semispace.
/// It returns true if the pinning operation has been performed, i.e.,
/// the object status changed from non-pinned to pinned
///
/// Arguments:
/// * `object`: The object to be pinned
pub fn pin_object(object: ObjectReference) -> bool {
use crate::mmtk::SFT_MAP;
use crate::policy::sft_map::SFTMap;
SFT_MAP.get_checked(object.to_address()).pin_object(object)
}

/// Unpin an object.
/// Returns true if the unpinning operation has been performed, i.e.,
/// the object status changed from pinned to non-pinned
///
/// Arguments:
/// * `object`: The object to be pinned
pub fn unpin_object(object: ObjectReference) -> bool {
use crate::mmtk::SFT_MAP;
use crate::policy::sft_map::SFTMap;
SFT_MAP
.get_checked(object.to_address())
.unpin_object(object)
}

/// Check whether an object is currently pinned
///
/// Arguments:
/// * `object`: The object to be checked
pub fn is_pinned(object: ObjectReference) -> bool {
use crate::mmtk::SFT_MAP;
use crate::policy::sft_map::SFTMap;
SFT_MAP
.get_checked(object.to_address())
.is_object_pinned(object)
}

/// Get an object that is ready for finalization. After each GC, if any registered object is not
/// alive, this call will return one of the objects. MMTk will retain the liveness of those objects
/// until they are popped through this call. Once an object is popped, it is the responsibility of
Expand Down
12 changes: 12 additions & 0 deletions src/policy/copyspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ impl<VM: VMBinding> SFT for CopySpace<VM> {
!self.is_from_space() || object_forwarding::is_forwarded::<VM>(object)
}

fn pin_object(&self, _object: ObjectReference) -> bool {
panic!("Pinning and unpinning objects is not supported for CopySpace")
}

fn unpin_object(&self, _object: ObjectReference) -> bool {
panic!("Pinning and unpinning objects is not supported for CopySpace")
}

fn is_object_pinned(&self, _object: ObjectReference) -> bool {
panic!("Pinning and unpinning objects is not supported for CopySpace")
}

fn is_movable(&self) -> bool {
true
}
Expand Down
71 changes: 65 additions & 6 deletions src/policy/immix/immixspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,57 @@ impl<VM: VMBinding> SFT for ImmixSpace<VM> {
self.is_marked(object, self.mark_state) || ForwardingWord::is_forwarded::<VM>(object)
}
}
fn pin_object(&self, object: ObjectReference) -> bool {
debug_assert!(
!crate::util::object_forwarding::is_forwarded_or_being_forwarded::<VM>(object),
"Object to be unpinned should not be forwarded or being forwarded."
);

let res = VM::VMObjectModel::LOCAL_PINNING_BIT_SPEC.compare_exchange_metadata::<VM, u8>(
object,
0,
1,
None,
Ordering::SeqCst,
Ordering::SeqCst,
);

match res {
Ok(_) => true,
Err(_) => false,
}
}
fn unpin_object(&self, object: ObjectReference) -> bool {
debug_assert!(
!crate::util::object_forwarding::is_forwarded_or_being_forwarded::<VM>(object),
"Object to be unpinned should not be forwarded or being forwarded."
);

let res = VM::VMObjectModel::LOCAL_PINNING_BIT_SPEC.compare_exchange_metadata::<VM, u8>(
object,
1,
0,
None,
Ordering::SeqCst,
Ordering::SeqCst,
);

match res {
Ok(_) => true,
Err(_) => false,
}
}
fn is_object_pinned(&self, object: ObjectReference) -> bool {
if unsafe { VM::VMObjectModel::LOCAL_PINNING_BIT_SPEC.load::<VM, u8>(object, None) == 1 } {
return true;
}

return false;
}
fn is_movable(&self) -> bool {
super::DEFRAG
}

#[cfg(feature = "sanity")]
fn is_sane(&self) -> bool {
true
Expand Down Expand Up @@ -436,7 +484,11 @@ impl<VM: VMBinding> ImmixSpace<VM> {
) -> ObjectReference {
let copy_context = worker.get_copy_context_mut();
debug_assert!(!super::BLOCK_ONLY);
let forwarding_status = ForwardingWord::attempt_to_forward::<VM>(object);
let forwarding_status = if Self::is_pinned(object) {
0
} else {
ForwardingWord::attempt_to_forward::<VM>(object)
};
if ForwardingWord::state_is_forwarded_or_being_forwarded(forwarding_status) {
// We lost the forwarding race as some other thread has set the forwarding word; wait
// until the object has been forwarded by the winner. Note that the object may not
Expand Down Expand Up @@ -471,14 +523,18 @@ impl<VM: VMBinding> ImmixSpace<VM> {
"Forwarded object is the same as original object {} even though it should have been copied",
object,
);
ForwardingWord::clear_forwarding_bits::<VM>(object);
if !Self::is_pinned(object) {
ForwardingWord::clear_forwarding_bits::<VM>(object);
}
object
} else {
// We won the forwarding race; actually forward and copy the object if it is not pinned
// and we have sufficient space in our copy allocator
let new_object = if Self::is_pinned(object) || self.defrag.space_exhausted() {
self.attempt_mark(object, self.mark_state);
ForwardingWord::clear_forwarding_bits::<VM>(object);
if !Self::is_pinned(object) {
ForwardingWord::clear_forwarding_bits::<VM>(object);
}
Block::containing::<VM>(object).set_state(BlockState::Marked);
object
} else {
Expand Down Expand Up @@ -547,9 +603,12 @@ impl<VM: VMBinding> ImmixSpace<VM> {

/// Check if an object is pinned.
#[inline(always)]
fn is_pinned(_object: ObjectReference) -> bool {
// TODO(wenyuzhao): Object pinning not supported yet.
false
fn is_pinned(object: ObjectReference) -> bool {
use crate::mmtk::SFT_MAP;
use crate::policy::sft_map::SFTMap;
SFT_MAP
.get_checked(object.to_address())
.is_object_pinned(object)
}

/// Hole searching.
Expand Down
9 changes: 9 additions & 0 deletions src/policy/immortalspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ impl<VM: VMBinding> SFT for ImmortalSpace<VM> {
);
old_value == self.mark_state
}
fn pin_object(&self, _object: ObjectReference) -> bool {
false
}
fn unpin_object(&self, _object: ObjectReference) -> bool {
false
}
fn is_object_pinned(&self, _object: ObjectReference) -> bool {
false
}
fn is_movable(&self) -> bool {
false
}
Expand Down
9 changes: 9 additions & 0 deletions src/policy/largeobjectspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ impl<VM: VMBinding> SFT for LargeObjectSpace<VM> {
fn is_live(&self, object: ObjectReference) -> bool {
self.test_mark_bit(object, self.mark_state)
}
fn pin_object(&self, _object: ObjectReference) -> bool {
false
}
fn unpin_object(&self, _object: ObjectReference) -> bool {
false
}
fn is_object_pinned(&self, _object: ObjectReference) -> bool {
false
}
fn is_movable(&self) -> bool {
false
}
Expand Down
9 changes: 9 additions & 0 deletions src/policy/lockfreeimmortalspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ impl<VM: VMBinding> SFT for LockFreeImmortalSpace<VM> {
fn is_live(&self, _object: ObjectReference) -> bool {
unimplemented!()
}
fn pin_object(&self, _object: ObjectReference) -> bool {
unimplemented!()
}
fn unpin_object(&self, _object: ObjectReference) -> bool {
unimplemented!()
}
fn is_object_pinned(&self, _object: ObjectReference) -> bool {
unimplemented!()
}
fn is_movable(&self) -> bool {
unimplemented!()
}
Expand Down
12 changes: 12 additions & 0 deletions src/policy/mallocspace/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ impl<VM: VMBinding> SFT for MallocSpace<VM> {
is_marked::<VM>(object, Ordering::SeqCst)
}

fn pin_object(&self, _object: ObjectReference) -> bool {
false
}

fn unpin_object(&self, _object: ObjectReference) -> bool {
false
}

fn is_object_pinned(&self, _object: ObjectReference) -> bool {
false
}

fn is_movable(&self) -> bool {
false
}
Expand Down
12 changes: 12 additions & 0 deletions src/policy/markcompactspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ impl<VM: VMBinding> SFT for MarkCompactSpace<VM> {
Self::is_marked(object)
}

fn pin_object(&self, _object: ObjectReference) -> bool {
unimplemented!()
}

fn unpin_object(&self, _object: ObjectReference) -> bool {
unimplemented!()
}

fn is_object_pinned(&self, _object: ObjectReference) -> bool {
unimplemented!()
}

fn is_movable(&self) -> bool {
true
}
Expand Down
18 changes: 18 additions & 0 deletions src/policy/sft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ pub trait SFT {
self.is_live(object)
}

// Returns true if object status unpinned => pinned
fn pin_object(&self, object: ObjectReference) -> bool;

// Returns true if object status pinned => unpinned
fn unpin_object(&self, object: ObjectReference) -> bool;

// Returns true if object status is currently pinned
fn is_object_pinned(&self, object: ObjectReference) -> bool;

/// Is the object movable, determined by the policy? E.g. the policy is non-moving,
/// or the object is pinned.
fn is_movable(&self) -> bool;
Expand Down Expand Up @@ -130,6 +139,15 @@ impl SFT for EmptySpaceSFT {
warn!("Object in empty space!");
false
}
fn pin_object(&self, _object: ObjectReference) -> bool {
false
}
fn unpin_object(&self, _object: ObjectReference) -> bool {
false
}
fn is_object_pinned(&self, _object: ObjectReference) -> bool {
false
}
fn is_movable(&self) -> bool {
/*
* FIXME steveb I think this should panic (ie the function should not
Expand Down
4 changes: 4 additions & 0 deletions src/vm/object_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ pub trait ObjectModel<VM: VMBinding> {
const LOCAL_FORWARDING_BITS_SPEC: VMLocalForwardingBitsSpec;
/// The metadata specification for the mark bit, used by most plans that need to mark live objects. 1 bit.
const LOCAL_MARK_BIT_SPEC: VMLocalMarkBitSpec;
/// The metadata specification for the pinning bit, used by most plans that need to pin objects. 1 bit.
const LOCAL_PINNING_BIT_SPEC: VMLocalPinningBitSpec;
/// The metadata specification for the mark-and-nursery bits, used by most plans that has large object allocation. 2 bits.
const LOCAL_LOS_MARK_NURSERY_SPEC: VMLocalLOSMarkNurserySpec;

Expand Down Expand Up @@ -496,6 +498,8 @@ pub mod specs {
define_vm_metadata_spec!(VMLocalForwardingBitsSpec, false, 1, LOG_MIN_OBJECT_SIZE);
// Mark bit: 1 bit per object, local
define_vm_metadata_spec!(VMLocalMarkBitSpec, false, 0, LOG_MIN_OBJECT_SIZE);
// Pinning bit: 1 bit per object, local
define_vm_metadata_spec!(VMLocalPinningBitSpec, false, 0, LOG_MIN_OBJECT_SIZE);
// Mark&nursery bits for LOS: 2 bit per page, local
define_vm_metadata_spec!(VMLocalLOSMarkNurserySpec, false, 1, LOG_BYTES_IN_PAGE);
}