diff --git a/internal/variable.h b/internal/variable.h index 021e7cc6a8..63b074a308 100644 --- a/internal/variable.h +++ b/internal/variable.h @@ -47,7 +47,8 @@ VALUE rb_mod_set_temporary_name(VALUE, VALUE); struct gen_ivtbl; int rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl); -int rb_obj_evacuate_ivs_to_hash_table(ID key, VALUE val, st_data_t arg); +void rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table); +void rb_obj_convert_to_too_complex(VALUE obj, st_table *table); void rb_evict_ivars_to_hash(VALUE obj); RUBY_SYMBOL_EXPORT_BEGIN diff --git a/object.c b/object.c index f442a562ea..a8090d0763 100644 --- a/object.c +++ b/object.c @@ -293,12 +293,10 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj) rb_shape_t * src_shape = rb_shape_get_shape(obj); if (rb_shape_obj_too_complex(obj)) { + // obj is TOO_COMPLEX so we can copy its iv_hash st_table * table = rb_st_init_numtable_with_size(rb_st_table_size(ROBJECT_IV_HASH(obj))); - - rb_ivar_foreach(obj, rb_obj_evacuate_ivs_to_hash_table, (st_data_t)table); - rb_shape_set_too_complex(dest); - - ROBJECT(dest)->as.heap.ivptr = (VALUE *)table; + st_replace(table, ROBJECT_IV_HASH(obj)); + rb_obj_convert_to_too_complex(dest, table); return; } @@ -328,10 +326,8 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj) shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape); if (UNLIKELY(rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID)) { st_table * table = rb_st_init_numtable_with_size(src_num_ivs); - - rb_ivar_foreach(obj, rb_obj_evacuate_ivs_to_hash_table, (st_data_t)table); - rb_shape_set_too_complex(dest); - ROBJECT(dest)->as.heap.ivptr = (VALUE *)table; + rb_obj_copy_ivs_to_hash_table(obj, table); + rb_obj_convert_to_too_complex(dest, table); return; } diff --git a/shape.c b/shape.c index 588c24604d..7ccf82b246 100644 --- a/shape.c +++ b/shape.c @@ -915,13 +915,6 @@ rb_shape_obj_too_complex(VALUE obj) return rb_shape_get_shape_id(obj) == OBJ_TOO_COMPLEX_SHAPE_ID; } -void -rb_shape_set_too_complex(VALUE obj) -{ - RUBY_ASSERT(!rb_shape_obj_too_complex(obj)); - rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID); -} - size_t rb_shape_edges_count(rb_shape_t *shape) { diff --git a/shape.h b/shape.h index f1823258da..5b8420a402 100644 --- a/shape.h +++ b/shape.h @@ -226,7 +226,6 @@ rb_shape_t *rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_ bool rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id); VALUE rb_obj_debug_shape(VALUE self, VALUE obj); -void rb_shape_set_too_complex(VALUE obj); // For ext/objspace RUBY_SYMBOL_EXPORT_BEGIN diff --git a/variable.c b/variable.c index d5c425472b..7935162098 100644 --- a/variable.c +++ b/variable.c @@ -1370,6 +1370,50 @@ rb_attr_delete(VALUE obj, ID id) return rb_ivar_delete(obj, id, Qnil); } +void +rb_obj_convert_to_too_complex(VALUE obj, st_table *table) +{ + RUBY_ASSERT(!rb_shape_obj_too_complex(obj)); + + VALUE *old_ivptr = NULL; + + switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) { + old_ivptr = ROBJECT_IVPTR(obj); + } + rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID); + ROBJECT_SET_IV_HASH(obj, table); + break; + case T_CLASS: + case T_MODULE: + old_ivptr = RCLASS_IVPTR(obj); + rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID); + RCLASS_SET_IV_HASH(obj, table); + break; + default: + RB_VM_LOCK_ENTER(); + { + struct st_table *gen_ivs = generic_ivtbl_no_ractor_check(obj); + st_lookup(gen_ivs, (st_data_t)&obj, (st_data_t *)&old_ivptr); + + struct gen_ivtbl *ivtbl = xmalloc(sizeof(struct gen_ivtbl)); + ivtbl->as.complex.table = table; +#if SHAPE_IN_BASIC_FLAGS + rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID); +#else + ivtbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID; +#endif + st_insert(gen_ivs, (st_data_t)obj, (st_data_t)ivtbl); + } + RB_VM_LOCK_LEAVE(); + } + + if (old_ivptr) { + xfree(old_ivptr); + } +} + void rb_evict_ivars_to_hash(VALUE obj) { @@ -1378,48 +1422,8 @@ rb_evict_ivars_to_hash(VALUE obj) st_table *table = st_init_numtable_with_size(rb_ivar_count(obj)); // Evacuate all previous values from shape into id_table - rb_ivar_foreach(obj, rb_obj_evacuate_ivs_to_hash_table, (st_data_t)table); - - switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - rb_shape_set_too_complex(obj); - - if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) { - xfree(ROBJECT(obj)->as.heap.ivptr); - } - - ROBJECT_SET_IV_HASH(obj, table); - break; - case T_CLASS: - case T_MODULE: - rb_shape_set_too_complex(obj); - - xfree(RCLASS_IVPTR(obj)); - RCLASS_SET_IV_HASH(obj, table); - break; - default: - RB_VM_LOCK_ENTER(); - { - struct st_table *gen_ivs = generic_ivtbl_no_ractor_check(obj); - st_data_t old_ivtbl; - struct gen_ivtbl *ivtbl = NULL; - - if (st_delete(gen_ivs, &obj, &old_ivtbl)) { - ivtbl = (struct gen_ivtbl *)old_ivtbl; - } - - ivtbl = xrealloc(ivtbl, sizeof(struct gen_ivtbl)); - ivtbl->as.complex.table = table; -#if SHAPE_IN_BASIC_FLAGS - rb_shape_set_too_complex(obj); -#else - ivtbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID; -#endif - - st_insert(gen_ivs, (st_data_t)obj, (st_data_t)ivtbl); - } - RB_VM_LOCK_LEAVE(); - } + rb_obj_copy_ivs_to_hash_table(obj, table); + rb_obj_convert_to_too_complex(obj, table); RUBY_ASSERT(rb_shape_obj_too_complex(obj)); } @@ -1637,12 +1641,18 @@ rb_ensure_iv_list_size(VALUE obj, uint32_t current_capacity, uint32_t new_capaci } int -rb_obj_evacuate_ivs_to_hash_table(ID key, VALUE val, st_data_t arg) +rb_obj_copy_ivs_to_hash_table_i(ID key, VALUE val, st_data_t arg) { st_insert((st_table *)arg, (st_data_t)key, (st_data_t)val); return ST_CONTINUE; } +void +rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table) +{ + rb_ivar_foreach(obj, rb_obj_copy_ivs_to_hash_table_i, (st_data_t)table); +} + static VALUE * obj_ivar_set_shape_ivptr(VALUE obj, void *_data) {