@@ -3207,9 +3207,105 @@ objspace_each_objects(rb_objspace_t *objspace, each_obj_callback *callback, void
3207
3207
objspace_each_exec (protected , & each_obj_data );
3208
3208
}
3209
3209
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
+ // Allocate a tmpbuf object. It's OK if it triggers GC now.
3242
+ volatile VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer ();
3243
+
3244
+ // Build an array of object references.
3245
+ const size_t initial_capacity = 512 ;
3246
+ // We must not trigger GC while running `mmtk_enumerate_objects`,
3247
+ // so we use `malloc` directly.
3248
+ // It will be realloced as we add more objects.
3249
+ VALUE * array = (VALUE * )malloc (sizeof (VALUE ) * initial_capacity );
3250
+ struct rb_mmtk_build_obj_array_data build_array_data = {
3251
+ .array_ptr = & array ,
3252
+ .len = 0 ,
3253
+ .capa = initial_capacity ,
3254
+ };
3255
+
3256
+ // No GC from now on.
3257
+ mmtk_enumerate_objects (rb_mmtk_build_obj_array_i , & build_array_data );
3258
+
3259
+ // Root the array.
3260
+ rb_imemo_tmpbuf_set_ptr (tmpbuf , array );
3261
+ ((rb_imemo_tmpbuf_t * )tmpbuf )-> cnt = build_array_data .len ;
3262
+ // GC is OK from now on.
3263
+
3264
+ // Inform the VM about malloc memory usage.
3265
+ // Since elements of `array` are rooted by `tmpbuf`, it is safe to trigger GC.
3266
+ // The GC won't free any object because we have just rooted every object.
3267
+ // But the GC may adjust the threshold for triggering the next GC.
3268
+ rb_gc_adjust_memory_usage (sizeof (VALUE ) * build_array_data .capa );
3269
+
3270
+ RUBY_DEBUG_LOG ("Begin enumerating %zu objects\n" , build_array_data .len );
3271
+
3272
+ // Now enumerate objects.
3273
+ // If GC is triggered in `callback`, `tmpbuf` will keep elements of `array` alive.
3274
+ for (size_t i = 0 ; i < build_array_data .len ; i ++ ) {
3275
+ volatile VALUE object = array [i ];
3276
+ size_t object_size = rb_mmtk_get_object_size (object );
3277
+ uintptr_t object_end = object + object_size ;
3278
+
3279
+ RUBY_DEBUG_LOG ("Enumerating object: %p\n" , (void * )object );
3280
+ callback ((void * )object , (void * )object_end , object_size , data );
3281
+ RB_GC_GUARD (object );
3282
+
3283
+ // Clear the element so that it no longer pins the object if it dies.
3284
+ array [i ] = 0 ;
3285
+ }
3286
+
3287
+ RUBY_DEBUG_LOG ("End enumerating %zu objects\n" , build_array_data .len );
3288
+
3289
+ // Explicitly free `array` because we know it is no longer used.
3290
+ // Don't wait for GC to free it because `free()` is a bottleneck during GC.
3291
+ // Adjust memory usage accordingly.
3292
+ rb_imemo_tmpbuf_set_ptr (tmpbuf , NULL );
3293
+ ((rb_imemo_tmpbuf_t * )tmpbuf )-> cnt = 0 ;
3294
+ free (array );
3295
+ rb_gc_adjust_memory_usage (- (ssize_t )(sizeof (VALUE ) * build_array_data .capa ));
3296
+
3297
+ RB_GC_GUARD (tmpbuf );
3298
+ }
3299
+ #endif
3300
+
3210
3301
void
3211
3302
rb_gc_impl_each_objects (void * objspace_ptr , each_obj_callback * callback , void * data )
3212
3303
{
3304
+ WHEN_USING_MMTK ({
3305
+ rb_mmtk_each_objects_safe (callback , data );
3306
+ return ;
3307
+ })
3308
+
3213
3309
objspace_each_objects (objspace_ptr , callback , data , TRUE);
3214
3310
}
3215
3311
0 commit comments