Skip to content

Commit 6eb0cd8

Browse files
committed
Get rid of SHAPE_T_OBJECT
Now that we have the `heap_index` in shape flags we no longer need `T_OBJECT` shapes.
1 parent 1c96aed commit 6eb0cd8

File tree

6 files changed

+47
-53
lines changed

6 files changed

+47
-53
lines changed

ext/objspace/objspace_dump.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -817,9 +817,6 @@ shape_id_i(shape_id_t shape_id, void *data)
817817
dump_append(dc, ",\"edge_name\":");
818818
dump_append_id(dc, shape->edge_name);
819819

820-
break;
821-
case SHAPE_T_OBJECT:
822-
dump_append(dc, ", \"shape_type\":\"T_OBJECT\"");
823820
break;
824821
case SHAPE_OBJ_ID:
825822
dump_append(dc, ", \"shape_type\":\"OBJ_ID\"");

object.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
339339
shape_id_t dest_shape_id = src_shape_id;
340340
shape_id_t initial_shape_id = RBASIC_SHAPE_ID(dest);
341341

342-
RUBY_ASSERT(RSHAPE(initial_shape_id)->type == SHAPE_T_OBJECT);
342+
RUBY_ASSERT(RSHAPE(initial_shape_id)->type == SHAPE_ROOT);
343343

344344
dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id);
345345
if (UNLIKELY(rb_shape_too_complex_p(dest_shape_id))) {

shape.c

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ static ID id_frozen;
3737
static ID id_t_object;
3838
ID ruby_internal_object_id; // extern
3939

40-
static const attr_index_t *shape_capacities = NULL;
41-
4240
#define LEAF 0
4341
#define BLACK 0x0
4442
#define RED 0x1
@@ -497,7 +495,7 @@ redblack_cache_ancestors(rb_shape_t *shape)
497495
static attr_index_t
498496
shape_grow_capa(attr_index_t current_capa)
499497
{
500-
const attr_index_t *capacities = shape_capacities;
498+
const attr_index_t *capacities = GET_SHAPE_TREE()->capacities;
501499

502500
// First try to use the next size that will be embeddable in a larger object slot.
503501
attr_index_t capa;
@@ -532,7 +530,6 @@ rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type)
532530
}
533531
break;
534532
case SHAPE_ROOT:
535-
case SHAPE_T_OBJECT:
536533
rb_bug("Unreachable");
537534
break;
538535
}
@@ -858,7 +855,6 @@ shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
858855
*value = shape->next_field_index - 1;
859856
return true;
860857
case SHAPE_ROOT:
861-
case SHAPE_T_OBJECT:
862858
return false;
863859
case SHAPE_OBJ_ID:
864860
rb_bug("Ivar should not exist on transition");
@@ -1070,7 +1066,7 @@ rb_shape_id_offset(void)
10701066
static rb_shape_t *
10711067
shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
10721068
{
1073-
RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
1069+
RUBY_ASSERT(initial_shape->type == SHAPE_ROOT);
10741070
rb_shape_t *next_shape = initial_shape;
10751071

10761072
if (dest_shape->type != initial_shape->type) {
@@ -1107,7 +1103,6 @@ shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
11071103
}
11081104
break;
11091105
case SHAPE_ROOT:
1110-
case SHAPE_T_OBJECT:
11111106
break;
11121107
}
11131108

@@ -1133,7 +1128,7 @@ shape_rebuild(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
11331128
{
11341129
rb_shape_t *midway_shape;
11351130

1136-
RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT || initial_shape->type == SHAPE_ROOT);
1131+
RUBY_ASSERT(initial_shape->type == SHAPE_ROOT);
11371132

11381133
if (dest_shape->type != initial_shape->type) {
11391134
midway_shape = shape_rebuild(initial_shape, RSHAPE(dest_shape->parent_id));
@@ -1151,7 +1146,6 @@ shape_rebuild(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
11511146
break;
11521147
case SHAPE_OBJ_ID:
11531148
case SHAPE_ROOT:
1154-
case SHAPE_T_OBJECT:
11551149
break;
11561150
}
11571151

@@ -1279,8 +1273,18 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
12791273
}
12801274

12811275
uint8_t flags_heap_index = rb_shape_heap_index(shape_id);
1282-
if (flags_heap_index != shape->heap_index) {
1283-
rb_bug("shape_id heap_index flags mismatch: flags=%u, transition=%u\n", flags_heap_index, shape->heap_index);
1276+
if (RB_TYPE_P(obj, T_OBJECT)) {
1277+
size_t shape_id_slot_size = GET_SHAPE_TREE()->capacities[flags_heap_index - 1] * sizeof(VALUE) + sizeof(struct RBasic);
1278+
size_t actual_slot_size = rb_gc_obj_slot_size(obj);
1279+
1280+
if (shape_id_slot_size != actual_slot_size) {
1281+
rb_bug("shape_id heap_index flags mismatch: shape_id_slot_size=%lu, gc_slot_size=%lu\n", shape_id_slot_size, actual_slot_size);
1282+
}
1283+
}
1284+
else {
1285+
if (flags_heap_index) {
1286+
rb_bug("shape_id indicate heap_index > 0 but objet is not T_OBJECT: %s", rb_obj_info(obj));
1287+
}
12841288
}
12851289

12861290
return true;
@@ -1339,7 +1343,7 @@ shape_id_t_to_rb_cShape(shape_id_t shape_id)
13391343
INT2NUM(shape->next_field_index),
13401344
INT2NUM(shape->heap_index),
13411345
INT2NUM(shape->type),
1342-
INT2NUM(shape->capacity));
1346+
INT2NUM(RSHAPE_CAPACITY(shape_id)));
13431347
rb_obj_freeze(obj);
13441348
return obj;
13451349
}
@@ -1509,7 +1513,7 @@ Init_default_shapes(void)
15091513
for (index = 0; index < heaps_count; index++) {
15101514
capacities[index] = (heap_sizes[index] - sizeof(struct RBasic)) / sizeof(VALUE);
15111515
}
1512-
shape_capacities = capacities;
1516+
GET_SHAPE_TREE()->capacities = capacities;
15131517

