Skip to content

Commit 84d048a

Browse files
committed
Support VO bit (#197)
This PR ports #158 to `dev`, and updates Julia to mmtk/julia#76.
1 parent 80a7a65 commit 84d048a

File tree

4 files changed

+185
-1
lines changed

4 files changed

+185
-1
lines changed

mmtk/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,15 @@ memoffset = "*"
4040
# ykstackmaps = { git = "https://github.com/udesou/ykstackmaps.git", branch = "udesou-master", version = "*" }
4141

4242
[features]
43-
default = ["mmtk/vm_space", "julia_copy_stack", "object_pinning"]
43+
default = ["mmtk/vm_space", "julia_copy_stack", "object_pinning", "is_mmtk_object"]
4444

4545
# Plans
4646
nogc = []
4747
immix = []
4848
stickyimmix = ["mmtk/sticky_immix_non_moving_nursery", "mmtk/immix_smaller_block"]
4949
marksweep = []
5050
object_pinning = ["mmtk/object_pinning"]
51+
is_mmtk_object = ["mmtk/is_mmtk_object"]
5152

5253
# This feature disables moving
5354
non_moving = ["mmtk/immix_non_moving", "mmtk/immix_smaller_block"]

mmtk/src/api.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@ pub extern "C" fn mmtk_set_vm_space(start: Address, size: usize) {
350350

351351
#[cfg(feature = "stickyimmix")]
352352
set_side_log_bit_for_region(start, size);
353+
#[cfg(feature = "is_mmtk_object")]
354+
set_side_vo_bit_for_region(start, size);
353355
}
354356

355357
#[no_mangle]
@@ -381,6 +383,8 @@ pub extern "C" fn mmtk_memory_region_copy(
381383
pub extern "C" fn mmtk_immortal_region_post_alloc(start: Address, size: usize) {
382384
#[cfg(feature = "stickyimmix")]
383385
set_side_log_bit_for_region(start, size);
386+
#[cfg(feature = "is_mmtk_object")]
387+
set_side_vo_bit_for_region(start, size);
384388
}
385389

386390
#[cfg(feature = "stickyimmix")]
@@ -393,6 +397,18 @@ fn set_side_log_bit_for_region(start: Address, size: usize) {
393397
}
394398
}
395399

400+
#[cfg(feature = "is_mmtk_object")]
401+
fn set_side_vo_bit_for_region(start: Address, size: usize) {
402+
debug!(
403+
"Bulk set VO bit {} to {} ({} bytes)",
404+
start,
405+
start + size,
406+
size
407+
);
408+
409+
crate::vo_bit::bulk_update_vo_bit(start, size)
410+
}
411+
396412
#[no_mangle]
397413
pub extern "C" fn mmtk_object_reference_write_post(
398414
mutator: *mut Mutator<JuliaVM>,
@@ -427,6 +443,11 @@ pub extern "C" fn mmtk_object_reference_write_slow(
427443
pub static MMTK_SIDE_LOG_BIT_BASE_ADDRESS: Address =
428444
mmtk::util::metadata::side_metadata::GLOBAL_SIDE_METADATA_VM_BASE_ADDRESS;
429445

446+
/// VO bit base address
447+
#[no_mangle]
448+
pub static MMTK_SIDE_VO_BIT_BASE_ADDRESS: Address =
449+
mmtk::util::metadata::side_metadata::VO_BIT_SIDE_METADATA_ADDR;
450+
430451
#[no_mangle]
431452
pub extern "C" fn mmtk_object_is_managed_by_mmtk(addr: usize) -> bool {
432453
crate::api::mmtk_is_mapped_address(unsafe { Address::from_usize(addr) })

mmtk/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub mod reference_glue;
2727
pub mod scanning;
2828
pub mod slots;
2929
pub mod util;
30+
mod vo_bit;
3031

3132
pub mod julia_finalizer;
3233
pub mod julia_scanning;

mmtk/src/vo_bit.rs

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
use crate::api::MMTK_SIDE_VO_BIT_BASE_ADDRESS;
2+
use core::sync::atomic::Ordering;
3+
use mmtk::util::Address;
4+
use std::sync::atomic::AtomicU8;
5+
6+
// This module is a duplicate of MMTK core's side metadata to allow bulk setting for VO bit.
7+
// The problem is that VO bit is internal to MMTk core, and we cannot access VO bit.
8+
// FIXME: We should consider refactoring MMTk core to either expose `SideMetadataSpec` for VO bit,
9+
// or allow the binding to construct `SideMetadataSpec` for VO bit. For either case, we can
10+
// remove this module and remove this code duplication.
11+
12+
// Functions to set the side metadata for the VO bit (copied from mmtk-core)
13+
pub const VO_BIT_LOG_NUM_OF_BITS: i32 = 0;
14+
pub const VO_BIT_LOG_BYTES_PER_REGION: usize = mmtk::util::constants::LOG_MIN_OBJECT_SIZE as usize;
15+
16+
pub fn bulk_update_vo_bit(start: Address, size: usize) {
17+
// Update bits for a contiguous side metadata spec. We can simply calculate the data end address, and
18+
// calculate the metadata address for the data end.
19+
let update_contiguous = |data_start: Address, data_bytes: usize| {
20+
if data_bytes == 0 {
21+
return;
22+
}
23+
let meta_start = address_to_meta_address(data_start);
24+
let meta_start_shift = meta_byte_lshift(data_start);
25+
let meta_end = address_to_meta_address(data_start + data_bytes);
26+
let meta_end_shift = meta_byte_lshift(data_start + data_bytes);
27+
set_meta_bits(meta_start, meta_start_shift, meta_end, meta_end_shift);
28+
};
29+
30+
// VO bit is global
31+
update_contiguous(start, size);
32+
}
33+
34+
/// Performs the translation of data address (`data_addr`) to metadata address for the specified metadata (`metadata_spec`).
35+
pub fn address_to_meta_address(data_addr: Address) -> Address {
36+
#[cfg(target_pointer_width = "32")]
37+
let res = {
38+
if metadata_spec.is_global {
39+
address_to_contiguous_meta_address(metadata_spec, data_addr)
40+
} else {
41+
address_to_chunked_meta_address(metadata_spec, data_addr)
42+
}
43+
};
44+
#[cfg(target_pointer_width = "64")]
45+
let res = { address_to_contiguous_meta_address(data_addr) };
46+
47+
res
48+
}
49+
50+
/// Performs address translation in contiguous metadata spaces (e.g. global and policy-specific in 64-bits, and global in 32-bits)
51+
pub fn address_to_contiguous_meta_address(data_addr: Address) -> Address {
52+
let rshift = (mmtk::util::constants::LOG_BITS_IN_BYTE as i32) - VO_BIT_LOG_NUM_OF_BITS;
53+
54+
if rshift >= 0 {
55+
MMTK_SIDE_VO_BIT_BASE_ADDRESS + ((data_addr >> VO_BIT_LOG_BYTES_PER_REGION) >> rshift)
56+
} else {
57+
MMTK_SIDE_VO_BIT_BASE_ADDRESS + ((data_addr >> VO_BIT_LOG_BYTES_PER_REGION) << (-rshift))
58+
}
59+
}
60+
61+
pub fn meta_byte_lshift(data_addr: Address) -> u8 {
62+
if VO_BIT_LOG_NUM_OF_BITS >= 3 {
63+
return 0;
64+
}
65+
let rem_shift = mmtk::util::constants::BITS_IN_WORD as i32
66+
- ((mmtk::util::constants::LOG_BITS_IN_BYTE as i32) - VO_BIT_LOG_NUM_OF_BITS);
67+
((((data_addr >> VO_BIT_LOG_BYTES_PER_REGION) << rem_shift) >> rem_shift)
68+
<< VO_BIT_LOG_NUM_OF_BITS) as u8
69+
}
70+
71+
/// This method is used for bulk updating side metadata for a data address range. As we cannot guarantee
72+
/// that the data address range can be mapped to whole metadata bytes, we have to deal with cases that
73+
/// we need to mask and zero certain bits in a metadata byte. The end address and the end bit are exclusive.
74+
/// The end bit for update_bits could be 8, so overflowing needs to be taken care of.
75+
pub fn update_meta_bits(
76+
meta_start_addr: Address,
77+
meta_start_bit: u8,
78+
meta_end_addr: Address,
79+
meta_end_bit: u8,
80+
update_bytes: &impl Fn(Address, Address),
81+
update_bits: &impl Fn(Address, u8, u8),
82+
) {
83+
// Start/end is the same, we don't need to do anything.
84+
if meta_start_addr == meta_end_addr && meta_start_bit == meta_end_bit {
85+
return;
86+
}
87+
88+
// zeroing bytes
89+
if meta_start_bit == 0 && meta_end_bit == 0 {
90+
update_bytes(meta_start_addr, meta_end_addr);
91+
return;
92+
}
93+
94+
if meta_start_addr == meta_end_addr {
95+
// Update bits in the same byte between start and end bit
96+
update_bits(meta_start_addr, meta_start_bit, meta_end_bit);
97+
} else if meta_start_addr + 1usize == meta_end_addr && meta_end_bit == 0 {
98+
// Update bits in the same byte after the start bit (between start bit and 8)
99+
update_bits(meta_start_addr, meta_start_bit, 8);
100+
} else {
101+
// update bits in the first byte
102+
update_meta_bits(
103+
meta_start_addr,
104+
meta_start_bit,
105+
meta_start_addr + 1usize,
106+
0,
107+
update_bytes,
108+
update_bits,
109+
);
110+
// update bytes in the middle
111+
update_meta_bits(
112+
meta_start_addr + 1usize,
113+
0,
114+
meta_end_addr,
115+
0,
116+
update_bytes,
117+
update_bits,
118+
);
119+
// update bits in the last byte
120+
update_meta_bits(
121+
meta_end_addr,
122+
0,
123+
meta_end_addr,
124+
meta_end_bit,
125+
update_bytes,
126+
update_bits,
127+
);
128+
}
129+
}
130+
131+
/// This method is used for bulk setting side metadata for a data address range.
132+
pub fn set_meta_bits(
133+
meta_start_addr: Address,
134+
meta_start_bit: u8,
135+
meta_end_addr: Address,
136+
meta_end_bit: u8,
137+
) {
138+
let set_bytes = |start: Address, end: Address| {
139+
set(start, 0xff, end - start);
140+
};
141+
let set_bits = |addr: Address, start_bit: u8, end_bit: u8| {
142+
// we are setting selected bits in one byte
143+
let mask: u8 = !(u8::MAX.checked_shl(end_bit.into()).unwrap_or(0)) & (u8::MAX << start_bit); // Get a mask that the bits we need to set are 1, and the other bits are 0.
144+
unsafe { addr.as_ref::<AtomicU8>() }.fetch_or(mask, Ordering::SeqCst);
145+
};
146+
update_meta_bits(
147+
meta_start_addr,
148+
meta_start_bit,
149+
meta_end_addr,
150+
meta_end_bit,
151+
&set_bytes,
152+
&set_bits,
153+
);
154+
}
155+
156+
/// Set a range of memory to the given value. Similar to memset.
157+
pub fn set(start: Address, val: u8, len: usize) {
158+
unsafe {
159+
std::ptr::write_bytes::<u8>(start.to_mut_ptr(), val, len);
160+
}
161+
}

0 commit comments

Comments
 (0)