Skip to content

Commit 169b37c

Browse files
committed
fix rb_obj_copy_ivar to not copy object_id over
1 parent a67156d commit 169b37c

1 file changed

Lines changed: 36 additions & 18 deletions

File tree

object.c

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -329,54 +329,72 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
329329
RUBY_ASSERT(!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE));
330330

331331
RUBY_ASSERT(BUILTIN_TYPE(dest) == BUILTIN_TYPE(obj));
332+
333+
unsigned long src_num_ivs = rb_ivar_count(obj);
334+
if (!src_num_ivs) {
335+
return;
336+
}
337+
332338
rb_shape_t *src_shape = rb_shape_get_shape(obj);
333339

334-
if (rb_shape_obj_too_complex(obj)) {
340+
if (rb_shape_too_complex_p(src_shape)) {
335341
// obj is TOO_COMPLEX so we can copy its iv_hash
336342
st_table *table = st_copy(ROBJECT_IV_HASH(obj));
343+
if (rb_shape_has_object_id(src_shape)) {
344+
st_data_t id = (st_data_t)internal_object_id;
345+
st_delete(table, &id, NULL);
346+
}
337347
rb_obj_init_too_complex(dest, table);
338348

339349
return;
340350
}
341351

342-
uint32_t src_num_ivs = RBASIC_FIELDS_COUNT(obj);
343352
rb_shape_t *shape_to_set_on_dest = src_shape;
344-
VALUE * src_buf;
345-
VALUE * dest_buf;
346-
347-
if (!src_num_ivs) {
348-
return;
349-
}
350-
351-
src_buf = ROBJECT_IVPTR(obj);
352-
dest_buf = ROBJECT_IVPTR(dest);
353-
354353
rb_shape_t *initial_shape = rb_shape_get_shape(dest);
355354

356355
if (initial_shape->heap_index != src_shape->heap_index || !rb_shape_canonical_p(src_shape)) {
357356
RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
358357

359358
shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape);
360359
if (UNLIKELY(rb_shape_too_complex_p(shape_to_set_on_dest))) {
361-
st_table * table = rb_st_init_numtable_with_size(src_num_ivs);
360+
st_table *table = rb_st_init_numtable_with_size(src_num_ivs);
362361
rb_obj_copy_ivs_to_hash_table(obj, table);
363362
rb_obj_init_too_complex(dest, table);
364363

365364
return;
366365
}
367366
}
368367

369-
RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity || rb_shape_too_complex_p(shape_to_set_on_dest));
368+
VALUE *src_buf = ROBJECT_IVPTR(obj);
369+
VALUE *dest_buf = ROBJECT_IVPTR(dest);
370+
371+
RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity);
370372
if (initial_shape->capacity < shape_to_set_on_dest->capacity) {
371373
rb_ensure_iv_list_size(dest, initial_shape->capacity, shape_to_set_on_dest->capacity);
372374
dest_buf = ROBJECT_IVPTR(dest);
373375
}
374376

375-
MEMCPY(dest_buf, src_buf, VALUE, src_num_ivs);
377+
if (src_shape->next_field_index == shape_to_set_on_dest->next_field_index) {
378+
// Happy path, we can just memcpy the ivptr content
379+
MEMCPY(dest_buf, src_buf, VALUE, src_num_ivs);
380+
381+
// Fire write barriers
382+
for (uint32_t i = 0; i < src_num_ivs; i++) {
383+
RB_OBJ_WRITTEN(dest, Qundef, dest_buf[i]);
384+
}
385+
}
386+
else {
387+
rb_shape_t *dest_shape = shape_to_set_on_dest;
388+
while (src_shape->parent_id != INVALID_SHAPE_ID) {
389+
if (src_shape->type == SHAPE_IVAR) {
390+
while (dest_shape->edge_name != src_shape->edge_name) {
391+
dest_shape = rb_shape_get_shape_by_id(dest_shape->parent_id);
392+
}
376393

377-
// Fire write barriers
378-
for (uint32_t i = 0; i < src_num_ivs; i++) {
379-
RB_OBJ_WRITTEN(dest, Qundef, dest_buf[i]);
394+
RB_OBJ_WRITE(dest, &dest_buf[dest_shape->next_field_index - 1], src_buf[src_shape->next_field_index - 1]);
395+
}
396+
src_shape = rb_shape_get_shape_by_id(src_shape->parent_id);
397+
}
380398
}
381399

382400
rb_shape_set_shape(dest, shape_to_set_on_dest);

0 commit comments

Comments
 (0)