15141518
#ifdef HAVE_MMAP
15151519
size_t shape_list_mmap_size = rb_size_mul_or_raise(SHAPE_BUFFER_SIZE, sizeof(rb_shape_t), rb_eRuntimeError);
@@ -1568,33 +1572,12 @@ Init_default_shapes(void)
15681572
root_with_obj_id->next_field_index++;
15691573
root_with_obj_id->heap_index = 0;
15701574
RUBY_ASSERT(raw_shape_id(root_with_obj_id) == ROOT_SHAPE_WITH_OBJ_ID);
1571-
1572-
// Make shapes for T_OBJECT
1573-
size_t *sizes = rb_gc_heap_sizes();
1574-
int i;
1575-
for (i = 0; sizes[i] > 0; i++) {
1576-
rb_shape_t *t_object_shape = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
1577-
t_object_shape->type = SHAPE_T_OBJECT;
1578-
t_object_shape->heap_index = i + 1;
1579-
t_object_shape->capacity = (uint32_t)((sizes[i] - offsetof(struct RObject, as.ary)) / sizeof(VALUE));
1580-
t_object_shape->edges = rb_managed_id_table_new(256);
1581-
t_object_shape->ancestor_index = LEAF;
1582-
RUBY_ASSERT(t_object_shape == RSHAPE(rb_shape_root(i)));
1583-
}
1584-
1585-
// Prebuild all ROOT + OBJ_ID shapes so that even when we run out of shape we can always transtion to
1586-
// COMPLEX + OBJ_ID.
1587-
bool dont_care;
1588-
for (i = 0; sizes[i] > 0; i++) {
1589-
get_next_shape_internal(RSHAPE(rb_shape_root(i)), ruby_internal_object_id, SHAPE_OBJ_ID, &dont_care, true);
1590-
}
15911575
}
15921576

15931577
void
15941578
rb_shape_free_all(void)
15951579
{
1596-
xfree((void *)shape_capacities);
1597-
shape_capacities = NULL;
1580+
xfree((void *)GET_SHAPE_TREE()->capacities);
15981581
xfree(GET_SHAPE_TREE());
15991582
}
16001583

@@ -1624,11 +1607,9 @@ Init_shape(void)
16241607

16251608
rb_define_const(rb_cShape, "SHAPE_ROOT", INT2NUM(SHAPE_ROOT));
16261609
rb_define_const(rb_cShape, "SHAPE_IVAR", INT2NUM(SHAPE_IVAR));
1627-
rb_define_const(rb_cShape, "SHAPE_T_OBJECT", INT2NUM(SHAPE_T_OBJECT));
16281610
rb_define_const(rb_cShape, "SHAPE_ID_NUM_BITS", INT2NUM(SHAPE_ID_NUM_BITS));
16291611
rb_define_const(rb_cShape, "SHAPE_FLAG_SHIFT", INT2NUM(SHAPE_FLAG_SHIFT));
16301612
rb_define_const(rb_cShape, "SPECIAL_CONST_SHAPE_ID", INT2NUM(SPECIAL_CONST_SHAPE_ID));
1631-
rb_define_const(rb_cShape, "FIRST_T_OBJECT_SHAPE_ID", INT2NUM(FIRST_T_OBJECT_SHAPE_ID));
16321613
rb_define_const(rb_cShape, "SHAPE_MAX_VARIATIONS", INT2NUM(SHAPE_MAX_VARIATIONS));
16331614
rb_define_const(rb_cShape, "SIZEOF_RB_SHAPE_T", INT2NUM(sizeof(rb_shape_t)));
16341615
rb_define_const(rb_cShape, "SIZEOF_REDBLACK_NODE_T", INT2NUM(sizeof(redblack_node_t)));

