Skip to content
Merged
4 changes: 3 additions & 1 deletion mmtk/api/mmtk.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ extern int mmtk_object_is_managed_by_mmtk(void* addr);
extern void mmtk_runtime_panic(void);
extern void mmtk_unreachable(void);
extern unsigned char mmtk_pin_object(void* obj);
extern bool mmtk_is_pinned(void* obj);
extern bool mmtk_is_object_pinned(void* obj);
extern unsigned char mmtk_pin_pointer(void* ptr);
extern bool mmtk_is_pointer_pinned(void* ptr);
extern const char* get_mmtk_version(void);

extern void mmtk_set_vm_space(void* addr, size_t size);
Expand Down
116 changes: 104 additions & 12 deletions mmtk/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,39 +485,131 @@ pub extern "C" fn mmtk_get_obj_size(obj: ObjectReference) -> usize {
}
}

#[allow(unused_variables)]
fn assert_is_object(object: ObjectReference) {
// The checks are quite expensive. Dont run it in normal builds.
const ASSERT_OBJECT: bool = false;
if ASSERT_OBJECT {
#[cfg(debug_assertions)]
{
use crate::object_model::{is_object_in_immixspace, is_object_in_los};
if !mmtk_object_is_managed_by_mmtk(object.to_raw_address().as_usize()) {
panic!("{} is not managed by MMTk", object);
}
if !is_object_in_immixspace(&object) && !is_object_in_los(&object) {
// We will use VO bit in the following check. But if the object is not in immix space or LOS, we cannot do the check.
return;
}
if !object
.to_raw_address()
.is_aligned_to(ObjectReference::ALIGNMENT)
{
panic!(
"{} is not aligned, it cannot be an object reference",
object
)
}
if memory_manager::is_mmtk_object(object.to_raw_address()).is_none() {
error!("{} is not an object", object);
if let Some(base_ref) = memory_manager::find_object_from_internal_pointer(
object.to_raw_address(),
usize::MAX,
) {
panic!("{} is an internal pointer of {}", object, base_ref);
} else {
panic!(
"{} is not recognised as an object reference, or an internal reference",
object
);
}
}
}
}
}
#[no_mangle]
pub extern "C" fn mmtk_pin_object(object: ObjectReference) -> bool {
assert_is_object(object);
crate::early_return_for_non_moving_build!(false);
memory_manager::pin_object(object)
}

#[no_mangle]
pub extern "C" fn mmtk_unpin_object(object: ObjectReference) -> bool {
assert_is_object(object);
crate::early_return_for_non_moving_build!(false);
memory_manager::unpin_object(object)
}

