Refactor rb_obj_evacuate_ivs_to_hash_table
That function is a bit too low level to called from multiple places. It's always used in tandem with `rb_shape_set_too_complex` and both have to know how the object is laid out to update the `iv_ptr`. So instead we can provide two higher level function: - `rb_obj_copy_ivs_to_hash_table` to prepare a `st_table` from an arbitrary oject. - `rb_obj_convert_to_too_complex` to assign the new `st_table` to the old object, and safely free the old `iv_ptr`. Unfortunately both can't be combined into one, because `rb_obj_copy_ivar` need `rb_obj_copy_ivs_to_hash_table` to copy from one object to another.
This commit is contained in:
parent
498b086c37
commit
94c9f16663
@ -47,7 +47,8 @@ VALUE rb_mod_set_temporary_name(VALUE, VALUE);
|
|||||||
|
|
||||||
struct gen_ivtbl;
|
struct gen_ivtbl;
|
||||||
int rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl);
|
int rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl);
|
||||||
int rb_obj_evacuate_ivs_to_hash_table(ID key, VALUE val, st_data_t arg);
|
void rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table);
|
||||||
|
void rb_obj_convert_to_too_complex(VALUE obj, st_table *table);
|
||||||
void rb_evict_ivars_to_hash(VALUE obj);
|
void rb_evict_ivars_to_hash(VALUE obj);
|
||||||
|
|
||||||
RUBY_SYMBOL_EXPORT_BEGIN
|
RUBY_SYMBOL_EXPORT_BEGIN
|
||||||
|
14
object.c
14
object.c
@ -293,12 +293,10 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
|
|||||||
rb_shape_t * src_shape = rb_shape_get_shape(obj);
|
rb_shape_t * src_shape = rb_shape_get_shape(obj);
|
||||||
|
|
||||||
if (rb_shape_obj_too_complex(obj)) {
|
if (rb_shape_obj_too_complex(obj)) {
|
||||||
|
// obj is TOO_COMPLEX so we can copy its iv_hash
|
||||||
st_table * table = rb_st_init_numtable_with_size(rb_st_table_size(ROBJECT_IV_HASH(obj)));
|
st_table * table = rb_st_init_numtable_with_size(rb_st_table_size(ROBJECT_IV_HASH(obj)));
|
||||||
|
st_replace(table, ROBJECT_IV_HASH(obj));
|
||||||
rb_ivar_foreach(obj, rb_obj_evacuate_ivs_to_hash_table, (st_data_t)table);
|
rb_obj_convert_to_too_complex(dest, table);
|
||||||
rb_shape_set_too_complex(dest);
|
|
||||||
|
|
||||||
ROBJECT(dest)->as.heap.ivptr = (VALUE *)table;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -328,10 +326,8 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
|
|||||||
shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape);
|
shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape);
|
||||||
if (UNLIKELY(rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID)) {
|
if (UNLIKELY(rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID)) {
|
||||||
st_table * table = rb_st_init_numtable_with_size(src_num_ivs);
|
st_table * table = rb_st_init_numtable_with_size(src_num_ivs);
|
||||||
|
rb_obj_copy_ivs_to_hash_table(obj, table);
|
||||||
rb_ivar_foreach(obj, rb_obj_evacuate_ivs_to_hash_table, (st_data_t)table);
|
rb_obj_convert_to_too_complex(dest, table);
|
||||||
rb_shape_set_too_complex(dest);
|
|
||||||
ROBJECT(dest)->as.heap.ivptr = (VALUE *)table;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
7
shape.c
7
shape.c
@ -915,13 +915,6 @@ rb_shape_obj_too_complex(VALUE obj)
|
|||||||
return rb_shape_get_shape_id(obj) == OBJ_TOO_COMPLEX_SHAPE_ID;
|
return rb_shape_get_shape_id(obj) == OBJ_TOO_COMPLEX_SHAPE_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
rb_shape_set_too_complex(VALUE obj)
|
|
||||||
{
|
|
||||||
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
|
|
||||||
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
rb_shape_edges_count(rb_shape_t *shape)
|
rb_shape_edges_count(rb_shape_t *shape)
|
||||||
{
|
{
|
||||||
|
1
shape.h
1
shape.h
@ -226,7 +226,6 @@ rb_shape_t *rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_
|
|||||||
bool rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id);
|
bool rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id);
|
||||||
|
|
||||||
VALUE rb_obj_debug_shape(VALUE self, VALUE obj);
|
VALUE rb_obj_debug_shape(VALUE self, VALUE obj);
|
||||||
void rb_shape_set_too_complex(VALUE obj);
|
|
||||||
|
|
||||||
// For ext/objspace
|
// For ext/objspace
|
||||||
RUBY_SYMBOL_EXPORT_BEGIN
|
RUBY_SYMBOL_EXPORT_BEGIN
|
||||||
|
96
variable.c
96
variable.c
@ -1370,6 +1370,50 @@ rb_attr_delete(VALUE obj, ID id)
|
|||||||
return rb_ivar_delete(obj, id, Qnil);
|
return rb_ivar_delete(obj, id, Qnil);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_obj_convert_to_too_complex(VALUE obj, st_table *table)
|
||||||
|
{
|
||||||
|
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
|
||||||
|
|
||||||
|
VALUE *old_ivptr = NULL;
|
||||||
|
|
||||||
|
switch (BUILTIN_TYPE(obj)) {
|
||||||
|
case T_OBJECT:
|
||||||
|
if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
|
||||||
|
old_ivptr = ROBJECT_IVPTR(obj);
|
||||||
|
}
|
||||||
|
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
|
||||||
|
ROBJECT_SET_IV_HASH(obj, table);
|
||||||
|
break;
|
||||||
|
case T_CLASS:
|
||||||
|
case T_MODULE:
|
||||||
|
old_ivptr = RCLASS_IVPTR(obj);
|
||||||
|
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
|
||||||
|
RCLASS_SET_IV_HASH(obj, table);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
RB_VM_LOCK_ENTER();
|
||||||
|
{
|
||||||
|
struct st_table *gen_ivs = generic_ivtbl_no_ractor_check(obj);
|
||||||
|
st_lookup(gen_ivs, (st_data_t)&obj, (st_data_t *)&old_ivptr);
|
||||||
|
|
||||||
|
struct gen_ivtbl *ivtbl = xmalloc(sizeof(struct gen_ivtbl));
|
||||||
|
ivtbl->as.complex.table = table;
|
||||||
|
#if SHAPE_IN_BASIC_FLAGS
|
||||||
|
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old_ivptr) {
|
||||||
|
xfree(old_ivptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_evict_ivars_to_hash(VALUE obj)
|
rb_evict_ivars_to_hash(VALUE obj)
|
||||||
{
|
{
|
||||||
@ -1378,48 +1422,8 @@ rb_evict_ivars_to_hash(VALUE obj)
|
|||||||
st_table *table = st_init_numtable_with_size(rb_ivar_count(obj));
|
st_table *table = st_init_numtable_with_size(rb_ivar_count(obj));
|
||||||
|
|
||||||
// Evacuate all previous values from shape into id_table
|
// 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_obj_copy_ivs_to_hash_table(obj, table);
|
||||||
|
rb_obj_convert_to_too_complex(obj, table);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
ROBJECT_SET_IV_HASH(obj, table);
|
|
||||||
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 old_ivtbl;
|
|
||||||
struct gen_ivtbl *ivtbl = NULL;
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
st_insert(gen_ivs, (st_data_t)obj, (st_data_t)ivtbl);
|
|
||||||
}
|
|
||||||
RB_VM_LOCK_LEAVE();
|
|
||||||
}
|
|
||||||
|
|
||||||
RUBY_ASSERT(rb_shape_obj_too_complex(obj));
|
RUBY_ASSERT(rb_shape_obj_too_complex(obj));
|
||||||
}
|
}
|
||||||
@ -1637,12 +1641,18 @@ rb_ensure_iv_list_size(VALUE obj, uint32_t current_capacity, uint32_t new_capaci
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rb_obj_evacuate_ivs_to_hash_table(ID key, VALUE val, st_data_t arg)
|
rb_obj_copy_ivs_to_hash_table_i(ID key, VALUE val, st_data_t arg)
|
||||||
{
|
{
|
||||||
st_insert((st_table *)arg, (st_data_t)key, (st_data_t)val);
|
st_insert((st_table *)arg, (st_data_t)key, (st_data_t)val);
|
||||||
return ST_CONTINUE;
|
return ST_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table)
|
||||||
|
{
|
||||||
|
rb_ivar_foreach(obj, rb_obj_copy_ivs_to_hash_table_i, (st_data_t)table);
|
||||||
|
}
|
||||||
|
|
||||||
static VALUE *
|
static VALUE *
|
||||||
obj_ivar_set_shape_ivptr(VALUE obj, void *_data)
|
obj_ivar_set_shape_ivptr(VALUE obj, void *_data)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user