Skip to content

Commit 8b0868c

Browse files
committed
Refactor rb_shape_rebuild_shape to stop exposing rb_shape_t
1 parent cd355ac commit 8b0868c

File tree

5 files changed

+107
-93
lines changed

5 files changed

+107
-93
lines changed

object.c

Lines changed: 28 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -322,36 +322,28 @@ void
322322
rb_obj_copy_ivar(VALUE dest, VALUE obj)
323323
{
324324
RUBY_ASSERT(!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE));
325-
326325
RUBY_ASSERT(BUILTIN_TYPE(dest) == BUILTIN_TYPE(obj));
327326

328327
unsigned long src_num_ivs = rb_ivar_count(obj);
329328
if (!src_num_ivs) {
330329
return;
331330
}
332331

333-
rb_shape_t *src_shape = rb_obj_shape(obj);
334-
335-
if (rb_shape_too_complex_p(src_shape)) {
336-
// obj is TOO_COMPLEX so we can copy its iv_hash
337-
st_table *table = st_copy(ROBJECT_FIELDS_HASH(obj));
338-
if (rb_shape_has_object_id(src_shape)) {
339-
st_data_t id = (st_data_t)ruby_internal_object_id;
340-
st_delete(table, &id, NULL);
341-
}
342-
rb_obj_init_too_complex(dest, table);
332+
shape_id_t src_shape_id = RBASIC_SHAPE_ID(obj);
343333

334+
if (rb_shape_id_too_complex_p(src_shape_id)) {
335+
rb_shape_copy_complex_ivars(dest, obj, src_shape_id, ROBJECT_FIELDS_HASH(obj));
344336
return;
345337
}
346338

347-
rb_shape_t *shape_to_set_on_dest = src_shape;
348-
rb_shape_t *initial_shape = rb_obj_shape(dest);
339+
shape_id_t dest_shape_id = src_shape_id;
340+
shape_id_t initial_shape_id = RBASIC_SHAPE_ID(dest);
349341

350-
if (initial_shape->heap_index != src_shape->heap_index || !rb_shape_canonical_p(src_shape)) {
351-
RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
342+
if (RSHAPE(initial_shape_id)->heap_index != RSHAPE(src_shape_id)->heap_index || !rb_shape_id_canonical_p(src_shape_id)) {
343+
RUBY_ASSERT(RSHAPE(initial_shape_id)->type == SHAPE_T_OBJECT);
352344

353-
shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape);
354-
if (UNLIKELY(rb_shape_too_complex_p(shape_to_set_on_dest))) {
345+
dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id);
346+
if (UNLIKELY(rb_shape_id_too_complex_p(dest_shape_id))) {
355347
st_table *table = rb_st_init_numtable_with_size(src_num_ivs);
356348
rb_obj_copy_ivs_to_hash_table(obj, table);
357349
rb_obj_init_too_complex(dest, table);
@@ -363,36 +355,14 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
363355
VALUE *src_buf = ROBJECT_FIELDS(obj);
364356
VALUE *dest_buf = ROBJECT_FIELDS(dest);
365357

366-
RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity);
367-
if (initial_shape->capacity < shape_to_set_on_dest->capacity) {
368-
rb_ensure_iv_list_size(dest, initial_shape->capacity, shape_to_set_on_dest->capacity);
358+
RUBY_ASSERT(src_num_ivs <= RSHAPE(dest_shape_id)->capacity);
359+
if (RSHAPE(initial_shape_id)->capacity < RSHAPE(dest_shape_id)->capacity) {
360+
rb_ensure_iv_list_size(dest, RSHAPE(initial_shape_id)->capacity, RSHAPE(dest_shape_id)->capacity);
369361
dest_buf = ROBJECT_FIELDS(dest);
370362
}
371363

372-
if (src_shape->next_field_index == shape_to_set_on_dest->next_field_index) {
373-
// Happy path, we can just memcpy the fields content
374-
MEMCPY(dest_buf, src_buf, VALUE, src_num_ivs);
375-
376-
// Fire write barriers
377-
for (uint32_t i = 0; i < src_num_ivs; i++) {
378-
RB_OBJ_WRITTEN(dest, Qundef, dest_buf[i]);
379-
}
380-
}
381-
else {
382-
rb_shape_t *dest_shape = shape_to_set_on_dest;
383-
while (src_shape->parent_id != INVALID_SHAPE_ID) {
384-
if (src_shape->type == SHAPE_IVAR) {
385-
while (dest_shape->edge_name != src_shape->edge_name) {
386-
dest_shape = RSHAPE(dest_shape->parent_id);
387-
}
388-
389-
RB_OBJ_WRITE(dest, &dest_buf[dest_shape->next_field_index - 1], src_buf[src_shape->next_field_index - 1]);
390-
}
391-
src_shape = RSHAPE(src_shape->parent_id);
392-
}
393-
}
394-
395-
rb_shape_set_shape(dest, shape_to_set_on_dest);
364+
rb_shape_copy_fields(dest, dest_buf, dest_shape_id, obj, src_buf, src_shape_id);
365+
rb_shape_set_shape_id(dest, dest_shape_id);
396366
}
397367

398368
static void
@@ -404,11 +374,20 @@ init_copy(VALUE dest, VALUE obj)
404374
RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR);
405375
// Copies the shape id from obj to dest
406376
RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR);
407-
if (RB_TYPE_P(obj, T_OBJECT)) {
408-
rb_obj_copy_ivar(dest, obj);
409-
}
410-
else {
411-
rb_copy_generic_ivar(dest, obj);
377+
switch (BUILTIN_TYPE(obj)) {
378+
case T_IMEMO:
379+
rb_bug("Unreacheable");
380+
break;
381+
case T_CLASS:
382+
case T_MODULE:
383+
// noop: handled in class.c: rb_mod_init_copy
384+
break;
385+
case T_OBJECT:
386+
rb_obj_copy_ivar(dest, obj);
387+
break;
388+
default:
389+
rb_copy_generic_ivar(dest, obj);
390+
break;
412391
}
413392
rb_gc_copy_attributes(dest, obj);
414393
}

