@@ -1372,43 +1372,38 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
1372
1372
if (SPECIAL_CONST_P (obj )) return undef ;
1373
1373
1374
1374
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 ;
1393
1375
}
1394
1376
1395
1377
shape_id_t shape_id ;
1396
- VALUE * ivar_list ;
1397
- shape_id = RBASIC_SHAPE_ID (obj );
1378
+ VALUE * ivar_list ;
1398
1379
1399
1380
switch (BUILTIN_TYPE (obj )) {
1400
1381
case T_CLASS :
1401
1382
case T_MODULE :
1402
1383
{
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 ) &&
741A
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 ;
1404
1398
}
1405
1399
case T_IMEMO :
1406
1400
// Handled like T_OBJECT
1407
1401
{
1408
1402
RUBY_ASSERT (IMEMO_TYPE_P (obj , imemo_class_fields ));
1403
+ shape_id = RBASIC_SHAPE_ID (obj );
1409
1404
1410
1405
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 );
1412
1407
VALUE val ;
1413
1408
if (rb_st_lookup (iv_table , (st_data_t )id , (st_data_t * )& val )) {
1414
1409
return val ;
@@ -1424,8 +1419,9 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
1424
1419
}
1425
1420
case T_OBJECT :
1426
1421
{
1422
+ shape_id = RBASIC_SHAPE_ID (obj );
1427
1423
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 );
1429
1425
VALUE val ;
1430
1426
if (rb_st_lookup (iv_table , (st_data_t )id , (st_data_t * )& val )) {
1431
1427
return val ;
@@ -1440,6 +1436,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
1440
1436
break ;
1441
1437
}
1442
1438
default :
1439
+ shape_id = RBASIC_SHAPE_ID (obj );
1443
1440
if (FL_TEST_RAW (obj , FL_EXIVAR )) {
1444
1441
struct gen_fields_tbl * fields_tbl ;
1445
1442
rb_gen_fields_tbl_get (obj , id , & fields_tbl );
@@ -1494,13 +1491,16 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
1494
1491
1495
1492
VALUE fields_obj = RCLASS_FIELDS_OBJ (obj );
1496
1493
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 {
1499
1500
val = rb_ivar_delete (fields_obj , id , undef );
1500
1501
}
1501
- RB_VM_LOCK_LEAVE ();
1502
- return val ;
1503
1502
}
1503
+ return val ;
1504
1504
}
1505
1505
1506
1506
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)
2128
2128
ivar_set (obj , id , val );
2129
2129
}
2130
2130
2131
- static void class_field_set (VALUE obj , shape_id_t target_shape_id , VALUE val );
2132
-
2133
2131
void
2134
2132
rb_obj_field_set (VALUE obj , shape_id_t target_shape_id , VALUE val )
2135
2133
{
@@ -2139,8 +2137,8 @@ rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val)
2139
2137
break ;
2140
2138
case T_CLASS :
2141
2139
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" );
2144
2142
break ;
2145
2143
default :
2146
2144
generic_field_set (obj , target_shape_id , val );
@@ -2200,7 +2198,7 @@ rb_ivar_defined(VALUE obj, ID id)
2200
2198
switch (BUILTIN_TYPE (obj )) {
2201
2199
case T_CLASS :
2202
2200
case T_MODULE :
2203
- RB_VM_LOCKING () {
2201
+ {
2204
2202
VALUE fields_obj = RCLASS_FIELDS_OBJ (obj );
2205
2203
if (fields_obj ) {
2206
2204
defined = ivar_defined0 (fields_obj , id );
@@ -2454,11 +2452,9 @@ rb_field_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg,
2454
2452
case T_CLASS :
2455
2453
case T_MODULE :
2456
2454
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
- }
2455
+ VALUE fields_obj = RCLASS_FIELDS_OBJ (obj );
2456
+ if (fields_obj ) {
2457
+ class_fields_each (fields_obj , func , arg , ivar_only );
2462
2458
}
2463
2459
break ;
2464
2460
default :
@@ -4702,15 +4698,16 @@ rb_iv_set(VALUE obj, const char *name, VALUE val)
4702
4698
return rb_ivar_set (obj , id , val );
4703
4699
}
4704
4700
4705
- static int
4706
- class_ivar_set (VALUE obj , ID id , VALUE val )
4701
+ static bool
4702
+ class_fields_ivar_set (VALUE klass , VALUE fields_obj , ID id , VALUE val , bool concurrent , VALUE * new_fields_obj )
4707
4703
{
4708
4704
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 );
4705
+ const VALUE original_fields_obj = fields_obj ;
4706
+ fields_obj = original_fields_obj ? original_fields_obj : rb_imemo_class_fields_new (klass , 1 );
4711
4707
4712
- shape_id_t next_shape_id = 0 ;
4713
4708
shape_id_t current_shape_id = RBASIC_SHAPE_ID (fields_obj );
4709
+ shape_id_t next_shape_id = current_shape_id ;
4710
+
4714
4711
if (UNLIKELY (rb_shape_too_complex_p (current_shape_id ))) {
4715
4712
goto too_complex ;
4716
4713
}
@@ -4727,7 +4724,7 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
4727
4724
next_shape_id = rb_shape_transition_add_ivar (fields_obj , id );
4728
4725
if (UNLIKELY (rb_shape_too_complex_p (next_shape_id ))) {
4729
4726
attr_index_t current_len = RSHAPE_LEN (current_shape_id );
4730
- fields_obj = rb_imemo_class_fields_new_complex (obj , current_len + 1 );
4727
+ fields_obj = rb_imemo_class_fields_new_complex (klass , current_len + 1 );
4731
4728
if (current_len ) {
4732
4729
rb_obj_copy_fields_to_hash_table (original_fields_obj , rb_imemo_class_fields_complex_tbl (fields_obj ));
4733
4730
RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
@@ -4738,10 +4735,12 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
4738
4735
attr_index_t next_capacity = RSHAPE_CAPACITY (next_shape_id );
4739
4736
attr_index_t current_capacity = RSHAPE_CAPACITY (current_shape_id );
4740
4737
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 );
4738
+ if (concurrent || next_capacity != current_capacity ) {
4739
+ RUBY_ASSERT (concurrent || next_capacity > current_capacity );
4740
+
4741
+ // We allocate a new fields_obj even when concurrency isn't a concern
4742
+ // so that we're embedded as long as possible.
4743
+ fields_obj = rb_imemo_class_fields_new (klass , next_capacity );
4745
4744
if (original_fields_obj ) {
4746
4745
MEMCPY (rb_imemo_class_fields_ptr (fields_obj ), rb_imemo_class_fields_ptr (original_fields_obj ), VALUE , RSHAPE_LEN (current_shape_id ));
4747
4746
}
@@ -4753,20 +4752,12 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
4753
4752
4754
4753
VALUE * fields = rb_imemo_class_fields_ptr (fields_obj );
4755
4754
RB_OBJ_WRITE (fields_obj , & fields [index ], val );
4755
+
4756
4756
if (!existing ) {
4757
4757
RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
4758
4758
}
4759
4759
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 );
4760
+ * new_fields_obj = fields_obj ;
4770
4761
return existing ;
4771
4762
4772
4763
too_complex :
@@ -4777,41 +4768,37 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
4777
4768
4778
4769
if (fields_obj != original_fields_obj ) {
4779
4770
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 );
4786
4771
}
4787
4772
}
4788
- RB_GC_GUARD (fields_obj );
4773
+
4774
+ * new_fields_obj = fields_obj ;
4789
4775
return existing ;
4790
4776
}
4791
4777
4792
4778
int
4793
4779
rb_class_ivar_set (VALUE obj , ID id , VALUE val )
4794
4780
{
4795
4781
RUBY_ASSERT (RB_TYPE_P (obj , T_CLASS ) || RB_TYPE_P (obj , T_MODULE ));
4796
- bool existing = false;
4797
4782
rb_check_frozen (obj );
4798
4783
4799
4784
rb_class_ensure_writable (obj );
4800
4785
4801
- RB_VM_LOCKING () {
4802
- existing = class_ivar_set (obj , id , val );
4803
- }
4786
+ const VALUE original_fields_obj = RCLASS_FIELDS_OBJ (obj );
4787
+ VALUE new_fields_obj = 0 ;
4804
4788
4805
- return existing ;
4806
- }
4789
+ bool existing = class_fields_ivar_set (obj , original_fields_obj , id , val , rb_multi_ractor_p (), & new_fields_obj );
4807
4790
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
- }
4791
+ if (new_fields_obj != original_fields_obj ) {
4792
+ RCLASS_SET_FIELDS_OBJ (obj , new_fields_obj );
4814
4793
4794
+ // TODO: What should we set as the T_CLASS shape_id?
4795
+ // In most case we can replicate the single `fields_obj` shape
4796
+ // but in namespaced case?
4797
+ // Perhaps INVALID_SHAPE_ID?
4798
+ RBASIC_SET_SHAPE_ID (obj , RBASIC_SHAPE_ID (new_fields_obj ));
4799
+ }
4800
+ return existing ;
4801
+ }
4815
4802
static int
4816
4803
tbl_copy_i (ID key , VALUE val , st_data_t dest )
4817
4804
{
0 commit comments