@@ -304,14 +304,7 @@ shape_tree_mark(void *data)
304304 rb_shape_t * end = RSHAPE (GET_SHAPE_TREE ()-> next_shape_id - 1 );
305305 while (cursor < end ) {
306306 if (cursor -> edges && !SINGLE_CHILD_P (cursor -> edges )) {
307- // FIXME: GC compaction may call `rb_shape_traverse_from_new_root`
308- // to migrate objects from one object slot to another.
309- // Because of this if we don't pin `cursor->edges` it might be turned
310- // into a T_MOVED during GC.
311- // We'd need to eliminate `SHAPE_T_OBJECT` so that GC never need to lookup
312- // shapes this way.
313- // rb_gc_mark_movable(cursor->edges);
314- rb_gc_mark (cursor -> edges );
307+ rb_gc_mark_movable (cursor -> edges );
315308 }
316309 cursor ++ ;
317310 }
@@ -368,7 +361,16 @@ shape_id(rb_shape_t *shape, shape_id_t previous_shape_id)
368361 return INVALID_SHAPE_ID ;
369362 }
370363 shape_id_t raw_id = (shape_id_t )(shape - GET_SHAPE_TREE ()-> shape_list );
371- return raw_id | (previous_shape_id & SHAPE_ID_FLAGS_MASK );
364+ shape_id_t new_id = raw_id | (previous_shape_id & SHAPE_ID_FLAGS_MASK );
365+
366+ attr_index_t embed_capa = RSHAPE_EMBED_CAPA (previous_shape_id );
367+ if (embed_capa > shape -> next_field_index ) {
368+ new_id |= SHAPE_ID_FL_EMBEDDED ;
369+ }
370+ else {
371+ new_id &= ~SHAPE_ID_FL_EMBEDDED ;
372+ }
373+ return new_id ;
372374}
373375
374376#if RUBY_DEBUG
@@ -455,7 +457,6 @@ rb_shape_alloc(ID edge_name, rb_shape_t *parent, enum shape_type type)
455457{
456458 rb_shape_t * shape = rb_shape_alloc_with_parent_id (edge_name , raw_shape_id (parent ));
457459 shape -> type = (uint8_t )type ;
458- shape -> heap_index = parent -> heap_index ;
459460 shape -> capacity = parent -> capacity ;
460461 shape -> edges = 0 ;
461462 return shape ;
@@ -515,7 +516,6 @@ rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type)
515516 }
516517 break ;
517518 case SHAPE_ROOT :
518- case SHAPE_T_OBJECT :
519519 rb_bug ("Unreachable" );
520520 break ;
521521 }
@@ -743,7 +743,7 @@ rb_shape_transition_frozen(VALUE obj)
743743{
744744 RUBY_ASSERT (RB_OBJ_FROZEN (obj ));
745745
746- shape_id_t shape_id = rb_obj_shape_id (obj );
746+ shape_id_t shape_id = RBASIC_SHAPE_ID (obj );
747747 return shape_id | SHAPE_ID_FL_FROZEN ;
748748}
749749
@@ -753,6 +753,12 @@ rb_shape_transition_complex(VALUE obj)
753753 return transition_frozen (RBASIC_SHAPE_ID (obj ));
754754}
755755
756+ shape_id_t
757+ rb_shape_transition_heap (VALUE obj , size_t heap_index )
758+ {
759+ return (RBASIC_SHAPE_ID (obj ) & (~SHAPE_ID_HEAP_INDEX_MASK )) | rb_shape_root (heap_index );
760+ }
761+
756762shape_id_t
757763rb_shape_transition_object_id (VALUE obj )
758764{
@@ -822,7 +828,6 @@ shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
822828 * value = shape -> next_field_index - 1 ;
823829 return true;
824830 case SHAPE_ROOT :
825- case SHAPE_T_OBJECT :
826831 return false;
827832 case SHAPE_OBJ_ID :
828833 rb_bug ("Ivar should not exist on transition" );
@@ -1019,61 +1024,6 @@ rb_shape_id_offset(void)
10191024 return sizeof (uintptr_t ) - SHAPE_ID_NUM_BITS / sizeof (uintptr_t );
10201025}
10211026
1022- static rb_shape_t *
1023- shape_traverse_from_new_root (rb_shape_t * initial_shape , rb_shape_t * dest_shape )
1024- {
1025- RUBY_ASSERT (initial_shape -> type == SHAPE_T_OBJECT );
1026- rb_shape_t * next_shape = initial_shape ;
1027-
1028- if (dest_shape -> type != initial_shape -> type ) {
1029- next_shape = shape_traverse_from_new_root (initial_shape , RSHAPE (dest_shape -> parent_id ));
1030- if (!next_shape ) {
1031- return NULL ;
1032- }
1033- }
1034-
1035- switch ((enum shape_type )dest_shape -> type ) {
1036- case SHAPE_IVAR :
1037- case SHAPE_OBJ_ID :
1038- if (!next_shape -> edges ) {
1039- return NULL ;
1040- }
1041-
1042- VALUE lookup_result ;
1043- if (SINGLE_CHILD_P (next_shape -> edges )) {
1044- rb_shape_t * child = SINGLE_CHILD (next_shape -> edges );
1045- if (child -> edge_name == dest_shape -> edge_name ) {
1046- return child ;
1047- }
1048- else {
1049- return NULL ;
1050- }
1051- }
1052- else {
1053- if (rb_managed_id_table_lookup (next_shape -> edges , dest_shape -> edge_name , & lookup_result )) {
1054- next_shape = (rb_shape_t * )lookup_result ;
1055- }
1056- else {
1057- return NULL ;
1058- }
1059- }
1060- break ;
1061- case SHAPE_ROOT :
1062- case SHAPE_T_OBJECT :
1063- break ;
1064- }
1065-
1066- return next_shape ;
1067- }
1068-
1069- shape_id_t
1070- rb_shape_traverse_from_new_root (shape_id_t initial_shape_id , shape_id_t dest_shape_id )
1071- {
1072- rb_shape_t * initial_shape = RSHAPE (initial_shape_id );
1073- rb_shape_t * dest_shape = RSHAPE (dest_shape_id );
1074- return shape_id (shape_traverse_from_new_root (initial_shape , dest_shape ), dest_shape_id );
1075- }
1076-
10771027// Rebuild a similar shape with the same ivars but starting from
10781028// a different SHAPE_T_OBJECT, and don't cary over non-canonical transitions
10791029// such as SHAPE_OBJ_ID.
@@ -1082,7 +1032,7 @@ shape_rebuild(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
10821032{
10831033 rb_shape_t * midway_shape ;
10841034
1085- RUBY_ASSERT (initial_shape -> type == SHAPE_T_OBJECT || initial_shape -> type == SHAPE_ROOT );
1035+ RUBY_ASSERT (initial_shape -> type == SHAPE_ROOT );
10861036
10871037 if (dest_shape -> type != initial_shape -> type ) {
10881038 midway_shape = shape_rebuild (initial_shape , RSHAPE (dest_shape -> parent_id ));
@@ -1100,7 +1050,6 @@ shape_rebuild(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
11001050 break ;
11011051 case SHAPE_OBJ_ID :
11021052 case SHAPE_ROOT :
1103- case SHAPE_T_OBJECT :
11041053 break ;
11051054 }
11061055
@@ -1113,7 +1062,14 @@ rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id)
11131062 RUBY_ASSERT (!rb_shape_too_complex_p (initial_shape_id ));
11141063 RUBY_ASSERT (!rb_shape_too_complex_p (dest_shape_id ));
11151064
1116- return raw_shape_id (shape_rebuild (RSHAPE (initial_shape_id ), RSHAPE (dest_shape_id )));
1065+ if (rb_shape_has_object_id (dest_shape_id )) {
1066+ // The tree contains a SHAPE_OBJ_ID. We need to rebuild a need tree without it
1067+ return shape_id (shape_rebuild (RSHAPE (initial_shape_id ), RSHAPE (dest_shape_id )), initial_shape_id & ~SHAPE_ID_FL_NON_CANONICAL_MASK );
1068+ }
1069+ else {
1070+ // In the simple case we keep the tree from `dest_shape_id` and the flags from `initial_shape_id`.
1071+ return (dest_shape_id & ~SHAPE_ID_FLAGS_MASK ) | (initial_shape_id & SHAPE_ID_FLAGS_MASK );
1072+ }
11171073}
11181074
11191075void
@@ -1122,6 +1078,10 @@ rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALU
11221078 rb_shape_t * dest_shape = RSHAPE (dest_shape_id );
11231079 rb_shape_t * src_shape = RSHAPE (src_shape_id );
11241080
1081+ if (!dest_shape -> next_field_index ) {
1082+ return ;
1083+ }
1084+
11251085 if (src_shape -> next_field_index == dest_shape -> next_field_index ) {
11261086 // Happy path, we can just memcpy the ivptr content
11271087 MEMCPY (dest_buf , src_buf , VALUE , dest_shape -> next_field_index );
@@ -1135,6 +1095,9 @@ rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALU
11351095 while (src_shape -> parent_id != INVALID_SHAPE_ID ) {
11361096 if (src_shape -> type == SHAPE_IVAR ) {
11371097 while (dest_shape -> edge_name != src_shape -> edge_name ) {
1098+ if (UNLIKELY (dest_shape -> parent_id == INVALID_SHAPE_ID )) {
1099+ rb_bug ("Lost field %s" , rb_id2name (src_shape -> edge_name ));
1100+ }
11381101 dest_shape = RSHAPE (dest_shape -> parent_id );
11391102 }
11401103
@@ -1212,6 +1175,16 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
12121175 }
12131176 }
12141177
1178+ if (RB_TYPE_P (obj , T_OBJECT )) {
1179+ size_t slot_size = rb_gc_obj_slot_size (obj );
1180+ size_t real_embed_capa = (slot_size - sizeof (struct RBasic )) / sizeof (VALUE );
1181+ size_t shape_embed_capa = RSHAPE_EMBED_CAPA (shape_id );
1182+
1183+ if (real_embed_capa != shape_embed_capa ) {
1184+ rb_bug ("Expected real_embed_capa=%lu to match shape_embed_capa=%lu\n" , real_embed_capa , shape_embed_capa );
1185+ }
1186+ }
1187+
12151188 return true;
12161189}
12171190#endif
@@ -1259,13 +1232,15 @@ shape_id_t_to_rb_cShape(shape_id_t shape_id)
12591232{
12601233 VALUE rb_cShape = rb_const_get (rb_cRubyVM , rb_intern ("Shape" ));
12611234 rb_shape_t * shape = RSHAPE (shape_id );
1235+ size_t heap_index = rb_shape_heap_index (shape_id );
12621236
12631237 VALUE obj = rb_struct_new (rb_cShape ,
12641238 INT2NUM (shape_id ),
1239+ INT2NUM (shape_id & SHAPE_ID_OFFSET_MASK ),
12651240 INT2NUM (shape -> parent_id ),
12661241 rb_shape_edge_name (shape ),
12671242 INT2NUM (shape -> next_field_index ),
1268- INT2NUM ( shape -> heap_index ) ,
1243+ heap_index ? SIZET2NUM ( heap_index - 1 ) : Qnil ,
12691244 INT2NUM (shape -> type ),
12701245 INT2NUM (shape -> capacity ));
12711246 rb_obj_freeze (obj );
@@ -1473,28 +1448,15 @@ Init_default_shapes(void)
14731448 rb_shape_t * root = rb_shape_alloc_with_parent_id (0 , INVALID_SHAPE_ID );
14741449 root -> capacity = 0 ;
14751450 root -> type = SHAPE_ROOT ;
1476- root -> heap_index = 0 ;
14771451 GET_SHAPE_TREE ()-> root_shape = root ;
14781452 RUBY_ASSERT (raw_shape_id (GET_SHAPE_TREE ()-> root_shape ) == ROOT_SHAPE_ID );
14791453
14801454 rb_shape_t * root_with_obj_id = rb_shape_alloc_with_parent_id (0 , ROOT_SHAPE_ID );
14811455 root_with_obj_id -> type = SHAPE_OBJ_ID ;
14821456 root_with_obj_id -> edge_name = ruby_internal_object_id ;
14831457 root_with_obj_id -> next_field_index ++ ;
1484- root_with_obj_id -> heap_index = 0 ;
14851458 RUBY_ASSERT (raw_shape_id (root_with_obj_id ) == ROOT_SHAPE_WITH_OBJ_ID );
1486-
1487- // Make shapes for T_OBJECT
1488- size_t * sizes = rb_gc_heap_sizes ();
1489- for (int i = 0 ; sizes [i ] > 0 ; i ++ ) {
1490- rb_shape_t * t_object_shape = rb_shape_alloc_with_parent_id (0 , INVALID_SHAPE_ID );
1491- t_object_shape -> type = SHAPE_T_OBJECT ;
1492- t_object_shape -> heap_index = i ;
1493- t_object_shape -> capacity = (uint32_t )((sizes [i ] - offsetof(struct RObject , as .ary )) / sizeof (VALUE ));
1494- t_object_shape -> edges = rb_managed_id_table_new (256 );
1495- t_object_shape -> ancestor_index = LEAF ;
1496- RUBY_ASSERT (t_object_shape == RSHAPE (rb_shape_root (i )));
1497- }
1459+ RUBY_ASSERT (RSHAPE (ROOT_TOO_COMPLEX_WITH_OBJ_ID )-> type == SHAPE_OBJ_ID );
14981460}
14991461
15001462void
@@ -1511,6 +1473,7 @@ Init_shape(void)
15111473 * :nodoc: */
15121474 VALUE rb_cShape = rb_struct_define_under (rb_cRubyVM , "Shape" ,
15131475 "id" ,
1476+ "raw_id" ,
15141477 "parent_id" ,
15151478 "edge_name" ,
15161479 "next_field_index" ,
@@ -1528,11 +1491,9 @@ Init_shape(void)
15281491
15291492 rb_define_const (rb_cShape , "SHAPE_ROOT" , INT2NUM (SHAPE_ROOT ));
15301493 rb_define_const (rb_cShape , "SHAPE_IVAR" , INT2NUM (SHAPE_IVAR ));
1531- rb_define_const (rb_cShape , "SHAPE_T_OBJECT" , INT2NUM (SHAPE_T_OBJECT ));
15321494 rb_define_const (rb_cShape , "SHAPE_ID_NUM_BITS" , INT2NUM (SHAPE_ID_NUM_BITS ));
15331495 rb_define_const (rb_cShape , "SHAPE_FLAG_SHIFT" , INT2NUM (SHAPE_FLAG_SHIFT ));
15341496 rb_define_const (rb_cShape , "SPECIAL_CONST_SHAPE_ID" , INT2NUM (SPECIAL_CONST_SHAPE_ID ));
1535- rb_define_const (rb_cShape , "FIRST_T_OBJECT_SHAPE_ID" , INT2NUM (FIRST_T_OBJECT_SHAPE_ID ));
15361497 rb_define_const (rb_cShape , "SHAPE_MAX_VARIATIONS" , INT2NUM (SHAPE_MAX_VARIATIONS ));
15371498 rb_define_const (rb_cShape , "SIZEOF_RB_SHAPE_T" , INT2NUM (sizeof (rb_shape_t )));
15381499 rb_define_const (rb_cShape , "SIZEOF_REDBLACK_NODE_T" , INT2NUM (sizeof (redblack_node_t )));
0 commit comments