3333#define MAX_SHAPE_ID (SHAPE_BUFFER_SIZE - 1)
3434#define ANCESTOR_SEARCH_MAX_DEPTH 2
3535
36- static ID id_object_id ;
36+ static ID id_object_id , id_old_address ;
3737
3838#define LEAF 0
3939#define BLACK 0x0
@@ -504,6 +504,7 @@ rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type)
504504
505505 switch (shape_type ) {
506506 case SHAPE_OBJ_ID :
507+ case SHAPE_OLD_ADDRESS :
507508 case SHAPE_IVAR :
508509 if (UNLIKELY (shape -> next_field_index >= shape -> capacity )) {
509510 RUBY_ASSERT (shape -> next_field_index == shape -> capacity );
@@ -725,6 +726,21 @@ rb_shape_transition_object_id(VALUE obj)
725726 return shape_transition_object_id (RBASIC_SHAPE_ID (obj ));
726727}
727728
729+ shape_id_t
730+ rb_shape_transition_old_address (shape_id_t original_shape_id )
731+ {
732+ RUBY_ASSERT (!rb_shape_has_old_address (original_shape_id ));
733+
734+ bool dont_care ;
735+ rb_shape_t * shape = get_next_shape_internal (RSHAPE (original_shape_id ), id_old_address , SHAPE_OLD_ADDRESS , & dont_care , true);
736+ if (!shape ) {
737+ shape = RSHAPE (ROOT_SHAPE_WITH_OLD_ADDRESS );
738+ }
739+
740+ RUBY_ASSERT (shape );
741+ return shape_id (shape , original_shape_id ) | SHAPE_ID_FL_HAS_OLD_ADDRESS ;
742+ }
743+
728744shape_id_t
729745rb_shape_object_id (shape_id_t original_shape_id )
730746{
@@ -741,6 +757,22 @@ rb_shape_object_id(shape_id_t original_shape_id)
741757 return shape_id (shape , original_shape_id ) | SHAPE_ID_FL_HAS_OBJECT_ID ;
742758}
743759
760+ shape_id_t
761+ rb_shape_old_address (shape_id_t original_shape_id )
762+ {
763+ RUBY_ASSERT (rb_shape_has_old_address (original_shape_id ));
764+
765+ rb_shape_t * shape = RSHAPE (original_shape_id );
766+ while (shape -> type != SHAPE_OLD_ADDRESS ) {
767+ if (UNLIKELY (shape -> parent_id == INVALID_SHAPE_ID )) {
768+ rb_bug ("Missing old_address in shape tree" );
769+ }
770+ shape = RSHAPE (shape -> parent_id );
771+ }
772+
773+ return shape_id (shape , original_shape_id ) | SHAPE_ID_FL_HAS_OLD_ADDRESS ;
774+ }
775+
744776static inline shape_id_t
745777transition_complex (shape_id_t shape_id )
746778{
@@ -860,6 +892,7 @@ shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
860892 case SHAPE_ROOT :
861893 return false;
862894 case SHAPE_OBJ_ID :
895+ case SHAPE_OLD_ADDRESS :
863896 rb_bug ("Ivar should not exist on transition" );
864897 }
865898 }
@@ -1111,6 +1144,7 @@ shape_rebuild(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
11111144 midway_shape = shape_get_next_iv_shape (midway_shape , dest_shape -> edge_name );
11121145 break ;
11131146 case SHAPE_OBJ_ID :
1147+ case SHAPE_OLD_ADDRESS :
11141148 case SHAPE_ROOT :
11151149 break ;
11161150 }
@@ -1242,11 +1276,16 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
12421276 rb_shape_t * shape = RSHAPE (shape_id );
12431277
12441278 bool has_object_id = false;
1279+ bool has_old_address = false;
1280+
12451281 while (shape -> parent_id != INVALID_SHAPE_ID ) {
12461282 if (shape -> type == SHAPE_OBJ_ID ) {
12471283 has_object_id = true;
1248- break ;
12491284 }
1285+ else if (shape -> type == SHAPE_OLD_ADDRESS ) {
1286+ has_old_address = true;
1287+ }
1288+
12501289 shape = RSHAPE (shape -> parent_id );
12511290 }
12521291
@@ -1263,6 +1302,19 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
12631302 }
12641303 }
12651304
1305+ if (rb_shape_has_old_address (shape_id )) {
1306+ if (!has_old_address ) {
1307+ rb_p (obj );
1308+ rb_bug ("shape_id claim having has_old_address but doesn't shape_id=%u, obj=%s" , shape_id , rb_obj_info (obj ));
1309+ }
1310+ }
1311+ else {
1312+ if (has_old_address ) {
1313+ rb_p (obj );
1314+ rb_bug ("shape_id claim not having has_old_address but it does shape_id=%u, obj=%s" , shape_id , rb_obj_info (obj ));
1315+ }
1316+ }
1317+
12661318 // Make sure SHAPE_ID_HAS_IVAR_MASK is valid.
12671319 if (rb_shape_too_complex_p (shape_id )) {
12681320 RUBY_ASSERT (shape_id & SHAPE_ID_HAS_IVAR_MASK );
@@ -1272,6 +1324,11 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
12721324 if (has_object_id ) {
12731325 ivar_count -- ;
12741326 }
1327+
1328+ if (has_old_address ) {
1329+ ivar_count -- ;
1330+ }
1331+
12751332 if (ivar_count ) {
12761333 RUBY_ASSERT (shape_id & SHAPE_ID_HAS_IVAR_MASK );
12771334 }
@@ -1543,6 +1600,7 @@ Init_default_shapes(void)
15431600 }
15441601
15451602 id_object_id = rb_make_internal_id ();
1603+ id_old_address = rb_make_internal_id ();
15461604
15471605#ifdef HAVE_MMAP
15481606 size_t shape_cache_mmap_size = rb_size_mul_or_raise (REDBLACK_CACHE_SIZE , sizeof (redblack_node_t ), rb_eRuntimeError );
@@ -1581,6 +1639,22 @@ Init_default_shapes(void)
15811639 RUBY_ASSERT (root_with_obj_id -> next_field_index == 1 );
15821640 RUBY_ASSERT (!(raw_shape_id (root_with_obj_id ) & SHAPE_ID_HAS_IVAR_MASK ));
15831641 (void )root_with_obj_id ;
1642+
1643+ rb_shape_t * root_with_old_address = get_next_shape_internal (root , id_old_address , SHAPE_OLD_ADDRESS , & dontcare , true);
1644+ RUBY_ASSERT (raw_shape_id (root_with_old_address ) == ROOT_SHAPE_WITH_OLD_ADDRESS );
1645+ RUBY_ASSERT (root_with_old_address -> type == SHAPE_OLD_ADDRESS );
1646+ RUBY_ASSERT (root_with_old_address -> edge_name == id_old_address );
1647+ RUBY_ASSERT (root_with_old_address -> next_field_index == 1 );
1648+ RUBY_ASSERT (!(raw_shape_id (root_with_obj_id ) & SHAPE_ID_HAS_IVAR_MASK ));
1649+ (void )root_with_old_address ;
1650+
1651+ rb_shape_t * root_with_obj_id_and_old_address = get_next_shape_internal (root_with_obj_id , id_old_address , SHAPE_OLD_ADDRESS , & dontcare , true);
1652+ RUBY_ASSERT (raw_shape_id (root_with_obj_id_and_old_address ) == ROOT_SHAPE_WITH_OBJ_ID_AND_OLD_ADDRESS );
1653+ RUBY_ASSERT (root_with_obj_id_and_old_address -> type == SHAPE_OLD_ADDRESS );
1654+ RUBY_ASSERT (root_with_obj_id_and_old_address -> edge_name == id_old_address );
1655+ RUBY_ASSERT (root_with_obj_id_and_old_address -> next_field_index == 2 );
1656+ RUBY_ASSERT (!(raw_shape_id (root_with_obj_id_and_old_address ) & SHAPE_ID_HAS_IVAR_MASK ));
1657+ (void )root_with_obj_id_and_old_address ;
15841658}
15851659
15861660void
0 commit comments