Skip to content

Commit 9775aae

Browse files
committed
Add pointer pinning to handle internal pointers. Use jl_active_task_stack. (#217)
This PR adds pinning that handles internal pointers. It also uses `jl_active_task_stack` for stack scanning instead of `jl_task_stack_buffer`.
1 parent 5c8f1b8 commit 9775aae

File tree

4 files changed

+138
-29
lines changed

4 files changed

+138
-29
lines changed

mmtk/api/mmtk.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ extern int mmtk_object_is_managed_by_mmtk(void* addr);
4949
extern void mmtk_runtime_panic(void);
5050
extern void mmtk_unreachable(void);
5151
extern unsigned char mmtk_pin_object(void* obj);
52-
extern bool mmtk_is_pinned(void* obj);
52+
extern bool mmtk_is_object_pinned(void* obj);
53+
extern unsigned char mmtk_pin_pointer(void* ptr);
54+
extern bool mmtk_is_pointer_pinned(void* ptr);
5355
extern const char* get_mmtk_version(void);
5456

5557
extern void mmtk_set_vm_space(void* addr, size_t size);

mmtk/src/api.rs

Lines changed: 104 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -485,39 +485,131 @@ pub extern "C" fn mmtk_get_obj_size(obj: ObjectReference) -> usize {
485485
}
486486
}
487487

