diff --git a/gc/default.c b/gc/default.c index d9f6623f66013a..1dcc9907ca829d 100644 --- a/gc/default.c +++ b/gc/default.c @@ -2533,7 +2533,7 @@ rb_gc_impl_obj_slot_size(VALUE obj) #if USE_MMTK if (rb_mmtk_enabled_p()) { // Load from our hidden field before the object. - return *(size_t*)(obj - MMTK_OBJREF_OFFSET); + return rb_mmtk_get_payload_size(obj); } #endif @@ -3290,7 +3290,8 @@ rb_mmtk_each_objects_safe(each_obj_callback *callback, void *data) // If GC is triggered in `callback`, `tmpbuf` will keep elements of `array` alive. for (size_t i = 0; i < build_array_data.len; i++) { volatile VALUE object = array[i]; - size_t object_size = rb_mmtk_get_object_size(object); + // This is the "object size" seen by the callback. It's only the payload size. + size_t object_size = rb_mmtk_get_payload_size(object); uintptr_t object_end = object + object_size; RUBY_DEBUG_LOG("Enumerating object: %p\n", (void*)object); diff --git a/internal/mmtk.h b/internal/mmtk.h index 6231694c8f99fa..1f58042365d5d1 100644 --- a/internal/mmtk.h +++ b/internal/mmtk.h @@ -29,6 +29,10 @@ typedef uint32_t MMTk_AllocationSemantics; #define MMTK_GC_THREAD_KIND_WORKER 1 +#define MMTK_HAS_MOVED_GIVTBL 9223372036854775808ull + +#define MMTK_HIDDEN_SIZE_MASK 281474976710655 + typedef struct st_table st_table; typedef struct RubyBindingOptions { @@ -112,6 +116,10 @@ typedef struct MMTk_RawVecOfObjRef { size_t capa; } MMTk_RawVecOfObjRef; +typedef struct MMTk_HiddenHeader { + size_t prefix; +} MMTk_HiddenHeader; + /** * Create an MMTKBuilder instance with default options. * This instance shall be consumed by `mmtk_init_binding`. diff --git a/internal/mmtk_support.h b/internal/mmtk_support.h index bca8c2b72c2052..5977806ab84869 100644 --- a/internal/mmtk_support.h +++ b/internal/mmtk_support.h @@ -49,7 +49,8 @@ void rb_mmtk_destroy_mutator(MMTk_VMMutatorThread cur_thread, bool at_fork); // Object layout size_t rb_mmtk_prefix_size(void); size_t rb_mmtk_suffix_size(void); -size_t rb_mmtk_get_object_size(VALUE object); +void rb_mmtk_init_hidden_header(VALUE object, size_t payload_size); +size_t rb_mmtk_get_payload_size(VALUE object); // Allocation VALUE rb_mmtk_alloc_obj(size_t mmtk_alloc_size, size_t size_pool_size, size_t prefix_size); diff --git a/mmtk_support.c b/mmtk_support.c index abd6197ee8b1ed..e060f078909be1 100644 --- a/mmtk_support.c +++ b/mmtk_support.c @@ -395,12 +395,27 @@ rb_mmtk_suffix_size(void) return ruby_binding_options.suffix_size; } -size_t -rb_mmtk_get_object_size(VALUE object) +void +rb_mmtk_init_hidden_header(VALUE object, size_t payload_size) { - return *(size_t*)(object - sizeof(VALUE)); + RUBY_ASSERT(payload_size <= MMTK_HIDDEN_SIZE_MASK, + "payload size greater than MMTK_HIDDEN_SIZE_MASK. payload_size: %zu", payload_size); + + struct MMTk_HiddenHeader *hidden_header = (struct MMTk_HiddenHeader*)(object - MMTK_OBJREF_OFFSET); + hidden_header->prefix = payload_size; } +size_t +rb_mmtk_get_payload_size(VALUE object) +{ + struct MMTk_HiddenHeader *hidden_header = (struct MMTk_HiddenHeader*)(object - MMTK_OBJREF_OFFSET); + size_t prefix = hidden_header->prefix; + + RUBY_ASSERT((prefix & ~(MMTK_HIDDEN_SIZE_MASK | MMTK_HAS_MOVED_GIVTBL)) == 0, + "Hidden field is corrupted. Object: %p, prefix: %zx", (void*) object, prefix); + + return prefix & MMTK_HIDDEN_SIZE_MASK; +} //////////////////////////////////////////////////////////////////////////////// // Allocation @@ -495,13 +510,13 @@ rb_mmtk_alloc_obj(size_t mmtk_alloc_size, size_t size_pool_size, size_t prefix_s // Allocate the object. void *addr = rb_mmtk_alloc(mmtk_alloc_size, semantics); - // Store the Ruby-level object size before the object. - *(size_t*)addr = size_pool_size; - // The Ruby-level object reference (i.e. VALUE) is at an offset from the MMTk-level // allocation unit. VALUE obj = (VALUE)addr + prefix_size; + // Store the Ruby-level object size before the object. + rb_mmtk_init_hidden_header(obj, size_pool_size); + rb_mmtk_post_alloc(obj, mmtk_alloc_size, semantics); return obj;