@@ -1542,11 +1542,68 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
15421542 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR (id );
15431543 }
15441544
1545- if (!rb_shape_transition_remove_ivar (obj , id , & val )) {
1546- if (!rb_shape_obj_too_complex_p (obj )) {
1547- rb_evict_fields_to_hash (obj );
1548- }
1545+ shape_id_t old_shape_id = rb_obj_shape_id (obj );
1546+ if (rb_shape_id_too_complex_p (old_shape_id )) {
1547+ goto too_complex ;
1548+ }
1549+
1550+ shape_id_t removed_shape_id = 0 ;
1551+ shape_id_t next_shape_id = rb_shape_transition_remove_ivar (obj , id , & removed_shape_id );
1552+
1553+ if (next_shape_id == old_shape_id ) {
1554+ return undef ;
1555+ }
1556+
1557+ if (UNLIKELY (rb_shape_id_too_complex_p (next_shape_id ))) {
1558+ rb_evict_fields_to_hash (obj );
1559+ goto too_complex ;
1560+ }
1561+
1562+ RUBY_ASSERT (RSHAPE (next_shape_id )-> next_field_index == RSHAPE (old_shape_id )-> next_field_index - 1 );
1563+
1564+ VALUE * fields ;
1565+ switch (BUILTIN_TYPE (obj )) {
1566+ case T_CLASS :
1567+ case T_MODULE :
1568+ fields = RCLASS_PRIME_FIELDS (obj );
1569+ break ;
1570+ case T_OBJECT :
1571+ fields = ROBJECT_FIELDS (obj );
1572+ break ;
1573+ default : {
1574+ struct gen_fields_tbl * fields_tbl ;
1575+ rb_gen_fields_tbl_get (obj , id , & fields_tbl );
1576+ fields = fields_tbl -> as .shape .fields ;
1577+ break ;
1578+ }
1579+ }
1580+
1581+ RUBY_ASSERT (removed_shape_id != INVALID_SHAPE_ID );
1582+
1583+ attr_index_t new_fields_count = RSHAPE (next_shape_id )-> next_field_index ;
1584+
1585+ attr_index_t removed_index = RSHAPE (removed_shape_id )-> next_field_index - 1 ;
1586+ val = fields [removed_index ];
1587+ size_t trailing_fields = new_fields_count - removed_index ;
15491588
1589+ MEMMOVE (& fields [removed_index ], & fields [removed_index + 1 ], VALUE , trailing_fields );
1590+
1591+ if (RB_TYPE_P (obj , T_OBJECT ) &&
1592+ !RB_FL_TEST_RAW (obj , ROBJECT_EMBED ) &&
1593+ rb_obj_embedded_size (new_fields_count ) <= rb_gc_obj_slot_size (obj )) {
1594+ // Re-embed objects when instances become small enough
1595+ // This is necessary because YJIT assumes that objects with the same shape
1596+ // have the same embeddedness for efficiency (avoid extra checks)
1597+ RB_FL_SET_RAW (obj , ROBJECT_EMBED );
1598+ MEMCPY (ROBJECT_FIELDS (obj ), fields , VALUE , new_fields_count );
1599+ xfree (fields );
1600+ }
1601+ rb_shape_set_shape_id (obj , next_shape_id );
1602+
1603+ return val ;
1604+
1605+ too_complex :
1606+ {
15501607 st_table * table = NULL ;
15511608 switch (BUILTIN_TYPE (obj )) {
15521609 case T_CLASS :
@@ -1573,7 +1630,6 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
15731630 }
15741631 }
15751632 }
1576-
15771633 return val ;
15781634}
15791635
0 commit comments