summaryrefslogtreecommitdiff
path: root/variable.c
diff options
context:
space:
mode:
-rw-r--r--variable.c549
1 files changed, 273 insertions, 276 deletions
@@ -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;