diff options
author | Jean Boussier <[email protected]> | 2025-06-16 11:19:12 +0200 |
---|---|---|
committer | Jean Boussier <[email protected]> | 2025-06-17 15:28:05 +0200 |
commit | cd9f447be247478d2eb3da985295735cce20cb23 () | |
tree | 1f87f079323e42a71f07b862b6d32daa6260e5b7 | |
parent | 164486a954e3cf3e716393c5f9a9e2c4dd776993 (diff) |
Refactor generic fields to use `T_IMEMO/fields` objects.
Followup: https://.com/ruby/ruby/pull/13589 This simplify a lot of things, as we no longer need to manually manage the memory, we can use the Read-Copy-Update pattern and avoid numerous race conditions. Co-Authored-By: Étienne Barrié <[email protected]>
Notes: Merged: https://.com/ruby/ruby/pull/13626
-rw-r--r-- | ext/objspace/objspace_dump.c | 9 | ||||
-rw-r--r-- | gc.c | 130 | ||||
-rw-r--r-- | imemo.c | 30 | ||||
-rw-r--r-- | internal/imemo.h | 2 | ||||
-rw-r--r-- | internal/variable.h | 4 | ||||
-rw-r--r-- | ractor.c | 9 | ||||
-rw-r--r-- | test/ruby/test_encoding.rb | 2 | ||||
-rw-r--r-- | variable.c | 549 | ||||
-rw-r--r-- | variable.h | 13 | ||||
-rw-r--r-- | vm_insnhelper.c | 20 |
10 files changed, 366 insertions, 402 deletions
@@ -394,9 +394,10 @@ dump_object(VALUE obj, struct dump_config *dc) dc->cur_obj = obj; dc->cur_obj_references = 0; - if (BUILTIN_TYPE(obj) == T_NODE || BUILTIN_TYPE(obj) == T_IMEMO) { dc->cur_obj_klass = 0; - } else { dc->cur_obj_klass = RBASIC_CLASS(obj); } @@ -414,8 +415,8 @@ dump_object(VALUE obj, struct dump_config *dc) dump_append(dc, obj_type(obj)); dump_append(dc, "\""); - if (BUILTIN_TYPE(obj) != T_IMEMO) { - size_t shape_id = rb_obj_shape_id(obj); dump_append(dc, ", \"shape_id\":"); dump_append_sizet(dc, shape_id); } @@ -2015,27 +2015,6 @@ object_id_to_ref(void *objspace_ptr, VALUE object_id) static inline void obj_free_object_id(VALUE obj) { - if (RB_BUILTIN_TYPE(obj) == T_IMEMO) { - return; - } - -#if RUBY_DEBUG - switch (BUILTIN_TYPE(obj)) { - case T_CLASS: - case T_MODULE: - break; - default: - if (rb_shape_obj_has_id(obj)) { - VALUE id = object_id_get(obj, RBASIC_SHAPE_ID(obj)); // Crash if missing - if (!(FIXNUM_P(id) || RB_TYPE_P(id, T_BIGNUM))) { - rb_p(obj); - rb_bug("Corrupted object_id"); - } - } - break; - } -#endif - VALUE obj_id = 0; if (RB_UNLIKELY(id2ref_tbl)) { switch (BUILTIN_TYPE(obj)) { @@ -2043,21 +2022,32 @@ obj_free_object_id(VALUE obj) case T_MODULE: obj_id = RCLASS(obj)->object_id; break; - default: { shape_id_t shape_id = RBASIC_SHAPE_ID(obj); if (rb_shape_has_object_id(shape_id)) { obj_id = object_id_get(obj, shape_id); } break; } } if (RB_UNLIKELY(obj_id)) { RUBY_ASSERT(FIXNUM_P(obj_id) || RB_TYPE_P(obj_id, T_BIGNUM)); if (!st_delete(id2ref_tbl, (st_data_t *)&obj_id, NULL)) { - // If we're currently building the table then it's not a bug - if (id2ref_tbl_built) { rb_bug("Object ID seen, but not in _id2ref table: object_id=%llu object=%s", NUM2ULL(obj_id), rb_obj_info(obj)); } } @@ -2071,7 +2061,7 @@ rb_gc_obj_free_vm_weak_references(VALUE obj) obj_free_object_id(obj); if (rb_obj_exivar_p(obj)) { - rb_free_generic_ivar((VALUE)obj); } switch (BUILTIN_TYPE(obj)) { @@ -2316,10 +2306,6 @@ rb_obj_memsize_of(VALUE obj) return 0; } - if (rb_obj_exivar_p(obj)) { - size += rb_generic_ivar_memsize(obj); - } - switch (BUILTIN_TYPE(obj)) { case T_OBJECT: if (rb_shape_obj_too_complex_p(obj)) { @@ -3935,38 +3921,6 @@ vm_weak_table_foreach_update_weak_value(st_data_t *key, st_data_t *value, st_dat return iter_data->update_callback((VALUE *)value, iter_data->data); } -static void -free_gen_fields_tbl(VALUE obj, struct gen_fields_tbl *fields_tbl) -{ - if (UNLIKELY(rb_shape_obj_too_complex_p(obj))) { - st_free_table(fields_tbl->as.complex.table); - } - - xfree(fields_tbl); -} - -static int -vm_weak_table_gen_fields_foreach_too_complex_i(st_data_t _key, st_data_t value, st_data_t data, int error) -{ - struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data; - - GC_ASSERT(!iter_data->weak_only); - - if (SPECIAL_CONST_P((VALUE)value)) return ST_CONTINUE; - - return iter_data->callback((VALUE)value, iter_data->data); -} - -static int -vm_weak_table_gen_fields_foreach_too_complex_replace_i(st_data_t *_key, st_data_t *value, st_data_t data, int existing) -{ - struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data; - - GC_ASSERT(!iter_data->weak_only); - - return iter_data->update_callback((VALUE *)value, iter_data->data); -} - struct st_table *rb_generic_fields_tbl_get(void); static int @@ -4003,60 +3957,50 @@ vm_weak_table_gen_fields_foreach(st_data_t key, st_data_t value, st_data_t data) int ret = iter_data->callback((VALUE)key, iter_data->data); switch (ret) { case ST_CONTINUE: break; case ST_DELETE: - free_gen_fields_tbl((VALUE)key, (struct gen_fields_tbl *)value); RBASIC_SET_SHAPE_ID((VALUE)key, ROOT_SHAPE_ID); return ST_DELETE; case ST_REPLACE: { - VALUE new_key = (VALUE)key; ret = iter_data->update_callback(&new_key, iter_data->data); - if (key != new_key) ret = ST_DELETE; - DURING_GC_COULD_MALLOC_REGION_START(); - { - st_insert(rb_generic_fields_tbl_get(), (st_data_t)new_key, value); } - DURING_GC_COULD_MALLOC_REGION_END(); - key = (st_data_t)new_key; break; } default: - return ret; } if (!iter_data->weak_only) { - struct gen_fields_tbl *fields_tbl = (struct gen_fields_tbl *)value; - if (rb_shape_obj_too_complex_p((VALUE)key)) { - st_foreach_with_replace( - fields_tbl->as.complex.table, - vm_weak_table_gen_fields_foreach_too_complex_i, - vm_weak_table_gen_fields_foreach_too_complex_replace_i, - data - ); } - else { - uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID((VALUE)key)); - for (uint32_t i = 0; i < fields_count; i++) { - if (SPECIAL_CONST_P(fields_tbl->as.shape.fields[i])) continue; - int ivar_ret = iter_data->callback(fields_tbl->as.shape.fields[i], iter_data->data); - switch (ivar_ret) { - case ST_CONTINUE: - break; - case ST_REPLACE: - iter_data->update_callback(&fields_tbl->as.shape.fields[i], iter_data->data); - break; - default: - rb_bug("vm_weak_table_gen_fields_foreach: return value %d not supported", ivar_ret); - } - } } } return ret; @@ -147,6 +147,23 @@ rb_imemo_fields_new_complex(VALUE klass, size_t capa) return imemo_fields_new_complex(klass, capa); } VALUE rb_imemo_fields_clone(VALUE fields_obj) { @@ -168,6 +185,19 @@ rb_imemo_fields_clone(VALUE fields_obj) return clone; } /* ========================================================================= * memsize * ========================================================================= */ @@ -280,7 +280,9 @@ struct rb_fields { VALUE rb_imemo_fields_new(VALUE klass, size_t capa); VALUE rb_imemo_fields_new_complex(VALUE klass, size_t capa); VALUE rb_imemo_fields_clone(VALUE fields_obj); static inline VALUE * rb_imemo_fields_ptr(VALUE obj_fields) @@ -18,7 +18,6 @@ /* variable.c */ void rb_gc_mark_global_tbl(void); void rb_gc_update_global_tbl(void); -size_t rb_generic_ivar_memsize(VALUE); VALUE rb_search_class_path(VALUE); VALUE rb_attr_delete(VALUE, ID); void rb_autoload_str(VALUE mod, ID id, VALUE file); @@ -47,8 +46,7 @@ void rb_gvar_namespace_ready(const char *name); */ VALUE rb_mod_set_temporary_name(VALUE, VALUE); -struct gen_fields_tbl; -int rb_gen_fields_tbl_get(VALUE obj, ID id, struct gen_fields_tbl **fields_tbl); 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_evict_ivars_to_hash(VALUE obj); @@ -1657,8 +1657,8 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data) } while (0) if (UNLIKELY(rb_obj_exivar_p(obj))) { - struct gen_fields_tbl *fields_tbl; - rb_ivar_generic_fields_tbl_lookup(obj, &fields_tbl); if (UNLIKELY(rb_shape_obj_too_complex_p(obj))) { struct obj_traverse_replace_callback_data d = { @@ -1667,7 +1667,7 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data) .src = obj, }; rb_st_foreach_with_replace( - fields_tbl->as.complex.table, obj_iv_hash_traverse_replace_foreach_i, obj_iv_hash_traverse_replace_i, (st_data_t)&d @@ -1676,8 +1676,9 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data) } else { uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj)); for (uint32_t i = 0; i < fields_count; i++) { - CHECK_AND_REPLACE(fields_tbl->as.shape.fields[i]); } } } @@ -33,7 +33,7 @@ class TestEncoding < Test::Unit::TestCase encodings.each do |e| assert_raise(TypeError) { e.dup } assert_raise(TypeError) { e.clone } - assert_equal(e.object_id, Marshal.load(Marshal.dump(e)).object_id) end end @@ -1197,8 +1197,31 @@ rb_generic_fields_tbl_get(void) return generic_fields_tbl_; } int -rb_gen_fields_tbl_get(VALUE obj, ID id, struct gen_fields_tbl **fields_tbl) { RUBY_ASSERT(!RB_TYPE_P(obj, T_ICLASS)); @@ -1207,7 +1230,7 @@ rb_gen_fields_tbl_get(VALUE obj, ID id, struct gen_fields_tbl **fields_tbl) RB_VM_LOCKING() { if (st_lookup(generic_fields_tbl(obj, id, false), (st_data_t)obj, &data)) { - *fields_tbl = (struct gen_fields_tbl *)data; r = 1; } } @@ -1216,33 +1239,17 @@ rb_gen_fields_tbl_get(VALUE obj, ID id, struct gen_fields_tbl **fields_tbl) } int -rb_ivar_generic_fields_tbl_lookup(VALUE obj, struct gen_fields_tbl **fields_tbl) -{ - return rb_gen_fields_tbl_get(obj, 0, fields_tbl); -} - -static size_t -gen_fields_tbl_bytes(size_t n) { - return offsetof(struct gen_fields_tbl, as.shape.fields) + n * sizeof(VALUE); } - void rb_mark_generic_ivar(VALUE obj) { - st_data_t data; - if (st_lookup(generic_fields_tbl_no_ractor_check(obj), (st_data_t)obj, &data)) { - struct gen_fields_tbl *fields_tbl = (struct gen_fields_tbl *)data; - if (rb_shape_obj_too_complex_p(obj)) { - rb_mark_tbl_no_pin(fields_tbl->as.complex.table); - } - else { - uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj)); - for (uint32_t i = 0; i < fields_count; i++) { - rb_gc_mark_movable(fields_tbl->as.shape.fields[i]); - } - } } } @@ -1252,47 +1259,9 @@ rb_free_generic_ivar(VALUE obj) if (rb_obj_exivar_p(obj)) { st_data_t key = (st_data_t)obj, value; - bool too_complex = rb_shape_obj_too_complex_p(obj); - RB_VM_LOCKING() { - if (st_delete(generic_fields_tbl_no_ractor_check(obj), &key, &value)) { - struct gen_fields_tbl *fields_tbl = (struct gen_fields_tbl *)value; - - if (UNLIKELY(too_complex)) { - st_free_table(fields_tbl->as.complex.table); - } - - xfree(fields_tbl); - } } - RBASIC_SET_SHAPE_ID(obj, ROOT_SHAPE_ID); - } -} - -size_t -rb_generic_ivar_memsize(VALUE obj) -{ - struct gen_fields_tbl *fields_tbl; - - if (rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) { - if (rb_shape_obj_too_complex_p(obj)) { - return sizeof(struct gen_fields_tbl) + st_memsize(fields_tbl->as.complex.table); - } - else { - return gen_fields_tbl_bytes(RSHAPE_CAPACITY(RBASIC_SHAPE_ID(obj))); - } - } - return 0; -} - -static size_t -gen_fields_tbl_count(VALUE obj, const struct gen_fields_tbl *fields_tbl) -{ - if (rb_shape_obj_too_complex_p(obj)) { - return st_table_size(fields_tbl->as.complex.table); - } - else { - return RSHAPE_LEN(RBASIC_SHAPE_ID(obj)); } } @@ -1321,12 +1290,16 @@ rb_obj_field_get(VALUE obj, shape_id_t target_shape_id) case T_OBJECT: fields_hash = ROBJECT_FIELDS_HASH(obj); break; default: RUBY_ASSERT(rb_obj_exivar_p(obj)); - struct gen_fields_tbl *fields_tbl = NULL; - rb_ivar_generic_fields_tbl_lookup(obj, &fields_tbl); - RUBY_ASSERT(fields_tbl); - fields_hash = fields_tbl->as.complex.table; break; } VALUE value = Qundef; @@ -1352,12 +1325,16 @@ rb_obj_field_get(VALUE obj, shape_id_t target_shape_id) case T_OBJECT: fields = ROBJECT_FIELDS(obj); break; default: RUBY_ASSERT(rb_obj_exivar_p(obj)); - struct gen_fields_tbl *fields_tbl = NULL; - rb_ivar_generic_fields_tbl_lookup(obj, &fields_tbl); - RUBY_ASSERT(fields_tbl); - fields = fields_tbl->as.shape.fields; break; } return fields[attr_index]; @@ -1432,19 +1409,21 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef) default: shape_id = RBASIC_SHAPE_ID(obj); if (rb_obj_exivar_p(obj)) { - struct gen_fields_tbl *fields_tbl; - rb_gen_fields_tbl_get(obj, id, &fields_tbl); - if (rb_shape_obj_too_complex_p(obj)) { VALUE val; - if (rb_st_lookup(fields_tbl->as.complex.table, (st_data_t)id, (st_data_t *)&val)) { return val; } else { return undef; } } - ivar_list = fields_tbl->as.shape.fields; } else { return undef; @@ -1530,9 +1509,9 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef) fields = ROBJECT_FIELDS(obj); break; default: { - struct gen_fields_tbl *fields_tbl; - rb_gen_fields_tbl_get(obj, id, &fields_tbl); - fields = fields_tbl->as.shape.fields; break; } } @@ -1585,9 +1564,9 @@ too_complex: break; default: { - struct gen_fields_tbl *fields_tbl; - if (rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) { - table = fields_tbl->as.complex.table; } break; } @@ -1609,6 +1588,8 @@ rb_attr_delete(VALUE obj, ID id) return rb_ivar_delete(obj, id, Qnil); } static shape_id_t obj_transition_too_complex(VALUE obj, st_table *table) { @@ -1619,46 +1600,37 @@ obj_transition_too_complex(VALUE obj, st_table *table) RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); shape_id_t shape_id = rb_shape_transition_complex(obj); - VALUE *old_fields = NULL; - switch (BUILTIN_TYPE(obj)) { case T_OBJECT: - if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) { - old_fields = ROBJECT_FIELDS(obj); } - RBASIC_SET_SHAPE_ID(obj, shape_id); - ROBJECT_SET_FIELDS_HASH(obj, table); break; case T_CLASS: case T_MODULE: rb_bug("Unreachable"); break; default: - RB_VM_LOCKING() { - struct st_table *gen_ivs = generic_fields_tbl_no_ractor_check(obj); - - struct gen_fields_tbl *old_fields_tbl = NULL; - st_lookup(gen_ivs, (st_data_t)obj, (st_data_t *)&old_fields_tbl); - - if (old_fields_tbl) { - /* We need to modify old_fields_tbl to have the too complex shape - * and hold the table because the xmalloc could trigger a GC - * compaction. We want the table to be updated rather than - * the original fields. */ - rb_obj_set_shape_id(obj, shape_id); - old_fields_tbl->as.complex.table = table; - old_fields = (VALUE *)old_fields_tbl; - } - - struct gen_fields_tbl *fields_tbl = xmalloc(sizeof(struct gen_fields_tbl)); - fields_tbl->as.complex.table = table; - st_insert(gen_ivs, (st_data_t)obj, (st_data_t)fields_tbl); RBASIC_SET_SHAPE_ID(obj, shape_id); } } - xfree(old_fields); return shape_id; } @@ -1673,12 +1645,12 @@ rb_obj_init_too_complex(VALUE obj, st_table *table) obj_transition_too_complex(obj, table); } // Copy all object fields, including ivars and internal object_id, etc shape_id_t rb_evict_fields_to_hash(VALUE obj) { - void rb_obj_copy_fields_to_hash_table(VALUE obj, st_table *table); - RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); st_table *table = st_init_numtable_with_size(RSHAPE_LEN(RBASIC_SHAPE_ID(obj))); @@ -1809,135 +1781,174 @@ general_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val, void *data, } } -struct gen_fields_lookup_ensure_size { - VALUE obj; - ID id; - shape_id_t shape_id; - bool resize; -}; -static VALUE * -generic_ivar_set_shape_fields(VALUE obj, void *data) { - RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); - struct gen_fields_lookup_ensure_size *fields_lookup = data; - struct gen_fields_tbl *fields_tbl = NULL; - // We can't use st_update, since when resizing the fields table GC can - // happen, which will modify the st_table and may rebuild it - RB_VM_LOCKING() { - st_table *tbl = generic_fields_tbl(obj, fields_lookup->id, false); - int existing = st_lookup(tbl, (st_data_t)obj, (st_data_t *)&fields_tbl); - if (!existing || fields_lookup->resize) { - uint32_t new_capa = RSHAPE_CAPACITY(fields_lookup->shape_id); - uint32_t old_capa = RSHAPE_CAPACITY(RSHAPE_PARENT(fields_lookup->shape_id)); - if (existing) { - RUBY_ASSERT(RSHAPE_TYPE_P(fields_lookup->shape_id, SHAPE_IVAR) || RSHAPE_TYPE_P(fields_lookup->shape_id, SHAPE_OBJ_ID)); - RUBY_ASSERT(old_capa < new_capa); - RUBY_ASSERT(fields_tbl); - } - else { - RUBY_ASSERT(!fields_tbl); - RUBY_ASSERT(old_capa == 0); - } - RUBY_ASSERT(new_capa > 0); - struct gen_fields_tbl *old_fields_tbl = fields_tbl; - fields_tbl = xmalloc(gen_fields_tbl_bytes(new_capa)); - if (old_fields_tbl) { - memcpy(fields_tbl, old_fields_tbl, gen_fields_tbl_bytes(old_capa)); - } - st_insert(tbl, (st_data_t)obj, (st_data_t)fields_tbl); - if (old_fields_tbl) { - xfree(old_fields_tbl); } } - if (fields_lookup->shape_id) { - rb_obj_set_shape_id(fields_lookup->obj, fields_lookup->shape_id); } } - return fields_tbl->as.shape.fields; -} -static void -generic_ivar_set_shape_resize_fields(VALUE obj, attr_index_t _old_capa, attr_index_t new_capa, void *data) -{ - struct gen_fields_lookup_ensure_size *fields_lookup = data; - fields_lookup->resize = true; -} -static void -generic_ivar_set_set_shape_id(VALUE obj, shape_id_t shape_id, void *data) -{ - struct gen_fields_lookup_ensure_size *fields_lookup = data; - fields_lookup->shape_id = shape_id; -} -static shape_id_t -generic_ivar_set_transition_too_complex(VALUE obj, void *_data) -{ - shape_id_t new_shape_id = rb_evict_fields_to_hash(obj); - return new_shape_id; -} -static st_table * -generic_ivar_set_too_complex_table(VALUE obj, void *data) -{ - struct gen_fields_lookup_ensure_size *fields_lookup = data; - struct gen_fields_tbl *fields_tbl; - if (!rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) { - fields_tbl = xmalloc(sizeof(struct gen_fields_tbl)); - fields_tbl->as.complex.table = st_init_numtable_with_size(1); - RB_VM_LOCKING() { - st_insert(generic_fields_tbl(obj, fields_lookup->id, false), (st_data_t)obj, (st_data_t)fields_tbl); } } - RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); - return fields_tbl->as.complex.table; } static void -generic_ivar_set(VALUE obj, ID id, VALUE val) { - struct gen_fields_lookup_ensure_size fields_lookup = { - .obj = obj, - .id = id, - .resize = false, - }; - general_ivar_set(obj, id, val, &fields_lookup, - generic_ivar_set_shape_fields, - generic_ivar_set_shape_resize_fields, - generic_ivar_set_set_shape_id, - generic_ivar_set_transition_too_complex, - generic_ivar_set_too_complex_table); -} -static void -generic_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val) -{ - struct gen_fields_lookup_ensure_size fields_lookup = { - .obj = obj, - .resize = false, - }; - general_field_set(obj, target_shape_id, val, &fields_lookup, - generic_ivar_set_shape_fields, - generic_ivar_set_shape_resize_fields, - generic_ivar_set_set_shape_id, - generic_ivar_set_transition_too_complex, - generic_ivar_set_too_complex_table); } void @@ -2165,11 +2176,10 @@ ivar_defined0(VALUE obj, ID id) break; default: { - struct gen_fields_tbl *fields_tbl; - if (rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) { - table = fields_tbl->as.complex.table; } - break; } } @@ -2225,27 +2235,23 @@ iterate_over_shapes_callback(shape_id_t shape_id, void *data) return ST_CONTINUE; } - VALUE *iv_list; switch (BUILTIN_TYPE(itr_data->obj)) { case T_OBJECT: RUBY_ASSERT(!rb_shape_obj_too_complex_p(itr_data->obj)); - iv_list = ROBJECT_FIELDS(itr_data->obj); break; - case T_CLASS: - case T_MODULE: - rb_bug("Unreachable"); case T_IMEMO: RUBY_ASSERT(IMEMO_TYPE_P(itr_data->obj, imemo_fields)); RUBY_ASSERT(!rb_shape_obj_too_complex_p(itr_data->obj)); - iv_list = rb_imemo_fields_ptr(itr_data->obj); break; default: - iv_list = itr_data->fields_tbl->as.shape.fields; - break; } - VALUE val = iv_list[RSHAPE_INDEX(shape_id)]; return itr_data->func(RSHAPE_EDGE_NAME(shape_id), val, itr_data->arg); } @@ -2287,31 +2293,7 @@ obj_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, b } static void -gen_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, bool ivar_only) -{ - struct gen_fields_tbl *fields_tbl; - if (!rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) return; - - struct iv_itr_data itr_data = { - .obj = obj, - .fields_tbl = fields_tbl, - .arg = arg, - .func = func, - .ivar_only = ivar_only, - }; - - shape_id_t shape_id = RBASIC_SHAPE_ID(obj); - if (rb_shape_too_complex_p(shape_id)) { - rb_st_foreach(fields_tbl->as.complex.table, each_hash_iv, (st_data_t)&itr_data); - } - else { - itr_data.fields = fields_tbl->as.shape.fields; - iterate_over_shapes(shape_id, func, &itr_data); - } -} - -static void -class_fields_each(VALUE fields_obj, rb_ivar_foreach_callback_func *func, st_data_t arg, bool ivar_only) { IMEMO_TYPE_P(fields_obj, imemo_fields); @@ -2335,8 +2317,8 @@ class_fields_each(VALUE fields_obj, rb_ivar_foreach_callback_func *func, st_data void rb_copy_generic_ivar(VALUE dest, VALUE obj) { - struct gen_fields_tbl *obj_fields_tbl; - struct gen_fields_tbl *new_fields_tbl; rb_check_frozen(dest); @@ -2344,19 +2326,16 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj) return; } - unsigned long src_num_ivs = rb_ivar_count(obj); - if (!src_num_ivs) { - goto clear; - } - shape_id_t src_shape_id = rb_obj_shape_id(obj); - if (rb_gen_fields_tbl_get(obj, 0, &obj_fields_tbl)) { - if (gen_fields_tbl_count(obj, obj_fields_tbl) == 0) goto clear; 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); return; } @@ -2371,7 +2350,6 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj) 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); - return; } } @@ -2381,25 +2359,19 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj) return; } - uint32_t dest_capa = RSHAPE_CAPACITY(dest_shape_id); - RUBY_ASSERT(dest_capa > 0); - new_fields_tbl = xmalloc(gen_fields_tbl_bytes(dest_capa)); - - VALUE *src_buf = obj_fields_tbl->as.shape.fields; - VALUE *dest_buf = new_fields_tbl->as.shape.fields; - rb_shape_copy_fields(dest, dest_buf, dest_shape_id, obj, src_buf, src_shape_id); - /* - * c.fields_tbl may change in gen_fields_copy due to realloc, - * no need to free - */ RB_VM_LOCKING() { generic_fields_tbl_no_ractor_check(dest); - st_insert(generic_fields_tbl_no_ractor_check(obj), (st_data_t)dest, (st_data_t)new_fields_tbl); } - rb_obj_set_shape_id(dest, dest_shape_id); } return; @@ -2428,7 +2400,7 @@ rb_field_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, switch (BUILTIN_TYPE(obj)) { case T_IMEMO: if (IMEMO_TYPE_P(obj, imemo_fields)) { - class_fields_each(obj, func, arg, ivar_only); } break; case T_OBJECT: @@ -2440,13 +2412,16 @@ rb_field_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(0); VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj); if (fields_obj) { - class_fields_each(fields_obj, func, arg, ivar_only); } } break; default: if (rb_obj_exivar_p(obj)) { - gen_fields_each(obj, func, arg, ivar_only); } break; } @@ -2468,6 +2443,7 @@ rb_ivar_count(VALUE obj) case T_OBJECT: iv_count = ROBJECT_FIELDS_COUNT(obj); break; case T_CLASS: case T_MODULE: { @@ -2476,16 +2452,37 @@ rb_ivar_count(VALUE obj) return 0; } if (rb_shape_obj_too_complex_p(fields_obj)) { - return rb_st_table_size(rb_imemo_fields_complex_tbl(fields_obj)); } - return RBASIC_FIELDS_COUNT(fields_obj); } default: if (rb_obj_exivar_p(obj)) { - struct gen_fields_tbl *fields_tbl; - if (rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) { - iv_count = gen_fields_tbl_count(obj, fields_tbl); } } break; @@ -12,18 +12,7 @@ #include "shape.h" -struct gen_fields_tbl { - union { - struct { - VALUE fields[1]; - } shape; - struct { - st_table *table; - } complex; - } as; -}; - -int rb_ivar_generic_fields_tbl_lookup(VALUE obj, struct gen_fields_tbl **); void rb_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_table *fields_table); void rb_free_rb_global_tbl(void); @@ -1259,9 +1259,11 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call } default: if (rb_obj_exivar_p(obj)) { - struct gen_fields_tbl *fields_tbl; - rb_gen_fields_tbl_get(obj, id, &fields_tbl); - ivar_list = fields_tbl->as.shape.fields; } else { return default_value; @@ -1333,9 +1335,9 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call break; default: { - struct gen_fields_tbl *fields_tbl; - if (rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) { - table = fields_tbl->as.complex.table; } break; } @@ -1456,7 +1458,7 @@ vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_i { shape_id_t shape_id = RBASIC_SHAPE_ID(obj); - struct gen_fields_tbl *fields_tbl = 0; // Cache hit case if (shape_id == dest_shape_id) { @@ -1474,13 +1476,13 @@ vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_i return Qundef; } - rb_gen_fields_tbl_get(obj, 0, &fields_tbl); if (shape_id != dest_shape_id) { RBASIC_SET_SHAPE_ID(obj, dest_shape_id); } - RB_OBJ_WRITE(obj, &fields_tbl->as.shape.fields[index], val); RB_DEBUG_COUNTER_INC(ivar_set_ic_hit); |