@@ -723,15 +723,67 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
723723 }
724724}
725725
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+
726762static inline shape_id_t
727763transition_complex (shape_id_t shape_id )
728764{
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+ }
731781 }
732- return ROOT_TOO_COMPLEX_SHAPE_ID | (shape_id & SHAPE_ID_FLAGS_MASK );
733- }
734782
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+ }
735787
736788shape_id_t
737789rb_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)
754806 else if (removed_shape ) {
755807 // We found the shape to remove, but couldn't create a new variation.
756808 // 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 ;
758812 }
759813 return original_shape_id ;
760814}
@@ -774,41 +828,6 @@ rb_shape_transition_complex(VALUE obj)
774828 return transition_complex (RBASIC_SHAPE_ID (obj ));
775829}
776830
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-
812831/*
813832 * This function is used for assertions where we don't want to increment
814833 * max_iv_count
@@ -918,7 +937,13 @@ rb_shape_transition_add_ivar(VALUE obj, ID id)
918937 shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
919938 RUBY_ASSERT (!shape_frozen_p (original_shape_id ));
920939
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+ }
922947}
923948
924949shape_id_t
@@ -927,7 +952,13 @@ rb_shape_transition_add_ivar_no_warnings(VALUE obj, ID id)
927952 shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
928953 RUBY_ASSERT (!shape_frozen_p (original_shape_id ));
929954
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+ }
931962}
932963
933964// 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)
11391170 RUBY_ASSERT (!rb_shape_too_complex_p (initial_shape_id ));
11401171 RUBY_ASSERT (!rb_shape_too_complex_p (dest_shape_id ));
11411172
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+ }
11431180}
11441181
11451182void
@@ -1217,6 +1254,10 @@ rb_shape_memsize(shape_id_t shape_id)
12171254bool
12181255rb_shape_verify_consistency (VALUE obj , shape_id_t shape_id )
12191256{
1257+ if (shape_id == INVALID_SHAPE_ID ) {
1258+ rb_bug ("Can't set INVALID_SHAPE_ID on an object" );
1259+ }
1260+
12201261 rb_shape_t * shape = RSHAPE (shape_id );
12211262
12221263 bool has_object_id = false;
@@ -1241,12 +1282,9 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
12411282 }
12421283 }
12431284
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 );
12501288 }
12511289
12521290 return true;
@@ -1537,7 +1575,8 @@ Init_default_shapes(void)
15371575
15381576 // Make shapes for T_OBJECT
15391577 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 ++ ) {
15411580 rb_shape_t * t_object_shape = rb_shape_alloc_with_parent_id (0 , INVALID_SHAPE_ID );
15421581 t_object_shape -> type = SHAPE_T_OBJECT ;
15431582 t_object_shape -> heap_index = i + 1 ;
@@ -1546,6 +1585,13 @@ Init_default_shapes(void)
15461585 t_object_shape -> ancestor_index = LEAF ;
15471586 RUBY_ASSERT (t_object_shape == RSHAPE (rb_shape_root (i )));
15481587 }
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+ }
15491595}
15501596
15511597void
0 commit comments