~ubuntu-branches/ubuntu/quantal/ruby1.9.1/quantal

« back to all changes in this revision

Viewing changes to gc.c

  • Committer: Bazaar Package Importer
  • Author(s): Lucas Nussbaum
  • Date: 2011-09-24 19:16:17 UTC
  • mfrom: (1.1.8 upstream) (13.1.7 experimental)
  • Revision ID: james.westby@ubuntu.com-20110924191617-o1qz4rcmqjot8zuy
Tags: 1.9.3~rc1-1
* New upstream release: 1.9.3 RC1.
  + Includes load.c fixes. Closes: #639959.
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 
3
3
  gc.c -
4
4
 
5
 
  $Author: yugui $
 
5
  $Author: nari $
6
6
  created at: Tue Oct  5 09:44:46 JST 1993
7
7
 
8
8
  Copyright (C) 1993-2007 Yukihiro Matsumoto
18
18
#include "ruby/util.h"
19
19
#include "eval_intern.h"
20
20
#include "vm_core.h"
 
21
#include "internal.h"
21
22
#include "gc.h"
 
23
#include "constant.h"
22
24
#include <stdio.h>
23
25
#include <setjmp.h>
24
26
#include <sys/types.h>
38
40
#ifdef HAVE_VALGRIND_MEMCHECK_H
39
41
# include <valgrind/memcheck.h>
40
42
# ifndef VALGRIND_MAKE_MEM_DEFINED
41
 
#  define VALGRIND_MAKE_MEM_DEFINED(p, n) VALGRIND_MAKE_READABLE(p, n)
 
43
#  define VALGRIND_MAKE_MEM_DEFINED(p, n) VALGRIND_MAKE_READABLE((p), (n))
42
44
# endif
43
45
# ifndef VALGRIND_MAKE_MEM_UNDEFINED
44
 
#  define VALGRIND_MAKE_MEM_UNDEFINED(p, n) VALGRIND_MAKE_WRITABLE(p, n)
 
46
#  define VALGRIND_MAKE_MEM_UNDEFINED(p, n) VALGRIND_MAKE_WRITABLE((p), (n))
45
47
# endif
46
48
#else
47
49
# define VALGRIND_MAKE_MEM_DEFINED(p, n) /* empty */
48
50
# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) /* empty */
49
51
#endif
50
52
 
51
 
int rb_io_fptr_finalize(struct rb_io_t*);
52
 
 
53
53
#define rb_setjmp(env) RUBY_SETJMP(env)
54
54
#define rb_jmp_buf rb_jmpbuf_t
55
55
 
77
77
#ifndef GC_MALLOC_LIMIT
78
78
#define GC_MALLOC_LIMIT 8000000
79
79
#endif
 
80
#define HEAP_MIN_SLOTS 10000
 
81
#define FREE_MIN  4096
 
82
 
 
83
static unsigned int initial_malloc_limit   = GC_MALLOC_LIMIT;
 
84
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
 
85
static unsigned int initial_heap_min_slots = HEAP_MIN_SLOTS;
 
86
#endif
 
87
static unsigned int initial_free_min       = FREE_MIN;
80
88
 
81
89
#define nomem_error GET_VM()->special_exceptions[ruby_error_nomemory]
82
90
 
100
108
    size_t heap_total_size;
101
109
 
102
110
    int have_finalize;
 
111
    int is_marked;
103
112
 
104
113
    size_t allocate_increase;
105
114
    size_t allocate_limit;
160
169
        }\
161
170
    } while(0)
162
171
 
163
 
#define GC_PROF_TIMER_STOP do {\
 
172
#define GC_PROF_TIMER_STOP(marked) do {\
164
173
        if (objspace->profile.run) {\
165
174
            gc_time = getrusage_time() - gc_time;\
166
175
            if (gc_time < 0) gc_time = 0;\
167
176
            objspace->profile.record[count].gc_time = gc_time;\
 
177
            objspace->profile.record[count].is_marked = !!(marked);\
 
178
            GC_PROF_SET_HEAP_INFO(objspace->profile.record[count]);\
168
179
            objspace->profile.count++;\
169
180
        }\
170
181
    } while(0)
171
182
 
172
183
#if GC_PROFILE_MORE_DETAIL
173
 
#define INIT_GC_PROF_PARAMS double gc_time = 0, mark_time = 0, sweep_time = 0;\
174
 
    size_t count = objspace->profile.count
 
184
#define INIT_GC_PROF_PARAMS double gc_time = 0, sweep_time = 0;\
 
185
    size_t count = objspace->profile.count, total = 0, live = 0
175
186
 
176
 
#define GC_PROF_MARK_TIMER_START do {\
 
187
#define GC_PROF_MARK_TIMER_START double mark_time = 0;\
 
188
    do {\
177
189
        if (objspace->profile.run) {\
178
190
            mark_time = getrusage_time();\
179
191
        }\
183
195
        if (objspace->profile.run) {\
184
196
            mark_time = getrusage_time() - mark_time;\
185
197
            if (mark_time < 0) mark_time = 0;\
186
 
            objspace->profile.record[count].gc_mark_time = mark_time;\
 
198
            objspace->profile.record[objspace->profile.count].gc_mark_time = mark_time;\
187
199
        }\
188
200
    } while(0)
189
201
 
207
219
            record->allocate_limit = malloc_limit; \
208
220
        }\
209
221
    } while(0)
210
 
#define GC_PROF_SET_HEAP_INFO do {\
211
 
        if (objspace->profile.run) {\
212
 
            gc_profile_record *record = &objspace->profile.record[objspace->profile.count];\
213
 
            record->heap_use_slots = heaps_used;\
214
 
            record->heap_live_objects = live;\
215
 
            record->heap_free_objects = freed; \
216
 
            record->heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\
217
 
            record->have_finalize = final_list ? Qtrue : Qfalse;\
218
 
            record->heap_use_size = live * sizeof(RVALUE); \
219
 
            record->heap_total_size = heaps_used * (HEAP_OBJ_LIMIT * sizeof(RVALUE));\
220
 
        }\
 
222
#define GC_PROF_SET_HEAP_INFO(record) do {\
 
223
        live = objspace->heap.live_num;\
 
224
        total = heaps_used * HEAP_OBJ_LIMIT;\
 
225
        (record).heap_use_slots = heaps_used;\
 
226
        (record).heap_live_objects = live;\
 
227
        (record).heap_free_objects = total - live;\
 
228
        (record).heap_total_objects = total;\
 
229
        (record).have_finalize = deferred_final_list ? Qtrue : Qfalse;\
 
230
        (record).heap_use_size = live * sizeof(RVALUE);\
 
231
        (record).heap_total_size = total * sizeof(RVALUE);\
221
232
    } while(0)
 
233
#define GC_PROF_INC_LIVE_NUM objspace->heap.live_num++
 
234
#define GC_PROF_DEC_LIVE_NUM objspace->heap.live_num--
222
235
#else
223
236
#define INIT_GC_PROF_PARAMS double gc_time = 0;\
224
 
    size_t count = objspace->profile.count
 
237
    size_t count = objspace->profile.count, total = 0, live = 0
225
238
#define GC_PROF_MARK_TIMER_START
226
239
#define GC_PROF_MARK_TIMER_STOP
227
240
#define GC_PROF_SWEEP_TIMER_START
228
241
#define GC_PROF_SWEEP_TIMER_STOP
229
242
#define GC_PROF_SET_MALLOC_INFO
230
 
#define GC_PROF_SET_HEAP_INFO do {\
231
 
        if (objspace->profile.run) {\
232
 
            gc_profile_record *record = &objspace->profile.record[objspace->profile.count];\
233
 
            record->heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\
234
 
            record->heap_use_size = live * sizeof(RVALUE); \
235
 
            record->heap_total_size = heaps_used * HEAP_SIZE;\
236
 
        }\
 
243
#define GC_PROF_SET_HEAP_INFO(record) do {\
 
244
        live = objspace->heap.live_num;\
 
245
        total = heaps_used * HEAP_OBJ_LIMIT;\
 
246
        (record).heap_total_objects = total;\
 
247
        (record).heap_use_size = live * sizeof(RVALUE);\
 
248
        (record).heap_total_size = total * sizeof(RVALUE);\
237
249
    } while(0)
 
250
#define GC_PROF_INC_LIVE_NUM
 
251
#define GC_PROF_DEC_LIVE_NUM
238
252
#endif
239
253
 
240
254
 
280
294
    void *membase;
281
295
    RVALUE *slot;
282
296
    size_t limit;
283
 
    int finalize_flag;
 
297
    struct heaps_slot *next;
 
298
    struct heaps_slot *prev;
284
299
};
285
300
 
286
 
#define HEAP_MIN_SLOTS 10000
287
 
#define FREE_MIN  4096
 
301
struct sorted_heaps_slot {
 
302
    RVALUE *start;
 
303
    RVALUE *end;
 
304
    struct heaps_slot *slot;
 
305
};
288
306
 
289
307
struct gc_list {
290
308
    VALUE *varptr;
305
323
    struct {
306
324
        size_t increment;
307
325
        struct heaps_slot *ptr;
 
326
        struct heaps_slot *sweep_slots;
 
327
        struct sorted_heaps_slot *sorted;
308
328
        size_t length;
309
329
        size_t used;
310
330
        RVALUE *freelist;
311
331
        RVALUE *range[2];
312
332
        RVALUE *freed;
 
333
        size_t live_num;
 
334
        size_t free_num;
 
335
        size_t free_min;
 
336
        size_t final_num;
 
337
        size_t do_heap_free;
313
338
    } heap;
314
339
    struct {
315
340
        int dont_gc;
 
341
        int dont_lazy_sweep;
316
342
        int during_gc;
317
343
    } flags;
318
344
    struct {
332
358
        double invoke_time;
333
359
    } profile;
334
360
    struct gc_list *global_list;
335
 
    unsigned int count;
 
361
    size_t count;
336
362
    int gc_stress;
337
363
} rb_objspace_t;
338
364
 
346
372
#endif
347
373
#define malloc_limit            objspace->malloc_params.limit
348
374
#define malloc_increase         objspace->malloc_params.increase
349
 
#define heap_slots              objspace->heap.slots
350
375
#define heaps                   objspace->heap.ptr
351
376
#define heaps_length            objspace->heap.length
352
377
#define heaps_used              objspace->heap.used
365
390
#define global_List             objspace->global_list
366
391
#define ruby_gc_stress          objspace->gc_stress
367
392
 
368
 
#define need_call_final         (finalizer_table && finalizer_table->num_entries)
369
 
 
370
393
static void rb_objspace_call_finalizer(rb_objspace_t *objspace);
371
394
 
372
395
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
375
398
{
376
399
    rb_objspace_t *objspace = malloc(sizeof(rb_objspace_t));
377
400
    memset(objspace, 0, sizeof(*objspace));
378
 
    malloc_limit = GC_MALLOC_LIMIT;
 
401
    malloc_limit = initial_malloc_limit;
379
402
    ruby_gc_stress = ruby_initial_gc_stress;
380
403
 
381
404
    return objspace;
382
405
}
383
406
 
 
407
static void initial_expand_heap(rb_objspace_t *objspace);
 
408
 
 
409
void
 
410
rb_gc_set_params(void)
 
