@@ -1197,6 +1197,29 @@ rb_generic_fields_tbl_get(void)
11971197 return generic_fields_tbl_ ;
11981198}
11991199
1200+ static inline VALUE
1201+ generic_fields_lookup (VALUE obj , ID id , bool force_check_ractor )
1202+ {
1203+ VALUE fields_obj = Qfalse ;
1204+ RB_VM_LOCKING () {
1205+ st_table * generic_tbl = generic_fields_tbl (obj , id , false);
1206+ st_lookup (generic_tbl , obj , (st_data_t * )& fields_obj );
1207+ }
1208+ return fields_obj ;
1209+ }
1210+
1211+ static inline void
1212+ generic_fields_insert (VALUE obj , VALUE fields_obj )
1213+ {
1214+ RUBY_ASSERT (IMEMO_TYPE_P (fields_obj , imemo_fields ));
1215+
1216+ RB_VM_LOCKING () {
1217+ st_table * generic_tbl = generic_fields_tbl_no_ractor_check (obj );
1218+ st_insert (generic_tbl , obj , fields_obj );
1219+ }
1220+ RB_OBJ_WRITTEN (obj , Qundef , fields_obj );
1221+ }
1222+
12001223int
12011224rb_gen_fields_tbl_get (VALUE obj , ID id , VALUE * fields_obj )
12021225{
@@ -1566,6 +1589,8 @@ rb_attr_delete(VALUE obj, ID id)
15661589 return rb_ivar_delete (obj , id , Qnil );
15671590}
15681591
1592+ static inline void generic_update_fields_obj (VALUE obj , VALUE fields_obj , const VALUE original_fields_obj );
1593+
15691594static shape_id_t
15701595obj_transition_too_complex (VALUE obj , st_table * table )
15711596{
@@ -1599,12 +1624,11 @@ obj_transition_too_complex(VALUE obj, st_table *table)
15991624 VALUE fields_obj = rb_imemo_fields_new_complex_tbl (rb_obj_class (obj ), table );
16001625 RBASIC_SET_SHAPE_ID (fields_obj , shape_id );
16011626
1602- struct st_table * gen_fields_tbl = generic_fields_tbl_no_ractor_check (obj );
16031627 RB_VM_LOCKING () {
1604- st_insert (gen_fields_tbl , (st_data_t )obj , (st_data_t )fields_obj );
1628+ const VALUE original_fields_obj = generic_fields_lookup (obj , 0 , false);
1629+ generic_update_fields_obj (obj , fields_obj , original_fields_obj );
16051630 }
16061631 RBASIC_SET_SHAPE_ID (obj , shape_id );
1607- RB_OBJ_WRITTEN (obj , Qundef , fields_obj );
16081632 }
16091633 }
16101634
@@ -1758,17 +1782,25 @@ general_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val, void *data,
17581782 }
17591783}
17601784
1785+ static inline void
1786+ generic_update_fields_obj (VALUE obj , VALUE fields_obj , const VALUE original_fields_obj )
1787+ {
1788+ if (fields_obj != original_fields_obj ) {
1789+ if (original_fields_obj ) {
1790+ // Clear root shape to avoid triggering cleanup such as free_object_id.
1791+ RBASIC_SET_SHAPE_ID (original_fields_obj , ROOT_SHAPE_ID );
1792+ }
1793+
1794+ generic_fields_insert (obj , fields_obj );
1795+ }
1796+ }
1797+
17611798static void
17621799generic_ivar_set (VALUE obj , ID id , VALUE val )
17631800{
1764- VALUE fields_obj = 0 ;
1765- st_table * generic_tbl ;
17661801 bool existing = true;
17671802
1768- RB_VM_LOCKING () {
1769- generic_tbl = generic_fields_tbl (obj , id , false);
1770- st_lookup (generic_tbl , obj , (st_data_t * )& fields_obj );
1771- }
1803+ VALUE fields_obj = generic_fields_lookup (obj , id , false);
17721804
17731805 const VALUE original_fields_obj = fields_obj ;
17741806 if (!fields_obj ) {
@@ -1831,17 +1863,7 @@ generic_ivar_set(VALUE obj, ID id, VALUE val)
18311863 RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
18321864 }
18331865
1834- if (fields_obj != original_fields_obj ) {
1835- RB_VM_LOCKING () {
1836- st_insert (generic_tbl , obj , fields_obj );
1837- }
1838- RB_OBJ_WRITTEN (obj , original_fields_obj , fields_obj );
1839-
1840- if (original_fields_obj ) {
1841- // Clear root shape to avoid triggering cleanup such as free_object_id.
1842- RBASIC_SET_SHAPE_ID (original_fields_obj , ROOT_SHAPE_ID );
1843- }
1844- }
1866+ generic_update_fields_obj (obj , fields_obj , original_fields_obj );
18451867
18461868 if (!existing ) {
18471869 RBASIC_SET_SHAPE_ID (obj , next_shape_id );
@@ -1857,17 +1879,8 @@ generic_ivar_set(VALUE obj, ID id, VALUE val)
18571879 existing = st_insert (table , (st_data_t )id , (st_data_t )val );
18581880 RB_OBJ_WRITTEN (fields_obj , Qundef , val );
18591881
1860- if (fields_obj != original_fields_obj ) {
1861- RB_VM_LOCKING () {
1862- st_insert (generic_tbl , obj , fields_obj );
1863- }
1864- RB_OBJ_WRITTEN (obj , original_fields_obj , fields_obj );
1882+ generic_update_fields_obj (obj , fields_obj , original_fields_obj );
18651883
1866- if (original_fields_obj ) {
1867- // Clear root shape to avoid triggering cleanup such as free_object_id.
1868- RBASIC_SET_SHAPE_ID (original_fields_obj , ROOT_SHAPE_ID );
1869- }
1870- }
18711884 if (!existing ) {
18721885 RBASIC_SET_SHAPE_ID (obj , next_shape_id );
18731886 }
@@ -1881,15 +1894,9 @@ generic_ivar_set(VALUE obj, ID id, VALUE val)
18811894static void
18821895generic_field_set (VALUE obj , shape_id_t target_shape_id , VALUE val )
18831896{
1884- VALUE fields_obj = 0 ;
1885- st_table * generic_tbl ;
18861897 bool existing = true;
18871898
1888- RB_VM_LOCKING () {
1889- generic_tbl = generic_fields_tbl (obj , RSHAPE_EDGE_NAME (target_shape_id ), false);
1890- st_lookup (generic_tbl , obj , (st_data_t * )& fields_obj );
1891- }
1892-
1899+ VALUE fields_obj = generic_fields_lookup (obj , RSHAPE_EDGE_NAME (target_shape_id ), false);
18931900 const VALUE original_fields_obj = fields_obj ;
18941901
18951902 shape_id_t current_shape_id = fields_obj ? RBASIC_SHAPE_ID (fields_obj ) : ROOT_SHAPE_ID ;
@@ -1908,10 +1915,10 @@ generic_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val)
19081915 existing = false;
19091916 st_table * table = rb_imemo_fields_complex_tbl (fields_obj );
19101917
1911- RBASIC_SET_SHAPE_ID (fields_obj , target_shape_id );
19121918 RUBY_ASSERT (RSHAPE_EDGE_NAME (target_shape_id ));
19131919 st_insert (table , (st_data_t )RSHAPE_EDGE_NAME (target_shape_id ), (st_data_t )val );
19141920 RB_OBJ_WRITTEN (fields_obj , Qundef , val );
1921+ RBASIC_SET_SHAPE_ID (fields_obj , target_shape_id );
19151922 }
19161923 else {
19171924 attr_index_t index = RSHAPE_INDEX (target_shape_id );
@@ -1927,26 +1934,16 @@ generic_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val)
19271934 }
19281935 }
19291936
1937+ VALUE * table = rb_imemo_fields_ptr (fields_obj );
1938+ RB_OBJ_WRITE (fields_obj , & table [index ], val );
1939+
19301940 if (RSHAPE_LEN (target_shape_id ) > RSHAPE_LEN (current_shape_id )) {
19311941 existing = false;
19321942 RBASIC_SET_SHAPE_ID (fields_obj , target_shape_id );
19331943 }
1934-
1935- VALUE * table = rb_imemo_fields_ptr (fields_obj );
1936- RB_OBJ_WRITE (fields_obj , & table [index ], val );
19371944 }
19381945
1939- if (fields_obj != original_fields_obj ) {
1940- RB_VM_LOCKING () {
1941- st_insert (generic_tbl , obj , fields_obj );
1942- }
1943- RB_OBJ_WRITTEN (obj , original_fields_obj , fields_obj );
1944-
1945- if (original_fields_obj ) {
1946- // Clear root shape to avoid triggering cleanup such as free_object_id.
1947- RBASIC_SET_SHAPE_ID (original_fields_obj , ROOT_SHAPE_ID );
1948- }
1949- }
1946+ generic_update_fields_obj (obj , fields_obj , original_fields_obj );
19501947
19511948 if (!existing ) {
19521949 RBASIC_SET_SHAPE_ID (obj , target_shape_id );
0 commit comments