shape.h

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ typedef uint32_t redblack_id_t;
4444
#define ROOT_TOO_COMPLEX_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_TOO_COMPLEX)
4545
#define ROOT_TOO_COMPLEX_WITH_OBJ_ID (ROOT_SHAPE_WITH_OBJ_ID | SHAPE_ID_FL_TOO_COMPLEX | SHAPE_ID_FL_HAS_OBJECT_ID)
4646
#define SPECIAL_CONST_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_FROZEN)
47-
#define FIRST_T_OBJECT_SHAPE_ID 0x2
4847

4948
extern ID ruby_internal_object_id;
5049

@@ -74,7 +73,6 @@ enum shape_type {
7473
SHAPE_ROOT,
7574
SHAPE_IVAR,
7675
SHAPE_OBJ_ID,
77-
SHAPE_T_OBJECT,
7876
};
7977

8078
enum shape_flags {
@@ -89,6 +87,7 @@ typedef struct {
8987
/* object shapes */
9088
rb_shape_t *shape_list;
9189
rb_shape_t *root_shape;
90+
const attr_index_t *capacities;
9291
rb_atomic_t next_shape_id;
9392

9493
redblack_node_t *shape_cache;
@@ -209,8 +208,7 @@ rb_shape_root(size_t heap_id)
209208
{
210209
shape_id_t heap_index = (shape_id_t)heap_id;
211210

212-
shape_id_t shape_id = (heap_index + FIRST_T_OBJECT_SHAPE_ID);
213-
return shape_id | ((heap_index + 1) << SHAPE_ID_HEAP_INDEX_OFFSET);
211+
return ROOT_SHAPE_ID | ((heap_index + 1) << SHAPE_ID_HEAP_INDEX_OFFSET);
214212
}
215213

216214
static inline bool
@@ -219,10 +217,27 @@ RSHAPE_TYPE_P(shape_id_t shape_id, enum shape_type type)
219217
return RSHAPE(shape_id)->type == type;
220218
}
221219

220+
static inline attr_index_t
221+
RSHAPE_EMBEDDED_CAPACITY(shape_id_t shape_id)
222+
{
223+
uint8_t heap_index = rb_shape_heap_index(shape_id);
224+
if (heap_index) {
225+
return GET_SHAPE_TREE()->capacities[heap_index - 1];
226+
}
227+
return 0;
228+
}
229+
222230
static inline attr_index_t
223231
RSHAPE_CAPACITY(shape_id_t shape_id)
224232
{
225-
return RSHAPE(shape_id)->capacity;
233+
attr_index_t embedded_capacity = RSHAPE_EMBEDDED_CAPACITY(shape_id);
234+
235+
if (embedded_capacity > RSHAPE(shape_id)->capacity) {
236+
return embedded_capacity;
237+
}
238+
else {
239+
return RSHAPE(shape_id)->capacity;
240+
}
226241
}
227242

228243
static inline attr_index_t

test/ruby/test_shapes.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -905,13 +905,15 @@ def test_remove_instance_variable_when_out_of_shapes
905905
def test_remove_instance_variable_capacity_transition
906906
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
907907
begin;
908-
t_object_shape = RubyVM::Shape.find_by_id(RubyVM::Shape::FIRST_T_OBJECT_SHAPE_ID)
909-
assert_equal(RubyVM::Shape::SHAPE_T_OBJECT, t_object_shape.type)
910-
911-
initial_capacity = t_object_shape.capacity
912908
913909
# a does not transition in capacity
914910
a = Class.new.new
911+
root_shape = RubyVM::Shape.of(a)
912+
913+
assert_equal(RubyVM::Shape::SHAPE_ROOT, root_shape.type)
914+
initial_capacity = root_shape.capacity
915+
refute_equal(0, initial_capacity)
916+
915917
initial_capacity.times do |i|
916918
a.instance_variable_set(:"@ivar#{i + 1}", i)
917919
end
@@ -1007,7 +1009,7 @@ class TestObject; end
10071009
def test_new_obj_has_t_object_shape
10081010
obj = TestObject.new
10091011
shape = RubyVM::Shape.of(obj)
1010-
assert_equal RubyVM::Shape::SHAPE_T_OBJECT, shape.type
1012+
assert_equal RubyVM::Shape::SHAPE_ROOT, shape.type
10111013
assert_nil shape.parent
10121014
end
10131015

@@ -1039,7 +1041,7 @@ def test_basic_shape_transition
10391041
assert_equal RubyVM::Shape::SHAPE_IVAR, shape.type
10401042

10411043
shape = shape.parent
1042-
assert_equal RubyVM::Shape::SHAPE_T_OBJECT, shape.type
1044+
assert_equal RubyVM::Shape::SHAPE_ROOT, shape.type
10431045
assert_nil shape.parent
10441046

10451047
assert_equal(1, obj.instance_variable_get(:@a))

variable.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2211,7 +2211,6 @@ iterate_over_shapes_with_callback(rb_shape_t *shape, rb_ivar_foreach_callback_fu
22112211
{
22122212
switch ((enum shape_type)shape->type) {
22132213
case SHAPE_ROOT:
2214-
case SHAPE_T_OBJECT:
22152214
return false;
22162215
case SHAPE_OBJ_ID:
22172216
if (itr_data->ivar_only) {

0 commit comments

Comments
 (0)