Project

General

Profile

Feature #15626 ยป 0001-GC-Compaction-for-MRI.patch

tenderlovemaking (Aaron Patterson), 02/27/2019 11:43 PM

View differences:

class.c
539 539

  
540 540
    rb_name_class(obj, id);
541 541
    rb_const_set((rb_cObject ? rb_cObject : obj), id, obj);
542
    rb_vm_add_root_module(id, obj);
542 543
    return obj;
543 544
}
544 545

  
......
781 782
    }
782 783
    module = rb_define_module_id(id);
783 784
    rb_vm_add_root_module(id, module);
785
    rb_gc_register_mark_object(module);
784 786
    rb_const_set(rb_cObject, id, module);
785 787

  
786 788
    return module;
constant.h
31 31
typedef struct rb_const_entry_struct {
32 32
    rb_const_flag_t flag;
33 33
    int line;
34
    const VALUE value;            /* should be mark */
35
    const VALUE file;             /* should be mark */
34
    VALUE value;            /* should be mark */
35
    VALUE file;             /* should be mark */
36 36
} rb_const_entry_t;
37 37

  
38 38
VALUE rb_mod_private_constant(int argc, const VALUE *argv, VALUE obj);
ext/-test-/memory_location/extconf.rb
1
# frozen_string_literal: false
2
$srcs = Dir[File.join($srcdir, "*.{#{SRC_EXT.join(%q{,})}}")]
3
inits = $srcs.map {|s| File.basename(s, ".*")}
4
inits.delete("init")
5
inits.map! {|s|"X(#{s})"}
6
$defs << "-DTEST_INIT_FUNCS(X)=\"#{inits.join(' ')}\""
7
create_makefile("-test-/memory_location")
ext/-test-/memory_location/memory_location.c
1
#include "ruby.h"
2

  
3
#if SIZEOF_LONG == SIZEOF_VOIDP
4
# define nonspecial_obj_id(obj) (VALUE)((SIGNED_VALUE)(obj)|FIXNUM_FLAG)
5
# define obj_id_to_ref(objid) ((objid) ^ FIXNUM_FLAG) /* unset FIXNUM_FLAG */
6
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
7
# define nonspecial_obj_id(obj) LL2NUM((SIGNED_VALUE)(obj) / 2)
8
# define obj_id_to_ref(objid) (FIXNUM_P(objid) ? \
9
   ((objid) ^ FIXNUM_FLAG) : (NUM2PTR(objid) << 1))
10
#else
11
# error not supported
12
#endif
13

  
14
static VALUE
15
rb_memory_location(VALUE self)
16
{
17
    return nonspecial_obj_id(self);
18
}
19

  
20
void
21
Init_memory_location(void)
22
{
23
    rb_define_method(rb_mKernel, "memory_location", rb_memory_location, 0);
24
}
25

  
gc.c
29 29
#include "ruby_atomic.h"
30 30
#include "probes.h"
31 31
#include "id_table.h"
32
#include "symbol.h"
32 33
#include <stdio.h>
33 34
#include <stdarg.h>
34 35
#include <setjmp.h>
......
194 195
    FALSE,
195 196
};
196 197

  
198
static st_table *id_to_obj_tbl;
199
static st_table *obj_to_id_tbl;
200

  
197 201
/* GC_DEBUG:
198 202
 *  enable to embed GC debugging information.
199 203
 */
......
404 408
	    VALUE flags;		/* always 0 for freed obj */
405 409
	    struct RVALUE *next;
406 410
	} free;
411
	struct RMoved  moved;
407 412
	struct RBasic  basic;
408 413
	struct RObject object;
409 414
	struct RClass  klass;
......
581 586
#if USE_RGENGC
582 587
	size_t minor_gc_count;
583 588
	size_t major_gc_count;
589
	size_t object_id_collisions;
584 590
#if RGENGC_PROFILE > 0
585 591
	size_t total_generated_normal_object_count;
586 592
	size_t total_generated_shady_object_count;
......
635 641
	size_t error_count;
636 642
#endif
637 643
    } rgengc;
644

  
645
    struct {
646
	size_t considered_count_table[T_MASK];
647
	size_t moved_count_table[T_MASK];
648
    } rcompactor;
649

  
638 650
#if GC_ENABLE_INCREMENTAL_MARK
639 651
    struct {
640 652
	size_t pooled_slots;
......
682 694
#if USE_RGENGC
683 695
    bits_t wb_unprotected_bits[HEAP_PAGE_BITMAP_LIMIT];
684 696
#endif
697
    /* If set, the object is not movable */
698
    bits_t pinned_bits[HEAP_PAGE_BITMAP_LIMIT];
685 699
    /* the following three bitmaps are cleared at the beginning of full GC */
686 700
    bits_t mark_bits[HEAP_PAGE_BITMAP_LIMIT];
687 701
#if USE_RGENGC
......
706 720

  
707 721
/* getting bitmap */
708 722
#define GET_HEAP_MARK_BITS(x)           (&GET_HEAP_PAGE(x)->mark_bits[0])
723
#define GET_HEAP_PINNED_BITS(x)         (&GET_HEAP_PAGE(x)->pinned_bits[0])
709 724
#if USE_RGENGC
710 725
#define GET_HEAP_UNCOLLECTIBLE_BITS(x)  (&GET_HEAP_PAGE(x)->uncollectible_bits[0])
711 726
#define GET_HEAP_WB_UNPROTECTED_BITS(x) (&GET_HEAP_PAGE(x)->wb_unprotected_bits[0])
......
826 841
int ruby_disable_gc = 0;
827 842

  
828 843
void rb_iseq_mark(const rb_iseq_t *iseq);
844
void rb_iseq_update_references(rb_iseq_t *iseq);
829 845
void rb_iseq_free(const rb_iseq_t *iseq);
846
void rb_vm_update_references(void *ptr);
830 847

  
831 848
void rb_gcdebug_print_obj_condition(VALUE obj);
832 849

  
......
861 878
static void gc_sweep_continue(rb_objspace_t *objspace, rb_heap_t *heap);
862 879

  
863 880
static inline void gc_mark(rb_objspace_t *objspace, VALUE ptr);
881
static inline void gc_pin(rb_objspace_t *objspace, VALUE ptr);
882
static inline void gc_mark_and_pin(rb_objspace_t *objspace, VALUE ptr);
864 883
static void gc_mark_ptr(rb_objspace_t *objspace, VALUE ptr);
865 884
NO_SANITIZE("memory", static void gc_mark_maybe(rb_objspace_t *objspace, VALUE ptr));
885
static void gc_mark_and_pin_maybe(rb_objspace_t *objspace, VALUE ptr);
866 886
static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr);
867 887

  
868 888
static int gc_mark_stacked_objects_incremental(rb_objspace_t *, size_t count);
......
895 915
static inline void gc_prof_set_malloc_info(rb_objspace_t *);
896 916
static inline void gc_prof_set_heap_info(rb_objspace_t *);
897 917

  
918
#define TYPED_UPDATE_IF_MOVED(_objspace, _type, _thing) do { \
919
    if (gc_object_moved_p(_objspace, (VALUE)_thing)) { \
920
       (_thing) = (_type)RMOVED((_thing))->destination; \
921
    } \