411
{
 
412
    char *malloc_limit_ptr, *heap_min_slots_ptr, *free_min_ptr;
 
413
 
 
414
    if (rb_safe_level() > 0) return;
 
415
 
 
416
    malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT");
 
417
    if (malloc_limit_ptr != NULL) {
 
418
        int malloc_limit_i = atoi(malloc_limit_ptr);
 
419
        printf("malloc_limit=%d (%d)\n", malloc_limit_i, initial_malloc_limit);
 
420
        if (malloc_limit_i > 0) {
 
421
            initial_malloc_limit = malloc_limit_i;
 
422
        }
 
423
    }
 
424
 
 
425
    heap_min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS");
 
426
    if (heap_min_slots_ptr != NULL) {
 
427
        int heap_min_slots_i = atoi(heap_min_slots_ptr);
 
428
        printf("heap_min_slots=%d (%d)\n", heap_min_slots_i, initial_heap_min_slots);
 
429
        if (heap_min_slots_i > 0) {
 
430
            initial_heap_min_slots = heap_min_slots_i;
 
431
            initial_expand_heap(&rb_objspace);
 
432
        }
 
433
    }
 
434
 
 
435
    free_min_ptr = getenv("RUBY_FREE_MIN");
 
436
    if (free_min_ptr != NULL) {
 
437
        int free_min_i = atoi(free_min_ptr);
 
438
        printf("free_min=%d (%d)\n", free_min_i, initial_free_min);
 
439
        if (free_min_i > 0) {
 
440
            initial_free_min = free_min_i;
 
441
        }
 
442
    }
 
443
}
 
444
 
 
445
static void gc_sweep(rb_objspace_t *);
 
446
static void slot_sweep(rb_objspace_t *, struct heaps_slot *);
 
447
static void gc_clear_mark_on_sweep_slots(rb_objspace_t *);
 
448
 
384
449
void
385
450
rb_objspace_free(rb_objspace_t *objspace)
386
451
{
387
 
    rb_objspace_call_finalizer(objspace);
 
452
    gc_clear_mark_on_sweep_slots(objspace);
 
453
    gc_sweep(objspace);
388
454
    if (objspace->profile.record) {
389
455
        free(objspace->profile.record);
390
456
        objspace->profile.record = 0;
396
462
            free(list);
397
463
        }
398
464
    }
399
 
    if (heaps) {
 
465
    if (objspace->heap.sorted) {
400
466
        size_t i;
401
467
        for (i = 0; i < heaps_used; ++i) {
402
 
            free(heaps[i].membase);
 
468
            free(objspace->heap.sorted[i].slot->membase);
 
469
            free(objspace->heap.sorted[i].slot);
403
470
        }
404
 
        free(heaps);
 
471
        free(objspace->heap.sorted);
405
472
        heaps_used = 0;
406
473
        heaps = 0;
407
474
    }
408
475
    free(objspace);
409
476
}
 
477
#else
 
478
void
 
479
rb_gc_set_params(void)
 
480
{
 
481
}
410
482
#endif
411
483
 
412
484
/* tiny heap size */
427
499
 
428
500
#define HEAP_OBJ_LIMIT (HEAP_SIZE / sizeof(struct RVALUE))
429
501
 
430
 
extern VALUE rb_cMutex;
431
502
extern st_table *rb_class_tbl;
432
503
 
433
504
int ruby_disable_gc_stress = 0;
434
505
 
435
506
static void run_final(rb_objspace_t *objspace, VALUE obj);
436
507
static int garbage_collect(rb_objspace_t *objspace);
 
508
static int gc_lazy_sweep(rb_objspace_t *objspace);
437
509
 
438
510
void
439
511
rb_global_variable(VALUE *var)
502
574
 *  call-seq:
503
575
 *    GC.stress = bool          -> bool
504
576
 *
505
 
 *  updates GC stress mode.
506
 
 *
507
 
 *  When GC.stress = true, GC is invoked for all GC opportunity:
508
 
 *  all memory and object allocation.
509
 
 *
510
 
 *  Since it makes Ruby very slow, it is only for debugging.
 
577
 *  Updates the GC stress mode.
 
578
 *
 
579
 *  When stress mode is enabled the GC is invoked at every GC opportunity:
 
580
 *  all memory and object allocations.
 
581
 *
 
582
 *  Enabling stress mode makes Ruby very slow, it is only for debugging.
511
583
 */
512
584
 
513
585
static VALUE
523
595
 *  call-seq:
524
596
 *    GC::Profiler.enable?                 -> true or false
525
597
 *
526
 
 *  returns current status of GC profile mode.
 
598
 *  The current status of GC profile mode.
527
599
 */
528
600
 
529
601
static VALUE
537
609
 *  call-seq:
538
610
 *    GC::Profiler.enable          -> nil
539
611
 *
540
 
 *  updates GC profile mode.
541
 
 *  start profiler for GC.
 
612
 *  Starts the GC profiler.
542
613
 *
543
614
 */
544
615
 
555
626
 *  call-seq:
556
627
 *    GC::Profiler.disable          -> nil
557
628
 *
558
 
 *  updates GC profile mode.
559
 
 *  stop profiler for GC.
 
629
 *  Stops the GC profiler.
560
630
 *
561
631
 */
562
632
 
573
643
 *  call-seq:
574
644
 *    GC::Profiler.clear          -> nil
575
645
 *
576
 
 *  clear before profile data.
 
646
 *  Clears the GC profiler data.
577
647
 *
578
648
 */
579
649
 
637
707
 
638
708
static void vm_xfree(rb_objspace_t *objspace, void *ptr);
639
709
 
640
 
static void *
641
 
vm_xmalloc(rb_objspace_t *objspace, size_t size)
 
710
static inline size_t
 
711
vm_malloc_prepare(rb_objspace_t *objspace, size_t size)
642
712
{
643
 
    void *mem;
644
 
 
645
713
    if ((ssize_t)size < 0) {
646
714
        negative_size_allocation_error("negative allocation size (or too big)");
647
715
    }
655
723
        (malloc_increase+size) > malloc_limit) {
656
724
        garbage_collect_with_gvl(objspace);
657
725
    }
658
 
    mem = malloc(size);
659
 
    if (!mem) {
660
 
        if (garbage_collect_with_gvl(objspace)) {
661
 
            mem = malloc(size);
662
 
        }
663
 
        if (!mem) {
664
 
            ruby_memerror();
665
 
        }
666
 
    }
 
726
 
 
727
    return size;
 
728
}
 
729
 
 
730
static inline void *
 
731
vm_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
 
732
{
667
733
    malloc_increase += size;
668
734
 
669
735
#if CALC_EXACT_MALLOC_SIZE
676
742
    return mem;
677
743
}
678
744
 
 
745
#define TRY_WITH_GC(alloc) do { \
 
746
        if (!(alloc) && \
 
747
            (!garbage_collect_with_gvl(objspace) || \
 
748
             !(alloc))) { \
 
749
            ruby_memerror(); \
 
750
        } \
 
751
    } while (0)
 
752
 
 
753
static void *
 
754
vm_xmalloc(rb_objspace_t *objspace, size_t size)
 
755
{
 
756
    void *mem;
 
757
 
 
758
    size = vm_malloc_prepare(objspace, size);
 
759
    TRY_WITH_GC(mem = malloc(size));
 
760
    return vm_malloc_fixup(objspace, mem, size);
 
761
}
 
762
 
679
763
static void *
680
764
vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size)
681
765
{
738
822
    return vm_xmalloc(&rb_objspace, size);
739
823
}
740
824
 
 
825
static inline size_t
 
826
xmalloc2_size(size_t n, size_t size)
 
827
{
 
828
    size_t len = size * n;
 
829
    if (n != 0 && size != len / n) {
 
830
        rb_raise(rb_eArgError, "malloc: possible integer overflow");
 
831
    }
 
832
    return len;
 
833
}
 
834
 
741
835
void *
742
836
ruby_xmalloc2(size_t n, size_t size)
743
837
{
744
 
    size_t len = size * n;
745
 
    if (n != 0 && size != len / n) {
746
 
        rb_raise(rb_eArgError, "malloc: possible integer overflow");
747
 
    }
748
 
    return vm_xmalloc(&rb_objspace, len);
 
838
    return vm_xmalloc(&rb_objspace, xmalloc2_size(n, size));
 
839
}
 
840
 
 
841
static void *
 
842
vm_xcalloc(rb_objspace_t *objspace, size_t count, size_t elsize)
 
843
{
 
844
    void *mem;
 
845
    size_t size;
 
846
 
 
847
    size = xmalloc2_size(count, elsize);
 
848
    size = vm_malloc_prepare(objspace, size);
 
849
 
 
850
    TRY_WITH_GC(mem = calloc(1, size));
 
851
    return vm_malloc_fixup(objspace, mem, size);
749
852
}
750
853
 
751
854
void *
752
855
ruby_xcalloc(size_t n, size_t size)
753
856
{
754
 
    void *mem = ruby_xmalloc2(n, size);
755
 
    memset(mem, 0, n * size);
756
 
 
757
 
    return mem;
 
857
    return vm_xcalloc(&rb_objspace, n, size);
758
858
}
759
859
 
760
860
void *
872
972
 
873
973
 
874
974
static void
875
 
allocate_heaps(rb_objspace_t *objspace, size_t next_heaps_length)
 
