2020#define SHAPE_DEBUG (VM_CHECK_MODE > 0)
2121#endif
2222
23- #define ROOT_TOO_COMPLEX_SHAPE_ID 0x1
24-
2523#define REDBLACK_CACHE_SIZE (SHAPE_BUFFER_SIZE * 32)
2624
2725/* This depends on that the allocated memory by Ruby's allocator or
@@ -381,12 +379,6 @@ shape_frozen_p(shape_id_t shape_id)
381379}
382380#endif
383381
384- static inline bool
385- shape_too_complex_p (rb_shape_t * shape )
386- {
387- return shape -> flags & SHAPE_FL_TOO_COMPLEX ;
388- }
389-
390382void
391383rb_shape_each_shape_id (each_shape_callback callback , void * data )
392384{
@@ -531,7 +523,6 @@ rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type)
531523 redblack_cache_ancestors (new_shape );
532524 }
533525 break ;
534- case SHAPE_OBJ_TOO_COMPLEX :
535526 case SHAPE_ROOT :
536527 case SHAPE_T_OBJECT :
537528 rb_bug ("Unreachable" );
@@ -541,8 +532,6 @@ rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type)
541532 return new_shape ;
542533}
543534
544- static rb_shape_t * shape_transition_too_complex (rb_shape_t * original_shape );
545-
546535#define RUBY_ATOMIC_VALUE_LOAD (x ) (VALUE)(RUBY_ATOMIC_PTR_LOAD(x))
547536
548537static rb_shape_t *
@@ -581,7 +570,7 @@ get_next_shape_internal_atomic(rb_shape_t *shape, ID id, enum shape_type shape_t
581570 // If we're not allowed to create a new variation, of if we're out of shapes
582571 // we return TOO_COMPLEX_SHAPE.
583572 if (!new_variations_allowed || GET_SHAPE_TREE ()-> next_shape_id > MAX_SHAPE_ID ) {
584- res = shape_transition_too_complex ( shape ) ;
573+ res = NULL ;
585574 }
586575 else {
587576 VALUE new_edges = 0 ;
@@ -623,9 +612,6 @@ get_next_shape_internal_atomic(rb_shape_t *shape, ID id, enum shape_type shape_t
623612static rb_shape_t *
624613get_next_shape_internal (rb_shape_t * shape , ID id , enum shape_type shape_type , bool * variation_created , bool new_variations_allowed )
625614{
626- // There should never be outgoing edges from "too complex", except for SHAPE_OBJ_ID
627- RUBY_ASSERT (!shape_too_complex_p (shape ) || shape_type == SHAPE_OBJ_ID );
628-
629615 if (rb_multi_ractor_p ()) {
630616 return get_next_shape_internal_atomic (shape , id , shape_type , variation_created , new_variations_allowed );
631617 }
@@ -660,7 +646,7 @@ get_next_shape_internal(rb_shape_t *shape, ID id, enum shape_type shape_type, bo
660646 // If we're not allowed to create a new variation, of if we're out of shapes
661647 // we return TOO_COMPLEX_SHAPE.
662648 if (!new_variations_allowed || GET_SHAPE_TREE ()-> next_shape_id > MAX_SHAPE_ID ) {
663- res = shape_transition_too_complex ( shape ) ;
649+ res = NULL ;
664650 }
665651 else {
666652 rb_shape_t * new_shape = rb_shape_alloc_new_child (id , shape , shape_type );
@@ -695,6 +681,7 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
695681 if (shape -> parent_id == INVALID_SHAPE_ID ) {
696682 // We've hit the top of the shape tree and couldn't find the
697683 // IV we wanted to remove, so return NULL
684+ * removed_shape = NULL ;
698685 return NULL ;
699686 }
700687 else {
@@ -710,23 +697,14 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
710697 // We found a new parent. Create a child of the new parent that
711698 // has the same attributes as this shape.
712699 if (new_parent ) {
713- if (UNLIKELY (shape_too_complex_p (new_parent ))) {
714- return new_parent ;
715- }
716-
717700 bool dont_care ;
718701 rb_shape_t * new_child = get_next_shape_internal (new_parent , shape -> edge_name , shape -> type , & dont_care , true);
719- if (UNLIKELY (shape_too_complex_p (new_child ))) {
720- return new_child ;
721- }
722-
723- RUBY_ASSERT (new_child -> capacity <= shape -> capacity );
724-
702+ RUBY_ASSERT (!new_child || new_child -> capacity <= shape -> capacity );
725703 return new_child ;
726704 }
727705 else {
728706 // We went all the way to the top of the shape tree and couldn't
729- // find an IV to remove, so return NULL
707+ // find an IV to remove so return NULL.
730708 return NULL ;
731709 }
732710 }
@@ -736,19 +714,27 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
736714shape_id_t
737715rb_shape_transition_remove_ivar (VALUE obj , ID id , shape_id_t * removed_shape_id )
738716{
739- shape_id_t shape_id = rb_obj_shape_id (obj );
740- rb_shape_t * shape = RSHAPE (shape_id );
717+ shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
741718
742- RUBY_ASSERT (!shape_too_complex_p ( shape ));
743- RUBY_ASSERT (!shape_frozen_p (shape_id ));
719+ RUBY_ASSERT (!rb_shape_too_complex_p ( original_shape_id ));
720+ RUBY_ASSERT (!shape_frozen_p (original_shape_id ));
744721
745722 rb_shape_t * removed_shape = NULL ;
746- rb_shape_t * new_shape = remove_shape_recursive (shape , id , & removed_shape );
747- if (new_shape ) {
723+ rb_shape_t * new_shape = remove_shape_recursive (RSHAPE (original_shape_id ), id , & removed_shape );
724+
725+ if (removed_shape ) {
748726 * removed_shape_id = raw_shape_id (removed_shape );
749- return raw_shape_id (new_shape );
750727 }
751- return shape_id ;
728+
729+ if (new_shape ) {
730+ return shape_id (new_shape , original_shape_id );
731+ }
732+ else if (removed_shape ) {
733+ // We found the shape to remove, but couldn't create a new variation.
734+ // We must transition to TOO_COMPLEX.
735+ return ROOT_TOO_COMPLEX_SHAPE_ID | (original_shape_id & SHAPE_ID_FLAGS_MASK );
736+ }
737+ return original_shape_id ;
752738}
753739
754740shape_id_t
@@ -760,24 +746,11 @@ rb_shape_transition_frozen(VALUE obj)
760746 return shape_id | SHAPE_ID_FL_FROZEN ;
761747}
762748
763- static rb_shape_t *
764- shape_transition_too_complex (rb_shape_t * original_shape )
765- {
766- rb_shape_t * next_shape = RSHAPE (ROOT_TOO_COMPLEX_SHAPE_ID );
767-
768- if (original_shape -> flags & SHAPE_FL_HAS_OBJECT_ID ) {
769- bool dont_care ;
770- next_shape = get_next_shape_internal (next_shape , ruby_internal_object_id , SHAPE_OBJ_ID , & dont_care , false);
771- }
772-
773- return next_shape ;
774- }
775-
776749shape_id_t
777750rb_shape_transition_complex (VALUE obj )
778751{
779752 shape_id_t original_shape_id = RBASIC_SHAPE_ID (obj );
780- return shape_id ( shape_transition_too_complex ( RSHAPE ( original_shape_id )), original_shape_id );
753+ return ROOT_TOO_COMPLEX_SHAPE_ID | ( original_shape_id & SHAPE_ID_FLAGS_MASK );
781754}
782755
783756static inline bool
@@ -849,7 +822,6 @@ shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
849822 case SHAPE_ROOT :
850823 case SHAPE_T_OBJECT :
851824 return false;
852- case SHAPE_OBJ_TOO_COMPLEX :
853825 case SHAPE_OBJ_ID :
854826 rb_bug ("Ivar should not exist on transition" );
855827 }
@@ -865,9 +837,6 @@ static inline rb_shape_t *
865837shape_get_next (rb_shape_t * shape , VALUE obj , ID id , bool emit_warnings )
866838{
867839 RUBY_ASSERT (!is_instance_id (id ) || RTEST (rb_sym2str (ID2SYM (id ))));
868- if (UNLIKELY (shape_too_complex_p (shape ))) {
869- return shape ;
870- }
871840
872841#if RUBY_DEBUG
873842 attr_index_t index ;
@@ -891,6 +860,11 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
891860 bool variation_created = false;
892861 rb_shape_t * new_shape = get_next_shape_internal (shape , id , SHAPE_IVAR , & variation_created , allow_new_shape );
893862
863+ if (!new_shape ) {
864+ // We could create a new variation, transitioning to TOO_COMPLEX.
865+ return NULL ;
866+ }
867+
894868 // Check if we should update max_iv_count on the object's class
895869 if (obj != klass && new_shape -> next_field_index > RCLASS_MAX_IV_COUNT (klass )) {
896870 RCLASS_SET_MAX_IV_COUNT (klass , new_shape -> next_field_index );
@@ -1016,11 +990,11 @@ shape_cache_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
1016990bool
1017991rb_shape_get_iv_index (shape_id_t shape_id , ID id , attr_index_t * value )
1018992{
1019- rb_shape_t * shape = RSHAPE (shape_id );
1020-
1021993 // It doesn't make sense to ask for the index of an IV that's stored
1022994 // on an object that is "too complex" as it uses a hash for storing IVs
1023- RUBY_ASSERT (!shape_too_complex_p (shape ));
995+ RUBY_ASSERT (!rb_shape_too_complex_p (shape_id ));
996+
997+ rb_shape_t * shape = RSHAPE (shape_id );
1024998
1025999 if (!shape_cache_get_iv_index (shape , id , value )) {
10261000 // If it wasn't in the ancestor cache, then don't do a linear search
@@ -1083,9 +1057,6 @@ shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
10831057 case SHAPE_ROOT :
10841058 case SHAPE_T_OBJECT :
10851059 break ;
1086- case SHAPE_OBJ_TOO_COMPLEX :
1087- rb_bug ("Unreachable" );
1088- break ;
10891060 }
10901061
10911062 return next_shape ;
@@ -1102,20 +1073,17 @@ rb_shape_traverse_from_new_root(shape_id_t initial_shape_id, shape_id_t dest_sha
11021073// Rebuild a similar shape with the same ivars but starting from
11031074// a different SHAPE_T_OBJECT, and don't cary over non-canonical transitions
11041075// such as SHAPE_OBJ_ID.
1105- rb_shape_t *
1106- rb_shape_rebuild_shape (rb_shape_t * initial_shape , rb_shape_t * dest_shape )
1076+ static rb_shape_t *
1077+ shape_rebuild (rb_shape_t * initial_shape , rb_shape_t * dest_shape )
11071078{
1108- RUBY_ASSERT (raw_shape_id (initial_shape ) != ROOT_TOO_COMPLEX_SHAPE_ID );
1109- RUBY_ASSERT (raw_shape_id (dest_shape ) != ROOT_TOO_COMPLEX_SHAPE_ID );
1110-
11111079 rb_shape_t * midway_shape ;
11121080
11131081 RUBY_ASSERT (initial_shape -> type == SHAPE_T_OBJECT || initial_shape -> type == SHAPE_ROOT );
11141082
11151083 if (dest_shape -> type != initial_shape -> type ) {
1116- midway_shape = rb_shape_rebuild_shape (initial_shape , RSHAPE (dest_shape -> parent_id ));
1117- if (UNLIKELY (raw_shape_id ( midway_shape ) == ROOT_TOO_COMPLEX_SHAPE_ID )) {
1118- return midway_shape ;
1084+ midway_shape = shape_rebuild (initial_shape , RSHAPE (dest_shape -> parent_id ));
1085+ if (UNLIKELY (! midway_shape )) {
1086+ return NULL ;
11191087 }
11201088 }
11211089 else {
@@ -1130,9 +1098,6 @@ rb_shape_rebuild_shape(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
11301098 case SHAPE_ROOT :
11311099 case SHAPE_T_OBJECT :
11321100 break ;
1133- case SHAPE_OBJ_TOO_COMPLEX :
1134- rb_bug ("Unreachable" );
1135- break ;
11361101 }
11371102
11381103 return midway_shape ;
@@ -1141,7 +1106,10 @@ rb_shape_rebuild_shape(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
11411106shape_id_t
11421107rb_shape_rebuild (shape_id_t initial_shape_id , shape_id_t dest_shape_id )
11431108{
1144- return raw_shape_id (rb_shape_rebuild_shape (RSHAPE (initial_shape_id ), RSHAPE (dest_shape_id )));
1109+ RUBY_ASSERT (!rb_shape_too_complex_p (initial_shape_id ));
1110+ RUBY_ASSERT (!rb_shape_too_complex_p (dest_shape_id ));
1111+
1112+ return raw_shape_id (shape_rebuild (RSHAPE (initial_shape_id ), RSHAPE (dest_shape_id )));
11451113}
11461114
11471115void
@@ -1185,18 +1153,6 @@ rb_shape_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_t
11851153 rb_obj_init_too_complex (dest , table );
11861154}
11871155
1188- RUBY_FUNC_EXPORTED bool
1189- rb_shape_obj_too_complex_p (VALUE obj )
1190- {
1191- return shape_too_complex_p (obj_shape (obj ));
1192- }
1193-
1194- bool
1195- rb_shape_too_complex_p (shape_id_t shape_id )
1196- {
1197- return shape_too_complex_p (RSHAPE (shape_id ));
1198- }
1199-
12001156size_t
12011157rb_shape_edges_count (shape_id_t shape_id )
12021158{
@@ -1233,8 +1189,7 @@ static VALUE
12331189shape_too_complex (VALUE self )
12341190{
12351191 shape_id_t shape_id = NUM2INT (rb_struct_getmember (self , rb_intern ("id" )));
1236- rb_shape_t * shape = RSHAPE (shape_id );
1237- return RBOOL (shape_too_complex_p (shape ));
1192+ return RBOOL (rb_shape_too_complex_p (shape_id ));
12381193}
12391194
12401195static VALUE
@@ -1486,13 +1441,6 @@ Init_default_shapes(void)
14861441 GET_SHAPE_TREE ()-> root_shape = root ;
14871442 RUBY_ASSERT (raw_shape_id (GET_SHAPE_TREE ()-> root_shape ) == ROOT_SHAPE_ID );
14881443
1489- bool dont_care ;
1490- rb_shape_t * too_complex_shape = rb_shape_alloc_with_parent_id (0 , ROOT_SHAPE_ID );
1491- too_complex_shape -> type = SHAPE_OBJ_TOO_COMPLEX ;
1492- too_complex_shape -> flags |= SHAPE_FL_TOO_COMPLEX ;
1493- too_complex_shape -> heap_index = 0 ;
1494- RUBY_ASSERT (too_complex_shape == RSHAPE (ROOT_TOO_COMPLEX_SHAPE_ID ));
1495-
14961444 // Make shapes for T_OBJECT
14971445 size_t * sizes = rb_gc_heap_sizes ();
14981446 for (int i = 0 ; sizes [i ] > 0 ; i ++ ) {
@@ -1504,10 +1452,6 @@ Init_default_shapes(void)
15041452 t_object_shape -> ancestor_index = LEAF ;
15051453 RUBY_ASSERT (t_object_shape == RSHAPE (rb_shape_root (i )));
15061454 }
1507-
1508- // Prebuild TOO_COMPLEX variations so that they already exist if we ever need them after we
1509- // ran out of shapes.
1510- get_next_shape_internal (too_complex_shape , ruby_internal_object_id , SHAPE_OBJ_ID , & dont_care , true);
15111455}
15121456
15131457void
0 commit comments