Add ST table to gen_ivtbl for complex shapes
On 32-bit systems, we must store the shape ID in the gen_ivtbl to not lose the shape. If we directly store the ST table into the generic ivar table, then we lose the shape. This makes it impossible to determine the shape of the object and whether it is too complex or not.
This commit is contained in:
parent
1c45124c49
commit
e2d950733e
10
ractor.c
10
ractor.c
@ -2758,8 +2758,8 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
|
||||
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
|
||||
for (uint32_t i = 0; i < ivtbl->numiv; i++) {
|
||||
VALUE val = ivtbl->ivptr[i];
|
||||
for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
|
||||
VALUE val = ivtbl->as.shape.ivptr[i];
|
||||
if (!UNDEF_P(val) && obj_traverse_i(val, data)) return 1;
|
||||
}
|
||||
}
|
||||
@ -3229,9 +3229,9 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
|
||||
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
|
||||
for (uint32_t i = 0; i < ivtbl->numiv; i++) {
|
||||
if (!UNDEF_P(ivtbl->ivptr[i])) {
|
||||
CHECK_AND_REPLACE(ivtbl->ivptr[i]);
|
||||
for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
|
||||
if (!UNDEF_P(ivtbl->as.shape.ivptr[i])) {
|
||||
CHECK_AND_REPLACE(ivtbl->as.shape.ivptr[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
4
shape.c
4
shape.c
@ -539,7 +539,7 @@ move_iv(VALUE obj, ID id, attr_index_t from, attr_index_t to)
|
||||
default: {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
rb_gen_ivtbl_get(obj, id, &ivtbl);
|
||||
ivtbl->ivptr[to] = ivtbl->ivptr[from];
|
||||
ivtbl->as.shape.ivptr[to] = ivtbl->as.shape.ivptr[from];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -570,7 +570,7 @@ remove_shape_recursive(VALUE obj, ID id, rb_shape_t * shape, VALUE * removed)
|
||||
default: {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
rb_gen_ivtbl_get(obj, id, &ivtbl);
|
||||
*removed = ivtbl->ivptr[index];
|
||||
*removed = ivtbl->as.shape.ivptr[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
177
variable.c
177
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;
|
||||
|
||||
if (st_delete(generic_ivtbl_no_ractor_check(obj), &key, &ivtbl))
|
||||
xfree((struct gen_ivtbl *)ivtbl);
|
||||
bool too_complex = rb_shape_obj_too_complex(obj);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Insert the hash table
|
||||
st_insert(gen_ivs, (st_data_t)obj, (st_data_t)table);
|
||||
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
|
||||
|
||||
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;
|
||||
|
11
variable.h
11
variable.h
@ -16,8 +16,15 @@ struct gen_ivtbl {
|
||||
#if !SHAPE_IN_BASIC_FLAGS
|
||||
uint16_t shape_id;
|
||||
#endif
|
||||
uint32_t numiv;
|
||||
VALUE ivptr[FLEX_ARY_LEN];
|
||||
union {
|
||||
struct {
|
||||
uint32_t numiv;
|
||||
VALUE ivptr[1];
|
||||
} shape;
|
||||
struct {
|
||||
st_table *table;
|
||||
} complex;
|
||||
} as;
|
||||
};
|
||||
|
||||
int rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **);
|
||||
|
@ -1227,7 +1227,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
|
||||
#if !SHAPE_IN_BASIC_FLAGS
|
||||
shape_id = ivtbl->shape_id;
|
||||
#endif
|
||||
ivar_list = ivtbl->ivptr;
|
||||
ivar_list = ivtbl->as.shape.ivptr;
|
||||
}
|
||||
else {
|
||||
return default_value;
|
||||
@ -1456,7 +1456,7 @@ vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_i
|
||||
return Qundef;
|
||||
}
|
||||
|
||||
VALUE *ptr = ivtbl->ivptr;
|
||||
VALUE *ptr = ivtbl->as.shape.ivptr;
|
||||
|
||||
RB_OBJ_WRITE(obj, &ptr[index], val);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user