aboutsummaryrefslogtreecommitdiffstats
path: root/variable.c
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2023-11-02 11:01:35 -0400
committerPeter Zhu <peter@peterzhu.ca>2023-11-02 13:42:11 -0400
commit4c3cc25ea2bc176aa699d14f155b566655936a38 (patch)
tree567c7e132e706720d30a1a9b6f05df4c2051a212 /variable.c
parent38ba040d8bda65321daad8d5bfa8956b5072e826 (diff)
downloadruby-4c3cc25ea2bc176aa699d14f155b566655936a38.tar.gz
Use shape capacity transition for class ivars
This commit changes class ivars to respect the capacity transition in shapes rather than growing the capacity independently.
Diffstat (limited to 'variable.c')
-rw-r--r--variable.c56
1 files changed, 31 insertions, 25 deletions
diff --git a/variable.c b/variable.c
index 48ca1452df..27c10a27dd 100644
--- a/variable.c
+++ b/variable.c
@@ -4152,44 +4152,50 @@ rb_class_ivar_set(VALUE obj, ID key, VALUE value)
rb_shape_t * shape = rb_shape_get_shape(obj);
if (shape->type == SHAPE_OBJ_TOO_COMPLEX) {
found = rb_complex_ivar_set(obj, key, value);
+ goto finish;
}
- else {
- attr_index_t idx;
- found = rb_shape_get_iv_index(shape, key, &idx);
- if (found) {
- // Changing an existing instance variable
- RUBY_ASSERT(RCLASS_IVPTR(obj));
+ attr_index_t idx;
+ found = rb_shape_get_iv_index(shape, key, &idx);
- RCLASS_IVPTR(obj)[idx] = value;
- RB_OBJ_WRITTEN(obj, Qundef, value);
- }
- else {
- // Creating and setting a new instance variable
+ if (!found) {
+ idx = shape->next_iv_index;
+
+ if (UNLIKELY(idx >= shape->capacity)) {
+ RUBY_ASSERT(shape->next_iv_index == shape->capacity);
- // Move to a shape which fits the new ivar
- idx = shape->next_iv_index;
- rb_shape_t * next_shape = rb_shape_get_next(shape, obj, key);
+ rb_shape_t *next_shape = rb_shape_transition_shape_capa(shape);
if (next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
rb_evict_ivars_to_hash(obj, shape);
rb_complex_ivar_set(obj, key, value);
+ goto finish;
}
- else {
- // We always allocate a power of two sized IV array. This way we
- // only need to realloc when we expand into a new power of two size
- if ((idx & (idx - 1)) == 0) {
- size_t newsize = idx ? idx * 2 : 1;
- REALLOC_N(RCLASS_IVPTR(obj), VALUE, newsize);
- }
- RUBY_ASSERT(RCLASS_IVPTR(obj));
+ REALLOC_N(RCLASS_IVPTR(obj), VALUE, next_shape->capacity);
- RB_OBJ_WRITE(obj, &RCLASS_IVPTR(obj)[idx], value);
- rb_shape_set_shape(obj, next_shape);
- }
+ shape = next_shape;
+ RUBY_ASSERT(shape->type == SHAPE_CAPACITY_CHANGE);
+ }
+
+ rb_shape_t *next_shape = rb_shape_get_next(shape, obj, key);
+ if (next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
+ rb_evict_ivars_to_hash(obj, shape);
+ rb_complex_ivar_set(obj, key, value);
+ goto finish;
+ }
+ else {
+ rb_shape_set_shape(obj, next_shape);
+
+ RUBY_ASSERT(next_shape->type == SHAPE_IVAR);
+ RUBY_ASSERT(idx == (next_shape->next_iv_index - 1));
}
}
+
+ RUBY_ASSERT(RCLASS_IVPTR(obj));
+
+ RB_OBJ_WRITE(obj, &RCLASS_IVPTR(obj)[idx], value);
}
+finish:
RB_VM_LOCK_LEAVE();
return found;