diff options
| author | Jean Boussier <jean.boussier@gmail.com> | 2025-08-25 11:36:09 +0200 |
|---|---|---|
| committer | Jean Boussier <jean.boussier@gmail.com> | 2025-08-25 13:45:51 +0200 |
| commit | 78b8ecd1ea79c777260c2d0221835ca2e5cdca31 (patch) | |
| tree | 63273b568e5f04fe324947a55c41ceddf34fbbab /variable.c | |
| parent | e535b0da483fe0aad5c4f661ad1eb6640325dec5 (diff) | |
Refactor rb_obj_ivar_set
With the recent changes to shapes and variables
`general_ivar_set` no longer make sense and is
just extra complexity.
Trying to have a unified logic for all 3 types of objects
made sense, but also made the code way more complex.
We should definitely try to share more code between the
3 paths though, but that can be done with functions like
`generic_shape_ivar`.
Diffstat (limited to 'variable.c')
| -rw-r--r-- | variable.c | 210 |
1 files changed, 70 insertions, 140 deletions
diff --git a/variable.c b/variable.c index 4949065583..ac57685232 100644 --- a/variable.c +++ b/variable.c @@ -1769,112 +1769,6 @@ imemo_fields_copy_capa(VALUE owner, VALUE source_fields_obj, attr_index_t new_si return fields_obj; } -struct general_ivar_set_result { - attr_index_t index; - bool existing; -}; - -static struct general_ivar_set_result -general_ivar_set(VALUE obj, ID id, VALUE val, void *data, - VALUE *(*shape_fields_func)(VALUE, void *), - void (*shape_resize_fields_func)(VALUE, attr_index_t, attr_index_t, void *), - void (*set_shape_id_func)(VALUE, shape_id_t, void *), - st_table *(*too_complex_table_func)(VALUE, void *)) -{ - struct general_ivar_set_result result = { - .index = 0, - .existing = true - }; - - shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj); - - if (UNLIKELY(rb_shape_too_complex_p(current_shape_id))) { - goto too_complex; - } - - attr_index_t index; - if (!rb_shape_get_iv_index(current_shape_id, id, &index)) { - result.existing = false; - - index = RSHAPE_LEN(current_shape_id); - if (index >= SHAPE_MAX_FIELDS) { - rb_raise(rb_eArgError, "too many instance variables"); - } - - shape_id_t next_shape_id = rb_shape_transition_add_ivar(obj, id); - if (UNLIKELY(rb_shape_too_complex_p(next_shape_id))) { - current_shape_id = rb_evict_fields_to_hash(obj); - goto too_complex; - } - else if (UNLIKELY(RSHAPE_CAPACITY(next_shape_id) != RSHAPE_CAPACITY(current_shape_id))) { - RUBY_ASSERT(RSHAPE_CAPACITY(next_shape_id) > RSHAPE_CAPACITY(current_shape_id)); - shape_resize_fields_func(obj, RSHAPE_CAPACITY(current_shape_id), RSHAPE_CAPACITY(next_shape_id), data); - } - - RUBY_ASSERT(RSHAPE_TYPE_P(next_shape_id, SHAPE_IVAR), - "next_shape_id: 0x%" PRIx32 " RSHAPE_TYPE(next_shape_id): %d", - next_shape_id, (int)RSHAPE_TYPE(next_shape_id)); - RUBY_ASSERT(index == (RSHAPE_INDEX(next_shape_id))); - set_shape_id_func(obj, next_shape_id, data); - } - - VALUE *table = shape_fields_func(obj, data); - RB_OBJ_WRITE(obj, &table[index], val); - - result.index = index; - return result; - -too_complex: - { - RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); - - st_table *table = too_complex_table_func(obj, data); - result.existing = st_insert(table, (st_data_t)id, (st_data_t)val); - result.index = 0; - RB_OBJ_WRITTEN(obj, Qundef, val); - } - return result; -} - -static void -general_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val, void *data, - VALUE *(*shape_fields_func)(VALUE, void *), - void (*shape_resize_fields_func)(VALUE, attr_index_t, attr_index_t, void *), - void (*set_shape_id_func)(VALUE, shape_id_t, void *), - st_table *(*too_complex_table_func)(VALUE, void *)) -{ - shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj); - - if (UNLIKELY(rb_shape_too_complex_p(target_shape_id))) { - if (UNLIKELY(!rb_shape_too_complex_p(current_shape_id))) { - current_shape_id = rb_evict_fields_to_hash(obj); - } - - st_table *table = too_complex_table_func(obj, data); - - if (RSHAPE_LEN(target_shape_id) > RSHAPE_LEN(current_shape_id)) { - RBASIC_SET_SHAPE_ID(obj, target_shape_id); - } - - RUBY_ASSERT(RSHAPE_EDGE_NAME(target_shape_id)); - st_insert(table, (st_data_t)RSHAPE_EDGE_NAME(target_shape_id), (st_data_t)val); - RB_OBJ_WRITTEN(obj, Qundef, val); - } - else { - attr_index_t index = RSHAPE_INDEX(target_shape_id); - if (index >= RSHAPE_CAPACITY(current_shape_id)) { - shape_resize_fields_func(obj, RSHAPE_CAPACITY(current_shape_id), RSHAPE_CAPACITY(target_shape_id), data); - } - - if (RSHAPE_LEN(target_shape_id) > RSHAPE_LEN(current_shape_id)) { - set_shape_id_func(obj, target_shape_id, data); - } - - VALUE *table = shape_fields_func(obj, data); - RB_OBJ_WRITE(obj, &table[index], val); - } -} - static VALUE imemo_fields_set(VALUE owner, VALUE fields_obj, shape_id_t target_shape_id, ID field_name, VALUE val, bool concurrent) { @@ -2001,52 +1895,88 @@ rb_obj_copy_fields_to_hash_table(VALUE obj, st_table *table) rb_field_foreach(obj, rb_obj_copy_ivs_to_hash_table_i, (st_data_t)table, false); } -static VALUE * -obj_ivar_set_shape_fields(VALUE obj, void *_data) +attr_index_t +rb_obj_ivar_set(VALUE obj, ID id, VALUE val) { - RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); + shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj); - return ROBJECT_FIELDS(obj); -} + if (UNLIKELY(rb_shape_too_complex_p(current_shape_id))) { + goto too_complex; + } -static void -obj_ivar_set_shape_resize_fields(VALUE obj, attr_index_t old_capa, attr_index_t new_capa, void *_data) -{ - rb_ensure_iv_list_size(obj, old_capa, new_capa); -} + attr_index_t index; + if (!rb_shape_get_iv_index(current_shape_id, id, &index)) { + index = RSHAPE_LEN(current_shape_id); + if (index >= SHAPE_MAX_FIELDS) { + rb_raise(rb_eArgError, "too many instance variables"); + } -static void -obj_ivar_set_set_shape_id(VALUE obj, shape_id_t shape_id, void *_data) -{ - rb_obj_set_shape_id(obj, shape_id); -} + shape_id_t next_shape_id = rb_shape_transition_add_ivar(obj, id); + if (UNLIKELY(rb_shape_too_complex_p(next_shape_id))) { + current_shape_id = rb_evict_fields_to_hash(obj); + goto too_complex; + } + else if (UNLIKELY(RSHAPE_CAPACITY(next_shape_id) != RSHAPE_CAPACITY(current_shape_id))) { + RUBY_ASSERT(RSHAPE_CAPACITY(next_shape_id) > RSHAPE_CAPACITY(current_shape_id)); + rb_ensure_iv_list_size(obj, RSHAPE_CAPACITY(current_shape_id), RSHAPE_CAPACITY(next_shape_id)); + } -static st_table * -obj_ivar_set_too_complex_table(VALUE obj, void *_data) -{ - RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); + RUBY_ASSERT(RSHAPE_TYPE_P(next_shape_id, SHAPE_IVAR), + "next_shape_id: 0x%" PRIx32 " RSHAPE_TYPE(next_shape_id): %d", + next_shape_id, (int)RSHAPE_TYPE(next_shape_id)); + RUBY_ASSERT(index == (RSHAPE_INDEX(next_shape_id))); + rb_obj_set_shape_id(obj, next_shape_id); + } - return ROBJECT_FIELDS_HASH(obj); -} + VALUE *table = ROBJECT_FIELDS(obj); + RB_OBJ_WRITE(obj, &table[index], val); -attr_index_t -rb_obj_ivar_set(VALUE obj, ID id, VALUE val) -{ - return general_ivar_set(obj, id, val, NULL, - obj_ivar_set_shape_fields, - obj_ivar_set_shape_resize_fields, - obj_ivar_set_set_shape_id, - obj_ivar_set_too_complex_table).index; + return index; + +too_complex: + { + RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); + + st_table *table = ROBJECT_FIELDS_HASH(obj); + st_insert(table, (st_data_t)id, (st_data_t)val); + RB_OBJ_WRITTEN(obj, Qundef, val); + } + return 0; } static void obj_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val) { - general_field_set(obj, target_shape_id, val, NULL, - obj_ivar_set_shape_fields, - obj_ivar_set_shape_resize_fields, - obj_ivar_set_set_shape_id, - obj_ivar_set_too_complex_table); + shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj); + + if (UNLIKELY(rb_shape_too_complex_p(target_shape_id))) { + if (UNLIKELY(!rb_shape_too_complex_p(current_shape_id))) { + current_shape_id = rb_evict_fields_to_hash(obj); + } + + st_table *table = ROBJECT_FIELDS_HASH(obj); + + if (RSHAPE_LEN(target_shape_id) > RSHAPE_LEN(current_shape_id)) { + RBASIC_SET_SHAPE_ID(obj, target_shape_id); + } + + RUBY_ASSERT(RSHAPE_EDGE_NAME(target_shape_id)); + st_insert(table, (st_data_t)RSHAPE_EDGE_NAME(target_shape_id), (st_data_t)val); + RB_OBJ_WRITTEN(obj, Qundef, val); + } + else { + attr_index_t index = RSHAPE_INDEX(target_shape_id); + if (index >= RSHAPE_CAPACITY(current_shape_id)) { + rb_ensure_iv_list_size(obj, RSHAPE_CAPACITY(current_shape_id), RSHAPE_CAPACITY(target_shape_id)); + } + + if (RSHAPE_LEN(target_shape_id) > RSHAPE_LEN(current_shape_id)) { + rb_obj_set_shape_id(obj, target_shape_id); + } + + VALUE *table = ROBJECT_FIELDS(obj); + RB_OBJ_WRITE(obj, &table[index], val); + } } /* Set the instance variable +val+ on object +obj+ at ivar name +id+. |