922
} while (0)
923

  
924
#define UPDATE_IF_MOVED(_objspace, _thing) TYPED_UPDATE_IF_MOVED(_objspace, VALUE, _thing)
925

  
898 926
#define gc_prof_record(objspace) (objspace)->profile.current_record
899 927
#define gc_prof_enabled(objspace) ((objspace)->profile.run && (objspace)->profile.current_record)
900 928

  
......
1020 1048
#define FL_UNSET2(x,f) FL_CHECK2("FL_UNSET2", x, RBASIC(x)->flags &= ~(f))
1021 1049

  
1022 1050
#define RVALUE_MARK_BITMAP(obj)           MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), (obj))
1051
#define RVALUE_PIN_BITMAP(obj)            MARKED_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), (obj))
1023 1052
#define RVALUE_PAGE_MARKED(page, obj)     MARKED_IN_BITMAP((page)->mark_bits, (obj))
1024 1053

  
1025 1054
#if USE_RGENGC
......
1113 1142
}
1114 1143
#endif
1115 1144

  
1145
static inline int
1146
gc_object_moved_p(rb_objspace_t * objspace, VALUE obj)
1147
{
1148
    if (RB_SPECIAL_CONST_P(obj)) {
1149
	return FALSE;
1150
    } else {
1151
	return BUILTIN_TYPE(obj) == T_MOVED;
1152
    }
1153
}
1154

  
1116 1155
static inline int
1117 1156
RVALUE_MARKED(VALUE obj)
1118 1157
{
......
1120 1159
    return RVALUE_MARK_BITMAP(obj) != 0;
1121 1160
}
1122 1161

  
1162
static inline int
1163
RVALUE_PINNED(VALUE obj)
1164
{
1165
    check_rvalue_consistency(obj);
1166
    return RVALUE_PIN_BITMAP(obj) != 0;
1167
}
1168

  
1123 1169
#if USE_RGENGC
1124 1170
static inline int
1125 1171
RVALUE_WB_UNPROTECTED(VALUE obj)
......
2191 2237
	rb_free_generic_ivar((VALUE)obj);
2192 2238
	FL_UNSET(obj, FL_EXIVAR);
2193 2239
    }
2240
    VALUE id;
2241
    if (st_lookup(obj_to_id_tbl, (st_data_t)obj, &id)) {
2242
#ifdef GC_COMPACT_DEBUG
2243
	fprintf(stderr, "Collecting %p -> %p\n", obj, obj_id_to_ref(id));
2244
#endif
2245
	st_delete(obj_to_id_tbl, (st_data_t *)&obj, 0);
2246
	st_delete(id_to_obj_tbl, (st_data_t *)&id, 0);
2247
    }
2194 2248

  
2195 2249
#if USE_RGENGC
2196 2250
    if (RVALUE_WB_UNPROTECTED(obj)) CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj);
......
2359 2413
	break;
2360 2414
      case T_RATIONAL:
2361 2415
      case T_COMPLEX:
2416
      case T_MOVED:
2362 2417
	break;
2363 2418
      case T_ICLASS:
2364 2419
	/* Basically , T_ICLASS shares table with the module */
......
2624 2679
	    UNEXPECTED_NODE(internal_object_p);
2625 2680
	    break;
2626 2681
	  case T_NONE:
2682
	  case T_MOVED:
2627 2683
	  case T_IMEMO:
2628 2684
	  case T_ICLASS:
2629 2685
	  case T_ZOMBIE:
......
3203 3259
    if (ptr == Qtrue) return Qtrue;
3204 3260
    if (ptr == Qfalse) return Qfalse;
3205 3261
    if (ptr == Qnil) return Qnil;
3262

  
3206 3263
    if (FIXNUM_P(ptr)) return (VALUE)ptr;
3207 3264
    if (FLONUM_P(ptr)) return (VALUE)ptr;
3208 3265
    ptr = obj_id_to_ref(objid);
3209 3266

  
3267
    if (st_lookup(id_to_obj_tbl, objid, &ptr)) {
3268
	return ptr;
3269
    }
3270

  
3210 3271
    if ((ptr % sizeof(RVALUE)) == (4 << 2)) {
3211 3272
        ID symid = ptr / sizeof(RVALUE);
3212 3273
        if (rb_id2str(symid) == 0)
......
3295 3356
    else if (SPECIAL_CONST_P(obj)) {
3296 3357
	return LONG2NUM((SIGNED_VALUE)obj);
3297 3358
    }
3359
    VALUE id;
3360

  
3361
    if (st_lookup(obj_to_id_tbl, (st_data_t)obj, &id)) {
3362
#ifdef GC_COMPACT_DEBUG
3363
	fprintf(stderr, "Second time object_id was called on this object: %p\n", obj);
3364
#endif
3365
	return id;
3366
    } else {
3367
	int tries;
3368
	id = nonspecial_obj_id(obj);
3369

  
3370
	while(1) {
3371
	    /* id is the object id */
3372
	    if (st_lookup(id_to_obj_tbl, (st_data_t)id, 0)) {
3373
#ifdef GC_COMPACT_DEBUG
3374
		fprintf(stderr, "object_id called on %p, but there was a collision at %d\n", obj, NUM2INT(id));
3375
#endif
3376
		rb_objspace_t *objspace = &rb_objspace;
3377
		objspace->profile.object_id_collisions++;
3378
		id += 40;
3379
	    } else {
3380
#ifdef GC_COMPACT_DEBUG
3381
		fprintf(stderr, "Initial insert: %p id: %d\n", obj, NUM2INT(id));
3382
#endif
3383
		st_insert(obj_to_id_tbl, (st_data_t)obj, id);
3384
		st_insert(id_to_obj_tbl, (st_data_t)id, obj);
3385
		return id;
3386
	    }
3387
	}
3388
    }
3298 3389
    return nonspecial_obj_id(obj);
3299 3390
}
3300 3391

  
......
3417 3508
	break;
3418 3509

  
3419 3510
      case T_ZOMBIE:
3511
      case T_MOVED:
3420 3512
	break;
3421 3513

  
3422 3514
      default:
......
3442 3534
    return ST_CONTINUE;
