@@ -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