@@ -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-
17921784static int
17931785object_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
18791871static 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
18861904static 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
18941939static 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 ) {
0 commit comments