3443 3535
}
3444 3536

  
3537
static VALUE
3538
type_sym(int type)
3539
{
3540
    switch (type) {
3541
#define COUNT_TYPE(t) case (t): return ID2SYM(rb_intern(#t)); break;
3542
	COUNT_TYPE(T_NONE);
3543
	COUNT_TYPE(T_OBJECT);
3544
	COUNT_TYPE(T_CLASS);
3545
	COUNT_TYPE(T_MODULE);
3546
	COUNT_TYPE(T_FLOAT);
3547
	COUNT_TYPE(T_STRING);
3548
	COUNT_TYPE(T_REGEXP);
3549
	COUNT_TYPE(T_ARRAY);
3550
	COUNT_TYPE(T_HASH);
3551
	COUNT_TYPE(T_STRUCT);
3552
	COUNT_TYPE(T_BIGNUM);
3553
	COUNT_TYPE(T_FILE);
3554
	COUNT_TYPE(T_DATA);
3555
	COUNT_TYPE(T_MATCH);
3556
	COUNT_TYPE(T_COMPLEX);
3557
	COUNT_TYPE(T_RATIONAL);
3558
	COUNT_TYPE(T_NIL);
3559
	COUNT_TYPE(T_TRUE);
3560
	COUNT_TYPE(T_FALSE);
3561
	COUNT_TYPE(T_SYMBOL);
3562
	COUNT_TYPE(T_FIXNUM);
3563
	COUNT_TYPE(T_IMEMO);
3564
	COUNT_TYPE(T_UNDEF);
3565
	COUNT_TYPE(T_NODE);
3566
	COUNT_TYPE(T_ICLASS);
3567
	COUNT_TYPE(T_ZOMBIE);
3568
	COUNT_TYPE(T_MOVED);
3569
#undef COUNT_TYPE
3570
	default:              return INT2NUM(type); break;
3571
    }
3572
}
3573

  
3445 3574
/*
3446 3575
 *  call-seq:
3447 3576
 *     ObjectSpace.count_objects([result_hash]) -> hash
......
3523 3652
    rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(freed));
3524 3653

  
3525 3654
    for (i = 0; i <= T_MASK; i++) {
3526
        VALUE type;
3527
        switch (i) {
3528
#define COUNT_TYPE(t) case (t): type = ID2SYM(rb_intern(#t)); break;
3529
	    COUNT_TYPE(T_NONE);
3530
	    COUNT_TYPE(T_OBJECT);
3531
	    COUNT_TYPE(T_CLASS);
3532
	    COUNT_TYPE(T_MODULE);
3533
	    COUNT_TYPE(T_FLOAT);
3534
	    COUNT_TYPE(T_STRING);
3535
	    COUNT_TYPE(T_REGEXP);
3536
	    COUNT_TYPE(T_ARRAY);
3537
	    COUNT_TYPE(T_HASH);
3538
	    COUNT_TYPE(T_STRUCT);
3539
	    COUNT_TYPE(T_BIGNUM);
3540
	    COUNT_TYPE(T_FILE);
3541
	    COUNT_TYPE(T_DATA);
3542
	    COUNT_TYPE(T_MATCH);
3543
	    COUNT_TYPE(T_COMPLEX);
3544
	    COUNT_TYPE(T_RATIONAL);
3545
	    COUNT_TYPE(T_NIL);
3546
	    COUNT_TYPE(T_TRUE);
3547
	    COUNT_TYPE(T_FALSE);
3548
	    COUNT_TYPE(T_SYMBOL);
3549
	    COUNT_TYPE(T_FIXNUM);
3550
	    COUNT_TYPE(T_IMEMO);
3551
	    COUNT_TYPE(T_UNDEF);
3552
	    COUNT_TYPE(T_ICLASS);
3553
	    COUNT_TYPE(T_ZOMBIE);
3554
#undef COUNT_TYPE
3555
          default:              type = INT2NUM(i); break;
3556
        }
3655
        VALUE type = type_sym(i);
3557 3656
        if (counts[i])
3558 3657
            rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
3559 3658
    }
......
4007 4106
static void
4008 4107
push_mark_stack(mark_stack_t *stack, VALUE data)
4009 4108
{
4109
    if (BUILTIN_TYPE(data) == T_MOVED) {
4110
	VALUE dest = (VALUE)RMOVED(data)->destination;
4111
	fprintf(stderr, "<%s>", obj_info(dest));
4112
	rb_bug("moved item (%p -> %p (type: %d) should not be marked", (RVALUE *)data, (RVALUE *)dest, BUILTIN_TYPE(dest));
4113
    }
4010 4114
    if (stack->index == stack->limit) {
4011 4115
        push_mark_stack_chunk(stack);
4012 4116
    }
......
4168 4272
    VALUE v;
4169 4273
    while (n--) {
4170 4274
        v = *x;
4171
	gc_mark_maybe(objspace, v);
4275
	gc_mark_and_pin_maybe(objspace, v);
4172 4276
	x++;
4173 4277
    }
4174 4278
}
......
4189 4293
    gc_mark_locations(&rb_objspace, start, end);
4190 4294
}
4191 4295

  
4296
static void
4297
gc_mark_and_pin_values(rb_objspace_t *objspace, long n, const VALUE *values)
4298
{
4299
    long i;
4300

  
4301
    for (i=0; i<n; i++) {
4302
	gc_mark_and_pin(objspace, values[i]);
4303
    }
4304
}
4305

  
4192 4306
static void
4193 4307
gc_mark_values(rb_objspace_t *objspace, long n, const VALUE *values)
4194 4308
{
......
4203 4317
rb_gc_mark_values(long n, const VALUE *values)
4204 4318
{
4205 4319
    rb_objspace_t *objspace = &rb_objspace;
4206
    gc_mark_values(objspace, n, values);
4320
    gc_mark_and_pin_values(objspace, n, values);
4321
}
4322

  
4323
static void
4324
gc_mark_and_pin_stack_values(rb_objspace_t *objspace, long n, const VALUE *values)
4325
{
4326
    long i;
4327

  
4328
    for (i=0; i<n; i++) {
4329
	/* skip MOVED objects that are on the stack */
4330
	if (is_markable_object(objspace, values[i]) && T_MOVED != BUILTIN_TYPE(values[i])) {
4331
	    gc_mark_and_pin(objspace, values[i]);
4332
	}
4333
    }
4334
}
4335

  
4336
void
4337
rb_gc_mark_stack_values(long n, const VALUE *values)
4338
{
4339
    rb_objspace_t *objspace = &rb_objspace;
4340
    gc_mark_and_pin_stack_values(objspace, n, values);
4207 4341
}
4208 4342

  
4209 4343
static int
4210
mark_entry(st_data_t key, st_data_t value, st_data_t data)
4344
mark_entry_no_pin(st_data_t key, st_data_t value, st_data_t data)
4211 4345
{
4212 4346
    rb_objspace_t *objspace = (rb_objspace_t *)data;
4213 4347
    gc_mark(objspace, (VALUE)value);
4214 4348
    return ST_CONTINUE;
4215 4349
}
4216 4350

  
4351
static int
4352
mark_entry(st_data_t key, st_data_t value, st_data_t data)
4353
{
4354
    rb_objspace_t *objspace = (rb_objspace_t *)data;
4355
    gc_mark_and_pin(objspace, (VALUE)value);
4356
    return ST_CONTINUE;
4357
}
4358

  
4359
static void
4360
mark_tbl_no_pin(rb_objspace_t *objspace, st_table *tbl)
4361
{
4362
    if (!tbl || tbl->num_entries == 0) return;
4363
    st_foreach(tbl, mark_entry_no_pin, (st_data_t)objspace);
4364
}
4365

  
4217 4366
static void
4218 4367
mark_tbl(rb_objspace_t *objspace, st_table *tbl)
4219 4368
{
......
4247 4396
{
4248 4397
    rb_objspace_t *objspace = (rb_objspace_t *)data;
4249 4398

  
4250
    gc_mark(objspace, (VALUE)key);
4399
    if (SPECIAL_CONST_P((VALUE)key) || BUILTIN_TYPE((VALUE)key) == T_STRING) {
4400
	gc_mark(objspace, (VALUE)key);
4401
    } else {
4402
	gc_mark_and_pin(objspace, (VALUE)key);
4403
    }
4251 4404
    gc_mark(objspace, (VALUE)value);
4252 4405
    return ST_CONTINUE;
4253 4406
}
......
4427 4580
    mark_tbl(&rb_objspace, tbl);
4428 4581
}
4429 4582

  
4583
void
4584
rb_mark_tbl_no_pin(st_table *tbl)
4585
{
4586
    mark_tbl_no_pin(&rb_objspace, tbl);
4587
}
4588

  
4589
static void
4590
gc_mark_and_pin_maybe(rb_objspace_t *objspace, VALUE obj)
4591
{
4592
    (void)VALGRIND_MAKE_MEM_DEFINED(&obj, sizeof(obj));
4593
    if (is_pointer_to_heap(objspace, (void *)obj)) {
4594
	int type = BUILTIN_TYPE(obj);
4595
	if (type != T_MOVED && type != T_ZOMBIE && type != T_NONE) {
4596
	    gc_pin(objspace, obj);
4597
	    gc_mark_ptr(objspace, obj);
4598
	}
4599
    }
4600
}
4601

  
4430 4602
static void
4431 4603
gc_mark_maybe(rb_objspace_t *objspace, VALUE obj)
4432 4604
{
......
4449 4621
void
4450 4622
rb_gc_mark_maybe(VALUE obj)
4451 4623
{
4452
    gc_mark_maybe(&rb_objspace, obj);
4624
    gc_mark_and_pin_maybe(&rb_objspace, obj);
4453 4625
}
4454 4626

  
4455 4627
static inline int
......
4584 4756
    }
