Skip to content

Commit 2e5f756

Browse files
committed
WIP
1 parent 548b162 commit 2e5f756

5 files changed

Lines changed: 100 additions & 37 deletions

File tree

gc.c

Lines changed: 81 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,14 +1781,6 @@ generate_next_object_id(void)
17811781
#endif
17821782
}
17831783

1784-
void
1785-
rb_gc_obj_id_moved(VALUE obj)
1786-
{
1787-
if (UNLIKELY(id2ref_tbl)) {
1788-
st_insert(id2ref_tbl, (st_data_t)rb_obj_id(obj), (st_data_t)obj);
1789-
}
1790-
}
1791-
17921784
static int
17931785
object_id_cmp(st_data_t x, st_data_t y)
17941786
{
@@ -1877,18 +1869,71 @@ obj_to_id_tbl_memsize(const void *data)
18771869
}
18781870

18791871
static void
1880-
obj_to_id_tbl_compact(void *data)
1872+
obj_to_id_tbl_free(void *data)
18811873
{
1882-
st_table *table = (st_table *)data;
1883-
gc_update_table_refs(table);
1874+
if (obj_to_id_tbl) {
1875+
st_free_table(obj_to_id_tbl);
1876+
obj_to_id_tbl = NULL; // clear global ref
1877+
}
1878+
}
1879+
1880+
struct obj_to_id_tbl_any_moved_p_args {
1881+
bool need_rebuild;
1882+
};
1883+
1884+
static int
1885+
obj_to_id_tbl_any_moved_p_i(st_data_t key, st_data_t value, st_data_t data)
1886+
{
1887+
struct obj_to_id_tbl_any_moved_p_args *args = (struct obj_to_id_tbl_any_moved_p_args *)data;
1888+
1889+
if (rb_gc_location(key) != key || (!FIXNUM_P(value) && rb_gc_location(value) != value)) {
1890+
args->need_rebuild = true;
1891+
return ST_STOP;
1892+
}
1893+
return ST_CONTINUE;
1894+
}
1895+
1896+
static int
1897+
obj_to_id_rebuild_table_i(st_data_t key, st_data_t value, st_data_t data)
1898+
{
1899+
st_table *new_table = (st_table *)data;
1900+
st_insert(new_table, rb_gc_location(key), rb_gc_location(value));
1901+
return ST_CONTINUE;
18841902
}
18851903

18861904
static void
1887-
obj_to_id_tbl_free(void *data)
1905+
obj_to_id_tbl_compact(void *data)
18881906
{
1889-
obj_to_id_tbl = NULL; // clear global ref
1890-
st_table *table = (st_table *)data;
1891-
st_free_table(table);
1907+
if (obj_to_id_tbl) {
1908+
struct obj_to_id_tbl_any_moved_p_args any_moved_args = { 0 };
1909+
st_foreach(obj_to_id_tbl, obj_to_id_tbl_any_moved_p_i, (st_data_t)&any_moved_args);
1910+
1911+
if (any_moved_args.need_rebuild) {
1912+
st_table *new_table;
1913+
DURING_GC_COULD_MALLOC_REGION_START();
1914+
{
1915+
new_table = st_init_numtable_with_size(st_table_size(obj_to_id_tbl));
1916+
}
1917+
DURING_GC_COULD_MALLOC_REGION_END();
1918+
st_foreach(obj_to_id_tbl, obj_to_id_rebuild_table_i, (st_data_t)new_table);
1919+
st_free_table(obj_to_id_tbl);
1920+
obj_to_id_tbl = new_table;
1921+
}
1922+
}
1923+
}
1924+
1925+
void
1926+
rb_gc_obj_id_moved(VALUE old_obj, VALUE obj)
1927+
{
1928+
if (UNLIKELY(id2ref_tbl)) {
1929+
st_insert(id2ref_tbl, (st_data_t)rb_obj_id(obj), (st_data_t)obj);
1930+
}
1931+
1932+
if (rb_shape_obj_has_id(obj) == SHAPE_ID_FL_OBJ_ID_EXTERNAL) {
1933+
VALUE object_id;
1934+
st_delete(obj_to_id_tbl, &old_obj, &object_id);
1935+
st_insert(obj_to_id_tbl, obj, object_id);
1936+
}
18921937
}
18931938

