diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c index dbb3545..60bbbfc 100644 --- a/gc/mmtk/mmtk.c +++ b/gc/mmtk/mmtk.c @@ -57,6 +57,7 @@ struct objspace { uintptr_t vo_bit_log_region_size; uintptr_t vo_bit_base_addr; + size_t max_non_los_default_alloc_bytes; }; #define OBJ_FREE_BUF_CAPACITY 128 @@ -110,6 +111,7 @@ RB_THREAD_LOCAL_SPECIFIER VALUE marking_parent_object; #include #define MMTK_ALLOCATION_SEMANTICS_DEFAULT 0 +#define MMTK_ALLOCATION_SEMANTICS_LOS 2 static inline VALUE rb_mmtk_call_object_closure(VALUE obj, bool pin); @@ -604,6 +606,7 @@ rb_gc_impl_objspace_init(void *objspace_ptr) objspace->vo_bit_log_region_size = mmtk_get_vo_bit_log_region_size(); objspace->vo_bit_base_addr = mmtk_get_vo_bit_base_addr(); + objspace->max_non_los_default_alloc_bytes = mmtk_max_non_los_default_alloc_bytes(); } void @@ -670,8 +673,6 @@ void rb_gc_impl_set_params(void *objspace_ptr) { } static VALUE gc_verify_internal_consistency(VALUE self) { return Qnil; } -#define MMTK_MAX_OBJ_SIZE 1024 - static inline size_t rb_mmtk_align_obj_size(size_t object_size) { @@ -685,12 +686,12 @@ rb_gc_impl_zjit_new_obj_fastpath(void *objspace_ptr, size_t alloc_size, VALUE fl #if USE_ZJIT && RB_GC_OBJ_SUFFIX_SIZE == 0 struct objspace *objspace = objspace_ptr; - if (alloc_size > MMTK_MAX_OBJ_SIZE) return false; - size_t total_size = rb_mmtk_align_obj_size(alloc_size + sizeof(VALUE) + RB_GC_OBJ_SUFFIX_SIZE); size_t object_size = total_size - sizeof(VALUE) - RB_GC_OBJ_SUFFIX_SIZE; size_t value_size_shift = sizeof(VALUE) == 8 ? 3 : 2; + if (total_size > objspace->max_non_los_default_alloc_bytes) return false; + struct rb_gc_zjit_mmtk_new_obj_fastpath mmtk_fastpath = { objspace, offsetof(struct objspace, total_allocated_objects), @@ -730,7 +731,6 @@ rb_gc_impl_init(void) rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX]))); rb_hash_aset(gc_constants, ID2SYM(rb_intern("RBASIC_SIZE")), SIZET2NUM(sizeof(struct RBasic))); rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OVERHEAD")), INT2NUM(0)); - rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(MMTK_MAX_OBJ_SIZE)); // TODO: correctly set RVALUE_OLD_AGE when we have generational GC support rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OLD_AGE")), INT2FIX(0)); OBJ_FREEZE(gc_constants); @@ -960,22 +960,27 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags struct objspace *objspace = objspace_ptr; struct MMTk_ractor_cache *ractor_cache = cache_ptr; - if (alloc_size == 0 || alloc_size > MMTK_MAX_OBJ_SIZE) { - rb_bug("rb_gc_impl_new_obj: allocation size too large (size=%"PRIuSIZE")", alloc_size); + if (alloc_size == 0) { + rb_bug("rb_gc_impl_new_obj: allocation size out of range (size=%"PRIuSIZE")", alloc_size); } // Layout: [hidden size header (sizeof(VALUE))][payload (alloc_size)][suffix (RB_GC_OBJ_SUFFIX_SIZE)] size_t total_size = rb_mmtk_align_obj_size(alloc_size + sizeof(VALUE) + RB_GC_OBJ_SUFFIX_SIZE); size_t object_size = total_size - sizeof(VALUE) - RB_GC_OBJ_SUFFIX_SIZE; + MMTk_AllocationSemantics semantics = total_size > objspace->max_non_los_default_alloc_bytes + ? MMTK_ALLOCATION_SEMANTICS_LOS + : MMTK_ALLOCATION_SEMANTICS_DEFAULT; *actual_alloc_size = object_size; if (objspace->gc_stress) { mmtk_handle_user_collection_request(ractor_cache, false, false); } - VALUE *alloc_obj = (VALUE *)rb_mmtk_alloc_fast_path(objspace, ractor_cache, total_size, MMTk_MIN_OBJ_ALIGN); + VALUE *alloc_obj = semantics == MMTK_ALLOCATION_SEMANTICS_DEFAULT + ? (VALUE *)rb_mmtk_alloc_fast_path(objspace, ractor_cache, total_size, MMTk_MIN_OBJ_ALIGN) + : NULL; if (!alloc_obj) { - alloc_obj = mmtk_alloc(ractor_cache->mutator, total_size, MMTk_MIN_OBJ_ALIGN, 0, MMTK_ALLOCATION_SEMANTICS_DEFAULT); + alloc_obj = mmtk_alloc(ractor_cache->mutator, total_size, MMTk_MIN_OBJ_ALIGN, 0, semantics); // On heap exhaustion raise NoMemoryError. if (RB_UNLIKELY(alloc_obj == NULL)) { @@ -988,8 +993,8 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags alloc_obj[0] = flags; alloc_obj[1] = klass; - if (ractor_cache->bump_pointer == NULL) { - mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, object_size, MMTK_ALLOCATION_SEMANTICS_DEFAULT); + if (semantics == MMTK_ALLOCATION_SEMANTICS_LOS || ractor_cache->bump_pointer == NULL) { + mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, total_size, semantics); } else { // We can use the post alloc fast path if we're using Immix bump pointer allocator @@ -1013,7 +1018,7 @@ rb_gc_impl_obj_slot_size(VALUE obj) size_t rb_gc_impl_size_slot_size(void *objspace_ptr, size_t size) { - if (size == 0 || size > MMTK_MAX_OBJ_SIZE) { + if (size == 0) { rb_bug("rb_gc_impl_size_slot_size: size too large (size=%"PRIuSIZE")", size); } @@ -1023,13 +1028,13 @@ rb_gc_impl_size_slot_size(void *objspace_ptr, size_t size) bool rb_gc_impl_size_allocatable_p(size_t size) { - return size <= MMTK_MAX_OBJ_SIZE; + return true; } size_t rb_gc_impl_max_allocation_size(void) { - return MMTK_MAX_OBJ_SIZE; + return SIZE_MAX; } // Malloc diff --git a/gc/mmtk/mmtk.h b/gc/mmtk/mmtk.h index 42edeb1..7f330b8 100644 --- a/gc/mmtk/mmtk.h +++ b/gc/mmtk/mmtk.h @@ -115,6 +115,8 @@ void mmtk_set_gc_enabled(bool enable); bool mmtk_gc_enabled_p(void); +size_t mmtk_max_non_los_default_alloc_bytes(void); + MMTk_Address mmtk_alloc(MMTk_Mutator *mutator, size_t size, size_t align, diff --git a/gc/mmtk/src/api.rs b/gc/mmtk/src/api.rs index 936baf7..e8770d4 100644 --- a/gc/mmtk/src/api.rs +++ b/gc/mmtk/src/api.rs @@ -314,6 +314,14 @@ pub extern "C" fn mmtk_gc_enabled_p() -> bool { // =============== Object allocation =============== +#[no_mangle] +pub extern "C" fn mmtk_max_non_los_default_alloc_bytes() -> usize { + mmtk() + .get_plan() + .constraints() + .max_non_los_default_alloc_bytes +} + #[no_mangle] pub unsafe extern "C" fn mmtk_alloc( mutator: *mut RubyMutator, diff --git a/test/.excludes-mmtk/TestStruct/SubStruct.rb b/test/.excludes-mmtk/TestStruct/SubStruct.rb new file mode 100644 index 0000000..709cd0f --- /dev/null +++ b/test/.excludes-mmtk/TestStruct/SubStruct.rb @@ -0,0 +1 @@ +exclude(:test_larger_than_largest_pool, "depends on max slot size") diff --git a/test/.excludes-mmtk/TestStruct/TopStruct.rb b/test/.excludes-mmtk/TestStruct/TopStruct.rb new file mode 100644 index 0000000..709cd0f --- /dev/null +++ b/test/.excludes-mmtk/TestStruct/TopStruct.rb @@ -0,0 +1 @@ +exclude(:test_larger_than_largest_pool, "depends on max slot size") diff --git a/test/.excludes-mmtk/Test_StringCapacity.rb b/test/.excludes-mmtk/Test_StringCapacity.rb new file mode 100644 index 0000000..59b47a5 --- /dev/null +++ b/test/.excludes-mmtk/Test_StringCapacity.rb @@ -0,0 +1,7 @@ +exclude(:test_capacity_embedded, "depends on max slot size") +exclude(:test_capacity_frozen, "depends on max slot size") +exclude(:test_capacity_fstring, "depends on max slot size") +exclude(:test_capacity_normal, "depends on max slot size") +exclude(:test_io_read, "depends on max slot size") +exclude(:test_literal_capacity, "depends on max slot size") +exclude(:test_s_new_capacity, "depends on max slot size")