4585 4757
}
4586 4758

  
4759
static inline void
4760
gc_mark_and_pin(rb_objspace_t *objspace, VALUE obj)
4761
{
4762
    if (!is_markable_object(objspace, obj)) return;
4763
    MARK_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj);
4764
    gc_mark_ptr(objspace, obj);
4765
}
4766

  
4767
static inline void
4768
gc_pin(rb_objspace_t *objspace, VALUE obj)
4769
{
4770
    if (!is_markable_object(objspace, obj)) return;
4771
    MARK_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj);
4772
}
4773

  
4587 4774
static inline void
4588 4775
gc_mark(rb_objspace_t *objspace, VALUE obj)
4589 4776
{
......
4592 4779
}
4593 4780

  
4594 4781
void
4595
rb_gc_mark(VALUE ptr)
4782
rb_gc_mark_no_pin(VALUE ptr)
4596 4783
{
4597 4784
    gc_mark(&rb_objspace, ptr);
4598 4785
}
4599 4786

  
4787
void
4788
rb_gc_mark(VALUE ptr)
4789
{
4790
    gc_mark_and_pin(&rb_objspace, ptr);
4791
}
4792

  
4600 4793
/* CAUTION: THIS FUNCTION ENABLE *ONLY BEFORE* SWEEPING.
4601 4794
 * This function is only for GC_END_MARK timing.
4602 4795
 */
......
4607 4800
    return RVALUE_MARKED(obj) ? TRUE : FALSE;
4608 4801
}
4609 4802

  
4803
int
4804
rb_objspace_pinned_object_p(VALUE obj)
4805
{
4806
    return RVALUE_PINNED(obj) ? TRUE : FALSE;
4807
}
4808

  
4610 4809
static inline void
4611 4810
gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj)
4612 4811
{
......
4628 4827
	{
4629 4828
	    const rb_env_t *env = (const rb_env_t *)obj;
4630 4829
	    GC_ASSERT(VM_ENV_ESCAPED_P(env->ep));
4631
	    gc_mark_values(objspace, (long)env->env_size, env->env);
4830
	    gc_mark_and_pin_values(objspace, (long)env->env_size, env->env);
4632 4831
	    VM_ENV_FLAGS_SET(env->ep, VM_ENV_FLAG_WB_REQUIRED);
4633
	    gc_mark(objspace, (VALUE)rb_vm_env_prev_env(env));
4832
	    gc_mark_and_pin(objspace, (VALUE)rb_vm_env_prev_env(env));
4634 4833
	    gc_mark(objspace, (VALUE)env->iseq);
4635 4834
	}
4636 4835
	return;
......
4715 4914
      case T_MODULE:
4716 4915
	mark_m_tbl(objspace, RCLASS_M_TBL(obj));
4717 4916
	if (!RCLASS_EXT(obj)) break;
4718
	mark_tbl(objspace, RCLASS_IV_TBL(obj));
4917
	mark_tbl_no_pin(objspace, RCLASS_IV_TBL(obj));
4719 4918
	mark_const_tbl(objspace, RCLASS_CONST_TBL(obj));
4720 4919
	gc_mark(objspace, RCLASS_SUPER((VALUE)obj));
4721 4920
	break;
......
4848 5047
#if GC_DEBUG
4849 5048
	rb_gcdebug_print_obj_condition((VALUE)obj);
4850 5049
#endif
5050
	if (BUILTIN_TYPE(obj) == T_MOVED)   rb_bug("rb_gc_mark(): %p is T_MOVED", (void *)obj);
4851 5051
	if (BUILTIN_TYPE(obj) == T_NONE)   rb_bug("rb_gc_mark(): %p is T_NONE", (void *)obj);
4852 5052
	if (BUILTIN_TYPE(obj) == T_ZOMBIE) rb_bug("rb_gc_mark(): %p is T_ZOMBIE", (void *)obj);
4853 5053
	rb_bug("rb_gc_mark(): unknown data type 0x%x(%p) %s",
......
5324 5524
	    /* count objects */
5325 5525
	    data->live_object_count++;
5326 5526

  
5327
	    rb_objspace_reachable_objects_from(obj, check_children_i, (void *)data);
5527
	    if (!gc_object_moved_p(objspace, obj)) {
5528
		/* moved slots don't have children */
5529
		rb_objspace_reachable_objects_from(obj, check_children_i, (void *)data);
5530
	    }
5328 5531

  
5329 5532
#if USE_RGENGC
5330 5533
	    /* check health of children */
......
6049 6252

  
6050 6253
    list_for_each(&heap->pages, page, page_node) {
6051 6254
	memset(&page->mark_bits[0],       0, HEAP_PAGE_BITMAP_SIZE);
6255
	memset(&page->pinned_bits[0],     0, HEAP_PAGE_BITMAP_SIZE);
6052 6256
	memset(&page->marking_bits[0],    0, HEAP_PAGE_BITMAP_SIZE);
6053 6257
	memset(&page->uncollectible_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
6054 6258
	page->flags.has_uncollectible_shady_objects = FALSE;
......
6303 6507
    size_t n = 0;
6304 6508
    static ID ID_marked;
6305 6509
#if USE_RGENGC
6306
    static ID ID_wb_protected, ID_old, ID_marking, ID_uncollectible;
6510
    static ID ID_wb_protected, ID_old, ID_marking, ID_uncollectible, ID_pinned;
6307 6511
#endif
6308 6512

  
6309 6513
    if (!ID_marked) {
......
6314 6518
	I(old);
6315 6519
	I(marking);
6316 6520
	I(uncollectible);
6521
	I(pinned);
6317 6522
#endif
6318 6523
#undef I
6319 6524
    }
......
6325 6530
    if (MARKED_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj) && n<max) flags[n++] = ID_marking;
6326 6531
#endif
6327 6532
    if (MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj) && n<max)    flags[n++] = ID_marked;
6533
    if (MARKED_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj) && n<max)  flags[n++] = ID_pinned;
6328 6534
    return n;
6329 6535
}
6330 6536

  
......
6898 7104
    return Qnil;
6899 7105
}
6900 7106

  
7107
static int
7108
gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
7109
{
7110
    if (SPECIAL_CONST_P(obj) || BUILTIN_TYPE(obj) == T_NONE || BUILTIN_TYPE(obj) == T_ZOMBIE || rb_objspace_pinned_object_p(obj)) {
7111
	return FALSE;
7112
    }
7113

  
7114
    if (FL_TEST(obj, FL_FINALIZE)) {
7115
	return FALSE;
7116
    }
7117

  
7118
    switch(BUILTIN_TYPE(obj)) {
7119
	case T_NONE:
7120
	case T_NIL:
7121
	    return FALSE;
7122
	    break;
7123
	case T_STRING:
7124
	case T_OBJECT:
7125
	case T_FLOAT:
7126
	case T_IMEMO:
7127
	case T_ARRAY:
7128
	case T_BIGNUM:
7129
	case T_ICLASS:
7130
	case T_MODULE:
7131
	case T_REGEXP:
7132
	case T_DATA:
7133
	case T_SYMBOL:
7134
	case T_MATCH:
7135
	case T_STRUCT:
7136
	case T_HASH:
7137
	case T_FILE:
7138
	case T_COMPLEX:
7139
	case T_RATIONAL:
7140
	case T_NODE:
7141
	case T_CLASS:
7142
	    break;
7143
	default:
7144
	    rb_bug("gc_is_moveable_obj: unreachable (%d)", (int)BUILTIN_TYPE(obj));
7145
	    break;
7146
    }
7147

  
7148
    return TRUE;
7149
}
7150

  
7151
static int
7152
update_id_to_obj(st_data_t *key, st_data_t *value, st_data_t arg, int exists)
7153
{
7154
    if (exists) {
7155
	*value = arg;
7156
	return ST_CONTINUE;
7157
    } else {
7158
	return ST_STOP;
7159
    }
7160
}
7161

  
7162
static void
7163
gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free)
7164
{
7165
    int marked;
7166
    int wb_unprotected;
7167
    int uncollectible;
7168
    int marking;
7169
    RVALUE *dest = (RVALUE *)free;
7170
    RVALUE *src = (RVALUE *)scan;
7171

  
7172
#if RGENGC_CHECK_MODE >= 5
7173
    fprintf(stderr, "moving: %s -> ", obj_info(src));
7174
#endif
7175

  
7176
    /* Save off bits for current object. */
7177
    marked = rb_objspace_marked_object_p((VALUE)src);
7178
    wb_unprotected = RVALUE_WB_UNPROTECTED((VALUE)src);
7179
    uncollectible = RVALUE_UNCOLLECTIBLE((VALUE)src);
7180
    marking = RVALUE_MARKING((VALUE)src);
7181

  
7182
    objspace->total_allocated_objects++;
7183

  
7184
    /* Clear bits for eventual T_MOVED */
7185
    CLEAR_IN_BITMAP(GET_HEAP_MARK_BITS((VALUE)src), (VALUE)src);
7186
    CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS((VALUE)src), (VALUE)src);
