aboutsummaryrefslogtreecommitdiffstats
path: root/variable.c
diff options
context:
space:
mode:
authorJean Boussier <byroot@ruby-lang.org>2023-11-07 18:09:55 +0100
committerJean Boussier <jean.boussier@gmail.com>2023-11-08 11:02:55 +0100
commitd898e8d6f89fba34a9ee5c0e139f38ac807059e6 (patch)
treebf9d79ff3b3502565b5b718427f192bcd472dc64 /variable.c
parent4abf6cde583f3ebe562bd9d62e0126b2cbf4dfac (diff)
downloadruby-d898e8d6f89fba34a9ee5c0e139f38ac807059e6.tar.gz
Refactor rb_shape_transition_shape_capa out
Right now the `rb_shape_get_next` shape caller need to first check if there is capacity left, and if not call `rb_shape_transition_shape_capa` before it can call `rb_shape_get_next`. And on each of these it needs to checks if we got a TOO_COMPLEX back. All this logic is duplicated in the interpreter, YJIT and RJIT. Instead we can have `rb_shape_get_next` do the capacity transition when needed. The caller can compare the old and new shapes capacity to know if resizing is needed. It also can check for TOO_COMPLEX only once.
Diffstat (limited to 'variable.c')
-rw-r--r--variable.c55
1 files changed, 13 insertions, 42 deletions
diff --git a/variable.c b/variable.c
index 37194782a3..72c0fd7c2b 100644
--- a/variable.c
+++ b/variable.c
@@ -1442,45 +1442,34 @@ general_ivar_set(VALUE obj, ID id, VALUE val, void *data,
.existing = true
};
- rb_shape_t *shape = rb_shape_get_shape(obj);
+ rb_shape_t *current_shape = rb_shape_get_shape(obj);
- if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
+ if (UNLIKELY(current_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
goto too_complex;
}
attr_index_t index;
- if (!rb_shape_get_iv_index(shape, id, &index)) {
+ if (!rb_shape_get_iv_index(current_shape, id, &index)) {
result.existing = false;
- index = shape->next_iv_index;
+ index = current_shape->next_iv_index;
if (index >= MAX_IVARS) {
rb_raise(rb_eArgError, "too many instance variables");
}
- if (UNLIKELY(shape->next_iv_index >= shape->capacity)) {
- RUBY_ASSERT(shape->next_iv_index == shape->capacity);
-
- rb_shape_t *next_shape = rb_shape_transition_shape_capa(shape);
- if (next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
- transition_too_complex_func(obj, data);
- goto too_complex;
- }
-
- RUBY_ASSERT(next_shape->type == SHAPE_CAPACITY_CHANGE);
- RUBY_ASSERT(next_shape->capacity > shape->capacity);
- shape_resize_ivptr_func(obj, shape->capacity, next_shape->capacity, data);
- shape = next_shape;
- }
-
- shape = rb_shape_get_next(shape, obj, id);
- if (shape->type == SHAPE_OBJ_TOO_COMPLEX) {
+ rb_shape_t *next_shape = rb_shape_get_next(current_shape, obj, id);
+ if (UNLIKELY(next_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
transition_too_complex_func(obj, data);
goto too_complex;
}
+ else if (UNLIKELY(next_shape->capacity != current_shape->capacity)) {
+ RUBY_ASSERT(next_shape->capacity > current_shape->capacity);
+ shape_resize_ivptr_func(obj, current_shape->capacity, next_shape->capacity, data);
+ }
- RUBY_ASSERT(shape->type == SHAPE_IVAR);
- RUBY_ASSERT(index == (shape->next_iv_index - 1));
- set_shape_func(obj, shape, data);
+ RUBY_ASSERT(next_shape->type == SHAPE_IVAR);
+ RUBY_ASSERT(index == (next_shape->next_iv_index - 1));
+ set_shape_func(obj, next_shape, data);
}
VALUE *table = shape_ivptr_func(obj, data);
@@ -1647,24 +1636,6 @@ rb_ensure_iv_list_size(VALUE obj, uint32_t current_capacity, uint32_t new_capaci
}
}
-// @note May raise when there are too many instance variables.
-rb_shape_t *
-rb_grow_iv_list(VALUE obj)
-{
- rb_shape_t * initial_shape = rb_shape_get_shape(obj);
- RUBY_ASSERT(initial_shape->capacity > 0);
- rb_shape_t * res = rb_shape_transition_shape_capa(initial_shape);
- if (res->type == SHAPE_OBJ_TOO_COMPLEX) { // Out of shapes
- rb_evict_ivars_to_hash(obj, initial_shape);
- }
- else {
- rb_ensure_iv_list_size(obj, initial_shape->capacity, res->capacity);
- rb_shape_set_shape(obj, res);
- }
-
- return res;
-}
-
int
rb_obj_evacuate_ivs_to_hash_table(ID key, VALUE val, st_data_t arg)
{