#[no_mangle]
pub extern "C" fn mmtk_is_object_pinned(object: ObjectReference) -> bool {
assert_is_object(object);
crate::early_return_for_non_moving_build!(false);

// We may in the future replace this with a check for the immix space (bound check), which should be much cheaper.
if mmtk_object_is_managed_by_mmtk(object.to_raw_address().as_usize()) {
memory_manager::pin_object(object)
memory_manager::is_pinned(object)
}

macro_rules! handle_potential_internal_pointer {
($func: path, $addr: expr) => {{
if $addr.is_aligned_to(ObjectReference::ALIGNMENT) {
if let Some(obj) = memory_manager::is_mmtk_object($addr) {
return $func(obj);
}
}
let maybe_objref = memory_manager::find_object_from_internal_pointer($addr, usize::MAX);
if let Some(obj) = maybe_objref {
trace!(
"Attempt to pin {:?}, but it is an internal reference of {:?}",
$addr,
obj
);
$func(obj)
} else {
warn!(
"Attempt to pin {:?}, but it is not recognised as a object",
$addr
);
false
}
}};
}

#[no_mangle]
pub extern "C" fn mmtk_pin_pointer(addr: Address) -> bool {
crate::early_return_for_non_moving_build!(false);

if crate::object_model::is_addr_in_immixspace(addr) {
handle_potential_internal_pointer!(memory_manager::pin_object, addr)
} else {
debug!("Object is not managed by mmtk - (un)pinning it via this function isn't supported.");
debug!("Object is not in Immix space. MMTk will not move the object. No need to pin the object.");
false
}
}

#[no_mangle]
pub extern "C" fn mmtk_unpin_object(object: ObjectReference) -> bool {
pub extern "C" fn mmtk_unpin_pointer(addr: Address) -> bool {
crate::early_return_for_non_moving_build!(false);

if mmtk_object_is_managed_by_mmtk(object.to_raw_address().as_usize()) {
memory_manager::unpin_object(object)
if crate::object_model::is_addr_in_immixspace(addr) {
handle_potential_internal_pointer!(memory_manager::unpin_object, addr)
} else {
debug!("Object is not managed by mmtk - (un)pinning it via this function isn't supported.");
debug!("Object is not in Immix space. MMTk will not move the object. No need to unpin the object.");
false
}
}

#[no_mangle]
pub extern "C" fn mmtk_is_pinned(object: ObjectReference) -> bool {
pub extern "C" fn mmtk_is_pointer_pinned(addr: Address) -> bool {
crate::early_return_for_non_moving_build!(false);

if mmtk_object_is_managed_by_mmtk(object.to_raw_address().as_usize()) {
memory_manager::is_pinned(object)
if crate::object_model::is_addr_in_immixspace(addr) {
handle_potential_internal_pointer!(memory_manager::is_pinned, addr)
} else if !mmtk_object_is_managed_by_mmtk(addr.as_usize()) {
debug!(
"Object is not in Immix space. MMTk will not move the object. We assume it is pinned."
);
true
} else {
debug!("Object is not managed by mmtk - checking via this function isn't supported.");
debug!("Object is not managed by mmtk - checking pinning state via this function isn't supported.");
false
}
}
Expand Down
37 changes: 25 additions & 12 deletions mmtk/src/conservative.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::jl_task_stack_buffer;
use crate::julia_types::*;
use mmtk::memory_manager;
use mmtk::util::constants::BYTES_IN_ADDRESS;
Expand Down Expand Up @@ -44,24 +43,38 @@ pub unsafe fn mmtk_conservative_scan_task_stack(ta: *const jl_task_t) {
crate::early_return_for_non_moving_build!(());
crate::early_return_for_current_gc!();

let mut size: u64 = 0;
let mut ptid: i32 = 0;
log::debug!("mmtk_conservative_scan_native_stack begin ta = {:?}", ta);
let stk = unsafe { jl_task_stack_buffer(ta, &mut size as *mut _, &mut ptid as *mut _) };
let mut active_start = Address::ZERO;
let mut active_end = Address::ZERO;
let mut total_start = Address::ZERO;
let mut total_end = Address::ZERO;
unsafe {
crate::jl_active_task_stack(
ta,
&mut active_start as _,
&mut active_end as _,
&mut total_start as _,
&mut total_end as _,
)
};
log::debug!(
"mmtk_conservative_scan_native_stack continue stk = {}, size = {}, ptid = {:x}",
stk,
size,
ptid
"mmtk_conservative_scan_native_stack continue, active = {},{}, total = {},{}",
active_start,
active_end,
total_start,
total_end,
);
if !stk.is_zero() {

let size = active_end - active_start;

if !active_start.is_zero() {
log::debug!("Conservatively scan the stack");
// See jl_guard_size
// TODO: Are we sure there are always guard pages we need to skip?
const JL_GUARD_PAGE: usize = 4096 * 8;
let guard_page_start = stk + JL_GUARD_PAGE;
log::debug!("Skip guard page: {}, {}", stk, guard_page_start);
conservative_scan_range(guard_page_start, stk + size as usize);
let guard_page_start = active_start + JL_GUARD_PAGE;
log::debug!("Skip guard page: {}, {}", active_start, guard_page_start);
conservative_scan_range(guard_page_start, active_start + size);
} else {
log::warn!("Skip stack for {:?}", ta);
}
Expand Down
10 changes: 6 additions & 4 deletions mmtk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,13 @@ extern "C" {
pub fn jl_gc_get_owner_address_to_mmtk(m: Address) -> Address;
pub fn jl_gc_genericmemory_how(m: Address) -> usize;
pub fn jl_gc_get_max_memory() -> usize;
pub fn jl_task_stack_buffer(
pub fn jl_active_task_stack(
task: *const crate::julia_types::jl_task_t,
size: *mut u64,
ptid: *mut i32,
) -> Address;
active_start: *mut Address,
active_end: *mut Address,
total_start: *mut Address,
total_end: *mut Address,
);
pub static jl_true: *mut crate::julia_types::jl_value_t;
}

Expand Down