7187
    CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS((VALUE)src), (VALUE)src);
7188
    CLEAR_IN_BITMAP(GET_HEAP_MARKING_BITS((VALUE)src), (VALUE)src);
7189

  
7190
    if (FL_TEST(src, FL_EXIVAR)) {
7191
	rb_mv_generic_ivar((VALUE)src, (VALUE)dest);
7192
    }
7193

  
7194
    VALUE id;
7195

  
7196
    /* If the source object's object_id has been seen, we need to update
7197
     * the object to object id mapping. */
7198
    if(st_lookup(obj_to_id_tbl, (VALUE)src, &id)) {
7199
#ifdef GC_COMPACT_DEBUG
7200
	fprintf(stderr, "Moving insert: %p -> %p\n", src, dest);
7201
#endif
7202
	st_delete(obj_to_id_tbl, (st_data_t *)&src, 0);
7203
	st_insert(obj_to_id_tbl, (VALUE)dest, id);
7204
	st_update(id_to_obj_tbl, (st_data_t)id, update_id_to_obj, (st_data_t)dest);
7205
    }
7206

  
7207
    /* Move the object */
7208
    memcpy(dest, src, sizeof(RVALUE));
7209
    memset(src, 0, sizeof(RVALUE));
7210

  
7211
    /* Set bits for object in new location */
7212
    if (marking) {
7213
	MARK_IN_BITMAP(GET_HEAP_MARKING_BITS((VALUE)dest), (VALUE)dest);
7214
    } else {
7215
	CLEAR_IN_BITMAP(GET_HEAP_MARKING_BITS((VALUE)dest), (VALUE)dest);
7216
    }
7217

  
7218
    if (marked) {
7219
	MARK_IN_BITMAP(GET_HEAP_MARK_BITS((VALUE)dest), (VALUE)dest);
7220
    } else {
7221
	CLEAR_IN_BITMAP(GET_HEAP_MARK_BITS((VALUE)dest), (VALUE)dest);
7222
    }
7223

  
7224
    if (wb_unprotected) {
7225
	MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS((VALUE)dest), (VALUE)dest);
7226
    } else {
7227
	CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS((VALUE)dest), (VALUE)dest);
7228
    }
7229

  
7230
    if (uncollectible) {
7231
	MARK_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS((VALUE)dest), (VALUE)dest);
7232
    } else {
7233
	CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS((VALUE)dest), (VALUE)dest);
7234
    }
7235

  
7236
    /* Assign forwarding address */
7237
    src->as.moved.flags = T_MOVED;
7238
    src->as.moved.destination = (VALUE)dest;
7239

  
7240
#if RGENGC_CHECK_MODE >= 5
7241
    fprintf(stderr, "%s\n", obj_info(dest));
