@@ -723,15 +723,67 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
723
723
}
724
724
}
725
725
726
+
727
+ static shape_id_t
728
+ shape_transition_object_id (shape_id_t original_shape_id )
729
+ {
730
+ RUBY_ASSERT (!rb_shape_has_object_id (original_shape_id ));
731
+
732
+ bool dont_care ;
733
+ rb_shape_t * shape = get_next_shape_internal (RSHAPE (original_shape_id ), ruby_internal_object_id , SHAPE_OBJ_ID , & dont_care , true);
734
+
735
+ RUBY_ASSERT (shape );
736
+
737
+ return shape_id (shape , original_shape_id ) | SHAPE_ID_FL_HAS_OBJECT_ID ;
738
+ }
739
+
740
+ shape_id_t
741
+ rb_shape_transition_object_id (VALUE obj )
742
+ {
743
+ return shape_transition_object_id (RBASIC_SHAPE_ID (obj ));
744
+ }
745
+
746
+ shape_id_t
747
+ rb_shape_object_id (shape_id_t original_shape_id )
748
+ {
749
+ RUBY_ASSERT (rb_shape_has_object_id (original_shape_id ));
750
+
751
+ rb_shape_t * shape = RSHAPE (original_shape_id );
752
+ while (shape -> type != SHAPE_OBJ_ID ) {
753
+ if (UNLIKELY (shape -> parent_id == INVALID_SHAPE_ID )) {
754
+ rb_bug ("Missing object_id in shape tree" );
755
+ }
756
+ shape = RSHAPE (shape -> parent_id );
757
+ }
758
+
759
+ return shape_id (shape , original_shape_id ) | SHAPE_ID_FL_HAS_OBJECT_ID ;
760
+ }
761
+
726
762
static inline shape_id_t
727
763
transition_complex (shape_id_t shape_id )
728
764
{
729
- if (rb_shape_has_object_id (shape_id )) {
730
- return ROOT_TOO_COMPLEX_WITH_OBJ_ID | (shape_id & SHAPE_ID_FLAGS_MASK );
765
+ uint8_t heap_index = RSHAPE (shape_id )-> heap_index ;
766
+ shape_id_t next_shape_id ;
767
+
768
+ if (heap_index ) {
769
+ next_shape_id = rb_shape_root (heap_index - 1 ) | SHAPE_ID_FL_TOO_COMPLEX ;
770
+ if (rb_shape_has_object_id (shape_id )) {
771
+ next_shape_id = shape_transition_object_id (next_shape_id );
772
+ }
773
+ }
774
+ else {
775
+ if (rb_shape_has_object_id (shape_id )) {
776
+ next_shape_id = ROOT_TOO_COMPLEX_WITH_OBJ_ID | (shape_id & SHAPE_ID_FLAGS_MASK );
777
+ }
778
+ else {
779
+ next_shape_id = ROOT_TOO_COMPLEX_SHAPE_ID | (shape_id & SHAPE_ID_FLAGS_MASK );
780
+ }
731
781
}
732
- return ROOT_TOO_COMPLEX_SHAPE_ID | (shape_id & SHAPE_ID_FLAGS_MASK );
733
- }
734
782
783
+ RUBY_ASSERT (rb_shape_has_object_id (shape_id ) == rb_shape_has_object_id (next_shape_id ));
784
+
785
+ return next_shape_id ;
786
+ }
735
787
736
788
shape_id_t
737
789
rb_shape_transition_remove_ivar (VALUE obj , ID id , shape_id_t * removed_shape_id )
@@ -754,7 +806,9 @@ rb_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id)
754
806
else if (removed_shape ) {
755
807
// We found the shape to remove, but couldn't create a new variation.
756
808
// We must transition to TOO_COMPLEX.
757
- return transition_complex (original_shape_id );
809
+ shape_id_t next_shape_id = transition_complex (original_shape_id );
810
+ RUBY_ASSERT (rb_shape_has_object_id (next_shape_id ) == rb_shape_has_object_id (original_shape_id ));
811
+ return next_shape_id ;
758
812
}
759
813
return original_shape_id ;
760
814
}
@@ -774,41 +828,6 @@ rb_shape_transition_complex(VALUE obj)
774
828
return transition_complex (RBASIC_SHAPE_ID (obj ));
775
829
}
776
830
777
- shape_id_t
778
- rb_shape_transition_object_id (VALUE obj )
779
- {
780
- shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
781
-
782
- RUBY_ASSERT (!rb_shape_has_object_id (original_shape_id ));
783
-
784
- rb_shape_t * shape = NULL ;
785
- if (!rb_shape_too_complex_p (original_shape_id )) {
786
- bool dont_care ;
787
- shape = get_next_shape_internal (RSHAPE (original_shape_id ), ruby_internal_object_id , SHAPE_OBJ_ID , & dont_care , true);
788
- }
789
-
790
- if (!shape ) {
791
- shape = RSHAPE (ROOT_TOO_COMPLEX_WITH_OBJ_ID );
792
- }
793
- return shape_id (shape , original_shape_id ) | SHAPE_ID_FL_HAS_OBJECT_ID ;
794
- }
795
-
796
- shape_id_t
797
- rb_shape_object_id (shape_id_t original_shape_id )
798
- {
799
- RUBY_ASSERT (rb_shape_has_object_id (original_shape_id ));
800
-
801
- rb_shape_t * shape = RSHAPE (original_shape_id );
802
- while (shape -> type != SHAPE_OBJ_ID ) {
803
- if (UNLIKELY (shape -> parent_id == INVALID_SHAPE_ID )) {
804
- rb_bug ("Missing object_id in shape tree" );
805
- }
806
- shape = RSHAPE (shape -> parent_id );
807
- }
808
-
809
- return shape_id (shape , original_shape_id ) | SHAPE_ID_FL_HAS_OBJECT_ID ;
810
- }
811
-
812
831
/*
813
832
* This function is used for assertions where we don't want to increment
814
833
* max_iv_count
@@ -918,7 +937,13 @@ rb_shape_transition_add_ivar(VALUE obj, ID id)
918
937
shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
919
938
RUBY_ASSERT (!shape_frozen_p (original_shape_id ));
920
939
921
- return shape_id (shape_get_next (RSHAPE (original_shape_id ), obj , id , true), original_shape_id );
940
+ rb_shape_t * next_shape = shape_get_next (RSHAPE (original_shape_id ), obj , id , true);
941
+ if (next_shape ) {
942
+ return shape_id (next_shape , original_shape_id );
943
+ }
944
+ else {
945
+ return transition_complex (original_shape_id );
946
+ }
922
947
}
923
948
924
949
shape_id_t
@@ -927,7 +952,13 @@ rb_shape_transition_add_ivar_no_warnings(VALUE obj, ID id)
927
952
shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
928
953
RUBY_ASSERT (!shape_frozen_p (original_shape_id ));
929
954
930
- return shape_id (shape_get_next (RSHAPE (original_shape_id ), obj , id , false), original_shape_id );
955
+ rb_shape_t * next_shape = shape_get_next (RSHAPE (original_shape_id ), obj , id , false);
956
+ if (next_shape ) {
957
+ return shape_id (next_shape , original_shape_id );
958
+ }
959
+ else {
960
+ return transition_complex (original_shape_id );
961
+ }
931
962
}
932
963
933
964
// Same as rb_shape_get_iv_index, but uses a provided valid shape id and index
@@ -1139,7 +1170,13 @@ rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id)
1139
1170
RUBY_ASSERT (!rb_shape_too_complex_p (initial_shape_id ));
1140
1171
RUBY_ASSERT (!rb_shape_too_complex_p (dest_shape_id ));
1141
1172
1142
- return shape_id (shape_rebuild (RSHAPE (initial_shape_id ), RSHAPE (dest_shape_id )), initial_shape_id );
1173
+ rb_shape_t * next_shape = shape_rebuild (RSHAPE (initial_shape_id ), RSHAPE (dest_shape_id ));
1174
+ if (next_shape ) {
1175
+ return shape_id (next_shape , initial_shape_id );
1176
+ }
1177
+ else {
1178
+ return transition_complex (initial_shape_id | (dest_shape_id & SHAPE_ID_FL_HAS_OBJECT_ID ));
1179
+ }
1143
1180
}
1144
1181
1145
1182
void
@@ -1217,6 +1254,10 @@ rb_shape_memsize(shape_id_t shape_id)
1217
1254
bool
1218
1255
rb_shape_verify_consistency (VALUE obj , shape_id_t shape_id )
1219
1256
{
1257
+ if (shape_id == INVALID_SHAPE_ID ) {
1258
+ rb_bug ("Can't set INVALID_SHAPE_ID on an object" );
1259
+ }
1260
+
1220
1261
rb_shape_t * shape = RSHAPE (shape_id );
1221
1262
1222
1263
bool has_object_id = false;
@@ -1241,12 +1282,9 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
1241
1282
}
1242
1283
}
1243
1284
1244
- // All complex shape are in heap_index=0, it's a limitation
1245
- if (!rb_shape_too_complex_p (shape_id )) {
1246
- uint8_t flags_heap_index = rb_shape_heap_index (shape_id );
1247
- if (flags_heap_index != shape -> heap_index ) {
1248
- rb_bug ("shape_id heap_index flags mismatch: flags=%u, transition=%u\n" , flags_heap_index , shape -> heap_index );
1249
- }
1285
+ uint8_t flags_heap_index = rb_shape_heap_index (shape_id );
1286
+ if (flags_heap_index != shape -> heap_index ) {
1287
+ rb_bug ("shape_id heap_index flags mismatch: flags=%u, transition=%u\n" , flags_heap_index , shape -> heap_index );
1250
1288
}
1251
1289
1252
1290
return true;
@@ -1537,7 +1575,8 @@ Init_default_shapes(void)
1537
1575
1538
1576
// Make shapes for T_OBJECT
1539
1577
size_t * sizes = rb_gc_heap_sizes ();
1540
- for (int i = 0 ; sizes [i ] > 0 ; i ++ ) {
1578
+ int i ;
1579
+ for (i = 0 ; sizes [i ] > 0 ; i ++ ) {
1541
1580
rb_shape_t * t_object_shape = rb_shape_alloc_with_parent_id (0 , INVALID_SHAPE_ID );
1542
1581
t_object_shape -> type = SHAPE_T_OBJECT ;
1543
1582
t_object_shape -> heap_index = i + 1 ;
@@ -1546,6 +1585,13 @@ Init_default_shapes(void)
1546
1585
t_object_shape -> ancestor_index = LEAF ;
1547
1586
RUBY_ASSERT (t_object_shape == RSHAPE (rb_shape_root (i )));
1548
1587
}
1588
+
1589
+ // Prebuild all ROOT + OBJ_ID shapes so that even when we run out of shape we can always transtion to
1590
+ // COMPLEX + OBJ_ID.
1591
+ bool dont_care ;
1592
+ for (i = 0 ; sizes [i ] > 0 ; i ++ ) {
1593
+ get_next_shape_internal (RSHAPE (rb_shape_root (i )), ruby_internal_object_id , SHAPE_OBJ_ID , & dont_care , true);
1594
+ }
1549
1595
}
1550
1596
1551
1597
void
0 commit comments