Skip to content

Commit c64f2b5

Browse files
committed
Refactor OBJ_TOO_COMPLEX_SHAPE_ID to not be referenced outside shape.h
Also refactor checks for `->type == SHAPE_OBJ_TOO_COMPLEX`.
1 parent e49cc24 commit c64f2b5

11 files changed

Lines changed: 54 additions & 33 deletions

File tree

gc.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,9 +379,10 @@ rb_gc_set_shape(VALUE obj, uint32_t shape_id)
379379
uint32_t
380380
rb_gc_rebuild_shape(VALUE obj, size_t heap_id)
381381
{
382-
rb_shape_t *orig_shape = rb_shape_get_shape(obj);
382+
shape_id_t orig_shape_id = rb_shape_get_shape_id(obj);
383+
rb_shape_t *orig_shape = rb_shape_get_shape_by_id(orig_shape_id);
383384

384-
if (rb_shape_obj_too_complex(obj)) return (uint32_t)OBJ_TOO_COMPLEX_SHAPE_ID;
385+
if (rb_shape_too_complex_p(orig_shape)) return orig_shape_id;
385386

386387
rb_shape_t *initial_shape = rb_shape_get_shape_by_id((shape_id_t)(heap_id + FIRST_T_OBJECT_SHAPE_ID));
387388
rb_shape_t *new_shape = rb_shape_traverse_from_new_root(initial_shape, orig_shape);

object.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
362362
RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
363363

364364
shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape);
365-
if (UNLIKELY(rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID)) {
365+
if (UNLIKELY(rb_shape_too_complex_p(shape_to_set_on_dest))) {
366366
st_table * table = rb_st_init_numtable_with_size(src_num_ivs);
367367
rb_obj_copy_ivs_to_hash_table(obj, table);
368368
rb_obj_convert_to_too_complex(dest, table);
@@ -371,7 +371,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
371371
}
372372
}
373373

