Skip to content

Commit ef66b5b

Browse files
committed
Get rid of TOO_COMPLEX shape type
Complex shapes still exist, but it's now a `shape_id` bit flag rather than a materialized shape transition. This allows to check for complex shape without dereferencing the shape.
1 parent 675f335 commit ef66b5b

3 files changed

Lines changed: 25 additions & 24 deletions

File tree

gc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1897,7 +1897,8 @@ object_id0(VALUE obj)
18971897
{
18981898
VALUE id = Qfalse;
18991899

1900-
if (rb_shape_has_object_id(RBASIC_SHAPE_ID(obj))) {
1900+
shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1901+
if (rb_shape_has_object_id(shape_id)) {
19011902
shape_id_t object_id_shape_id = rb_shape_transition_object_id(obj);
19021903
id = rb_obj_field_get(obj, object_id_shape_id);
19031904
RUBY_ASSERT(id, "object_id missing");

shape.c

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,6 @@ rb_shape_alloc(ID edge_name, rb_shape_t *parent, enum shape_type type)
461461
{
462462
rb_shape_t *shape = rb_shape_alloc_with_parent_id(edge_name, raw_shape_id(parent));
463463
shape->type = (uint8_t)type;
464-
shape->flags = parent->flags;
465464
shape->heap_index = parent->heap_index;
466465
shape->capacity = parent->capacity;
467466
shape->edges = 0;
@@ -510,8 +509,6 @@ rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type)
510509

511510
switch (shape_type) {
512511
case SHAPE_OBJ_ID:
513-
new_shape->flags |= SHAPE_FL_HAS_OBJECT_ID;
514-
// fallthrough
515512
case SHAPE_IVAR:
516513
if (UNLIKELY(shape->next_field_index >= shape->capacity)) {
517514
RUBY_ASSERT(shape->next_field_index == shape->capacity);
@@ -753,18 +750,6 @@ rb_shape_transition_complex(VALUE obj)
753750
return ROOT_TOO_COMPLEX_SHAPE_ID | (original_shape_id & SHAPE_ID_FLAGS_MASK);
754751
}
755752

756-
static inline bool
757-
shape_has_object_id(rb_shape_t *shape)
758-
{
759-
return shape->flags & SHAPE_FL_HAS_OBJECT_ID;
760-
}
761-
762-
bool
763-
rb_shape_has_object_id(shape_id_t shape_id)
764-
{
765-
return shape_has_object_id(RSHAPE(shape_id));
766-
}
767-
768753
shape_id_t
769754
rb_shape_transition_object_id(VALUE obj)
770755
{
@@ -773,7 +758,11 @@ rb_shape_transition_object_id(VALUE obj)
773758
rb_shape_t* shape = RSHAPE(original_shape_id);
774759
RUBY_ASSERT(shape);
775760

776-
if (shape->flags & SHAPE_FL_HAS_OBJECT_ID) {
761+
if (rb_shape_has_object_id(original_shape_id)) {
762+
if (rb_shape_too_complex_p(original_shape_id)) {
763+
return ROOT_SHAPE_WITH_OBJ_ID | SHAPE_ID_FL_HAS_OBJECT_ID | SHAPE_ID_FL_TOO_COMPLEX;
764+
}
765+
777766
while (shape->type != SHAPE_OBJ_ID) {
778767
shape = RSHAPE(shape->parent_id);
779768
}
@@ -783,7 +772,7 @@ rb_shape_transition_object_id(VALUE obj)
783772
shape = get_next_shape_internal(shape, ruby_internal_object_id, SHAPE_OBJ_ID, &dont_care, true);
784773
}
785774
RUBY_ASSERT(shape);
786-
return shape_id(shape, original_shape_id);
775+
return shape_id(shape, original_shape_id) | SHAPE_ID_FL_HAS_OBJECT_ID;
787776
}
788777

789778
/*
@@ -1203,8 +1192,7 @@ static VALUE
12031192
shape_has_object_id_p(VALUE self)
12041193
{
12051194
shape_id_t shape_id = NUM2INT(rb_struct_getmember(self, rb_intern("id")));
1206-
rb_shape_t *shape = RSHAPE(shape_id);
1207-
return RBOOL(shape_has_object_id(shape));
1195+
return RBOOL(rb_shape_has_object_id(shape_id));
12081196
}
12091197

12101198
static VALUE
@@ -1441,6 +1429,11 @@ Init_default_shapes(void)
14411429
GET_SHAPE_TREE()->root_shape = root;
14421430
RUBY_ASSERT(raw_shape_id(GET_SHAPE_TREE()->root_shape) == ROOT_SHAPE_ID);
14431431

1432+
rb_shape_t *root_with_obj_id = rb_shape_alloc_with_parent_id(0, ROOT_SHAPE_ID);
1433+
root_with_obj_id->type = SHAPE_OBJ_ID;
1434+
root_with_obj_id->heap_index = 0;
1435+
RUBY_ASSERT(raw_shape_id(root_with_obj_id) == ROOT_SHAPE_WITH_OBJ_ID);
1436+
14441437
// Make shapes for T_OBJECT
14451438
size_t *sizes = rb_gc_heap_sizes();
14461439
for (int i = 0; sizes[i] > 0; i++) {

shape.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ STATIC_ASSERT(shape_id_num_bits, SHAPE_ID_NUM_BITS == sizeof(shape_id_t) * CHAR_
1414
#define SHAPE_ID_OFFSET_MASK (SHAPE_BUFFER_SIZE - 1)
1515
#define SHAPE_ID_FLAGS_MASK (shape_id_t)(((1 << (SHAPE_ID_NUM_BITS - SHAPE_ID_OFFSET_NUM_BITS)) - 1) << SHAPE_ID_OFFSET_NUM_BITS)
1616
#define SHAPE_ID_FL_FROZEN (SHAPE_FL_FROZEN << SHAPE_ID_OFFSET_NUM_BITS)
17+
#define SHAPE_ID_FL_HAS_OBJECT_ID (SHAPE_FL_HAS_OBJECT_ID << SHAPE_ID_OFFSET_NUM_BITS)
1718
#define SHAPE_ID_FL_TOO_COMPLEX (SHAPE_FL_TOO_COMPLEX << SHAPE_ID_OFFSET_NUM_BITS)
19+
#define SHAPE_ID_FL_NON_CANONICAL_MASK (SHAPE_FL_NON_CANONICAL_MASK << SHAPE_ID_OFFSET_NUM_BITS)
1820
#define SHAPE_ID_READ_ONLY_MASK (~SHAPE_ID_FL_FROZEN)
1921

2022
typedef uint32_t redblack_id_t;
@@ -29,9 +31,10 @@ typedef uint32_t redblack_id_t;
2931
#define ATTR_INDEX_NOT_SET ((attr_index_t)-1)
3032

3133
#define ROOT_SHAPE_ID 0x0
34+
#define ROOT_SHAPE_WITH_OBJ_ID 0x1
3235
#define ROOT_TOO_COMPLEX_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_TOO_COMPLEX)
3336
#define SPECIAL_CONST_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_FROZEN)
34-
#define FIRST_T_OBJECT_SHAPE_ID 0x1
37+
#define FIRST_T_OBJECT_SHAPE_ID 0x2
3538

3639
extern ID ruby_internal_object_id;
3740

@@ -46,7 +49,6 @@ struct rb_shape {
4649
attr_index_t capacity; // Total capacity of the object with this shape
4750
uint8_t type;
4851
uint8_t heap_index;
49-
uint8_t flags;
5052
};
5153

5254
typedef struct rb_shape rb_shape_t;
@@ -142,7 +144,6 @@ RUBY_FUNC_EXPORTED shape_id_t rb_obj_shape_id(VALUE obj);
142144
shape_id_t rb_shape_get_next_iv_shape(shape_id_t shape_id, ID id);
143145
bool rb_shape_get_iv_index(shape_id_t shape_id, ID id, attr_index_t *value);
144146
bool rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *value, shape_id_t *shape_id_hint);
145-
bool rb_shape_has_object_id(shape_id_t shape_id);
146147

147148
shape_id_t rb_shape_transition_frozen(VALUE obj);
148149
shape_id_t rb_shape_transition_complex(VALUE obj);
@@ -169,10 +170,16 @@ rb_shape_obj_too_complex_p(VALUE obj)
169170
return !RB_SPECIAL_CONST_P(obj) && rb_shape_too_complex_p(RBASIC_SHAPE_ID(obj));
170171
}
171172

173+
static inline bool
174+
rb_shape_has_object_id(shape_id_t shape_id)
175+
{
176+
return shape_id & SHAPE_ID_FL_HAS_OBJECT_ID;
177+
}
178+
172179
static inline bool
173180
rb_shape_canonical_p(shape_id_t shape_id)
174181
{
175-
return !(shape_id & SHAPE_ID_FLAGS_MASK) && !RSHAPE(shape_id)->flags;
182+
return !(shape_id & SHAPE_ID_FL_NON_CANONICAL_MASK);
176183
}
177184

178185
static inline shape_id_t

0 commit comments

Comments
 (0)