Refactor rb_shape_too_complex_p to take a shape_id_t.

This commit is contained in:
Jean Boussier 2025-05-27 13:32:55 +02:00
parent a1f72d23a9
commit ccf2b7c5b8
Notes: git 2025-05-27 13:34:17 +00:00
8 changed files with 51 additions and 54 deletions

2
gc.c
View File

@ -380,7 +380,7 @@ uint32_t
rb_gc_rebuild_shape(VALUE obj, size_t heap_id) rb_gc_rebuild_shape(VALUE obj, size_t heap_id)
{ {
shape_id_t orig_shape_id = rb_obj_shape_id(obj); shape_id_t orig_shape_id = rb_obj_shape_id(obj);
if (rb_shape_id_too_complex_p(orig_shape_id)) { if (rb_shape_too_complex_p(orig_shape_id)) {
return (uint32_t)orig_shape_id; return (uint32_t)orig_shape_id;
} }

View File

@ -331,7 +331,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
shape_id_t src_shape_id = RBASIC_SHAPE_ID(obj); shape_id_t src_shape_id = RBASIC_SHAPE_ID(obj);
if (rb_shape_id_too_complex_p(src_shape_id)) { if (rb_shape_too_complex_p(src_shape_id)) {
rb_shape_copy_complex_ivars(dest, obj, src_shape_id, ROBJECT_FIELDS_HASH(obj)); rb_shape_copy_complex_ivars(dest, obj, src_shape_id, ROBJECT_FIELDS_HASH(obj));
return; return;
} }
@ -343,7 +343,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
RUBY_ASSERT(RSHAPE(initial_shape_id)->type == SHAPE_T_OBJECT); RUBY_ASSERT(RSHAPE(initial_shape_id)->type == SHAPE_T_OBJECT);
dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id); dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id);
if (UNLIKELY(rb_shape_id_too_complex_p(dest_shape_id))) { if (UNLIKELY(rb_shape_too_complex_p(dest_shape_id))) {
st_table *table = rb_st_init_numtable_with_size(src_num_ivs); st_table *table = rb_st_init_numtable_with_size(src_num_ivs);
rb_obj_copy_ivs_to_hash_table(obj, table); rb_obj_copy_ivs_to_hash_table(obj, table);
rb_obj_init_too_complex(dest, table); rb_obj_init_too_complex(dest, table);
@ -496,7 +496,7 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
if (RB_OBJ_FROZEN(obj)) { if (RB_OBJ_FROZEN(obj)) {
shape_id_t next_shape_id = rb_shape_transition_frozen(clone); shape_id_t next_shape_id = rb_shape_transition_frozen(clone);
if (!rb_shape_obj_too_complex_p(clone) && rb_shape_id_too_complex_p(next_shape_id)) { if (!rb_shape_obj_too_complex_p(clone) && rb_shape_too_complex_p(next_shape_id)) {
rb_evict_ivars_to_hash(clone); rb_evict_ivars_to_hash(clone);
} }
else { else {
@ -520,7 +520,7 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
shape_id_t next_shape_id = rb_shape_transition_frozen(clone); shape_id_t next_shape_id = rb_shape_transition_frozen(clone);
// If we're out of shapes, but we want to freeze, then we need to // If we're out of shapes, but we want to freeze, then we need to
// evacuate this clone to a hash // evacuate this clone to a hash
if (!rb_shape_obj_too_complex_p(clone) && rb_shape_id_too_complex_p(next_shape_id)) { if (!rb_shape_obj_too_complex_p(clone) && rb_shape_too_complex_p(next_shape_id)) {
rb_evict_ivars_to_hash(clone); rb_evict_ivars_to_hash(clone);
} }
else { else {

32
shape.c
View File

@ -328,6 +328,12 @@ rb_shape_id(rb_shape_t *shape)
return (shape_id_t)(shape - GET_SHAPE_TREE()->shape_list); return (shape_id_t)(shape - GET_SHAPE_TREE()->shape_list);
} }
static inline bool
shape_too_complex_p(rb_shape_t *shape)
{
return shape->flags & SHAPE_FL_TOO_COMPLEX;
}
void void
rb_shape_each_shape_id(each_shape_callback callback, void *data) rb_shape_each_shape_id(each_shape_callback callback, void *data)
{ {
@ -494,7 +500,7 @@ get_next_shape_internal(rb_shape_t *shape, ID id, enum shape_type shape_type, bo
rb_shape_t *res = NULL; rb_shape_t *res = NULL;
// There should never be outgoing edges from "too complex", except for SHAPE_FROZEN and SHAPE_OBJ_ID // There should never be outgoing edges from "too complex", except for SHAPE_FROZEN and SHAPE_OBJ_ID
RUBY_ASSERT(!rb_shape_too_complex_p(shape) || shape_type == SHAPE_FROZEN || shape_type == SHAPE_OBJ_ID); RUBY_ASSERT(!shape_too_complex_p(shape) || shape_type == SHAPE_FROZEN || shape_type == SHAPE_OBJ_ID);
*variation_created = false; *variation_created = false;
@ -597,13 +603,13 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
// We found a new parent. Create a child of the new parent that // We found a new parent. Create a child of the new parent that
// has the same attributes as this shape. // has the same attributes as this shape.
if (new_parent) { if (new_parent) {
if (UNLIKELY(rb_shape_too_complex_p(new_parent))) { if (UNLIKELY(shape_too_complex_p(new_parent))) {
return new_parent; return new_parent;
} }
bool dont_care; bool dont_care;
rb_shape_t *new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care, true); rb_shape_t *new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care, true);
if (UNLIKELY(rb_shape_too_complex_p(new_child))) { if (UNLIKELY(shape_too_complex_p(new_child))) {
return new_child; return new_child;
} }
@ -626,7 +632,7 @@ rb_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id)
shape_id_t shape_id = rb_obj_shape_id(obj); shape_id_t shape_id = rb_obj_shape_id(obj);
rb_shape_t *shape = RSHAPE(shape_id); rb_shape_t *shape = RSHAPE(shape_id);
RUBY_ASSERT(!rb_shape_too_complex_p(shape)); RUBY_ASSERT(!shape_too_complex_p(shape));
rb_shape_t *removed_shape = NULL; rb_shape_t *removed_shape = NULL;
rb_shape_t *new_shape = remove_shape_recursive(shape, id, &removed_shape); rb_shape_t *new_shape = remove_shape_recursive(shape, id, &removed_shape);
@ -770,7 +776,7 @@ static inline rb_shape_t *
shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings) shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
{ {
RUBY_ASSERT(!is_instance_id(id) || RTEST(rb_sym2str(ID2SYM(id)))); RUBY_ASSERT(!is_instance_id(id) || RTEST(rb_sym2str(ID2SYM(id))));
if (UNLIKELY(rb_shape_too_complex_p(shape))) { if (UNLIKELY(shape_too_complex_p(shape))) {
return shape; return shape;
} }
@ -921,7 +927,7 @@ rb_shape_get_iv_index(shape_id_t shape_id, ID id, attr_index_t *value)
// It doesn't make sense to ask for the index of an IV that's stored // It doesn't make sense to ask for the index of an IV that's stored
// on an object that is "too complex" as it uses a hash for storing IVs // on an object that is "too complex" as it uses a hash for storing IVs
RUBY_ASSERT(!rb_shape_too_complex_p(shape)); RUBY_ASSERT(!shape_too_complex_p(shape));
if (!shape_cache_get_iv_index(shape, id, value)) { if (!shape_cache_get_iv_index(shape, id, value)) {
// If it wasn't in the ancestor cache, then don't do a linear search // If it wasn't in the ancestor cache, then don't do a linear search
@ -1091,19 +1097,13 @@ rb_shape_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_t
RUBY_FUNC_EXPORTED bool RUBY_FUNC_EXPORTED bool
rb_shape_obj_too_complex_p(VALUE obj) rb_shape_obj_too_complex_p(VALUE obj)
{ {
return rb_shape_too_complex_p(obj_shape(obj)); return shape_too_complex_p(obj_shape(obj));
} }
bool bool
rb_shape_id_too_complex_p(shape_id_t shape_id) rb_shape_too_complex_p(shape_id_t shape_id)
{ {
return rb_shape_too_complex_p(RSHAPE(shape_id)); return shape_too_complex_p(RSHAPE(shape_id));
}
bool
rb_shape_too_complex_p(rb_shape_t *shape)
{
return shape->flags & SHAPE_FL_TOO_COMPLEX;
} }
size_t size_t
@ -1143,7 +1143,7 @@ shape_too_complex(VALUE self)
{ {
shape_id_t shape_id = NUM2INT(rb_struct_getmember(self, rb_intern("id"))); shape_id_t shape_id = NUM2INT(rb_struct_getmember(self, rb_intern("id")));
rb_shape_t *shape = RSHAPE(shape_id); rb_shape_t *shape = RSHAPE(shape_id);
return RBOOL(rb_shape_too_complex_p(shape)); return RBOOL(shape_too_complex_p(shape));
} }
static VALUE static VALUE

View File

@ -125,8 +125,7 @@ shape_id_t rb_shape_get_next_iv_shape(shape_id_t shape_id, ID id);
bool rb_shape_get_iv_index(shape_id_t shape_id, ID id, attr_index_t *value); bool rb_shape_get_iv_index(shape_id_t shape_id, ID id, attr_index_t *value);
bool rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *value, shape_id_t *shape_id_hint); bool rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *value, shape_id_t *shape_id_hint);
RUBY_FUNC_EXPORTED bool rb_shape_obj_too_complex_p(VALUE obj); RUBY_FUNC_EXPORTED bool rb_shape_obj_too_complex_p(VALUE obj);
bool rb_shape_too_complex_p(rb_shape_t *shape); bool rb_shape_too_complex_p(shape_id_t shape_id);
bool rb_shape_id_too_complex_p(shape_id_t shape_id);
bool rb_shape_has_object_id(shape_id_t shape_id); bool rb_shape_has_object_id(shape_id_t shape_id);
shape_id_t rb_shape_transition_frozen(VALUE obj); shape_id_t rb_shape_transition_frozen(VALUE obj);

View File

@ -1322,7 +1322,7 @@ rb_obj_field_get(VALUE obj, shape_id_t target_shape_id)
RUBY_ASSERT(!SPECIAL_CONST_P(obj)); RUBY_ASSERT(!SPECIAL_CONST_P(obj));
RUBY_ASSERT(RSHAPE(target_shape_id)->type == SHAPE_IVAR || RSHAPE(target_shape_id)->type == SHAPE_OBJ_ID); RUBY_ASSERT(RSHAPE(target_shape_id)->type == SHAPE_IVAR || RSHAPE(target_shape_id)->type == SHAPE_OBJ_ID);
if (rb_shape_id_too_complex_p(target_shape_id)) { if (rb_shape_too_complex_p(target_shape_id)) {
st_table *fields_hash; st_table *fields_hash;
switch (BUILTIN_TYPE(obj)) { switch (BUILTIN_TYPE(obj)) {
case T_CLASS: case T_CLASS:
@ -1386,7 +1386,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
VALUE val; VALUE val;
RB_VM_LOCKING() { RB_VM_LOCKING() {
if (rb_shape_id_too_complex_p(shape_id)) { if (rb_shape_too_complex_p(shape_id)) {
st_table * iv_table = RCLASS_FIELDS_HASH(obj); st_table * iv_table = RCLASS_FIELDS_HASH(obj);
if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) { if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) {
found = true; found = true;
@ -1422,7 +1422,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
} }
case T_OBJECT: case T_OBJECT:
{ {
if (rb_shape_id_too_complex_p(shape_id)) { if (rb_shape_too_complex_p(shape_id)) {
st_table * iv_table = ROBJECT_FIELDS_HASH(obj); st_table * iv_table = ROBJECT_FIELDS_HASH(obj);
VALUE val; VALUE val;
if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) { if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) {
@ -1496,7 +1496,7 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
} }
shape_id_t old_shape_id = rb_obj_shape_id(obj); shape_id_t old_shape_id = rb_obj_shape_id(obj);
if (rb_shape_id_too_complex_p(old_shape_id)) { if (rb_shape_too_complex_p(old_shape_id)) {
goto too_complex; goto too_complex;
} }
@ -1510,7 +1510,7 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
return undef; return undef;
} }
if (UNLIKELY(rb_shape_id_too_complex_p(next_shape_id))) { if (UNLIKELY(rb_shape_too_complex_p(next_shape_id))) {
rb_evict_fields_to_hash(obj); rb_evict_fields_to_hash(obj);
goto too_complex; goto too_complex;
} }
@ -1714,33 +1714,31 @@ general_ivar_set(VALUE obj, ID id, VALUE val, void *data,
shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj); shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj);
if (UNLIKELY(rb_shape_id_too_complex_p(current_shape_id))) { if (UNLIKELY(rb_shape_too_complex_p(current_shape_id))) {
goto too_complex; goto too_complex;
} }
attr_index_t index; attr_index_t index;
if (!rb_shape_get_iv_index(current_shape_id, id, &index)) { if (!rb_shape_get_iv_index(current_shape_id, id, &index)) {
result.existing = false; result.existing = false;
rb_shape_t *current_shape = RSHAPE(current_shape_id);
index = current_shape->next_field_index; index = RSHAPE_LEN(current_shape_id);
if (index >= SHAPE_MAX_FIELDS) { if (index >= SHAPE_MAX_FIELDS) {
rb_raise(rb_eArgError, "too many instance variables"); rb_raise(rb_eArgError, "too many instance variables");
} }
shape_id_t next_shape_id = rb_shape_transition_add_ivar(obj, id); shape_id_t next_shape_id = rb_shape_transition_add_ivar(obj, id);
rb_shape_t *next_shape = RSHAPE(next_shape_id); if (UNLIKELY(rb_shape_too_complex_p(next_shape_id))) {
if (UNLIKELY(rb_shape_too_complex_p(next_shape))) {
transition_too_complex_func(obj, data); transition_too_complex_func(obj, data);
goto too_complex; goto too_complex;
} }
else if (UNLIKELY(next_shape->capacity != current_shape->capacity)) { else if (UNLIKELY(RSHAPE_CAPACITY(next_shape_id) != RSHAPE_CAPACITY(current_shape_id))) {
RUBY_ASSERT(next_shape->capacity > current_shape->capacity); RUBY_ASSERT(RSHAPE_CAPACITY(next_shape_id) > RSHAPE_CAPACITY(current_shape_id));
shape_resize_fields_func(obj, current_shape->capacity, next_shape->capacity, data); shape_resize_fields_func(obj, RSHAPE_CAPACITY(current_shape_id), RSHAPE_CAPACITY(next_shape_id), data);
} }
RUBY_ASSERT(next_shape->type == SHAPE_IVAR); RUBY_ASSERT(RSHAPE_TYPE_P(next_shape_id, SHAPE_IVAR));
RUBY_ASSERT(index == (next_shape->next_field_index - 1)); RUBY_ASSERT(index == (RSHAPE_INDEX(next_shape_id)));
set_shape_id_func(obj, next_shape_id, data); set_shape_id_func(obj, next_shape_id, data);
} }
@ -1772,8 +1770,8 @@ general_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val, void *data,
{ {
shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj); shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj);
if (UNLIKELY(rb_shape_id_too_complex_p(target_shape_id))) { if (UNLIKELY(rb_shape_too_complex_p(target_shape_id))) {
if (UNLIKELY(!rb_shape_id_too_complex_p(current_shape_id))) { if (UNLIKELY(!rb_shape_too_complex_p(current_shape_id))) {
transition_too_complex_func(obj, data); transition_too_complex_func(obj, data);
} }
@ -2062,7 +2060,7 @@ void rb_obj_freeze_inline(VALUE x)
// If we're transitioning from "not complex" to "too complex" // If we're transitioning from "not complex" to "too complex"
// then evict ivars. This can happen if we run out of shapes // then evict ivars. This can happen if we run out of shapes
if (rb_shape_id_too_complex_p(next_shape_id) && !rb_shape_obj_too_complex_p(x)) { if (rb_shape_too_complex_p(next_shape_id) && !rb_shape_obj_too_complex_p(x)) {
rb_evict_fields_to_hash(x); rb_evict_fields_to_hash(x);
} }
rb_shape_set_shape_id(x, next_shape_id); rb_shape_set_shape_id(x, next_shape_id);
@ -2257,7 +2255,7 @@ obj_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, b
}; };
shape_id_t shape_id = RBASIC_SHAPE_ID(obj); shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
if (rb_shape_id_too_complex_p(shape_id)) { if (rb_shape_too_complex_p(shape_id)) {
rb_st_foreach(ROBJECT_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data); rb_st_foreach(ROBJECT_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
} }
else { else {
@ -2280,7 +2278,7 @@ gen_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, b
}; };
shape_id_t shape_id = RBASIC_SHAPE_ID(obj); shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
if (rb_shape_id_too_complex_p(shape_id)) { if (rb_shape_too_complex_p(shape_id)) {
rb_st_foreach(fields_tbl->as.complex.table, each_hash_iv, (st_data_t)&itr_data); rb_st_foreach(fields_tbl->as.complex.table, each_hash_iv, (st_data_t)&itr_data);
} }
else { else {
@ -2301,7 +2299,7 @@ class_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg,
}; };
shape_id_t shape_id = RBASIC_SHAPE_ID(obj); shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
if (rb_shape_id_too_complex_p(shape_id)) { if (rb_shape_too_complex_p(shape_id)) {
rb_st_foreach(RCLASS_WRITABLE_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data); rb_st_foreach(RCLASS_WRITABLE_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
} }
else { else {
@ -2334,7 +2332,7 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj)
FL_SET(dest, FL_EXIVAR); FL_SET(dest, FL_EXIVAR);
if (rb_shape_id_too_complex_p(src_shape_id)) { if (rb_shape_too_complex_p(src_shape_id)) {
rb_shape_copy_complex_ivars(dest, obj, src_shape_id, obj_fields_tbl->as.complex.table); rb_shape_copy_complex_ivars(dest, obj, src_shape_id, obj_fields_tbl->as.complex.table);
return; return;
} }
@ -2346,7 +2344,7 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj)
RUBY_ASSERT(RSHAPE(initial_shape_id)->type == SHAPE_ROOT); RUBY_ASSERT(RSHAPE(initial_shape_id)->type == SHAPE_ROOT);
dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id); dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id);
if (UNLIKELY(rb_shape_id_too_complex_p(dest_shape_id))) { if (UNLIKELY(rb_shape_too_complex_p(dest_shape_id))) {
st_table *table = rb_st_init_numtable_with_size(src_num_ivs); st_table *table = rb_st_init_numtable_with_size(src_num_ivs);
rb_obj_copy_ivs_to_hash_table(obj, table); rb_obj_copy_ivs_to_hash_table(obj, table);
rb_obj_init_too_complex(dest, table); rb_obj_init_too_complex(dest, table);

View File

@ -1275,7 +1275,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
} }
if (LIKELY(cached_id == shape_id)) { if (LIKELY(cached_id == shape_id)) {
RUBY_ASSERT(!rb_shape_id_too_complex_p(cached_id)); RUBY_ASSERT(!rb_shape_too_complex_p(cached_id));
if (index == ATTR_INDEX_NOT_SET) { if (index == ATTR_INDEX_NOT_SET) {
return default_value; return default_value;
@ -1316,7 +1316,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
} }
#endif #endif
if (rb_shape_id_too_complex_p(shape_id)) { if (rb_shape_too_complex_p(shape_id)) {
st_table *table = NULL; st_table *table = NULL;
switch (BUILTIN_TYPE(obj)) { switch (BUILTIN_TYPE(obj)) {
case T_CLASS: case T_CLASS:
@ -1394,7 +1394,7 @@ general_path:
static void static void
populate_cache(attr_index_t index, shape_id_t next_shape_id, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, bool is_attr) populate_cache(attr_index_t index, shape_id_t next_shape_id, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, bool is_attr)
{ {
RUBY_ASSERT(!rb_shape_id_too_complex_p(next_shape_id)); RUBY_ASSERT(!rb_shape_too_complex_p(next_shape_id));
// Cache population code // Cache population code
if (is_attr) { if (is_attr) {
@ -1422,7 +1422,7 @@ vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic,
shape_id_t next_shape_id = RBASIC_SHAPE_ID(obj); shape_id_t next_shape_id = RBASIC_SHAPE_ID(obj);
if (!rb_shape_id_too_complex_p(next_shape_id)) { if (!rb_shape_too_complex_p(next_shape_id)) {
populate_cache(index, next_shape_id, id, iseq, ic, cc, is_attr); populate_cache(index, next_shape_id, id, iseq, ic, cc, is_attr);
} }
@ -1495,7 +1495,7 @@ vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t i
VM_ASSERT(!rb_ractor_shareable_p(obj) || rb_obj_frozen_p(obj)); VM_ASSERT(!rb_ractor_shareable_p(obj) || rb_obj_frozen_p(obj));
shape_id_t shape_id = RBASIC_SHAPE_ID(obj); shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
RUBY_ASSERT(dest_shape_id == INVALID_SHAPE_ID || !rb_shape_id_too_complex_p(dest_shape_id)); RUBY_ASSERT(dest_shape_id == INVALID_SHAPE_ID || !rb_shape_too_complex_p(dest_shape_id));
if (LIKELY(shape_id == dest_shape_id)) { if (LIKELY(shape_id == dest_shape_id)) {
RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID);

View File

@ -3121,14 +3121,14 @@ fn gen_set_ivar(
let new_shape = if !shape_too_complex && receiver_t_object && ivar_index.is_none() { let new_shape = if !shape_too_complex && receiver_t_object && ivar_index.is_none() {
let current_shape = comptime_receiver.shape_of(); let current_shape = comptime_receiver.shape_of();
let next_shape_id = unsafe { rb_shape_transition_add_ivar_no_warnings(comptime_receiver, ivar_name) }; let next_shape_id = unsafe { rb_shape_transition_add_ivar_no_warnings(comptime_receiver, ivar_name) };
let next_shape = unsafe { rb_shape_lookup(next_shape_id) };
// If the VM ran out of shapes, or this class generated too many leaf, // If the VM ran out of shapes, or this class generated too many leaf,
// it may be de-optimized into OBJ_TOO_COMPLEX_SHAPE (hash-table). // it may be de-optimized into OBJ_TOO_COMPLEX_SHAPE (hash-table).
new_shape_too_complex = unsafe { rb_shape_too_complex_p(next_shape) }; new_shape_too_complex = unsafe { rb_shape_too_complex_p(next_shape_id) };
if new_shape_too_complex { if new_shape_too_complex {
Some((next_shape_id, None, 0_usize)) Some((next_shape_id, None, 0_usize))
} else { } else {
let next_shape = unsafe { rb_shape_lookup(next_shape_id) };
let current_capacity = unsafe { (*current_shape).capacity }; let current_capacity = unsafe { (*current_shape).capacity };
// If the new shape has a different capacity, or is TOO_COMPLEX, we'll have to // If the new shape has a different capacity, or is TOO_COMPLEX, we'll have to

View File

@ -1144,7 +1144,7 @@ extern "C" {
pub fn rb_obj_shape_id(obj: VALUE) -> shape_id_t; pub fn rb_obj_shape_id(obj: VALUE) -> shape_id_t;
pub fn rb_shape_get_iv_index(shape_id: shape_id_t, id: ID, value: *mut attr_index_t) -> bool; pub fn rb_shape_get_iv_index(shape_id: shape_id_t, id: ID, value: *mut attr_index_t) -> bool;
pub fn rb_shape_obj_too_complex_p(obj: VALUE) -> bool; pub fn rb_shape_obj_too_complex_p(obj: VALUE) -> bool;
pub fn rb_shape_too_complex_p(shape: *mut rb_shape_t) -> bool; pub fn rb_shape_too_complex_p(shape_id: shape_id_t) -> bool;
pub fn rb_shape_transition_add_ivar_no_warnings(obj: VALUE, id: ID) -> shape_id_t; pub fn rb_shape_transition_add_ivar_no_warnings(obj: VALUE, id: ID) -> shape_id_t;
pub fn rb_gvar_get(arg1: ID) -> VALUE; pub fn rb_gvar_get(arg1: ID) -> VALUE;
pub fn rb_gvar_set(arg1: ID, arg2: VALUE) -> VALUE; pub fn rb_gvar_set(arg1: ID, arg2: VALUE) -> VALUE;