Skip to content

Commit 9520129

Browse files
committed
Refactor the last references to rb_shape_t
The type isn't opaque because Ruby isn't often compiled with LTO, so for optimization purpose it's better to allow as much inlining as possible. However ideally only `shape.c` and `shape.h` should deal with the actual struct, and everything else should just deal with opaque `shape_id_t`.
1 parent 4463ac2 commit 9520129

File tree

8 files changed

+96
-75
lines changed

8 files changed

+96
-75
lines changed

ext/objspace/objspace_dump.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -792,30 +792,29 @@ shape_id_i(shape_id_t shape_id, void *data)
792792
return;
793793
}
794794

795-
rb_shape_t *shape = RSHAPE(shape_id);
796795
dump_append(dc, "{\"address\":");
797-
dump_append_ref(dc, (VALUE)shape);
796+
dump_append_ref(dc, (VALUE)RSHAPE(shape_id));
798797

799798
dump_append(dc, ", \"type\":\"SHAPE\", \"id\":");
800799
dump_append_sizet(dc, shape_id);
801800

802-
if (shape->type != SHAPE_ROOT) {
801+
if (RSHAPE_TYPE(shape_id) != SHAPE_ROOT) {
803802
dump_append(dc, ", \"parent_id\":");
804-
dump_append_lu(dc, shape->parent_id);
803+
dump_append_lu(dc, RSHAPE_PARENT(shape_id));
805804
}
806805

807806
dump_append(dc, ", \"depth\":");
808807
dump_append_sizet(dc, rb_shape_depth(shape_id));
809808

810-
switch((enum shape_type)shape->type) {
809+
switch (RSHAPE_TYPE(shape_id)) {
811810
case SHAPE_ROOT:
812811
dump_append(dc, ", \"shape_type\":\"ROOT\"");
813812
break;
814813
case SHAPE_IVAR:
815814
dump_append(dc, ", \"shape_type\":\"IVAR\"");
816815

817816
dump_append(dc, ",\"edge_name\":");
818-
dump_append_id(dc, shape->edge_name);
817+
dump_append_id(dc, RSHAPE_EDGE_NAME(shape_id));
819818

820819
break;
821820
case SHAPE_OBJ_ID:

internal/class.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ RCLASS_FIELDS_COUNT(VALUE obj)
576576
return count;
577577
}
578578
else {
579-
return RSHAPE(RBASIC_SHAPE_ID(obj))->next_field_index;
579+
return RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
580580
}
581581
}
582582

internal/variable.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include "constant.h" /* for rb_const_entry_t */
1414
#include "ruby/internal/stdbool.h" /* for bool */
1515
#include "ruby/ruby.h" /* for VALUE */
16-
#include "shape.h" /* for rb_shape_t */
16+
#include "shape.h" /* for shape_id_t */
1717

1818
/* variable.c */
1919
void rb_gc_mark_global_tbl(void);

object.c

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

343-
RUBY_ASSERT(RSHAPE(initial_shape_id)->type == SHAPE_ROOT);
343+
RUBY_ASSERT(RSHAPE_TYPE_P(initial_shape_id, SHAPE_ROOT));
344344

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

shape.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,31 @@ rb_shape_memsize(shape_id_t shape_id)
11841184
return memsize;
11851185
}
11861186

1187+
bool
1188+
rb_shape_foreach_field(shape_id_t initial_shape_id, rb_shape_foreach_transition_callback func, void *data)
1189+
{
1190+
RUBY_ASSERT(!rb_shape_too_complex_p(initial_shape_id));
1191+
1192+
rb_shape_t *shape = RSHAPE(initial_shape_id);
1193+
if (shape->type == SHAPE_ROOT) {
1194+
return true;
1195+
}
1196+
1197+
shape_id_t parent_id = shape_id(RSHAPE(shape->parent_id), initial_shape_id);
1198+
if (rb_shape_foreach_field(parent_id, func, data)) {
1199+
switch (func(shape_id(shape, initial_shape_id), data)) {
1200+
case ST_STOP:
1201+
return false;
1202+
case ST_CHECK:
1203+
case ST_CONTINUE:
1204+
break;
1205+
default:
1206+
rb_bug("unreachable");
1207+
}
1208+
}
1209+
return true;
1210+
}
1211+
11871212
#if RUBY_DEBUG
11881213
bool
11891214
rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)