shape.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,12 @@ rb_shape_has_object_id(rb_shape_t *shape)
685685
return shape->flags & SHAPE_FL_HAS_OBJECT_ID;
686686
}
687687

688+
bool
689+
rb_shape_id_has_object_id(shape_id_t shape_id)
690+
{
691+
return rb_shape_has_object_id(RSHAPE(shape_id));
692+
}
693+
688694
shape_id_t
689695
rb_shape_transition_object_id(VALUE obj)
690696
{
@@ -1032,6 +1038,53 @@ rb_shape_rebuild_shape(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
10321038
return midway_shape;
10331039
}
10341040

1041+
shape_id_t
1042+
rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id)
1043+
{
1044+
return rb_shape_id(rb_shape_rebuild_shape(RSHAPE(initial_shape_id), RSHAPE(dest_shape_id)));
1045+
}
1046+
1047+
void
1048+
rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALUE src, VALUE *src_buf, shape_id_t src_shape_id)
1049+
{
1050+
rb_shape_t *dest_shape = RSHAPE(dest_shape_id);
1051+
rb_shape_t *src_shape = RSHAPE(src_shape_id);
1052+
1053+
if (src_shape->next_field_index == dest_shape->next_field_index) {
1054+
// Happy path, we can just memcpy the ivptr content
1055+
MEMCPY(dest_buf, src_buf, VALUE, dest_shape->next_field_index);
1056+
1057+
// Fire write barriers
1058+
for (uint32_t i = 0; i < dest_shape->next_field_index; i++) {
1059+
RB_OBJ_WRITTEN(dest, Qundef, dest_buf[i]);
1060+
}
1061+
}
1062+
else {
1063+
while (src_shape->parent_id != INVALID_SHAPE_ID) {
1064+
if (src_shape->type == SHAPE_IVAR) {
1065+
while (dest_shape->edge_name != src_shape->edge_name) {
1066+
dest_shape = RSHAPE(dest_shape->parent_id);
1067+
}
1068+
1069+
RB_OBJ_WRITE(dest, &dest_buf[dest_shape->next_field_index - 1], src_buf[src_shape->next_field_index - 1]);
1070+
}
1071+
src_shape = RSHAPE(src_shape->parent_id);
1072+
}
1073+
}
1074+
}
1075+
1076+
void
1077+
rb_shape_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_table *fields_table)
1078+
{
1079+
// obj is TOO_COMPLEX so we can copy its iv_hash
1080+
st_table *table = st_copy(fields_table);
1081+
if (rb_shape_id_has_object_id(src_shape_id)) {
1082+
st_data_t id = (st_data_t)ruby_internal_object_id;
1083+
st_delete(table, &id, NULL);
1084+
}
1085+
rb_obj_init_too_complex(dest, table);
1086+
}
1087+
10351088
RUBY_FUNC_EXPORTED bool
10361089
rb_shape_obj_too_complex_p(VALUE obj)
10371090
{

shape.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ bool rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *v
127127
RUBY_FUNC_EXPORTED bool rb_shape_obj_too_complex_p(VALUE obj);
128128
bool rb_shape_too_complex_p(rb_shape_t *shape);
129129
bool rb_shape_id_too_complex_p(shape_id_t shape_id);
130+
bool rb_shape_has_object_id(rb_shape_t *shape);
131+
bool rb_shape_id_has_object_id(shape_id_t shape_id);
130132

131133
void rb_shape_set_shape(VALUE obj, rb_shape_t *shape);
132134
shape_id_t rb_shape_transition_frozen(VALUE obj);
@@ -136,10 +138,11 @@ shape_id_t rb_shape_transition_add_ivar(VALUE obj, ID id);
136138
shape_id_t rb_shape_transition_add_ivar_no_warnings(VALUE obj, ID id);
137139
shape_id_t rb_shape_transition_object_id(VALUE obj);
138140

139-
bool rb_shape_has_object_id(rb_shape_t *shape);
140141
void rb_shape_free_all(void);
141142

142-
rb_shape_t *rb_shape_rebuild_shape(rb_shape_t *initial_shape, rb_shape_t *dest_shape);
143+
shape_id_t rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id);
144+
void rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALUE src, VALUE *src_buf, shape_id_t src_shape_id);
145+
void rb_shape_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_table *fields_table);
143146

