Skip to content

Commit 6e14928

Browse files
authored
Merge pull request #98 from ruby/alloc-large-objects
Implement large object space
2 parents 11ea3a4 + 62fde9f commit 6e14928

6 files changed

Lines changed: 38 additions & 14 deletions

File tree

gc/mmtk/mmtk.c

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct objspace {
5757

5858
uintptr_t vo_bit_log_region_size;
5959
uintptr_t vo_bit_base_addr;
60+
size_t max_non_los_default_alloc_bytes;
6061
};
6162

6263
#define OBJ_FREE_BUF_CAPACITY 128
@@ -110,6 +111,7 @@ RB_THREAD_LOCAL_SPECIFIER VALUE marking_parent_object;
110111
#include <pthread.h>
111112

112113
#define MMTK_ALLOCATION_SEMANTICS_DEFAULT 0
114+
#define MMTK_ALLOCATION_SEMANTICS_LOS 2
113115

114116
static inline VALUE rb_mmtk_call_object_closure(VALUE obj, bool pin);
115117

@@ -604,6 +606,7 @@ rb_gc_impl_objspace_init(void *objspace_ptr)
604606

605607
objspace->vo_bit_log_region_size = mmtk_get_vo_bit_log_region_size();
606608
objspace->vo_bit_base_addr = mmtk_get_vo_bit_base_addr();
609+
objspace->max_non_los_default_alloc_bytes = mmtk_max_non_los_default_alloc_bytes();
607610
}
608611

609612
void
@@ -670,8 +673,6 @@ void rb_gc_impl_set_params(void *objspace_ptr) { }
670673

671674
static VALUE gc_verify_internal_consistency(VALUE self) { return Qnil; }
672675

673-
#define MMTK_MAX_OBJ_SIZE 1024
674-
675676
static inline size_t
676677
rb_mmtk_align_obj_size(size_t object_size)
677678
{
@@ -685,12 +686,12 @@ rb_gc_impl_zjit_new_obj_fastpath(void *objspace_ptr, size_t alloc_size, VALUE fl
685686
#if USE_ZJIT && RB_GC_OBJ_SUFFIX_SIZE == 0
686687
struct objspace *objspace = objspace_ptr;
687688

688-
if (alloc_size > MMTK_MAX_OBJ_SIZE) return false;
689-
690689
size_t total_size = rb_mmtk_align_obj_size(alloc_size + sizeof(VALUE) + RB_GC_OBJ_SUFFIX_SIZE);
691690
size_t object_size = total_size - sizeof(VALUE) - RB_GC_OBJ_SUFFIX_SIZE;
692691
size_t value_size_shift = sizeof(VALUE) == 8 ? 3 : 2;
693692

693+
if (total_size > objspace->max_non_los_default_alloc_bytes) return false;
694+
694695
struct rb_gc_zjit_mmtk_new_obj_fastpath mmtk_fastpath = {
695696
objspace,
696697
offsetof(struct objspace, total_allocated_objects),
@@ -730,7 +731,6 @@ rb_gc_impl_init(void)
730731
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX])));
731732
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RBASIC_SIZE")), SIZET2NUM(sizeof(struct RBasic)));
732733
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OVERHEAD")), INT2NUM(0));
733-
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(MMTK_MAX_OBJ_SIZE));
734734
// TODO: correctly set RVALUE_OLD_AGE when we have generational GC support
735735
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OLD_AGE")), INT2FIX(0));
736736
OBJ_FREEZE(gc_constants);
@@ -960,22 +960,27 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
960960
struct objspace *objspace = objspace_ptr;
961961
struct MMTk_ractor_cache *ractor_cache = cache_ptr;
962962

