@@ -1372,43 +1372,38 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
13721372 if (SPECIAL_CONST_P (obj )) return undef ;
13731373
13741374 if (BUILTIN_TYPE (obj ) == T_CLASS || BUILTIN_TYPE (obj ) == T_MODULE ) {
1375- VALUE val = undef ;
1376- RB_VM_LOCK_ENTER ();
1377- {
1378- VALUE fields_obj = RCLASS_FIELDS_OBJ (obj );
1379- if (fields_obj ) {
1380- val = rb_ivar_lookup (fields_obj , id , undef );
1381- }
1382- }
1383- RB_VM_LOCK_LEAVE ();
1384-
1385- if (val != undef &&
1386- rb_is_instance_id (id ) &&
1387- UNLIKELY (!rb_ractor_main_p ()) &&
1388- !rb_ractor_shareable_p (val )) {
1389- rb_raise (rb_eRactorIsolationError ,
1390- "can not get unshareable values from instance variables of classes/modules from non-main Ractors" );
1391- }
1392- return val ;
13931375 }
13941376
13951377 shape_id_t shape_id ;
1396- VALUE * ivar_list ;
1397- shape_id = RBASIC_SHAPE_ID (obj );
1378+ VALUE * ivar_list ;
13981379
13991380 switch (BUILTIN_TYPE (obj )) {
14001381 case T_CLASS :
14011382 case T_MODULE :
14021383 {
1403- rb_bug ("Unreachable" );
1384+ VALUE val = undef ;
1385+ VALUE fields_obj = RCLASS_FIELDS_OBJ (obj );
1386+ if (fields_obj ) {
1387+ val = rb_ivar_lookup (fields_obj , id , undef );
1388+ }
1389+
1390+ if (val != undef &&
1391+ rb_is_instance_id (id ) &&
1392+ UNLIKELY (!rb_ractor_main_p ()) &&
1393+ !rb_ractor_shareable_p (val )) {
1394+ rb_raise (rb_eRactorIsolationError ,
1395+ "can not get unshareable values from instance variables of classes/modules from non-main Ractors" );
1396+ }
1397+ return val ;
14041398 }
14051399 case T_IMEMO :
14061400 // Handled like T_OBJECT
14071401 {
14081402 RUBY_ASSERT (IMEMO_TYPE_P (obj , imemo_class_fields ));
1403+ shape_id = RBASIC_SHAPE_ID (obj );
14091404
14101405 if (rb_shape_too_complex_p (shape_id )) {
1411- st_table * iv_table = rb_imemo_class_fields_complex_tbl (obj );
1406+ st_table * iv_table = rb_imemo_class_fields_complex_tbl (obj );
14121407 VALUE val ;
14131408 if (rb_st_lookup (iv_table , (st_data_t )id , (st_data_t * )& val )) {
14141409 return val ;
@@ -1424,8 +1419,9 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
14241419 }
14251420 case T_OBJECT :
14261421 {
1422+ shape_id = RBASIC_SHAPE_ID (obj );
14271423 if (rb_shape_too_complex_p (shape_id )) {
1428- st_table * iv_table = ROBJECT_FIELDS_HASH (obj );
1424+ st_table * iv_table = ROBJECT_FIELDS_HASH (obj );
14291425 VALUE val ;
14301426 if (rb_st_lookup (iv_table , (st_data_t )id , (st_data_t * )& val )) {
14311427 return val ;
@@ -1440,6 +1436,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
14401436 break ;
14411437 }
14421438 default :
1439+ shape_id = RBASIC_SHAPE_ID (obj );
14431440 if (FL_TEST_RAW (obj , FL_EXIVAR )) {
14441441 struct gen_fields_tbl * fields_tbl ;
14451442 rb_gen_fields_tbl_get (obj , id , & fields_tbl );
@@ -1494,13 +1491,16 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
14941491
14951492 VALUE fields_obj = RCLASS_FIELDS_OBJ (obj );
14961493 if (fields_obj ) {
1497- RB_VM_LOCK_ENTER ();
1498- {
1494+ if (rb_multi_ractor_p ()) {
1495+ fields_obj = rb_imemo_class_fields_clone (fields_obj );
1496+ val = rb_ivar_delete (fields_obj , id , undef );
1497+ RCLASS_SET_FIELDS_OBJ (obj , fields_obj );
1498+ }
1499+ else {
14991500 val = rb_ivar_delete (fields_obj , id , undef );
15001501 }
1501- RB_VM_LOCK_LEAVE ();
1502- return val ;
15031502 }
1503+ return val ;
15041504 }
15051505
15061506 shape_id_t old_shape_id = rb_obj_shape_id (obj );
@@ -2128,8 +2128,6 @@ rb_ivar_set_internal(VALUE obj, ID id, VALUE val)
21282128 ivar_set (obj , id , val );
21292129}
21302130
2131- static void class_field_set (VALUE obj , shape_id_t target_shape_id , VALUE val );
2132-
21332131void
21342132rb_obj_field_set (VALUE obj , shape_id_t target_shape_id , VALUE val )
21352133{
@@ -2139,8 +2137,8 @@ rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val)
21392137 break ;
21402138 case T_CLASS :
21412139 case T_MODULE :
2142- ASSERT_vm_locking ();
2143- class_field_set ( obj , target_shape_id , val );
2140+ // The only field is object_id and T_CLASS handle it differently.
2141+ rb_bug ( "Unreachable" );
21442142 break ;
21452143 default :
21462144 generic_field_set (obj , target_shape_id , val );
@@ -2200,11 +2198,9 @@ rb_ivar_defined(VALUE obj, ID id)
22002198 switch (BUILTIN_TYPE (obj )) {
22012199 case T_CLASS :
22022200 case T_MODULE :
2203- RB_VM_LOCKING () {
2204- VALUE fields_obj = RCLASS_FIELDS_OBJ (obj );
2205- if (fields_obj ) {
2206- defined = ivar_defined0 (fields_obj , id );
2207- }
2201+ VALUE fields_obj = RCLASS_FIELDS_OBJ (obj );
2202+ if (fields_obj ) {
2203+ defined = ivar_defined0 (fields_obj , id );
22082204 }
22092205 break ;
22102206 default :
@@ -2454,11 +2450,9 @@ rb_field_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg,
24542450 case T_CLASS :
24552451 case T_MODULE :
24562452 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR (0 );
2457- RB_VM_LOCKING () {
2458- VALUE fields_obj = RCLASS_FIELDS_OBJ (obj );
2459- if (fields_obj ) {
2460- class_fields_each (fields_obj , func , arg , ivar_only );
2461- }
2453+ VALUE fields_obj = RCLASS_FIELDS_OBJ (obj );
2454+ if (fields_obj ) {
2455+ class_fields_each (fields_obj , func , arg , ivar_only );
24622456 }
24632457 break ;
24642458 default :
@@ -4702,15 +4696,16 @@ rb_iv_set(VALUE obj, const char *name, VALUE val)
47024696 return rb_ivar_set (obj , id , val );
47034697}
47044698
4705- static int
4706- class_ivar_set (VALUE obj , ID id , VALUE val )
4699+ static bool
4700+ class_fields_ivar_set (VALUE klass , VALUE fields_obj , ID id , VALUE val , bool concurrent , VALUE * new_fields_obj )
47074701{
47084702 bool existing = true;
4709- const VALUE original_fields_obj = RCLASS_FIELDS_OBJ ( obj ) ;
4710- VALUE fields_obj = original_fields_obj ? original_fields_obj : rb_imemo_class_fields_new (obj , 1 );
4703+ const VALUE original_fields_obj = fields_obj ;
4704+ fields_obj = original_fields_obj ? original_fields_obj : rb_imemo_class_fields_new (klass , 1 );
47114705
4712- shape_id_t next_shape_id = 0 ;
47134706 shape_id_t current_shape_id = RBASIC_SHAPE_ID (fields_obj );
4707+ shape_id_t next_shape_id = current_shape_id ;
4708+
47144709 if (UNLIKELY (rb_shape_too_complex_p (current_shape_id ))) {
47154710 goto too_complex ;
47164711 }
@@ -4727,7 +4722,7 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
47274722 next_shape_id = rb_shape_transition_add_ivar (fields_obj , id );
47284723 if (UNLIKELY (rb_shape_too_complex_p (next_shape_id ))) {
47294724 attr_index_t current_len = RSHAPE_LEN (current_shape_id );
4730- fields_obj = rb_imemo_class_fields_new_complex (obj , current_len + 1 );
4725+ fields_obj = rb_imemo_class_fields_new_complex (klass , current_len + 1 );
47314726 if (current_len ) {
47324727 rb_obj_copy_fields_to_hash_table (original_fields_obj , rb_imemo_class_fields_complex_tbl (fields_obj ));
47334728 RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
@@ -4738,10 +4733,12 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
47384733 attr_index_t next_capacity = RSHAPE_CAPACITY (next_shape_id );
47394734 attr_index_t current_capacity = RSHAPE_CAPACITY (current_shape_id );
47404735
4741- if (UNLIKELY (next_capacity != current_capacity )) {
4742- RUBY_ASSERT (next_capacity > current_capacity );
4743- // We allocate a new fields_obj so that we're embedded as long as possible
4744- fields_obj = rb_imemo_class_fields_new (obj , next_capacity );
4736+ if (concurrent || next_capacity != current_capacity ) {
4737+ RUBY_ASSERT (concurrent || next_capacity > current_capacity );
4738+
4739+ // We allocate a new fields_obj even when concurrency isn't a concern
4740+ // so that we're embedded as long as possible.
4741+ fields_obj = rb_imemo_class_fields_new (klass , next_capacity );
47454742 if (original_fields_obj ) {
47464743 MEMCPY (rb_imemo_class_fields_ptr (fields_obj ), rb_imemo_class_fields_ptr (original_fields_obj ), VALUE , RSHAPE_LEN (current_shape_id ));
47474744 }
@@ -4753,20 +4750,12 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
47534750
47544751 VALUE * fields = rb_imemo_class_fields_ptr (fields_obj );
47554752 RB_OBJ_WRITE (fields_obj , & fields [index ], val );
4753+
47564754 if (!existing ) {
47574755 RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
47584756 }
47594757
4760- if (fields_obj != original_fields_obj ) {
4761- RCLASS_SET_FIELDS_OBJ (obj , fields_obj );
4762- // TODO: What should we set as the T_CLASS shape_id?
4763- // In most case we can replicate the single `fields_obj` shape
4764- // but in namespaced case?
4765- // Perhaps INVALID_SHAPE_ID?
4766- RBASIC_SET_SHAPE_ID (obj , next_shape_id );
4767- }
4768-
4769- RB_GC_GUARD (fields_obj );
4758+ * new_fields_obj = fields_obj ;
47704759 return existing ;
47714760
47724761too_complex :
@@ -4777,41 +4766,37 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
47774766
47784767 if (fields_obj != original_fields_obj ) {
47794768 RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
4780- RCLASS_SET_FIELDS_OBJ (obj , fields_obj );
4781- // TODO: What should we set as the T_CLASS shape_id?
4782- // In most case we can replicate the single `fields_obj` shape
4783- // but in namespaced case?
4784- // Perhaps INVALID_SHAPE_ID?
4785- RBASIC_SET_SHAPE_ID (obj , next_shape_id );
47864769 }
47874770 }
4788- RB_GC_GUARD (fields_obj );
4771+
4772+ * new_fields_obj = fields_obj ;
47894773 return existing ;
47904774}
47914775
47924776int
47934777rb_class_ivar_set (VALUE obj , ID id , VALUE val )
47944778{
47954779 RUBY_ASSERT (RB_TYPE_P (obj , T_CLASS ) || RB_TYPE_P (obj , T_MODULE ));
4796- bool existing = false;
47974780 rb_check_frozen (obj );
47984781
47994782 rb_class_ensure_writable (obj );
48004783
4801- RB_VM_LOCKING () {
4802- existing = class_ivar_set (obj , id , val );
4803- }
4784+ const VALUE original_fields_obj = RCLASS_FIELDS_OBJ (obj );
4785+ VALUE new_fields_obj = 0 ;
48044786
4805- return existing ;
4806- }
4787+ bool existing = class_fields_ivar_set (obj , original_fields_obj , id , val , rb_multi_ractor_p (), & new_fields_obj );
48074788
4808- static void
4809- class_field_set (VALUE obj , shape_id_t target_shape_id , VALUE val )
4810- {
4811- RUBY_ASSERT (RB_TYPE_P (obj , T_CLASS ) || RB_TYPE_P (obj , T_MODULE ));
4812- obj_field_set (RCLASS_ENSURE_FIELDS_OBJ (obj ), target_shape_id , val );
4813- }
4789+ if (new_fields_obj != original_fields_obj ) {
4790+ RCLASS_SET_FIELDS_OBJ (obj , new_fields_obj );
48144791
4792+ // TODO: What should we set as the T_CLASS shape_id?
4793+ // In most case we can replicate the single `fields_obj` shape
4794+ // but in namespaced case?
4795+ // Perhaps INVALID_SHAPE_ID?
4796+ RBASIC_SET_SHAPE_ID (obj , RBASIC_SHAPE_ID (new_fields_obj ));
4797+ }
4798+ return existing ;
4799+ }
48154800static int
48164801tbl_copy_i (ID key , VALUE val , st_data_t dest )
48174802{
0 commit comments