374-
RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity || rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID);
374+
RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity || rb_shape_too_complex_p(shape_to_set_on_dest));
375375
if (initial_shape->capacity < shape_to_set_on_dest->capacity) {
376376
rb_ensure_iv_list_size(dest, initial_shape->capacity, shape_to_set_on_dest->capacity);
377377
dest_buf = ROBJECT_FIELDS(dest);
@@ -507,7 +507,7 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
507507

508508
if (RB_OBJ_FROZEN(obj)) {
509509
rb_shape_t *next_shape = rb_shape_transition_shape_frozen(clone);
510-
if (!rb_shape_obj_too_complex(clone) && next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
510+
if (!rb_shape_obj_too_complex(clone) && rb_shape_too_complex_p(next_shape)) {
511511
rb_evict_ivars_to_hash(clone);
512512
}
513513
else {
@@ -531,7 +531,7 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
531531
rb_shape_t *next_shape = rb_shape_transition_shape_frozen(clone);
532532
// If we're out of shapes, but we want to freeze, then we need to
533533
// evacuate this clone to a hash
534-
if (!rb_shape_obj_too_complex(clone) && next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
534+
if (!rb_shape_obj_too_complex(clone) && rb_shape_too_complex_p(next_shape)) {
535535
rb_evict_ivars_to_hash(clone);
536536
}
537537
else {

shape.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ get_next_shape_internal(rb_shape_t *shape, ID id, enum shape_type shape_type, bo
495495
rb_shape_t *res = NULL;
496496

497497
// There should never be outgoing edges from "too complex"
498-
RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
498+
RUBY_ASSERT(!rb_shape_too_complex_p(shape));
499499

500500
*variation_created = false;
501501

@@ -573,7 +573,7 @@ get_next_shape_internal(rb_shape_t *shape, ID id, enum shape_type shape_type, bo
573573
return res;
574574
}
575575

576-
int
576+
bool
577577
rb_shape_frozen_shape_p(rb_shape_t *shape)
578578
{
579579
return SHAPE_FROZEN == (enum shape_type)shape->type;
@@ -703,6 +703,11 @@ rb_shape_transition_shape_frozen(VALUE obj)
703703
return next_shape;
704704
}
705705

706+
rb_shape_t *
707+
rb_shape_transition_shape_too_complex(VALUE obj)
708+
{
709+
return rb_shape_get_shape_by_id(OBJ_TOO_COMPLEX_SHAPE_ID);
710+
}
706711
/*
707712
* This function is used for assertions where we don't want to increment
708713
* max_iv_count
@@ -1012,6 +1017,18 @@ rb_shape_obj_too_complex(VALUE obj)
10121017
return rb_shape_get_shape_id(obj) == OBJ_TOO_COMPLEX_SHAPE_ID;
10131018
}
10141019

1020+
bool
1021+
rb_shape_too_complex_p(rb_shape_t *shape)
1022+
{
1023+
return rb_shape_id(shape) == OBJ_TOO_COMPLEX_SHAPE_ID;
1024+
}
1025+
1026+
bool
1027+
rb_shape_id_too_complex_p(shape_id_t shape_id)
1028+
{
1029+
return shape_id == OBJ_TOO_COMPLEX_SHAPE_ID;
1030+
}
1031+
10151032
size_t
10161033
rb_shape_edges_count(rb_shape_t *shape)
10171034
{

shape.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,14 @@ rb_shape_t *rb_shape_get_next_iv_shape(rb_shape_t *shape, ID id);
157157
bool rb_shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value);
158158
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);
159159
RUBY_FUNC_EXPORTED bool rb_shape_obj_too_complex(VALUE obj);
160+
bool rb_shape_too_complex_p(rb_shape_t *shape);
161+
bool rb_shape_id_too_complex_p(shape_id_t shape_id);
160162

161163
void rb_shape_set_shape(VALUE obj, rb_shape_t *shape);
162164
rb_shape_t *rb_shape_get_shape(VALUE obj);
163-
int rb_shape_frozen_shape_p(rb_shape_t *shape);
165+
bool rb_shape_frozen_shape_p(rb_shape_t *shape);
164166
rb_shape_t *rb_shape_transition_shape_frozen(VALUE obj);
167+
rb_shape_t *rb_shape_transition_shape_too_complex(VALUE obj);
165168
bool rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE *removed);
166169
rb_shape_t *rb_shape_get_next(rb_shape_t *shape, VALUE obj, ID id);
167170
rb_shape_t *rb_shape_get_next_no_warnings(rb_shape_t *shape, VALUE obj, ID id);

variable.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,7 @@ void
14821482
rb_obj_convert_to_too_complex(VALUE obj, st_table *table)
14831483
{
14841484
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
1485+
rb_shape_t *too_complex_shape = rb_shape_transition_shape_too_complex(obj);
14851486

14861487
VALUE *old_fields = NULL;
14871488

@@ -1490,13 +1491,13 @@ rb_obj_convert_to_too_complex(VALUE obj, st_table *table)
14901491
if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
14911492
old_fields = ROBJECT_FIELDS(obj);
14921493
}
1493-
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
1494+
rb_shape_set_shape(obj, too_complex_shape);
14941495
ROBJECT_SET_FIELDS_HASH(obj, table);
14951496
break;
14961497
case T_CLASS:
14971498
case T_MODULE:
14981499
old_fields = RCLASS_FIELDS(obj);
1499-
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
1500+
rb_shape_set_shape(obj, too_complex_shape);
15001501
RCLASS_SET_FIELDS_HASH(obj, table);
15011502
break;
15021503
default:
@@ -1513,9 +1514,9 @@ rb_obj_convert_to_too_complex(VALUE obj, st_table *table)
15131514
* compaction. We want the table to be updated rather than
15141515
* the original fields. */
15151516
#if SHAPE_IN_BASIC_FLAGS
1516-
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
1517+
rb_shape_set_shape(obj, too_complex_shape);
15171518
#else
1518-
old_fields_tbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
1519+
old_fields_tbl->shape_id = rb_shape_id(too_complex_shape);
15191520
#endif
15201521
old_fields_tbl->as.complex.table = table;
15211522
old_fields = (VALUE *)old_fields_tbl;
@@ -1524,10 +1525,11 @@ rb_obj_convert_to_too_complex(VALUE obj, st_table *table)
15241525
struct gen_fields_tbl *fields_tbl = xmalloc(sizeof(struct gen_fields_tbl));
15251526
fields_tbl->as.complex.table = table;
15261527
st_insert(gen_ivs, (st_data_t)obj, (st_data_t)fields_tbl);
1528+
15271529
#if SHAPE_IN_BASIC_FLAGS
1528-
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
1530+
rb_shape_set_shape(obj, too_complex_shape);
15291531
#else
1530-
fields_tbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
1532+
fields_tbl->shape_id = rb_shape_id(too_complex_shape);
15311533
#endif
15321534
}
15331535
RB_VM_LOCK_LEAVE();
@@ -1570,7 +1572,7 @@ general_ivar_set(VALUE obj, ID id, VALUE val, void *data,
15701572

15711573
rb_shape_t *current_shape = rb_shape_get_shape(obj);
15721574

1573-
if (UNLIKELY(current_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
1575+
if (UNLIKELY(rb_shape_too_complex_p(current_shape))) {
15741576
goto too_complex;
15751577
}
15761578

@@ -1584,7 +1586,7 @@ general_ivar_set(VALUE obj, ID id, VALUE val, void *data,
15841586
}
15851587

15861588
rb_shape_t *next_shape = rb_shape_get_next(current_shape, obj, id);
1587-
if (UNLIKELY(next_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
1589+
if (UNLIKELY(rb_shape_too_complex_p(next_shape))) {
15881590
transition_too_complex_func(obj, data);
15891591
goto too_complex;
15901592
}
@@ -1709,7 +1711,7 @@ generic_ivar_set_too_complex_table(VALUE obj, void *data)
17091711
if (!rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) {
17101712
fields_tbl = xmalloc(sizeof(struct gen_fields_tbl));
17111713
#if !SHAPE_IN_BASIC_FLAGS
1712-
fields_tbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
1714+
fields_tbl->shape_id = rb_shape_id(rb_shape_transition_shape_too_complex(obj));
17131715
#endif
17141716
fields_tbl->as.complex.table = st_init_numtable_with_size(1);
17151717

@@ -1886,7 +1888,7 @@ void rb_obj_freeze_inline(VALUE x)
18861888

18871889
// If we're transitioning from "not complex" to "too complex"
18881890
// then evict ivars. This can happen if we run out of shapes
1889-
if (!rb_shape_obj_too_complex(x) && next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
1891+
if (!rb_shape_obj_too_complex(x) && rb_shape_too_complex_p(next_shape)) {
18901892
rb_evict_ivars_to_hash(x);
18911893
}
18921894
rb_shape_set_shape(x, next_shape);
@@ -2029,7 +2031,6 @@ iterate_over_shapes_with_callback(rb_shape_t *shape, rb_ivar_foreach_callback_fu
20292031
case SHAPE_FROZEN:
20302032
return iterate_over_shapes_with_callback(rb_shape_get_parent(shape), callback, itr_data);
20312033
case SHAPE_OBJ_TOO_COMPLEX:
2032-
default:
20332034
rb_bug("Unreachable");
20342035
}
20352036
}
@@ -2117,7 +2118,7 @@ rb_copy_generic_ivar(VALUE clone, VALUE obj)
21172118
if (rb_shape_obj_too_complex(obj)) {
21182119
new_fields_tbl = xmalloc(sizeof(struct gen_fields_tbl));
21192120
#if !SHAPE_IN_BASIC_FLAGS
2120-
new_fields_tbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
2121+
new_fields_tbl->shape_id = old_fields_tbl->shape_id;
21212122
#endif
21222123
new_fields_tbl->as.complex.table = st_copy(obj_fields_tbl->as.complex.table);
21232124
}
@@ -2140,7 +2141,7 @@ rb_copy_generic_ivar(VALUE clone, VALUE obj)
21402141
}
21412142
RB_VM_LOCK_LEAVE();
21422143

2143-
rb_shape_t * obj_shape = rb_shape_get_shape(obj);
2144+
rb_shape_t *obj_shape = rb_shape_get_shape(obj);
21442145
if (rb_shape_frozen_shape_p(obj_shape)) {
21452146
rb_shape_set_shape_id(clone, obj_shape->parent_id);
21462147
}

vm_insnhelper.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,7 +1289,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
12891289
}
12901290

12911291
if (LIKELY(cached_id == shape_id)) {
1292-
RUBY_ASSERT(cached_id != OBJ_TOO_COMPLEX_SHAPE_ID);
1292+
RUBY_ASSERT(!rb_shape_id_too_complex_p(cached_id));
12931293

12941294
if (index == ATTR_INDEX_NOT_SET) {
12951295
return default_value;
@@ -1330,7 +1330,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
13301330
}
13311331
#endif
13321332

1333-
if (shape_id == OBJ_TOO_COMPLEX_SHAPE_ID) {
1333+
if (rb_shape_id_too_complex_p(shape_id)) {
13341334
st_table *table = NULL;
13351335
switch (BUILTIN_TYPE(obj)) {
13361336
case T_CLASS:
@@ -1408,7 +1408,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
14081408
static void
14091409
populate_cache(attr_index_t index, shape_id_t next_shape_id, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, bool is_attr)
14101410
{
1411-
RUBY_ASSERT(next_shape_id != OBJ_TOO_COMPLEX_SHAPE_ID);
1411+
RUBY_ASSERT(!rb_shape_id_too_complex_p(next_shape_id));
14121412

14131413
// Cache population code
14141414
if (is_attr) {
@@ -1436,7 +1436,7 @@ vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic,
14361436

14371437
shape_id_t next_shape_id = ROBJECT_SHAPE_ID(obj);
14381438

1439-
if (next_shape_id != OBJ_TOO_COMPLEX_SHAPE_ID) {
1439+
if (!rb_shape_id_too_complex_p(next_shape_id)) {
14401440
populate_cache(index, next_shape_id, id, iseq, ic, cc, is_attr);
14411441
}
14421442

@@ -1517,7 +1517,7 @@ vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t i
15171517
VM_ASSERT(!rb_ractor_shareable_p(obj) || rb_obj_frozen_p(obj));
15181518

15191519
shape_id_t shape_id = ROBJECT_SHAPE_ID(obj);
1520-
RUBY_ASSERT(dest_shape_id != OBJ_TOO_COMPLEX_SHAPE_ID);
1520+
RUBY_ASSERT(!rb_shape_id_too_complex_p(dest_shape_id));
15211521

15221522
if (LIKELY(shape_id == dest_shape_id)) {
15231523
RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID);

yjit/bindgen/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ fn main() {
101101
.allowlist_function("rb_shape_get_next_no_warnings")
102102
.allowlist_function("rb_shape_id")
103103
.allowlist_function("rb_shape_obj_too_complex")
104+
.allowlist_function("rb_shape_too_complex_p")
104105
.allowlist_var("SHAPE_ID_NUM_BITS")
105-
.allowlist_var("OBJ_TOO_COMPLEX_SHAPE_ID")
106106

107107
// From ruby/internal/intern/object.h
108108
.allowlist_function("rb_obj_is_kind_of")

yjit/src/codegen.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3109,14 +3109,16 @@ fn gen_set_ivar(
31093109
};
31103110

31113111
// The current shape doesn't contain this iv, we need to transition to another shape.
3112+
let mut new_shape_too_complex = false;
31123113
let new_shape = if !shape_too_complex && receiver_t_object && ivar_index.is_none() {
31133114
let current_shape = comptime_receiver.shape_of();
31143115
let next_shape = unsafe { rb_shape_get_next_no_warnings(current_shape, comptime_receiver, ivar_name) };
31153116
let next_shape_id = unsafe { rb_shape_id(next_shape) };
31163117

31173118
// If the VM ran out of shapes, or this class generated too many leaf,
31183119
// it may be de-optimized into OBJ_TOO_COMPLEX_SHAPE (hash-table).
3119-
if next_shape_id == OBJ_TOO_COMPLEX_SHAPE_ID {
3120+
new_shape_too_complex = unsafe { rb_shape_too_complex_p(next_shape) };
3121+
if new_shape_too_complex {
31203122
Some((next_shape_id, None, 0_usize))
31213123
} else {
31223124
let current_capacity = unsafe { (*current_shape).capacity };
@@ -3138,7 +3140,6 @@ fn gen_set_ivar(
31383140
} else {
31393141
None
31403142
};
3141-
let new_shape_too_complex = matches!(new_shape, Some((OBJ_TOO_COMPLEX_SHAPE_ID, _, _)));
31423143

31433144
// If the receiver isn't a T_OBJECT, or uses a custom allocator,
31443145
// then just write out the IV write as a function call.

yjit/src/cruby_bindings.inc.rs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

zjit/bindgen/src/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ fn main() {
115115
.allowlist_function("rb_shape_id")
116116
.allowlist_function("rb_shape_obj_too_complex")
117117
.allowlist_var("SHAPE_ID_NUM_BITS")
118-
.allowlist_var("OBJ_TOO_COMPLEX_SHAPE_ID")
119118

120119
// From ruby/internal/intern/object.h
121120
.allowlist_function("rb_obj_is_kind_of")

0 commit comments

Comments
 (0)