975
allocate_sorted_heaps(rb_objspace_t *objspace, size_t next_heaps_length)
876
976
{
877
 
    struct heaps_slot *p;
 
977
    struct sorted_heaps_slot *p;
878
978
    size_t size;
879
979
 
880
 
    size = next_heaps_length*sizeof(struct heaps_slot);
 
980
    size = next_heaps_length*sizeof(struct sorted_heaps_slot);
881
981
 
882
982
    if (heaps_used > 0) {
883
 
        p = (struct heaps_slot *)realloc(heaps, size);
884
 
        if (p) heaps = p;
 
983
        p = (struct sorted_heaps_slot *)realloc(objspace->heap.sorted, size);
 
984
        if (p) objspace->heap.sorted = p;
885
985
    }
886
986
    else {
887
 
        p = heaps = (struct heaps_slot *)malloc(size);
 
987
        p = objspace->heap.sorted = (struct sorted_heaps_slot *)malloc(size);
888
988
    }
889
989
 
890
990
    if (p == 0) {
898
998
assign_heap_slot(rb_objspace_t *objspace)
899
999
{
900
1000
    RVALUE *p, *pend, *membase;
 
1001
    struct heaps_slot *slot;
901
1002
    size_t hi, lo, mid;
902
1003
    size_t objs;
903
1004
 
904
1005
    objs = HEAP_OBJ_LIMIT;
905
1006
    p = (RVALUE*)malloc(HEAP_SIZE);
906
 
 
907
1007
    if (p == 0) {
908
1008
        during_gc = 0;
909
1009
        rb_memerror();
910
1010
    }
 
1011
    slot = (struct heaps_slot *)malloc(sizeof(struct heaps_slot));
 
1012
    if (slot == 0) {
 
1013
        xfree(p);
 
1014
        during_gc = 0;
 
1015
        rb_memerror();
 
1016
    }
 
1017
    MEMZERO((void*)slot, struct heaps_slot, 1);
 
1018
 
 
1019
    slot->next = heaps;
 
1020
    if (heaps) heaps->prev = slot;
 
1021
    heaps = slot;
911
1022
 
912
1023
    membase = p;
913
1024
    if ((VALUE)p % sizeof(RVALUE) != 0) {
922
1033
    while (lo < hi) {
923
1034
        register RVALUE *mid_membase;
924
1035
        mid = (lo + hi) / 2;
925
 
        mid_membase = heaps[mid].membase;
 
1036
        mid_membase = objspace->heap.sorted[mid].slot->membase;
926
1037
        if (mid_membase < membase) {
927
1038
            lo = mid + 1;
928
1039
        }
934
1045
        }
935
1046
    }
936
1047
    if (hi < heaps_used) {
937
 
        MEMMOVE(&heaps[hi+1], &heaps[hi], struct heaps_slot, heaps_used - hi);
 
1048
        MEMMOVE(&objspace->heap.sorted[hi+1], &objspace->heap.sorted[hi], struct sorted_heaps_slot, heaps_used - hi);
938
1049
    }
939
 
    heaps[hi].membase = membase;
940
 
    heaps[hi].slot = p;
941
 
    heaps[hi].limit = objs;
942
 
    heaps[hi].finalize_flag = FALSE;
 
1050
    objspace->heap.sorted[hi].slot = slot;
 
1051
    objspace->heap.sorted[hi].start = p;
 
1052
    objspace->heap.sorted[hi].end = (p + objs);
 
1053
    heaps->membase = membase;
 
1054
    heaps->slot = p;
 
1055
    heaps->limit = objs;
 
1056
    objspace->heap.free_num += objs;
943
1057
    pend = p + objs;
944
1058
    if (lomem == 0 || lomem > p) lomem = p;
945
1059
    if (himem < pend) himem = pend;
954
1068
}
955
1069
 
956
1070
static void
957
 
init_heap(rb_objspace_t *objspace)
 
1071
add_heap_slots(rb_objspace_t *objspace, size_t add)
958
1072
{
959
 
    size_t add, i;
960
 
 
961
 
    add = HEAP_MIN_SLOTS / HEAP_OBJ_LIMIT;
962
 
 
963
 
    if (!add) {
964
 
        add = 1;
965
 
    }
 
1073
    size_t i;
966
1074
 
967
1075
    if ((heaps_used + add) > heaps_length) {
968
 
        allocate_heaps(objspace, heaps_used + add);
 
1076
        allocate_sorted_heaps(objspace, heaps_used + add);
969
1077
    }
970
1078
 
971
1079
    for (i = 0; i < add; i++) {
972
1080
        assign_heap_slot(objspace);
973
1081
    }
 
1082
}
 
1083
 
 
1084
static void
 
1085
init_heap(rb_objspace_t *objspace)
 
1086
{
 
1087
    add_heap_slots(objspace, HEAP_MIN_SLOTS / HEAP_OBJ_LIMIT);
 
1088
#ifdef USE_SIGALTSTACK
 
1089
    {
 
1090
        /* altstack of another threads are allocated in another place */
 
1091
        rb_thread_t *th = GET_THREAD();
 
1092
        void *tmp = th->altstack;
 
1093
        th->altstack = malloc(ALT_STACK_SIZE);
 
1094
        free(tmp); /* free previously allocated area */
 
1095
    }
 
1096
#endif
 
1097
 
974
1098
    heaps_inc = 0;
975
1099
    objspace->profile.invoke_time = getrusage_time();
976
 
}
977
 
 
 
1100
    finalizer_table = st_init_numtable();
 
1101
}
 
1102
 
 
1103
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
 
1104
static void
 
1105
initial_expand_heap(rb_objspace_t *objspace)
 
1106
{
 
1107
    size_t min_size = initial_heap_min_slots / HEAP_OBJ_LIMIT;
 
1108
 
 
1109
    if (min_size > heaps_used) {
 
1110
        add_heap_slots(objspace, min_size - heaps_used);
 
1111
    }
 
1112
}
 
1113
#endif
978
1114
 
979
1115
static void
980
1116
set_heaps_increment(rb_objspace_t *objspace)
988
1124
    heaps_inc = next_heaps_length - heaps_used;
989
1125
 
990
1126
    if (next_heaps_length > heaps_length) {
991
 
        allocate_heaps(objspace, next_heaps_length);
 
1127
        allocate_sorted_heaps(objspace, next_heaps_length);
992
1128
    }
993
1129
}
994
1130
 
1003
1139
    return FALSE;
1004
1140
}
1005
1141
 
 
1142
int
 
1143
rb_during_gc(void)
 
1144
{
 
1145
    rb_objspace_t *objspace = &rb_objspace;
 
1146
    return during_gc;
 
1147
}
 
1148
 
1006
1149
#define RANY(o) ((RVALUE*)(o))
1007
1150
 
1008
 
static VALUE
1009
 
rb_newobj_from_heap(rb_objspace_t *objspace)
 
1151
VALUE
 