7242
#endif
7243
}
7244

  
7245
struct heap_cursor {
7246
    RVALUE *slot;
7247
    size_t index;
7248
    struct heap_page *page;
7249
    rb_objspace_t * objspace;
7250
};
7251

  
7252
static void
7253
advance_cursor(struct heap_cursor *free, struct heap_page **page_list)
7254
{
7255
    rb_objspace_t *objspace = free->objspace;
7256

  
7257
    if (free->slot == free->page->start + free->page->total_slots - 1) {
7258
	free->index++;
7259
	free->page = page_list[free->index];
7260
	free->slot = free->page->start;
7261
    } else {
7262
	free->slot++;
7263
    }
7264
}
7265

  
7266
static void
7267
retreat_cursor(struct heap_cursor *scan, struct heap_page **page_list)
7268
{
7269
    rb_objspace_t *objspace = scan->objspace;
7270

  
7271
    if (scan->slot == scan->page->start) {
7272
	scan->index--;
7273
	scan->page = page_list[scan->index];
7274
	scan->slot = scan->page->start + scan->page->total_slots - 1;
7275
    } else {
7276
	scan->slot--;
7277
    }
7278
}
7279

  
7280
static int
7281
not_met(struct heap_cursor *free, struct heap_cursor *scan)
7282
{
7283
    if (free->index < scan->index)
7284
	return 1;
7285

  
7286
    if (free->index > scan->index)
7287
	return 0;
7288

  
7289
    return free->slot < scan->slot;
7290
}
7291

  
7292
static void
7293
init_cursors(rb_objspace_t *objspace, struct heap_cursor *free, struct heap_cursor *scan, struct heap_page **page_list)
7294
{
7295
    struct heap_page *page;
7296
    page = page_list[0];
7297

  
7298
    free->index = 0;
7299
    free->page = page;
7300
    free->slot = page->start;
7301
    free->objspace = objspace;
7302

  
7303
    page = page_list[heap_allocated_pages - 1];
7304
    scan->index = heap_allocated_pages - 1;
7305
    scan->page = page;
7306
    scan->slot = page->start + page->total_slots - 1;
7307
    scan->objspace = objspace;
7308
}
7309

  
7310
int count_pinned(struct heap_page *page)
7311
{
7312
    RVALUE *pstart = page->start;
7313
    RVALUE *pend = pstart + page->total_slots;
7314
    int pinned = 0;
7315

  
7316
    VALUE v = (VALUE)pstart;
7317
    for(; v != (VALUE)pend; v += sizeof(RVALUE)) {
7318
	if (RBASIC(v)->flags && RVALUE_PINNED(v)) {
7319
	    pinned++;
7320
	}
7321
    }
7322

  
7323
    return pinned;
7324
}
7325

  
7326
int compare_pinned(const void *left, const void *right)
7327
{
7328
    int left_count = count_pinned(*(struct heap_page * const *)left);
7329
    int right_count = count_pinned(*(struct heap_page * const *)right);
7330
    return right_count - left_count;
7331
}
7332

  
7333
static void
7334
gc_compact_heap(rb_objspace_t *objspace)
7335
{
7336
    struct heap_cursor free_cursor;
7337
    struct heap_cursor scan_cursor;
7338
    int number_considered;
7339
    struct heap_page **page_list;
7340

  
7341
    memset(objspace->rcompactor.considered_count_table, 0, T_MASK * sizeof(size_t));
7342
    memset(objspace->rcompactor.moved_count_table, 0, T_MASK * sizeof(size_t));
7343

  
7344
    page_list = calloc(heap_allocated_pages, sizeof(struct heap_page *));
7345
    memcpy(page_list, heap_pages_sorted, heap_allocated_pages * sizeof(struct heap_page *));
7346
    qsort(page_list, heap_allocated_pages, sizeof(struct heap_page *), compare_pinned);
7347

  
7348
    init_cursors(objspace, &free_cursor, &scan_cursor, page_list);
7349

  
7350
    /* Two finger algorithm */
7351
    while (not_met(&free_cursor, &scan_cursor)) {
7352
	while(BUILTIN_TYPE(free_cursor.slot) != T_NONE && not_met(&free_cursor, &scan_cursor)) {
7353
	    advance_cursor(&free_cursor, page_list);
7354
	}
7355

  
7356
	objspace->rcompactor.considered_count_table[BUILTIN_TYPE((VALUE)scan_cursor.slot)]++;
7357

  
7358
	while(!gc_is_moveable_obj(objspace, (VALUE)scan_cursor.slot) && not_met(&free_cursor, &scan_cursor)) {
7359
	    retreat_cursor(&scan_cursor, page_list);
7360
	    objspace->rcompactor.considered_count_table[BUILTIN_TYPE((VALUE)scan_cursor.slot)]++;
7361
	}
7362

  
7363
	if (not_met(&free_cursor, &scan_cursor)) {
7364
	    objspace->rcompactor.moved_count_table[BUILTIN_TYPE((VALUE)scan_cursor.slot)]++;
7365
	    gc_move(objspace, (VALUE)scan_cursor.slot, (VALUE)free_cursor.slot);
7366
	    advance_cursor(&free_cursor, page_list);
7367
	    retreat_cursor(&scan_cursor, page_list);
7368
	}
7369
    }
7370
    free(page_list);
7371
}
7372

  
7373
static void
7374
gc_ref_update_array(rb_objspace_t * objspace, VALUE v)
7375
{
7376
    long i, len;
7377

  
7378
    if (FL_TEST(v, ELTS_SHARED))
7379
	return;
7380

  
7381
    len = RARRAY_LEN(v);
7382
    if (len > 0) {
7383
	VALUE *ptr = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(v);
7384
	for(i = 0; i < len; i++) {
7385
	    UPDATE_IF_MOVED(objspace, ptr[i]);
7386
	}
7387
    }
7388
}
7389

  
7390
static void
7391
gc_ref_update_object(rb_objspace_t * objspace, VALUE v)
7392
{
7393
    uint32_t i, len = ROBJECT_NUMIV(v);
7394
    VALUE *ptr = ROBJECT_IVPTR(v);
7395
    for (i = 0; i < len; i++) {
7396
	UPDATE_IF_MOVED(objspace, ptr[i]);
7397
    }
7398
}
7399

  
7400
static int
7401
hash_replace_ref(st_data_t *key, st_data_t *value, st_data_t argp, int existing)
7402
{
7403
    rb_objspace_t *objspace;
7404

  
7405
    if(!SPECIAL_CONST_P((void *)*key) && BUILTIN_TYPE(*key) == T_MOVED) {
7406
	*key = (VALUE)RMOVED(*key)->destination;
7407
    }
7408

  
7409
    if(!SPECIAL_CONST_P((void *)*value) && BUILTIN_TYPE(*value) == T_MOVED) {
7410
	*value = (VALUE)RMOVED(*value)->destination;
7411
    }
7412

  
7413
    return ST_CONTINUE;
7414
}
7415

  
7416
static int
7417
hash_foreach_replace(st_data_t key, st_data_t value, st_data_t argp, int error)
7418
{
7419
    rb_objspace_t *objspace;
7420

  
7421
    objspace = (rb_objspace_t *)argp;
7422

  
7423
    if(!SPECIAL_CONST_P((void *)key) && BUILTIN_TYPE(key) == T_MOVED) {
7424
	return ST_REPLACE;
7425
    }
7426

  
7427
    if(!SPECIAL_CONST_P((void *)value) && BUILTIN_TYPE(value) == T_MOVED) {
7428
	return ST_REPLACE;
7429
    }
7430
    return ST_CHECK;
7431
}
7432

  
7433
static void
7434
gc_update_table_refs(rb_objspace_t * objspace, st_table *ht)
7435
{
7436
    if (st_foreach_with_replace(ht, hash_foreach_replace, hash_replace_ref, (st_data_t)objspace)) {
7437
	rb_raise(rb_eRuntimeError, "hash modified during iteration");
7438
    }
7439
}
7440

  
7441
void
7442
rb_gc_update_tbl_refs(st_table *ptr)
7443
{
7444
    rb_objspace_t *objspace = &rb_objspace;
7445
    gc_update_table_refs(objspace, ptr);
7446
}
7447

  
7448
static void
7449
gc_ref_update_hash(rb_objspace_t * objspace, VALUE v)
7450
{
7451
    gc_update_table_refs(objspace, rb_hash_tbl_raw(v));
7452
}
7453

  
7454
void rb_update_st_references(struct st_table *ht)
7455
{
7456
    rb_objspace_t *objspace = &rb_objspace;
7457
    gc_update_table_refs(objspace, ht);
7458
}
7459

  
7460
static void
7461
gc_ref_update_method_entry(rb_objspace_t *objspace, rb_method_entry_t *me)
7462
{
7463
    rb_method_definition_t *def = me->def;
7464

  
7465
    UPDATE_IF_MOVED(objspace, me->owner);
7466
    UPDATE_IF_MOVED(objspace, me->defined_class);
7467

  
7468
    if (def) {
7469
	switch (def->type) {
7470
	  case VM_METHOD_TYPE_ISEQ:
7471
	    if (def->body.iseq.iseqptr) {
7472
		TYPED_UPDATE_IF_MOVED(objspace, rb_iseq_t *, def->body.iseq.iseqptr);
7473
	    }
7474
	    TYPED_UPDATE_IF_MOVED(objspace, rb_cref_t *, def->body.iseq.cref);
7475
	    break;
7476
	  case VM_METHOD_TYPE_ATTRSET:
7477
	  case VM_METHOD_TYPE_IVAR:
7478
	    UPDATE_IF_MOVED(objspace, def->body.attr.location);
7479
	    break;
7480
	  case VM_METHOD_TYPE_BMETHOD:
7481
            UPDATE_IF_MOVED(objspace, def->body.bmethod.proc);
7482
	    break;
7483
	  case VM_METHOD_TYPE_ALIAS:
7484
	    TYPED_UPDATE_IF_MOVED(objspace, struct rb_method_entry_struct *, def->body.alias.original_me);
7485
	    return;
7486
	  case VM_METHOD_TYPE_REFINED:
7487
	    TYPED_UPDATE_IF_MOVED(objspace, struct rb_method_entry_struct *, def->body.refined.orig_me);
7488
	    UPDATE_IF_MOVED(objspace, def->body.refined.owner);
7489
	    break;
7490
	  case VM_METHOD_TYPE_CFUNC:
7491
	  case VM_METHOD_TYPE_ZSUPER:
7492
	  case VM_METHOD_TYPE_MISSING:
7493
	  case VM_METHOD_TYPE_OPTIMIZED:
7494
	  case VM_METHOD_TYPE_UNDEF:
7495
	  case VM_METHOD_TYPE_NOTIMPLEMENTED:
7496
	    break;
7497
	}
7498
    }
7499
}
7500

  
7501
static void
7502
gc_ref_update_imemo(rb_objspace_t *objspace, VALUE obj)
7503
{
7504
    switch(imemo_type(obj)) {
7505
	case imemo_env:
7506
	    {
7507
		rb_env_t *env = (rb_env_t *)obj;
7508
		TYPED_UPDATE_IF_MOVED(objspace, rb_iseq_t *, env->iseq);
7509
	    }
7510
	    break;
7511
	    break;
7512
	case imemo_cref:
7513
	    UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.cref.klass);
7514
	    TYPED_UPDATE_IF_MOVED(objspace, struct rb_cref_struct *, RANY(obj)->as.imemo.cref.next);
7515
	    UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.cref.refinements);