488+
#[allow(unused_variables)]
489+
fn assert_is_object(object: ObjectReference) {
490+
// The checks are quite expensive. Dont run it in normal builds.
491+
const ASSERT_OBJECT: bool = false;
492+
if ASSERT_OBJECT {
493+
#[cfg(debug_assertions)]
494+
{
495+
use crate::object_model::{is_object_in_immixspace, is_object_in_los};
496+
if !mmtk_object_is_managed_by_mmtk(object.to_raw_address().as_usize()) {
497+
panic!("{} is not managed by MMTk", object);
498+
}
499+
if !is_object_in_immixspace(&object) && !is_object_in_los(&object) {
500+
// 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.
501+
return;
502+
}
503+
if !object
504+
.to_raw_address()
505+
.is_aligned_to(ObjectReference::ALIGNMENT)
506+
{
507+
panic!(
508+
"{} is not aligned, it cannot be an object reference",
509+
object
510+
)
511+
}
512+
if memory_manager::is_mmtk_object(object.to_raw_address()).is_none() {
513+
error!("{} is not an object", object);
514+
if let Some(base_ref) = memory_manager::find_object_from_internal_pointer(
515+
object.to_raw_address(),
516+
usize::MAX,
517+
) {
518+
panic!("{} is an internal pointer of {}", object, base_ref);
519+
} else {
520+
panic!(
521+
"{} is not recognised as an object reference, or an internal reference",
522+
object
523+
);
524+
}
525+
}
526+
}
527+
}
528+
}
488529
#[no_mangle]
489530
pub extern "C" fn mmtk_pin_object(object: ObjectReference) -> bool {
531+
assert_is_object(object);
532+
crate::early_return_for_non_moving_build!(false);
533+
memory_manager::pin_object(object)
534+
}
535+
536+
#[no_mangle]
537+
pub extern "C" fn mmtk_unpin_object(object: ObjectReference) -> bool {
538+
assert_is_object(object);
539+
crate::early_return_for_non_moving_build!(false);
540+
memory_manager::unpin_object(object)
541+
}
542+
543+
#[no_mangle]
544+
pub extern "C" fn mmtk_is_object_pinned(object: ObjectReference) -> bool {
545+
assert_is_object(object);
490546
crate::early_return_for_non_moving_build!(false);
491547

492-
// We may in the future replace this with a check for the immix space (bound check), which should be much cheaper.
493-
if mmtk_object_is_managed_by_mmtk(object.to_raw_address().as_usize()) {
494-
memory_manager::pin_object(object)
548+
memory_manager::is_pinned(object)
549+
}
550+
551+
macro_rules! handle_potential_internal_pointer {
552+
($func: path, $addr: expr) => {{
553+
if $addr.is_aligned_to(ObjectReference::ALIGNMENT) {
554+
if let Some(obj) = memory_manager::is_mmtk_object($addr) {
555+
return $func(obj);
556+
}
557+
}
558+
let maybe_objref = memory_manager::find_object_from_internal_pointer($addr, usize::MAX);
559+
if let Some(obj) = maybe_objref {
560+
trace!(
561+
"Attempt to pin {:?}, but it is an internal reference of {:?}",
562+
$addr,
563+
obj
564+
);
565+
$func(obj)
566+
} else {
567+
warn!(
568+
"Attempt to pin {:?}, but it is not recognised as a object",
569+
$addr
570+
);
571+
false
572+
}
573+
}};
574+
}
575+
576+
#[no_mangle]
577+
pub extern "C" fn mmtk_pin_pointer(addr: Address) -> bool {
578+
crate::early_return_for_non_moving_build!(false);
579+
580+
if crate::object_model::is_addr_in_immixspace(addr) {
581+
handle_potential_internal_pointer!(memory_manager::pin_object, addr)
495582
} else {
496-
debug!("Object is not managed by mmtk - (un)pinning it via this function isn't supported.");
583+
debug!("Object is not in Immix space. MMTk will not move the object. No need to pin the object.");
497584
false
498585
}
499586
}
500587

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

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

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

517-
if mmtk_object_is_managed_by_mmtk(object.to_raw_address().as_usize()) {
518-
memory_manager::is_pinned(object)
604+
if crate::object_model::is_addr_in_immixspace(addr) {
605+
handle_potential_internal_pointer!(memory_manager::is_pinned, addr)
606+
} else if !mmtk_object_is_managed_by_mmtk(addr.as_usize()) {
607+
debug!(
608+
"Object is not in Immix space. MMTk will not move the object. We assume it is pinned."
609+
);
610+
true
519611
} else {
520-
debug!("Object is not managed by mmtk - checking via this function isn't supported.");
612+
debug!("Object is not managed by mmtk - checking pinning state via this function isn't supported.");
521613
false
522614
}
523615
}

mmtk/src/conservative.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::jl_task_stack_buffer;
21
use crate::julia_types::*;
32
use mmtk::memory_manager;
43
use mmtk::util::constants::BYTES_IN_ADDRESS;
@@ -41,24 +40,38 @@ pub fn mmtk_conservative_scan_task_stack(ta: *const jl_task_t) {
4140
crate::early_return_for_non_moving_build!(());
4241
crate::early_return_for_current_gc!();
4342

44-
let mut size: u64 = 0;
45-
let mut ptid: i32 = 0;
4643
log::debug!("mmtk_conservative_scan_native_stack begin ta = {:?}", ta);
47-
let stk = unsafe { jl_task_stack_buffer(ta, &mut size as *mut _, &mut ptid as *mut _) };
44+
let mut active_start = Address::ZERO;
45+
let mut active_end = Address::ZERO;
46+
let mut total_start = Address::ZERO;
47+
let mut total_end = Address::ZERO;
48+
unsafe {
49+
crate::jl_active_task_stack(
50+
ta,
51+
&mut active_start as _,
52+
&mut active_end as _,
53+
&mut total_start as _,
54+
&mut total_end as _,
55+
)
56+
};
4857
log::debug!(
49-
"mmtk_conservative_scan_native_stack continue stk = {}, size = {}, ptid = {:x}",
50-
stk,
51-
size,
52-
ptid
58+
"mmtk_conservative_scan_native_stack continue, active = {},{}, total = {},{}",
59+
active_start,
60+
active_end,
61+
total_start,
62+
total_end,
5363
);
54-
if !stk.is_zero() {
64+
65+
let size = active_end - active_start;
66+
67+
if !active_start.is_zero() {
5568
log::debug!("Conservatively scan the stack");
5669
// See jl_guard_size
5770
// TODO: Are we sure there are always guard pages we need to skip?
5871
const JL_GUARD_PAGE: usize = 4096 * 8;
59-
let guard_page_start = stk + JL_GUARD_PAGE;
60-
log::debug!("Skip guard page: {}, {}", stk, guard_page_start);
61-
conservative_scan_range(guard_page_start, stk + size as usize);
72+
let guard_page_start = active_start + JL_GUARD_PAGE;
73+
log::debug!("Skip guard page: {}, {}", active_start, guard_page_start);
74+
conservative_scan_range(guard_page_start, active_start + size);
6275
} else {
6376
log::warn!("Skip stack for {:?}", ta);
6477
}

mmtk/src/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,13 @@ extern "C" {
121121
pub fn jl_gc_get_owner_address_to_mmtk(m: Address) -> Address;
122122
pub fn jl_gc_genericmemory_how(m: Address) -> usize;
123123
pub fn jl_gc_get_max_memory() -> usize;
124-
pub fn jl_task_stack_buffer(
124+
pub fn jl_active_task_stack(
125125
task: *const crate::julia_types::jl_task_t,
126-
size: *mut u64,
127-
ptid: *mut i32,
128-
) -> Address;
126+
active_start: *mut Address,
127+
active_end: *mut Address,
128+
total_start: *mut Address,
129+
total_end: *mut Address,
130+
);
129131
pub static jl_true: *mut crate::julia_types::jl_value_t;
130132
}
131133

0 commit comments

Comments
 (0)