@@ -424,12 +424,6 @@ rb_shape_depth(shape_id_t shape_id)
424
424
return depth ;
425
425
}
426
426
427
- static inline rb_shape_t *
428
- obj_shape (VALUE obj )
429
- {
430
- return RSHAPE (rb_obj_shape_id (obj ));
431
- }
432
-
433
427
static rb_shape_t *
434
428
shape_alloc (void )
435
429
{
@@ -461,7 +455,6 @@ rb_shape_alloc(ID edge_name, rb_shape_t *parent, enum shape_type type)
461
455
{
462
456
rb_shape_t * shape = rb_shape_alloc_with_parent_id (edge_name , raw_shape_id (parent ));
463
457
shape -> type = (uint8_t )type ;
464
- shape -> flags = parent -> flags ;
465
458
shape -> heap_index = parent -> heap_index ;
466
459
shape -> capacity = parent -> capacity ;
467
460
shape -> edges = 0 ;
@@ -510,8 +503,6 @@ rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type)
510
503
511
504
switch (shape_type ) {
512
505
case SHAPE_OBJ_ID :
513
- new_shape -> flags |= SHAPE_FL_HAS_OBJECT_ID ;
514
- // fallthrough
515
506
case SHAPE_IVAR :
516
507
if (UNLIKELY (shape -> next_field_index >= shape -> capacity )) {
517
508
RUBY_ASSERT (shape -> next_field_index == shape -> capacity );
@@ -711,6 +702,16 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
711
702
}
712
703
}
713
704
705
+ static inline shape_id_t
706
+ transition_frozen (shape_id_t shape_id )
707
+ {
708
+ if (rb_shape_has_object_id (shape_id )) {
709
+ return ROOT_TOO_COMPLEX_WITH_OBJ_ID | (shape_id & SHAPE_ID_FLAGS_MASK );
710
+ }
711
+ return ROOT_TOO_COMPLEX_SHAPE_ID | (shape_id & SHAPE_ID_FLAGS_MASK );
712
+ }
713
+
714
+
714
715
shape_id_t
715
716
rb_shape_transition_remove_ivar (VALUE obj , ID id , shape_id_t * removed_shape_id )
716
717
{
@@ -732,7 +733,7 @@ rb_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id)
732
733
else if (removed_shape ) {
733
734
// We found the shape to remove, but couldn't create a new variation.
734
735
// We must transition to TOO_COMPLEX.
735
- return ROOT_TOO_COMPLEX_SHAPE_ID | (original_shape_id & SHAPE_ID_FLAGS_MASK );
736
+ return transition_frozen (original_shape_id );
736
737
}
737
738
return original_shape_id ;
738
739
}
@@ -749,41 +750,42 @@ rb_shape_transition_frozen(VALUE obj)
749
750
shape_id_t
750
751
rb_shape_transition_complex (VALUE obj )
751
752
{
752
- shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
753
- return ROOT_TOO_COMPLEX_SHAPE_ID | (original_shape_id & SHAPE_ID_FLAGS_MASK );
753
+ return transition_frozen (RBASIC_SHAPE_ID (obj ));
754
754
}
755
755
756
- static inline bool
757
- shape_has_object_id ( rb_shape_t * shape )
756
+ shape_id_t
757
+ rb_shape_transition_object_id ( VALUE obj )
758
758
{
759
- return shape -> flags & SHAPE_FL_HAS_OBJECT_ID ;
760
- }
759
+ shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
761
760
762
- bool
763
- rb_shape_has_object_id (shape_id_t shape_id )
764
- {
765
- return shape_has_object_id (RSHAPE (shape_id ));
761
+ RUBY_ASSERT (!rb_shape_has_object_id (original_shape_id ));
762
+
763
+ rb_shape_t * shape = NULL ;
764
+ if (!rb_shape_too_complex_p (original_shape_id )) {
765
+ bool dont_care ;
766
+ shape = get_next_shape_internal (RSHAPE (original_shape_id ), ruby_internal_object_id , SHAPE_OBJ_ID , & dont_care , true);
767
+ }
768
+
769
+ if (!shape ) {
770
+ shape = RSHAPE (ROOT_TOO_COMPLEX_WITH_OBJ_ID );
771
+ }
772
+ return shape_id (shape , original_shape_id ) | SHAPE_ID_FL_HAS_OBJECT_ID ;
766
773
}
767
774
768
775
shape_id_t
769
- rb_shape_transition_object_id ( VALUE obj )
776
+ rb_shape_object_id ( shape_id_t original_shape_id )
770
777
{
771
- shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
772
-
773
- rb_shape_t * shape = RSHAPE (original_shape_id );
774
- RUBY_ASSERT (shape );
778
+ RUBY_ASSERT (rb_shape_has_object_id (original_shape_id ));
775
779
776
- if (shape -> flags & SHAPE_FL_HAS_OBJECT_ID ) {
777
- while (shape -> type != SHAPE_OBJ_ID ) {
778
- shape = RSHAPE (shape -> parent_id );
780
+ rb_shape_t * shape = RSHAPE (original_shape_id );
781
+ while (shape -> type != SHAPE_OBJ_ID ) {
782
+ if (UNLIKELY (shape -> parent_id == INVALID_SHAPE_ID )) {
783
+ rb_bug ("Missing object_id in shape tree" );
779
784
}
785
+ shape = RSHAPE (shape -> parent_id );
780
786
}
781
- else {
782
- bool dont_care ;
783
- shape = get_next_shape_internal (shape , ruby_internal_object_id , SHAPE_OBJ_ID , & dont_care , true);
784
- }
785
- RUBY_ASSERT (shape );
786
- return shape_id (shape , original_shape_id );
787
+
788
+ return shape_id (shape , original_shape_id ) | SHAPE_ID_FL_HAS_OBJECT_ID ;
787
789
}
788
790
789
791
/*
@@ -892,17 +894,19 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
892
894
shape_id_t
893
895
rb_shape_transition_add_ivar (VALUE obj , ID id )
894
896
{
895
- RUBY_ASSERT (!shape_frozen_p (RBASIC_SHAPE_ID (obj )));
897
+ shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
898
+ RUBY_ASSERT (!shape_frozen_p (original_shape_id ));
896
899
897
- return raw_shape_id (shape_get_next (obj_shape ( obj ), obj , id , true));
900
+ return shape_id (shape_get_next (RSHAPE ( original_shape_id ), obj , id , true), original_shape_id );
898
901
}
899
902
900
903
shape_id_t
901
904
rb_shape_transition_add_ivar_no_warnings (VALUE obj , ID id )
902
905
{
903
- RUBY_ASSERT (!shape_frozen_p (RBASIC_SHAPE_ID (obj )));
906
+ shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
907
+ RUBY_ASSERT (!shape_frozen_p (original_shape_id ));
904
908
905
- return raw_shape_id (shape_get_next (obj_shape ( obj ), obj , id , false));
909
+ return shape_id (shape_get_next (RSHAPE ( original_shape_id ), obj , id , false), original_shape_id );
906
910
}
907
911
908
912
// Same as rb_shape_get_iv_index, but uses a provided valid shape id and index
@@ -1180,7 +1184,40 @@ rb_shape_memsize(shape_id_t shape_id)
1180
1184
return memsize ;
1181
1185
}
1182
1186
1187
+ #if RUBY_DEBUG
1188
+ bool
1189
+ rb_shape_verify_consistency (VALUE obj , shape_id_t shape_id )
1190
+ {
1191
+ rb_shape_t * shape = RSHAPE (shape_id );
1192
+
1193
+ bool has_object_id = false;
1194
+ while (shape -> parent_id != INVALID_SHAPE_ID ) {
1195
+ if (shape -> type == SHAPE_OBJ_ID ) {
1196
+ has_object_id = true;
1197
+ break ;
1198
+ }
1199
+ shape = RSHAPE (shape -> parent_id );
1200
+ }
1201
+
1202
+ if (rb_shape_has_object_id (shape_id )) {
1203
+ if (!has_object_id ) {
1204
+ rb_p (obj );
1205
+ rb_bug ("shape_id claim having obj_id but doesn't shape_id=%u, obj=%s" , shape_id , rb_obj_info (obj ));
1206
+ }
1207
+ }
1208
+ else {
1209
+ if (has_object_id ) {
1210
+ rb_p (obj );
1211
+ rb_bug ("shape_id claim not having obj_id but it does shape_id=%u, obj=%s" , shape_id , rb_obj_info (obj ));
1212
+ }
1213
+ }
1214
+
1215
+ return true;
1216
+ }
1217
+ #endif
1218
+
1183
1219
#if SHAPE_DEBUG
1220
+
1184
1221
/*
1185
1222
* Exposing Shape to Ruby via RubyVM.debug_shape
1186
1223
*/
@@ -1203,8 +1240,7 @@ static VALUE
1203
1240
shape_has_object_id_p (VALUE self )
1204
1241
{
1205
1242
shape_id_t shape_id = NUM2INT (rb_struct_getmember (self , rb_intern ("id" )));
1206
- rb_shape_t * shape = RSHAPE (shape_id );
1207
- return RBOOL (shape_has_object_id (shape ));
1243
+ return RBOOL (rb_shape_has_object_id (shape_id ));
1208
1244
}
1209
1245
1210
1246
static VALUE
@@ -1441,6 +1477,13 @@ Init_default_shapes(void)
1441
1477
GET_SHAPE_TREE ()-> root_shape = root ;
1442
1478
RUBY_ASSERT (raw_shape_id (GET_SHAPE_TREE ()-> root_shape ) == ROOT_SHAPE_ID );
1443
1479
1480
+ rb_shape_t * root_with_obj_id = rb_shape_alloc_with_parent_id (0 , ROOT_SHAPE_ID );
1481
+ root_with_obj_id -> type = SHAPE_OBJ_ID ;
1482
+ root_with_obj_id -> edge_name = ruby_internal_object_id ;
1483
+ root_with_obj_id -> next_field_index ++ ;
1484
+ root_with_obj_id -> heap_index = 0 ;
1485
+ RUBY_ASSERT (raw_shape_id (root_with_obj_id ) == ROOT_SHAPE_WITH_OBJ_ID );
1486
+
1444
1487
// Make shapes for T_OBJECT
1445
1488
size_t * sizes = rb_gc_heap_sizes ();
1446
1489
for (int i = 0 ; sizes [i ] > 0 ; i ++ ) {
@@ -1489,7 +1532,6 @@ Init_shape(void)
1489
1532
rb_define_const (rb_cShape , "SHAPE_ID_NUM_BITS" , INT2NUM (SHAPE_ID_NUM_BITS ));
1490
1533
rb_define_const (rb_cShape , "SHAPE_FLAG_SHIFT" , INT2NUM (SHAPE_FLAG_SHIFT ));
1491
1534
rb_define_const (rb_cShape , "SPECIAL_CONST_SHAPE_ID" , INT2NUM (SPECIAL_CONST_SHAPE_ID ));
1492
- rb_define_const (rb_cShape , "ROOT_TOO_COMPLEX_SHAPE_ID" , INT2NUM (ROOT_TOO_COMPLEX_SHAPE_ID ));
1493
1535
rb_define_const (rb_cShape , "FIRST_T_OBJECT_SHAPE_ID" , INT2NUM (FIRST_T_OBJECT_SHAPE_ID ));
1494
1536
rb_define_const (rb_cShape , "SHAPE_MAX_VARIATIONS" , INT2NUM (SHAPE_MAX_VARIATIONS ));
1495
1537
rb_define_const (rb_cShape , "SIZEOF_RB_SHAPE_T" , INT2NUM (sizeof (rb_shape_t )));
0 commit comments