shape.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ shape_id_t rb_shape_get_next_iv_shape(shape_id_t shape_id, ID id);
158158
bool rb_shape_get_iv_index(shape_id_t shape_id, ID id, attr_index_t *value);
159159
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);
160160

161+
typedef int rb_shape_foreach_transition_callback(shape_id_t shape_id, void *data);
162+
bool rb_shape_foreach_field(shape_id_t shape_id, rb_shape_foreach_transition_callback func, void *data);
163+
161164
shape_id_t rb_shape_transition_frozen(VALUE obj);
162165
shape_id_t rb_shape_transition_complex(VALUE obj);
163166
shape_id_t rb_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id);
@@ -211,10 +214,22 @@ rb_shape_root(size_t heap_id)
211214
return ROOT_SHAPE_ID | ((heap_index + 1) << SHAPE_ID_HEAP_INDEX_OFFSET);
212215
}
213216

217+
static inline shape_id_t
218+
RSHAPE_PARENT(shape_id_t shape_id)
219+
{
220+
return RSHAPE(shape_id)->parent_id;
221+
}
222+
223+
static inline enum shape_type
224+
RSHAPE_TYPE(shape_id_t shape_id)
225+
{
226+
return RSHAPE(shape_id)->type;
227+
}
228+
214229
static inline bool
215230
RSHAPE_TYPE_P(shape_id_t shape_id, enum shape_type type)
216231
{
217-
return RSHAPE(shape_id)->type == type;
232+
return RSHAPE_TYPE(shape_id) == type;
218233
}
219234

220235
static inline attr_index_t

variable.c