7516
	    break;
7517
	case imemo_svar:
7518
	    UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.cref_or_me);
7519
	    UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.lastline);
7520
	    UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.backref);
7521
	    UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.others);
7522
	    break;
7523
	case imemo_throw_data:
7524
	    UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.throw_data.throw_obj);
7525
	    break;
7526
	case imemo_ifunc:
7527
	    if (is_pointer_to_heap(objspace, RANY(obj)->as.imemo.ifunc.data)) {
7528
		TYPED_UPDATE_IF_MOVED(objspace, void *, RANY(obj)->as.imemo.ifunc.data);
7529
	    }
7530
	    break;
7531
	case imemo_memo:
7532
	    UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.memo.v1);
7533
	    UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.memo.v2);
7534
	    if (is_pointer_to_heap(objspace, (void *)RANY(obj)->as.imemo.memo.u3.value)) {
7535
		UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.memo.u3.value);
7536
	    }
7537
	    break;
7538
	case imemo_ment:
7539
	    gc_ref_update_method_entry(objspace, &RANY(obj)->as.imemo.ment);
7540
	    break;
7541
	case imemo_iseq:
7542
	    rb_iseq_update_references((rb_iseq_t *)obj);
7543
	    break;
7544
	case imemo_ast:
7545
	case imemo_parser_strterm:
7546
	case imemo_tmpbuf:
7547
	    break;
7548
	default:
7549
	    rb_bug("not reachable %d", imemo_type(obj));
7550
	    break;
7551
    }
7552
}
7553

  
7554
static enum rb_id_table_iterator_result
7555
check_id_table_move(ID id, VALUE value, void *data)
7556
{
7557
    if(!SPECIAL_CONST_P((void *)value) && BUILTIN_TYPE(value) == T_MOVED) {
7558
	return ID_TABLE_REPLACE;
7559
    }
7560

  
7561
    return ID_TABLE_CONTINUE;
7562
}
7563

  
7564
/* Returns the new location of an object, if it moved.  Otherwise returns
7565
 * the existing location. */
7566
VALUE
7567
rb_gc_new_location(VALUE value)
7568
{
7569
    if(!SPECIAL_CONST_P((void *)value) && BUILTIN_TYPE(value) == T_MOVED) {
7570
	return (VALUE)RMOVED(value)->destination;
7571
    } else {
7572
	return value;
7573
    }
7574
}
7575

  
7576
static enum rb_id_table_iterator_result
7577
update_id_table(ID *key, VALUE * value, void *data, int existing)
7578
{
7579
    if(!SPECIAL_CONST_P((void *)*value) && BUILTIN_TYPE(*value) == T_MOVED) {
7580
	*value = (VALUE)RMOVED(*value)->destination;
7581
    }
7582

  
7583
    return ID_TABLE_CONTINUE;
7584
}
7585

  
7586
static void
7587
update_m_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
7588
{
7589
    if (tbl) {
7590
	rb_id_table_foreach_with_replace(tbl, check_id_table_move, update_id_table, objspace);
7591
    }
7592
}
7593

  
7594
static enum rb_id_table_iterator_result
7595
update_const_table(VALUE value, void *data)
7596
{
7597
    rb_const_entry_t *ce = (rb_const_entry_t *)value;
7598

  
7599
    if(!SPECIAL_CONST_P((void *)ce->value) && BUILTIN_TYPE(ce->value) == T_MOVED) {
7600
	ce->value = (VALUE)RMOVED(ce->value)->destination;
7601
    }
7602

  
7603
    if(!SPECIAL_CONST_P((void *)ce->file) && BUILTIN_TYPE(ce->file) == T_MOVED) {
7604
	ce->file = (VALUE)RMOVED(ce->file)->destination;
7605
    }
7606

  
7607
    return ID_TABLE_CONTINUE;
7608
}
7609

  
7610
static void
7611
update_const_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
7612
{
7613
    if (!tbl) return;
7614
    rb_id_table_foreach_values(tbl, update_const_table, objspace);
7615
}
7616

  
7617
static void
7618
update_subclass_entries(rb_objspace_t *objspace, rb_subclass_entry_t *entry)
7619
{
7620
    while (entry) {
7621
	UPDATE_IF_MOVED(objspace, entry->klass);
7622
	entry = entry->next;
7623
    }
7624
}
7625

  
7626
static void
7627
update_class_ext(rb_objspace_t *objspace, rb_classext_t *ext)
7628
{
7629
    UPDATE_IF_MOVED(objspace, ext->origin_);
7630
    UPDATE_IF_MOVED(objspace, ext->refined_class);
7631
    update_subclass_entries(objspace, ext->subclasses);
7632
}
7633

  
7634
static void
7635
gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
7636
{
7637
    RVALUE *any = RANY(obj);
7638

  
7639
#if RGENGC_CHECK_MODE >= 5
7640
    fprintf(stderr, "update-refs: %s -> ", obj_info(obj));
7641
#endif
7642

  
7643
    switch(BUILTIN_TYPE(obj)) {
7644
	case T_CLASS:
7645
	case T_MODULE:
7646
	    update_m_tbl(objspace, RCLASS_M_TBL(obj));
7647
	    if (!RCLASS_EXT(obj)) break;
7648
	    if (RCLASS_IV_TBL(obj)) {
7649
		gc_update_table_refs(objspace, RCLASS_IV_TBL(obj));
7650
	    }
7651
	    update_class_ext(objspace, RCLASS_EXT(obj));
7652
	    update_const_tbl(objspace, RCLASS_CONST_TBL(obj));
7653
	    UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);
7654
	    break;
7655

  
7656
	case T_ICLASS:
7657
	    if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
7658
		update_m_tbl(objspace, RCLASS_M_TBL(obj));
7659
	    }
7660
	    if (!RCLASS_EXT(obj)) break;
7661
	    if (RCLASS_IV_TBL(obj)) {
7662
		gc_update_table_refs(objspace, RCLASS_IV_TBL(obj));
7663
	    }
7664
	    update_class_ext(objspace, RCLASS_EXT(obj));
7665
	    update_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
7666
	    UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);
7667
	    break;
7668

  
7669
	case T_IMEMO:
7670
	    gc_ref_update_imemo(objspace, obj);
7671
	    break;
7672

  
7673
	case T_NIL:
7674
	case T_FIXNUM:
7675
	case T_NODE:
7676
	case T_MOVED:
7677
	case T_NONE:
7678
	    /* These can't move */
7679
	    return;
7680

  
7681
	case T_ARRAY:
7682
	    if (FL_TEST(obj, ELTS_SHARED)) {
7683
		UPDATE_IF_MOVED(objspace, any->as.array.as.heap.aux.shared);
7684
	    } else {
7685
		gc_ref_update_array(objspace, obj);
7686
	    }
7687
	    break;
7688

  
7689
	case T_HASH:
7690
	    gc_ref_update_hash(objspace, obj);
7691
	    UPDATE_IF_MOVED(objspace, any->as.hash.ifnone);
7692
	    break;
7693

  
7694
	case T_STRING:
7695
	    if (STR_SHARED_P(obj)) {
7696
		UPDATE_IF_MOVED(objspace, any->as.string.as.heap.aux.shared);
7697
	    }
7698
	case T_DATA:
7699
	    /* Call the compaction callback, if it exists */
7700
	    {
7701
		void *const ptr = DATA_PTR(obj);
7702
		if (ptr) {
7703
		    if (RTYPEDDATA_P(obj)) {
7704
			RUBY_DATA_FUNC compact_func = any->as.typeddata.type->function.dcompact;
7705
			if (compact_func) (*compact_func)(ptr);
7706
		    }
7707
		}
7708
	    }
