summaryrefslogtreecommitdiff
path: root/variable.c
diff options
context:
space:
mode:
authorAaron Patterson <[email protected]>2023-10-19 11:00:54 -0700
committerAaron Patterson <[email protected]>2023-10-24 10:52:06 -0700
commitcaf6a72348431e0e6b61be84919cd06c7a745189 ()
treea8340c3033d0885aaa3d0ec460035d52bcac6afc /variable.c
parent27c75319396b8e9fa43b33aca99725b7352a6dcb (diff)
remove IV limit / support complex shapes on classes
-rw-r--r--variable.c212
1 files changed, 151 insertions, 61 deletions
@@ -72,6 +72,22 @@ struct ivar_update {
#endif
};
void
Init_var_tables(void)
{
@@ -1231,7 +1247,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
case T_CLASS:
case T_MODULE:
{
- bool found;
VALUE val;
RB_VM_LOCK_ENTER();
@@ -1240,18 +1256,30 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
shape_id = RCLASS_SHAPE_ID(obj);
#endif
- attr_index_t index = 0;
- shape = rb_shape_get_shape_by_id(shape_id);
- found = rb_shape_get_iv_index(shape, id, &index);
-
- if (found) {
- ivar_list = RCLASS_IVPTR(obj);
- RUBY_ASSERT(ivar_list);
-
- val = ivar_list[index];
}
else {
- val = undef;
}
}
RB_VM_LOCK_LEAVE();
@@ -1439,6 +1467,60 @@ rb_ensure_generic_iv_list_size(VALUE obj, rb_shape_t *shape, uint32_t newsize)
return ivtbl;
}
// @note May raise when there are too many instance variables.
rb_shape_t *
rb_grow_iv_list(VALUE obj)
@@ -1446,10 +1528,13 @@ 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);
-
- rb_ensure_iv_list_size(obj, initial_shape->capacity, res->capacity);
-
- rb_shape_set_shape(obj, res);
return res;
}
@@ -1470,12 +1555,12 @@ rb_obj_ivar_set(VALUE obj, ID id, VALUE val)
uint32_t num_iv = shape->capacity;
if (rb_shape_obj_too_complex(obj)) {
- st_table * table = ROBJECT_IV_HASH(obj);
- st_insert(table, (st_data_t)id, (st_data_t)val);
- RB_OBJ_WRITTEN(obj, Qundef, val);
return 0;
}
if (!rb_shape_get_iv_index(shape, id, &index)) {
index = shape->next_iv_index;
if (index >= MAX_IVARS) {
@@ -1487,31 +1572,20 @@ rb_obj_ivar_set(VALUE obj, ID id, VALUE val)
if (UNLIKELY(shape->next_iv_index >= num_iv)) {
RUBY_ASSERT(shape->next_iv_index == num_iv);
- shape = rb_grow_iv_list(obj);
RUBY_ASSERT(shape->type == SHAPE_CAPACITY_CHANGE);
}
- rb_shape_t *next_shape = rb_shape_get_next(shape, obj, id);
if (next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
- st_table * table = st_init_numtable_with_size(shape->next_iv_index);
-
- // Evacuate all previous values from shape into id_table
- rb_ivar_foreach(obj, rb_obj_evacuate_ivs_to_hash_table, (st_data_t)table);
-
- // Insert new value too
- st_insert(table, (st_data_t)id, (st_data_t)val);
- RB_OBJ_WRITTEN(obj, Qundef, val);
-
- rb_shape_set_too_complex(obj);
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
-
- if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
- xfree(ROBJECT(obj)->as.heap.ivptr);
- }
-
- ROBJECT(obj)->as.heap.ivptr = (VALUE *)table;
-
return 0;
}
else {
@@ -1765,7 +1839,13 @@ class_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
struct iv_itr_data itr_data;
itr_data.obj = obj;
itr_data.arg = arg;
- iterate_over_shapes_with_callback(shape, func, &itr_data);
}
void
@@ -3989,40 +4069,50 @@ int
rb_class_ivar_set(VALUE obj, ID key, VALUE value)
{
RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
- int found;
rb_check_frozen(obj);
RB_VM_LOCK_ENTER();
{
rb_shape_t * shape = rb_shape_get_shape(obj);
- 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));
-
- RCLASS_IVPTR(obj)[idx] = value;
- RB_OBJ_WRITTEN(obj, Qundef, value);
}
else {
- // Creating and setting a new instance variable
- // Move to a shape which fits the new ivar
- idx = shape->next_iv_index;
- shape = rb_shape_get_next(shape, obj, key);
- // 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));
- RB_OBJ_WRITE(obj, &RCLASS_IVPTR(obj)[idx], value);
- rb_shape_set_shape(obj, shape);
}
}
RB_VM_LOCK_LEAVE();