963-
if (alloc_size == 0 || alloc_size > MMTK_MAX_OBJ_SIZE) {
964-
rb_bug("rb_gc_impl_new_obj: allocation size too large (size=%"PRIuSIZE")", alloc_size);
963+
if (alloc_size == 0) {
964+
rb_bug("rb_gc_impl_new_obj: allocation size out of range (size=%"PRIuSIZE")", alloc_size);
965965
}
966966

967967
// Layout: [hidden size header (sizeof(VALUE))][payload (alloc_size)][suffix (RB_GC_OBJ_SUFFIX_SIZE)]
968968
size_t total_size = rb_mmtk_align_obj_size(alloc_size + sizeof(VALUE) + RB_GC_OBJ_SUFFIX_SIZE);
969969
size_t object_size = total_size - sizeof(VALUE) - RB_GC_OBJ_SUFFIX_SIZE;
970+
MMTk_AllocationSemantics semantics = total_size > objspace->max_non_los_default_alloc_bytes
971+
? MMTK_ALLOCATION_SEMANTICS_LOS
972+
: MMTK_ALLOCATION_SEMANTICS_DEFAULT;
970973
*actual_alloc_size = object_size;
971974

972975
if (objspace->gc_stress) {
973976
mmtk_handle_user_collection_request(ractor_cache, false, false);
974977
}
975978

976-
VALUE *alloc_obj = (VALUE *)rb_mmtk_alloc_fast_path(objspace, ractor_cache, total_size, MMTk_MIN_OBJ_ALIGN);
979+
VALUE *alloc_obj = semantics == MMTK_ALLOCATION_SEMANTICS_DEFAULT
980+
? (VALUE *)rb_mmtk_alloc_fast_path(objspace, ractor_cache, total_size, MMTk_MIN_OBJ_ALIGN)
981+
: NULL;
977982
if (!alloc_obj) {
978-
alloc_obj = mmtk_alloc(ractor_cache->mutator, total_size, MMTk_MIN_OBJ_ALIGN, 0, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
983+
alloc_obj = mmtk_alloc(ractor_cache->mutator, total_size, MMTk_MIN_OBJ_ALIGN, 0, semantics);
979984

980985
// On heap exhaustion raise NoMemoryError.
981986
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
988993
alloc_obj[0] = flags;
989994
alloc_obj[1] = klass;
990995

991-
if (ractor_cache->bump_pointer == NULL) {
992-
mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, object_size, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
996+
if (semantics == MMTK_ALLOCATION_SEMANTICS_LOS || ractor_cache->bump_pointer == NULL) {
997+
mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, total_size, semantics);
993998
}
994999
else {
9951000
// 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)
10131018
size_t
10141019
rb_gc_impl_size_slot_size(void *objspace_ptr, size_t size)
10151020
{
1016-
if (size == 0 || size > MMTK_MAX_OBJ_SIZE) {
1021+
if (size == 0) {
10171022
rb_bug("rb_gc_impl_size_slot_size: size too large (size=%"PRIuSIZE")", size);
10181023
}
10191024

@@ -1023,13 +1028,13 @@ rb_gc_impl_size_slot_size(void *objspace_ptr, size_t size)
10231028
bool
10241029
rb_gc_impl_size_allocatable_p(size_t size)
10251030
{
1026-
return size <= MMTK_MAX_OBJ_SIZE;
1031+
return true;
10271032
}
10281033

10291034
size_t
10301035
rb_gc_impl_max_allocation_size(void)
10311036
{
1032-
return MMTK_MAX_OBJ_SIZE;
1037+
return SIZE_MAX;
10331038
}
10341039

10351040
// Malloc

gc/mmtk/mmtk.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ void mmtk_set_gc_enabled(bool enable);
115115

116116
bool mmtk_gc_enabled_p(void);
117117

118+
size_t mmtk_max_non_los_default_alloc_bytes(void);
119+
118120
MMTk_Address mmtk_alloc(MMTk_Mutator *mutator,
119121
size_t size,
120122
size_t align,

gc/mmtk/src/api.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,14 @@ pub extern "C" fn mmtk_gc_enabled_p() -> bool {
314314

315315
// =============== Object allocation ===============
316316

317+
#[no_mangle]
318+
pub extern "C" fn mmtk_max_non_los_default_alloc_bytes() -> usize {
319+
mmtk()
320+
.get_plan()
321+
.constraints()
322+
.max_non_los_default_alloc_bytes
323+
}
324+
317325
#[no_mangle]
318326
pub unsafe extern "C" fn mmtk_alloc(
319327
mutator: *mut RubyMutator,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exclude(:test_larger_than_largest_pool, "depends on max slot size")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exclude(:test_larger_than_largest_pool, "depends on max slot size")
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
exclude(:test_capacity_embedded, "depends on max slot size")
2+
exclude(:test_capacity_frozen, "depends on max slot size")
3+
exclude(:test_capacity_fstring, "depends on max slot size")
4+
exclude(:test_capacity_normal, "depends on max slot size")
5+
exclude(:test_io_read, "depends on max slot size")
6+
exclude(:test_literal_capacity, "depends on max slot size")
7+
exclude(:test_s_new_capacity, "depends on max slot size")

0 commit comments

Comments
 (0)