From d34c15054708c84e9d3305ede0752820b42ac498 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Mon, 21 Apr 2025 12:01:01 +0900 Subject: [PATCH] shape.c: refactor frozen shape to no longer be final This opens the door to store more informations in shapes, such as the `object_id` or object address in case it has been observed and the object has to be moved. --- object.c | 2 +- shape.c | 13 ++++++++++++- shape.h | 7 +++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/object.c b/object.c index 99ceb342f1..8d32d689af 100644 --- a/object.c +++ b/object.c @@ -358,7 +358,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj) rb_shape_t *initial_shape = rb_shape_get_shape(dest); - if (initial_shape->heap_index != src_shape->heap_index) { + if (initial_shape->heap_index != src_shape->heap_index || !rb_shape_canonical_p(src_shape)) { RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT); shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape); diff --git a/shape.c b/shape.c index 2a0fb4033f..13b803c55a 100644 --- a/shape.c +++ b/shape.c @@ -50,6 +50,12 @@ static ID id_t_object; #define BLACK 0x0 #define RED 0x1 +enum shape_flags { + SHAPE_FL_FROZEN = 1 << 0, + + SHAPE_FL_NON_CANONICAL_MASK = SHAPE_FL_FROZEN, +}; + static redblack_node_t * redblack_left(redblack_node_t *node) { @@ -418,6 +424,7 @@ rb_shape_alloc(ID edge_name, rb_shape_t *parent, enum shape_type type) { rb_shape_t *shape = rb_shape_alloc_with_parent_id(edge_name, rb_shape_id(parent)); shape->type = (uint8_t)type; + shape->flags = parent->flags; shape->heap_index = parent->heap_index; shape->capacity = parent->capacity; shape->edges = 0; @@ -478,6 +485,7 @@ rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type) break; case SHAPE_FROZEN: new_shape->next_field_index = shape->next_field_index; + new_shape->flags |= SHAPE_FL_FROZEN; break; case SHAPE_OBJ_TOO_COMPLEX: case SHAPE_ROOT: @@ -576,7 +584,7 @@ get_next_shape_internal(rb_shape_t *shape, ID id, enum shape_type shape_type, bo bool rb_shape_frozen_shape_p(rb_shape_t *shape) { - return SHAPE_FROZEN == (enum shape_type)shape->type; + return SHAPE_FL_FROZEN & shape->flags; } static rb_shape_t * @@ -975,6 +983,9 @@ rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shap return next_shape; } +// Rebuild a similar shape with the same ivars but starting from +// a different SHAPE_T_OBJECT, and don't cary over non-canonical transitions +// such as SHAPE_FROZEN. rb_shape_t * rb_shape_rebuild_shape(rb_shape_t *initial_shape, rb_shape_t *dest_shape) { diff --git a/shape.h b/shape.h index 39191a73eb..8dfa94e9bc 100644 --- a/shape.h +++ b/shape.h @@ -48,6 +48,7 @@ struct rb_shape { attr_index_t capacity; // Total capacity of the object with this shape uint8_t type; uint8_t heap_index; + uint8_t flags; shape_id_t parent_id; redblack_node_t *ancestor_index; }; @@ -171,6 +172,12 @@ rb_shape_t *rb_shape_get_next_no_warnings(rb_shape_t *shape, VALUE obj, ID id); rb_shape_t *rb_shape_rebuild_shape(rb_shape_t *initial_shape, rb_shape_t *dest_shape); +static inline bool +rb_shape_canonical_p(rb_shape_t *shape) +{ + return !shape->flags; +} + static inline uint32_t ROBJECT_FIELDS_CAPACITY(VALUE obj) {