Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bootstraptest/test_ractor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2163,7 +2163,7 @@ def ==(o)

# move object with complex generic ivars
assert_equal 'ok', %q{
# Make Array too_complex
# Make Array complex
30.times { |i| [].instance_variable_set(:"@complex#{i}", 1) }

ractor = Ractor.new { Ractor.receive }
Expand All @@ -2190,7 +2190,7 @@ def ==(o)

# copy object with complex generic ivars
assert_equal 'ok', %q{
# Make Array too_complex
# Make Array complex
30.times { |i| [].instance_variable_set(:"@complex#{i}", 1) }

ractor = Ractor.new { Ractor.receive }
Expand Down
2 changes: 1 addition & 1 deletion debug_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ RB_DEBUG_COUNTER(obj_wb_unprotect)

RB_DEBUG_COUNTER(obj_obj_embed)
RB_DEBUG_COUNTER(obj_obj_ptr)
RB_DEBUG_COUNTER(obj_obj_too_complex)
RB_DEBUG_COUNTER(obj_obj_complex)

RB_DEBUG_COUNTER(obj_str_ptr)
RB_DEBUG_COUNTER(obj_str_embed)
Expand Down
4 changes: 2 additions & 2 deletions ext/objspace/objspace_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,8 @@ dump_object(VALUE obj, struct dump_config *dc)

dump_append(dc, ", \"ivars\":");
dump_append_lu(dc, ROBJECT_FIELDS_COUNT(obj));
if (rb_shape_obj_too_complex_p(obj)) {
dump_append(dc, ", \"too_complex_shape\":true");
if (rb_obj_shape_complex_p(obj)) {
dump_append(dc, ", \"complex_shape\":true");
}
break;

Expand Down
75 changes: 47 additions & 28 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1069,27 +1069,46 @@ rb_newobj_of(VALUE klass, VALUE flags, size_t size)
return rb_newobj(GET_EC(), klass, flags, ROOT_SHAPE_ID, true, size);
}

static
VALUE class_allocate_complex_instance(VALUE klass, uint32_t capacity)
{
shape_id_t initial_shape_id = rb_shape_root(rb_gc_heap_id_for_size(sizeof(struct RObject)));
VALUE obj = rb_newobj_of_with_shape(klass, T_OBJECT, initial_shape_id, sizeof(struct RObject));
rb_obj_init_complex(obj, rb_st_init_numtable_with_size(capacity));
return obj;
}

VALUE
rb_class_allocate_instance(VALUE klass)
{
uint32_t index_tbl_num_entries = RCLASS_MAX_IV_COUNT(klass);
VALUE obj;

size_t size = rb_obj_embedded_size(index_tbl_num_entries);
if (!rb_gc_size_allocatable_p(size)) {
size = sizeof(struct RObject);
// Directly start as COMPLEX if we know we're over the limit.
RUBY_ASSERT(rb_shape_tree.max_capacity > 0);
if (RB_UNLIKELY(index_tbl_num_entries > rb_shape_tree.max_capacity)) {
obj = class_allocate_complex_instance(klass, index_tbl_num_entries);
}
else {
size_t size = rb_obj_embedded_size(index_tbl_num_entries);
if (!rb_gc_size_allocatable_p(size)) {
size = sizeof(struct RObject);
}

// There might be a NEWOBJ tracepoint callback, and it may set fields.
// So the shape must be passed to `NEWOBJ_OF`.
VALUE obj = rb_newobj_of_with_shape(klass, T_OBJECT, rb_shape_root(rb_gc_heap_id_for_size(size)), size);
// There might be a NEWOBJ tracepoint callback, and it may set fields.
// So the shape must be passed to `NEWOBJ_OF`.
obj = rb_newobj_of_with_shape(klass, T_OBJECT, rb_shape_root(rb_gc_heap_id_for_size(size)), size);

#if RUBY_DEBUG
RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
VALUE *ptr = ROBJECT_FIELDS(obj);
size_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
for (size_t i = fields_count; i < ROBJECT_FIELDS_CAPACITY(obj); i++) {
ptr[i] = Qundef;
#if RUBY_DEBUG
VALUE *ptr = ROBJECT_FIELDS(obj);
size_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
for (size_t i = fields_count; i < ROBJECT_FIELDS_CAPACITY(obj); i++) {
ptr[i] = Qundef;
}
#endif
}

#if RUBY_DEBUG
if (rb_obj_class(obj) != rb_class_real(klass)) {
rb_bug("Expected rb_class_allocate_instance to set the class correctly");
}
Expand Down Expand Up @@ -1322,7 +1341,7 @@ rb_gc_imemo_needs_cleanup_p(VALUE obj)
return ((rb_imemo_tmpbuf_t *)obj)->ptr != NULL;

case imemo_fields:
return FL_TEST_RAW(obj, OBJ_FIELD_HEAP) || (id2ref_tbl && rb_shape_obj_has_id(obj));
return FL_TEST_RAW(obj, OBJ_FIELD_HEAP) || (id2ref_tbl && rb_obj_shape_has_id(obj));
}
UNREACHABLE_RETURN(true);
}
Expand Down Expand Up @@ -1524,8 +1543,8 @@ rb_gc_obj_free(void *objspace, VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
if (rb_shape_obj_too_complex_p(obj)) {
RB_DEBUG_COUNTER_INC(obj_obj_too_complex);
if (rb_obj_shape_complex_p(obj)) {
RB_DEBUG_COUNTER_INC(obj_obj_complex);
st_free_table(ROBJECT_FIELDS_HASH(obj));
}
else {
Expand Down Expand Up @@ -2127,8 +2146,8 @@ static inline VALUE
object_id_get(VALUE obj, shape_id_t shape_id)
{
VALUE id;
if (rb_shape_too_complex_p(shape_id)) {
id = rb_obj_field_get(obj, ROOT_TOO_COMPLEX_WITH_OBJ_ID);
if (rb_shape_complex_p(shape_id)) {
id = rb_obj_field_get(obj, ROOT_COMPLEX_WITH_OBJ_ID);
}
else {
id = rb_obj_field_get(obj, rb_shape_object_id(shape_id));
Expand Down Expand Up @@ -2160,7 +2179,7 @@ object_id0(VALUE obj)
rb_obj_field_set(obj, object_id_shape_id, 0, id);

RUBY_ASSERT(RBASIC_SHAPE_ID(obj) == object_id_shape_id);
RUBY_ASSERT(rb_shape_obj_has_id(obj));
RUBY_ASSERT(rb_obj_shape_has_id(obj));

if (RB_UNLIKELY(id2ref_tbl)) {
RB_VM_LOCKING() {
Expand Down Expand Up @@ -2212,13 +2231,13 @@ build_id2ref_i(VALUE obj, void *data)
break;
case T_IMEMO:
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
if (IMEMO_TYPE_P(obj, imemo_fields) && rb_shape_obj_has_id(obj)) {
if (IMEMO_TYPE_P(obj, imemo_fields) && rb_obj_shape_has_id(obj)) {
st_insert(id2ref_tbl, rb_obj_id(obj), rb_imemo_fields_owner(obj));
}
break;
case T_OBJECT:
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
if (rb_shape_obj_has_id(obj)) {
if (rb_obj_shape_has_id(obj)) {
st_insert(id2ref_tbl, rb_obj_id(obj), obj);
}
break;
Expand Down Expand Up @@ -2485,7 +2504,7 @@ rb_obj_id(VALUE obj)
bool
rb_obj_id_p(VALUE obj)
{
return !RB_TYPE_P(obj, T_IMEMO) && rb_shape_obj_has_id(obj);
return !RB_TYPE_P(obj, T_IMEMO) && rb_obj_shape_has_id(obj);
}

/*
Expand Down Expand Up @@ -2566,7 +2585,7 @@ rb_obj_memsize_of(VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
if (rb_shape_obj_too_complex_p(obj)) {
if (rb_obj_shape_complex_p(obj)) {
size += rb_st_memsize(ROBJECT_FIELDS_HASH(obj));
}
else {
Expand Down Expand Up @@ -3472,7 +3491,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)

case T_OBJECT: {
uint32_t len;
if (rb_shape_obj_too_complex_p(obj)) {
if (rb_obj_shape_complex_p(obj)) {
gc_mark_tbl_no_pin(ROBJECT_FIELDS_HASH(obj));
len = ROBJECT_FIELDS_COUNT_COMPLEX(obj);
}
Expand Down Expand Up @@ -3530,7 +3549,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
gc_mark_internal(ptr[i]);
}

if (rb_shape_obj_has_fields(obj) && !FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS)) {
if (rb_obj_shape_has_fields(obj) && !FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS)) {
gc_mark_internal(RSTRUCT_FIELDS_OBJ(obj));
}

Expand Down Expand Up @@ -3563,7 +3582,7 @@ rb_gc_obj_optimal_size(VALUE obj)
}

case T_OBJECT:
if (rb_shape_obj_too_complex_p(obj)) {
if (rb_obj_shape_complex_p(obj)) {
return sizeof(struct RObject);
}
else {
Expand Down Expand Up @@ -3830,7 +3849,7 @@ gc_ref_update_object(void *objspace, VALUE v)
VALUE *ptr = ROBJECT_FIELDS(v);

if (FL_TEST_RAW(v, ROBJECT_HEAP)) {
if (rb_shape_obj_too_complex_p(v)) {
if (rb_obj_shape_complex_p(v)) {
gc_ref_update_table_values_only(ROBJECT_FIELDS_HASH(v));
return;
}
Expand Down Expand Up @@ -5018,9 +5037,9 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
case T_OBJECT:
{
if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
if (rb_shape_obj_too_complex_p(obj)) {
if (rb_obj_shape_complex_p(obj)) {
size_t hash_len = rb_st_table_size(ROBJECT_FIELDS_HASH(obj));
APPEND_F("(too_complex) len:%zu", hash_len);
APPEND_F("(complex) len:%zu", hash_len);
}
else {
APPEND_F("(embed) len:%d capa:%d", RSHAPE_LEN(RBASIC_SHAPE_ID(obj)), ROBJECT_FIELDS_CAPACITY(obj));
Expand Down
37 changes: 11 additions & 26 deletions imemo.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,16 +128,10 @@ rb_imemo_fields_new(VALUE owner, shape_id_t shape_id, bool shareable)
{
size_t capa = RSHAPE_CAPACITY(shape_id);
size_t embedded_size = offsetof(struct rb_fields, as.embed) + capa * sizeof(VALUE);
VALUE fields;
if (rb_gc_size_allocatable_p(embedded_size)) {
fields = rb_imemo_new(imemo_fields, owner, embedded_size, shareable);
}
else {
fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable);
IMEMO_OBJ_FIELDS(fields)->as.external.ptr = ALLOC_N(VALUE, capa);
FL_SET_RAW(fields, OBJ_FIELD_HEAP);
}
RUBY_ASSERT(rb_gc_size_allocatable_p(embedded_size));
VALUE fields = rb_imemo_new(imemo_fields, owner, embedded_size, shareable);
RBASIC_SET_SHAPE_ID(fields, shape_id);
RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_fields));
return fields;
}

Expand Down Expand Up @@ -183,7 +177,7 @@ rb_imemo_fields_clone(VALUE fields_obj)
shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
VALUE clone;

if (rb_shape_too_complex_p(shape_id)) {
if (rb_shape_complex_p(shape_id)) {
st_table *src_table = rb_imemo_fields_complex_tbl(fields_obj);

st_table *dest_table = xcalloc(1, sizeof(st_table));
Expand Down Expand Up @@ -211,8 +205,8 @@ rb_imemo_fields_clear(VALUE fields_obj)
{
// When replacing an imemo/fields by another one, we must clear
// its shape so that gc.c:obj_free_object_id won't be called.
if (rb_shape_obj_too_complex_p(fields_obj)) {
RBASIC_SET_SHAPE_ID(fields_obj, ROOT_TOO_COMPLEX_SHAPE_ID);
if (rb_obj_shape_complex_p(fields_obj)) {
RBASIC_SET_SHAPE_ID(fields_obj, ROOT_COMPLEX_SHAPE_ID);
}
else {
RBASIC_SET_SHAPE_ID(fields_obj, ROOT_SHAPE_ID);
Expand Down Expand Up @@ -265,13 +259,8 @@ rb_imemo_memsize(VALUE obj)
case imemo_cvar_entry:
break;
case imemo_fields:
if (FL_TEST_RAW(obj, OBJ_FIELD_HEAP)) {
if (rb_shape_obj_too_complex_p(obj)) {
size += st_memsize(IMEMO_OBJ_FIELDS(obj)->as.complex.table);
}
else {
size += RSHAPE_CAPACITY(RBASIC_SHAPE_ID(obj)) * sizeof(VALUE);
}
if (rb_obj_shape_complex_p(obj)) {
size += st_memsize(IMEMO_OBJ_FIELDS(obj)->as.complex.table);
}
break;
default:
Expand Down Expand Up @@ -524,7 +513,7 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
// imemo_fields can refer unshareable objects
// even if the imemo_fields is shareable.

if (rb_shape_obj_too_complex_p(obj)) {
if (rb_obj_shape_complex_p(obj)) {
st_table *tbl = rb_imemo_fields_complex_tbl(obj);
if (reference_updating) {
rb_gc_ref_update_table_values_only(tbl);
Expand Down Expand Up @@ -572,12 +561,8 @@ imemo_fields_free(struct rb_fields *fields)
{
if (FL_TEST_RAW((VALUE)fields, OBJ_FIELD_HEAP)) {
shape_id_t shape_id = RBASIC_SHAPE_ID((VALUE)fields);
if (rb_shape_too_complex_p(shape_id)) {
st_free_table(fields->as.complex.table);
}
else {
SIZED_FREE_N(fields->as.external.ptr, RSHAPE_CAPACITY(shape_id));
}
RUBY_ASSERT(rb_shape_complex_p(shape_id));
st_free_table(fields->as.complex.table);
}
}

Expand Down
6 changes: 3 additions & 3 deletions internal/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ struct rb_classext_struct {
const VALUE includer;
} iclass;
} as;
attr_index_t max_iv_count;
uint16_t superclass_depth;
unsigned char variation_count;
attr_index_t max_iv_count;
uint8_t variation_count;
bool permanent_classpath : 1;
bool cloned : 1;
bool shared_const_tbl : 1;
Expand Down Expand Up @@ -550,7 +550,7 @@ RCLASS_FIELDS_COUNT(VALUE obj)

VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
if (fields_obj) {
if (rb_shape_obj_too_complex_p(fields_obj)) {
if (rb_obj_shape_complex_p(fields_obj)) {
return (uint32_t)rb_st_table_size(rb_imemo_fields_complex_tbl(fields_obj));
}
else {
Expand Down
2 changes: 1 addition & 1 deletion internal/imemo.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ rb_imemo_fields_complex_tbl(VALUE fields_obj)
RUBY_ASSERT(FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP));

// Some codepaths unconditionally access the fields_ptr, and assume it can be used as st_table if the
// shape is too_complex.
// shape is complex.
RUBY_ASSERT((st_table *)rb_imemo_fields_ptr(fields_obj) == IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table);

return IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table;
Expand Down
2 changes: 1 addition & 1 deletion internal/variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void rb_gvar_box_dynamic(const char *name);
VALUE rb_mod_set_temporary_name(VALUE, VALUE);

void rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table);
void rb_obj_init_too_complex(VALUE obj, st_table *table);
void rb_obj_init_complex(VALUE obj, st_table *table);
void rb_evict_ivars_to_hash(VALUE obj);
VALUE rb_obj_field_get(VALUE obj, shape_id_t target_shape_id);
void rb_ivar_set_internal(VALUE obj, ID id, VALUE val);
Expand Down
8 changes: 6 additions & 2 deletions iseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -3041,7 +3041,7 @@ rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq)
}
}

attr_index_t count = (attr_index_t)iv_names.num_entries;
size_t count = iv_names.num_entries;

VALUE superclass = rb_class_superclass(klass);
if (!NIL_P(superclass)) { // BasicObject doesn't have a superclass
Expand All @@ -3050,7 +3050,11 @@ rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq)

set_free_embedded_table(&iv_names);

return count;
if (count > (attr_index_t)-1) {
return (attr_index_t)-1;
}

return (attr_index_t)count;
}

/*
Expand Down
4 changes: 2 additions & 2 deletions jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,9 @@ rb_set_cfp_sp(struct rb_control_frame_struct *cfp, VALUE *sp)
}

bool
rb_jit_shape_too_complex_p(shape_id_t shape_id)
rb_jit_shape_complex_p(shape_id_t shape_id)
{
return rb_shape_too_complex_p(shape_id);
return rb_shape_complex_p(shape_id);
}

bool
Expand Down
6 changes: 3 additions & 3 deletions object.c
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)

shape_id_t src_shape_id = RBASIC_SHAPE_ID(obj);

if (rb_shape_too_complex_p(src_shape_id)) {
if (rb_shape_complex_p(src_shape_id)) {
rb_shape_copy_complex_ivars(dest, obj, src_shape_id, ROBJECT_FIELDS_HASH(obj));
return;
}
Expand All @@ -347,10 +347,10 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
RUBY_ASSERT(RSHAPE_TYPE_P(initial_shape_id, SHAPE_ROOT));

shape_id_t dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id);
if (UNLIKELY(rb_shape_too_complex_p(dest_shape_id))) {
if (UNLIKELY(rb_shape_complex_p(dest_shape_id))) {
st_table *table = rb_st_init_numtable_with_size(src_num_ivs);
rb_obj_copy_ivs_to_hash_table(obj, table);
rb_obj_init_too_complex(dest, table);
rb_obj_init_complex(dest, table);

return;
}
Expand Down
Loading