144147
static inline rb_shape_t *
145148
rb_obj_shape(VALUE obj)
@@ -153,6 +156,12 @@ rb_shape_canonical_p(rb_shape_t *shape)
153156
return !shape->flags;
154157
}
155158

159+
static inline bool
160+
rb_shape_id_canonical_p(shape_id_t shape_id)
161+
{
162+
return rb_shape_canonical_p(RSHAPE(shape_id));
163+
}
164+
156165
static inline shape_id_t
157166
rb_shape_root(size_t heap_id)
158167
{

variable.c

Lines changed: 14 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2330,34 +2330,27 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj)
23302330
goto clear;
23312331
}
23322332

2333-
rb_shape_t *src_shape = rb_obj_shape(obj);
2333+
shape_id_t src_shape_id = rb_obj_shape_id(obj);
23342334

23352335
if (rb_gen_fields_tbl_get(obj, 0, &obj_fields_tbl)) {
23362336
if (gen_fields_tbl_count(obj, obj_fields_tbl) == 0)
23372337
goto clear;
23382338

23392339
FL_SET(dest, FL_EXIVAR);
23402340

2341-
if (rb_shape_too_complex_p(src_shape)) {
2342-
// obj is TOO_COMPLEX so we can copy its iv_hash
2343-
st_table *table = st_copy(obj_fields_tbl->as.complex.table);
2344-
if (rb_shape_has_object_id(src_shape)) {
2345-
st_data_t id = (st_data_t)ruby_internal_object_id;
2346-
st_delete(table, &id, NULL);
2347-
}
2348-
rb_obj_init_too_complex(dest, table);
2349-
2341+
if (rb_shape_id_too_complex_p(src_shape_id)) {
2342+
rb_shape_copy_complex_ivars(dest, obj, src_shape_id, obj_fields_tbl->as.complex.table);
23502343
return;
23512344
}
23522345

2353-
rb_shape_t *shape_to_set_on_dest = src_shape;
2354-
rb_shape_t *initial_shape = rb_obj_shape(dest);
2346+
shape_id_t dest_shape_id = src_shape_id;
2347+
shape_id_t initial_shape_id = rb_obj_shape_id(dest);
23552348

2356-
if (!rb_shape_canonical_p(src_shape)) {
2357-
RUBY_ASSERT(initial_shape->type == SHAPE_ROOT);
2349+
if (!rb_shape_id_canonical_p(src_shape_id)) {
2350+
RUBY_ASSERT(RSHAPE(initial_shape_id)->type == SHAPE_ROOT);
23582351

2359-
shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape);
2360-
if (UNLIKELY(rb_shape_too_complex_p(shape_to_set_on_dest))) {
2352+
dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id);
2353+
if (UNLIKELY(rb_shape_id_too_complex_p(dest_shape_id))) {
23612354
st_table *table = rb_st_init_numtable_with_size(src_num_ivs);
23622355
rb_obj_copy_ivs_to_hash_table(obj, table);
23632356
rb_obj_init_too_complex(dest, table);
@@ -2366,39 +2359,18 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj)
23662359
}
23672360
}
23682361

2369-
if (!shape_to_set_on_dest->capacity) {
2370-
rb_shape_set_shape(dest, shape_to_set_on_dest);
2362+
if (!RSHAPE(dest_shape_id)->capacity) {
2363+
rb_shape_set_shape_id(dest, dest_shape_id);
23712364
FL_UNSET(dest, FL_EXIVAR);
23722365
return;
23732366
}
23742367

2375-
new_fields_tbl = gen_fields_tbl_resize(0, shape_to_set_on_dest->capacity);
2368+
new_fields_tbl = gen_fields_tbl_resize(0, RSHAPE(dest_shape_id)->capacity);
23762369

23772370
VALUE *src_buf = obj_fields_tbl->as.shape.fields;
23782371
VALUE *dest_buf = new_fields_tbl->as.shape.fields;
23792372

2380-
if (src_shape->next_field_index == shape_to_set_on_dest->next_field_index) {
2381-
// Happy path, we can just memcpy the ivptr content
2382-
MEMCPY(dest_buf, src_buf, VALUE, shape_to_set_on_dest->next_field_index);
2383-
2384-
// Fire write barriers
2385-
for (uint32_t i = 0; i < shape_to_set_on_dest->next_field_index; i++) {
2386-
RB_OBJ_WRITTEN(dest, Qundef, dest_buf[i]);
2387-
}
2388-
}
2389-
else {
2390-
rb_shape_t *dest_shape = shape_to_set_on_dest;
2391-
while (src_shape->parent_id != INVALID_SHAPE_ID) {
2392-
if (src_shape->type == SHAPE_IVAR) {
2393-
while (dest_shape->edge_name != src_shape->edge_name) {
2394-
dest_shape = RSHAPE(dest_shape->parent_id);
2395-
}
2396-
2397-
RB_OBJ_WRITE(dest, &dest_buf[dest_shape->next_field_index - 1], src_buf[src_shape->next_field_index - 1]);
2398-
}
2399-
src_shape = RSHAPE(src_shape->parent_id);
2400-
}
2401-
}
2373+
rb_shape_copy_fields(dest, dest_buf, dest_shape_id, obj, src_buf, src_shape_id);
24022374

24032375
/*
24042376
* c.fields_tbl may change in gen_fields_copy due to realloc,
@@ -2409,7 +2381,7 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj)
24092381
st_insert(generic_fields_tbl_no_ractor_check(obj), (st_data_t)dest, (st_data_t)new_fields_tbl);
24102382
}
24112383

2412-
rb_shape_set_shape(dest, shape_to_set_on_dest);
2384+
rb_shape_set_shape_id(dest, dest_shape_id);
24132385
}
24142386
return;
24152387

variable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct gen_fields_tbl {
2525
};
2626

2727
int rb_ivar_generic_fields_tbl_lookup(VALUE obj, struct gen_fields_tbl **);
28+
void rb_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_table *fields_table);
2829

2930
void rb_free_rb_global_tbl(void);
3031
void rb_free_generic_fields_tbl_(void);

0 commit comments

Comments
 (0)