@@ -1371,44 +1371,36 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
1371
1371
{
1372
1372
if (SPECIAL_CONST_P (obj )) return undef ;
1373
1373
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_WRITABLE_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
- }
1394
-
1395
1374
shape_id_t shape_id ;
1396
- VALUE * ivar_list ;
1397
- shape_id = RBASIC_SHAPE_ID (obj );
1375
+ VALUE * ivar_list ;
1398
1376
1399
1377
switch (BUILTIN_TYPE (obj )) {
1400
1378
case T_CLASS :
1401
1379
case T_MODULE :
1402
1380
{
1403
- rb_bug ("Unreachable" );
1381
+ VALUE val = undef ;
1382
+ VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ (obj );
1383
+ if (fields_obj ) {
1384
+ val = rb_ivar_lookup (fields_obj , id , undef );
1385
+ }
1386
+
1387
+ if (val != undef &&
1388
+ rb_is_instance_id (id ) &&
1389
+ UNLIKELY (!rb_ractor_main_p ()) &&
1390
+ !rb_ractor_shareable_p (val )) {
1391
+ rb_raise (rb_eRactorIsolationError ,
1392
+ "can not get unshareable values from instance variables of classes/modules from non-main Ractors" );
1393
+ }
1394
+ return val ;
1404
1395
}
1405
1396
case T_IMEMO :
1406
1397
// Handled like T_OBJECT
1407
1398
{
1408
1399
RUBY_ASSERT (IMEMO_TYPE_P (obj , imemo_class_fields ));
1400
+ shape_id = RBASIC_SHAPE_ID (obj );
1409
1401
1410
1402
if (rb_shape_too_complex_p (shape_id )) {
1411
- st_table * iv_table = rb_imemo_class_fields_complex_tbl (obj );
1403
+ st_table * iv_table = rb_imemo_class_fields_complex_tbl (obj );
1412
1404
VALUE val ;
1413
1405
if (rb_st_lookup (iv_table , (st_data_t )id , (st_data_t * )& val )) {
1414
1406
return val ;
@@ -1424,8 +1416,9 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
1424
1416
}
1425
1417
case T_OBJECT :
1426
1418
{
1419
+ shape_id = RBASIC_SHAPE_ID (obj );
1427
1420
if (rb_shape_too_complex_p (shape_id )) {
1428
- st_table * iv_table = ROBJECT_FIELDS_HASH (obj );
1421
+ st_table * iv_table = ROBJECT_FIELDS_HASH (obj );
1429
1422
VALUE val ;
1430
1423
if (rb_st_lookup (iv_table , (st_data_t )id , (st_data_t * )& val )) {
1431
1424
return val ;
@@ -1440,6 +1433,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
1440
1433
break ;
1441
1434
}
1442
1435
default :
1436
+ shape_id = RBASIC_SHAPE_ID (obj );
1443
1437
if (FL_TEST_RAW (obj , FL_EXIVAR )) {
1444
1438
struct gen_fields_tbl * fields_tbl ;
1445
1439
rb_gen_fields_tbl_get (obj , id , & fields_tbl );
@@ -1494,13 +1488,16 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
1494
1488
1495
1489
VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ (obj );
1496
1490
if (fields_obj ) {
1497
- RB_VM_LOCK_ENTER ();
1498
- {
1491
+ if (rb_multi_ractor_p ()) {
1492
+ fields_obj = rb_imemo_class_fields_clone (fields_obj );
1493
+ val = rb_ivar_delete (fields_obj , id , undef );
1494
+ RCLASS_WRITABLE_SET_FIELDS_OBJ (obj , fields_obj );
1495
+ }
1496
+ else {
1499
1497
val = rb_ivar_delete (fields_obj , id , undef );
1500
1498
}
1501
- RB_VM_LOCK_LEAVE ();
1502
- return val ;
1503
1499
}
1500
+ return val ;
1504
1501
}
1505
1502
1506
1503
shape_id_t old_shape_id = rb_obj_shape_id (obj );
@@ -2127,8 +2124,6 @@ rb_ivar_set_internal(VALUE obj, ID id, VALUE val)
2127
2124
ivar_set (obj , id , val );
2128
2125
}
2129
2126
2130
- static void class_field_set (VALUE obj , shape_id_t target_shape_id , VALUE val );
2131
-
2132
2127
void
2133
2128
rb_obj_field_set (VALUE obj , shape_id_t target_shape_id , VALUE val )
2134
2129
{
@@ -2138,8 +2133,8 @@ rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val)
2138
2133
break ;
2139
2134
case T_CLASS :
2140
2135
case T_MODULE :
2141
- ASSERT_vm_locking ();
2142
- class_field_set ( obj , target_shape_id , val );
2136
+ // The only field is object_id and T_CLASS handle it differently.
2137
+ rb_bug ( "Unreachable" );
2143
2138
break ;
2144
2139
default :
2145
2140
generic_field_set (obj , target_shape_id , val );
@@ -2199,7 +2194,7 @@ rb_ivar_defined(VALUE obj, ID id)
2199
2194
switch (BUILTIN_TYPE (obj )) {
2200
2195
case T_CLASS :
2201
2196
case T_MODULE :
2202
- RB_VM_LOCKING () {
2197
+ {
2203
2198
VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ (obj );
2204
2199
if (fields_obj ) {
2205
2200
defined = ivar_defined0 (fields_obj , id );
@@ -2452,8 +2447,8 @@ rb_field_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg,
2452
2447
break ;
2453
2448
case T_CLASS :
2454
2449
case T_MODULE :
2455
- IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR ( 0 );
2456
- RB_VM_LOCKING () {
2450
+ {
2451
+ IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR ( 0 );
2457
2452
VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ (obj );
2458
2453
if (fields_obj ) {
2459
2454
class_fields_each (fields_obj , func , arg , ivar_only );
@@ -4701,15 +4696,16 @@ rb_iv_set(VALUE obj, const char *name, VALUE val)
4701
4696
return rb_ivar_set (obj , id , val );
4702
4697
}
4703
4698
4704
- static int
4705
- 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 )
4706
4701
{
4707
4702
bool existing = true;
4708
- const VALUE original_fields_obj = RCLASS_WRITABLE_FIELDS_OBJ ( obj ) ;
4709
- 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 );
4710
4705
4711
- shape_id_t next_shape_id = 0 ;
4712
4706
shape_id_t current_shape_id = RBASIC_SHAPE_ID (fields_obj );
4707
+ shape_id_t next_shape_id = current_shape_id ;
4708
+
4713
4709
if (UNLIKELY (rb_shape_too_complex_p (current_shape_id ))) {
4714
4710
goto too_complex ;
4715
4711
}
@@ -4726,7 +4722,7 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
4726
4722
next_shape_id = rb_shape_transition_add_ivar (fields_obj , id );
4727
4723
if (UNLIKELY (rb_shape_too_complex_p (next_shape_id ))) {
4728
4724
attr_index_t current_len = RSHAPE_LEN (current_shape_id );
4729
- 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 );
4730
4726
if (current_len ) {
4731
4727
rb_obj_copy_fields_to_hash_table (original_fields_obj , rb_imemo_class_fields_complex_tbl (fields_obj ));
4732
4728
RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
@@ -4737,10 +4733,12 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
4737
4733
attr_index_t next_capacity = RSHAPE_CAPACITY (next_shape_id );
4738
4734
attr_index_t current_capacity = RSHAPE_CAPACITY (current_shape_id );
4739
4735
4740
- if (UNLIKELY (next_capacity != current_capacity )) {
4741
- RUBY_ASSERT (next_capacity > current_capacity );
4742
- // We allocate a new fields_obj so that we're embedded as long as possible
4743
- 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 );
4744
4742
if (original_fields_obj ) {
4745
4743
MEMCPY (rb_imemo_class_fields_ptr (fields_obj ), rb_imemo_class_fields_ptr (original_fields_obj ), VALUE , RSHAPE_LEN (current_shape_id ));
4746
4744
}
@@ -4752,20 +4750,12 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
4752
4750
4753
4751
VALUE * fields = rb_imemo_class_fields_ptr (fields_obj );
4754
4752
RB_OBJ_WRITE (fields_obj , & fields [index ], val );
4753
+
4755
4754
if (!existing ) {
4756
4755
RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
4757
4756
}
4758
4757
4759
- if (fields_obj != original_fields_obj ) {
4760
- RCLASS_WRITABLE_SET_FIELDS_OBJ (obj , fields_obj );
4761
- // TODO: What should we set as the T_CLASS shape_id?
4762
- // In most case we can replicate the single `fields_obj` shape
4763
- // but in namespaced case?
4764
- // Perhaps INVALID_SHAPE_ID?
4765
- RBASIC_SET_SHAPE_ID (obj , next_shape_id );
4766
- }
4767
-
4768
- RB_GC_GUARD (fields_obj );
4758
+ * new_fields_obj = fields_obj ;
4769
4759
return existing ;
4770
4760
4771
4761
too_complex :
@@ -4776,39 +4766,36 @@ class_ivar_set(VALUE obj, ID id, VALUE val)
4776
4766
4777
4767
if (fields_obj != original_fields_obj ) {
4778
4768
RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
4779
- RCLASS_WRITABLE_SET_FIELDS_OBJ (obj , fields_obj );
4780
- // TODO: What should we set as the T_CLASS shape_id?
4781
- // In most case we can replicate the single `fields_obj` shape
4782
- // but in namespaced case?
4783
- // Perhaps INVALID_SHAPE_ID?
4784
- RBASIC_SET_SHAPE_ID (obj , next_shape_id );
4785
4769
}
4786
4770
}
4787
- RB_GC_GUARD (fields_obj );
4771
+
4772
+ * new_fields_obj = fields_obj ;
4788
4773
return existing ;
4789
4774
}
4790
4775
4791
4776
int
4792
4777
rb_class_ivar_set (VALUE obj , ID id , VALUE val )
4793
4778
{
4794
4779
RUBY_ASSERT (RB_TYPE_P (obj , T_CLASS ) || RB_TYPE_P (obj , T_MODULE ));
4795
- bool existing = false;
4796
4780
rb_check_frozen (obj );
4797
4781
4798
4782
rb_class_ensure_writable (obj );
4799
4783
4800
- RB_VM_LOCKING () {
4801
- existing = class_ivar_set (obj , id , val );
4802
- }
4784
+ const VALUE original_fields_obj = RCLASS_WRITABLE_FIELDS_OBJ (obj );
4785
+ VALUE new_fields_obj = 0 ;
4803
4786
4804
- return existing ;
4805
- }
4787
+ bool existing = class_fields_ivar_set (obj , original_fields_obj , id , val , rb_multi_ractor_p (), & new_fields_obj );
4806
4788
4807
- static void
4808
- class_field_set (VALUE obj , shape_id_t target_shape_id , VALUE val )
4809
- {
4810
- RUBY_ASSERT (RB_TYPE_P (obj , T_CLASS ) || RB_TYPE_P (obj , T_MODULE ));
4811
- obj_field_set (RCLASS_WRITABLE_ENSURE_FIELDS_OBJ (obj ), target_shape_id , val );
4789
+ if (new_fields_obj != original_fields_obj ) {
4790
+ RCLASS_WRITABLE_SET_FIELDS_OBJ (obj , new_fields_obj );
4791
+
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 ;
4812
4799
}
4813
4800
4814
4801
static int
0 commit comments