@@ -1844,6 +1844,9 @@ imemo_fields_set(VALUE klass, VALUE fields_obj, shape_id_t target_shape_id, ID f
18441844 if (UNLIKELY (rb_shape_too_complex_p (target_shape_id ))) {
18451845 if (rb_shape_too_complex_p (current_shape_id )) {
18461846 if (concurrent ) {
1847+ // In multi-ractor case, we must always work on a copy because
1848+ // even if the field already exist, inserting in a st_table may
1849+ // cause a rebuild.
18471850 fields_obj = rb_imemo_fields_clone (fields_obj );
18481851 }
18491852 }
@@ -4680,9 +4683,7 @@ class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool conc
46804683 attr_index_t next_capacity = RSHAPE_CAPACITY (next_shape_id );
46814684 attr_index_t current_capacity = RSHAPE_CAPACITY (current_shape_id );
46824685
4683- if (concurrent || next_capacity != current_capacity ) {
4684- RUBY_ASSERT (concurrent || next_capacity > current_capacity );
4685-
4686+ if (next_capacity > current_capacity ) {
46864687 // We allocate a new fields_obj even when concurrency isn't a concern
46874688 // so that we're embedded as long as possible.
46884689 fields_obj = imemo_fields_copy_capa (rb_singleton_class (klass ), fields_obj , next_capacity );
@@ -4693,7 +4694,12 @@ class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool conc
46934694 }
46944695
46954696 VALUE * fields = rb_imemo_fields_ptr (fields_obj );
4696- RB_OBJ_WRITE (fields_obj , & fields [index ], val );
4697+ if (concurrent && existing ) {
4698+ RB_OBJ_ATOMIC_WRITE (fields_obj , & fields [index ], val );
4699+ }
4700+ else {
4701+ RB_OBJ_WRITE (fields_obj , & fields [index ], val );
4702+ }
46974703
46984704 if (!existing ) {
46994705 RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
@@ -4705,9 +4711,12 @@ class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool conc
47054711too_complex :
47064712 {
47074713 if (concurrent && fields_obj == original_fields_obj ) {
4708- // If we're in the multi-ractor mode, we can't directly insert in the table.
4714+ // In multi-ractor case, we must always work on a copy because
4715+ // even if the field already exist, inserting in a st_table may
4716+ // cause a rebuild.
47094717 fields_obj = rb_imemo_fields_clone (fields_obj );
47104718 }
4719+
47114720 st_table * table = rb_imemo_fields_complex_tbl (fields_obj );
47124721 existing = st_insert (table , (st_data_t )id , (st_data_t )val );
47134722 RB_OBJ_WRITTEN (fields_obj , Qundef , val );
0 commit comments