Skip to content

Add pointer pinning to handle internal pointers. Use jl_active_task_stack. #217

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 12 commits into from
Feb 5, 2025
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