@@ -322,61 +322,93 @@ rb_obj_singleton_class(VALUE obj)
322322 return rb_singleton_class (obj );
323323}
324324
325+ struct ivar_copy_value_args = {
326+ VALUE dest ;
327+ VALUE src ;
328+ };
329+
330+ static int
331+ ivar_copy_value_i (ID key , VALUE _empty_val , st_data_t data )
332+ {
333+ struct ivar_copy_value_args args = (struct ivar_copy_value_args * )data ;
334+
335+ rb_ivar_set (args -> dest , key , rb_ivar_get (args -> src , key ));
336+ return ST_CONTINUE ;
337+ }
338+
325339/*! \private */
326340void
327341rb_obj_copy_ivar (VALUE dest , VALUE obj )
328342{
329343 RUBY_ASSERT (!RB_TYPE_P (obj , T_CLASS ) && !RB_TYPE_P (obj , T_MODULE ));
330344
331345 RUBY_ASSERT (BUILTIN_TYPE (dest ) == BUILTIN_TYPE (obj ));
346+
347+ unsigned long src_num_ivs = rb_ivar_count (obj );
348+ if (!src_num_ivs ) {
349+ return ;
350+ }
351+
332352 rb_shape_t * src_shape = rb_shape_get_shape (obj );
333353
334- if (rb_shape_obj_too_complex ( obj )) {
354+ if (rb_shape_too_complex_p ( src_shape )) {
335355 // obj is TOO_COMPLEX so we can copy its iv_hash
336356 st_table * table = st_copy (ROBJECT_IV_HASH (obj ));
357+ if (rb_shape_has_object_id (src_shape )) {
358+ st_data_t id = (st_data_t )internal_object_id ;
359+ st_delete (table , & id , NULL );
360+ }
337361 rb_obj_init_too_complex (dest , table );
338362
339363 return ;
340364 }
341365
342- uint32_t src_num_ivs = RBASIC_FIELDS_COUNT (obj );
343366 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-
354367 rb_shape_t * initial_shape = rb_shape_get_shape (dest );
355368
356369 if (initial_shape -> heap_index != src_shape -> heap_index || !rb_shape_canonical_p (src_shape )) {
357370 RUBY_ASSERT (initial_shape -> type == SHAPE_T_OBJECT );
358371
359372 shape_to_set_on_dest = rb_shape_rebuild_shape (initial_shape , src_shape );
360373 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 );
374+ st_table * table = rb_st_init_numtable_with_size (src_num_ivs );
362375 rb_obj_copy_ivs_to_hash_table (obj , table );
363376 rb_obj_init_too_complex (dest , table );
364377
365378 return ;
366379 }
367380 }
368381
369- RUBY_ASSERT (src_num_ivs <= shape_to_set_on_dest -> capacity || rb_shape_too_complex_p (shape_to_set_on_dest ));
382+ VALUE * src_buf = ROBJECT_IVPTR (obj );
383+ VALUE * dest_buf = ROBJECT_IVPTR (dest );
384+
385+ RUBY_ASSERT (src_num_ivs <= shape_to_set_on_dest -> capacity );
370386 if (initial_shape -> capacity < shape_to_set_on_dest -> capacity ) {
371387 rb_ensure_iv_list_size (dest , initial_shape -> capacity , shape_to_set_on_dest -> capacity );
372388 dest_buf = ROBJECT_IVPTR (dest );
373389 }
374390
375- MEMCPY (dest_buf , src_buf , VALUE , src_num_ivs );
391+ if (src_shape -> next_field_index == shape_to_set_on_dest -> next_field_index ) {
392+ // Happy path, we can just memcpy the ivptr content
393+ MEMCPY (dest_buf , src_buf , VALUE , src_num_ivs );
376394
377- // Fire write barriers
378- for (uint32_t i = 0 ; i < src_num_ivs ; i ++ ) {
379- RB_OBJ_WRITTEN (dest , Qundef , dest_buf [i ]);
395+ // Fire write barriers
396+ for (uint32_t i = 0 ; i < src_num_ivs ; i ++ ) {
397+ RB_OBJ_WRITTEN (dest , Qundef , dest_buf [i ]);
398+ }
399+ }
400+ else {
401+ itr_data = {
402+ .dest = dest ,
403+ .src_obj = obj ,
404+ }
405+ VALUE args [2 ] = {dest , obj };
406+ iterate_over_shapes_with_callback (shape_to_set_on_dest , ivar_copy_value , & itr_data );
407+ // FIXME: this is a stub
408+
409+ rb_ivar_foreach (obj , ivar_copy_i , (st_data_t )dest );
410+ // The shape was rebuilt, we have to copy ivars one by one.
411+ // rb_bug("Not implemented");
380412 }
381413
382414 rb_shape_set_shape (dest , shape_to_set_on_dest );
0 commit comments