mmtk/policy/compressor/
forwarding.rsuse crate::policy::compressor::GC_MARK_BIT_MASK;
use crate::util::constants::BYTES_IN_WORD;
use crate::util::heap::MonotonePageResource;
use crate::util::linear_scan::{Region, RegionIterator};
use crate::util::metadata::side_metadata::spec_defs::{COMPRESSOR_MARK, COMPRESSOR_OFFSET_VECTOR};
use crate::util::metadata::side_metadata::SideMetadataSpec;
use crate::util::{Address, ObjectReference};
use crate::vm::object_model::ObjectModel;
use crate::vm::VMBinding;
use atomic::Ordering;
use std::marker::PhantomData;
use std::sync::atomic::AtomicBool;
#[derive(Debug)]
struct Transducer {
live: usize,
last_bit_visited: Address,
in_object: bool,
}
impl Transducer {
pub fn new() -> Self {
Self {
live: 0,
last_bit_visited: Address::ZERO,
in_object: false,
}
}
pub fn visit_mark_bit(&mut self, address: Address) {
if self.in_object {
let first_word = self.last_bit_visited;
let last_word = address;
let size = last_word - first_word + BYTES_IN_WORD;
self.live += size;
}
self.in_object = !self.in_object;
self.last_bit_visited = address;
}
pub fn encode(&self, current_position: Address) -> usize {
if self.in_object {
self.live + (current_position - self.last_bit_visited) + 1
} else {
self.live
}
}
pub fn decode(offset: usize, current_position: Address) -> Self {
Transducer {
live: offset & !1,
last_bit_visited: current_position,
in_object: (offset & 1) == 1,
}
}
}
pub struct ForwardingMetadata<VM: VMBinding> {
pub(crate) first_address: Address,
calculated: AtomicBool,
vm: PhantomData<VM>,
}
#[derive(Copy, Clone, PartialEq, PartialOrd)]
pub(crate) struct Block(Address);
impl Region for Block {
const LOG_BYTES: usize = 9;
fn from_aligned_address(address: Address) -> Self {
assert!(address.is_aligned_to(Self::BYTES));
Block(address)
}
fn start(&self) -> Address {
self.0
}
}
pub(crate) const MARK_SPEC: SideMetadataSpec = COMPRESSOR_MARK;
pub(crate) const OFFSET_VECTOR_SPEC: SideMetadataSpec = COMPRESSOR_OFFSET_VECTOR;
impl<VM: VMBinding> ForwardingMetadata<VM> {
pub fn new(start: Address) -> ForwardingMetadata<VM> {
ForwardingMetadata {
first_address: start,
calculated: AtomicBool::new(false),
vm: PhantomData,
}
}
pub fn mark_last_word_of_object(&self, object: ObjectReference) {
let last_word_of_object = object.to_object_start::<VM>()
+ VM::VMObjectModel::get_current_size(object)
- BYTES_IN_WORD;
#[cfg(debug_assertions)]
{
debug_assert!(
MARK_SPEC.are_different_metadata_bits(
object.to_object_start::<VM>(),
last_word_of_object
),
"The first and last mark bits should be different bits."
);
}
MARK_SPEC.fetch_or_atomic(last_word_of_object, GC_MARK_BIT_MASK, Ordering::SeqCst);
}
pub fn calculate_offset_vector(&self, pr: &MonotonePageResource<VM>) {
let mut state = Transducer::new();
let first_block = Block::from_aligned_address(self.first_address);
let last_block = Block::from_aligned_address(pr.cursor());
for block in RegionIterator::<Block>::new(first_block, last_block) {
OFFSET_VECTOR_SPEC.store_atomic::<usize>(
block.start(),
state.encode(block.start()),
Ordering::Relaxed,
);
MARK_SPEC.scan_non_zero_values::<u8>(
block.start(),
block.end(),
&mut |addr: Address| {
state.visit_mark_bit(addr);
},
);
}
self.calculated.store(true, Ordering::Relaxed);
}
pub fn release(&self) {
self.calculated.store(false, Ordering::Relaxed);
}
pub fn forward(&self, address: Address) -> Address {
debug_assert!(
self.calculated.load(Ordering::Relaxed),
"forward() should only be called when we have calculated an offset vector"
);
let block = Block::from_unaligned_address(address);
let mut state = Transducer::decode(
OFFSET_VECTOR_SPEC.load_atomic::<usize>(block.start(), Ordering::Relaxed),
block.start(),
);
MARK_SPEC.scan_non_zero_values::<u8>(block.start(), address, &mut |addr: Address| {
state.visit_mark_bit(addr)
});
self.first_address + state.live
}
pub fn scan_marked_objects(
&self,
start: Address,
end: Address,
f: &mut impl FnMut(ObjectReference),
) {
let mut in_object = false;
MARK_SPEC.scan_non_zero_values::<u8>(start, end, &mut |addr: Address| {
if !in_object {
let object = ObjectReference::from_raw_address(addr).unwrap();
f(object);
}
in_object = !in_object;
});
}
pub fn has_calculated_forwarding_addresses(&self) -> bool {
self.calculated.load(Ordering::Relaxed)
}
}