summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gc.c10
-rw-r--r--include/ruby/st.h2
-rw-r--r--object.c2
-rw-r--r--ractor.c43
-rw-r--r--shape.h6
-rw-r--r--st.c6
-rw-r--r--test/ruby/test_shapes.rb21
-rw-r--r--variable.c28
-rw-r--r--vm_insnhelper.c2
9 files changed, 74 insertions, 46 deletions
diff --git a/gc.c b/gc.c
index 06a4bacfb8..af789bc9ee 100644
--- a/gc.c
+++ b/gc.c
@@ -3512,7 +3512,7 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
case T_OBJECT:
if (rb_shape_obj_too_complex(obj)) {
RB_DEBUG_COUNTER_INC(obj_obj_too_complex);
- rb_id_table_free(ROBJECT_IV_HASH(obj));
+ st_free_table(ROBJECT_IV_HASH(obj));
}
else if (RANY(obj)->as.basic.flags & ROBJECT_EMBED) {
RB_DEBUG_COUNTER_INC(obj_obj_embed);
@@ -4910,7 +4910,7 @@ obj_memsize_of(VALUE obj, int use_all_types)
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
if (rb_shape_obj_too_complex(obj)) {
- size += rb_id_table_memsize(ROBJECT_IV_HASH(obj));
+ size += rb_st_memsize(ROBJECT_IV_HASH(obj));
}
else if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
size += ROBJECT_IV_CAPACITY(obj) * sizeof(VALUE);
@@ -7400,7 +7400,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
{
rb_shape_t *shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj));
if (rb_shape_obj_too_complex(obj)) {
- mark_m_tbl(objspace, ROBJECT_IV_HASH(obj));
+ mark_tbl_no_pin(objspace, ROBJECT_IV_HASH(obj));
}
else {
const VALUE * const ptr = ROBJECT_IVPTR(obj);
@@ -10117,15 +10117,13 @@ gc_ref_update_array(rb_objspace_t * objspace, VALUE v)
}
}
-static void update_m_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl);
-
static void
gc_ref_update_object(rb_objspace_t *objspace, VALUE v)
{
VALUE *ptr = ROBJECT_IVPTR(v);
if (rb_shape_obj_too_complex(v)) {
- update_m_tbl(objspace, ROBJECT_IV_HASH(v));
+ rb_gc_update_tbl_refs(ROBJECT_IV_HASH(v));
return;
}
diff --git a/include/ruby/st.h b/include/ruby/st.h
index 1e4bb80686..f35ab43603 100644
--- a/include/ruby/st.h
+++ b/include/ruby/st.h
@@ -98,6 +98,8 @@ struct st_table {
enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE, ST_CHECK, ST_REPLACE};
+size_t rb_st_table_size(const struct st_table *tbl);
+#define st_table_size rb_st_table_size
st_table *rb_st_init_table(const struct st_hash_type *);
#define st_init_table rb_st_init_table
st_table *rb_st_init_table_with_size(const struct st_hash_type *, st_index_t);
diff --git a/object.c b/object.c
index 983fde9b09..24cbdd516f 100644
--- a/object.c
+++ b/object.c
@@ -281,7 +281,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
rb_shape_t * src_shape = rb_shape_get_shape(obj);
if (rb_shape_id(src_shape) == OBJ_TOO_COMPLEX_SHAPE_ID) {
- struct rb_id_table * table = rb_id_table_create(rb_id_table_size(ROBJECT_IV_HASH(obj)));
+ st_table * table = rb_st_init_numtable_with_size(rb_st_table_size(ROBJECT_IV_HASH(obj)));
rb_ivar_foreach(obj, rb_obj_evacuate_ivs_to_hash_table, (st_data_t)table);
rb_shape_set_too_complex(dest);
diff --git a/ractor.c b/ractor.c
index dbaa5aab9a..b56f020586 100644
--- a/ractor.c
+++ b/ractor.c
@@ -2649,17 +2649,17 @@ obj_hash_traverse_i(VALUE key, VALUE val, VALUE ptr)
return ST_CONTINUE;
}
-static enum rb_id_table_iterator_result
-obj_hash_iv_traverse_i(VALUE val, void *ptr)
+static int
+obj_hash_iv_traverse_i(st_data_t key, st_data_t val, st_data_t ptr)
{
struct obj_traverse_callback_data *d = (struct obj_traverse_callback_data *)ptr;
- if (obj_traverse_i(val, d->data)) {
+ if (obj_traverse_i((VALUE)val, d->data)) {
d->stop = true;
- return ID_TABLE_STOP;
+ return ST_STOP;
}
- return ID_TABLE_CONTINUE;
+ return ST_CONTINUE;
}
static void
@@ -2725,7 +2725,7 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
.stop = false,
.data = data,
};
- rb_id_table_foreach_values(ROBJECT_IV_HASH(obj), obj_hash_iv_traverse_i, &d);
+ rb_st_foreach(ROBJECT_IV_HASH(obj), obj_hash_iv_traverse_i, (st_data_t)&d);
if (d.stop) return 1;
}
else {
@@ -3080,28 +3080,28 @@ obj_hash_traverse_replace_i(st_data_t *key, st_data_t *val, st_data_t ptr, int e
return ST_CONTINUE;
}
-static enum rb_id_table_iterator_result
-obj_iv_hash_traverse_replace_foreach_i(VALUE val, void *data)
+static int
+obj_iv_hash_traverse_replace_foreach_i(st_data_t _key, st_data_t _val, st_data_t _data, int _x)
{
- return ID_TABLE_REPLACE;
+ return ST_REPLACE;
}
-static enum rb_id_table_iterator_result
-obj_iv_hash_traverse_replace_i(VALUE *val, void *ptr, int exists)
+static int
+obj_iv_hash_traverse_replace_i(st_data_t * _key, st_data_t * val, st_data_t ptr, int exists)
{
struct obj_traverse_replace_callback_data *d = (struct obj_traverse_replace_callback_data *)ptr;
struct obj_traverse_replace_data *data = d->data;
- if (obj_traverse_replace_i(*val, data)) {
+ if (obj_traverse_replace_i(*(VALUE *)val, data)) {
d->stop = true;
- return ID_TABLE_STOP;
+ return ST_STOP;
}
- else if (*val != data->replacement) {
- VALUE v = *val = data->replacement;
+ else if (*(VALUE *)val != data->replacement) {
+ VALUE v = *(VALUE *)val = data->replacement;
RB_OBJ_WRITTEN(d->src, Qundef, v);
}
- return ID_TABLE_CONTINUE;
+ return ST_CONTINUE;
}
static struct st_table *
@@ -3205,16 +3205,17 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_OBJECT:
{
if (rb_shape_obj_too_complex(obj)) {
- struct rb_id_table * table = ROBJECT_IV_HASH(obj);
+ st_table * table = ROBJECT_IV_HASH(obj);
struct obj_traverse_replace_callback_data d = {
.stop = false,
.data = data,
.src = obj,
};
- rb_id_table_foreach_values_with_replace(table,
- obj_iv_hash_traverse_replace_foreach_i,
- obj_iv_hash_traverse_replace_i,
- (void *)&d);
+ rb_st_foreach_with_replace(
+ table,
+ obj_iv_hash_traverse_replace_foreach_i,
+ obj_iv_hash_traverse_replace_i,
+ (st_data_t)&d);
}
else {
#if USE_TRANSIENT_HEAP
diff --git a/shape.h b/shape.h
index 41d0b1f131..b635ddf8b7 100644
--- a/shape.h
+++ b/shape.h
@@ -156,12 +156,12 @@ ROBJECT_IV_CAPACITY(VALUE obj)
return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->capacity;
}
-static inline struct rb_id_table *
+static inline st_table *
ROBJECT_IV_HASH(VALUE obj)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID);
- return (struct rb_id_table *)ROBJECT(obj)->as.heap.ivptr;
+ return (st_table *)ROBJECT(obj)->as.heap.ivptr;
}
static inline void
@@ -178,7 +178,7 @@ static inline uint32_t
ROBJECT_IV_COUNT(VALUE obj)
{
if (ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID) {
- return (uint32_t)rb_id_table_size(ROBJECT_IV_HASH(obj));
+ return (uint32_t)rb_st_table_size(ROBJECT_IV_HASH(obj));
}
else {
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
diff --git a/st.c b/st.c
index b18b9d6cb9..411237d13b 100644
--- a/st.c
+++ b/st.c
@@ -569,6 +569,12 @@ st_init_table_with_size(const struct st_hash_type *type, st_index_t size)
return tab;
}
+size_t
+st_table_size(const struct st_table *tbl)
+{
+ return tbl->num_entries;
+}
+
/* Create and return table with TYPE which can hold a minimal number
of entries (see comments for get_power2). */
st_table *
diff --git a/test/ruby/test_shapes.rb b/test/ruby/test_shapes.rb
index b1a2ba2f1b..9525167d65 100644
--- a/test/ruby/test_shapes.rb
+++ b/test/ruby/test_shapes.rb
@@ -3,6 +3,17 @@ require 'test/unit'
# These test the functionality of object shapes
class TestShapes < Test::Unit::TestCase
+ class IVOrder
+ def expected_ivs
+ %w{ @a @b @c @d @e @f @g @h @i @j @k }
+ end
+
+ def set_ivs
+ expected_ivs.each { instance_variable_set(_1, 1) }
+ self
+ end
+ end
+
class ShapeOrder
def initialize
@b = :b # 5 => 6
@@ -80,6 +91,16 @@ class TestShapes < Test::Unit::TestCase
refute_equal(shape1.id, shape2.id)
end
+ def test_iv_order_correct_on_complex_objects
+ (RubyVM::Shape::SHAPE_MAX_VARIATIONS + 1).times {
+ IVOrder.new.instance_variable_set("@a#{_1}", 1)
+ }
+
+ obj = IVOrder.new
+ iv_list = obj.set_ivs.instance_variables
+ assert_equal obj.expected_ivs, iv_list.map(&:to_s)
+ end
+
def test_too_complex
ensure_complex
diff --git a/variable.c b/variable.c
index 30b786335e..90fa8760a0 100644
--- a/variable.c
+++ b/variable.c
@@ -1167,9 +1167,9 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
shape_id = ROBJECT_SHAPE_ID(obj);
#endif
if (rb_shape_obj_too_complex(obj)) {
- struct rb_id_table * iv_table = ROBJECT_IV_HASH(obj);
+ st_table * iv_table = ROBJECT_IV_HASH(obj);
VALUE val;
- if (rb_id_table_lookup(iv_table, id, &val)) {
+ if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) {
return val;
}
else {
@@ -1426,7 +1426,7 @@ rb_grow_iv_list(VALUE obj)
int
rb_obj_evacuate_ivs_to_hash_table(ID key, VALUE val, st_data_t arg)
{
- rb_id_table_insert((struct rb_id_table *)arg, key, val);
+ st_insert((st_table *)arg, (st_data_t)key, (st_data_t)val);
return ST_CONTINUE;
}
@@ -1439,8 +1439,8 @@ rb_obj_ivar_set(VALUE obj, ID id, VALUE val)
uint32_t num_iv = shape->capacity;
if (rb_shape_obj_too_complex(obj)) {
- struct rb_id_table * table = ROBJECT_IV_HASH(obj);
- rb_id_table_insert(table, id, val);
+ 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;
}
@@ -1463,13 +1463,13 @@ rb_obj_ivar_set(VALUE obj, ID id, VALUE val)
rb_shape_t *next_shape = rb_shape_get_next(shape, obj, id);
if (next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
- struct rb_id_table * table = rb_id_table_create(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);
// Insert new value too
- rb_id_table_insert(table, id, val);
+ st_insert(table, (st_data_t)id, (st_data_t)val);
RB_OBJ_WRITTEN(obj, Qundef, val);
rb_shape_set_too_complex(obj);
@@ -1618,7 +1618,7 @@ rb_ivar_defined(VALUE obj, ID id)
if (SPECIAL_CONST_P(obj)) return Qfalse;
if (rb_shape_obj_too_complex(obj)) {
VALUE idx;
- if (!rb_id_table_lookup(ROBJECT_IV_HASH(obj), id, &idx)) {
+ if (!rb_st_lookup(ROBJECT_IV_HASH(obj), id, &idx)) {
return Qfalse;
}
@@ -1677,12 +1677,12 @@ iterate_over_shapes_with_callback(rb_shape_t *shape, rb_ivar_foreach_callback_fu
}
}
-static enum rb_id_table_iterator_result
-each_hash_iv(ID id, VALUE val, void *data)
+static int
+each_hash_iv(st_data_t id, st_data_t val, st_data_t data)
{
struct iv_itr_data * itr_data = (struct iv_itr_data *)data;
rb_ivar_foreach_callback_func *callback = itr_data->func;
- return callback(id, val, itr_data->arg);
+ return callback((ID)id, (VALUE)val, itr_data->arg);
}
static void
@@ -1694,7 +1694,7 @@ obj_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
itr_data.arg = arg;
itr_data.func = func;
if (rb_shape_obj_too_complex(obj)) {
- rb_id_table_foreach(ROBJECT_IV_HASH(obj), each_hash_iv, &itr_data);
+ rb_st_foreach(ROBJECT_IV_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
}
else {
iterate_over_shapes_with_callback(shape, func, &itr_data);
@@ -1988,8 +1988,8 @@ rb_obj_remove_instance_variable(VALUE obj, VALUE name)
break;
case T_OBJECT: {
if (rb_shape_obj_too_complex(obj)) {
- if (rb_id_table_lookup(ROBJECT_IV_HASH(obj), id, &val)) {
- rb_id_table_delete(ROBJECT_IV_HASH(obj), id);
+ if (rb_st_lookup(ROBJECT_IV_HASH(obj), (st_data_t)id, (st_data_t *)&val)) {
+ rb_st_delete(ROBJECT_IV_HASH(obj), (st_data_t *)&id, 0);
}
}
else {
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 674308c90c..e2cab6054a 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1259,7 +1259,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id);
if (shape_id == OBJ_TOO_COMPLEX_SHAPE_ID) {
- if (!rb_id_table_lookup(ROBJECT_IV_HASH(obj), id, &val)) {
+ if (!st_lookup(ROBJECT_IV_HASH(obj), id, &val)) {
val = default_value;
}
}