7709
	    break;
7710

  
7711
	case T_OBJECT:
7712
	    gc_ref_update_object(objspace, obj);
7713
	    break;
7714

  
7715
	case T_FILE:
7716
	    if (any->as.file.fptr) {
7717
		UPDATE_IF_MOVED(objspace, any->as.file.fptr->pathv);
7718
		UPDATE_IF_MOVED(objspace, any->as.file.fptr->tied_io_for_writing);
7719
		UPDATE_IF_MOVED(objspace, any->as.file.fptr->writeconv_asciicompat);
7720
		UPDATE_IF_MOVED(objspace, any->as.file.fptr->writeconv_pre_ecopts);
7721
		UPDATE_IF_MOVED(objspace, any->as.file.fptr->encs.ecopts);
7722
		UPDATE_IF_MOVED(objspace, any->as.file.fptr->write_lock);
7723
	    }
7724
	    break;
7725
	case T_REGEXP:
7726
	    UPDATE_IF_MOVED(objspace, any->as.regexp.src);
7727
	    break;
7728

  
7729
	case T_SYMBOL:
7730
	    if (DYNAMIC_SYM_P((VALUE)any)) {
7731
		UPDATE_IF_MOVED(objspace, RSYMBOL(any)->fstr);
7732
	    }
7733
	    break;
7734

  
7735
	case T_FLOAT:
7736
	case T_BIGNUM:
7737
	    break;
7738

  
7739
	case T_MATCH:
7740
	    UPDATE_IF_MOVED(objspace, any->as.match.regexp);
7741

  
7742
	    if (any->as.match.str) {
7743
		UPDATE_IF_MOVED(objspace, any->as.match.str);
7744
	    }
7745
	    break;
7746

  
7747
	case T_RATIONAL:
7748
	    UPDATE_IF_MOVED(objspace, any->as.rational.num);
7749
	    UPDATE_IF_MOVED(objspace, any->as.rational.den);
7750
	    break;
7751

  
7752
	case T_COMPLEX:
7753
	    UPDATE_IF_MOVED(objspace, any->as.complex.real);
7754
	    UPDATE_IF_MOVED(objspace, any->as.complex.imag);
7755

  
7756
	    break;
7757

  
7758
	case T_STRUCT:
7759
	    {
7760
		long i, len = RSTRUCT_LEN(obj);
7761
		VALUE *ptr = (VALUE *)RSTRUCT_CONST_PTR(obj);
7762

  
7763
		for(i = 0; i < len; i++) {
7764
		    UPDATE_IF_MOVED(objspace, ptr[i]);
7765
		}
7766
	    }
7767
	    break;
7768
	default:
7769
#if GC_DEBUG
7770
	    rb_gcdebug_print_obj_condition((VALUE)obj);
7771
	    rb_obj_info_dump(obj);
7772
	    rb_bug("unreachable");
7773
#endif
7774
	    break;
7775

  
7776
    }
7777

  
7778
    UPDATE_IF_MOVED(objspace, RBASIC(obj)->klass);
7779

  
7780
#if RGENGC_CHECK_MODE >= 5
7781
    fprintf(stderr, "%s\n", obj_info(obj));
7782
#endif
7783
}
7784
static int
7785
gc_ref_update(void *vstart, void *vend, size_t stride, void * data)
7786
{
7787
    rb_objspace_t * objspace;
7788
    struct heap_page *page;
7789
    short free_slots = 0;
7790

  
7791
    VALUE v = (VALUE)vstart;
7792
    objspace = (rb_objspace_t *)data;
7793
    page = GET_HEAP_PAGE(v);
7794
    page->freelist = NULL;
7795
    page->flags.has_uncollectible_shady_objects = FALSE;
7796

  
7797
    /* For each object on the page */
7798
    for(; v != (VALUE)vend; v += stride) {
7799
	if (SPECIAL_CONST_P(v)) {
7800
	} else if (BUILTIN_TYPE(v) == T_NONE) {
7801
	    heap_page_add_freeobj(objspace, page, v);
7802
	    free_slots++;
7803
	} else {
7804
	    if (RVALUE_WB_UNPROTECTED(v)) {
7805
		page->flags.has_uncollectible_shady_objects = TRUE;
7806
	    }
7807
	    gc_update_object_references(objspace, v);
7808
	}
7809
    }
7810

  
7811
    page->free_slots = free_slots;
7812
    return 0;
7813
}
7814

  
7815
extern rb_symbols_t global_symbols;
7816

  
7817
static void
7818
gc_update_references(rb_objspace_t * objspace)
7819
{
7820
    rb_execution_context_t *ec = GET_EC();
7821
    rb_vm_t *vm = rb_ec_vm_ptr(ec);
7822

  
7823
    rb_objspace_each_objects_without_setup(gc_ref_update, objspace);
7824
    rb_vm_update_references(vm);
7825
    gc_update_table_refs(objspace, global_symbols.str_sym);
7826
}
7827

  
7828
static VALUE type_sym(int type);
7829

  
7830
static VALUE
7831
rb_gc_compact_stats(VALUE mod)
7832
{
7833
    int i;
7834

  
7835
    rb_objspace_t *objspace = &rb_objspace;
7836
    VALUE h = rb_hash_new();
7837
    VALUE considered = rb_hash_new();
7838
    VALUE moved = rb_hash_new();
7839

  
7840
    for (i=0; i<T_MASK; i++) {
7841
	rb_hash_aset(considered, type_sym(i), SIZET2NUM(objspace->rcompactor.considered_count_table[i]));
7842
    }
7843

  
7844
    for (i=0; i<T_MASK; i++) {
7845
	rb_hash_aset(moved, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_count_table[i]));
7846
    }
7847

  
7848
    rb_hash_aset(h, ID2SYM(rb_intern("considered")), considered);
7849
    rb_hash_aset(h, ID2SYM(rb_intern("moved")), moved);
7850

  
7851
    return h;
7852
}
7853

  
7854
static VALUE
7855
rb_gc_compact(VALUE mod)
7856
{
7857
    rb_objspace_t *objspace = &rb_objspace;
7858

  
7859
    /* Ensure objects are pinned */
7860
    rb_gc();
7861

  
7862
    /* Drain interrupts so that THEAP has a chance to evacuate before
7863
     * any possible compaction. */
7864
    rb_thread_execute_interrupts(rb_thread_current());
7865

  
7866
    gc_compact_heap(objspace);
7867

  
7868
    gc_update_references(objspace);
7869

  
7870
    rb_clear_method_cache_by_class(rb_cObject);
7871
    rb_clear_constant_cache();
7872

  
7873
    /* GC after compaction to eliminate T_MOVED */
7874
    rb_gc();
7875

  
7876
    return rb_gc_compact_stats(mod);
7877
}
7878

  
7879
/*
7880
 *  call-seq:
7881
 *     GC.verify_compaction_references                  -> nil
7882
 *
7883
 *  Verify compaction reference consistency.
7884
 *
7885
 *  This method is implementation specific.  During compaction, objects that
7886
 *  were moved are replaced with T_MOVED objects.  No object should have a
7887
 *  reference to a T_MOVED object after compaction.
7888
 *
7889
 *  This function doubles the heap to ensure room to move all objects,
7890
 *  compacts the heap to make sure everything moves, updates all references,
7891
 *  then performs a full GC.  If any object contains a reference to a T_MOVED
7892
 *  object, that object should be pushed on the mark stack, and will
7893
 *  make a SEGV.
7894
 */
7895
static VALUE
7896
gc_verify_compaction_references(VALUE dummy)
7897
{
7898
    rb_objspace_t *objspace = &rb_objspace;
7899

  
7900
    /* Double heap size */
... This diff was truncated because it exceeds the maximum size that can be displayed.