Skip to content

Commit 1649090

Browse files
authored
Add an feature to record moved objects (#258)
Add a debug feature to record information about moved objects. When we move an object, we record the object's old reference (which becomes dangling soon), and its type in a map. Then we see the dangling pointer, we can query the map to know its original type. We could expand this to record more information other than the type. This could be helpful for debugging.
1 parent 97bace5 commit 1649090

File tree

3 files changed

+48
-26
lines changed

3 files changed

+48
-26
lines changed

mmtk/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,7 @@ address_based_hashing = []
7070
heap_dump = []
7171
dump_block_stats = []
7272
print_fragmentation = []
73+
74+
# Debug option to record the type of moved objects.
75+
# When we encounter a dangling pointer, we can know its old type.
76+
record_moved_objects = []

mmtk/src/julia_scanning.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -230,19 +230,7 @@ pub unsafe fn scan_julia_object<SV: SlotVisitor<JuliaVMSlot>>(obj: Address, clos
230230
}
231231
return;
232232
} else {
233-
let vt = vtag.to_ptr::<jl_datatype_t>();
234-
let type_tag = mmtk_jl_typetagof(vtag);
235-
236-
if type_tag.as_usize() != ((jl_small_typeof_tags_jl_datatype_tag as usize) << 4)
237-
|| (*vt).smalltag() != 0
238-
{
239-
panic!(
240-
"GC error (probable corruption) - !jl_is_datatype(vt) = {}; vt->smalltag = {}, vt = {:?}",
241-
vt as usize != ((jl_small_typeof_tags_jl_datatype_tag as usize) << 4),
242-
(*(vtag.to_ptr::<jl_datatype_t>())).smalltag() != 0,
243-
vt
244-
);
245-
}
233+
crate::object_model::assert_generic_datatype(obj);
246234
}
247235
let vt = vtag.to_ptr::<jl_datatype_t>();
248236
if (*vt).name == jl_array_typename {

mmtk/src/object_model.rs

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ pub(crate) const HASH_BITS_SPEC: SideMetadataSpec = SideMetadataSpec {
3131
log_bytes_in_region: LOG_MIN_OBJECT_SIZE as usize,
3232
};
3333

34+
#[cfg(feature = "record_moved_objects")]
35+
use std::{sync::Mutex, collections::HashMap};
36+
#[cfg(feature = "record_moved_objects")]
37+
lazy_static! {
38+
static ref COPIED_OBJECTS: Mutex<HashMap<usize, String>> = Mutex::new(HashMap::new());
39+
}
40+
3441
pub(crate) const MARKING_METADATA_SPEC: VMLocalMarkBitSpec =
3542
VMLocalMarkBitSpec::side_after(LOS_METADATA_SPEC.as_spec());
3643

@@ -187,6 +194,12 @@ impl ObjectModel<JuliaVM> for VMObjectModel {
187194
}
188195
}
189196

197+
#[cfg(feature = "record_moved_objects")]
198+
{
199+
let mut map = COPIED_OBJECTS.lock().unwrap();
200+
map.insert(from.to_raw_address().as_usize(), unsafe { crate::julia_scanning::get_julia_object_type(from.to_raw_address()) });
201+
}
202+
190203
// zero from_obj (for debugging purposes)
191204
#[cfg(debug_assertions)]
192205
{
@@ -297,6 +310,35 @@ pub fn is_object_in_nonmoving(object: &ObjectReference) -> bool {
297310
&& (*object).to_raw_address().as_usize() < 0xa00_0000_0000
298311
}
299312

313+
// If an object has its type tag bits set as 'smalltag', but those bits are not recognizable,
314+
// very possibly the object is corrupted. This function asserts this case.
315+
pub fn assert_generic_datatype(obj: Address) {
316+
unsafe {
317+
let vtag = mmtk_jl_typetagof(obj);
318+
let vt = vtag.to_ptr::<jl_datatype_t>();
319+
let type_tag = mmtk_jl_typetagof(vtag);
320+
321+
if type_tag.as_usize() != ((jl_small_typeof_tags_jl_datatype_tag as usize) << 4)
322+
|| (*vt).smalltag() != 0
323+
{
324+
#[cfg(feature = "record_moved_objects")]
325+
let old_type = {
326+
let not_moved = "not moved".to_string();
327+
{ let map = COPIED_OBJECTS.lock().unwrap(); map.get(&obj.as_usize()).unwrap_or(&not_moved).to_string() }
328+
};
329+
#[cfg(not(feature = "record_moved_objects"))]
330+
let old_type = "not recorded (need record_moved_objects)".to_string();
331+
panic!(
332+
"GC error (probable corruption) - !jl_is_datatype(vt) = {}; vt->smalltag = {}, vt = {:?}, it was = {}",
333+
vt as usize != ((jl_small_typeof_tags_jl_datatype_tag as usize) << 4),
334+
(*(vtag.to_ptr::<jl_datatype_t>())).smalltag() != 0,
335+
vt,
336+
old_type
337+
);
338+
}
339+
}
340+
}
341+
300342
/// This function uses mutable static variables and requires unsafe annotation
301343
302344
#[inline(always)]
@@ -353,19 +395,7 @@ pub unsafe fn get_so_object_size(object: ObjectReference, hash_size: usize) -> u
353395
return llt_align(with_header_size(dtsz), 16);
354396
}
355397
} else {
356-
let vt = vtag.to_ptr::<jl_datatype_t>();
357-
let type_tag = mmtk_jl_typetagof(vtag);
358-
359-
if type_tag.as_usize() != ((jl_small_typeof_tags_jl_datatype_tag as usize) << 4)
360-
|| (*vt).smalltag() != 0
361-
{
362-
panic!(
363-
"GC error (probable corruption) - !jl_is_datatype(vt) = {}; vt->smalltag = {}, vt = {:?}",
364-
type_tag.as_usize() != ((jl_small_typeof_tags_jl_datatype_tag as usize) << 4),
365-
(*(vtag.to_ptr::<jl_datatype_t>())).smalltag() != 0,
366-
vt
367-
);
368-
}
398+
assert_generic_datatype(obj_address);
369399
}
370400

371401
let obj_type = mmtk_jl_typeof(obj_address);

0 commit comments

Comments
 (0)