Skip to content

Commit 7e6f35e

Browse files
committed
Introduce the RubyObjectAccess type
It is now the canoincal source of object layout information. In the future, it will also provide more convenient methods for accessing Ruby objects.
1 parent 942ffaf commit 7e6f35e

File tree

2 files changed

+84
-19
lines changed

2 files changed

+84
-19
lines changed

mmtk/src/abi.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::api::RubyMutator;
22
use crate::{upcalls, Ruby};
33
use mmtk::scheduler::{GCController, GCWorker};
4-
use mmtk::util::{ObjectReference, VMMutatorThread, VMWorkerThread};
4+
use mmtk::util::{Address, ObjectReference, VMMutatorThread, VMWorkerThread};
55

66
// For the C binding
77
pub const OBJREF_OFFSET: usize = 8;
@@ -10,6 +10,63 @@ pub const MIN_OBJ_ALIGN: usize = 8; // Even on 32-bit machine. A Ruby object is
1010
pub const GC_THREAD_KIND_CONTROLLER: libc::c_int = 0;
1111
pub const GC_THREAD_KIND_WORKER: libc::c_int = 1;
1212

13+
/// Provide convenient methods for accessing Ruby objects.
14+
/// TODO: Wrap C functions in `RubyUpcalls` as Rust-friendly methods.
15+
pub struct RubyObjectAccess {
16+
objref: ObjectReference,
17+
}
18+
19+
impl RubyObjectAccess {
20+
pub fn from_objref(objref: ObjectReference) -> Self {
21+
Self { objref }
22+
}
23+
24+
pub fn obj_start(&self) -> Address {
25+
self.objref.to_raw_address().sub(Self::prefix_size())
26+
}
27+
28+
pub fn payload_addr(&self) -> Address {
29+
self.objref.to_raw_address()
30+
}
31+
32+
pub fn suffix_addr(&self) -> Address {
33+
self.objref.to_raw_address().add(self.payload_size())
34+
}
35+
36+
pub fn obj_end(&self) -> Address {
37+
self.suffix_addr() + Self::suffix_size()
38+
}
39+
40+
fn hidden_field(&self) -> Address {
41+
self.obj_start()
42+
}
43+
44+
pub fn payload_size(&self) -> usize {
45+
unsafe {
46+
// That hidden field holds the payload size.
47+
self.hidden_field().load()
48+
}
49+
}
50+
51+
pub fn set_payload_size(&self, size: usize) {
52+
unsafe { self.hidden_field().store(size) }
53+
}
54+
55+
pub fn prefix_size() -> usize {
56+
// Currently, a hidden size field of word size is placed before each object.
57+
OBJREF_OFFSET
58+
}
59+
60+
pub fn suffix_size() -> usize {
61+
// In RACTOR_CHECK_MODE, Ruby hides a field after each object to hold the Ractor ID.
62+
unsafe { crate::BINDING_FAST.suffix_size }
63+
}
64+
65+
pub fn object_size(&self) -> usize {
66+
Self::prefix_size() + self.payload_size() + Self::suffix_size()
67+
}
68+
}
69+
1370
type ObjectClosureFunction =
1471
extern "C" fn(*mut libc::c_void, *mut libc::c_void, ObjectReference, bool) -> ObjectReference;
1572

mmtk/src/object_model.rs

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use std::ptr::copy_nonoverlapping;
2+
3+
use crate::abi::{RubyObjectAccess, MIN_OBJ_ALIGN, OBJREF_OFFSET};
14
use crate::{abi, Ruby};
25
use mmtk::util::copy::{CopySemantics, GCWorkerCopyContext};
36
use mmtk::util::{Address, ObjectReference};
@@ -32,32 +35,37 @@ impl ObjectModel<Ruby> for VMObjectModel {
3235
const OBJECT_REF_OFFSET_LOWER_BOUND: isize = Self::OBJREF_OFFSET as isize;
3336

3437
fn copy(
35-
_from: ObjectReference,
36-
_semantics: CopySemantics,
37-
_copy_context: &mut GCWorkerCopyContext<Ruby>,
38+
from: ObjectReference,
39+
semantics: CopySemantics,
40+
copy_context: &mut GCWorkerCopyContext<Ruby>,
3841
) -> ObjectReference {
39-
todo!()
42+
let from_acc = RubyObjectAccess::from_objref(from);
43+
let from_start = from_acc.obj_start();
44+
let object_size = from_acc.object_size();
45+
let to_start = copy_context.alloc_copy(from, object_size, MIN_OBJ_ALIGN, 0, semantics);
46+
let to_payload = to_start.add(OBJREF_OFFSET);
47+
unsafe {
48+
copy_nonoverlapping::<u8>(from_start.to_ptr(), to_start.to_mut_ptr(), object_size);
49+
}
50+
let to_obj = ObjectReference::from_raw_address(to_payload);
51+
copy_context.post_copy(to_obj, object_size, semantics);
52+
to_obj
4053
}
4154

4255
fn copy_to(_from: ObjectReference, _to: ObjectReference, _region: Address) -> Address {
43-
todo!()
56+
unimplemented!(
57+
"This function cannot be called because we do not support MarkCompact for Ruby."
58+
)
4459
}
4560

4661
fn get_reference_when_copied_to(_from: ObjectReference, _to: Address) -> ObjectReference {
47-
todo!()
62+
unimplemented!(
63+
"This function cannot be called because we do not support MarkCompact for Ruby."
64+
)
4865
}
4966

5067
fn get_current_size(object: ObjectReference) -> usize {
51-
// Currently, a hidden size field of word size is placed before each object.
52-
let prefix_size = abi::OBJREF_OFFSET;
53-
54-
// That hidden field holds the payload size.
55-
let start = Self::ref_to_object_start(object);
56-
let payload_size = unsafe { start.load::<usize>() };
57-
58-
// In RACTOR_CHECK_MODE, Ruby hides a field after each object to hold the Ractor ID.
59-
let suffix_size = unsafe { crate::BINDING_FAST.suffix_size };
60-
prefix_size + payload_size + suffix_size
68+
RubyObjectAccess::from_objref(object).object_size()
6169
}
6270

6371
fn get_type_descriptor(_reference: ObjectReference) -> &'static [i8] {
@@ -69,11 +77,11 @@ impl ObjectModel<Ruby> for VMObjectModel {
6977
}
7078

7179
fn ref_to_object_start(object: ObjectReference) -> Address {
72-
object.to_raw_address() - Self::OBJREF_OFFSET
80+
RubyObjectAccess::from_objref(object).obj_start()
7381
}
7482

7583
fn ref_to_header(object: ObjectReference) -> Address {
76-
object.to_raw_address()
84+
RubyObjectAccess::from_objref(object).payload_addr()
7785
}
7886

7987
fn address_to_ref(addr: Address) -> ObjectReference {

0 commit comments

Comments
 (0)