Lines changed: 44 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,7 +1303,7 @@ VALUE
13031303
rb_obj_field_get(VALUE obj, shape_id_t target_shape_id)
13041304
{
13051305
RUBY_ASSERT(!SPECIAL_CONST_P(obj));
1306-
RUBY_ASSERT(RSHAPE(target_shape_id)->type == SHAPE_IVAR || RSHAPE(target_shape_id)->type == SHAPE_OBJ_ID);
1306+
RUBY_ASSERT(RSHAPE_TYPE_P(target_shape_id, SHAPE_IVAR) || RSHAPE_TYPE_P(target_shape_id, SHAPE_OBJ_ID));
13071307

13081308
if (rb_shape_too_complex_p(target_shape_id)) {
13091309
st_table *fields_hash;
@@ -1325,7 +1325,7 @@ rb_obj_field_get(VALUE obj, shape_id_t target_shape_id)
13251325
break;
13261326
}
13271327
VALUE value = Qundef;
1328-
st_lookup(fields_hash, RSHAPE(target_shape_id)->edge_name, &value);
1328+
st_lookup(fields_hash, RSHAPE_EDGE_NAME(target_shape_id), &value);
13291329

13301330
#if RUBY_DEBUG
13311331
if (UNDEF_P(value)) {
@@ -1337,7 +1337,7 @@ rb_obj_field_get(VALUE obj, shape_id_t target_shape_id)
13371337
return value;
13381338
}
13391339

1340-
attr_index_t attr_index = RSHAPE(target_shape_id)->next_field_index - 1;
1340+
attr_index_t attr_index = RSHAPE_INDEX(target_shape_id);
13411341
VALUE *fields;
13421342
switch (BUILTIN_TYPE(obj)) {
13431343
case T_CLASS:
@@ -1505,7 +1505,7 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
15051505
goto too_complex;
15061506
}
15071507

1508-
RUBY_ASSERT(RSHAPE(next_shape_id)->next_field_index == RSHAPE(old_shape_id)->next_field_index - 1);
1508+
RUBY_ASSERT(RSHAPE_LEN(next_shape_id) == RSHAPE_LEN(old_shape_id) - 1);
15091509

15101510
VALUE *fields;
15111511
switch(BUILTIN_TYPE(obj)) {
@@ -1526,9 +1526,9 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
15261526

15271527
RUBY_ASSERT(removed_shape_id != INVALID_SHAPE_ID);
15281528

1529-
attr_index_t new_fields_count = RSHAPE(next_shape_id)->next_field_index;
1529+
attr_index_t new_fields_count = RSHAPE_LEN(next_shape_id);
15301530

1531-
attr_index_t removed_index = RSHAPE(removed_shape_id)->next_field_index - 1;
1531+
attr_index_t removed_index = RSHAPE_INDEX(removed_shape_id);
15321532
val = fields[removed_index];
15331533
size_t trailing_fields = new_fields_count - removed_index;
15341534

@@ -1810,8 +1810,8 @@ generic_fields_lookup_ensure_size(st_data_t *k, st_data_t *v, st_data_t u, int e
18101810

18111811
if (!existing || fields_lookup->resize) {
18121812
if (existing) {
1813-
RUBY_ASSERT(RSHAPE(fields_lookup->shape_id)->type == SHAPE_IVAR || RSHAPE(fields_lookup->shape_id)->type == SHAPE_OBJ_ID);
1814-
RUBY_ASSERT(RSHAPE_CAPACITY(RSHAPE(fields_lookup->shape_id)->parent_id) < RSHAPE_CAPACITY(fields_lookup->shape_id));
1813+
RUBY_ASSERT(RSHAPE_TYPE_P(fields_lookup->shape_id, SHAPE_IVAR) || RSHAPE_TYPE_P(fields_lookup->shape_id, SHAPE_OBJ_ID));
1814+
RUBY_ASSERT(RSHAPE_CAPACITY(RSHAPE_PARENT(fields_lookup->shape_id)) < RSHAPE_CAPACITY(fields_lookup->shape_id));
18151815
}
18161816
else {
18171817
FL_SET_RAW((VALUE)*k, FL_EXIVAR);
@@ -2186,57 +2186,42 @@ struct iv_itr_data {
21862186
bool ivar_only;
21872187
};
21882188

2189-
/*
2190-
* Returns a flag to stop iterating depending on the result of +callback+.
2191-
*/
2192-
static bool
2193-
iterate_over_shapes_with_callback(rb_shape_t *shape, rb_ivar_foreach_callback_func *callback, struct iv_itr_data *itr_data)
2189+
static int
2190+
iterate_over_shapes_callback(shape_id_t shape_id, void *data)
21942191
{
2195-
switch ((enum shape_type)shape->type) {
2196-
case SHAPE_ROOT:
2197-
return false;
2198-
case SHAPE_OBJ_ID:
2199-
if (itr_data->ivar_only) {
2200-
return iterate_over_shapes_with_callback(RSHAPE(shape->parent_id), callback, itr_data);
2201-
}
2202-
// fallthrough
2203-
case SHAPE_IVAR:
2204-
ASSUME(callback);
2205-
if (iterate_over_shapes_with_callback(RSHAPE(shape->parent_id), callback, itr_data)) {
2206-
return true;
2207-
}
2192+
struct iv_itr_data *itr_data = data;
22082193

2209-
VALUE * iv_list;
2210-
switch (BUILTIN_TYPE(itr_data->obj)) {
2211-
case T_OBJECT:
2212-
RUBY_ASSERT(!rb_shape_obj_too_complex_p(itr_data->obj));
2213-
iv_list = ROBJECT_FIELDS(itr_data->obj);
2214-
break;
2215-
case T_CLASS:
2216-
case T_MODULE:
2217-
RUBY_ASSERT(!rb_shape_obj_too_complex_p(itr_data->obj));
2218-
iv_list = RCLASS_PRIME_FIELDS(itr_data->obj);
2219-
break;
2220-
default:
2221-
iv_list = itr_data->fields_tbl->as.shape.fields;
2222-
break;
2223-
}
2224-
VALUE val = iv_list[shape->next_field_index - 1];
2225-
if (!UNDEF_P(val)) {
2226-
switch (callback(shape->edge_name, val, itr_data->arg)) {
2227-
case ST_CHECK:
2228-
case ST_CONTINUE:
2229-
break;
2230-
case ST_STOP:
2231-
return true;
2232-
default:
2233-
rb_bug("unreachable");
2234-
}
2235-
}
2236-
return false;
2194+
if (itr_data->ivar_only && !RSHAPE_TYPE_P(shape_id, SHAPE_IVAR)) {
2195+
return ST_CONTINUE;
2196+
}
2197+
2198+
VALUE *iv_list;
2199+
switch (BUILTIN_TYPE(itr_data->obj)) {
2200+
case T_OBJECT:
2201+
RUBY_ASSERT(!rb_shape_obj_too_complex_p(itr_data->obj));
2202+
iv_list = ROBJECT_FIELDS(itr_data->obj);
2203+
break;
2204+
case T_CLASS:
2205+
case T_MODULE:
2206+
RUBY_ASSERT(!rb_shape_obj_too_complex_p(itr_data->obj));
2207+
iv_list = RCLASS_PRIME_FIELDS(itr_data->obj);
2208+
break;
22372209
default:
2238-
UNREACHABLE_RETURN(false);
2210+
iv_list = itr_data->fields_tbl->as.shape.fields;
2211+
break;
22392212
}
2213+
2214+
VALUE val = iv_list[RSHAPE_INDEX(shape_id)];
2215+
return itr_data->func(RSHAPE_EDGE_NAME(shape_id), val, itr_data->arg);
2216+
}
2217+
2218+
/*
2219+
* Returns a flag to stop iterating depending on the result of +callback+.
2220+
*/
2221+
static void
2222+
iterate_over_shapes(shape_id_t shape_id, rb_ivar_foreach_callback_func *callback, struct iv_itr_data *itr_data)
2223+
{
2224+
rb_shape_foreach_field(shape_id, iterate_over_shapes_callback, itr_data);
22402225
}
22412226

22422227
static int
@@ -2262,7 +2247,7 @@ obj_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, b
22622247
rb_st_foreach(ROBJECT_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
22632248
}
22642249
else {
2265-
iterate_over_shapes_with_callback(RSHAPE(shape_id), func, &itr_data);
2250+
iterate_over_shapes(shape_id, func, &itr_data);
22662251
}
22672252
}
22682253

@@ -2285,7 +2270,7 @@ gen_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, b
22852270
rb_st_foreach(fields_tbl->as.complex.table, each_hash_iv, (st_data_t)&itr_data);
22862271
}
22872272
else {
2288-
iterate_over_shapes_with_callback(RSHAPE(shape_id), func, &itr_data);
2273+
iterate_over_shapes(shape_id, func, &itr_data);
22892274
}
22902275
}
22912276

@@ -2306,7 +2291,7 @@ class_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg,
23062291
rb_st_foreach(RCLASS_WRITABLE_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
23072292
}
23082293
else {
2309-
iterate_over_shapes_with_callback(RSHAPE(shape_id), func, &itr_data);
2294+
iterate_over_shapes(shape_id, func, &itr_data);
23102295
}
23112296
}
23122297

@@ -2344,7 +2329,7 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj)
23442329
shape_id_t initial_shape_id = rb_obj_shape_id(dest);
23452330

23462331
if (!rb_shape_canonical_p(src_shape_id)) {
2347-
RUBY_ASSERT(RSHAPE(initial_shape_id)->type == SHAPE_ROOT);
2332+
RUBY_ASSERT(RSHAPE_TYPE_P(initial_shape_id, SHAPE_ROOT));
23482333

23492334
dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id);
23502335
if (UNLIKELY(rb_shape_too_complex_p(dest_shape_id))) {

vm_insnhelper.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,9 +1455,7 @@ vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_i
14551455
RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID);
14561456
}
14571457
else if (dest_shape_id != INVALID_SHAPE_ID) {
1458-
rb_shape_t *dest_shape = RSHAPE(dest_shape_id);
1459-
1460-
if (shape_id == dest_shape->parent_id && dest_shape->edge_name == id && RSHAPE_CAPACITY(shape_id) == RSHAPE_CAPACITY(dest_shape_id)) {
1458+
if (shape_id == RSHAPE_PARENT(dest_shape_id) && RSHAPE_EDGE_NAME(dest_shape_id) == id && RSHAPE_CAPACITY(shape_id) == RSHAPE_CAPACITY(dest_shape_id)) {
14611459
RUBY_ASSERT(index < RSHAPE_CAPACITY(dest_shape_id));
14621460
}
14631461
else {
@@ -1498,10 +1496,9 @@ vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t i
14981496
VM_ASSERT(!rb_ractor_shareable_p(obj));
14991497
}
15001498
else if (dest_shape_id != INVALID_SHAPE_ID) {
1501-
rb_shape_t *dest_shape = RSHAPE(dest_shape_id);
1502-
shape_id_t source_shape_id = dest_shape->parent_id;
1499+
shape_id_t source_shape_id = RSHAPE_PARENT(dest_shape_id);
15031500

1504-
if (shape_id == source_shape_id && dest_shape->edge_name == id && RSHAPE_CAPACITY(shape_id) == RSHAPE_CAPACITY(dest_shape_id)) {
1501+
if (shape_id == source_shape_id && RSHAPE_EDGE_NAME(dest_shape_id) == id && RSHAPE_CAPACITY(shape_id) == RSHAPE_CAPACITY(dest_shape_id)) {
15051502
RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID);
15061503

15071504
RBASIC_SET_SHAPE_ID(obj, dest_shape_id);

0 commit comments

Comments
 (0)