Skip to content

Commit 1ee047d

Browse files
authored
Fix object copy performance (#130)
* Fix get-object-size and object-copy performance * Minor * Fix CI
1 parent caf4b9c commit 1ee047d

File tree

3 files changed

+87
-6
lines changed

3 files changed

+87
-6
lines changed

mmtk/src/abi.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::UPCALLS;
22
use mmtk::util::constants::*;
33
use mmtk::util::conversions;
4+
use mmtk::util::ObjectReference;
45
use mmtk::util::{Address, OpaquePointer};
56
use std::ffi::CStr;
67
use std::fmt;
@@ -64,9 +65,31 @@ pub struct Klass {
6465
}
6566

6667
impl Klass {
68+
pub const LH_NEUTRAL_VALUE: i32 = 0;
69+
pub const LH_INSTANCE_SLOW_PATH_BIT: i32 = 0x01;
70+
#[allow(clippy::erasing_op)]
71+
pub const LH_LOG2_ELEMENT_SIZE_SHIFT: i32 = BITS_IN_BYTE as i32 * 0;
72+
pub const LH_LOG2_ELEMENT_SIZE_MASK: i32 = BITS_IN_LONG as i32 - 1;
73+
pub const LH_HEADER_SIZE_SHIFT: i32 = BITS_IN_BYTE as i32 * 2;
74+
pub const LH_HEADER_SIZE_MASK: i32 = (1 << BITS_IN_BYTE) - 1;
6775
pub unsafe fn cast<'a, T>(&self) -> &'a T {
6876
&*(self as *const _ as usize as *const T)
6977
}
78+
/// Force slow-path for instance size calculation?
79+
#[inline(always)]
80+
const fn layout_helper_needs_slow_path(lh: i32) -> bool {
81+
(lh & Self::LH_INSTANCE_SLOW_PATH_BIT) != 0
82+
}
83+
/// Get log2 array element size
84+
#[inline(always)]
85+
const fn layout_helper_log2_element_size(lh: i32) -> i32 {
86+
(lh >> Self::LH_LOG2_ELEMENT_SIZE_SHIFT) & Self::LH_LOG2_ELEMENT_SIZE_MASK
87+
}
88+
/// Get array header size
89+
#[inline(always)]
90+
const fn layout_helper_header_size(lh: i32) -> i32 {
91+
(lh >> Self::LH_HEADER_SIZE_SHIFT) & Self::LH_HEADER_SIZE_MASK
92+
}
7093
}
7194

7295
#[repr(C)]
@@ -238,6 +261,13 @@ pub struct OopDesc {
238261
pub klass: &'static Klass,
239262
}
240263

264+
impl OopDesc {
265+
#[inline(always)]
266+
pub fn start(&self) -> Address {
267+
unsafe { mem::transmute(self) }
268+
}
269+
}
270+
241271
impl fmt::Debug for OopDesc {
242272
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243273
let c_string = unsafe { ((*UPCALLS).dump_object_string)(mem::transmute(self)) };
@@ -249,6 +279,22 @@ impl fmt::Debug for OopDesc {
249279

250280
pub type Oop = &'static OopDesc;
251281

282+
/// Convert ObjectReference to Oop
283+
impl From<ObjectReference> for &OopDesc {
284+
#[inline(always)]
285+
fn from(o: ObjectReference) -> Self {
286+
unsafe { mem::transmute(o) }
287+
}
288+
}
289+
290+
/// Convert Oop to ObjectReference
291+
impl From<&OopDesc> for ObjectReference {
292+
#[inline(always)]
293+
fn from(o: &OopDesc) -> Self {
294+
unsafe { mem::transmute(o) }
295+
}
296+
}
297+
252298
impl OopDesc {
253299
pub unsafe fn as_array_oop<T>(&self) -> ArrayOop<T> {
254300
&*(self as *const OopDesc as *const ArrayOopDesc<T>)
@@ -257,6 +303,40 @@ impl OopDesc {
257303
pub fn get_field_address(&self, offset: i32) -> Address {
258304
Address::from_ref(self) + offset as isize
259305
}
306+
307+
/// Slow-path for calculating object instance size
308+
#[inline(always)]
309+
unsafe fn size_slow(&self) -> usize {
310+
((*UPCALLS).get_object_size)(self.into())
311+
}
312+
313+
/// Calculate object instance size
314+
#[inline(always)]
315+
pub unsafe fn size(&self) -> usize {
316+
let klass = self.klass;
317+
let lh = klass.layout_helper;
318+
// The (scalar) instance size is pre-recorded in the TIB?
319+
if lh > Klass::LH_NEUTRAL_VALUE {
320+
if !Klass::layout_helper_needs_slow_path(lh) {
321+
lh as _
322+
} else {
323+
self.size_slow()
324+
}
325+
} else if lh <= Klass::LH_NEUTRAL_VALUE {
326+
if lh < Klass::LH_NEUTRAL_VALUE {
327+
// Calculate array size
328+
let array_length = self.as_array_oop::<()>().length();
329+
let mut size_in_bytes: usize =
330+
(array_length as usize) << Klass::layout_helper_log2_element_size(lh);
331+
size_in_bytes += Klass::layout_helper_header_size(lh) as usize;
332+
(size_in_bytes + 0b111) & !0b111
333+
} else {
334+
self.size_slow()
335+
}
336+
} else {
337+
unreachable!()
338+
}
339+
}
260340
}
261341

262342
#[repr(C)]

mmtk/src/object_model.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::sync::atomic::Ordering;
22

33
use super::UPCALLS;
4+
use crate::abi::Oop;
45
use crate::{vm_metadata, OpenJDK};
56
use mmtk::util::alloc::fill_alignment_gap;
67
use mmtk::util::copy::*;
@@ -89,13 +90,11 @@ impl ObjectModel<OpenJDK> for VMObjectModel {
8990
copy: CopySemantics,
9091
copy_context: &mut GCWorkerCopyContext<OpenJDK>,
9192
) -> ObjectReference {
92-
let bytes = unsafe { ((*UPCALLS).get_object_size)(from) };
93+
let bytes = unsafe { Oop::from(from).size() };
9394
let dst = copy_context.alloc_copy(from, bytes, ::std::mem::size_of::<usize>(), 0, copy);
9495
// Copy
9596
let src = from.to_address();
96-
for i in 0..bytes {
97-
unsafe { (dst + i).store((src + i).load::<u8>()) };
98-
}
97+
unsafe { std::ptr::copy_nonoverlapping::<u8>(src.to_ptr(), dst.to_mut_ptr(), bytes) }
9998
let to_obj = unsafe { dst.to_object_reference() };
10099
copy_context.post_copy(to_obj, bytes, copy);
101100
to_obj
@@ -125,7 +124,7 @@ impl ObjectModel<OpenJDK> for VMObjectModel {
125124
}
126125

127126
fn get_current_size(object: ObjectReference) -> usize {
128-
unsafe { ((*UPCALLS).get_object_size)(object) }
127+
unsafe { Oop::from(object).size() }
129128
}
130129

131130
fn get_size_when_copied(object: ObjectReference) -> usize {

openjdk/mmtkUpcalls.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,9 @@ static void mmtk_dump_object(void* object) {
207207

208208
static size_t mmtk_get_object_size(void* object) {
209209
oop o = (oop) object;
210-
return o->size() * HeapWordSize;
210+
// Slow-dispatch only. The fast-path code is moved to rust.
211+
auto klass = o->klass();
212+
return klass->oop_size(o) << LogHeapWordSize;
211213
}
212214

213215
static int mmtk_enter_vm() {

0 commit comments

Comments
 (0)