Skip to content

Commit 482db1b

Browse files
committed
Support heap traversal
We use the object enumeration feature in mmtk-core to implement heap traversal. This enables `ObjectSpace.each_object` as well as the `TracePoint` utility which needs heap traversal to enumerate objects and set hooks. Test cases involving each_object and TracePoint are no longer excluded. The TestTracepointObj test case remains excluded because we have not implemented querying GC statistics from TracePoint.
1 parent 3c7e6af commit 482db1b

9 files changed

+88
-12
lines changed

Diff for: gc/default.c

+73
Original file line numberDiff line numberDiff line change
@@ -3207,9 +3207,82 @@ objspace_each_objects(rb_objspace_t *objspace, each_obj_callback *callback, void
32073207
objspace_each_exec(protected, &each_obj_data);
32083208
}
32093209

3210+
#if USE_MMTK
3211+
struct rb_mmtk_build_obj_array_data {
3212+
VALUE **array_ptr;
3213+
size_t len;
3214+
size_t capa;
3215+
};
3216+
3217+
void
3218+
rb_mmtk_build_obj_array_i(MMTk_ObjectReference object, void *data)
3219+
{
3220+
struct rb_mmtk_build_obj_array_data *build_array_data = (struct rb_mmtk_build_obj_array_data*)data;
3221+
VALUE *array = *build_array_data->array_ptr;
3222+
size_t len = build_array_data->len;
3223+
size_t capa = build_array_data->capa;
3224+
if (len == capa) {
3225+
size_t new_capa = capa * 2;
3226+
VALUE *new_array = (VALUE*)realloc(array, sizeof(VALUE) * new_capa);
3227+
*build_array_data->array_ptr = new_array;
3228+
build_array_data->capa = new_capa;
3229+
array = new_array;
3230+
}
3231+
3232+
RUBY_ASSERT(build_array_data->len < build_array_data->capa);
3233+
3234+
array[len] = (VALUE)object;
3235+
build_array_data->len = len + 1;
3236+
}
3237+
3238+
void
3239+
rb_mmtk_each_objects_safe(each_obj_callback *callback, void *data)
3240+
{
3241+
VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
3242+
3243+
// Build an array of object references.
3244+
const size_t initial_capacity = 512;
3245+
VALUE *array = (VALUE*)malloc(sizeof(VALUE) * initial_capacity);
3246+
struct rb_mmtk_build_obj_array_data build_array_data = {
3247+
.array_ptr = &array,
3248+
.len = 0,
3249+
.capa = initial_capacity,
3250+
};
3251+
mmtk_enumerate_objects(rb_mmtk_build_obj_array_i, &build_array_data);
3252+
3253+
// Root the array.
3254+
rb_imemo_tmpbuf_set_ptr(tmpbuf, array);
3255+
3256+
RUBY_DEBUG_LOG("Begin enumerating %zu objects\n", build_array_data.len);
3257+
3258+
// Now enumerate objects
3259+
for (size_t i = 0; i < build_array_data.len; i++) {
3260+
VALUE object = array[i];
3261+
size_t object_size = rb_mmtk_get_object_size(object);
3262+
uintptr_t object_end = object + object_size;
3263+
3264+
RUBY_DEBUG_LOG("Enumerating object: %p\n", (void*)object);
3265+
callback((void*)object, (void*)object_end, object_size, data);
3266+
RB_GC_GUARD(object);
3267+
3268+
// Clear the element so that it no longer pins the object if it dies.
3269+
array[i] = 0;
3270+
}
3271+
3272+
RUBY_DEBUG_LOG("End enumerating %zu objects\n", build_array_data.len);
3273+
3274+
RB_GC_GUARD(tmpbuf);
3275+
}
3276+
#endif
3277+
32103278
void
32113279
rb_gc_impl_each_objects(void *objspace_ptr, each_obj_callback *callback, void *data)
32123280
{
3281+
WHEN_USING_MMTK({
3282+
rb_mmtk_each_objects_safe(callback, data);
3283+
return;
3284+
})
3285+
32133286
objspace_each_objects(objspace_ptr, callback, data, TRUE);
32143287
}
32153288

Diff for: internal/mmtk.h

+6
Original file line numberDiff line numberDiff line change
@@ -254,4 +254,10 @@ bool mmtk_is_object_wb_unprotected(MMTk_ObjectReference object);
254254

255255
void mmtk_object_reference_write_post(MMTk_Mutator *mutator, MMTk_ObjectReference object);
256256

257+
/**
258+
* Enumerate objects. This function will call `callback(object, data)` for each object. It has
259+
* undefined behavior if allocation or GC happens while this function is running.
260+
*/
261+
void mmtk_enumerate_objects(void (*callback)(MMTk_ObjectReference, void*), void *data);
262+
257263
#endif /* MMTK_H */

Diff for: internal/mmtk_support.h

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ void rb_mmtk_destroy_mutator(MMTk_VMMutatorThread cur_thread, bool at_fork);
4949
// Object layout
5050
size_t rb_mmtk_prefix_size(void);
5151
size_t rb_mmtk_suffix_size(void);
52+
size_t rb_mmtk_get_object_size(VALUE object);
5253

5354
// Allocation
5455
VALUE rb_mmtk_alloc_obj(size_t mmtk_alloc_size, size_t size_pool_size, size_t prefix_size);

Diff for: mmtk_support.c

+7
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,13 @@ rb_mmtk_suffix_size(void)
395395
return ruby_binding_options.suffix_size;
396396
}
397397

398+
size_t
399+
rb_mmtk_get_object_size(VALUE object)
400+
{
401+
return *(size_t*)(object - sizeof(VALUE));
402+
}
403+
404+
398405
////////////////////////////////////////////////////////////////////////////////
399406
// Allocation
400407
////////////////////////////////////////////////////////////////////////////////

Diff for: test/.excludes-mmtk/TestISeq.rb

-6
This file was deleted.

Diff for: test/.excludes-mmtk/TestObjectSpace.rb

-3
This file was deleted.

Diff for: test/.excludes-mmtk/TestRubyOptimization.rb

-1
This file was deleted.

Diff for: test/.excludes-mmtk/TestSetTraceFunc.rb

-1
This file was deleted.

Diff for: test/.excludes-mmtk/TestTracepointObj.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
exclude(/test_/, "tracepoints are not supported")
1+
exclude(/test_/, "tracepoints does not supported GC stats yet")

0 commit comments

Comments
 (0)