18941939
static const rb_data_type_t obj_to_id_tbl_type = {
@@ -1937,20 +1982,33 @@ object_id_get(VALUE obj, shape_id_t shape_id)
19371982
else {
19381983
id = rb_obj_field_get(obj, rb_shape_object_id_inline(shape_id));
19391984
}
1985+
1986+
#if RUBY_DEBUG
1987+
if (!(FIXNUM_P(id) || RB_TYPE_P(id, T_BIGNUM))) {
1988+
rb_p(obj);
1989+
rb_bug("Object's shape includes object_id, but it's missing %s", rb_obj_info(obj));
1990+
}
1991+
#endif
1992+
19401993
break;
19411994
case SHAPE_EXTERNAL_OBJ_ID:
1942-
RUBY_ASSERT(obj_to_id_tbl);
1943-
st_lookup(obj_to_id_tbl, obj, &id);
1944-
break;
1945-
}
1995+
{
1996+
RUBY_ASSERT(obj_to_id_tbl);
1997+
unsigned int lock_lev = RB_GC_VM_LOCK();
1998+
st_lookup(obj_to_id_tbl, obj, &id);
19461999

19472000
#if RUBY_DEBUG
19482001
if (!(FIXNUM_P(id) || RB_TYPE_P(id, T_BIGNUM))) {
19492002
rb_p(obj);
1950-
rb_bug("Object's shape includes object_id, but it's missing %s", rb_obj_info(obj));
2003+
rb_bug("Object %s/%"PRIxVALUE" shape includes external object_id, but it's missing in obj_to_id_tbl", rb_obj_info(obj), obj);
19512004
}
19522005
#endif
19532006

2007+
RB_GC_VM_UNLOCK(lock_lev);
2008+
}
2009+
break;
2010+
}
2011+
19542012
return id;
19552013
}
19562014

@@ -1968,9 +2026,9 @@ object_id0(VALUE obj, bool shareable)
19682026

19692027
attr_index_t capacity = RSHAPE_CAPACITY(shape_id);
19702028
attr_index_t free_capacity = capacity - RSHAPE_LEN(shape_id);
1971-
if (shareable && capacity && !free_capacity) {
1972-
// The object is shared and has no free capacity, we can't
1973-
// safely store the object_id inline.
2029+
if (shareable && RB_TYPE_P(obj, T_OBJECT) && capacity && !free_capacity) {
2030+
// If the object was shared and has no free capacity, we can't safely store the object_id inline.
2031+
// This is only a problem for T_OBJECT, given other types have external fields and can do RCU.
19742032
shape_id_t next_shape_id = rb_shape_transition_object_id_external(obj);
19752033
if (RB_UNLIKELY(!obj_to_id_tbl)) {
19762034
obj_to_id_tbl = st_init_numtable();
@@ -4236,17 +4294,6 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
42364294
}
42374295
break;
42384296
}
4239-
case RB_GC_VM_OBJ_TO_ID_TABLE: {
4240-
if (obj_to_id_tbl) {
4241-
st_foreach_with_replace(
4242-
obj_to_id_tbl,
4243-
vm_weak_table_foreach_weak_key,
4244-
vm_weak_table_foreach_update_weak_key,
4245-
(st_data_t)&foreach_data
4246-
);
4247-
}
4248-
break;
4249-
}
42504297
case RB_GC_VM_GENERIC_FIELDS_TABLE: {
42514298
st_table *generic_fields_tbl = rb_generic_fields_tbl_get();
42524299
if (generic_fields_tbl) {

gc/gc.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ enum rb_gc_vm_weak_tables {
2929
RB_GC_VM_OVERLOADED_CME_TABLE,
3030
RB_GC_VM_GLOBAL_SYMBOLS_TABLE,
3131
RB_GC_VM_ID2REF_TABLE,
32-
RB_GC_VM_OBJ_TO_ID_TABLE,
3332
RB_GC_VM_GENERIC_FIELDS_TABLE,
3433
RB_GC_VM_FROZEN_STRINGS_TABLE,
3534
RB_GC_VM_CC_REFINEMENT_TABLE,

internal/gc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ RUBY_ATTR_MALLOC void *rb_xcalloc_mul_add_mul(size_t, size_t, size_t, size_t);
201201
static inline void *ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2));
202202
static inline void *ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2, 3));
203203
static inline void ruby_sized_xfree_inlined(void *ptr, size_t size);
204-
void rb_gc_obj_id_moved(VALUE obj);
204+
void rb_gc_obj_id_moved(VALUE old_obj, VALUE obj);
205205

206206
void *rb_gc_ractor_cache_alloc(rb_ractor_t *ractor);
207207
void rb_gc_ractor_cache_free(void *cache);

ractor.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1866,7 +1866,7 @@ move_leave(VALUE obj, struct obj_traverse_replace_data *data)
18661866

18671867
void rb_replace_generic_ivar(VALUE clone, VALUE obj); // variable.c
18681868

1869-
rb_gc_obj_id_moved(data->replacement);
1869+
rb_gc_obj_id_moved(obj, data->replacement);
18701870

18711871
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
18721872
rb_replace_generic_ivar(data->replacement, obj);

test/ruby/test_object_id.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,23 @@ def initialize
227227
end;
228228
end
229229

230+
def test_external_object_id_ractor_move
231+
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
232+
begin;
233+
Warning[:experimental] = false
234+
class MyClass
235+
attr_reader :a, :b, :c
236+
def initialize
237+
@a = @b = @c = nil
238+
end
239+
end
240+
obj = Ractor.make_shareable(MyClass.new)
241+
object_id = obj.object_id
242+
obj = Ractor.new { Ractor.receive }.send(obj, move: true).value
243+
assert_equal object_id, obj.object_id
244+
end;
245+
end
246+
230247
def test_object_id_race_free_with_stress_compact
231248
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
232249
begin;

0 commit comments

Comments
 (0)