aboutsummaryrefslogtreecommitdiffstats
path: root/variable.c
diff options
context:
space:
mode:
Diffstat (limited to 'variable.c')
-rw-r--r--variable.c177
1 files changed, 100 insertions, 77 deletions
diff --git a/variable.c b/variable.c
index b0bb295369..f179b8b612 100644
--- a/variable.c
+++ b/variable.c
@@ -1084,7 +1084,7 @@ rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **ivtbl)
static size_t
gen_ivtbl_bytes(size_t n)
{
- return offsetof(struct gen_ivtbl, ivptr) + n * sizeof(VALUE);
+ return offsetof(struct gen_ivtbl, as.shape.ivptr) + n * sizeof(VALUE);
}
static struct gen_ivtbl *
@@ -1092,30 +1092,17 @@ gen_ivtbl_resize(struct gen_ivtbl *old, uint32_t n)
{
RUBY_ASSERT(n > 0);
- uint32_t len = old ? old->numiv : 0;
+ uint32_t len = old ? old->as.shape.numiv : 0;
struct gen_ivtbl *ivtbl = xrealloc(old, gen_ivtbl_bytes(n));
- ivtbl->numiv = n;
+ ivtbl->as.shape.numiv = n;
for (; len < n; len++) {
- ivtbl->ivptr[len] = Qundef;
+ ivtbl->as.shape.ivptr[len] = Qundef;
}
return ivtbl;
}
-#if 0
-static struct gen_ivtbl *
-gen_ivtbl_dup(const struct gen_ivtbl *orig)
-{
- size_t s = gen_ivtbl_bytes(orig->numiv);
- struct gen_ivtbl *ivtbl = xmalloc(s);
-
- memcpy(ivtbl, orig, s);
-
- return ivtbl;
-}
-#endif
-
static int
generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t u, int existing)
{
@@ -1126,7 +1113,7 @@ generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t u, int existing)
if (existing) {
ivtbl = (struct gen_ivtbl *)*v;
- if (ivup->iv_index < ivtbl->numiv) {
+ if (ivup->iv_index < ivtbl->as.shape.numiv) {
ivup->ivtbl = ivtbl;
return ST_STOP;
}
@@ -1142,31 +1129,19 @@ generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t u, int existing)
return ST_CONTINUE;
}
-static void
-gen_ivtbl_mark_and_update(struct gen_ivtbl *ivtbl)
-{
- uint32_t i;
-
- for (i = 0; i < ivtbl->numiv; i++) {
- rb_gc_mark_and_move(&ivtbl->ivptr[i]);
- }
-}
-
void
rb_mark_and_update_generic_ivar(VALUE obj)
{
- if (rb_shape_obj_too_complex(obj)) {
- st_table *ivtbl;
+ struct gen_ivtbl *ivtbl;
- if (rb_gen_ivtbl_get(obj, 0, (struct gen_ivtbl **)&ivtbl)) {
- rb_mark_tbl(ivtbl);
+ if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
+ if (rb_shape_obj_too_complex(obj)) {
+ rb_mark_tbl(ivtbl->as.complex.table);
}
- }
- else {
- struct gen_ivtbl *ivtbl;
-
- if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
- gen_ivtbl_mark_and_update(ivtbl);
+ else {
+ for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
+ rb_gc_mark_and_move(&ivtbl->as.shape.ivptr[i]);
+ }
}
}
}
@@ -1184,10 +1159,19 @@ rb_mv_generic_ivar(VALUE rsrc, VALUE dst)
void
rb_free_generic_ivar(VALUE obj)
{
- st_data_t key = (st_data_t)obj, ivtbl;
+ st_data_t key = (st_data_t)obj, value;
+
+ bool too_complex = rb_shape_obj_too_complex(obj);
- if (st_delete(generic_ivtbl_no_ractor_check(obj), &key, &ivtbl))
- xfree((struct gen_ivtbl *)ivtbl);
+ if (st_delete(generic_ivtbl_no_ractor_check(obj), &key, &value)) {
+ struct gen_ivtbl *ivtbl = (struct gen_ivtbl *)value;
+
+ if (UNLIKELY(too_complex)) {
+ st_free_table(ivtbl->as.complex.table);
+ }
+
+ xfree(ivtbl);
+ }
}
RUBY_FUNC_EXPORTED size_t
@@ -1195,8 +1179,14 @@ rb_generic_ivar_memsize(VALUE obj)
{
struct gen_ivtbl *ivtbl;
- if (rb_gen_ivtbl_get(obj, 0, &ivtbl))
- return gen_ivtbl_bytes(ivtbl->numiv);
+ if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
+ if (rb_shape_obj_too_complex(obj)) {
+ return sizeof(struct gen_ivtbl) + st_memsize(ivtbl->as.complex.table);
+ }
+ else {
+ return gen_ivtbl_bytes(ivtbl->as.shape.numiv);
+ }
+ }
return 0;
}
@@ -1225,14 +1215,19 @@ rb_generic_shape_id(VALUE obj)
#endif
static size_t
-gen_ivtbl_count(const struct gen_ivtbl *ivtbl)
+gen_ivtbl_count(VALUE obj, const struct gen_ivtbl *ivtbl)
{
uint32_t i;
size_t n = 0;
- for (i = 0; i < ivtbl->numiv; i++) {
- if (!UNDEF_P(ivtbl->ivptr[i])) {
- n++;
+ if (rb_shape_obj_too_complex(obj)) {
+ n = st_table_size(ivtbl->as.complex.table);
+ }
+ else {
+ for (i = 0; i < ivtbl->as.shape.numiv; i++) {
+ if (!UNDEF_P(ivtbl->as.shape.ivptr[i])) {
+ n++;
+ }
}
}
@@ -1328,9 +1323,8 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
rb_gen_ivtbl_get(obj, id, &ivtbl);
if (rb_shape_obj_too_complex(obj)) {
- st_table * iv_table = (st_table *)ivtbl;
VALUE val;
- if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) {
+ if (rb_st_lookup(ivtbl->as.complex.table, (st_data_t)id, (st_data_t *)&val)) {
return val;
}
else {
@@ -1341,7 +1335,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
#if !SHAPE_IN_BASIC_FLAGS
shape_id = ivtbl->shape_id;
#endif
- ivar_list = ivtbl->ivptr;
+ ivar_list = ivtbl->as.shape.ivptr;
}
else {
return undef;
@@ -1411,7 +1405,8 @@ rb_attr_delete(VALUE obj, ID id)
static int
rb_complex_ivar_set(VALUE obj, ID id, VALUE val)
{
- st_table * table;
+ struct gen_ivtbl *ivtbl;
+ st_table *table;
RUBY_ASSERT(rb_shape_obj_too_complex(obj));
switch (BUILTIN_TYPE(obj)) {
@@ -1423,9 +1418,18 @@ rb_complex_ivar_set(VALUE obj, ID id, VALUE val)
table = RCLASS_IV_HASH(obj);
break;
default:
- if (!rb_gen_ivtbl_get(obj, 0, (struct gen_ivtbl **)&table)) {
- table = st_init_numtable();
- st_insert(generic_ivtbl(obj, id, false), (st_data_t)obj, (st_data_t)table);
+ if (!rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
+ ivtbl = xmalloc(sizeof(struct gen_ivtbl));
+#if !SHAPE_IN_BASIC_FLAGS
+ ivtbl->shape_id = SHAPE_OBJ_TOO_COMPLEX;
+#endif
+ table = st_init_numtable_with_size(1);
+ ivtbl->as.complex.table = table;
+
+ st_insert(generic_ivtbl(obj, id, false), (st_data_t)obj, (st_data_t)ivtbl);
+ }
+ else {
+ table = ivtbl->as.complex.table;
}
}
@@ -1439,16 +1443,15 @@ rb_evict_ivars_to_hash(VALUE obj, rb_shape_t * shape)
{
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
- st_table * table = st_init_numtable_with_size(shape->next_iv_index);
+ 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);
- rb_shape_set_too_complex(obj);
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
-
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
+ rb_shape_set_too_complex(obj);
+
if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
xfree(ROBJECT(obj)->as.heap.ivptr);
}
@@ -1457,24 +1460,36 @@ rb_evict_ivars_to_hash(VALUE obj, rb_shape_t * shape)
break;
case T_CLASS:
case T_MODULE:
+ rb_shape_set_too_complex(obj);
+
xfree(RCLASS_IVPTR(obj));
RCLASS_SET_IV_HASH(obj, table);
break;
default:
RB_VM_LOCK_ENTER();
{
- struct st_table * gen_ivs = generic_ivtbl_no_ractor_check(obj);
- st_data_t ivtbl;
+ struct st_table *gen_ivs = generic_ivtbl_no_ractor_check(obj);
+ st_data_t old_ivtbl;
+ struct gen_ivtbl *ivtbl = NULL;
- // Free the old IV table
- if (st_delete(gen_ivs, &obj, &ivtbl))
- xfree((struct gen_ivtbl *)ivtbl);
+ if (st_delete(gen_ivs, &obj, &old_ivtbl)) {
+ ivtbl = (struct gen_ivtbl *)old_ivtbl;
+ }
+
+ ivtbl = xrealloc(ivtbl, sizeof(struct gen_ivtbl));
+ ivtbl->as.complex.table = table;
+#if SHAPE_IN_BASIC_FLAGS
+ rb_shape_set_too_complex(obj);
+#else
+ ivtbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
+#endif
- // Insert the hash table
- st_insert(gen_ivs, (st_data_t)obj, (st_data_t)table);
+ st_insert(gen_ivs, (st_data_t)obj, (st_data_t)ivtbl);
}
RB_VM_LOCK_LEAVE();
}
+
+ RUBY_ASSERT(rb_shape_obj_too_complex(obj));
}
static void
@@ -1501,9 +1516,7 @@ generic_ivar_set(VALUE obj, ID id, VALUE val)
index = shape->next_iv_index;
next_shape = rb_shape_get_next(shape, obj, id);
if (next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
- if (shape->next_iv_index > 0) {
- rb_evict_ivars_to_hash(obj, shape);
- }
+ rb_evict_ivars_to_hash(obj, shape);
rb_complex_ivar_set(obj, id, val);
rb_shape_set_shape(obj, next_shape);
FL_SET_RAW(obj, FL_EXIVAR);
@@ -1526,7 +1539,7 @@ generic_ivar_set(VALUE obj, ID id, VALUE val)
}
RB_VM_LOCK_LEAVE();
- ivup.ivtbl->ivptr[ivup.iv_index] = val;
+ ivup.ivtbl->as.shape.ivptr[ivup.iv_index] = val;
RB_OBJ_WRITTEN(obj, Qundef, val);
if (!found) {
@@ -1558,7 +1571,7 @@ rb_ensure_generic_iv_list_size(VALUE obj, rb_shape_t *shape, uint32_t newsize)
RB_VM_LOCK_ENTER();
{
- if (UNLIKELY(!gen_ivtbl_get_unlocked(obj, 0, &ivtbl) || newsize > ivtbl->numiv)) {
+ if (UNLIKELY(!gen_ivtbl_get_unlocked(obj, 0, &ivtbl) || newsize > ivtbl->as.shape.numiv)) {
struct ivar_update ivup = {
.iv_index = newsize - 1,
.max_index = newsize,
@@ -1829,7 +1842,7 @@ iterate_over_shapes_with_callback(rb_shape_t *shape, rb_ivar_foreach_callback_fu
iv_list = RCLASS_IVPTR(itr_data->obj);
break;
default:
- iv_list = itr_data->ivtbl->ivptr;
+ iv_list = itr_data->ivtbl->as.shape.ivptr;
break;
}
VALUE val = iv_list[shape->next_iv_index - 1];
@@ -1931,15 +1944,25 @@ rb_copy_generic_ivar(VALUE clone, VALUE obj)
}
if (rb_gen_ivtbl_get(obj, 0, &obj_ivtbl)) {
- if (gen_ivtbl_count(obj_ivtbl) == 0)
+ if (gen_ivtbl_count(obj, obj_ivtbl) == 0)
goto clear;
- new_ivtbl = gen_ivtbl_resize(0, obj_ivtbl->numiv);
FL_SET(clone, FL_EXIVAR);
- for (uint32_t i=0; i<obj_ivtbl->numiv; i++) {
- new_ivtbl->ivptr[i] = obj_ivtbl->ivptr[i];
- RB_OBJ_WRITTEN(clone, Qundef, &new_ivtbl[i]);
+ if (rb_shape_obj_too_complex(obj)) {
+ new_ivtbl = xmalloc(sizeof(struct gen_ivtbl));
+#if !SHAPE_IN_BASIC_FLAGS
+ new_ivtbl->shape_id = SHAPE_OBJ_TOO_COMPLEX;
+#endif
+ new_ivtbl->as.complex.table = st_copy(obj_ivtbl->as.complex.table);
+ }
+ else {
+ new_ivtbl = gen_ivtbl_resize(0, obj_ivtbl->as.shape.numiv);
+
+ for (uint32_t i=0; i<obj_ivtbl->as.shape.numiv; i++) {
+ new_ivtbl->as.shape.ivptr[i] = obj_ivtbl->as.shape.ivptr[i];
+ RB_OBJ_WRITTEN(clone, Qundef, &new_ivtbl[i]);
+ }
}
/*
@@ -2063,7 +2086,7 @@ rb_ivar_count(VALUE obj)
struct gen_ivtbl *ivtbl;
if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
- return gen_ivtbl_count(ivtbl);
+ return gen_ivtbl_count(obj, ivtbl);
}
}
break;