diff --git a/mmtk/api/mmtk.h b/mmtk/api/mmtk.h index 8e52239a..0c97a64f 100644 --- a/mmtk/api/mmtk.h +++ b/mmtk/api/mmtk.h @@ -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); diff --git a/mmtk/src/api.rs b/mmtk/src/api.rs index 819a1b71..08f0dafc 100644 --- a/mmtk/src/api.rs +++ b/mmtk/src/api.rs @@ -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 } } diff --git a/mmtk/src/conservative.rs b/mmtk/src/conservative.rs index 9e17ff10..2a251581 100644 --- a/mmtk/src/conservative.rs +++ b/mmtk/src/conservative.rs @@ -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; @@ -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); } diff --git a/mmtk/src/lib.rs b/mmtk/src/lib.rs index 9d6d7fbf..78365f38 100644 --- a/mmtk/src/lib.rs +++ b/mmtk/src/lib.rs @@ -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; }