1152
rb_newobj(void)
1010
1153
{
 
1154
    rb_objspace_t *objspace = &rb_objspace;
1011
1155
    VALUE obj;
1012
1156
 
1013
 
    if ((ruby_gc_stress && !ruby_disable_gc_stress) || !freelist) {
1014
 
        if (!heaps_increment(objspace) && !garbage_collect(objspace)) {
 
1157
    if (UNLIKELY(during_gc)) {
 
1158
        dont_gc = 1;
 
1159
        during_gc = 0;
 
1160
        rb_bug("object allocation during garbage collection phase");
 
1161
    }
 
1162
 
 
1163
    if (UNLIKELY(ruby_gc_stress && !ruby_disable_gc_stress)) {
 
1164
        if (!garbage_collect(objspace)) {
 
1165
            during_gc = 0;
 
1166
            rb_memerror();
 
1167
        }
 
1168
    }
 
1169
 
 
1170
    if (UNLIKELY(!freelist)) {
 
1171
        if (!gc_lazy_sweep(objspace)) {
1015
1172
            during_gc = 0;
1016
1173
            rb_memerror();
1017
1174
        }
1025
1182
    RANY(obj)->file = rb_sourcefile();
1026
1183
    RANY(obj)->line = rb_sourceline();
1027
1184
#endif
 
1185
    GC_PROF_INC_LIVE_NUM;
1028
1186
 
1029
1187
    return obj;
1030
1188
}
1031
1189
 
1032
 
#if USE_VALUE_CACHE
1033
 
static VALUE
1034
 
rb_fill_value_cache(rb_thread_t *th)
1035
 
{
1036
 
    rb_objspace_t *objspace = &rb_objspace;
1037
 
    int i;
1038
 
    VALUE rv;
1039
 
 
1040
 
    /* LOCK */
1041
 
    for (i=0; i<RUBY_VM_VALUE_CACHE_SIZE; i++) {
1042
 
        VALUE v = rb_newobj_from_heap(objspace);
1043
 
 
1044
 
        th->value_cache[i] = v;
1045
 
        RBASIC(v)->flags = FL_MARK;
1046
 
    }
1047
 
    th->value_cache_ptr = &th->value_cache[0];
1048
 
    rv = rb_newobj_from_heap(objspace);
1049
 
    /* UNLOCK */
1050
 
    return rv;
1051
 
}
1052
 
#endif
1053
 
 
1054
 
int
1055
 
rb_during_gc(void)
1056
 
{
1057
 
    rb_objspace_t *objspace = &rb_objspace;
1058
 
    return during_gc;
1059
 
}
1060
 
 
1061
 
VALUE
1062
 
rb_newobj(void)
1063
 
{
1064
 
#if USE_VALUE_CACHE || (defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE)
1065
 
    rb_thread_t *th = GET_THREAD();
1066
 
#endif
1067
 
#if USE_VALUE_CACHE
1068
 
    VALUE v = *th->value_cache_ptr;
1069
 
#endif
1070
 
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
1071
 
    rb_objspace_t *objspace = th->vm->objspace;
1072
 
#else
1073
 
    rb_objspace_t *objspace = &rb_objspace;
1074
 
#endif
1075
 
 
1076
 
    if (during_gc) {
1077
 
        dont_gc = 1;
1078
 
        during_gc = 0;
1079
 
        rb_bug("object allocation during garbage collection phase");
1080
 
    }
1081
 
 
1082
 
#if USE_VALUE_CACHE
1083
 
    if (v) {
1084
 
        RBASIC(v)->flags = 0;
1085
 
        th->value_cache_ptr++;
1086
 
    }
1087
 
    else {
1088
 
        v = rb_fill_value_cache(th);
1089
 
    }
1090
 
 
1091
 
#if defined(GC_DEBUG)
1092
 
    printf("cache index: %d, v: %p, th: %p\n",
1093
 
           th->value_cache_ptr - th->value_cache, v, th);
1094
 
#endif
1095
 
    return v;
1096
 
#else
1097
 
    return rb_newobj_from_heap(objspace);
1098
 
#endif
1099
 
}
1100
 
 
1101
1190
NODE*
1102
1191
rb_node_newnode(enum node_type type, VALUE a0, VALUE a1, VALUE a2)
1103
1192
{
1145
1234
size_t
1146
1235
rb_objspace_data_type_memsize(VALUE obj)
1147
1236
{
1148
 
    if (RTYPEDDATA_P(obj) && RTYPEDDATA_TYPE(obj)->dsize) {
1149
 
        return RTYPEDDATA_TYPE(obj)->dsize(RTYPEDDATA_DATA(obj));
 
1237
    if (RTYPEDDATA_P(obj) && RTYPEDDATA_TYPE(obj)->function.dsize) {
 
1238
        return RTYPEDDATA_TYPE(obj)->function.dsize(RTYPEDDATA_DATA(obj));
1150
1239
    }
1151
1240
    else {
1152
1241
        return 0;
1195
1284
}
1196
1285
#endif
1197
1286
 
1198
 
#define GC_WATER_MARK 512
 
1287
#define GC_LEVEL_MAX 250
 
1288
#define STACKFRAME_FOR_GC_MARK (GC_LEVEL_MAX * GC_MARK_STACKFRAME_WORD)
1199
1289
 
1200
1290
size_t
1201
1291
ruby_stack_length(VALUE **p)
1207
1297
}
1208
1298
 
1209
1299
static int
1210
 
stack_check(void)
 
1300
stack_check(int water_mark)
1211
1301
{
1212
1302
    int ret;
1213
1303
    rb_thread_t *th = GET_THREAD();
1214
1304
    SET_STACK_END;
1215
 
    ret = STACK_LENGTH > STACK_LEVEL_MAX - GC_WATER_MARK;
 
1305
    ret = STACK_LENGTH > STACK_LEVEL_MAX - water_mark;
1216
1306
#ifdef __ia64
1217
1307
    if (!ret) {
1218
1308
        ret = (VALUE*)rb_ia64_bsp() - th->machine_register_stack_start >
1219
 
              th->machine_register_stack_maxsize/sizeof(VALUE) - GC_WATER_MARK;
 
1309
              th->machine_register_stack_maxsize/sizeof(VALUE) - water_mark;
1220
1310
    }
1221
1311
#endif
1222
1312
    return ret;
1223
1313
}
1224
1314
 
 
1315
#define STACKFRAME_FOR_CALL_CFUNC 512
 
1316
 
1225
1317
int
1226
1318
ruby_stack_check(void)
1227
1319
{
1228
1320
#if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK)
1229
1321
    return 0;
1230
1322
#else
1231
 
    return stack_check();
 
1323
    return stack_check(STACKFRAME_FOR_CALL_CFUNC);
1232
1324
#endif
1233
1325
}
1234
1326
 
1252
1344
 
1253
1345
    init_mark_stack(objspace);
1254
1346
    for (i = 0; i < heaps_used; i++) {
1255
 
        p = heaps[i].slot; pend = p + heaps[i].limit;
 
1347
        p = objspace->heap.sorted[i].start; pend = objspace->heap.sorted[i].end;
1256
1348
        while (p < pend) {
1257
1349
            if ((p->as.basic.flags & FL_MARK) &&
1258
1350
                (p->as.basic.flags != FL_MARK)) {
1283
1375
is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
1284
1376
{
1285
1377
    register RVALUE *p = RANY(ptr);
1286
 
    register struct heaps_slot *heap;
 
1378
    register struct sorted_heaps_slot *heap;
1287
1379
    register size_t hi, lo, mid;
1288
1380
 
1289
1381
    if (p < lomem || p > himem) return FALSE;
1294
1386
    hi = heaps_used;
1295
1387
    while (lo < hi) {
1296
1388
        mid = (lo + hi) / 2;
1297
 
        heap = &heaps[mid];
1298
 
        if (heap->slot <= p) {
1299
 
            if (p < heap->slot + heap->limit)
 
1389
        heap = &objspace->heap.sorted[mid];
 
1390
        if (heap->start <= p) {
 
1391
            if (p < heap->end)
1300
1392
                return TRUE;
1301
1393
            lo = mid + 1;
1302
1394
        }
1337
1429
    gc_mark_locations(&rb_objspace, start, end);
1338
1430
}
1339
1431
 
1340
 
#define rb_gc_mark_locations(start, end) gc_mark_locations(objspace, start, end)
 
1432
#define rb_gc_mark_locations(start, end) gc_mark_locations(objspace, (start), (end))
1341
1433
 
1342
1434
struct mark_tbl_arg {
1343
1435
    rb_objspace_t *objspace;
1356
1448
mark_tbl(rb_objspace_t *objspace, st_table *tbl, int lev)
1357
1449
{
1358
1450
    struct mark_tbl_arg arg;
1359
 
    if (!tbl) return;
 
1451
    if (!tbl || tbl->num_entries == 0) return;
1360
1452
    arg.objspace = objspace;
1361
1453
    arg.lev = lev;
1362
1454
    st_foreach(tbl, mark_entry, (st_data_t)&arg);
1472
1564
    st_free_table(tbl);
1473
1565
}
1474
1566
 
 
1567
static int
 
1568
mark_const_entry_i(ID key, const rb_const_entry_t *ce, st_data_t data)
 
1569
{
 
1570
    struct mark_tbl_arg *arg = (void*)data;
 
1571
    gc_mark(arg->objspace, ce->value, arg->lev);
 
1572
    return ST_CONTINUE;
 
1573
}
 
1574
 
 
1575
static void
 
1576
mark_const_tbl(rb_objspace_t *objspace, st_table *tbl, int lev)
 
1577
{
 
1578
    struct mark_tbl_arg arg;
 
1579
    if (!tbl) return;
 
1580
    arg.objspace = objspace;
 
1581
    arg.lev = lev;
 
1582
    st_foreach(tbl, mark_const_entry_i, (st_data_t)&arg);
 
1583
}
 
1584
 
 
1585
static int
 
1586
free_const_entry_i(ID key, rb_const_entry_t *ce, st_data_t data)
 
1587
{
 
1588
    xfree(ce);
 
1589
    return ST_CONTINUE;
 
1590
}
 
1591
 
 
1592
void
 
1593
rb_free_const_table(st_table *tbl)
 
1594
{
 
1595
    st_foreach(tbl, free_const_entry_i, 0);
 
1596
    st_free_table(tbl);
 
1597
}
 
1598
 
1475
1599
void
1476
1600
rb_mark_tbl(st_table *tbl)
1477
1601
{
1486
1610
    }
1487
1611
}
1488
1612
 
1489
 
#define GC_LEVEL_MAX 250
1490
 
 
1491
1613
static void
1492
1614
gc_mark(rb_objspace_t *objspace, VALUE ptr, int lev)
1493
1615
{
1498
1620
    if (obj->as.basic.flags == 0) return;       /* free cell */
1499
1621
    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
1500
1622
    obj->as.basic.flags |= FL_MARK;
 
1623
    objspace->heap.live_num++;
1501
1624
 
1502
 
    if (lev > GC_LEVEL_MAX || (lev == 0 && stack_check())) {
 
1625
    if (lev > GC_LEVEL_MAX || (lev == 0 && stack_check(STACKFRAME_FOR_GC_MARK))) {
1503
1626
        if (!mark_stack_overflow) {
1504
1627
            if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) {
1505
1628
                *mark_stack_ptr = ptr;
1533
1656
    if (obj->as.basic.flags == 0) return;       /* free cell */
1534
1657
    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
1535
1658
    obj->as.basic.flags |= FL_MARK;
 
1659
    objspace->heap.live_num++;
1536
1660
 
1537
1661
  marking:
1538
1662
    if (FL_TEST(obj, FL_EXIVAR)) {
1684
1808
      case T_MODULE:
1685
1809
        mark_m_tbl(objspace, RCLASS_M_TBL(obj), lev);
1686
1810
        mark_tbl(objspace, RCLASS_IV_TBL(obj), lev);
 
1811
        mark_const_tbl(objspace, RCLASS_CONST_TBL(obj), lev);
1687
1812
        ptr = RCLASS_SUPER(obj);
1688
1813
        goto again;
1689
1814
 
1716
1841
 
1717
1842
      case T_DATA:
1718
1843
        if (RTYPEDDATA_P(obj)) {
1719
 
            if (obj->as.typeddata.type->dmark) (*obj->as.typeddata.type->dmark)(DATA_PTR(obj));
 
1844
            RUBY_DATA_FUNC mark_func = obj->as.typeddata.type->function.dmark;
 
1845
            if (mark_func) (*mark_func)(DATA_PTR(obj));
1720
1846
        }
1721
1847
        else {
1722
1848
            if (obj->as.data.dmark) (*obj->as.data.dmark)(DATA_PTR(obj));
1807
1933
        RVALUE *tmp = p->as.free.next;
1808
1934
        run_final(objspace, (VALUE)p);
1809
1935
        if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
1810
 
            add_freelist(objspace, p);
 
1936
            if (objspace->heap.sweep_slots) {
 
1937
                p->as.free.flags = 0;
 
1938
            }
 
1939
            else {
 
1940
                GC_PROF_DEC_LIVE_NUM;
 
1941
                add_freelist(objspace, p);
 
1942
            }
1811
1943
        }
1812
1944
        else {
1813
1945
            struct heaps_slot *slot = (struct heaps_slot *)(VALUE)RDATA(p)->dmark;
1818
1950
}
1819
1951
 
1820
1952
static void
 
1953
unlink_heap_slot(rb_objspace_t *objspace, struct heaps_slot *slot)
 
1954
{
 
1955
    if (slot->prev)
 
1956
        slot->prev->next = slot->next;
 
1957
    if (slot->next)
 
1958
        slot->next->prev = slot->prev;
 
1959
    if (heaps == slot)
 
1960
        heaps = slot->next;
 
1961
    if (objspace->heap.sweep_slots == slot)
 
1962
        objspace->heap.sweep_slots = slot->next;
 
1963
    slot->prev = NULL;
 
1964
    slot->next = NULL;
 
1965
}
 
1966
 
 
1967
 
 
1968
static void
1821
1969
free_unused_heaps(rb_objspace_t *objspace)
1822
1970
{
1823
1971
    size_t i, j;
1824
1972
    RVALUE *last = 0;
1825
1973
 
1826
1974
    for (i = j = 1; j < heaps_used; i++) {
1827
 
        if (heaps[i].limit == 0) {
 
1975
        if (objspace->heap.sorted[i].slot->limit == 0) {
1828
1976
            if (!last) {
1829
 
                last = heaps[i].membase;
 
1977
                last = objspace->heap.sorted[i].slot->membase;
1830
1978
            }
1831
1979
            else {
1832
 
                free(heaps[i].membase);
 
1980
                free(objspace->heap.sorted[i].slot->membase);
1833
1981
            }
 
1982
            free(objspace->heap.sorted[i].slot);
1834
1983
            heaps_used--;
1835
1984
        }
1836
1985
        else {
1837
1986
            if (i != j) {
1838
 
                heaps[j] = heaps[i];
 
1987
                objspace->heap.sorted[j] = objspace->heap.sorted[i];
1839
1988
            }
1840
1989
            j++;
1841
1990
        }
1852
2001
}
1853
2002
 
1854
2003
static void
1855
 
gc_sweep(rb_objspace_t *objspace)
1856
 
{
1857
 
    RVALUE *p, *pend, *final_list;
1858
 
    size_t freed = 0;
1859
 
    size_t i;
1860
 
    size_t live = 0, free_min = 0, do_heap_free = 0;
1861
 
 
1862
 
    do_heap_free = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.65);
1863
 
    free_min = (size_t)((heaps_used * HEAP_OBJ_LIMIT)  * 0.2);
1864
 
 
1865
 
    if (free_min < FREE_MIN) {
1866
 
        do_heap_free = heaps_used * HEAP_OBJ_LIMIT;
1867
 
        free_min = FREE_MIN;
1868
 
    }
1869
 
 
 
2004
slot_sweep(rb_objspace_t *objspace, struct heaps_slot *sweep_slot)
 
2005
{
 
2006
    size_t free_num = 0, final_num = 0;
 
2007
    RVALUE *p, *pend;
 
2008
    RVALUE *free = freelist, *final = deferred_final_list;
 
2009
    int deferred;
 
2010
 
 
2011
    p = sweep_slot->slot; pend = p + sweep_slot->limit;
 
2012
    while (p < pend) {
 
2013
        if (!(p->as.basic.flags & FL_MARK)) {
 
2014
            if (p->as.basic.flags &&
 
2015
                ((deferred = obj_free(objspace, (VALUE)p)) ||
 
2016
                 (FL_TEST(p, FL_FINALIZE)))) {
 
2017
                if (!deferred) {
 
2018
                    p->as.free.flags = T_ZOMBIE;
 
2019
                    RDATA(p)->dfree = 0;
 
2020
                }
 
2021
                p->as.free.flags |= FL_MARK;
 
2022
                p->as.free.next = deferred_final_list;
 
2023
                deferred_final_list = p;
 
2024
                final_num++;
 
2025
            }
 
2026
            else {
 
2027
                add_freelist(objspace, p);
 
2028
                free_num++;
 
2029
            }
 
2030
        }
 
2031
        else if (BUILTIN_TYPE(p) == T_ZOMBIE) {
 
2032
            /* objects to be finalized */
 
2033
            /* do nothing remain marked */
 
2034
        }
 
2035
        else {
 
2036
            RBASIC(p)->flags &= ~FL_MARK;
 
2037
        }
 
2038
        p++;
 
2039
    }
 
2040
    if (final_num + free_num == sweep_slot->limit &&
 
2041
        objspace->heap.free_num > objspace->heap.do_heap_free) {
 
2042
        RVALUE *pp;
 
2043
 
 
2044
        for (pp = deferred_final_list; pp != final; pp = pp->as.free.next) {
 
2045
            RDATA(pp)->dmark = (void (*)(void *))(VALUE)sweep_slot;
 
2046
            pp->as.free.flags |= FL_SINGLETON; /* freeing page mark */
 
2047
        }
 
2048
        sweep_slot->limit = final_num;
 
2049
        freelist = free;        /* cancel this page from freelist */
 
2050
        unlink_heap_slot(objspace, sweep_slot);
 
2051
    }
 
2052
    else {
 
2053
        objspace->heap.free_num += free_num;
 
2054
    }
 
2055
    objspace->heap.final_num += final_num;
 
2056
 
 
2057
    if (deferred_final_list) {
 
2058
        rb_thread_t *th = GET_THREAD();
 
2059
        if (th) {
 
2060
            RUBY_VM_SET_FINALIZER_INTERRUPT(th);
 
2061
        }
 
2062
    }
 
2063
}
 
2064
 
 
2065
static int
 
2066
ready_to_gc(rb_objspace_t *objspace)
 
2067
{
 
2068
    if (dont_gc || during_gc) {
 
2069
        if (!freelist) {
 
2070
            if (!heaps_increment(objspace)) {
 
2071
                set_heaps_increment(objspace);
 
2072
                heaps_increment(objspace);
 
2073
            }
 
2074
        }
 
2075
        return FALSE;
 
2076
    }
 
2077
    return TRUE;
 
2078
}
 
2079
 
 
2080
static void
 
2081
before_gc_sweep(rb_objspace_t *objspace)
 
2082
{
1870
2083
    freelist = 0;
1871
 
    final_list = deferred_final_list;
1872
 
    deferred_final_list = 0;
1873
 
    for (i = 0; i < heaps_used; i++) {
1874
 
        size_t free_num = 0, final_num = 0;
1875
 
        RVALUE *free = freelist;
1876
 
        RVALUE *final = final_list;
1877
 
        int deferred;
1878
 
 
1879
 
        if(heaps[i].finalize_flag) continue;
1880
 
 
1881
 
        p = heaps[i].slot; pend = p + heaps[i].limit;
1882
 
        while (p < pend) {
1883
 
            if (!(p->as.basic.flags & FL_MARK)) {
1884
 
                if (p->as.basic.flags &&
1885
 
                    ((deferred = obj_free(objspace, (VALUE)p)) ||
1886
 
                     ((FL_TEST(p, FL_FINALIZE)) && need_call_final))) {
1887
 
                    if (!deferred) {
1888
 
                        p->as.free.flags = T_ZOMBIE;
1889
 
                        RDATA(p)->dfree = 0;
1890
 
                    }
1891
 
                    p->as.free.flags |= FL_MARK;
1892
 
                    p->as.free.next = final_list;
1893
 
                    final_list = p;
1894
 
                    final_num++;
1895
 
                }
1896
 
                else {
1897
 
                    add_freelist(objspace, p);
1898
 
                    free_num++;
1899
 
                }
1900
 
            }
1901
 
            else if (BUILTIN_TYPE(p) == T_ZOMBIE) {
1902
 
                /* objects to be finalized */
1903
 
                /* do nothing remain marked */
1904
 
            }
1905
 
            else {
1906
 
                RBASIC(p)->flags &= ~FL_MARK;
1907
 
                live++;
1908
 
            }
1909
 
            p++;
1910
 
        }
1911
 
        if (final_num + free_num == heaps[i].limit && freed > do_heap_free) {
1912
 
            RVALUE *pp;
1913
 
 
1914
 
            for (pp = final_list; pp != final; pp = pp->as.free.next) {
1915
 
                RDATA(pp)->dmark = (void (*)())(VALUE)&heaps[i];
1916
 
                pp->as.free.flags |= FL_SINGLETON; /* freeing page mark */
1917
 
            }
1918
 
            heaps[i].limit = final_num;
1919
 
            heaps[i].finalize_flag = TRUE;
1920
 
            freelist = free;    /* cancel this page from freelist */
1921
 
        }
1922
 
        else {
1923
 
            freed += free_num;
1924
 
        }
1925
 
    }
 
2084
    objspace->heap.do_heap_free = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.65);
 
2085
    objspace->heap.free_min = (size_t)((heaps_used * HEAP_OBJ_LIMIT)  * 0.2);
 
2086
    if (objspace->heap.free_min < initial_free_min) {
 
2087
        objspace->heap.do_heap_free = heaps_used * HEAP_OBJ_LIMIT;
 
2088
        objspace->heap.free_min = initial_free_min;
 
2089
    }
 
2090
    objspace->heap.sweep_slots = heaps;
 
2091
    objspace->heap.free_num = 0;
 
2092
 
 
2093
    /* sweep unlinked method entries */
 
2094
    if (GET_VM()->unlinked_method_entry_list) {
 
2095
        rb_sweep_method_entry(GET_VM());
 
2096
    }
 
2097
}
 
2098
 
 
2099
static void
 
2100
after_gc_sweep(rb_objspace_t *objspace)
 
2101
{
1926
2102
    GC_PROF_SET_MALLOC_INFO;
 
2103
 
 
2104
    if (objspace->heap.free_num < objspace->heap.free_min) {
 
2105
        set_heaps_increment(objspace);
 
2106
        heaps_increment(objspace);
 
2107
    }
 
2108
 
1927
2109
    if (malloc_increase > malloc_limit) {
1928
 
        malloc_limit += (size_t)((malloc_increase - malloc_limit) * (double)live / (live + freed));
1929
 
        if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
 
2110
        malloc_limit += (size_t)((malloc_increase - malloc_limit) * (double)objspace->heap.live_num / (heaps_used * HEAP_OBJ_LIMIT));
 
2111
        if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit;
1930
2112
    }
1931
2113
    malloc_increase = 0;
1932
 
    if (freed < free_min) {
1933
 
        set_heaps_increment(objspace);
1934
 
        heaps_increment(objspace);
1935
 
    }
 
2114
 
 
2115
    free_unused_heaps(objspace);
 
2116
}
 
2117
 
 
2118
static int
 
2119
lazy_sweep(rb_objspace_t *objspace)
 
2120
{
 
2121
    struct heaps_slot *next;
 
2122
 
 
2123
    heaps_increment(objspace);
 
2124
    while (objspace->heap.sweep_slots) {
 
2125
        next = objspace->heap.sweep_slots->next;
 
2126
        slot_sweep(objspace, objspace->heap.sweep_slots);
 
2127
        objspace->heap.sweep_slots = next;
 
2128
        if (freelist) {
 
2129
            during_gc = 0;
 
2130
            return TRUE;
 
2131
        }
 
2132
    }
 
2133
    return FALSE;
 
2134
}
 
2135
 
 
2136
static void
 
2137
rest_sweep(rb_objspace_t *objspace)
 
2138
{
 
2139
    if (objspace->heap.sweep_slots) {
 
2140
       while (objspace->heap.sweep_slots) {
 
2141
           lazy_sweep(objspace);
 
2142
       }
 
2143
       after_gc_sweep(objspace);
 
2144
    }
 
2145
}
 
2146
 
 
2147
static void gc_marks(rb_objspace_t *objspace);
 
2148
 
 
2149
static int
 
2150
gc_lazy_sweep(rb_objspace_t *objspace)
 
2151
{
 
2152
    int res;
 
2153
    INIT_GC_PROF_PARAMS;
 
2154
 
 
2155
    if (objspace->flags.dont_lazy_sweep)
 
2156
        return garbage_collect(objspace);
 
2157
 
 
2158
 
 
2159
    if (!ready_to_gc(objspace)) return TRUE;
 
2160
 
 
2161
    during_gc++;
 
2162
    GC_PROF_TIMER_START;
 
2163
    GC_PROF_SWEEP_TIMER_START;
 
2164
 
 
2165
    if (objspace->heap.sweep_slots) {
 
2166
        res = lazy_sweep(objspace);
 
2167
        if (res) {
 
2168
            GC_PROF_SWEEP_TIMER_STOP;
 
2169
            GC_PROF_SET_MALLOC_INFO;
 
2170
            GC_PROF_TIMER_STOP(Qfalse);
 
2171
            return res;
 
2172
        }
 
2173
        after_gc_sweep(objspace);
 
2174
    }
 
2175
    else {
 
2176
        if (heaps_increment(objspace)) {
 
2177
            during_gc = 0;
 
2178
            return TRUE;
 
2179
        }
 
2180
    }
 
2181
 
 
2182
    gc_marks(objspace);
 
2183
 
 
2184
    before_gc_sweep(objspace);
 
2185
    if (objspace->heap.free_min > (heaps_used * HEAP_OBJ_LIMIT - objspace->heap.live_num)) {
 
2186
        set_heaps_increment(objspace);
 
2187
    }
 
2188
 
 
2189
    GC_PROF_SWEEP_TIMER_START;
 
2190
    if(!(res = lazy_sweep(objspace))) {
 
2191
        after_gc_sweep(objspace);
 
2192
        if(freelist) {
 
2193
            res = TRUE;
 
2194
            during_gc = 0;
 
2195
        }
 
2196
    }
 
2197
    GC_PROF_SWEEP_TIMER_STOP;
 
2198
 
 
2199
    GC_PROF_TIMER_STOP(Qtrue);
 
2200
    return res;
 
2201
}
 
2202
 
 
2203
static void
 
2204
gc_sweep(rb_objspace_t *objspace)
 
2205
{
 
2206
    struct heaps_slot *next;
 
2207
 
 
2208
    before_gc_sweep(objspace);
 
2209
 
 
2210
    while (objspace->heap.sweep_slots) {
 
2211
        next = objspace->heap.sweep_slots->next;
 
2212
        slot_sweep(objspace, objspace->heap.sweep_slots);
 
2213
        objspace->heap.sweep_slots = next;
 
2214
    }
 
2215
 
 
2216
    after_gc_sweep(objspace);
 
2217
 
1936
2218
    during_gc = 0;
1937
 
 
1938
 
    /* clear finalization list */
1939
 
    if (final_list) {
1940
 
        GC_PROF_SET_HEAP_INFO;
1941
 
        deferred_final_list = final_list;
1942
 
        RUBY_VM_SET_FINALIZER_INTERRUPT(GET_THREAD());
1943
 
    }
1944
 
    else{
1945
 
        free_unused_heaps(objspace);
1946
 
        GC_PROF_SET_HEAP_INFO;
1947
 
    }
1948
2219
}
1949
2220
 
1950
2221
void
1951
2222
rb_gc_force_recycle(VALUE p)
1952
2223
{
1953
2224
    rb_objspace_t *objspace = &rb_objspace;
1954
 
    add_freelist(objspace, (RVALUE *)p);
 
2225
    GC_PROF_DEC_LIVE_NUM;
 
2226
    if (RBASIC(p)->flags & FL_MARK) {
 
2227
        RANY(p)->as.free.flags = 0;
 
2228
    }
 
2229
    else {
 
2230
        add_freelist(objspace, (RVALUE *)p);
 
2231
    }
1955
2232
}
1956
2233
 
1957
2234
static inline void
2000
2277
        if (RCLASS_IV_TBL(obj)) {
2001
2278
            st_free_table(RCLASS_IV_TBL(obj));
2002
2279
        }
 
2280
        if (RCLASS_CONST_TBL(obj)) {
 
2281
            rb_free_const_table(RCLASS_CONST_TBL(obj));
 
2282
        }
2003
2283
        if (RCLASS_IV_INDEX_TBL(obj)) {
2004
2284
            st_free_table(RCLASS_IV_INDEX_TBL(obj));
2005
2285
        }
2024
2304
      case T_DATA:
2025
2305
        if (DATA_PTR(obj)) {
2026
2306
            if (RTYPEDDATA_P(obj)) {
2027
 
                RDATA(obj)->dfree = RANY(obj)->as.typeddata.type->dfree;
 
2307
                RDATA(obj)->dfree = RANY(obj)->as.typeddata.type->function.dfree;
2028
2308
            }
2029
 
            if ((long)RANY(obj)->as.data.dfree == -1) {
 
2309
            if (RANY(obj)->as.data.dfree == (RUBY_DATA_FUNC)-1) {
2030
2310
                xfree(DATA_PTR(obj));
2031
2311
            }
2032
2312
            else if (RANY(obj)->as.data.dfree) {
2096
2376
 
2097
2377
#define GC_NOTIFY 0
2098
2378
 
2099
 
void rb_vm_mark(void *ptr);
2100
 
 
2101
2379
#if STACK_GROW_DIRECTION < 0
2102
 
#define GET_STACK_BOUNDS(start, end, appendix) (start = STACK_END, end = STACK_START)
 
2380
#define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_END, (end) = STACK_START)
2103
2381
#elif STACK_GROW_DIRECTION > 0
2104
 
#define GET_STACK_BOUNDS(start, end, appendix) (start = STACK_START, end = STACK_END+appendix)
 
2382
#define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_START, (end) = STACK_END+(appendix))
2105
2383
#else
2106
2384
#define GET_STACK_BOUNDS(start, end, appendix) \
2107
2385
    ((STACK_END < STACK_START) ? \
2108
 
     (start = STACK_END, end = STACK_START) : (start = STACK_START, end = STACK_END+appendix))
 
2386
     ((start) = STACK_END, (end) = STACK_START) : ((start) = STACK_START, (end) = STACK_END+(appendix)))
2109
2387
#endif
2110
2388
 
 
2389
#define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
 
2390
 
2111
2391
static void
2112
2392
mark_current_machine_context(rb_objspace_t *objspace, rb_thread_t *th)
2113
2393
{
2114
 
    rb_jmp_buf save_regs_gc_mark;
 
2394
    union {
 
2395
        rb_jmp_buf j;
 
2396
        VALUE v[sizeof(rb_jmp_buf) / sizeof(VALUE)];
 
2397
    } save_regs_gc_mark;
2115
2398
    VALUE *stack_start, *stack_end;
2116
2399
 
2117
2400
    FLUSH_REGISTER_WINDOWS;
2118
2401
    /* This assumes that all registers are saved into the jmp_buf (and stack) */
2119
 
    rb_setjmp(save_regs_gc_mark);
 
2402
    rb_setjmp(save_regs_gc_mark.j);
2120
2403
 
2121
2404
    SET_STACK_END;
2122
2405
    GET_STACK_BOUNDS(stack_start, stack_end, 1);
2123
2406
 
2124
 
    mark_locations_array(objspace,
2125
 
                         (VALUE*)save_regs_gc_mark,
2126
 
                         sizeof(save_regs_gc_mark) / sizeof(VALUE));
 
2407
    mark_locations_array(objspace, save_regs_gc_mark.v, numberof(save_regs_gc_mark.v));
2127
2408
 
2128
2409
    rb_gc_mark_locations(stack_start, stack_end);
2129
2410
#ifdef __ia64
2130
2411
    rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end);
2131
2412
#endif
2132
2413
#if defined(__mc68000__)
2133
 
    mark_locations_array((VALUE*)((char*)STACK_END + 2),
 
2414
    mark_locations_array(objspace, (VALUE*)((char*)STACK_END + 2),
2134
2415
                         (STACK_START - STACK_END));
2135
2416
#endif
2136
2417
}
2137
2418
 
2138
 
void rb_gc_mark_encodings(void);
2139
 
 
2140
 
static int
2141
 
garbage_collect(rb_objspace_t *objspace)
 
2419
static void
 
2420
gc_clear_mark_on_sweep_slots(rb_objspace_t *objspace)
 
2421
{
 
2422
    struct heaps_slot *scan;
 
2423
    RVALUE *p, *pend;
 
2424
 
 
2425
    if (objspace->heap.sweep_slots) {
 
2426
        while (heaps_increment(objspace));
 
2427
        while (objspace->heap.sweep_slots) {
 
2428
            scan = objspace->heap.sweep_slots;
 
2429
            p = scan->slot; pend = p + scan->limit;
 
2430
            while (p < pend) {
 
2431
                if (p->as.free.flags & FL_MARK && BUILTIN_TYPE(p) != T_ZOMBIE) {
 
2432
                    p->as.basic.flags &= ~FL_MARK;
 
2433
                }
 
2434
                p++;
 
2435
            }
 
2436
            objspace->heap.sweep_slots = objspace->heap.sweep_slots->next;
 
2437
        }
 
2438
    }
 
2439
}
 
2440
 
 
2441
static void
 
2442
gc_marks(rb_objspace_t *objspace)
2142
2443
{
2143
2444
    struct gc_list *list;
2144
2445
    rb_thread_t *th = GET_THREAD();
2145
 
    INIT_GC_PROF_PARAMS;
2146
 
 
2147
 
    if (GC_NOTIFY) printf("start garbage_collect()\n");
2148
 
 
2149
 
    if (!heaps) {
2150
 
        return FALSE;
2151
 
    }
2152
 
 
2153
 
    if (dont_gc || during_gc) {
2154
 
        if (!freelist) {
2155
 
            if (!heaps_increment(objspace)) {
2156
 
                set_heaps_increment(objspace);
2157
 
                heaps_increment(objspace);
2158
 
            }
2159
 
        }
2160
 
        return TRUE;
2161
 
    }
2162
 
    during_gc++;
 
2446
    GC_PROF_MARK_TIMER_START;
 
2447
 
 
2448
    objspace->heap.live_num = 0;
2163
2449
    objspace->count++;
2164
2450
 
2165
 
    GC_PROF_TIMER_START;
2166
 
    GC_PROF_MARK_TIMER_START;
 
2451
 
 
2452
    gc_clear_mark_on_sweep_slots(objspace);
 
2453
 
2167
2454
    SET_STACK_END;
2168
2455
 
2169
2456
    init_mark_stack(objspace);
2170
2457
 
2171
2458
    th->vm->self ? rb_gc_mark(th->vm->self) : rb_vm_mark(th->vm);
2172
2459
 
2173
 
    if (finalizer_table) {
2174
 
        mark_tbl(objspace, finalizer_table, 0);
2175
 
    }
2176
 
 
 
2460
    mark_tbl(objspace, finalizer_table, 0);
2177
2461
    mark_current_machine_context(objspace, th);
2178
2462
 
2179
 
    rb_gc_mark_threads();
2180
2463
    rb_gc_mark_symbols();
2181
2464
    rb_gc_mark_encodings();
2182
2465
 
2194
2477
 
2195
2478
    rb_gc_mark_parser();
2196
2479
 
 
2480
    rb_gc_mark_unlinked_live_method_entries(th->vm);
 
2481
 
2197
2482
    /* gc_mark objects whose marking are not completed*/
2198
2483
    while (!MARK_STACK_EMPTY) {
2199
2484
        if (mark_stack_overflow) {
2204
2489
        }
2205
2490
    }
2206
2491
    GC_PROF_MARK_TIMER_STOP;
 
2492
}
 
2493
 
 
2494
static int
 
2495
garbage_collect(rb_objspace_t *objspace)
 
2496
{
 
2497
    INIT_GC_PROF_PARAMS;
 
2498
 
 
2499
    if (GC_NOTIFY) printf("start garbage_collect()\n");
 
2500
 
 
2501
    if (!heaps) {
 
2502
        return FALSE;
 
2503
    }
 
2504
    if (!ready_to_gc(objspace)) {
 
2505
        return TRUE;
 
2506
    }
 
2507
 
 
2508
    GC_PROF_TIMER_START;
 
2509
 
 
2510
    during_gc++;
 
2511
    gc_marks(objspace);
2207
2512
 
2208
2513
    GC_PROF_SWEEP_TIMER_START;
2209
2514
    gc_sweep(objspace);
2210
2515
    GC_PROF_SWEEP_TIMER_STOP;
2211
2516
 
2212
 
    /* sweep unlinked method entries */
2213
 
    if (th->vm->unlinked_method_entry_list) {
2214
 
        rb_sweep_method_entry(th->vm);
2215
 
    }
2216
 
 
2217
 
    GC_PROF_TIMER_STOP;
 
2517
    GC_PROF_TIMER_STOP(Qtrue);
2218
2518
    if (GC_NOTIFY) printf("end garbage_collect()\n");
2219
2519
    return TRUE;
2220
2520
}
2301
2601
    init_heap(&rb_objspace);
2302
2602
}
2303
2603
 
 
2604
static VALUE
 
2605
lazy_sweep_enable(void)
 
2606
{
 
2607
    rb_objspace_t *objspace = &rb_objspace;
 
2608
 
 
2609
    objspace->flags.dont_lazy_sweep = FALSE;
 
2610
    return Qnil;
 
2611
}
 
2612
 
 
2613
typedef int each_obj_callback(void *, void *, size_t, void *);
 
2614
 
 
2615
struct each_obj_args {
 
2616
    each_obj_callback *callback;
 
2617
    void *data;
 
2618
};
 
2619
 
 
2620
static VALUE
 
2621
objspace_each_objects(VALUE arg)
 
2622
{
 
2623
    size_t i;
 
2624
    RVALUE *membase = 0;
 
2625
    RVALUE *pstart, *pend;
 
2626
    rb_objspace_t *objspace = &rb_objspace;
 
2627
    struct each_obj_args *args = (struct each_obj_args *)arg;
 
2628
    volatile VALUE v;
 
2629
 
 
2630
    i = 0;
 
2631
    while (i < heaps_used) {
 
2632
        while (0 < i && (uintptr_t)membase < (uintptr_t)objspace->heap.sorted[i-1].slot->membase)
 
2633
            i--;
 
2634
        while (i < heaps_used && (uintptr_t)objspace->heap.sorted[i].slot->membase <= (uintptr_t)membase)
 
2635
            i++;
 
2636
        if (heaps_used <= i)
 
2637
          break;
 
2638
        membase = objspace->heap.sorted[i].slot->membase;
 
2639
 
 
2640
        pstart = objspace->heap.sorted[i].slot->slot;
 
2641
        pend = pstart + objspace->heap.sorted[i].slot->limit;
 
2642
 
 
2643
        for (; pstart != pend; pstart++) {
 
2644
            if (pstart->as.basic.flags) {
 
2645
                v = (VALUE)pstart; /* acquire to save this object */
 
2646
                break;
 
2647
            }
 
2648
        }
 
2649
        if (pstart != pend) {
 
2650
            if ((*args->callback)(pstart, pend, sizeof(RVALUE), args->data)) {
 
2651
                break;
 
2652
            }
 
2653
        }
 
2654
    }
 
2655
 
 
2656
    return Qnil;
 
2657
}
 
2658
 
2304
2659
/*
2305
2660
 * rb_objspace_each_objects() is special C API to walk through
2306
2661
 * Ruby object space.  This C API is too difficult to use it.
2338
2693
 *       use some constant value in the iteration.
2339
2694
 */
2340
2695
void
2341
 
rb_objspace_each_objects(int (*callback)(void *vstart, void *vend,
2342
 
                                         size_t stride, void *d),
2343
 
                         void *data)
 
2696
rb_objspace_each_objects(each_obj_callback *callback, void *data)
2344
2697
{
2345
 
    size_t i;
2346
 
    RVALUE *membase = 0;
2347
 
    RVALUE *pstart, *pend;
 
2698
    struct each_obj_args args;
2348
2699
    rb_objspace_t *objspace = &rb_objspace;
2349
 
    volatile VALUE v;
2350
 
 
2351
 
    i = 0;
2352
 
    while (i < heaps_used) {
2353
 
        while (0 < i && (uintptr_t)membase < (uintptr_t)heaps[i-1].membase)
2354
 
            i--;
2355
 
        while (i < heaps_used && (uintptr_t)heaps[i].membase <= (uintptr_t)membase )
2356
 
            i++;
2357
 
        if (heaps_used <= i)
2358
 
            break;
2359
 
        membase = heaps[i].membase;
2360
 
 
2361
 
        pstart = heaps[i].slot;
2362
 
        pend = pstart + heaps[i].limit;
2363
 
 
2364
 
        for (; pstart != pend; pstart++) {
2365
 
            if (pstart->as.basic.flags) {
2366
 
                v = (VALUE)pstart; /* acquire to save this object */
2367
 
                break;
2368
 
            }
2369
 
        }
2370
 
        if (pstart != pend) {
2371
 
            if ((*callback)(pstart, pend, sizeof(RVALUE), data)) {
2372
 
                return;
2373
 
            }
2374
 
        }
2375
 
    }
2376
 
 
2377
 
    return;
 
2700
 
 
2701
    rest_sweep(objspace);
 
2702
    objspace->flags.dont_lazy_sweep = TRUE;
 
2703
 
 
2704
    args.callback = callback;
 
2705
    args.data = data;
 
2706
    rb_ensure(objspace_each_objects, (VALUE)&args, lazy_sweep_enable, Qnil);
2378
2707
}
2379
2708
 
2380
2709
struct os_each_struct {
2489
2818
undefine_final(VALUE os, VALUE obj)
2490
2819
{
2491
2820
    rb_objspace_t *objspace = &rb_objspace;
2492
 
    if (OBJ_FROZEN(obj)) rb_error_frozen("object");
2493
 
    if (finalizer_table) {
2494
 
        st_delete(finalizer_table, (st_data_t*)&obj, 0);
2495
 
    }
 
2821
    st_data_t data = obj;
 
2822
    rb_check_frozen(obj);
 
2823
    st_delete(finalizer_table, &data, 0);
2496
2824
    FL_UNSET(obj, FL_FINALIZE);
2497
2825
    return obj;
2498
2826
}
2511
2839
{
2512
2840
    rb_objspace_t *objspace = &rb_objspace;
2513
2841
    VALUE obj, block, table;
 
2842
    st_data_t data;
2514
2843
 
2515
2844
    rb_scan_args(argc, argv, "11", &obj, &block);
2516
 
    if (OBJ_FROZEN(obj)) rb_error_frozen("object");
 
2845
    rb_check_frozen(obj);
2517
2846
    if (argc == 1) {
2518
2847
        block = rb_block_proc();
2519
2848
    }
2530
2859
    block = rb_ary_new3(2, INT2FIX(rb_safe_level()), block);
2531
2860
    OBJ_FREEZE(block);
2532
2861
 
2533
 
    if (!finalizer_table) {
2534
 
        finalizer_table = st_init_numtable();
2535
 
    }
2536
 
    if (st_lookup(finalizer_table, obj, &table)) {
 
2862
    if (st_lookup(finalizer_table, obj, &data)) {
 
2863
        table = (VALUE)data;
2537
2864
        rb_ary_push(table, block);
2538
2865
    }
2539
2866
    else {
2549
2876
{
2550
2877
    rb_objspace_t *objspace = &rb_objspace;
2551
2878
    VALUE table;
 
2879
    st_data_t data;
2552
2880
 
2553
 
    if (!finalizer_table) return;
2554
2881
    if (!FL_TEST(obj, FL_FINALIZE)) return;
2555
 
    if (st_lookup(finalizer_table, obj, &table)) {
 
2882
    if (st_lookup(finalizer_table, obj, &data)) {
 
2883
        table = (VALUE)data;
2556
2884
        st_insert(finalizer_table, dest, table);
2557
2885
    }
2558
2886
    FL_SET(dest, FL_FINALIZE);
2567
2895
}
2568
2896
 
2569
2897
static void
2570
 
run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE objid, VALUE table)
 
2898
run_finalizer(rb_objspace_t *objspace, VALUE objid, VALUE table)
2571
2899
{
2572
2900
    long i;
2573
2901
    int status;
2574
2902
    VALUE args[3];
2575
2903
 
2576
 
    args[1] = 0;
 
2904
    if (RARRAY_LEN(table) > 0) {
 
2905
        args[1] = rb_obj_freeze(rb_ary_new3(1, objid));
 
2906
    }
 
2907
    else {
 
2908
        args[1] = 0;
 
2909
    }
 
2910
 
2577
2911
    args[2] = (VALUE)rb_safe_level();
2578
 
    if (!args[1] && RARRAY_LEN(table) > 0) {
2579
 
        args[1] = rb_obj_freeze(rb_ary_new3(1, objid));
2580
 
    }
2581
2912
    for (i=0; i<RARRAY_LEN(table); i++) {
2582
2913
        VALUE final = RARRAY_PTR(table)[i];
2583
2914
        args[0] = RARRAY_PTR(final)[1];
2589
2920
static void
2590
2921
run_final(rb_objspace_t *objspace, VALUE obj)
2591
2922
{
2592
 
    VALUE table, objid;
 
2923
    VALUE objid;
2593
2924
    RUBY_DATA_FUNC free_func = 0;
 
2925
    st_data_t key, table;
 
2926
 
 
2927
    objspace->heap.final_num--;
2594
2928
 
2595
2929
    objid = rb_obj_id(obj);     /* make obj into id */
2596
2930
    RBASIC(obj)->klass = 0;
2597
2931
 
2598
2932
    if (RTYPEDDATA_P(obj)) {
2599
 
        free_func = RTYPEDDATA_TYPE(obj)->dfree;
 
2933
        free_func = RTYPEDDATA_TYPE(obj)->function.dfree;
2600
2934
    }
2601
2935
    else {
2602
2936
        free_func = RDATA(obj)->dfree;
2605
2939
        (*free_func)(DATA_PTR(obj));
2606
2940
    }
2607
2941
 
2608
 
    if (finalizer_table &&
2609
 
        st_delete(finalizer_table, (st_data_t*)&obj, &table)) {
2610
 
        run_finalizer(objspace, obj, objid, table);
 
2942
    key = (st_data_t)obj;
 
2943
    if (st_delete(finalizer_table, &key, &table)) {
 
2944
        run_finalizer(objspace, objid, (VALUE)table);
2611
2945
    }
2612
2946
}
2613
2947
 
2622
2956
    }
2623
2957
}
2624
2958
 
2625
 
static void
2626
 
gc_finalize_deferred(rb_objspace_t *objspace)
2627
 
{
2628
 
    finalize_deferred(objspace);
2629
 
    free_unused_heaps(objspace);
2630
 
}
2631
 
 
2632
2959
void
2633
2960
rb_gc_finalize_deferred(void)
2634
2961
{
2635
 
    gc_finalize_deferred(&rb_objspace);
 
2962
    finalize_deferred(&rb_objspace);
2636
2963
}
2637
2964
 
2638
2965
static int
2674
3001
    rb_objspace_call_finalizer(&rb_objspace);
2675
3002
}
2676
3003
 
2677
 
void
 
3004
static void
2678
3005
rb_objspace_call_finalizer(rb_objspace_t *objspace)
2679
3006
{
2680
3007
    RVALUE *p, *pend;
2682
3009
    size_t i;
2683
3010
 
2684
3011
    /* run finalizers */
2685
 
    if (finalizer_table) {
2686
 
        do {
2687
 
            /* XXX: this loop will make no sense */
2688
 
            /* because mark will not be removed */
2689
 
            finalize_deferred(objspace);
2690
 
            mark_tbl(objspace, finalizer_table, 0);
2691
 
            st_foreach(finalizer_table, chain_finalized_object,
2692
 
                       (st_data_t)&deferred_final_list);
2693
 
        } while (deferred_final_list);
2694
 
        /* force to run finalizer */
2695
 
        while (finalizer_table->num_entries) {
2696
 
            struct force_finalize_list *list = 0;
2697
 
            st_foreach(finalizer_table, force_chain_object, (st_data_t)&list);
2698
 
            while (list) {
2699
 
                struct force_finalize_list *curr = list;
2700
 
                run_finalizer(objspace, curr->obj, rb_obj_id(curr->obj), curr->table);
2701
 
                st_delete(finalizer_table, (st_data_t*)&curr->obj, 0);
2702
 
                list = curr->next;
2703
 
                xfree(curr);
2704
 
            }
 
3012
    gc_clear_mark_on_sweep_slots(objspace);
 
3013
 
 
3014
    do {
 
3015
        /* XXX: this loop will make no sense */
 
3016
        /* because mark will not be removed */
 
3017
        finalize_deferred(objspace);
 
3018
        mark_tbl(objspace, finalizer_table, 0);
 
3019
        st_foreach(finalizer_table, chain_finalized_object,
 
3020
                   (st_data_t)&deferred_final_list);
 
3021
    } while (deferred_final_list);
 
3022
    /* force to run finalizer */
 
3023
    while (finalizer_table->num_entries) {
 
3024
        struct force_finalize_list *list = 0;
 
3025
        st_foreach(finalizer_table, force_chain_object, (st_data_t)&list);
 
3026
        while (list) {
 
3027
            struct force_finalize_list *curr = list;
 
3028
            run_finalizer(objspace, rb_obj_id(curr->obj), curr->table);
 
3029
            st_delete(finalizer_table, (st_data_t*)&curr->obj, 0);
 
3030
            list = curr->next;
 
3031
            xfree(curr);
2705
3032
        }
2706
 
        st_free_table(finalizer_table);
2707
 
        finalizer_table = 0;
2708
3033
    }
 
3034
 
2709
3035
    /* finalizers are part of garbage collection */
2710
3036
    during_gc++;
 
3037
 
2711
3038
    /* run data object's finalizers */
2712
3039
    for (i = 0; i < heaps_used; i++) {
2713
 
        p = heaps[i].slot; pend = p + heaps[i].limit;
 
3040
        p = objspace->heap.sorted[i].start; pend = objspace->heap.sorted[i].end;
2714
3041
        while (p < pend) {
2715
3042
            if (BUILTIN_TYPE(p) == T_DATA &&
2716
3043
                DATA_PTR(p) && RANY(p)->as.data.dfree &&
2717
 
                RANY(p)->as.basic.klass != rb_cThread && RANY(p)->as.basic.klass != rb_cMutex) {
 
3044
                !rb_obj_is_thread((VALUE)p) && !rb_obj_is_mutex((VALUE)p) ) {
2718
3045
                p->as.free.flags = 0;
2719
3046
                if (RTYPEDDATA_P(p)) {
2720
 
                    RDATA(p)->dfree = RANY(p)->as.typeddata.type->dfree;
 
3047
                    RDATA(p)->dfree = RANY(p)->as.typeddata.type->function.dfree;
2721
3048
                }
2722
 
                if ((long)RANY(p)->as.data.dfree == -1) {
 
3049
                if (RANY(p)->as.data.dfree == (RUBY_DATA_FUNC)-1) {
2723
3050
                    xfree(DATA_PTR(p));
2724
3051
                }
2725
3052
                else if (RANY(p)->as.data.dfree) {
2742
3069
    if (final_list) {
2743
3070
        finalize_list(objspace, final_list);
2744
3071
    }
 
3072
 
 
3073
    st_free_table(finalizer_table);
 
3074
    finalizer_table = 0;
2745
3075
}
2746
3076
 
2747
3077
void
2749
3079
{
2750
3080
    rb_objspace_t *objspace = &rb_objspace;
2751
3081
    garbage_collect(objspace);
2752
 
    gc_finalize_deferred(objspace);
 
3082
    finalize_deferred(objspace);
 
3083
    free_unused_heaps(objspace);
2753
3084
}
2754
3085
 
2755
3086
/*
2862
3193
     *  24 if 32-bit, double is 8-byte aligned
2863
3194
     *  40 if 64-bit
2864
3195
     */
2865
 
    if (TYPE(obj) == T_SYMBOL) {
 
3196
    if (SYMBOL_P(obj)) {
2866
3197
        return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
2867
3198
    }
2868
3199
    if (SPECIAL_CONST_P(obj)) {
2922
3253
    for (i = 0; i < heaps_used; i++) {
2923
3254
        RVALUE *p, *pend;
2924
3255
 
2925
 
        p = heaps[i].slot; pend = p + heaps[i].limit;
 
3256
        p = objspace->heap.sorted[i].start; pend = objspace->heap.sorted[i].end;
2926
3257
        for (;p < pend; p++) {
2927
3258
            if (p->as.basic.flags) {
2928
3259
                counts[BUILTIN_TYPE(p)]++;
2931
3262
                freed++;
2932
3263
            }
2933
3264
        }
2934
 
        total += heaps[i].limit;
 
3265
        total += objspace->heap.sorted[i].slot->limit;
2935
3266
    }
2936
3267
 
2937
3268
    if (hash == Qnil) {
2946
3277
    for (i = 0; i <= T_MASK; i++) {
2947
3278
        VALUE type;
2948
3279
        switch (i) {
2949
 
#define COUNT_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
 
3280
#define COUNT_TYPE(t) case (t): type = ID2SYM(rb_intern(#t)); break;
2950
3281
            COUNT_TYPE(T_NONE);
2951
3282
            COUNT_TYPE(T_OBJECT);
2952
3283
            COUNT_TYPE(T_CLASS);
2998
3329
    return UINT2NUM((&rb_objspace)->count);
2999
3330
}
3000
3331
 
 
3332
/*
 
3333
 *  call-seq:
 
3334
 *     GC.stat -> Hash
 
3335
 *
 
3336
 *  Returns a Hash containing information about the GC.
 
3337
 *
 
3338
 *  The hash includes information about internal statistics about GC such as:
 
3339
 *
 
3340
 *    {
 
3341
 *      :count          => 18,
 
3342
 *      :heap_used      => 77,
 
3343
 *      :heap_length    => 77,
 
3344
 *      :heap_increment => 0,
 
3345
 *      :heap_live_num  => 23287,
 
3346
 *      :heap_free_num  => 8115,
 
3347
 *      :heap_final_num => 0,
 
3348
 *    }
 
3349
 *
 
3350
 *  The contents of the hash are implementation defined and may be changed in
 
3351
 *  the future.
 
3352
 *
 
3353
 *  This method is only expected to work on C Ruby.
 
3354
 *
 
3355
 */
 
3356
 
 
3357
static VALUE
 
3358
gc_stat(int argc, VALUE *argv, VALUE self)
 
3359
{
 
3360
    rb_objspace_t *objspace = &rb_objspace;
 
3361
    VALUE hash;
 
3362
 
 
3363
    if (rb_scan_args(argc, argv, "01", &hash) == 1) {
 
3364
        if (TYPE(hash) != T_HASH)
 
3365
            rb_raise(rb_eTypeError, "non-hash given");
 
3366
    }
 
3367
 
 
3368
    if (hash == Qnil) {
 
3369
        hash = rb_hash_new();
 
3370
    }
 
3371
 
 
3372
    rest_sweep(objspace);
 
3373
 
 
3374
    rb_hash_aset(hash, ID2SYM(rb_intern("count")), SIZET2NUM(objspace->count));
 
3375
 
 
3376
    /* implementation dependent counters */
 
3377
    rb_hash_aset(hash, ID2SYM(rb_intern("heap_used")), SIZET2NUM(objspace->heap.used));
 
3378
    rb_hash_aset(hash, ID2SYM(rb_intern("heap_length")), SIZET2NUM(objspace->heap.length));
 
3379
    rb_hash_aset(hash, ID2SYM(rb_intern("heap_increment")), SIZET2NUM(objspace->heap.increment));
 
3380
    rb_hash_aset(hash, ID2SYM(rb_intern("heap_live_num")), SIZET2NUM(objspace->heap.live_num));
 
3381
    rb_hash_aset(hash, ID2SYM(rb_intern("heap_free_num")), SIZET2NUM(objspace->heap.free_num));
 
3382
    rb_hash_aset(hash, ID2SYM(rb_intern("heap_final_num")), SIZET2NUM(objspace->heap.final_num));
 
3383
    return hash;
 
3384
}
 
3385
 
 
3386
 
3001
3387
#if CALC_EXACT_MALLOC_SIZE
3002
3388
/*
3003
3389
 *  call-seq:
3046
3432
        prof = rb_hash_new();
3047
3433
        rb_hash_aset(prof, ID2SYM(rb_intern("GC_TIME")), DBL2NUM(objspace->profile.record[i].gc_time));
3048
3434
        rb_hash_aset(prof, ID2SYM(rb_intern("GC_INVOKE_TIME")), DBL2NUM(objspace->profile.record[i].gc_invoke_time));
3049
 
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), rb_uint2inum(objspace->profile.record[i].heap_use_size));
3050
 
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")), rb_uint2inum(objspace->profile.record[i].heap_total_size));
3051
 
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_total_objects));
 
3435
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), SIZET2NUM(objspace->profile.record[i].heap_use_size));
 
3436
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")), SIZET2NUM(objspace->profile.record[i].heap_total_size));
 
3437
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")), SIZET2NUM(objspace->profile.record[i].heap_total_objects));
 
3438
        rb_hash_aset(prof, ID2SYM(rb_intern("GC_IS_MARKED")), objspace->profile.record[i].is_marked);
3052
3439
#if GC_PROFILE_MORE_DETAIL
3053
3440
        rb_hash_aset(prof, ID2SYM(rb_intern("GC_MARK_TIME")), DBL2NUM(objspace->profile.record[i].gc_mark_time));
3054
3441
        rb_hash_aset(prof, ID2SYM(rb_intern("GC_SWEEP_TIME")), DBL2NUM(objspace->profile.record[i].gc_sweep_time));
3055
 
        rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_INCREASE")), rb_uint2inum(objspace->profile.record[i].allocate_increase));
3056
 
        rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_LIMIT")), rb_uint2inum(objspace->profile.record[i].allocate_limit));
3057
 
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SLOTS")), rb_uint2inum(objspace->profile.record[i].heap_use_slots));
3058
 
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_LIVE_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_live_objects));
3059
 
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_FREE_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_free_objects));
 
3442
        rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_INCREASE")), SIZET2NUM(objspace->profile.record[i].allocate_increase));
 
3443
        rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_LIMIT")), SIZET2NUM(objspace->profile.record[i].allocate_limit));
 
3444
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SLOTS")), SIZET2NUM(objspace->profile.record[i].heap_use_slots));
 
3445
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_LIVE_OBJECTS")), SIZET2NUM(objspace->profile.record[i].heap_live_objects));
 
3446
        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_FREE_OBJECTS")), SIZET2NUM(objspace->profile.record[i].heap_free_objects));
3060
3447
        rb_hash_aset(prof, ID2SYM(rb_intern("HAVE_FINALIZE")), objspace->profile.record[i].have_finalize);
3061
3448
#endif
3062
3449
        rb_ary_push(gc_profile, prof);
3067
3454
 
3068
3455
/*
3069
3456
 *  call-seq:
3070
 
 *     GC::Profiler.result -> string
3071
 
 *
3072
 
 *  Report profile data to string.
3073
 
 *
3074
 
 *  It returns a string as:
3075
 
 *   GC 1 invokes.
3076
 
 *   Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC time(ms)
3077
 
 *       1               0.012               159240               212940                10647         0.00000000000001530000
 
3457
 *     GC::Profiler.result -> String
 
3458
 *
 
3459
 *  Returns a profile data report such as:
 
3460
 *
 
3461
 *    GC 1 invokes.
 
3462
 *    Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC time(ms)
 
3463
 *        1               0.012               159240               212940                10647         0.00000000000001530000
3078
3464
 */
3079
3465
 
3080
3466
static VALUE
3083
3469
    rb_objspace_t *objspace = &rb_objspace;
3084
3470
    VALUE record;
3085
3471
    VALUE result;
3086
 
    int i;
 
3472
    int i, index;
3087
3473
 
3088
3474
    record = gc_profile_record_get();
3089
3475
    if (objspace->profile.run && objspace->profile.count) {
3090
3476
        result = rb_sprintf("GC %d invokes.\n", NUM2INT(gc_count(0)));
 
3477
        index = 1;
3091
3478
        rb_str_cat2(result, "Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC Time(ms)\n");
3092
3479
        for (i = 0; i < (int)RARRAY_LEN(record); i++) {
3093
3480
            VALUE r = RARRAY_PTR(record)[i];
3094
 
            rb_str_catf(result, "%5d %19.3f %20d %20d %20d %30.20f\n",
3095
 
                        i+1, NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_INVOKE_TIME")))),
3096
 
                        NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SIZE")))),
3097
 
                        NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")))),
3098
 
                        NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")))),
 
3481
#if !GC_PROFILE_MORE_DETAIL
 
3482
            if (rb_hash_aref(r, ID2SYM(rb_intern("GC_IS_MARKED")))) {
 
3483
#endif
 
3484
            rb_str_catf(result, "%5d %19.3f %20"PRIuSIZE" %20"PRIuSIZE" %20"PRIuSIZE" %30.20f\n",
 
3485
                        index++, NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_INVOKE_TIME")))),
 
3486
                        (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SIZE")))),
 
3487
                        (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")))),
 
3488
                        (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")))),
3099
3489
                        NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_TIME"))))*1000);
 
3490
#if !GC_PROFILE_MORE_DETAIL
 
3491
            }
 
3492
#endif
3100
3493
        }
3101
3494
#if GC_PROFILE_MORE_DETAIL
3102
3495
        rb_str_cat2(result, "\n\n");
3103
3496
        rb_str_cat2(result, "More detail.\n");
3104
3497
        rb_str_cat2(result, "Index Allocate Increase    Allocate Limit  Use Slot  Have Finalize             Mark Time(ms)            Sweep Time(ms)\n");
 
3498
        index = 1;
3105
3499
        for (i = 0; i < (int)RARRAY_LEN(record); i++) {
3106
3500
            VALUE r = RARRAY_PTR(record)[i];
3107
 
            rb_str_catf(result, "%5d %17d %17d %9d %14s %25.20f %25.20f\n",
3108
 
                        i+1, NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_INCREASE")))),
3109
 
                        NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_LIMIT")))),
3110
 
                        NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SLOTS")))),
 
3501
            rb_str_catf(result, "%5d %17"PRIuSIZE" %17"PRIuSIZE" %9"PRIuSIZE" %14s %25.20f %25.20f\n",
 
3502
                        index++, (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_INCREASE")))),
 
3503
                        (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_LIMIT")))),
 
3504
                        (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SLOTS")))),
3111
3505
                        rb_hash_aref(r, ID2SYM(rb_intern("HAVE_FINALIZE")))? "true" : "false",
3112
3506
                        NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_MARK_TIME"))))*1000,
3113
3507
                        NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_SWEEP_TIME"))))*1000);
3124
3518
/*
3125
3519
 *  call-seq:
3126
3520
 *     GC::Profiler.report
 
3521
 *     GC::Profiler.report io
3127
3522
 *
3128
 
 *  GC::Profiler.result display
 
3523
 *  Writes the GC::Profiler#result to <tt>$stdout</tt> or the given IO object.
3129
3524
 *
3130
3525
 */
3131
3526
 
3149
3544
 *  call-seq:
3150
3545
 *     GC::Profiler.total_time -> float
3151
3546
 *
3152
 
 *  return total time that GC used. (msec)
 
3547
 *  The total time used for garbage collection in milliseconds
3153
3548
 */
3154
3549
 
3155
3550
static VALUE
3167
3562
    return DBL2NUM(time);
3168
3563
}
3169
3564
 
 
3565
/*  Document-class: GC::Profiler
 
3566
 *
 
3567
 *  The GC profiler provides access to information on GC runs including time,
 
3568
 *  length and object space size.
 
3569
 *
 
3570
 *  Example:
 
3571
 *
 
3572
 *    GC::Profiler.enable
 
3573
 *
 
3574
 *    require 'rdoc/rdoc'
 
3575
 *
 
3576
 *    puts GC::Profiler.result
 
3577
 *
 
3578
 *    GC::Profiler.disable
 
3579
 *
 
3580
 *  See also GC.count, GC.malloc_allocated_size and GC.malloc_allocations
 
3581
 */
 
3582
 
3170
3583
/*
3171
3584
 *  The <code>GC</code> module provides an interface to Ruby's mark and
3172
3585
 *  sweep garbage collection mechanism. Some of the underlying methods
3173
 
 *  are also available via the <code>ObjectSpace</code> module.
 
3586
 *  are also available via the ObjectSpace module.
 
3587
 *
 
3588
 *  You may obtain information about the operation of the GC through
 
3589
 *  GC::Profiler.
3174
3590
 */
3175
3591
 
3176
3592
void
3186
3602
    rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0);
3187
3603
    rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1);
3188
3604
    rb_define_singleton_method(rb_mGC, "count", gc_count, 0);
 
3605
    rb_define_singleton_method(rb_mGC, "stat", gc_stat, -1);
3189
3606
    rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
3190
3607
 
3191
3608
    rb_mProfiler = rb_define_module_under(rb_mGC, "Profiler");
3211
3628
    OBJ_TAINT(nomem_error);
3212
3629
    OBJ_FREEZE(nomem_error);
3213
3630
 
3214
 
    rb_define_method(rb_mKernel, "__id__", rb_obj_id, 0);
 
3631
    rb_define_method(rb_cBasicObject, "__id__", rb_obj_id, 0);
3215
3632
    rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0);
3216
3633
 
3217
3634
    rb_define_module_function(rb_mObSpace, "count_objects", count_objects, -1);