Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

gc.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 gc.c -
4
5 $Author: nagachika $
6 created at: Tue Oct 5 09:44:46 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12 **********************************************************************/
13
14 #include "ruby/ruby.h"
15 #include "ruby/st.h"
16 #include "ruby/re.h"
17 #include "ruby/io.h"
18 #include "ruby/thread.h"
19 #include "ruby/util.h"
20 #include "ruby/debug.h"
21 #include "eval_intern.h"
22 #include "vm_core.h"
23 #include "internal.h"
24 #include "gc.h"
25 #include "constant.h"
26 #include "ruby_atomic.h"
27 #include "probes.h"
28 #include <stdio.h>
29 #include <stdarg.h>
30 #include <setjmp.h>
31 #include <sys/types.h>
32 #include <assert.h>
33
34 #ifndef __has_feature
35 # define __has_feature(x) 0
36 #endif
37
38 #ifndef HAVE_MALLOC_USABLE_SIZE
39 # ifdef _WIN32
40 # define HAVE_MALLOC_USABLE_SIZE
41 # define malloc_usable_size(a) _msize(a)
42 # elif defined HAVE_MALLOC_SIZE
43 # define HAVE_MALLOC_USABLE_SIZE
44 # define malloc_usable_size(a) malloc_size(a)
45 # endif
46 #endif
47 #ifdef HAVE_MALLOC_USABLE_SIZE
48 # ifdef HAVE_MALLOC_H
49 # include <malloc.h>
50 # elif defined(HAVE_MALLOC_NP_H)
51 # include <malloc_np.h>
52 # elif defined(HAVE_MALLOC_MALLOC_H)
53 # include <malloc/malloc.h>
54 # endif
55 #endif
56
57 #if /* is ASAN enabled? */ \
58 __has_feature(address_sanitizer) /* Clang */ || \
59 defined(__SANITIZE_ADDRESS__) /* GCC 4.8.x */
60 #define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
61 __attribute__((no_address_safety_analysis)) \
62 __attribute__((noinline))
63 #else
64 #define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
65 #endif
66
67 #ifdef HAVE_SYS_TIME_H
68 #include <sys/time.h>
69 #endif
70
71 #ifdef HAVE_SYS_RESOURCE_H
72 #include <sys/resource.h>
73 #endif
74 #if defined(__native_client__) && defined(NACL_NEWLIB)
75 # include "nacl/resource.h"
76 # undef HAVE_POSIX_MEMALIGN
77 # undef HAVE_MEMALIGN
78
79 #endif
80
81 #if defined _WIN32 || defined __CYGWIN__
82 #include <windows.h>
83 #elif defined(HAVE_POSIX_MEMALIGN)
84 #elif defined(HAVE_MEMALIGN)
85 #include <malloc.h>
86 #endif
87
88 #define rb_setjmp(env) RUBY_SETJMP(env)
89 #define rb_jmp_buf rb_jmpbuf_t
90
91 #if defined(HAVE_RB_GC_GUARDED_PTR) && HAVE_RB_GC_GUARDED_PTR
92 volatile VALUE *
93 rb_gc_guarded_ptr(volatile VALUE *ptr)
94 {
95 return ptr;
96 }
97 #endif
98
99 #ifndef GC_HEAP_FREE_SLOTS
100 #define GC_HEAP_FREE_SLOTS 4096
101 #endif
102 #ifndef GC_HEAP_INIT_SLOTS
103 #define GC_HEAP_INIT_SLOTS 10000
104 #endif
105 #ifndef GC_HEAP_GROWTH_FACTOR
106 #define GC_HEAP_GROWTH_FACTOR 1.8
107 #endif
108 #ifndef GC_HEAP_GROWTH_MAX_SLOTS
109 #define GC_HEAP_GROWTH_MAX_SLOTS 0 /* 0 is disable */
110 #endif
111 #ifndef GC_HEAP_OLDOBJECT_LIMIT_FACTOR
112 #define GC_HEAP_OLDOBJECT_LIMIT_FACTOR 2.0
113 #endif
114
115 #ifndef GC_MALLOC_LIMIT_MIN
116 #define GC_MALLOC_LIMIT_MIN (16 * 1024 * 1024 /* 16MB */)
117 #endif
118 #ifndef GC_MALLOC_LIMIT_MAX
119 #define GC_MALLOC_LIMIT_MAX (32 * 1024 * 1024 /* 32MB */)
120 #endif
121 #ifndef GC_MALLOC_LIMIT_GROWTH_FACTOR
122 #define GC_MALLOC_LIMIT_GROWTH_FACTOR 1.4
123 #endif
124
125 #ifndef GC_OLDMALLOC_LIMIT_MIN
126 #define GC_OLDMALLOC_LIMIT_MIN (16 * 1024 * 1024 /* 16MB */)
127 #endif
128 #ifndef GC_OLDMALLOC_LIMIT_GROWTH_FACTOR
129 #define GC_OLDMALLOC_LIMIT_GROWTH_FACTOR 1.2
130 #endif
131 #ifndef GC_OLDMALLOC_LIMIT_MAX
132 #define GC_OLDMALLOC_LIMIT_MAX (128 * 1024 * 1024 /* 128MB */)
133 #endif
134
135 typedef struct {
136 unsigned int heap_init_slots;
137 unsigned int heap_free_slots;
138 double growth_factor;
139 unsigned int growth_max_slots;
140 double oldobject_limit_factor;
141 unsigned int malloc_limit_min;
142 unsigned int malloc_limit_max;
143 double malloc_limit_growth_factor;
144 unsigned int oldmalloc_limit_min;
145 unsigned int oldmalloc_limit_max;
146 double oldmalloc_limit_growth_factor;
147 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
148 VALUE gc_stress;
149 #endif
150 } ruby_gc_params_t;
151
152 static ruby_gc_params_t gc_params = {
153 GC_HEAP_INIT_SLOTS,
154 GC_HEAP_FREE_SLOTS,
155 GC_HEAP_GROWTH_FACTOR,
156 GC_HEAP_GROWTH_MAX_SLOTS,
157 GC_HEAP_OLDOBJECT_LIMIT_FACTOR,
158 GC_MALLOC_LIMIT_MIN,
159 GC_MALLOC_LIMIT_MAX,
160 GC_MALLOC_LIMIT_GROWTH_FACTOR,
161 GC_OLDMALLOC_LIMIT_MIN,
162 GC_OLDMALLOC_LIMIT_MAX,
163 GC_OLDMALLOC_LIMIT_GROWTH_FACTOR,
164 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
165 FALSE,
166 #endif
167 };
168
169 /* GC_DEBUG:
170 * enable to embed GC debugging information.
171 */
172 #ifndef GC_DEBUG
173 #define GC_DEBUG 0
174 #endif
175
176 #if USE_RGENGC
177 /* RGENGC_DEBUG:
178 * 1: basic information
179 * 2: remember set operation
180 * 3: mark
181 * 4:
182 * 5: sweep
183 */
184 #ifndef RGENGC_DEBUG
185 #define RGENGC_DEBUG 0
186 #endif
187
188 /* RGENGC_CHECK_MODE
189 * 0: disable all assertions
190 * 1: enable assertions (to debug RGenGC)
191 * 2: enable generational bits check (for debugging)
192 * 3: enable livness check
193 * 4: show all references
194 */
195 #ifndef RGENGC_CHECK_MODE
196 #define RGENGC_CHECK_MODE 0
197 #endif
198
199 /* RGENGC_PROFILE
200 * 0: disable RGenGC profiling
201 * 1: enable profiling for basic information
202 * 2: enable profiling for each types
203 */
204 #ifndef RGENGC_PROFILE
205 #define RGENGC_PROFILE 0
206 #endif
207
208 /* RGENGC_THREEGEN
209 * Enable/disable three gen GC.
210 * 0: Infant gen -> Old gen
211 * 1: Infant gen -> Young -> Old gen
212 */
213 #ifndef RGENGC_THREEGEN
214 #define RGENGC_THREEGEN 0
215 #endif
216
217 /* RGENGC_ESTIMATE_OLDMALLOC
218 * Enable/disable to estimate increase size of malloc'ed size by old objects.
219 * If estimation exceeds threashold, then will invoke full GC.
220 * 0: disable estimation.
221 * 1: enable estimation.
222 */
223 #ifndef RGENGC_ESTIMATE_OLDMALLOC
224 #define RGENGC_ESTIMATE_OLDMALLOC 1
225 #endif
226
227 #else /* USE_RGENGC */
228
229 #define RGENGC_DEBUG 0
230 #define RGENGC_CHECK_MODE 0
231 #define RGENGC_PROFILE 0
232 #define RGENGC_THREEGEN 0
233 #define RGENGC_ESTIMATE_OLDMALLOC 0
234
235 #endif /* USE_RGENGC */
236
237 #ifndef GC_PROFILE_MORE_DETAIL
238 #define GC_PROFILE_MORE_DETAIL 0
239 #endif
240 #ifndef GC_PROFILE_DETAIL_MEMORY
241 #define GC_PROFILE_DETAIL_MEMORY 0
242 #endif
243 #ifndef GC_ENABLE_LAZY_SWEEP
244 #define GC_ENABLE_LAZY_SWEEP 1
245 #endif
246 #ifndef CALC_EXACT_MALLOC_SIZE
247 #define CALC_EXACT_MALLOC_SIZE 0
248 #endif
249 #if defined(HAVE_MALLOC_USABLE_SIZE) || CALC_EXACT_MALLOC_SIZE > 0
250 #ifndef MALLOC_ALLOCATED_SIZE
251 #define MALLOC_ALLOCATED_SIZE 0
252 #endif
253 #else
254 #define MALLOC_ALLOCATED_SIZE 0
255 #endif
256 #ifndef MALLOC_ALLOCATED_SIZE_CHECK
257 #define MALLOC_ALLOCATED_SIZE_CHECK 0
258 #endif
259
260 typedef enum {
261 GPR_FLAG_NONE = 0x000,
262 /* major reason */
263 GPR_FLAG_MAJOR_BY_NOFREE = 0x001,
264 GPR_FLAG_MAJOR_BY_OLDGEN = 0x002,
265 GPR_FLAG_MAJOR_BY_SHADY = 0x004,
266 GPR_FLAG_MAJOR_BY_RESCAN = 0x008,
267 GPR_FLAG_MAJOR_BY_STRESS = 0x010,
268 #if RGENGC_ESTIMATE_OLDMALLOC
269 GPR_FLAG_MAJOR_BY_OLDMALLOC = 0x020,
270 #endif
271 GPR_FLAG_MAJOR_MASK = 0x0ff,
272
273 /* gc reason */
274 GPR_FLAG_NEWOBJ = 0x100,
275 GPR_FLAG_MALLOC = 0x200,
276 GPR_FLAG_METHOD = 0x400,
277 GPR_FLAG_CAPI = 0x800,
278 GPR_FLAG_STRESS = 0x1000,
279
280 /* others */
281 GPR_FLAG_IMMEDIATE_SWEEP = 0x2000,
282 GPR_FLAG_HAVE_FINALIZE = 0x4000
283 } gc_profile_record_flag;
284
285 typedef struct gc_profile_record {
286 int flags;
287
288 double gc_time;
289 double gc_invoke_time;
290
291 size_t heap_total_objects;
292 size_t heap_use_size;
293 size_t heap_total_size;
294
295 #if GC_PROFILE_MORE_DETAIL
296 double gc_mark_time;
297 double gc_sweep_time;
298
299 size_t heap_use_pages;
300 size_t heap_live_objects;
301 size_t heap_free_objects;
302
303 size_t allocate_increase;
304 size_t allocate_limit;
305
306 double prepare_time;
307 size_t removing_objects;
308 size_t empty_objects;
309 #if GC_PROFILE_DETAIL_MEMORY
310 long maxrss;
311 long minflt;
312 long majflt;
313 #endif
314 #endif
315 #if MALLOC_ALLOCATED_SIZE
316 size_t allocated_size;
317 #endif
318
319 #if RGENGC_PROFILE > 0
320 size_t old_objects;
321 size_t remembered_normal_objects;
322 size_t remembered_shady_objects;
323 #endif
324 } gc_profile_record;
325
326 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
327 #pragma pack(push, 1) /* magic for reducing sizeof(RVALUE): 24 -> 20 */
328 #endif
329
330 typedef struct RVALUE {
331 union {
332 struct {
333 VALUE flags; /* always 0 for freed obj */
334 struct RVALUE *next;
335 } free;
336 struct RBasic basic;
337 struct RObject object;
338 struct RClass klass;
339 struct RFloat flonum;
340 struct RString string;
341 struct RArray array;
342 struct RRegexp regexp;
343 struct RHash hash;
344 struct RData data;
345 struct RTypedData typeddata;
346 struct RStruct rstruct;
347 struct RBignum bignum;
348 struct RFile file;
349 struct RNode node;
350 struct RMatch match;
351 struct RRational rational;
352 struct RComplex complex;
353 struct {
354 struct RBasic basic;
355 VALUE v1;
356 VALUE v2;
357 VALUE v3;
358 } values;
359 } as;
360 #if GC_DEBUG
361 const char *file;
362 VALUE line;
363 #endif
364 } RVALUE;
365
366 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
367 #pragma pack(pop)
368 #endif
369
370 typedef uintptr_t bits_t;
371 enum {
372 BITS_SIZE = sizeof(bits_t),
373 BITS_BITLENGTH = ( BITS_SIZE * CHAR_BIT )
374 };
375
376 struct heap_page_header {
377 struct heap_page *page;
378 };
379
380 struct heap_page_body {
381 struct heap_page_header header;
382 /* char gap[]; */
383 /* RVALUE values[]; */
384 };
385
386 struct gc_list {
387 VALUE *varptr;
388 struct gc_list *next;
389 };
390
391 #define STACK_CHUNK_SIZE 500
392
393 typedef struct stack_chunk {
394 VALUE data[STACK_CHUNK_SIZE];
395 struct stack_chunk *next;
396 } stack_chunk_t;
397
398 typedef struct mark_stack {
399 stack_chunk_t *chunk;
400 stack_chunk_t *cache;
401 size_t index;
402 size_t limit;
403 size_t cache_size;
404 size_t unused_cache_size;
405 } mark_stack_t;
406
407 typedef struct rb_heap_struct {
408 struct heap_page *pages;
409 struct heap_page *free_pages;
410 struct heap_page *using_page;
411 struct heap_page *sweep_pages;
412 RVALUE *freelist;
413 size_t page_length; /* total page count in a heap */
414 size_t total_slots; /* total slot count (page_length * HEAP_OBJ_LIMIT) */
415 } rb_heap_t;
416
417 typedef struct rb_objspace {
418 struct {
419 size_t limit;
420 size_t increase;
421 #if MALLOC_ALLOCATED_SIZE
422 size_t allocated_size;
423 size_t allocations;
424 #endif
425 } malloc_params;
426
427 rb_heap_t eden_heap;
428 rb_heap_t tomb_heap; /* heap for zombies and ghosts */
429
430 struct {
431 struct heap_page **sorted;
432 size_t used;
433 size_t length;
434 RVALUE *range[2];
435
436 size_t limit;
437 size_t increment;
438
439 size_t swept_slots;
440 size_t min_free_slots;
441 size_t max_free_slots;
442
443 /* final */
444 size_t final_slots;
445 RVALUE *deferred_final;
446 } heap_pages;
447
448 struct {
449 int dont_gc;
450 int dont_lazy_sweep;
451 int during_gc;
452 rb_atomic_t finalizing;
453 } flags;
454 st_table *finalizer_table;
455 mark_stack_t mark_stack;
456 struct {
457 int run;
458 gc_profile_record *records;
459 gc_profile_record *current_record;
460 size_t next_index;
461 size_t size;
462
463 #if GC_PROFILE_MORE_DETAIL
464 double prepare_time;
465 #endif
466 double invoke_time;
467
468 #if USE_RGENGC
469 size_t minor_gc_count;
470 size_t major_gc_count;
471 #if RGENGC_PROFILE > 0
472 size_t generated_normal_object_count;
473 size_t generated_shady_object_count;
474 size_t shade_operation_count;
475 size_t promote_infant_count;
476 #if RGENGC_THREEGEN
477 size_t promote_young_count;
478 #endif
479 size_t remembered_normal_object_count;
480 size_t remembered_shady_object_count;
481
482 #if RGENGC_PROFILE >= 2
483 size_t generated_normal_object_count_types[RUBY_T_MASK];
484 size_t generated_shady_object_count_types[RUBY_T_MASK];
485 size_t shade_operation_count_types[RUBY_T_MASK];
486 size_t promote_infant_types[RUBY_T_MASK];
487 #if RGENGC_THREEGEN
488 size_t promote_young_types[RUBY_T_MASK];
489 #endif
490 size_t remembered_normal_object_count_types[RUBY_T_MASK];
491 size_t remembered_shady_object_count_types[RUBY_T_MASK];
492 #endif
493 #endif /* RGENGC_PROFILE */
494 #endif /* USE_RGENGC */
495
496 /* temporary profiling space */
497 double gc_sweep_start_time;
498 size_t total_allocated_object_num_at_gc_start;
499 size_t heap_used_at_gc_start;
500
501 /* basic statistics */
502 size_t count;
503 size_t total_allocated_object_num;
504 size_t total_freed_object_num;
505 int latest_gc_info;
506 } profile;
507 struct gc_list *global_list;
508 rb_event_flag_t hook_events; /* this place may be affinity with memory cache */
509 VALUE gc_stress;
510
511 struct mark_func_data_struct {
512 void *data;
513 void (*mark_func)(VALUE v, void *data);
514 } *mark_func_data;
515
516 #if USE_RGENGC
517 struct {
518 int during_minor_gc;
519 int parent_object_is_old;
520
521 int need_major_gc;
522
523 size_t last_major_gc;
524
525 size_t remembered_shady_object_count;
526 size_t remembered_shady_object_limit;
527 size_t old_object_count;
528 size_t old_object_limit;
529 #if RGENGC_THREEGEN
530 size_t young_object_count;
531 #endif
532
533 #if RGENGC_ESTIMATE_OLDMALLOC
534 size_t oldmalloc_increase;
535 size_t oldmalloc_increase_limit;
536 #endif
537
538 #if RGENGC_CHECK_MODE >= 2
539 struct st_table *allrefs_table;
540 size_t error_count;
541 #endif
542 } rgengc;
543 #endif /* USE_RGENGC */
544 } rb_objspace_t;
545
546
547 #ifndef HEAP_ALIGN_LOG
548 /* default tiny heap size: 16KB */
549 #define HEAP_ALIGN_LOG 14
550 #endif
551 #define CEILDIV(i, mod) (((i) + (mod) - 1)/(mod))
552 enum {
553 HEAP_ALIGN = (1UL << HEAP_ALIGN_LOG),
554 HEAP_ALIGN_MASK = (~(~0UL << HEAP_ALIGN_LOG)),
555 REQUIRED_SIZE_BY_MALLOC = (sizeof(size_t) * 5),
556 HEAP_SIZE = (HEAP_ALIGN - REQUIRED_SIZE_BY_MALLOC),
557 HEAP_OBJ_LIMIT = (unsigned int)((HEAP_SIZE - sizeof(struct heap_page_header))/sizeof(struct RVALUE)),
558 HEAP_BITMAP_LIMIT = CEILDIV(CEILDIV(HEAP_SIZE, sizeof(struct RVALUE)), BITS_BITLENGTH),
559 HEAP_BITMAP_SIZE = ( BITS_SIZE * HEAP_BITMAP_LIMIT),
560 HEAP_BITMAP_PLANES = USE_RGENGC ? 3 : 1 /* RGENGC: mark bits, rememberset bits and oldgen bits */
561 };
562
563 struct heap_page {
564 struct heap_page_body *body;
565 RVALUE *freelist;
566 RVALUE *start;
567 size_t final_slots;
568 size_t limit;
569 struct heap_page *next;
570 struct heap_page *prev;
571 struct heap_page *free_next;
572 rb_heap_t *heap;
573 int before_sweep;
574
575 bits_t mark_bits[HEAP_BITMAP_LIMIT];
576 #if USE_RGENGC
577 bits_t rememberset_bits[HEAP_BITMAP_LIMIT];
578 bits_t oldgen_bits[HEAP_BITMAP_LIMIT];
579 #endif
580 };
581
582 #define GET_PAGE_BODY(x) ((struct heap_page_body *)((bits_t)(x) & ~(HEAP_ALIGN_MASK)))
583 #define GET_PAGE_HEADER(x) (&GET_PAGE_BODY(x)->header)
584 #define GET_HEAP_PAGE(x) (GET_PAGE_HEADER(x)->page)
585 #define GET_HEAP_MARK_BITS(x) (&GET_HEAP_PAGE(x)->mark_bits[0])
586 #define GET_HEAP_REMEMBERSET_BITS(x) (&GET_HEAP_PAGE(x)->rememberset_bits[0])
587 #define GET_HEAP_OLDGEN_BITS(x) (&GET_HEAP_PAGE(x)->oldgen_bits[0])
588 #define NUM_IN_PAGE(p) (((bits_t)(p) & HEAP_ALIGN_MASK)/sizeof(RVALUE))
589 #define BITMAP_INDEX(p) (NUM_IN_PAGE(p) / BITS_BITLENGTH )
590 #define BITMAP_OFFSET(p) (NUM_IN_PAGE(p) & (BITS_BITLENGTH-1))
591 #define BITMAP_BIT(p) ((bits_t)1 << BITMAP_OFFSET(p))
592 /* Bitmap Operations */
593 #define MARKED_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] & BITMAP_BIT(p))
594 #define MARK_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] = (bits)[BITMAP_INDEX(p)] | BITMAP_BIT(p))
595 #define CLEAR_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] = (bits)[BITMAP_INDEX(p)] & ~BITMAP_BIT(p))
596
597 /* Aliases */
598 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
599 #define rb_objspace (*GET_VM()->objspace)
600 #define ruby_initial_gc_stress gc_params.gc_stress
601 VALUE *ruby_initial_gc_stress_ptr = &ruby_initial_gc_stress;
602 #else
603 static rb_objspace_t rb_objspace = {{GC_MALLOC_LIMIT_MIN}};
604 VALUE *ruby_initial_gc_stress_ptr = &rb_objspace.gc_stress;
605 #endif
606
607 #define malloc_limit objspace->malloc_params.limit
608 #define malloc_increase objspace->malloc_params.increase
609 #define malloc_allocated_size objspace->malloc_params.allocated_size
610 #define heap_pages_sorted objspace->heap_pages.sorted
611 #define heap_pages_used objspace->heap_pages.used
612 #define heap_pages_length objspace->heap_pages.length
613 #define heap_pages_lomem objspace->heap_pages.range[0]
614 #define heap_pages_himem objspace->heap_pages.range[1]
615 #define heap_pages_swept_slots objspace->heap_pages.swept_slots
616 #define heap_pages_increment objspace->heap_pages.increment
617 #define heap_pages_min_free_slots objspace->heap_pages.min_free_slots
618 #define heap_pages_max_free_slots objspace->heap_pages.max_free_slots
619 #define heap_pages_final_slots objspace->heap_pages.final_slots
620 #define heap_pages_deferred_final objspace->heap_pages.deferred_final
621 #define heap_eden (&objspace->eden_heap)
622 #define heap_tomb (&objspace->tomb_heap)
623 #define dont_gc objspace->flags.dont_gc
624 #define during_gc objspace->flags.during_gc
625 #define finalizing objspace->flags.finalizing
626 #define finalizer_table objspace->finalizer_table
627 #define global_List objspace->global_list
628 #define ruby_gc_stress objspace->gc_stress
629 #define monitor_level objspace->rgengc.monitor_level
630 #define monitored_object_table objspace->rgengc.monitored_object_table
631
632 #define is_lazy_sweeping(heap) ((heap)->sweep_pages != 0)
633 #if SIZEOF_LONG == SIZEOF_VOIDP
634 # define nonspecial_obj_id(obj) (VALUE)((SIGNED_VALUE)(obj)|FIXNUM_FLAG)
635 # define obj_id_to_ref(objid) ((objid) ^ FIXNUM_FLAG) /* unset FIXNUM_FLAG */
636 #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
637 # define nonspecial_obj_id(obj) LL2NUM((SIGNED_VALUE)(obj) / 2)
638 # define obj_id_to_ref(objid) (FIXNUM_P(objid) ? \
639 ((objid) ^ FIXNUM_FLAG) : (NUM2PTR(objid) << 1))
640 #else
641 # error not supported
642 #endif
643
644 #define RANY(o) ((RVALUE*)(o))
645
646 #define nomem_error GET_VM()->special_exceptions[ruby_error_nomemory]
647
648 int ruby_gc_debug_indent = 0;
649 VALUE rb_mGC;
650 int ruby_disable_gc_stress = 0;
651
652 void rb_gcdebug_print_obj_condition(VALUE obj);
653
654 static void rb_objspace_call_finalizer(rb_objspace_t *objspace);
655 static VALUE define_final0(VALUE obj, VALUE block);
656
657 static void negative_size_allocation_error(const char *);
658 static void *aligned_malloc(size_t, size_t);
659 static void aligned_free(void *);
660
661 static void init_mark_stack(mark_stack_t *stack);
662
663 static VALUE lazy_sweep_enable(void);
664 static int ready_to_gc(rb_objspace_t *objspace);
665 static int heap_ready_to_gc(rb_objspace_t *objspace, rb_heap_t *heap);
666 static int garbage_collect(rb_objspace_t *, int full_mark, int immediate_sweep, int reason);
667 static int garbage_collect_body(rb_objspace_t *, int full_mark, int immediate_sweep, int reason);
668 static int gc_heap_lazy_sweep(rb_objspace_t *objspace, rb_heap_t *heap);
669 static void gc_rest_sweep(rb_objspace_t *objspace);
670 static void gc_heap_rest_sweep(rb_objspace_t *objspace, rb_heap_t *heap);
671
672 static void gc_mark_stacked_objects(rb_objspace_t *);
673 static void gc_mark(rb_objspace_t *objspace, VALUE ptr);
674 static void gc_mark_maybe(rb_objspace_t *objspace, VALUE ptr);
675 static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr);
676
677 static size_t obj_memsize_of(VALUE obj, int use_tdata);
678
679 static double getrusage_time(void);
680 static inline void gc_prof_setup_new_record(rb_objspace_t *objspace, int reason);
681 static inline void gc_prof_timer_start(rb_objspace_t *);
682 static inline void gc_prof_timer_stop(rb_objspace_t *);
683 static inline void gc_prof_mark_timer_start(rb_objspace_t *);
684 static inline void gc_prof_mark_timer_stop(rb_objspace_t *);
685 static inline void gc_prof_sweep_timer_start(rb_objspace_t *);
686 static inline void gc_prof_sweep_timer_stop(rb_objspace_t *);
687 static inline void gc_prof_set_malloc_info(rb_objspace_t *);
688 static inline void gc_prof_set_heap_info(rb_objspace_t *);
689
690 #define gc_prof_record(objspace) (objspace)->profile.current_record
691 #define gc_prof_enabled(objspace) ((objspace)->profile.run && (objspace)->profile.current_record)
692
693 #define rgengc_report if (RGENGC_DEBUG) rgengc_report_body
694 static void rgengc_report_body(int level, rb_objspace_t *objspace, const char *fmt, ...);
695 static const char * type_name(int type, VALUE obj);
696 static const char *obj_type_name(VALUE obj);
697
698 #if USE_RGENGC
699 static int rgengc_remembered(rb_objspace_t *objspace, VALUE obj);
700 static int rgengc_remember(rb_objspace_t *objspace, VALUE obj);
701 static void rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace, rb_heap_t *heap);
702 static void rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap);
703
704 #define FL_TEST2(x,f) ((RGENGC_CHECK_MODE && SPECIAL_CONST_P(x)) ? (rb_bug("FL_TEST2: SPECIAL_CONST"), 0) : FL_TEST_RAW((x),(f)) != 0)
705 #define FL_SET2(x,f) do {if (RGENGC_CHECK_MODE && SPECIAL_CONST_P(x)) rb_bug("FL_SET2: SPECIAL_CONST"); RBASIC(x)->flags |= (f);} while (0)
706 #define FL_UNSET2(x,f) do {if (RGENGC_CHECK_MODE && SPECIAL_CONST_P(x)) rb_bug("FL_UNSET2: SPECIAL_CONST"); RBASIC(x)->flags &= ~(f);} while (0)
707
708 #define RVALUE_WB_PROTECTED_RAW(obj) FL_TEST2((obj), FL_WB_PROTECTED)
709 #define RVALUE_WB_PROTECTED(obj) RVALUE_WB_PROTECTED_RAW(check_gen_consistency((VALUE)obj))
710
711 #define RVALUE_OLDGEN_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_OLDGEN_BITS(obj), (obj))
712
713 static inline int is_pointer_to_heap(rb_objspace_t *objspace, void *ptr);
714 static inline int gc_marked(rb_objspace_t *objspace, VALUE ptr);
715
716 static inline VALUE
717 check_gen_consistency(VALUE obj)
718 {
719 if (RGENGC_CHECK_MODE > 0) {
720 int old_flag = RVALUE_OLDGEN_BITMAP(obj) != 0;
721 int promoted_flag = FL_TEST2(obj, FL_PROMOTED);
722 rb_objspace_t *objspace = &rb_objspace;
723
724 obj_memsize_of((VALUE)obj, FALSE);
725
726 if (!is_pointer_to_heap(objspace, (void *)obj)) {
727 rb_bug("check_gen_consistency: %p (%s) is not Ruby object.", (void *)obj, obj_type_name(obj));
728 }
729
730 if (promoted_flag) {
731 if (!RVALUE_WB_PROTECTED_RAW(obj)) {
732 const char *type = old_flag ? "old" : "young";
733 rb_bug("check_gen_consistency: %p (%s) is not WB protected, but %s object.", (void *)obj, obj_type_name(obj), type);
734 }
735
736 #if !RGENGC_THREEGEN
737 if (!old_flag) {
738 rb_bug("check_gen_consistency: %p (%s) is not infant, but is not old (on 2gen).", (void *)obj, obj_type_name(obj));
739 }
740 #endif
741
742 if (old_flag && objspace->rgengc.during_minor_gc && !gc_marked(objspace, obj)) {
743 rb_bug("check_gen_consistency: %p (%s) is old, but is not marked while minor marking.", (void *)obj, obj_type_name(obj));
744 }
745 }
746 else {
747 if (old_flag) {
748 rb_bug("check_gen_consistency: %p (%s) is not infant, but is old.", (void *)obj, obj_type_name(obj));
749 }
750 }
751 }
752 return obj;
753 }
754
755 static inline VALUE
756 RVALUE_INFANT_P(VALUE obj)
757 {
758 check_gen_consistency(obj);
759 return !FL_TEST2(obj, FL_PROMOTED);
760 }
761
762 static inline VALUE
763 RVALUE_OLD_BITMAP_P(VALUE obj)
764 {
765 check_gen_consistency(obj);
766 return (RVALUE_OLDGEN_BITMAP(obj) != 0);
767 }
768
769 static inline VALUE
770 RVALUE_OLD_P(VALUE obj)
771 {
772 check_gen_consistency(obj);
773 #if RGENGC_THREEGEN
774 return FL_TEST2(obj, FL_PROMOTED) && RVALUE_OLD_BITMAP_P(obj);
775 #else
776 return FL_TEST2(obj, FL_PROMOTED);
777 #endif
778 }
779
780 static inline VALUE
781 RVALUE_PROMOTED_P(VALUE obj)
782 {
783 check_gen_consistency(obj);
784 return FL_TEST2(obj, FL_PROMOTED);
785 }
786
787 static inline void
788 RVALUE_PROMOTE_INFANT(VALUE obj)
789 {
790 check_gen_consistency(obj);
791 if (RGENGC_CHECK_MODE && !RVALUE_INFANT_P(obj)) rb_bug("RVALUE_PROMOTE_INFANT: %p (%s) is not infant object.", (void *)obj, obj_type_name(obj));
792 FL_SET2(obj, FL_PROMOTED);
793 #if !RGENGC_THREEGEN
794 MARK_IN_BITMAP(GET_HEAP_OLDGEN_BITS(obj), obj);
795 #endif
796 check_gen_consistency(obj);
797
798 #if RGENGC_PROFILE >= 1
799 {
800 rb_objspace_t *objspace = &rb_objspace;
801 objspace->profile.promote_infant_count++;
802
803 #if RGENGC_PROFILE >= 2
804 objspace->profile.promote_infant_types[BUILTIN_TYPE(obj)]++;
805 #endif
806 }
807 #endif
808 }
809
810 #if RGENGC_THREEGEN
811 /*
812 * Two gen: Infant -> Old.
813 * Three gen: Infant -> Young -> Old.
814 */
815 static inline VALUE
816 RVALUE_YOUNG_P(VALUE obj)
817 {
818 check_gen_consistency(obj);
819 return FL_TEST2(obj, FL_PROMOTED) && (RVALUE_OLDGEN_BITMAP(obj) == 0);
820 }
821
822 static inline void
823 RVALUE_PROMOTE_YOUNG(VALUE obj)
824 {
825 check_gen_consistency(obj);
826 if (RGENGC_CHECK_MODE && !RVALUE_YOUNG_P(obj)) rb_bug("RVALUE_PROMOTE_YOUNG: %p (%s) is not young object.", (void *)obj, obj_type_name(obj));
827 MARK_IN_BITMAP(GET_HEAP_OLDGEN_BITS(obj), obj);
828 check_gen_consistency(obj);
829
830 #if RGENGC_PROFILE >= 1
831 {
832 rb_objspace_t *objspace = &rb_objspace;
833 objspace->profile.promote_young_count++;
834 #if RGENGC_PROFILE >= 2
835 objspace->profile.promote_young_types[BUILTIN_TYPE(obj)]++;
836 #endif
837 }
838 #endif
839 }
840
841 static inline void
842 RVALUE_DEMOTE_FROM_YOUNG(VALUE obj)
843 {
844 if (RGENGC_CHECK_MODE && !RVALUE_YOUNG_P(obj))
845 rb_bug("RVALUE_DEMOTE_FROM_YOUNG: %p (%s) is not young object.", (void *)obj, obj_type_name(obj));
846
847 check_gen_consistency(obj);
848 FL_UNSET2(obj, FL_PROMOTED);
849 check_gen_consistency(obj);
850 }
851 #endif
852
853 static inline void
854 RVALUE_DEMOTE_FROM_OLD(VALUE obj)
855 {
856 if (RGENGC_CHECK_MODE && !RVALUE_OLD_P(obj))
857 rb_bug("RVALUE_DEMOTE_FROM_OLD: %p (%s) is not old object.", (void *)obj, obj_type_name(obj));
858
859 check_gen_consistency(obj);
860 FL_UNSET2(obj, FL_PROMOTED);
861 CLEAR_IN_BITMAP(GET_HEAP_OLDGEN_BITS(obj), obj);
862 check_gen_consistency(obj);
863 }
864
865 #endif /* USE_RGENGC */
866
867 /*
868 --------------------------- ObjectSpace -----------------------------
869 */
870
871 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
872 rb_objspace_t *
873 rb_objspace_alloc(void)
874 {
875 rb_objspace_t *objspace = malloc(sizeof(rb_objspace_t));
876 memset(objspace, 0, sizeof(*objspace));
877 ruby_gc_stress = ruby_initial_gc_stress;
878
879 malloc_limit = gc_params.malloc_limit_min;
880
881 return objspace;
882 }
883 #endif
884
885 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
886 static void free_stack_chunks(mark_stack_t *);
887 static void heap_page_free(rb_objspace_t *objspace, struct heap_page *page);
888
889 void
890 rb_objspace_free(rb_objspace_t *objspace)
891 {
892 gc_rest_sweep(objspace);
893
894 if (objspace->profile.records) {
895 free(objspace->profile.records);
896 objspace->profile.records = 0;
897 }
898
899 if (global_List) {
900 struct gc_list *list, *next;
901 for (list = global_List; list; list = next) {
902 next = list->next;
903 xfree(list);
904 }
905 }
906 if (heap_pages_sorted) {
907 size_t i;
908 for (i = 0; i < heap_pages_used; ++i) {
909 heap_page_free(objspace, heap_pages_sorted[i]);
910 }
911 free(heap_pages_sorted);
912 heap_pages_used = 0;
913 heap_pages_length = 0;
914 heap_pages_lomem = 0;
915 heap_pages_himem = 0;
916
917 objspace->eden_heap.page_length = 0;
918 objspace->eden_heap.total_slots = 0;
919 objspace->eden_heap.pages = NULL;
920 }
921 free_stack_chunks(&objspace->mark_stack);
922 free(objspace);
923 }
924 #endif
925
926 static void
927 heap_pages_expand_sorted(rb_objspace_t *objspace)
928 {
929 size_t next_length = heap_pages_increment;
930 next_length += heap_eden->page_length;
931 next_length += heap_tomb->page_length;
932
933 if (next_length > heap_pages_length) {
934 struct heap_page **sorted;
935 size_t size = next_length * sizeof(struct heap_page *);
936
937 rgengc_report(3, objspace, "heap_pages_expand_sorted: next_length: %d, size: %d\n", (int)next_length, (int)size);
938
939 if (heap_pages_length > 0) {
940 sorted = (struct heap_page **)realloc(heap_pages_sorted, size);
941 if (sorted) heap_pages_sorted = sorted;
942 }
943 else {
944 sorted = heap_pages_sorted = (struct heap_page **)malloc(size);
945 }
946
947 if (sorted == 0) {
948 during_gc = 0;
949 rb_memerror();
950 }
951
952 heap_pages_length = next_length;
953 }
954 }
955
956 static inline void
957 heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
958 {
959 RVALUE *p = (RVALUE *)obj;
960 p->as.free.flags = 0;
961 p->as.free.next = page->freelist;
962 page->freelist = p;
963 rgengc_report(3, objspace, "heap_page_add_freeobj: %p (%s) is added to freelist\n", p, obj_type_name(obj));
964 }
965
966 static inline void
967 heap_add_freepage(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
968 {
969 if (page->freelist) {
970 page->free_next = heap->free_pages;
971 heap->free_pages = page;
972 }
973 }
974
975 static void
976 heap_unlink_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
977 {
978 if (page->prev) page->prev->next = page->next;
979 if (page->next) page->next->prev = page->prev;
980 if (heap->pages == page) heap->pages = page->next;
981 page->prev = NULL;
982 page->next = NULL;
983 page->heap = NULL;
984 heap->page_length--;
985 heap->total_slots -= page->limit;
986 }
987
988 static void
989 heap_page_free(rb_objspace_t *objspace, struct heap_page *page)
990 {
991 heap_pages_used--;
992 aligned_free(page->body);
993 free(page);
994 }
995
996 static void
997 heap_pages_free_unused_pages(rb_objspace_t *objspace)
998 {
999 size_t i, j;
1000
1001 for (i = j = 1; j < heap_pages_used; i++) {
1002 struct heap_page *page = heap_pages_sorted[i];
1003
1004 if (page->heap == heap_tomb && page->final_slots == 0) {
1005 if (heap_pages_swept_slots - page->limit > heap_pages_max_free_slots) {
1006 if (0) fprintf(stderr, "heap_pages_free_unused_pages: %d free page %p, heap_pages_swept_slots: %d, heap_pages_max_free_slots: %d\n",
1007 (int)i, page, (int)heap_pages_swept_slots, (int)heap_pages_max_free_slots);
1008 heap_pages_swept_slots -= page->limit;
1009 heap_unlink_page(objspace, heap_tomb, page);
1010 heap_page_free(objspace, page);
1011 continue;
1012 }
1013 else {
1014 /* fprintf(stderr, "heap_pages_free_unused_pages: remain!!\n"); */
1015 }
1016 }
1017 if (i != j) {
1018 heap_pages_sorted[j] = page;
1019 }
1020 j++;
1021 }
1022 assert(j == heap_pages_used);
1023 }
1024
1025 static struct heap_page *
1026 heap_page_allocate(rb_objspace_t *objspace)
1027 {
1028 RVALUE *start, *end, *p;
1029 struct heap_page *page;
1030 struct heap_page_body *page_body = 0;
1031 size_t hi, lo, mid;
1032 size_t limit = HEAP_OBJ_LIMIT;
1033
1034 /* assign heap_page body (contains heap_page_header and RVALUEs) */
1035 page_body = (struct heap_page_body *)aligned_malloc(HEAP_ALIGN, HEAP_SIZE);
1036 if (page_body == 0) {
1037 during_gc = 0;
1038 rb_memerror();
1039 }
1040
1041 /* assign heap_page entry */
1042 page = (struct heap_page *)malloc(sizeof(struct heap_page));
1043 if (page == 0) {
1044 aligned_free(page_body);
1045 during_gc = 0;
1046 rb_memerror();
1047 }
1048 MEMZERO((void*)page, struct heap_page, 1);
1049
1050 page->body = page_body;
1051
1052 /* setup heap_pages_sorted */
1053 lo = 0;
1054 hi = heap_pages_used;
1055 while (lo < hi) {
1056 struct heap_page *mid_page;
1057
1058 mid = (lo + hi) / 2;
1059 mid_page = heap_pages_sorted[mid];
1060 if (mid_page->body < page_body) {
1061 lo = mid + 1;
1062 }
1063 else if (mid_page->body > page_body) {
1064 hi = mid;
1065 }
1066 else {
1067 rb_bug("same heap page is allocated: %p at %"PRIuVALUE, (void *)page_body, (VALUE)mid);
1068 }
1069 }
1070 if (hi < heap_pages_used) {
1071 MEMMOVE(&heap_pages_sorted[hi+1], &heap_pages_sorted[hi], struct heap_page_header*, heap_pages_used - hi);
1072 }
1073
1074 heap_pages_sorted[hi] = page;
1075
1076 heap_pages_used++;
1077 assert(heap_pages_used <= heap_pages_length);
1078
1079 /* adjust obj_limit (object number available in this page) */
1080 start = (RVALUE*)((VALUE)page_body + sizeof(struct heap_page_header));
1081 if ((VALUE)start % sizeof(RVALUE) != 0) {
1082 int delta = (int)(sizeof(RVALUE) - ((VALUE)start % sizeof(RVALUE)));
1083 start = (RVALUE*)((VALUE)start + delta);
1084 limit = (HEAP_SIZE - (size_t)((VALUE)start - (VALUE)page_body))/sizeof(RVALUE);
1085 }
1086 end = start + limit;
1087
1088 if (heap_pages_lomem == 0 || heap_pages_lomem > start) heap_pages_lomem = start;
1089 if (heap_pages_himem < end) heap_pages_himem = end;
1090
1091 page->start = start;
1092 page->limit = limit;
1093 page_body->header.page = page;
1094
1095 for (p = start; p != end; p++) {
1096 rgengc_report(3, objspace, "assign_heap_page: %p is added to freelist\n");
1097 heap_page_add_freeobj(objspace, page, (VALUE)p);
1098 }
1099
1100 return page;
1101 }
1102
1103 static struct heap_page *
1104 heap_page_resurrect(rb_objspace_t *objspace)
1105 {
1106 struct heap_page *page;
1107
1108 if ((page = heap_tomb->pages) != NULL) {
1109 heap_unlink_page(objspace, heap_tomb, page);
1110 return page;
1111 }
1112 return NULL;
1113 }
1114
1115 static struct heap_page *
1116 heap_page_create(rb_objspace_t *objspace)
1117 {
1118 struct heap_page *page = heap_page_resurrect(objspace);
1119 const char *method = "recycle";
1120 if (page == NULL) {
1121 page = heap_page_allocate(objspace);
1122 method = "allocate";
1123 }
1124 if (0) fprintf(stderr, "heap_page_create: %s - %p, heap_pages_used: %d, heap_pages_used: %d, tomb->page_length: %d\n",
1125 method, page, (int)heap_pages_length, (int)heap_pages_used, (int)heap_tomb->page_length);
1126 return page;
1127 }
1128
1129 static void
1130 heap_add_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
1131 {
1132 page->heap = heap;
1133 page->next = heap->pages;
1134 if (heap->pages) heap->pages->prev = page;
1135 heap->pages = page;
1136 heap->page_length++;
1137 heap->total_slots += page->limit;
1138 }
1139
1140 static void
1141 heap_assign_page(rb_objspace_t *objspace, rb_heap_t *heap)
1142 {
1143 struct heap_page *page = heap_page_create(objspace);
1144 heap_add_page(objspace, heap, page);
1145 heap_add_freepage(objspace, heap, page);
1146 }
1147
1148 static void
1149 heap_add_pages(rb_objspace_t *objspace, rb_heap_t *heap, size_t add)
1150 {
1151 size_t i;
1152
1153 heap_pages_increment = add;
1154 heap_pages_expand_sorted(objspace);
1155 for (i = 0; i < add; i++) {
1156 heap_assign_page(objspace, heap);
1157 }
1158 heap_pages_increment = 0;
1159 }
1160
1161 static void
1162 heap_set_increment(rb_objspace_t *objspace, size_t minimum_limit)
1163 {
1164 size_t used = heap_pages_used - heap_tomb->page_length;
1165 size_t next_used_limit = (size_t)(used * gc_params.growth_factor);
1166 if (gc_params.growth_max_slots > 0) {
1167 size_t max_used_limit = (size_t)(used + gc_params.growth_max_slots/HEAP_OBJ_LIMIT);
1168 if (next_used_limit > max_used_limit) next_used_limit = max_used_limit;
1169 }
1170 if (next_used_limit == heap_pages_used) next_used_limit++;
1171
1172 if (next_used_limit < minimum_limit) {
1173 next_used_limit = minimum_limit;
1174 }
1175
1176 heap_pages_increment = next_used_limit - used;
1177 heap_pages_expand_sorted(objspace);
1178
1179 if (0) fprintf(stderr, "heap_set_increment: heap_pages_length: %d, heap_pages_used: %d, heap_pages_increment: %d, next_used_limit: %d\n",
1180 (int)heap_pages_length, (int)heap_pages_used, (int)heap_pages_increment, (int)next_used_limit);
1181 }
1182
1183 static int
1184 heap_increment(rb_objspace_t *objspace, rb_heap_t *heap)
1185 {
1186 rgengc_report(5, objspace, "heap_increment: heap_pages_length: %d, heap_pages_inc: %d, heap->page_length: %d\n",
1187 (int)heap_pages_length, (int)heap_pages_increment, (int)heap->page_length);
1188
1189 if (heap_pages_increment > 0) {
1190 heap_pages_increment--;
1191 heap_assign_page(objspace, heap);
1192 return TRUE;
1193 }
1194 return FALSE;
1195 }
1196
1197 static struct heap_page *
1198 heap_prepare_freepage(rb_objspace_t *objspace, rb_heap_t *heap)
1199 {
1200 if (!GC_ENABLE_LAZY_SWEEP && objspace->flags.dont_lazy_sweep) {
1201 if (heap_increment(objspace, heap) == 0 &&
1202 garbage_collect(objspace, FALSE, TRUE, GPR_FLAG_NEWOBJ) == 0) {
1203 goto err;
1204 }
1205 goto ok;
1206 }
1207
1208 if (!heap_ready_to_gc(objspace, heap)) return heap->free_pages;
1209
1210 during_gc++;
1211
1212 if ((is_lazy_sweeping(heap) && gc_heap_lazy_sweep(objspace, heap)) || heap_increment(objspace, heap)) {
1213 goto ok;
1214 }
1215
1216 #if GC_PROFILE_MORE_DETAIL
1217 objspace->profile.prepare_time = 0;
1218 #endif
1219 if (garbage_collect_body(objspace, 0, 0, GPR_FLAG_NEWOBJ) == 0) {
1220 err:
1221 during_gc = 0;
1222 rb_memerror();
1223 }
1224 ok:
1225 during_gc = 0;
1226 return heap->free_pages;
1227 }
1228
1229 static RVALUE *
1230 heap_get_freeobj_from_next_freepage(rb_objspace_t *objspace, rb_heap_t *heap)
1231 {
1232 struct heap_page *page;
1233 RVALUE *p;
1234
1235 page = heap->free_pages;
1236 while (page == NULL) {
1237 page = heap_prepare_freepage(objspace, heap);
1238 }
1239 heap->free_pages = page->free_next;
1240 heap->using_page = page;
1241
1242 p = page->freelist;
1243 page->freelist = NULL;
1244
1245 return p;
1246 }
1247
1248 static inline VALUE
1249 heap_get_freeobj(rb_objspace_t *objspace, rb_heap_t *heap)
1250 {
1251 RVALUE *p = heap->freelist;
1252
1253 while (1) {
1254 if (p) {
1255 heap->freelist = p->as.free.next;
1256 return (VALUE)p;
1257 }
1258 else {
1259 p = heap_get_freeobj_from_next_freepage(objspace, heap);
1260 }
1261 }
1262 }
1263
1264 void
1265 rb_objspace_set_event_hook(const rb_event_flag_t event)
1266 {
1267 rb_objspace_t *objspace = &rb_objspace;
1268 objspace->hook_events = event & RUBY_INTERNAL_EVENT_OBJSPACE_MASK;
1269 }
1270
1271 static void
1272 gc_event_hook_body(rb_objspace_t *objspace, const rb_event_flag_t event, VALUE data)
1273 {
1274 rb_thread_t *th = GET_THREAD();
1275 EXEC_EVENT_HOOK(th, event, th->cfp->self, 0, 0, data);
1276 }
1277
1278 #define gc_event_hook(objspace, event, data) do { \
1279 if (UNLIKELY((objspace)->hook_events & (event))) { \
1280 gc_event_hook_body((objspace), (event), (data)); \
1281 } \
1282 } while (0)
1283
1284 static VALUE
1285 newobj_of(VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3)
1286 {
1287 rb_objspace_t *objspace = &rb_objspace;
1288 VALUE obj;
1289
1290 if (UNLIKELY(during_gc)) {
1291 dont_gc = 1;
1292 during_gc = 0;
1293 rb_bug("object allocation during garbage collection phase");
1294 }
1295
1296 if (UNLIKELY(ruby_gc_stress && !ruby_disable_gc_stress)) {
1297 if (!garbage_collect(objspace, FALSE, FALSE, GPR_FLAG_NEWOBJ)) {
1298 during_gc = 0;
1299 rb_memerror();
1300 }
1301 }
1302
1303 obj = heap_get_freeobj(objspace, heap_eden);
1304
1305 /* OBJSETUP */
1306 RBASIC(obj)->flags = flags;
1307 RBASIC_SET_CLASS_RAW(obj, klass);
1308 if (rb_safe_level() >= 3) FL_SET((obj), FL_TAINT);
1309 RANY(obj)->as.values.v1 = v1;
1310 RANY(obj)->as.values.v2 = v2;
1311 RANY(obj)->as.values.v3 = v3;
1312
1313 #if GC_DEBUG
1314 RANY(obj)->file = rb_sourcefile();
1315 RANY(obj)->line = rb_sourceline();
1316 assert(!SPECIAL_CONST_P(obj)); /* check alignment */
1317 #endif
1318
1319 #if RGENGC_PROFILE
1320 if (flags & FL_WB_PROTECTED) {
1321 objspace->profile.generated_normal_object_count++;
1322 #if RGENGC_PROFILE >= 2
1323 objspace->profile.generated_normal_object_count_types[BUILTIN_TYPE(obj)]++;
1324 #endif
1325 }
1326 else {
1327 objspace->profile.generated_shady_object_count++;
1328 #if RGENGC_PROFILE >= 2
1329 objspace->profile.generated_shady_object_count_types[BUILTIN_TYPE(obj)]++;
1330 #endif
1331 }
1332 #endif
1333
1334 rgengc_report(5, objspace, "newobj: %p (%s)\n", (void *)obj, obj_type_name(obj));
1335
1336 #if USE_RGENGC && RGENGC_CHECK_MODE
1337 if (RVALUE_PROMOTED_P(obj)) rb_bug("newobj: %p (%s) is promoted.\n", (void *)obj, obj_type_name(obj));
1338 if (rgengc_remembered(objspace, (VALUE)obj)) rb_bug("newobj: %p (%s) is remembered.\n", (void *)obj, obj_type_name(obj));
1339 #endif
1340
1341 objspace->profile.total_allocated_object_num++;
1342 gc_event_hook(objspace, RUBY_INTERNAL_EVENT_NEWOBJ, obj);
1343
1344 return obj;
1345 }
1346
1347 VALUE
1348 rb_newobj(void)
1349 {
1350 return newobj_of(0, T_NONE, 0, 0, 0);
1351 }
1352
1353 VALUE
1354 rb_newobj_of(VALUE klass, VALUE flags)
1355 {
1356 return newobj_of(klass, flags, 0, 0, 0);
1357 }
1358
1359 NODE*
1360 rb_node_newnode(enum node_type type, VALUE a0, VALUE a1, VALUE a2)
1361 {
1362 VALUE flags = (RGENGC_WB_PROTECTED_NODE_CREF && type == NODE_CREF ? FL_WB_PROTECTED : 0);
1363 NODE *n = (NODE *)newobj_of(0, T_NODE | flags, a0, a1, a2);
1364 nd_set_type(n, type);
1365 return n;
1366 }
1367
1368 VALUE
1369 rb_data_object_alloc(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
1370 {
1371 if (klass) Check_Type(klass, T_CLASS);
1372 return newobj_of(klass, T_DATA, (VALUE)dmark, (VALUE)dfree, (VALUE)datap);
1373 }
1374
1375 VALUE
1376 rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *type)
1377 {
1378 if (klass) Check_Type(klass, T_CLASS);
1379 return newobj_of(klass, T_DATA | (type->flags & ~T_MASK), (VALUE)type, (VALUE)1, (VALUE)datap);
1380 }
1381
1382 size_t
1383 rb_objspace_data_type_memsize(VALUE obj)
1384 {
1385 if (RTYPEDDATA_P(obj) && RTYPEDDATA_TYPE(obj)->function.dsize) {
1386 return RTYPEDDATA_TYPE(obj)->function.dsize(RTYPEDDATA_DATA(obj));
1387 }
1388 else {
1389 return 0;
1390 }
1391 }
1392
1393 const char *
1394 rb_objspace_data_type_name(VALUE obj)
1395 {
1396 if (RTYPEDDATA_P(obj)) {
1397 return RTYPEDDATA_TYPE(obj)->wrap_struct_name;
1398 }
1399 else {
1400 return 0;
1401 }
1402 }
1403
1404 static inline int
1405 is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
1406 {
1407 register RVALUE *p = RANY(ptr);
1408 register struct heap_page *page;
1409 register size_t hi, lo, mid;
1410
1411 if (p < heap_pages_lomem || p > heap_pages_himem) return FALSE;
1412 if ((VALUE)p % sizeof(RVALUE) != 0) return FALSE;
1413
1414 /* check if p looks like a pointer using bsearch*/
1415 lo = 0;
1416 hi = heap_pages_used;
1417 while (lo < hi) {
1418 mid = (lo + hi) / 2;
1419 page = heap_pages_sorted[mid];
1420 if (page->start <= p) {
1421 if (p < page->start + page->limit) {
1422 return TRUE;
1423 }
1424 lo = mid + 1;
1425 }
1426 else {
1427 hi = mid;
1428 }
1429 }
1430 return FALSE;
1431 }
1432
1433 static int
1434 free_method_entry_i(ID key, rb_method_entry_t *me, st_data_t data)
1435 {
1436 if (!me->mark) {
1437 rb_free_method_entry(me);
1438 }
1439 return ST_CONTINUE;
1440 }
1441
1442 void
1443 rb_free_m_tbl(st_table *tbl)
1444 {
1445 st_foreach(tbl, free_method_entry_i, 0);
1446 st_free_table(tbl);
1447 }
1448
1449 void
1450 rb_free_m_tbl_wrapper(struct method_table_wrapper *wrapper)
1451 {
1452 if (wrapper->tbl) {
1453 rb_free_m_tbl(wrapper->tbl);
1454 }
1455 xfree(wrapper);
1456 }
1457
1458 static int
1459 free_const_entry_i(ID key, rb_const_entry_t *ce, st_data_t data)
1460 {
1461 xfree(ce);
1462 return ST_CONTINUE;
1463 }
1464
1465 void
1466 rb_free_const_table(st_table *tbl)
1467 {
1468 st_foreach(tbl, free_const_entry_i, 0);
1469 st_free_table(tbl);
1470 }
1471
1472 static inline void
1473 make_deferred(rb_objspace_t *objspace,RVALUE *p)
1474 {
1475 p->as.basic.flags = T_ZOMBIE;
1476 p->as.free.next = heap_pages_deferred_final;
1477 heap_pages_deferred_final = p;
1478 }
1479
1480 static inline void
1481 make_io_deferred(rb_objspace_t *objspace,RVALUE *p)
1482 {
1483 rb_io_t *fptr = p->as.file.fptr;
1484 make_deferred(objspace, p);
1485 p->as.data.dfree = (void (*)(void*))rb_io_fptr_finalize;
1486 p->as.data.data = fptr;
1487 }
1488
1489 static int
1490 obj_free(rb_objspace_t *objspace, VALUE obj)
1491 {
1492 gc_event_hook(objspace, RUBY_INTERNAL_EVENT_FREEOBJ, obj);
1493
1494 switch (BUILTIN_TYPE(obj)) {
1495 case T_NIL:
1496 case T_FIXNUM:
1497 case T_TRUE:
1498 case T_FALSE:
1499 rb_bug("obj_free() called for broken object");
1500 break;
1501 }
1502
1503 if (FL_TEST(obj, FL_EXIVAR)) {
1504 rb_free_generic_ivar((VALUE)obj);
1505 FL_UNSET(obj, FL_EXIVAR);
1506 }
1507
1508 #if USE_RGENGC
1509 if (MARKED_IN_BITMAP(GET_HEAP_OLDGEN_BITS(obj),obj))
1510 CLEAR_IN_BITMAP(GET_HEAP_OLDGEN_BITS(obj),obj);
1511 #endif
1512
1513 switch (BUILTIN_TYPE(obj)) {
1514 case T_OBJECT:
1515 if (!(RANY(obj)->as.basic.flags & ROBJECT_EMBED) &&
1516 RANY(obj)->as.object.as.heap.ivptr) {
1517 xfree(RANY(obj)->as.object.as.heap.ivptr);
1518 }
1519 break;
1520 case T_MODULE:
1521 case T_CLASS:
1522 if (RCLASS_M_TBL_WRAPPER(obj)) {
1523 rb_free_m_tbl_wrapper(RCLASS_M_TBL_WRAPPER(obj));
1524 }
1525 if (RCLASS_IV_TBL(obj)) {
1526 st_free_table(RCLASS_IV_TBL(obj));
1527 }
1528 if (RCLASS_CONST_TBL(obj)) {
1529 rb_free_const_table(RCLASS_CONST_TBL(obj));
1530 }
1531 if (RCLASS_IV_INDEX_TBL(obj)) {
1532 st_free_table(RCLASS_IV_INDEX_TBL(obj));
1533 }
1534 if (RCLASS_EXT(obj)->subclasses) {
1535 if (BUILTIN_TYPE(obj) == T_MODULE) {
1536 rb_class_detach_module_subclasses(obj);
1537 }
1538 else {
1539 rb_class_detach_subclasses(obj);
1540 }
1541 RCLASS_EXT(obj)->subclasses = NULL;
1542 }
1543 rb_class_remove_from_module_subclasses(obj);
1544 rb_class_remove_from_super_subclasses(obj);
1545 if (RANY(obj)->as.klass.ptr)
1546 xfree(RANY(obj)->as.klass.ptr);
1547 RANY(obj)->as.klass.ptr = NULL;
1548 break;
1549 case T_STRING:
1550 rb_str_free(obj);
1551 break;
1552 case T_ARRAY:
1553 rb_ary_free(obj);
1554 break;
1555 case T_HASH:
1556 if (RANY(obj)->as.hash.ntbl) {
1557 st_free_table(RANY(obj)->as.hash.ntbl);
1558 }
1559 break;
1560 case T_REGEXP:
1561 if (RANY(obj)->as.regexp.ptr) {
1562 onig_free(RANY(obj)->as.regexp.ptr);
1563 }
1564 break;
1565 case T_DATA:
1566 if (DATA_PTR(obj)) {
1567 int free_immediately = FALSE;
1568
1569 if (RTYPEDDATA_P(obj)) {
1570 free_immediately = (RANY(obj)->as.typeddata.type->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0;
1571 RDATA(obj)->dfree = RANY(obj)->as.typeddata.type->function.dfree;
1572 if (0 && free_immediately == 0) /* to expose non-free-immediate T_DATA */
1573 fprintf(stderr, "not immediate -> %s\n", RANY(obj)->as.typeddata.type->wrap_struct_name);
1574 }
1575 if (RANY(obj)->as.data.dfree == RUBY_DEFAULT_FREE) {
1576 xfree(DATA_PTR(obj));
1577 }
1578 else if (RANY(obj)->as.data.dfree) {
1579 if (free_immediately) {
1580 (RDATA(obj)->dfree)(DATA_PTR(obj));
1581 }
1582 else {
1583 make_deferred(objspace, RANY(obj));
1584 return 1;
1585 }
1586 }
1587 }
1588 break;
1589 case T_MATCH:
1590 if (RANY(obj)->as.match.rmatch) {
1591 struct rmatch *rm = RANY(obj)->as.match.rmatch;
1592 onig_region_free(&rm->regs, 0);
1593 if (rm->char_offset)
1594 xfree(rm->char_offset);
1595 xfree(rm);
1596 }
1597 break;
1598 case T_FILE:
1599 if (RANY(obj)->as.file.fptr) {
1600 make_io_deferred(objspace, RANY(obj));
1601 return 1;
1602 }
1603 break;
1604 case T_RATIONAL:
1605 case T_COMPLEX:
1606 break;
1607 case T_ICLASS:
1608 /* iClass shares table with the module */
1609 if (RCLASS_EXT(obj)->subclasses) {
1610 rb_class_detach_subclasses(obj);
1611 RCLASS_EXT(obj)->subclasses = NULL;
1612 }
1613 rb_class_remove_from_module_subclasses(obj);
1614 rb_class_remove_from_super_subclasses(obj);
1615 xfree(RANY(obj)->as.klass.ptr);
1616 RANY(obj)->as.klass.ptr = NULL;
1617 break;
1618
1619 case T_FLOAT:
1620 break;
1621
1622 case T_BIGNUM:
1623 if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
1624 xfree(RBIGNUM_DIGITS(obj));
1625 }
1626 break;
1627 case T_NODE:
1628 switch (nd_type(obj)) {
1629 case NODE_SCOPE:
1630 if (RANY(obj)->as.node.u1.tbl) {
1631 xfree(RANY(obj)->as.node.u1.tbl);
1632 }
1633 break;
1634 case NODE_ARGS:
1635 if (RANY(obj)->as.node.u3.args) {
1636 xfree(RANY(obj)->as.node.u3.args);
1637 }
1638 break;
1639 case NODE_ALLOCA:
1640 xfree(RANY(obj)->as.node.u1.node);
1641 break;
1642 }
1643 break; /* no need to free iv_tbl */
1644
1645 case T_STRUCT:
1646 if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
1647 RANY(obj)->as.rstruct.as.heap.ptr) {
1648 xfree((void *)RANY(obj)->as.rstruct.as.heap.ptr);
1649 }
1650 break;
1651
1652 default:
1653 rb_bug("gc_sweep(): unknown data type 0x%x(%p) 0x%"PRIxVALUE,
1654 BUILTIN_TYPE(obj), (void*)obj, RBASIC(obj)->flags);
1655 }
1656
1657 return 0;
1658 }
1659
1660 void
1661 Init_heap(void)
1662 {
1663 rb_objspace_t *objspace = &rb_objspace;
1664
1665 #if RGENGC_ESTIMATE_OLDMALLOC
1666 objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min;
1667 #endif
1668
1669 heap_add_pages(objspace, heap_eden, gc_params.heap_init_slots / HEAP_OBJ_LIMIT);
1670
1671 init_mark_stack(&objspace->mark_stack);
1672
1673 #ifdef USE_SIGALTSTACK
1674 {
1675 /* altstack of another threads are allocated in another place */
1676 rb_thread_t *th = GET_THREAD();
1677 void *tmp = th->altstack;
1678 th->altstack = malloc(rb_sigaltstack_size());
1679 free(tmp); /* free previously allocated area */
1680 }
1681 #endif
1682
1683 objspace->profile.invoke_time = getrusage_time();
1684 finalizer_table = st_init_numtable();
1685 }
1686
1687 typedef int each_obj_callback(void *, void *, size_t, void *);
1688
1689 struct each_obj_args {
1690 each_obj_callback *callback;
1691 void *data;
1692 };
1693
1694 static VALUE
1695 objspace_each_objects(VALUE arg)
1696 {
1697 size_t i;
1698 struct heap_page_body *last_body = 0;
1699 struct heap_page *page;
1700 RVALUE *pstart, *pend;
1701 rb_objspace_t *objspace = &rb_objspace;
1702 struct each_obj_args *args = (struct each_obj_args *)arg;
1703
1704 i = 0;
1705 while (i < heap_pages_used) {
1706 while (0 < i && last_body < heap_pages_sorted[i-1]->body) i--;
1707 while (i < heap_pages_used && heap_pages_sorted[i]->body <= last_body) i++;
1708 if (heap_pages_used <= i) break;
1709
1710 page = heap_pages_sorted[i];
1711 last_body = page->body;
1712
1713 pstart = page->start;
1714 pend = pstart + page->limit;
1715
1716 if ((*args->callback)(pstart, pend, sizeof(RVALUE), args->data)) {
1717 break;
1718 }
1719 }
1720
1721 return Qnil;
1722 }
1723
1724 /*
1725 * rb_objspace_each_objects() is special C API to walk through
1726 * Ruby object space. This C API is too difficult to use it.
1727 * To be frank, you should not use it. Or you need to read the
1728 * source code of this function and understand what this function does.
1729 *
1730 * 'callback' will be called several times (the number of heap page,
1731 * at current implementation) with:
1732 * vstart: a pointer to the first living object of the heap_page.
1733 * vend: a pointer to next to the valid heap_page area.
1734 * stride: a distance to next VALUE.
1735 *
1736 * If callback() returns non-zero, the iteration will be stopped.
1737 *
1738 * This is a sample callback code to iterate liveness objects:
1739 *
1740 * int
1741 * sample_callback(void *vstart, void *vend, int stride, void *data) {
1742 * VALUE v = (VALUE)vstart;
1743 * for (; v != (VALUE)vend; v += stride) {
1744 * if (RBASIC(v)->flags) { // liveness check
1745 * // do something with live object 'v'
1746 * }
1747 * return 0; // continue to iteration
1748 * }
1749 *
1750 * Note: 'vstart' is not a top of heap_page. This point the first
1751 * living object to grasp at least one object to avoid GC issue.
1752 * This means that you can not walk through all Ruby object page
1753 * including freed object page.
1754 *
1755 * Note: On this implementation, 'stride' is same as sizeof(RVALUE).
1756 * However, there are possibilities to pass variable values with
1757 * 'stride' with some reasons. You must use stride instead of
1758 * use some constant value in the iteration.
1759 */
1760 void
1761 rb_objspace_each_objects(each_obj_callback *callback, void *data)
1762 {
1763 struct each_obj_args args;
1764 rb_objspace_t *objspace = &rb_objspace;
1765 int prev_dont_lazy_sweep = objspace->flags.dont_lazy_sweep;
1766
1767 gc_rest_sweep(objspace);
1768 objspace->flags.dont_lazy_sweep = TRUE;
1769
1770 args.callback = callback;
1771 args.data = data;
1772
1773 if (prev_dont_lazy_sweep) {
1774 objspace_each_objects((VALUE)&args);
1775 }
1776 else {
1777 rb_ensure(objspace_each_objects, (VALUE)&args, lazy_sweep_enable, Qnil);
1778 }
1779 }
1780
1781 struct os_each_struct {
1782 size_t num;
1783 VALUE of;
1784 };
1785
1786 static int
1787 internal_object_p(VALUE obj)
1788 {
1789 RVALUE *p = (RVALUE *)obj;
1790
1791 if (p->as.basic.flags) {
1792 switch (BUILTIN_TYPE(p)) {
1793 case T_NONE:
1794 case T_ICLASS:
1795 case T_NODE:
1796 case T_ZOMBIE:
1797 break;
1798 case T_CLASS:
1799 if (FL_TEST(p, FL_SINGLETON))
1800 break;
1801 default:
1802 if (!p->as.basic.klass) break;
1803 return 0;
1804 }
1805 }
1806 return 1;
1807 }
1808
1809 int
1810 rb_objspace_internal_object_p(VALUE obj)
1811 {
1812 return internal_object_p(obj);
1813 }
1814
1815 static int
1816 os_obj_of_i(void *vstart, void *vend, size_t stride, void *data)
1817 {
1818 struct os_each_struct *oes = (struct os_each_struct *)data;
1819 RVALUE *p = (RVALUE *)vstart, *pend = (RVALUE *)vend;
1820
1821 for (; p != pend; p++) {
1822 volatile VALUE v = (VALUE)p;
1823 if (!internal_object_p(v)) {
1824 if (!oes->of || rb_obj_is_kind_of(v, oes->of)) {
1825 rb_yield(v);
1826 oes->num++;
1827 }
1828 }
1829 }
1830
1831 return 0;
1832 }
1833
1834 static VALUE
1835 os_obj_of(VALUE of)
1836 {
1837 struct os_each_struct oes;
1838
1839 oes.num = 0;
1840 oes.of = of;
1841 rb_objspace_each_objects(os_obj_of_i, &oes);
1842 return SIZET2NUM(oes.num);
1843 }
1844
1845 /*
1846 * call-seq:
1847 * ObjectSpace.each_object([module]) {|obj| ... } -> fixnum
1848 * ObjectSpace.each_object([module]) -> an_enumerator
1849 *
1850 * Calls the block once for each living, nonimmediate object in this
1851 * Ruby process. If <i>module</i> is specified, calls the block
1852 * for only those classes or modules that match (or are a subclass of)
1853 * <i>module</i>. Returns the number of objects found. Immediate
1854 * objects (<code>Fixnum</code>s, <code>Symbol</code>s
1855 * <code>true</code>, <code>false</code>, and <code>nil</code>) are
1856 * never returned. In the example below, <code>each_object</code>
1857 * returns both the numbers we defined and several constants defined in
1858 * the <code>Math</code> module.
1859 *
1860 * If no block is given, an enumerator is returned instead.
1861 *
1862 * a = 102.7
1863 * b = 95 # Won't be returned
1864 * c = 12345678987654321
1865 * count = ObjectSpace.each_object(Numeric) {|x| p x }
1866 * puts "Total count: #{count}"
1867 *
1868 * <em>produces:</em>
1869 *
1870 * 12345678987654321
1871 * 102.7
1872 * 2.71828182845905
1873 * 3.14159265358979
1874 * 2.22044604925031e-16
1875 * 1.7976931348623157e+308
1876 * 2.2250738585072e-308
1877 * Total count: 7
1878 *
1879 */
1880
1881 static VALUE
1882 os_each_obj(int argc, VALUE *argv, VALUE os)
1883 {
1884 VALUE of;
1885
1886 if (argc == 0) {
1887 of = 0;
1888 }
1889 else {
1890 rb_scan_args(argc, argv, "01", &of);
1891 }
1892 RETURN_ENUMERATOR(os, 1, &of);
1893 return os_obj_of(of);
1894 }
1895
1896 /*
1897 * call-seq:
1898 * ObjectSpace.undefine_finalizer(obj)
1899 *
1900 * Removes all finalizers for <i>obj</i>.
1901 *
1902 */
1903
1904 static VALUE
1905 undefine_final(VALUE os, VALUE obj)
1906 {
1907 return rb_undefine_finalizer(obj);
1908 }
1909
1910 VALUE
1911 rb_undefine_finalizer(VALUE obj)
1912 {
1913 rb_objspace_t *objspace = &rb_objspace;
1914 st_data_t data = obj;
1915 rb_check_frozen(obj);
1916 st_delete(finalizer_table, &data, 0);
1917 FL_UNSET(obj, FL_FINALIZE);
1918 return obj;
1919 }
1920
1921 static void
1922 should_be_callable(VALUE block)
1923 {
1924 if (!rb_obj_respond_to(block, rb_intern("call"), TRUE)) {
1925 rb_raise(rb_eArgError, "wrong type argument %s (should be callable)",
1926 rb_obj_classname(block));
1927 }
1928 }
1929 static void
1930 should_be_finalizable(VALUE obj)
1931 {
1932 rb_check_frozen(obj);
1933 if (!FL_ABLE(obj)) {
1934 rb_raise(rb_eArgError, "cannot define finalizer for %s",
1935 rb_obj_classname(obj));
1936 }
1937 }
1938
1939 /*
1940 * call-seq:
1941 * ObjectSpace.define_finalizer(obj, aProc=proc())
1942 *
1943 * Adds <i>aProc</i> as a finalizer, to be called after <i>obj</i>
1944 * was destroyed.
1945 *
1946 */
1947
1948 static VALUE
1949 define_final(int argc, VALUE *argv, VALUE os)
1950 {
1951 VALUE obj, block;
1952
1953 rb_scan_args(argc, argv, "11", &obj, &block);
1954 should_be_finalizable(obj);
1955 if (argc == 1) {
1956 block = rb_block_proc();
1957 }
1958 else {
1959 should_be_callable(block);
1960 }
1961
1962 return define_final0(obj, block);
1963 }
1964
1965 static VALUE
1966 define_final0(VALUE obj, VALUE block)
1967 {
1968 rb_objspace_t *objspace = &rb_objspace;
1969 VALUE table;
1970 st_data_t data;
1971
1972 RBASIC(obj)->flags |= FL_FINALIZE;
1973
1974 block = rb_ary_new3(2, INT2FIX(rb_safe_level()), block);
1975 OBJ_FREEZE(block);
1976
1977 if (st_lookup(finalizer_table, obj, &data)) {
1978 table = (VALUE)data;
1979 rb_ary_push(table, block);
1980 }
1981 else {
1982 table = rb_ary_new3(1, block);
1983 RBASIC_CLEAR_CLASS(table);
1984 st_add_direct(finalizer_table, obj, table);
1985 }
1986 return block;
1987 }
1988
1989 VALUE
1990 rb_define_finalizer(VALUE obj, VALUE block)
1991 {
1992 should_be_finalizable(obj);
1993 should_be_callable(block);
1994 return define_final0(obj, block);
1995 }
1996
1997 void
1998 rb_gc_copy_finalizer(VALUE dest, VALUE obj)
1999 {
2000 rb_objspace_t *objspace = &rb_objspace;
2001 VALUE table;
2002 st_data_t data;
2003
2004 if (!FL_TEST(obj, FL_FINALIZE)) return;
2005 if (st_lookup(finalizer_table, obj, &data)) {
2006 table = (VALUE)data;
2007 st_insert(finalizer_table, dest, table);
2008 }
2009 FL_SET(dest, FL_FINALIZE);
2010 }
2011
2012 static VALUE
2013 run_single_final(VALUE arg)
2014 {
2015 VALUE *args = (VALUE *)arg;
2016 rb_eval_cmd(args[0], args[1], (int)args[2]);
2017 return Qnil;
2018 }
2019
2020 static void
2021 run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table)
2022 {
2023 long i;
2024 int status;
2025 VALUE args[3];
2026 VALUE objid = nonspecial_obj_id(obj);
2027
2028 if (RARRAY_LEN(table) > 0) {
2029 args[1] = rb_obj_freeze(rb_ary_new3(1, objid));
2030 }
2031 else {
2032 args[1] = 0;
2033 }
2034
2035 args[2] = (VALUE)rb_safe_level();
2036 for (i=0; i<RARRAY_LEN(table); i++) {
2037 VALUE final = RARRAY_AREF(table, i);
2038 args[0] = RARRAY_AREF(final, 1);
2039 args[2] = FIX2INT(RARRAY_AREF(final, 0));
2040 status = 0;
2041 rb_protect(run_single_final, (VALUE)args, &status);
2042 if (status)
2043 rb_set_errinfo(Qnil);
2044 }
2045 }
2046
2047 static void
2048 run_final(rb_objspace_t *objspace, VALUE obj)
2049 {
2050 RUBY_DATA_FUNC free_func = 0;
2051 st_data_t key, table;
2052
2053 heap_pages_final_slots--;
2054
2055 RBASIC_CLEAR_CLASS(obj);
2056
2057 if (RTYPEDDATA_P(obj)) {
2058 free_func = RTYPEDDATA_TYPE(obj)->function.dfree;
2059 }
2060 else {
2061 free_func = RDATA(obj)->dfree;
2062 }
2063 if (free_func) {
2064 (*free_func)(DATA_PTR(obj));
2065 }
2066
2067 key = (st_data_t)obj;
2068 if (st_delete(finalizer_table, &key, &table)) {
2069 run_finalizer(objspace, obj, (VALUE)table);
2070 }
2071 }
2072
2073 static void
2074 finalize_list(rb_objspace_t *objspace, RVALUE *p)
2075 {
2076 while (p) {
2077 RVALUE *tmp = p->as.free.next;
2078 struct heap_page *page = GET_HEAP_PAGE(p);
2079
2080 run_final(objspace, (VALUE)p);
2081 objspace->profile.total_freed_object_num++;
2082
2083 page->final_slots--;
2084 heap_page_add_freeobj(objspace, GET_HEAP_PAGE(p), (VALUE)p);
2085 heap_pages_swept_slots++;
2086
2087 p = tmp;
2088 }
2089 }
2090
2091 static void
2092 finalize_deferred(rb_objspace_t *objspace)
2093 {
2094 RVALUE *p;
2095
2096 while ((p = ATOMIC_PTR_EXCHANGE(heap_pages_deferred_final, 0)) != 0) {
2097 finalize_list(objspace, p);
2098 }
2099 }
2100
2101 static void
2102 gc_finalize_deferred(void *dmy)
2103 {
2104 rb_objspace_t *objspace = &rb_objspace;
2105 if (ATOMIC_EXCHANGE(finalizing, 1)) return;
2106 finalize_deferred(objspace);
2107 ATOMIC_SET(finalizing, 0);
2108 }
2109
2110 /* TODO: to keep compatibility, maybe unused. */
2111 void
2112 rb_gc_finalize_deferred(void)
2113 {
2114 gc_finalize_deferred(0);
2115 }
2116
2117 static void
2118 gc_finalize_deferred_register(void)
2119 {
2120 if (rb_postponed_job_register_one(0, gc_finalize_deferred, 0) == 0) {
2121 rb_bug("gc_finalize_deferred_register: can't register finalizer.");
2122 }
2123 }
2124
2125 struct force_finalize_list {
2126 VALUE obj;
2127 VALUE table;
2128 struct force_finalize_list *next;
2129 };
2130
2131 static int
2132 force_chain_object(st_data_t key, st_data_t val, st_data_t arg)
2133 {
2134 struct force_finalize_list **prev = (struct force_finalize_list **)arg;
2135 struct force_finalize_list *curr = ALLOC(struct force_finalize_list);
2136 curr->obj = key;
2137 curr->table = val;
2138 curr->next = *prev;
2139 *prev = curr;
2140 return ST_CONTINUE;
2141 }
2142
2143 void
2144 rb_gc_call_finalizer_at_exit(void)
2145 {
2146 rb_objspace_call_finalizer(&rb_objspace);
2147 }
2148
2149 static void
2150 rb_objspace_call_finalizer(rb_objspace_t *objspace)
2151 {
2152 RVALUE *p, *pend;
2153 size_t i;
2154
2155 gc_rest_sweep(objspace);
2156
2157 if (ATOMIC_EXCHANGE(finalizing, 1)) return;
2158
2159 /* run finalizers */
2160 finalize_deferred(objspace);
2161 assert(heap_pages_deferred_final == 0);
2162
2163 /* force to run finalizer */
2164 while (finalizer_table->num_entries) {
2165 struct force_finalize_list *list = 0;
2166 st_foreach(finalizer_table, force_chain_object, (st_data_t)&list);
2167 while (list) {
2168 struct force_finalize_list *curr = list;
2169 st_data_t obj = (st_data_t)curr->obj;
2170 run_finalizer(objspace, curr->obj, curr->table);
2171 st_delete(finalizer_table, &obj, 0);
2172 list = curr->next;
2173 xfree(curr);
2174 }
2175 }
2176
2177 /* finalizers are part of garbage collection */
2178 during_gc++;
2179
2180 /* run data object's finalizers */
2181 for (i = 0; i < heap_pages_used; i++) {
2182 p = heap_pages_sorted[i]->start; pend = p + heap_pages_sorted[i]->limit;
2183 while (p < pend) {
2184 switch (BUILTIN_TYPE(p)) {
2185 case T_DATA:
2186 if (!DATA_PTR(p) || !RANY(p)->as.data.dfree) break;
2187 if (rb_obj_is_thread((VALUE)p)) break;
2188 if (rb_obj_is_mutex((VALUE)p)) break;
2189 if (rb_obj_is_fiber((VALUE)p)) break;
2190 p->as.free.flags = 0;
2191 if (RTYPEDDATA_P(p)) {
2192 RDATA(p)->dfree = RANY(p)->as.typeddata.type->function.dfree;
2193 }
2194 if (RANY(p)->as.data.dfree == (RUBY_DATA_FUNC)-1) {
2195 xfree(DATA_PTR(p));
2196 }
2197 else if (RANY(p)->as.data.dfree) {
2198 make_deferred(objspace, RANY(p));
2199 }
2200 break;
2201 case T_FILE:
2202 if (RANY(p)->as.file.fptr) {
2203 make_io_deferred(objspace, RANY(p));
2204 }
2205 break;
2206 }
2207 p++;
2208 }
2209 }
2210 during_gc = 0;
2211 if (heap_pages_deferred_final) {
2212 finalize_list(objspace, heap_pages_deferred_final);
2213 }
2214
2215 st_free_table(finalizer_table);
2216 finalizer_table = 0;
2217 ATOMIC_SET(finalizing, 0);
2218 }
2219
2220 static inline int
2221 is_id_value(rb_objspace_t *objspace, VALUE ptr)
2222 {
2223 if (!is_pointer_to_heap(objspace, (void *)ptr)) return FALSE;
2224 if (BUILTIN_TYPE(ptr) > T_FIXNUM) return FALSE;
2225 if (BUILTIN_TYPE(ptr) == T_ICLASS) return FALSE;
2226 return TRUE;
2227 }
2228
2229 static inline int
2230 heap_is_swept_object(rb_objspace_t *objspace, rb_heap_t *heap, VALUE ptr)
2231 {
2232 struct heap_page *page = GET_HEAP_PAGE(ptr);
2233 return page->before_sweep ? FALSE : TRUE;
2234 }
2235
2236 static inline int
2237 is_swept_object(rb_objspace_t *objspace, VALUE ptr)
2238 {
2239 if (heap_is_swept_object(objspace, heap_eden, ptr)) {
2240 return TRUE;
2241 }
2242 else {
2243 return FALSE;
2244 }
2245 }
2246
2247 static inline int
2248 is_dead_object(rb_objspace_t *objspace, VALUE ptr)
2249 {
2250 if (!is_lazy_sweeping(heap_eden) || MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(ptr), ptr)) return FALSE;
2251 if (!is_swept_object(objspace, ptr)) return TRUE;
2252 return FALSE;
2253 }
2254
2255 static inline int
2256 is_live_object(rb_objspace_t *objspace, VALUE ptr)
2257 {
2258 switch (BUILTIN_TYPE(ptr)) {
2259 case 0: case T_ZOMBIE:
2260 return FALSE;
2261 }
2262 if (is_dead_object(objspace, ptr)) return FALSE;
2263 return TRUE;
2264 }
2265
2266 static inline int
2267 is_markable_object(rb_objspace_t *objspace, VALUE obj)
2268 {
2269 if (rb_special_const_p(obj)) return 0; /* special const is not markable */
2270
2271 if (RGENGC_CHECK_MODE) {
2272 if (!is_pointer_to_heap(objspace, (void *)obj)) rb_bug("is_markable_object: %p is not pointer to heap", (void *)obj);
2273 if (BUILTIN_TYPE(obj) == T_NONE) rb_bug("is_markable_object: %p is T_NONE", (void *)obj);
2274 if (BUILTIN_TYPE(obj) == T_ZOMBIE) rb_bug("is_markable_object: %p is T_ZOMBIE", (void *)obj);
2275 }
2276
2277 return 1;
2278 }
2279
2280 int
2281 rb_objspace_markable_object_p(VALUE obj)
2282 {
2283 rb_objspace_t *objspace = &rb_objspace;
2284 return is_markable_object(objspace, obj) && is_live_object(objspace, obj);
2285 }
2286
2287 /*
2288 * call-seq:
2289 * ObjectSpace._id2ref(object_id) -> an_object
2290 *
2291 * Converts an object id to a reference to the object. May not be
2292 * called on an object id passed as a parameter to a finalizer.
2293 *
2294 * s = "I am a string" #=> "I am a string"
2295 * r = ObjectSpace._id2ref(s.object_id) #=> "I am a string"
2296 * r == s #=> true
2297 *
2298 */
2299
2300 static VALUE
2301 id2ref(VALUE obj, VALUE objid)
2302 {
2303 #if SIZEOF_LONG == SIZEOF_VOIDP
2304 #define NUM2PTR(x) NUM2ULONG(x)
2305 #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
2306 #define NUM2PTR(x) NUM2ULL(x)
2307 #endif
2308 rb_objspace_t *objspace = &rb_objspace;
2309 VALUE ptr;
2310 void *p0;
2311
2312 ptr = NUM2PTR(objid);
2313 p0 = (void *)ptr;
2314
2315 if (ptr == Qtrue) return Qtrue;
2316 if (ptr == Qfalse) return Qfalse;
2317 if (ptr == Qnil) return Qnil;
2318 if (FIXNUM_P(ptr)) return (VALUE)ptr;
2319 if (FLONUM_P(ptr)) return (VALUE)ptr;
2320 ptr = obj_id_to_ref(objid);
2321
2322 if ((ptr % sizeof(RVALUE)) == (4 << 2)) {
2323 ID symid = ptr / sizeof(RVALUE);
2324 if (rb_id2name(symid) == 0)
2325 rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
2326 return ID2SYM(symid);
2327 }
2328
2329 if (!is_id_value(objspace, ptr)) {
2330 rb_raise(rb_eRangeError, "%p is not id value", p0);
2331 }
2332 if (!is_live_object(objspace, ptr)) {
2333 rb_raise(rb_eRangeError, "%p is recycled object", p0);
2334 }
2335 return (VALUE)ptr;
2336 }
2337
2338 /*
2339 * Document-method: __id__
2340 * Document-method: object_id
2341 *
2342 * call-seq:
2343 * obj.__id__ -> integer
2344 * obj.object_id -> integer
2345 *
2346 * Returns an integer identifier for +obj+.
2347 *
2348 * The same number will be returned on all calls to +id+ for a given object,
2349 * and no two active objects will share an id.
2350 *
2351 * Object#object_id is a different concept from the +:name+ notation, which
2352 * returns the symbol id of +name+.
2353 *
2354 * Replaces the deprecated Object#id.
2355 */
2356
2357 /*
2358 * call-seq:
2359 * obj.hash -> fixnum
2360 *
2361 * Generates a Fixnum hash value for this object.
2362 *
2363 * This function must have the property that <code>a.eql?(b)</code> implies
2364 * <code>a.hash == b.hash</code>.
2365 *
2366 * The hash value is used by Hash class.
2367 *
2368 * Any hash value that exceeds the capacity of a Fixnum will be truncated
2369 * before being used.
2370 */
2371
2372 VALUE
2373 rb_obj_id(VALUE obj)
2374 {
2375 /*
2376 * 32-bit VALUE space
2377 * MSB ------------------------ LSB
2378 * false 00000000000000000000000000000000
2379 * true 00000000000000000000000000000010
2380 * nil 00000000000000000000000000000100
2381 * undef 00000000000000000000000000000110
2382 * symbol ssssssssssssssssssssssss00001110
2383 * object oooooooooooooooooooooooooooooo00 = 0 (mod sizeof(RVALUE))
2384 * fixnum fffffffffffffffffffffffffffffff1
2385 *
2386 * object_id space
2387 * LSB
2388 * false 00000000000000000000000000000000
2389 * true 00000000000000000000000000000010
2390 * nil 00000000000000000000000000000100
2391 * undef 00000000000000000000000000000110
2392 * symbol 000SSSSSSSSSSSSSSSSSSSSSSSSSSS0 S...S % A = 4 (S...S = s...s * A + 4)
2393 * object oooooooooooooooooooooooooooooo0 o...o % A = 0
2394 * fixnum fffffffffffffffffffffffffffffff1 bignum if required
2395 *
2396 * where A = sizeof(RVALUE)/4
2397 *
2398 * sizeof(RVALUE) is
2399 * 20 if 32-bit, double is 4-byte aligned
2400 * 24 if 32-bit, double is 8-byte aligned
2401 * 40 if 64-bit
2402 */
2403 if (SYMBOL_P(obj)) {
2404 return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
2405 }
2406 else if (FLONUM_P(obj)) {
2407 #if SIZEOF_LONG == SIZEOF_VOIDP
2408 return LONG2NUM((SIGNED_VALUE)obj);
2409 #else
2410 return LL2NUM((SIGNED_VALUE)obj);
2411 #endif
2412 }
2413 else if (SPECIAL_CONST_P(obj)) {
2414 return LONG2NUM((SIGNED_VALUE)obj);
2415 }
2416 return nonspecial_obj_id(obj);
2417 }
2418
2419 size_t rb_str_memsize(VALUE);
2420 size_t rb_ary_memsize(VALUE);
2421 size_t rb_io_memsize(const rb_io_t *);
2422 size_t rb_generic_ivar_memsize(VALUE);
2423 #include "regint.h"
2424
2425 static size_t
2426 obj_memsize_of(VALUE obj, int use_tdata)
2427 {
2428 size_t size = 0;
2429
2430 if (SPECIAL_CONST_P(obj)) {
2431 return 0;
2432 }
2433
2434 if (FL_TEST(obj, FL_EXIVAR)) {
2435 size += rb_generic_ivar_memsize(obj);
2436 }
2437
2438 switch (BUILTIN_TYPE(obj)) {
2439 case T_OBJECT:
2440 if (!(RBASIC(obj)->flags & ROBJECT_EMBED) &&
2441 ROBJECT(obj)->as.heap.ivptr) {
2442 size += ROBJECT(obj)->as.heap.numiv * sizeof(VALUE);
2443 }
2444 break;
2445 case T_MODULE:
2446 case T_CLASS:
2447 if (RCLASS_M_TBL_WRAPPER(obj)) {
2448 size += sizeof(struct method_table_wrapper);
2449 }
2450 if (RCLASS_M_TBL(obj)) {
2451 size += st_memsize(RCLASS_M_TBL(obj));
2452 }
2453 if (RCLASS_EXT(obj)) {
2454 if (RCLASS_IV_TBL(obj)) {
2455 size += st_memsize(RCLASS_IV_TBL(obj));
2456 }
2457 if (RCLASS_IV_INDEX_TBL(obj)) {
2458 size += st_memsize(RCLASS_IV_INDEX_TBL(obj));
2459 }
2460 if (RCLASS(obj)->ptr->iv_tbl) {
2461 size += st_memsize(RCLASS(obj)->ptr->iv_tbl);
2462 }
2463 if (RCLASS(obj)->ptr->const_tbl) {
2464 size += st_memsize(RCLASS(obj)->ptr->const_tbl);
2465 }
2466 size += sizeof(rb_classext_t);
2467 }
2468 break;
2469 case T_STRING:
2470 size += rb_str_memsize(obj);
2471 break;
2472 case T_ARRAY:
2473 size += rb_ary_memsize(obj);
2474 break;
2475 case T_HASH:
2476 if (RHASH(obj)->ntbl) {
2477 size += st_memsize(RHASH(obj)->ntbl);
2478 }
2479 break;
2480 case T_REGEXP:
2481 if (RREGEXP(obj)->ptr) {
2482 size += onig_memsize(RREGEXP(obj)->ptr);
2483 }
2484 break;
2485 case T_DATA:
2486 if (use_tdata) size += rb_objspace_data_type_memsize(obj);
2487 break;
2488 case T_MATCH:
2489 if (RMATCH(obj)->rmatch) {
2490 struct rmatch *rm = RMATCH(obj)->rmatch;
2491 size += onig_region_memsize(&rm->regs);
2492 size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated;
2493 size += sizeof(struct rmatch);
2494 }
2495 break;
2496 case T_FILE:
2497 if (RFILE(obj)->fptr) {
2498 size += rb_io_memsize(RFILE(obj)->fptr);
2499 }
2500 break;
2501 case T_RATIONAL:
2502 case T_COMPLEX:
2503 break;
2504 case T_ICLASS:
2505 /* iClass shares table with the module */
2506 break;
2507
2508 case T_FLOAT:
2509 break;
2510
2511 case T_BIGNUM:
2512 if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
2513 size += RBIGNUM_LEN(obj) * sizeof(BDIGIT);
2514 }
2515 break;
2516 case T_NODE:
2517 switch (nd_type(obj)) {
2518 case NODE_SCOPE:
2519 if (RNODE(obj)->u1.tbl) {
2520 /* TODO: xfree(RANY(obj)->as.node.u1.tbl); */
2521 }
2522 break;
2523 case NODE_ALLOCA:
2524 /* TODO: xfree(RANY(obj)->as.node.u1.node); */
2525 ;
2526 }
2527 break; /* no need to free iv_tbl */
2528
2529 case T_STRUCT:
2530 if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
2531 RSTRUCT(obj)->as.heap.ptr) {
2532 size += sizeof(VALUE) * RSTRUCT_LEN(obj);
2533 }
2534 break;
2535
2536 case T_ZOMBIE:
2537 break;
2538
2539 default:
2540 rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)",
2541 BUILTIN_TYPE(obj), (void*)obj);
2542 }
2543
2544 return size;
2545 }
2546
2547 size_t
2548 rb_obj_memsize_of(VALUE obj)
2549 {
2550 return obj_memsize_of(obj, TRUE);
2551 }
2552
2553 static int
2554 set_zero(st_data_t key, st_data_t val, st_data_t arg)
2555 {
2556 VALUE k = (VALUE)key;
2557 VALUE hash = (VALUE)arg;
2558 rb_hash_aset(hash, k, INT2FIX(0));
2559 return ST_CONTINUE;
2560 }
2561
2562 /*
2563 * call-seq:
2564 * ObjectSpace.count_objects([result_hash]) -> hash
2565 *
2566 * Counts objects for each type.
2567 *
2568 * It returns a hash, such as:
2569 * {
2570 * :TOTAL=>10000,
2571 * :FREE=>3011,
2572 * :T_OBJECT=>6,
2573 * :T_CLASS=>404,
2574 * # ...
2575 * }
2576 *
2577 * The contents of the returned hash are implementation specific.
2578 * It may be changed in future.
2579 *
2580 * If the optional argument +result_hash+ is given,
2581 * it is overwritten and returned. This is intended to avoid probe effect.
2582 *
2583 * This method is only expected to work on C Ruby.
2584 *
2585 */
2586
2587 static VALUE
2588 count_objects(int argc, VALUE *argv, VALUE os)
2589 {
2590 rb_objspace_t *objspace = &rb_objspace;
2591 size_t counts[T_MASK+1];
2592 size_t freed = 0;
2593 size_t total = 0;
2594 size_t i;
2595 VALUE hash;
2596
2597 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
2598 if (!RB_TYPE_P(hash, T_HASH))
2599 rb_raise(rb_eTypeError, "non-hash given");
2600 }
2601
2602 for (i = 0; i <= T_MASK; i++) {
2603 counts[i] = 0;
2604 }
2605
2606 for (i = 0; i < heap_pages_used; i++) {
2607 struct heap_page *page = heap_pages_sorted[i];
2608 RVALUE *p, *pend;
2609
2610 p = page->start; pend = p + page->limit;
2611 for (;p < pend; p++) {
2612 if (p->as.basic.flags) {
2613 counts[BUILTIN_TYPE(p)]++;
2614 }
2615 else {
2616 freed++;
2617 }
2618 }
2619 total += page->limit;
2620 }
2621
2622 if (hash == Qnil) {
2623 hash = rb_hash_new();
2624 }
2625 else if (!RHASH_EMPTY_P(hash)) {
2626 st_foreach(RHASH_TBL_RAW(hash), set_zero, hash);
2627 }
2628 rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
2629 rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(freed));
2630
2631 for (i = 0; i <= T_MASK; i++) {
2632 VALUE type;
2633 switch (i) {
2634 #define COUNT_TYPE(t) case (t): type = ID2SYM(rb_intern(#t)); break;
2635 COUNT_TYPE(T_NONE);
2636 COUNT_TYPE(T_OBJECT);
2637 COUNT_TYPE(T_CLASS);
2638 COUNT_TYPE(T_MODULE);
2639 COUNT_TYPE(T_FLOAT);
2640 COUNT_TYPE(T_STRING);
2641 COUNT_TYPE(T_REGEXP);
2642 COUNT_TYPE(T_ARRAY);
2643 COUNT_TYPE(T_HASH);
2644 COUNT_TYPE(T_STRUCT);
2645 COUNT_TYPE(T_BIGNUM);
2646 COUNT_TYPE(T_FILE);
2647 COUNT_TYPE(T_DATA);
2648 COUNT_TYPE(T_MATCH);
2649 COUNT_TYPE(T_COMPLEX);
2650 COUNT_TYPE(T_RATIONAL);
2651 COUNT_TYPE(T_NIL);
2652 COUNT_TYPE(T_TRUE);
2653 COUNT_TYPE(T_FALSE);
2654 COUNT_TYPE(T_SYMBOL);
2655 COUNT_TYPE(T_FIXNUM);
2656 COUNT_TYPE(T_UNDEF);
2657 COUNT_TYPE(T_NODE);
2658 COUNT_TYPE(T_ICLASS);
2659 COUNT_TYPE(T_ZOMBIE);
2660 #undef COUNT_TYPE
2661 default: type = INT2NUM(i); break;
2662 }
2663 if (counts[i])
2664 rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
2665 }
2666
2667 return hash;
2668 }
2669
2670 /*
2671 ------------------------ Garbage Collection ------------------------
2672 */
2673
2674 /* Sweeping */
2675
2676 static VALUE
2677 lazy_sweep_enable(void)
2678 {
2679 rb_objspace_t *objspace = &rb_objspace;
2680
2681 objspace->flags.dont_lazy_sweep = FALSE;
2682 return Qnil;
2683 }
2684
2685 static size_t
2686 objspace_live_slot(rb_objspace_t *objspace)
2687 {
2688 return objspace->profile.total_allocated_object_num - objspace->profile.total_freed_object_num;
2689 }
2690
2691 static size_t
2692 objspace_total_slot(rb_objspace_t *objspace)
2693 {
2694 return heap_eden->total_slots + heap_tomb->total_slots;
2695 }
2696
2697 static size_t
2698 objspace_free_slot(rb_objspace_t *objspace)
2699 {
2700 return objspace_total_slot(objspace) - (objspace_live_slot(objspace) - heap_pages_final_slots);
2701 }
2702
2703 static void
2704 gc_setup_mark_bits(struct heap_page *page)
2705 {
2706 #if USE_RGENGC
2707 /* copy oldgen bitmap to mark bitmap */
2708 memcpy(&page->mark_bits[0], &page->oldgen_bits[0], HEAP_BITMAP_SIZE);
2709 #else
2710 /* clear mark bitmap */
2711 memset(&page->mark_bits[0], 0, HEAP_BITMAP_SIZE);
2712 #endif
2713 }
2714
2715 static inline void
2716 gc_page_sweep(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *sweep_page)
2717 {
2718 int i;
2719 size_t empty_slots = 0, freed_slots = 0, final_slots = 0;
2720 RVALUE *p, *pend,*offset;
2721 bits_t *bits, bitset;
2722
2723 rgengc_report(1, objspace, "page_sweep: start.\n");
2724
2725 sweep_page->before_sweep = 0;
2726
2727 p = sweep_page->start; pend = p + sweep_page->limit;
2728 offset = p - NUM_IN_PAGE(p);
2729 bits = sweep_page->mark_bits;
2730
2731 /* create guard : fill 1 out-of-range */
2732 bits[BITMAP_INDEX(p)] |= BITMAP_BIT(p)-1;
2733 bits[BITMAP_INDEX(pend)] |= ~(BITMAP_BIT(pend) - 1);
2734
2735 for (i=0; i < HEAP_BITMAP_LIMIT; i++) {
2736 bitset = ~bits[i];
2737 if (bitset) {
2738 p = offset + i * BITS_BITLENGTH;
2739 do {
2740 if ((bitset & 1) && BUILTIN_TYPE(p) != T_ZOMBIE) {
2741 if (p->as.basic.flags) {
2742 rgengc_report(3, objspace, "page_sweep: free %p (%s)\n", p, obj_type_name((VALUE)p));
2743 #if USE_RGENGC && RGENGC_CHECK_MODE
2744 if (objspace->rgengc.during_minor_gc && RVALUE_OLD_P((VALUE)p)) rb_bug("page_sweep: %p (%s) is old while minor GC.\n", p, obj_type_name((VALUE)p));
2745 if (rgengc_remembered(objspace, (VALUE)p)) rb_bug("page_sweep: %p (%s) is remembered.\n", p, obj_type_name((VALUE)p));
2746 #endif
2747 if (obj_free(objspace, (VALUE)p)) {
2748 final_slots++;
2749 }
2750 else if (FL_TEST(p, FL_FINALIZE)) {
2751 RDATA(p)->dfree = 0;
2752 make_deferred(objspace,p);
2753 final_slots++;
2754 }
2755 else {
2756 (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
2757 heap_page_add_freeobj(objspace, sweep_page, (VALUE)p);
2758 rgengc_report(3, objspace, "page_sweep: %p (%s) is added to freelist\n", p, obj_type_name((VALUE)p));
2759 freed_slots++;
2760 }
2761 }
2762 else {
2763 empty_slots++;
2764 }
2765 }
2766 p++;
2767 bitset >>= 1;
2768 } while (bitset);
2769 }
2770 }
2771
2772 gc_setup_mark_bits(sweep_page);
2773
2774 #if GC_PROFILE_MORE_DETAIL
2775 if (gc_prof_enabled(objspace)) {
2776 gc_profile_record *record = gc_prof_record(objspace);
2777 record->removing_objects += final_slots + freed_slots;
2778 record->empty_objects += empty_slots;
2779 }
2780 #endif
2781
2782 if (final_slots + freed_slots + empty_slots == sweep_page->limit) {
2783 /* there are no living objects -> move this page to tomb heap */
2784 heap_unlink_page(objspace, heap, sweep_page);
2785 heap_add_page(objspace, heap_tomb, sweep_page);
2786 }
2787 else {
2788 if (freed_slots + empty_slots > 0) {
2789 heap_add_freepage(objspace, heap, sweep_page);
2790 }
2791 else {
2792 sweep_page->free_next = NULL;
2793 }
2794 }
2795 heap_pages_swept_slots += freed_slots + empty_slots;
2796 objspace->profile.total_freed_object_num += freed_slots;
2797 heap_pages_final_slots += final_slots;
2798 sweep_page->final_slots = final_slots;
2799
2800 if (0) fprintf(stderr, "gc_page_sweep(%d): freed?: %d, limt: %d, freed_slots: %d, empty_slots: %d, final_slots: %d\n",
2801 (int)rb_gc_count(),
2802 final_slots + freed_slots + empty_slots == sweep_page->limit,
2803 (int)sweep_page->limit, (int)freed_slots, (int)empty_slots, (int)final_slots);
2804
2805 if (heap_pages_deferred_final && !finalizing) {
2806 rb_thread_t *th = GET_THREAD();
2807 if (th) {
2808 gc_finalize_deferred_register();
2809 }
2810 }
2811
2812 rgengc_report(1, objspace, "page_sweep: end.\n");
2813 }
2814
2815 /* allocate additional minimum page to work */
2816 static void
2817 gc_heap_prepare_minimum_pages(rb_objspace_t *objspace, rb_heap_t *heap)
2818 {
2819 if (!heap->free_pages) {
2820 /* there is no free after page_sweep() */
2821 heap_set_increment(objspace, 0);
2822 if (!heap_increment(objspace, heap)) { /* can't allocate additional free objects */
2823 during_gc = 0;
2824 rb_memerror();
2825 }
2826 }
2827 }
2828
2829 static void
2830 gc_before_heap_sweep(rb_objspace_t *objspace, rb_heap_t *heap)
2831 {
2832 heap->sweep_pages = heap->pages;
2833 heap->free_pages = NULL;
2834
2835 if (heap->using_page) {
2836 RVALUE **p = &heap->using_page->freelist;
2837 while (*p) {
2838 p = &(*p)->as.free.next;
2839 }
2840 *p = heap->freelist;
2841 heap->using_page = NULL;
2842 }
2843 heap->freelist = NULL;
2844 }
2845
2846 #if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 4
2847 __attribute__((noinline))
2848 #endif
2849 static void
2850 gc_before_sweep(rb_objspace_t *objspace)
2851 {
2852 rb_heap_t *heap;
2853 size_t total_limit_slot;
2854
2855 rgengc_report(1, objspace, "gc_before_sweep\n");
2856
2857 /* sweep unlinked method entries */
2858 if (GET_VM()->unlinked_method_entry_list) {
2859 rb_sweep_method_entry(GET_VM());
2860 }
2861
2862 heap_pages_swept_slots = 0;
2863 total_limit_slot = objspace_total_slot(objspace);
2864
2865 heap_pages_min_free_slots = (size_t)(total_limit_slot * 0.30);
2866 if (heap_pages_min_free_slots < gc_params.heap_free_slots) {
2867 heap_pages_min_free_slots = gc_params.heap_free_slots;
2868 }
2869 heap_pages_max_free_slots = (size_t)(total_limit_slot * 0.80);
2870 if (heap_pages_max_free_slots < gc_params.heap_init_slots) {
2871 heap_pages_max_free_slots = gc_params.heap_init_slots;
2872 }
2873 if (0) fprintf(stderr, "heap_pages_min_free_slots: %d, heap_pages_max_free_slots: %d\n",
2874 (int)heap_pages_min_free_slots, (int)heap_pages_max_free_slots);
2875
2876 heap = heap_eden;
2877 gc_before_heap_sweep(objspace, heap);
2878
2879 gc_prof_set_malloc_info(objspace);
2880
2881 /* reset malloc info */
2882 if (0) fprintf(stderr, "%d\t%d\t%d\n", (int)rb_gc_count(), (int)malloc_increase, (int)malloc_limit);
2883
2884 {
2885 size_t inc = ATOMIC_SIZE_EXCHANGE(malloc_increase, 0);
2886 size_t old_limit = malloc_limit;
2887
2888 if (inc > malloc_limit) {
2889 malloc_limit = (size_t)(inc * gc_params.malloc_limit_growth_factor);
2890 if (gc_params.malloc_limit_max > 0 && /* ignore max-check if 0 */
2891 malloc_limit > gc_params.malloc_limit_max) {
2892 malloc_limit = gc_params.malloc_limit_max;
2893 }
2894 }
2895 else {
2896 malloc_limit = (size_t)(malloc_limit * 0.98); /* magic number */
2897 if (malloc_limit < gc_params.malloc_limit_min) {
2898 malloc_limit = gc_params.malloc_limit_min;
2899 }
2900 }
2901
2902 if (0) {
2903 if (old_limit != malloc_limit) {
2904 fprintf(stderr, "[%"PRIuSIZE"] malloc_limit: %"PRIuSIZE" -> %"PRIuSIZE"\n",
2905 rb_gc_count(), old_limit, malloc_limit);
2906 }
2907 else {
2908 fprintf(stderr, "[%"PRIuSIZE"] malloc_limit: not changed (%"PRIuSIZE")\n",
2909 rb_gc_count(), malloc_limit);
2910 }
2911 }
2912 }
2913
2914 /* reset oldmalloc info */
2915 #if RGENGC_ESTIMATE_OLDMALLOC
2916 if (objspace->rgengc.during_minor_gc) {
2917 if (objspace->rgengc.oldmalloc_increase > objspace->rgengc.oldmalloc_increase_limit) {
2918 objspace->rgengc.need_major_gc = GPR_FLAG_MAJOR_BY_OLDMALLOC;;
2919 objspace->rgengc.oldmalloc_increase_limit =
2920 (size_t)(objspace->rgengc.oldmalloc_increase_limit * gc_params.oldmalloc_limit_growth_factor);
2921
2922 if (objspace->rgengc.oldmalloc_increase_limit > gc_params.oldmalloc_limit_max) {
2923 objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_max;
2924 }
2925 }
2926
2927 if (0) fprintf(stderr, "%d\t%d\t%u\t%u\t%d\n",
2928 (int)rb_gc_count(),
2929 (int)objspace->rgengc.need_major_gc,
2930 (unsigned int)objspace->rgengc.oldmalloc_increase,
2931 (unsigned int)objspace->rgengc.oldmalloc_increase_limit,
2932 (unsigned int)gc_params.oldmalloc_limit_max);
2933 }
2934 else {
2935 /* major GC */
2936 objspace->rgengc.oldmalloc_increase = 0;
2937
2938 if ((objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_BY_OLDMALLOC) == 0) {
2939 objspace->rgengc.oldmalloc_increase_limit =
2940 (size_t)(objspace->rgengc.oldmalloc_increase_limit / ((gc_params.oldmalloc_limit_growth_factor - 1)/10 + 1));
2941 if (objspace->rgengc.oldmalloc_increase_limit < gc_params.oldmalloc_limit_min) {
2942 objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min;
2943 }
2944 }
2945 }
2946
2947 #endif
2948
2949 }
2950
2951 static void
2952 gc_after_sweep(rb_objspace_t *objspace)
2953 {
2954 rb_heap_t *heap = heap_eden;
2955
2956 rgengc_report(1, objspace, "after_gc_sweep: heap->total_slots: %d, heap->swept_slots: %d, min_free_slots: %d\n",
2957 (int)heap->total_slots, (int)heap_pages_swept_slots, (int)heap_pages_min_free_slots);
2958
2959 if (heap_pages_swept_slots < heap_pages_min_free_slots) {
2960 #if USE_RGENGC
2961 if (objspace->rgengc.during_minor_gc && objspace->profile.count - objspace->rgengc.last_major_gc > 2 /* magic number */) {
2962 objspace->rgengc.need_major_gc = GPR_FLAG_MAJOR_BY_NOFREE;
2963 }
2964 else {
2965 heap_set_increment(objspace, (heap_pages_min_free_slots - heap_pages_swept_slots) / HEAP_OBJ_LIMIT);
2966 heap_increment(objspace, heap);
2967 }
2968 #else
2969 heap_set_increment(objspace, (heap_pages_min_free_slots - heap_pages_swept_slots) / HEAP_OBJ_LIMIT);
2970 heap_increment(objspace, heap);
2971 #endif
2972 }
2973
2974 gc_prof_set_heap_info(objspace);
2975
2976 heap_pages_free_unused_pages(objspace);
2977
2978 /* if heap_pages has unused pages, then assign them to increment */
2979 if (heap_pages_increment < heap_tomb->page_length) {
2980 heap_pages_increment = heap_tomb->page_length;
2981 }
2982
2983 #if RGENGC_PROFILE > 0
2984 if (0) {
2985 fprintf(stderr, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
2986 (int)rb_gc_count(),
2987 (int)objspace->profile.major_gc_count,
2988 (int)objspace->profile.minor_gc_count,
2989 (int)objspace->profile.promote_infant_count,
2990 #if RGENGC_THREEGEN
2991 (int)objspace->profile.promote_young_count,
2992 #else
2993 0,
2994 #endif
2995 (int)objspace->profile.remembered_normal_object_count,
2996 (int)objspace->rgengc.remembered_shady_object_count);
2997 }
2998 #endif
2999
3000 gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_END_SWEEP, 0);
3001 }
3002
3003 static int
3004 gc_heap_lazy_sweep(rb_objspace_t *objspace, rb_heap_t *heap)
3005 {
3006 struct heap_page *page = heap->sweep_pages, *next;
3007 int result = FALSE;
3008
3009 if (page == NULL) return FALSE;
3010
3011 #if GC_ENABLE_LAZY_SWEEP
3012 gc_prof_sweep_timer_start(objspace);
3013 #endif
3014
3015 while (page) {
3016 heap->sweep_pages = next = page->next;
3017
3018 gc_page_sweep(objspace, heap, page);
3019
3020 if (!next) gc_after_sweep(objspace);
3021
3022 if (heap->free_pages) {
3023 result = TRUE;
3024 break;
3025 }
3026
3027 page = next;
3028 }
3029
3030 #if GC_ENABLE_LAZY_SWEEP
3031 gc_prof_sweep_timer_stop(objspace);
3032 #endif
3033
3034 return result;
3035 }
3036
3037 static void
3038 gc_heap_rest_sweep(rb_objspace_t *objspace, rb_heap_t *heap)
3039 {
3040 if (is_lazy_sweeping(heap)) {
3041 during_gc++;
3042 while (is_lazy_sweeping(heap)) {
3043 gc_heap_lazy_sweep(objspace, heap);
3044 }
3045 during_gc = 0;
3046 }
3047 }
3048
3049 static void
3050 gc_rest_sweep(rb_objspace_t *objspace)
3051 {
3052 rb_heap_t *heap = heap_eden; /* lazy sweep only for eden */
3053 gc_heap_rest_sweep(objspace, heap);
3054 }
3055
3056 static void
3057 gc_sweep(rb_objspace_t *objspace, int immediate_sweep)
3058 {
3059 if (immediate_sweep) {
3060 #if !GC_ENABLE_LAZY_SWEEP
3061 gc_prof_sweep_timer_start(objspace);
3062 #endif
3063 gc_before_sweep(objspace);
3064 gc_heap_rest_sweep(objspace, heap_eden);
3065 #if !GC_ENABLE_LAZY_SWEEP
3066 gc_prof_sweep_timer_stop(objspace);
3067 #endif
3068 }
3069 else {
3070 struct heap_page *page;
3071 gc_before_sweep(objspace);
3072 page = heap_eden->sweep_pages;
3073 while (page) {
3074 page->before_sweep = 1;
3075 page = page->next;
3076 }
3077 gc_heap_lazy_sweep(objspace, heap_eden);
3078 }
3079
3080 gc_heap_prepare_minimum_pages(objspace, heap_eden);
3081 }
3082
3083 /* Marking - Marking stack */
3084
3085 static void push_mark_stack(mark_stack_t *, VALUE);
3086 static int pop_mark_stack(mark_stack_t *, VALUE *);
3087 static void shrink_stack_chunk_cache(mark_stack_t *stack);
3088
3089 static stack_chunk_t *
3090 stack_chunk_alloc(void)
3091 {
3092 stack_chunk_t *res;
3093
3094 res = malloc(sizeof(stack_chunk_t));
3095 if (!res)
3096 rb_memerror();
3097
3098 return res;
3099 }
3100
3101 static inline int
3102 is_mark_stack_empty(mark_stack_t *stack)
3103 {
3104 return stack->chunk == NULL;
3105 }
3106
3107 static void
3108 add_stack_chunk_cache(mark_stack_t *stack, stack_chunk_t *chunk)
3109 {
3110 chunk->next = stack->cache;
3111 stack->cache = chunk;
3112 stack->cache_size++;
3113 }
3114
3115 static void
3116 shrink_stack_chunk_cache(mark_stack_t *stack)
3117 {
3118 stack_chunk_t *chunk;
3119
3120 if (stack->unused_cache_size > (stack->cache_size/2)) {
3121 chunk = stack->cache;
3122 stack->cache = stack->cache->next;
3123 stack->cache_size--;
3124 free(chunk);
3125 }
3126 stack->unused_cache_size = stack->cache_size;
3127 }
3128
3129 static void
3130 push_mark_stack_chunk(mark_stack_t *stack)
3131 {
3132 stack_chunk_t *next;
3133
3134 assert(stack->index == stack->limit);
3135 if (stack->cache_size > 0) {
3136 next = stack->cache;
3137 stack->cache = stack->cache->next;
3138 stack->cache_size--;
3139 if (stack->unused_cache_size > stack->cache_size)
3140 stack->unused_cache_size = stack->cache_size;
3141 }
3142 else {
3143 next = stack_chunk_alloc();
3144 }
3145 next->next = stack->chunk;
3146 stack->chunk = next;
3147 stack->index = 0;
3148 }
3149
3150 static void
3151 pop_mark_stack_chunk(mark_stack_t *stack)
3152 {
3153 stack_chunk_t *prev;
3154
3155 prev = stack->chunk->next;
3156 assert(stack->index == 0);
3157 add_stack_chunk_cache(stack, stack->chunk);
3158 stack->chunk = prev;
3159 stack->index = stack->limit;
3160 }
3161
3162 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
3163 static void
3164 free_stack_chunks(mark_stack_t *stack)
3165 {
3166 stack_chunk_t *chunk = stack->chunk;
3167 stack_chunk_t *next = NULL;
3168
3169 while (chunk != NULL) {
3170 next = chunk->next;
3171 free(chunk);
3172 chunk = next;
3173 }
3174 }
3175 #endif
3176
3177 static void
3178 push_mark_stack(mark_stack_t *stack, VALUE data)
3179 {
3180 if (stack->index == stack->limit) {
3181 push_mark_stack_chunk(stack);
3182 }
3183 stack->chunk->data[stack->index++] = data;
3184 }
3185
3186 static int
3187 pop_mark_stack(mark_stack_t *stack, VALUE *data)
3188 {
3189 if (is_mark_stack_empty(stack)) {
3190 return FALSE;
3191 }
3192 if (stack->index == 1) {
3193 *data = stack->chunk->data[--stack->index];
3194 pop_mark_stack_chunk(stack);
3195 }
3196 else {
3197 *data = stack->chunk->data[--stack->index];
3198 }
3199 return TRUE;
3200 }
3201
3202 static void
3203 init_mark_stack(mark_stack_t *stack)
3204 {
3205 int i;
3206
3207 if (0) push_mark_stack_chunk(stack);
3208 stack->index = stack->limit = STACK_CHUNK_SIZE;
3209
3210 for (i=0; i < 4; i++) {
3211 add_stack_chunk_cache(stack, stack_chunk_alloc());
3212 }
3213 stack->unused_cache_size = stack->cache_size;
3214 }
3215
3216 /* Marking */
3217
3218 #ifdef __ia64
3219 #define SET_STACK_END (SET_MACHINE_STACK_END(&th->machine.stack_end), th->machine.register_stack_end = rb_ia64_bsp())
3220 #else
3221 #define SET_STACK_END SET_MACHINE_STACK_END(&th->machine.stack_end)
3222 #endif
3223
3224 #define STACK_START (th->machine.stack_start)
3225 #define STACK_END (th->machine.stack_end)
3226 #define STACK_LEVEL_MAX (th->machine.stack_maxsize/sizeof(VALUE))
3227
3228 #if STACK_GROW_DIRECTION < 0
3229 # define STACK_LENGTH (size_t)(STACK_START - STACK_END)
3230 #elif STACK_GROW_DIRECTION > 0
3231 # define STACK_LENGTH (size_t)(STACK_END - STACK_START + 1)
3232 #else
3233 # define STACK_LENGTH ((STACK_END < STACK_START) ? (size_t)(STACK_START - STACK_END) \
3234 : (size_t)(STACK_END - STACK_START + 1))
3235 #endif
3236 #if !STACK_GROW_DIRECTION
3237 int ruby_stack_grow_direction;
3238 int
3239 ruby_get_stack_grow_direction(volatile VALUE *addr)
3240 {
3241 VALUE *end;
3242 SET_MACHINE_STACK_END(&end);
3243
3244 if (end > addr) return ruby_stack_grow_direction = 1;
3245 return ruby_stack_grow_direction = -1;
3246 }
3247 #endif
3248
3249 size_t
3250 ruby_stack_length(VALUE **p)
3251 {
3252 rb_thread_t *th = GET_THREAD();
3253 SET_STACK_END;
3254 if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END);
3255 return STACK_LENGTH;
3256 }
3257
3258 #if !(defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK))
3259 static int
3260 stack_check(int water_mark)
3261 {
3262 int ret;
3263 rb_thread_t *th = GET_THREAD();
3264 SET_STACK_END;
3265 ret = STACK_LENGTH > STACK_LEVEL_MAX - water_mark;
3266 #ifdef __ia64
3267 if (!ret) {
3268 ret = (VALUE*)rb_ia64_bsp() - th->machine.register_stack_start >
3269 th->machine.register_stack_maxsize/sizeof(VALUE) - water_mark;
3270 }
3271 #endif
3272 return ret;
3273 }
3274 #endif
3275
3276 #define STACKFRAME_FOR_CALL_CFUNC 512
3277
3278 int
3279 ruby_stack_check(void)
3280 {
3281 #if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK)
3282 return 0;
3283 #else
3284 return stack_check(STACKFRAME_FOR_CALL_CFUNC);
3285 #endif
3286 }
3287
3288 ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
3289 static void
3290 mark_locations_array(rb_objspace_t *objspace, register VALUE *x, register long n)
3291 {
3292 VALUE v;
3293 while (n--) {
3294 v = *x;
3295 gc_mark_maybe(objspace, v);
3296 x++;
3297 }
3298 }
3299
3300 static void
3301 gc_mark_locations(rb_objspace_t *objspace, VALUE *start, VALUE *end)
3302 {
3303 long n;
3304
3305 if (end <= start) return;
3306 n = end - start;
3307 mark_locations_array(objspace, start, n);
3308 }
3309
3310 void
3311 rb_gc_mark_locations(VALUE *start, VALUE *end)
3312 {
3313 gc_mark_locations(&rb_objspace, start, end);
3314 }
3315
3316 #define rb_gc_mark_locations(start, end) gc_mark_locations(objspace, (start), (end))
3317
3318 struct mark_tbl_arg {
3319 rb_objspace_t *objspace;
3320 };
3321
3322 static int
3323 mark_entry(st_data_t key, st_data_t value, st_data_t data)
3324 {
3325 struct mark_tbl_arg *arg = (void*)data;
3326 gc_mark(arg->objspace, (VALUE)value);
3327 return ST_CONTINUE;
3328 }
3329
3330 static void
3331 mark_tbl(rb_objspace_t *objspace, st_table *tbl)
3332 {
3333 struct mark_tbl_arg arg;
3334 if (!tbl || tbl->num_entries == 0) return;
3335 arg.objspace = objspace;
3336 st_foreach(tbl, mark_entry, (st_data_t)&arg);
3337 }
3338
3339 static int
3340 mark_key(st_data_t key, st_data_t value, st_data_t data)
3341 {
3342 struct mark_tbl_arg *arg = (void*)data;
3343 gc_mark(arg->objspace, (VALUE)key);
3344 return ST_CONTINUE;
3345 }
3346
3347 static void
3348 mark_set(rb_objspace_t *objspace, st_table *tbl)
3349 {
3350 struct mark_tbl_arg arg;
3351 if (!tbl) return;
3352 arg.objspace = objspace;
3353 st_foreach(tbl, mark_key, (st_data_t)&arg);
3354 }
3355
3356 void
3357 rb_mark_set(st_table *tbl)
3358 {
3359 mark_set(&rb_objspace, tbl);
3360 }
3361
3362 static int
3363 mark_keyvalue(st_data_t key, st_data_t value, st_data_t data)
3364 {
3365 struct mark_tbl_arg *arg = (void*)data;
3366 gc_mark(arg->objspace, (VALUE)key);
3367 gc_mark(arg->objspace, (VALUE)value);
3368 return ST_CONTINUE;
3369 }
3370
3371 static void
3372 mark_hash(rb_objspace_t *objspace, st_table *tbl)
3373 {
3374 struct mark_tbl_arg arg;
3375 if (!tbl) return;
3376 arg.objspace = objspace;
3377 st_foreach(tbl, mark_keyvalue, (st_data_t)&arg);
3378 }
3379
3380 void
3381 rb_mark_hash(st_table *tbl)
3382 {
3383 mark_hash(&rb_objspace, tbl);
3384 }
3385
3386 static void
3387 mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
3388 {
3389 const rb_method_definition_t *def = me->def;
3390
3391 gc_mark(objspace, me->klass);
3392 again:
3393 if (!def) return;
3394 switch (def->type) {
3395 case VM_METHOD_TYPE_ISEQ:
3396 gc_mark(objspace, def->body.iseq->self);
3397 break;
3398 case VM_METHOD_TYPE_BMETHOD:
3399 gc_mark(objspace, def->body.proc);
3400 break;
3401 case VM_METHOD_TYPE_ATTRSET:
3402 case VM_METHOD_TYPE_IVAR:
3403 gc_mark(objspace, def->body.attr.location);
3404 break;
3405 case VM_METHOD_TYPE_REFINED:
3406 if (def->body.orig_me) {
3407 def = def->body.orig_me->def;
3408 goto again;
3409 }
3410 break;
3411 default:
3412 break; /* ignore */
3413 }
3414 }
3415
3416 void
3417 rb_mark_method_entry(const rb_method_entry_t *me)
3418 {
3419 mark_method_entry(&rb_objspace, me);
3420 }
3421
3422 static int
3423 mark_method_entry_i(ID key, const rb_method_entry_t *me, st_data_t data)
3424 {
3425 struct mark_tbl_arg *arg = (void*)data;
3426 mark_method_entry(arg->objspace, me);
3427 return ST_CONTINUE;
3428 }
3429
3430 static void
3431 mark_m_tbl_wrapper(rb_objspace_t *objspace, struct method_table_wrapper *wrapper)
3432 {
3433 struct mark_tbl_arg arg;
3434 if (!wrapper || !wrapper->tbl) return;
3435 if (LIKELY(objspace->mark_func_data == 0)) {
3436 /* prevent multiple marking during same GC cycle,
3437 * since m_tbl is shared between several T_ICLASS */
3438 size_t serial = rb_gc_count();
3439 if (wrapper->serial == serial) return;
3440 wrapper->serial = serial;
3441 }
3442 arg.objspace = objspace;
3443 st_foreach(wrapper->tbl, mark_method_entry_i, (st_data_t)&arg);
3444 }
3445
3446 static int
3447 mark_const_entry_i(ID key, const rb_const_entry_t *ce, st_data_t data)
3448 {
3449 struct mark_tbl_arg *arg = (void*)data;
3450 gc_mark(arg->objspace, ce->value);
3451 gc_mark(arg->objspace, ce->file);
3452 return ST_CONTINUE;
3453 }
3454
3455 static void
3456 mark_const_tbl(rb_objspace_t *objspace, st_table *tbl)
3457 {
3458 struct mark_tbl_arg arg;
3459 if (!tbl) return;
3460 arg.objspace = objspace;
3461 st_foreach(tbl, mark_const_entry_i, (st_data_t)&arg);
3462 }
3463
3464 #if STACK_GROW_DIRECTION < 0
3465 #define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_END, (end) = STACK_START)
3466 #elif STACK_GROW_DIRECTION > 0
3467 #define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_START, (end) = STACK_END+(appendix))
3468 #else
3469 #define GET_STACK_BOUNDS(start, end, appendix) \
3470 ((STACK_END < STACK_START) ? \
3471 ((start) = STACK_END, (end) = STACK_START) : ((start) = STACK_START, (end) = STACK_END+(appendix)))
3472 #endif
3473
3474 static void
3475 mark_current_machine_context(rb_objspace_t *objspace, rb_thread_t *th)
3476 {
3477 union {
3478 rb_jmp_buf j;
3479 VALUE v[sizeof(rb_jmp_buf) / sizeof(VALUE)];
3480 } save_regs_gc_mark;
3481 VALUE *stack_start, *stack_end;
3482
3483 FLUSH_REGISTER_WINDOWS;
3484 /* This assumes that all registers are saved into the jmp_buf (and stack) */
3485 rb_setjmp(save_regs_gc_mark.j);
3486
3487 /* SET_STACK_END must be called in this function because
3488 * the stack frame of this function may contain
3489 * callee save registers and they should be marked. */
3490 SET_STACK_END;
3491 GET_STACK_BOUNDS(stack_start, stack_end, 1);
3492
3493 mark_locations_array(objspace, save_regs_gc_mark.v, numberof(save_regs_gc_mark.v));
3494
3495 rb_gc_mark_locations(stack_start, stack_end);
3496 #ifdef __ia64
3497 rb_gc_mark_locations(th->machine.register_stack_start, th->machine.register_stack_end);
3498 #endif
3499 #if defined(__mc68000__)
3500 mark_locations_array(objspace, (VALUE*)((char*)STACK_END + 2),
3501 (STACK_START - STACK_END));
3502 #endif
3503 }
3504
3505 void
3506 rb_gc_mark_machine_stack(rb_thread_t *th)
3507 {
3508 rb_objspace_t *objspace = &rb_objspace;
3509 VALUE *stack_start, *stack_end;
3510
3511 GET_STACK_BOUNDS(stack_start, stack_end, 0);
3512 rb_gc_mark_locations(stack_start, stack_end);
3513 #ifdef __ia64
3514 rb_gc_mark_locations(th->machine.register_stack_start, th->machine.register_stack_end);
3515 #endif
3516 }
3517
3518 void
3519 rb_mark_tbl(st_table *tbl)
3520 {
3521 mark_tbl(&rb_objspace, tbl);
3522 }
3523
3524 static void
3525 gc_mark_maybe(rb_objspace_t *objspace, VALUE obj)
3526 {
3527 (void)VALGRIND_MAKE_MEM_DEFINED(&obj, sizeof(obj));
3528 if (is_pointer_to_heap(objspace, (void *)obj)) {
3529 int type = BUILTIN_TYPE(obj);
3530 if (type != T_ZOMBIE && type != T_NONE) {
3531 gc_mark(objspace, obj);
3532 }
3533 }
3534 }
3535
3536 void
3537 rb_gc_mark_maybe(VALUE obj)
3538 {
3539 gc_mark_maybe(&rb_objspace, obj);
3540 }
3541
3542 static inline int
3543 gc_marked(rb_objspace_t *objspace, VALUE ptr)
3544 {
3545 register bits_t *bits = GET_HEAP_MARK_BITS(ptr);
3546 if (MARKED_IN_BITMAP(bits, ptr)) return 1;
3547 return 0;
3548 }
3549
3550 static inline int
3551 gc_mark_ptr(rb_objspace_t *objspace, VALUE ptr)
3552 {
3553 register bits_t *bits = GET_HEAP_MARK_BITS(ptr);
3554 if (gc_marked(objspace, ptr)) return 0;
3555 MARK_IN_BITMAP(bits, ptr);
3556 return 1;
3557 }
3558
3559 static void
3560 rgengc_check_relation(rb_objspace_t *objspace, VALUE obj)
3561 {
3562 #if USE_RGENGC
3563 if (objspace->rgengc.parent_object_is_old) {
3564 if (!RVALUE_WB_PROTECTED(obj)) {
3565 if (rgengc_remember(objspace, obj)) {
3566 objspace->rgengc.remembered_shady_object_count++;
3567 }
3568 }
3569 #if RGENGC_THREEGEN
3570 else {
3571 if (gc_marked(objspace, obj)) {
3572 if (!RVALUE_OLD_P(obj)) {
3573 /* An object pointed from an OLD object should be OLD. */
3574 rgengc_remember(objspace, obj);
3575 }
3576 }
3577 else {
3578 if (RVALUE_INFANT_P(obj)) {
3579 RVALUE_PROMOTE_INFANT(obj);
3580 }
3581 }
3582 }
3583 #endif
3584 }
3585 #endif
3586 }
3587
3588 static void
3589 gc_mark(rb_objspace_t *objspace, VALUE ptr)
3590 {
3591 if (!is_markable_object(objspace, ptr)) return;
3592
3593 if (LIKELY(objspace->mark_func_data == 0)) {
3594 rgengc_check_relation(objspace, ptr);
3595 if (!gc_mark_ptr(objspace, ptr)) return; /* already marked */
3596 push_mark_stack(&objspace->mark_stack, ptr);
3597 }
3598 else {
3599 objspace->mark_func_data->mark_func(ptr, objspace->mark_func_data->data);
3600 }
3601 }
3602
3603 void
3604 rb_gc_mark(VALUE ptr)
3605 {
3606 gc_mark(&rb_objspace, ptr);
3607 }
3608
3609 /* resurrect non-marked `obj' if obj is before swept */
3610
3611 void
3612 rb_gc_resurrect(VALUE obj)
3613 {
3614 rb_objspace_t *objspace = &rb_objspace;
3615
3616 if (is_lazy_sweeping(heap_eden) &&
3617 !gc_marked(objspace, obj) &&
3618 !is_swept_object(objspace, obj)) {
3619 gc_mark_ptr(objspace, obj);
3620 }
3621 }
3622
3623 static void
3624 gc_mark_children(rb_objspace_t *objspace, VALUE ptr)
3625 {
3626 register RVALUE *obj = RANY(ptr);
3627
3628 goto marking; /* skip */
3629
3630 again:
3631 if (LIKELY(objspace->mark_func_data == 0)) {
3632 obj = RANY(ptr);
3633 if (!is_markable_object(objspace, ptr)) return;
3634 rgengc_check_relation(objspace, ptr);
3635 if (!gc_mark_ptr(objspace, ptr)) return; /* already marked */
3636 }
3637 else {
3638 gc_mark(objspace, ptr);
3639 return;
3640 }
3641
3642 marking:
3643
3644 #if USE_RGENGC
3645 check_gen_consistency((VALUE)obj);
3646
3647 if (LIKELY(objspace->mark_func_data == 0)) {
3648 /* minor/major common */
3649 if (RVALUE_WB_PROTECTED(obj)) {
3650 if (RVALUE_INFANT_P((VALUE)obj)) {
3651 /* infant -> young */
3652 RVALUE_PROMOTE_INFANT((VALUE)obj);
3653 #if RGENGC_THREEGEN
3654 /* infant -> young */
3655 objspace->rgengc.young_object_count++;
3656 objspace->rgengc.parent_object_is_old = FALSE;
3657 #else
3658 /* infant -> old */
3659 objspace->rgengc.old_object_count++;
3660 objspace->rgengc.parent_object_is_old = TRUE;
3661 #endif
3662 rgengc_report(3, objspace, "gc_mark_children: promote infant -> young %p (%s).\n", (void *)obj, obj_type_name((VALUE)obj));
3663 }
3664 else {
3665 objspace->rgengc.parent_object_is_old = TRUE;
3666
3667 #if RGENGC_THREEGEN
3668 if (RVALUE_YOUNG_P((VALUE)obj)) {
3669 /* young -> old */
3670 RVALUE_PROMOTE_YOUNG((VALUE)obj);
3671 objspace->rgengc.old_object_count++;
3672 rgengc_report(3, objspace, "gc_mark_children: promote young -> old %p (%s).\n", (void *)obj, obj_type_name((VALUE)obj));
3673 }
3674 else {
3675 #endif
3676 if (!objspace->rgengc.during_minor_gc) {
3677 /* major/full GC */
3678 objspace->rgengc.old_object_count++;
3679 }
3680 #if RGENGC_THREEGEN
3681 }
3682 #endif
3683 }
3684 }
3685 else {
3686 rgengc_report(3, objspace, "gc_mark_children: do not promote non-WB-protected %p (%s).\n", (void *)obj, obj_type_name((VALUE)obj));
3687 objspace->rgengc.parent_object_is_old = FALSE;
3688 }
3689 }
3690
3691 check_gen_consistency((VALUE)obj);
3692 #endif /* USE_RGENGC */
3693
3694 if (FL_TEST(obj, FL_EXIVAR)) {
3695 rb_mark_generic_ivar(ptr);
3696 }
3697
3698 switch (BUILTIN_TYPE(obj)) {
3699 case T_NIL:
3700 case T_FIXNUM:
3701 rb_bug("rb_gc_mark() called for broken object");
3702 break;
3703
3704 case T_NODE:
3705 switch (nd_type(obj)) {
3706 case NODE_IF: /* 1,2,3 */
3707 case NODE_FOR:
3708 case NODE_ITER:
3709 case NODE_WHEN:
3710 case NODE_MASGN:
3711 case NODE_RESCUE:
3712 case NODE_RESBODY:
3713 case NODE_CLASS:
3714 case NODE_BLOCK_PASS:
3715 gc_mark(objspace, (VALUE)obj->as.node.u2.node);
3716 /* fall through */
3717 case NODE_BLOCK: /* 1,3 */
3718 case NODE_ARRAY:
3719 case NODE_DSTR:
3720 case NODE_DXSTR:
3721 case NODE_DREGX:
3722 case NODE_DREGX_ONCE:
3723 case NODE_ENSURE:
3724 case NODE_CALL:
3725 case NODE_DEFS:
3726 case NODE_OP_ASGN1:
3727 gc_mark(objspace, (VALUE)obj->as.node.u1.node);
3728 /* fall through */
3729 case NODE_SUPER: /* 3 */
3730 case NODE_FCALL:
3731 case NODE_DEFN:
3732 case NODE_ARGS_AUX:
3733 ptr = (VALUE)obj->as.node.u3.node;
3734 goto again;
3735
3736 case NODE_WHILE: /* 1,2 */
3737 case NODE_UNTIL:
3738 case NODE_AND:
3739 case NODE_OR:
3740 case NODE_CASE:
3741 case NODE_SCLASS:
3742 case NODE_DOT2:
3743 case NODE_DOT3:
3744 case NODE_FLIP2:
3745 case NODE_FLIP3:
3746 case NODE_MATCH2:
3747 case NODE_MATCH3:
3748 case NODE_OP_ASGN_OR:
3749 case NODE_OP_ASGN_AND:
3750 case NODE_MODULE:
3751 case NODE_ALIAS:
3752 case NODE_VALIAS:
3753 case NODE_ARGSCAT:
3754 gc_mark(objspace, (VALUE)obj->as.node.u1.node);
3755 /* fall through */
3756 case NODE_GASGN: /* 2 */
3757 case NODE_LASGN:
3758 case NODE_DASGN:
3759 case NODE_DASGN_CURR:
3760 case NODE_IASGN:
3761 case NODE_IASGN2:
3762 case NODE_CVASGN:
3763 case NODE_COLON3:
3764 case NODE_OPT_N:
3765 case NODE_EVSTR:
3766 case NODE_UNDEF:
3767 case NODE_POSTEXE:
3768 ptr = (VALUE)obj->as.node.u2.node;
3769 goto again;
3770
3771 case NODE_HASH: /* 1 */
3772 case NODE_LIT:
3773 case NODE_STR:
3774 case NODE_XSTR:
3775 case NODE_DEFINED:
3776 case NODE_MATCH:
3777 case NODE_RETURN:
3778 case NODE_BREAK:
3779 case NODE_NEXT:
3780 case NODE_YIELD:
3781 case NODE_COLON2:
3782 case NODE_SPLAT:
3783 case NODE_TO_ARY:
3784 ptr = (VALUE)obj->as.node.u1.node;
3785 goto again;
3786
3787 case NODE_SCOPE: /* 2,3 */
3788 case NODE_CDECL:
3789 case NODE_OPT_ARG:
3790 gc_mark(objspace, (VALUE)obj->as.node.u3.node);
3791 ptr = (VALUE)obj->as.node.u2.node;
3792 goto again;
3793
3794 case NODE_ARGS: /* custom */
3795 {
3796 struct rb_args_info *args = obj->as.node.u3.args;
3797 if (args) {
3798 if (args->pre_init) gc_mark(objspace, (VALUE)args->pre_init);
3799 if (args->post_init) gc_mark(objspace, (VALUE)args->post_init);
3800 if (args->opt_args) gc_mark(objspace, (VALUE)args->opt_args);
3801 if (args->kw_args) gc_mark(objspace, (VALUE)args->kw_args);
3802 if (args->kw_rest_arg) gc_mark(objspace, (VALUE)args->kw_rest_arg);
3803 }
3804 }
3805 ptr = (VALUE)obj->as.node.u2.node;
3806 goto again;
3807
3808 case NODE_ZARRAY: /* - */
3809 case NODE_ZSUPER:
3810 case NODE_VCALL:
3811 case NODE_GVAR:
3812 case NODE_LVAR:
3813 case NODE_DVAR:
3814 case NODE_IVAR:
3815 case NODE_CVAR:
3816 case NODE_NTH_REF:
3817 case NODE_BACK_REF:
3818 case NODE_REDO:
3819 case NODE_RETRY:
3820 case NODE_SELF:
3821 case NODE_NIL:
3822 case NODE_TRUE:
3823 case NODE_FALSE:
3824 case NODE_ERRINFO:
3825 case NODE_BLOCK_ARG:
3826 break;
3827 case NODE_ALLOCA:
3828 mark_locations_array(objspace,
3829 (VALUE*)obj->as.node.u1.value,
3830 obj->as.node.u3.cnt);
3831 gc_mark(objspace, (VALUE)obj->as.node.u2.node);
3832 break;
3833
3834 case NODE_CREF:
3835 gc_mark(objspace, obj->as.node.nd_refinements);
3836 gc_mark(objspace, (VALUE)obj->as.node.nd_clss);
3837 ptr = (VALUE)obj->as.node.nd_next;
3838 goto again;
3839
3840 default: /* unlisted NODE */
3841 gc_mark_maybe(objspace, (VALUE)obj->as.node.u1.node);
3842 gc_mark_maybe(objspace, (VALUE)obj->as.node.u2.node);
3843 gc_mark_maybe(objspace, (VALUE)obj->as.node.u3.node);
3844 }
3845 return; /* no need to mark class. */
3846 }
3847
3848 gc_mark(objspace, obj->as.basic.klass);
3849 switch (BUILTIN_TYPE(obj)) {
3850 case T_ICLASS:
3851 case T_CLASS:
3852 case T_MODULE:
3853 mark_m_tbl_wrapper(objspace, RCLASS_M_TBL_WRAPPER(obj));
3854 if (!RCLASS_EXT(obj)) break;
3855 mark_tbl(objspace, RCLASS_IV_TBL(obj));
3856 mark_const_tbl(objspace, RCLASS_CONST_TBL(obj));
3857 ptr = RCLASS_SUPER((VALUE)obj);
3858 goto again;
3859
3860 case T_ARRAY:
3861 if (FL_TEST(obj, ELTS_SHARED)) {
3862 ptr = obj->as.array.as.heap.aux.shared;
3863 goto again;
3864 }
3865 else {
3866 long i, len = RARRAY_LEN(obj);
3867 const VALUE *ptr = RARRAY_CONST_PTR(obj);
3868 for (i=0; i < len; i++) {
3869 gc_mark(objspace, *ptr++);
3870 }
3871 }
3872 break;
3873
3874 case T_HASH:
3875 mark_hash(objspace, obj->as.hash.ntbl);
3876 ptr = obj->as.hash.ifnone;
3877 goto again;
3878
3879 case T_STRING:
3880 #define STR_ASSOC FL_USER3 /* copied from string.c */
3881 if (FL_TEST(obj, RSTRING_NOEMBED) && FL_ANY(obj, ELTS_SHARED|STR_ASSOC)) {
3882 ptr = obj->as.string.as.heap.aux.shared;
3883 goto again;
3884 }
3885 break;
3886
3887 case T_DATA:
3888 if (RTYPEDDATA_P(obj)) {
3889 RUBY_DATA_FUNC mark_func = obj->as.typeddata.type->function.dmark;
3890 if (mark_func) (*mark_func)(DATA_PTR(obj));
3891 }
3892 else {
3893 if (obj->as.data.dmark) (*obj->as.data.dmark)(DATA_PTR(obj));
3894 }
3895 break;
3896
3897 case T_OBJECT:
3898 {
3899 long i, len = ROBJECT_NUMIV(obj);
3900 VALUE *ptr = ROBJECT_IVPTR(obj);
3901 for (i = 0; i < len; i++) {
3902 gc_mark(objspace, *ptr++);
3903 }
3904 }
3905 break;
3906
3907 case T_FILE:
3908 if (obj->as.file.fptr) {
3909 gc_mark(objspace, obj->as.file.fptr->pathv);
3910 gc_mark(objspace, obj->as.file.fptr->tied_io_for_writing);
3911 gc_mark(objspace, obj->as.file.fptr->writeconv_asciicompat);
3912 gc_mark(objspace, obj->as.file.fptr->writeconv_pre_ecopts);
3913 gc_mark(objspace, obj->as.file.fptr->encs.ecopts);
3914 gc_mark(objspace, obj->as.file.fptr->write_lock);
3915 }
3916 break;
3917
3918 case T_REGEXP:
3919 ptr = obj->as.regexp.src;
3920 goto again;
3921
3922 case T_FLOAT:
3923 case T_BIGNUM:
3924 break;
3925
3926 case T_MATCH:
3927 gc_mark(objspace, obj->as.match.regexp);
3928 if (obj->as.match.str) {
3929 ptr = obj->as.match.str;
3930 goto again;
3931 }
3932 break;
3933
3934 case T_RATIONAL:
3935 gc_mark(objspace, obj->as.rational.num);
3936 ptr = obj->as.rational.den;
3937 goto again;
3938
3939 case T_COMPLEX:
3940 gc_mark(objspace, obj->as.complex.real);
3941 ptr = obj->as.complex.imag;
3942 goto again;
3943
3944 case T_STRUCT:
3945 {
3946 long len = RSTRUCT_LEN(obj);
3947 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
3948
3949 while (len--) {
3950 gc_mark(objspace, *ptr++);
3951 }
3952 }
3953 break;
3954
3955 default:
3956 #if GC_DEBUG
3957 rb_gcdebug_print_obj_condition((VALUE)obj);
3958 #endif
3959 if (BUILTIN_TYPE(obj) == T_NONE) rb_bug("rb_gc_mark(): %p is T_NONE", (void *)obj);
3960 if (BUILTIN_TYPE(obj) == T_ZOMBIE) rb_bug("rb_gc_mark(): %p is T_ZOMBIE", (void *)obj);
3961 rb_bug("rb_gc_mark(): unknown data type 0x%x(%p) %s",
3962 BUILTIN_TYPE(obj), (void *)obj,
3963 is_pointer_to_heap(objspace, obj) ? "corrupted object" : "non object");
3964 }
3965 }
3966
3967 static void
3968 gc_mark_stacked_objects(rb_objspace_t *objspace)
3969 {
3970 mark_stack_t *mstack = &objspace->mark_stack;
3971 VALUE obj = 0;
3972
3973 if (!mstack->index) return;
3974 while (pop_mark_stack(mstack, &obj)) {
3975 if (RGENGC_CHECK_MODE > 0 && !gc_marked(objspace, obj)) {
3976 rb_bug("gc_mark_stacked_objects: %p (%s) is infant, but not marked.", (void *)obj, obj_type_name(obj));
3977 }
3978 gc_mark_children(objspace, obj);
3979 }
3980 shrink_stack_chunk_cache(mstack);
3981 }
3982
3983 #ifndef RGENGC_PRINT_TICK
3984 #define RGENGC_PRINT_TICK 0
3985 #endif
3986 /* the following code is only for internal tuning. */
3987
3988 /* Source code to use RDTSC is quoted and modified from
3989 * http://www.mcs.anl.gov/~kazutomo/rdtsc.html
3990 * written by Kazutomo Yoshii <kazutomo@mcs.anl.gov>
3991 */
3992
3993 #if RGENGC_PRINT_TICK
3994 #if defined(__GNUC__) && defined(__i386__)
3995 typedef unsigned long long tick_t;
3996
3997 static inline tick_t
3998 tick(void)
3999 {
4000 unsigned long long int x;
4001 __asm__ __volatile__ ("rdtsc" : "=A" (x));
4002 return x;
4003 }
4004
4005 #elif defined(__GNUC__) && defined(__x86_64__)
4006 typedef unsigned long long tick_t;
4007
4008 static __inline__ tick_t
4009 tick(void)
4010 {
4011 unsigned long hi, lo;
4012 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
4013 return ((unsigned long long)lo)|( ((unsigned long long)hi)<<32);
4014 }
4015
4016 #elif defined(_WIN32) && defined(_MSC_VER)
4017 #include <intrin.h>
4018 typedef unsigned __int64 tick_t;
4019
4020 static inline tick_t
4021 tick(void)
4022 {
4023 return __rdtsc();
4024 }
4025
4026 #else /* use clock */
4027 typedef clock_t tick_t;
4028 static inline tick_t
4029 tick(void)
4030 {
4031 return clock();
4032 }
4033 #endif
4034
4035 #define MAX_TICKS 0x100
4036 static tick_t mark_ticks[MAX_TICKS];
4037 static const char *mark_ticks_categories[MAX_TICKS];
4038
4039 static void
4040 show_mark_ticks(void)
4041 {
4042 int i;
4043 fprintf(stderr, "mark ticks result:\n");
4044 for (i=0; i<MAX_TICKS; i++) {
4045 const char *category = mark_ticks_categories[i];
4046 if (category) {
4047 fprintf(stderr, "%s\t%8lu\n", category, (unsigned long)mark_ticks[i]);
4048 }
4049 else {
4050 break;
4051 }
4052 }
4053 }
4054
4055 #endif /* RGENGC_PRINT_TICK */
4056
4057 static void
4058 gc_mark_roots(rb_objspace_t *objspace, int full_mark, const char **categoryp)
4059 {
4060 struct gc_list *list;
4061 rb_thread_t *th = GET_THREAD();
4062 if (categoryp) *categoryp = "xxx";
4063
4064 #if RGENGC_PRINT_TICK
4065 tick_t start_tick = tick();
4066 int tick_count = 0;
4067 const char *prev_category = 0;
4068
4069 if (mark_ticks_categories[0] == 0) {
4070 atexit(show_mark_ticks);
4071 }
4072 #endif
4073
4074 #if RGENGC_PRINT_TICK
4075 #define MARK_CHECKPOINT_PRINT_TICK(category) do { \
4076 if (prev_category) { \
4077 tick_t t = tick(); \
4078 mark_ticks[tick_count] = t - start_tick; \
4079 mark_ticks_categories[tick_count] = prev_category; \
4080 tick_count++; \
4081 } \
4082 prev_category = category; \
4083 start_tick = tick(); \
4084 } while (0)
4085 #else /* RGENGC_PRINT_TICK */
4086 #define MARK_CHECKPOINT_PRINT_TICK(category)
4087 #endif
4088
4089 #define MARK_CHECKPOINT(category) do { \
4090 if (categoryp) *categoryp = category; \
4091 MARK_CHECKPOINT_PRINT_TICK(category); \
4092 } while (0)
4093
4094 MARK_CHECKPOINT("vm");
4095 SET_STACK_END;
4096 th->vm->self ? rb_gc_mark(th->vm->self) : rb_vm_mark(th->vm);
4097
4098 MARK_CHECKPOINT("finalizers");
4099 mark_tbl(objspace, finalizer_table);
4100
4101 MARK_CHECKPOINT("machine_context");
4102 mark_current_machine_context(objspace, th);
4103
4104 MARK_CHECKPOINT("symbols");
4105 #if USE_RGENGC
4106 objspace->rgengc.parent_object_is_old = TRUE;
4107 rb_gc_mark_symbols(full_mark);
4108 objspace->rgengc.parent_object_is_old = FALSE;
4109 #else
4110 rb_gc_mark_symbols(full_mark);
4111 #endif
4112
4113 MARK_CHECKPOINT("encodings");
4114 rb_gc_mark_encodings();
4115
4116 /* mark protected global variables */
4117 MARK_CHECKPOINT("global_list");
4118 for (list = global_List; list; list = list->next) {
4119 rb_gc_mark_maybe(*list->varptr);
4120 }
4121
4122 MARK_CHECKPOINT("end_proc");
4123 rb_mark_end_proc();
4124
4125 MARK_CHECKPOINT("global_tbl");
4126 rb_gc_mark_global_tbl();
4127
4128 /* mark generic instance variables for special constants */
4129 MARK_CHECKPOINT("generic_ivars");
4130 rb_mark_generic_ivar_tbl();
4131
4132 MARK_CHECKPOINT("parser");
4133 rb_gc_mark_parser();
4134
4135 MARK_CHECKPOINT("live_method_entries");
4136 rb_gc_mark_unlinked_live_method_entries(th->vm);
4137
4138 MARK_CHECKPOINT("finish");
4139 #undef MARK_CHECKPOINT
4140 }
4141
4142 static void
4143 gc_marks_body(rb_objspace_t *objspace, int full_mark)
4144 {
4145 /* start marking */
4146 rgengc_report(1, objspace, "gc_marks_body: start (%s)\n", full_mark ? "full" : "minor");
4147
4148 #if USE_RGENGC
4149 objspace->rgengc.parent_object_is_old = FALSE;
4150 objspace->rgengc.during_minor_gc = full_mark ? FALSE : TRUE;
4151
4152 if (objspace->rgengc.during_minor_gc) {
4153 objspace->profile.minor_gc_count++;
4154 rgengc_rememberset_mark(objspace, heap_eden);
4155 }
4156 else {
4157 objspace->profile.major_gc_count++;
4158 rgengc_mark_and_rememberset_clear(objspace, heap_eden);
4159 }
4160 #endif
4161 gc_mark_roots(objspace, full_mark, 0);
4162 gc_mark_stacked_objects(objspace);
4163
4164 gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_END_MARK, 0);
4165 rgengc_report(1, objspace, "gc_marks_body: end (%s)\n", full_mark ? "full" : "minor");
4166 }
4167
4168 struct verify_internal_consistency_struct {
4169 rb_objspace_t *objspace;
4170 int err_count;
4171 VALUE parent;
4172 };
4173
4174 #if USE_RGENGC
4175 static void
4176 verify_internal_consistency_reachable_i(VALUE child, void *ptr)
4177 {
4178 struct verify_internal_consistency_struct *data = (struct verify_internal_consistency_struct *)ptr;
4179
4180 assert(RVALUE_OLD_P(data->parent));
4181
4182 if (!RVALUE_OLD_P(child)) {
4183 if (!MARKED_IN_BITMAP(GET_HEAP_PAGE(data->parent)->rememberset_bits, data->parent) &&
4184 !MARKED_IN_BITMAP(GET_HEAP_PAGE(child)->rememberset_bits, child)) {
4185 fprintf(stderr, "verify_internal_consistency_reachable_i: WB miss %p (%s) -> %p (%s)\n",
4186 (void *)data->parent, obj_type_name(data->parent),
4187 (void *)child, obj_type_name(child));
4188 data->err_count++;
4189 }
4190 }
4191 }
4192
4193 static int
4194 verify_internal_consistency_i(void *page_start, void *page_end, size_t stride, void *ptr)
4195 {
4196 struct verify_internal_consistency_struct *data = (struct verify_internal_consistency_struct *)ptr;
4197 VALUE v;
4198
4199 for (v = (VALUE)page_start; v != (VALUE)page_end; v += stride) {
4200 if (is_live_object(data->objspace, v)) {
4201 if (RVALUE_OLD_P(v)) {
4202 data->parent = v;
4203 /* reachable objects from an oldgen object should be old or (young with remember) */
4204 rb_objspace_reachable_objects_from(v, verify_internal_consistency_reachable_i, (void *)data);
4205 }
4206 }
4207 }
4208
4209 return 0;
4210 }
4211 #endif /* USE_RGENGC */
4212
4213 /*
4214 * call-seq:
4215 * GC.verify_internal_consistency -> nil
4216 *
4217 * Verify internal consistency.
4218 *
4219 * This method is implementation specific.
4220 * Now this method checks generatioanl consistency
4221 * if RGenGC is supported.
4222 */
4223 static VALUE
4224 gc_verify_internal_consistency(VALUE self)
4225 {
4226 struct verify_internal_consistency_struct data;
4227 data.objspace = &rb_objspace;
4228 data.err_count = 0;
4229
4230 #if USE_RGENGC
4231 {
4232 struct each_obj_args eo_args;
4233 eo_args.callback = verify_internal_consistency_i;
4234 eo_args.data = (void *)&data;
4235 objspace_each_objects((VALUE)&eo_args);
4236 }
4237 #endif
4238 if (data.err_count != 0) {
4239 rb_bug("gc_verify_internal_consistency: found internal consistency.\n");
4240 }
4241 return Qnil;
4242 }
4243
4244 #if RGENGC_CHECK_MODE >= 3
4245
4246 #define MAKE_ROOTSIG(obj) (((VALUE)(obj) << 1) | 0x01)
4247 #define IS_ROOTSIG(obj) ((VALUE)(obj) & 0x01)
4248 #define GET_ROOTSIG(obj) ((const char *)((VALUE)(obj) >> 1))
4249
4250 struct reflist {
4251 VALUE *list;
4252 int pos;
4253 int size;
4254 };
4255
4256 static struct reflist *
4257 reflist_create(VALUE obj)
4258 {
4259 struct reflist *refs = xmalloc(sizeof(struct reflist));
4260 refs->size = 1;
4261 refs->list = ALLOC_N(VALUE, refs->size);
4262 refs->list[0] = obj;
4263 refs->pos = 1;
4264 return refs;
4265 }
4266
4267 static void
4268 reflist_destruct(struct reflist *refs)
4269 {
4270 xfree(refs->list);
4271 xfree(refs);
4272 }
4273
4274 static void
4275 reflist_add(struct reflist *refs, VALUE obj)
4276 {
4277 if (refs->pos == refs->size) {
4278 refs->size *= 2;
4279 SIZED_REALLOC_N(refs->list, VALUE, refs->size, refs->size/2);
4280 }
4281
4282 refs->list[refs->pos++] = obj;
4283 }
4284
4285 static void
4286 reflist_dump(struct reflist *refs)
4287 {
4288 int i;
4289 for (i=0; i<refs->pos; i++) {
4290 VALUE obj = refs->list[i];
4291 if (IS_ROOTSIG(obj)) { /* root */
4292 fprintf(stderr, "<root@%s>", GET_ROOTSIG(obj));
4293 }
4294 else {
4295 fprintf(stderr, "<%p@%s>", (void *)obj, obj_type_name(obj));
4296 }
4297 if (i+1 < refs->pos) fprintf(stderr, ", ");
4298 }
4299 }
4300
4301 #if RGENGC_CHECK_MODE >= 3
4302 static int
4303 reflist_refered_from_machine_context(struct reflist *refs)
4304 {
4305 int i;
4306 for (i=0; i<refs->pos; i++) {
4307 VALUE obj = refs->list[i];
4308 if (IS_ROOTSIG(obj) && strcmp(GET_ROOTSIG(obj), "machine_context") == 0) return 1;
4309 }
4310 return 0;
4311 }
4312 #endif
4313
4314 struct allrefs {
4315 rb_objspace_t *objspace;
4316 /* a -> obj1
4317 * b -> obj1
4318 * c -> obj1
4319 * c -> obj2
4320 * d -> obj3
4321 * #=> {obj1 => [a, b, c], obj2 => [c, d]}
4322 */
4323 struct st_table *references;
4324 const char *category;
4325 VALUE root_obj;
4326 };
4327
4328 static int
4329 allrefs_add(struct allrefs *data, VALUE obj)
4330 {
4331 struct reflist *refs;
4332
4333 if (st_lookup(data->references, obj, (st_data_t *)&refs)) {
4334 reflist_add(refs, data->root_obj);
4335 return 0;
4336 }
4337 else {
4338 refs = reflist_create(data->root_obj);
4339 st_insert(data->references, obj, (st_data_t)refs);
4340 return 1;
4341 }
4342 }
4343
4344 static void
4345 allrefs_i(VALUE obj, void *ptr)
4346 {
4347 struct allrefs *data = (struct allrefs *)ptr;
4348
4349 if (allrefs_add(data, obj)) {
4350 push_mark_stack(&data->objspace->mark_stack, obj);
4351 }
4352 }
4353
4354 static void
4355 allrefs_roots_i(VALUE obj, void *ptr)
4356 {
4357 struct allrefs *data = (struct allrefs *)ptr;
4358 if (strlen(data->category) == 0) rb_bug("!!!");
4359 data->root_obj = MAKE_ROOTSIG(data->category);
4360
4361 if (allrefs_add(data, obj)) {
4362 push_mark_stack(&data->objspace->mark_stack, obj);
4363 }
4364 }
4365
4366 static st_table *
4367 objspace_allrefs(rb_objspace_t *objspace)
4368 {
4369 struct allrefs data;
4370 struct mark_func_data_struct mfd;
4371 VALUE obj;
4372
4373 data.objspace = objspace;
4374 data.references = st_init_numtable();
4375
4376 mfd.mark_func = allrefs_roots_i;
4377 mfd.data = &data;
4378
4379 /* traverse root objects */
4380 objspace->mark_func_data = &mfd;
4381 gc_mark_roots(objspace, TRUE, &data.category);
4382 objspace->mark_func_data = 0;
4383
4384 /* traverse rest objects reachable from root objects */
4385 while (pop_mark_stack(&objspace->mark_stack, &obj)) {
4386 rb_objspace_reachable_objects_from(data.root_obj = obj, allrefs_i, &data);
4387 }
4388 shrink_stack_chunk_cache(&objspace->mark_stack);
4389
4390 return data.references;
4391 }
4392
4393 static int
4394 objspaec_allrefs_destruct_i(st_data_t key, st_data_t value, void *ptr)
4395 {
4396 struct reflist *refs = (struct reflist *)value;
4397 reflist_destruct(refs);
4398 return ST_CONTINUE;
4399 }
4400
4401 static void
4402 objspace_allrefs_destruct(struct st_table *refs)
4403 {
4404 st_foreach(refs, objspaec_allrefs_destruct_i, 0);
4405 st_free_table(refs);
4406 }
4407
4408 #if RGENGC_CHECK_MODE >= 4
4409 static int
4410 allrefs_dump_i(st_data_t k, st_data_t v, st_data_t ptr)
4411 {
4412 VALUE obj = (VALUE)k;
4413 struct reflist *refs = (struct reflist *)v;
4414 fprintf(stderr, "[allrefs_dump_i] %p (%s%s%s%s) <- ",
4415 (void *)obj, obj_type_name(obj),
4416 RVALUE_OLD_P(obj) ? "[O]" : "[Y]",
4417 RVALUE_WB_PROTECTED(obj) ? "[W]" : "",
4418 MARKED_IN_BITMAP(GET_HEAP_REMEMBERSET_BITS(obj), obj) ? "[R]" : "");
4419 reflist_dump(refs);
4420 fprintf(stderr, "\n");
4421 return ST_CONTINUE;
4422 }
4423
4424 static void
4425 allrefs_dump(rb_objspace_t *objspace)
4426 {
4427 fprintf(stderr, "[all refs] (size: %d)\n", (int)objspace->rgengc.allrefs_table->num_entries);
4428 st_foreach(objspace->rgengc.allrefs_table, allrefs_dump_i, 0);
4429 }
4430 #endif
4431
4432 #if RGENGC_CHECK_MODE >= 3
4433 static int
4434 gc_check_after_marks_i(st_data_t k, st_data_t v, void *ptr)
4435 {
4436 VALUE obj = k;
4437 struct reflist *refs = (struct reflist *)v;
4438 rb_objspace_t *objspace = (rb_objspace_t *)ptr;
4439
4440 /* object should be marked or oldgen */
4441 if (!MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj)) {
4442 fprintf(stderr, "gc_check_after_marks_i: %p (%s) is not marked and not oldgen.\n", (void *)obj, obj_type_name(obj));
4443 fprintf(stderr, "gc_check_after_marks_i: %p is referred from ", (void *)obj);
4444 reflist_dump(refs);
4445
4446 if (reflist_refered_from_machine_context(refs)) {
4447 fprintf(stderr, " (marked from machine stack).\n");
4448 /* marked from machine context can be false positive */
4449 }
4450 else {
4451 objspace->rgengc.error_count++;
4452 fprintf(stderr, "\n");
4453 }
4454 }
4455 return ST_CONTINUE;
4456 }
4457 #endif
4458
4459 static void
4460 gc_marks_check(rb_objspace_t *objspace, int (*checker_func)(ANYARGS), const char *checker_name)
4461 {
4462
4463 size_t saved_malloc_increase = objspace->malloc_params.increase;
4464 #if RGENGC_ESTIMATE_OLDMALLOC
4465 size_t saved_oldmalloc_increase = objspace->rgengc.oldmalloc_increase;
4466 #endif
4467 VALUE already_disabled = rb_gc_disable();
4468
4469 objspace->rgengc.allrefs_table = objspace_allrefs(objspace);
4470 st_foreach(objspace->rgengc.allrefs_table, checker_func, (st_data_t)objspace);
4471
4472 if (objspace->rgengc.error_count > 0) {
4473 #if RGENGC_CHECK_MODE >= 4
4474 allrefs_dump(objspace);
4475 #endif
4476 rb_bug("%s: GC has problem.", checker_name);
4477 }
4478
4479 objspace_allrefs_destruct(objspace->rgengc.allrefs_table);
4480 objspace->rgengc.allrefs_table = 0;
4481
4482 if (already_disabled == Qfalse) rb_gc_enable();
4483 objspace->malloc_params.increase = saved_malloc_increase;
4484 #if RGENGC_ESTIMATE_OLDMALLOC
4485 objspace->rgengc.oldmalloc_increase = saved_oldmalloc_increase;
4486 #endif
4487 }
4488
4489 #endif /* RGENGC_CHECK_MODE >= 2 */
4490
4491 static void
4492 gc_marks(rb_objspace_t *objspace, int full_mark)
4493 {
4494 struct mark_func_data_struct *prev_mark_func_data;
4495
4496 gc_prof_mark_timer_start(objspace);
4497 {
4498 /* setup marking */
4499 prev_mark_func_data = objspace->mark_func_data;
4500 objspace->mark_func_data = 0;
4501
4502 #if USE_RGENGC
4503
4504 #if RGENGC_CHECK_MODE >= 2
4505 gc_verify_internal_consistency(Qnil);
4506 #endif
4507 if (full_mark == TRUE) { /* major/full GC */
4508 objspace->rgengc.remembered_shady_object_count = 0;
4509 objspace->rgengc.old_object_count = 0;
4510 #if RGENGC_THREEGEN
4511 objspace->rgengc.young_object_count = 0;
4512 #endif
4513
4514 gc_marks_body(objspace, TRUE);
4515 {
4516 /* See the comment about RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR */
4517 const double r = gc_params.oldobject_limit_factor;
4518 objspace->rgengc.remembered_shady_object_limit = (size_t)(objspace->rgengc.remembered_shady_object_count * r);
4519 objspace->rgengc.old_object_limit = (size_t)(objspace->rgengc.old_object_count * r);
4520 }
4521 }
4522 else { /* minor GC */
4523 gc_marks_body(objspace, FALSE);
4524 }
4525
4526 #if RGENGC_PROFILE > 0
4527 if (gc_prof_record(objspace)) {
4528 gc_profile_record *record = gc_prof_record(objspace);
4529 record->old_objects = objspace->rgengc.old_object_count;
4530 }
4531 #endif
4532
4533 #if RGENGC_CHECK_MODE >= 3
4534 gc_marks_check(objspace, gc_check_after_marks_i, "after_marks");
4535 #endif
4536
4537 #else /* USE_RGENGC */
4538 gc_marks_body(objspace, TRUE);
4539 #endif
4540
4541 objspace->mark_func_data = prev_mark_func_data;
4542 }
4543 gc_prof_mark_timer_stop(objspace);
4544 }
4545
4546 /* RGENGC */
4547
4548 static void
4549 rgengc_report_body(int level, rb_objspace_t *objspace, const char *fmt, ...)
4550 {
4551 if (level <= RGENGC_DEBUG) {
4552 char buf[1024];
4553 FILE *out = stderr;
4554 va_list args;
4555 const char *status = " ";
4556
4557 #if USE_RGENGC
4558 if (during_gc) {
4559 status = objspace->rgengc.during_minor_gc ? "-" : "+";
4560 }
4561 #endif
4562
4563 va_start(args, fmt);
4564 vsnprintf(buf, 1024, fmt, args);
4565 va_end(args);
4566
4567 fprintf(out, "%s|", status);
4568 fputs(buf, out);
4569 }
4570 }
4571
4572 #if USE_RGENGC
4573
4574 /* bit operations */
4575
4576 static int
4577 rgengc_remembersetbits_get(rb_objspace_t *objspace, VALUE obj)
4578 {
4579 bits_t *bits = GET_HEAP_REMEMBERSET_BITS(obj);
4580 return MARKED_IN_BITMAP(bits, obj) ? 1 : 0;
4581 }
4582
4583 static int
4584 rgengc_remembersetbits_set(rb_objspace_t *objspace, VALUE obj)
4585 {
4586 bits_t *bits = GET_HEAP_REMEMBERSET_BITS(obj);
4587 if (MARKED_IN_BITMAP(bits, obj)) {
4588 return FALSE;
4589 }
4590 else {
4591 MARK_IN_BITMAP(bits, obj);
4592 return TRUE;
4593 }
4594 }
4595
4596 /* wb, etc */
4597
4598 /* return FALSE if already remembered */
4599 static int
4600 rgengc_remember(rb_objspace_t *objspace, VALUE obj)
4601 {
4602 rgengc_report(2, objspace, "rgengc_remember: %p (%s, %s) %s\n", (void *)obj, obj_type_name(obj),
4603 RVALUE_WB_PROTECTED(obj) ? "WB-protected" : "non-WB-protected",
4604 rgengc_remembersetbits_get(objspace, obj) ? "was already remembered" : "is remembered now");
4605
4606 #if RGENGC_CHECK_MODE > 0
4607 {
4608 switch (BUILTIN_TYPE(obj)) {
4609 case T_NONE:
4610 case T_ZOMBIE:
4611 rb_bug("rgengc_remember: should not remember %p (%s)\n",
4612 (void *)obj, obj_type_name(obj));
4613 default:
4614 ;
4615 }
4616 }
4617 #endif
4618
4619 if (RGENGC_PROFILE) {
4620 if (!rgengc_remembered(objspace, obj)) {
4621 #if RGENGC_PROFILE > 0
4622 if (RVALUE_WB_PROTECTED(obj)) {
4623 objspace->profile.remembered_normal_object_count++;
4624 #if RGENGC_PROFILE >= 2
4625 objspace->profile.remembered_normal_object_count_types[BUILTIN_TYPE(obj)]++;
4626 #endif
4627 }
4628 else {
4629 objspace->profile.remembered_shady_object_count++;
4630 #if RGENGC_PROFILE >= 2
4631 objspace->profile.remembered_shady_object_count_types[BUILTIN_TYPE(obj)]++;
4632 #endif
4633 }
4634 #endif /* RGENGC_PROFILE > 0 */
4635 }
4636 }
4637
4638 return rgengc_remembersetbits_set(objspace, obj);
4639 }
4640
4641 static int
4642 rgengc_remembered(rb_objspace_t *objspace, VALUE obj)
4643 {
4644 int result = rgengc_remembersetbits_get(objspace, obj);
4645 check_gen_consistency(obj);
4646 rgengc_report(6, objspace, "gc_remembered: %p (%s) => %d\n", (void *)obj, obj_type_name(obj), result);
4647 return result;
4648 }
4649
4650 static void
4651 rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap)
4652 {
4653 size_t j;
4654 RVALUE *p, *offset;
4655 bits_t *bits, bitset;
4656 struct heap_page *page = heap->pages;
4657
4658 #if RGENGC_PROFILE > 0
4659 size_t shady_object_count = 0, clear_count = 0;
4660 #endif
4661
4662 while (page) {
4663 p = page->start;
4664 bits = page->rememberset_bits;
4665 offset = p - NUM_IN_PAGE(p);
4666
4667 for (j=0; j < HEAP_BITMAP_LIMIT; j++) {
4668 if (bits[j]) {
4669 p = offset + j * BITS_BITLENGTH;
4670 bitset = bits[j];
4671 do {
4672 if (bitset & 1) {
4673 /* mark before RVALUE_PROMOTE_... */
4674 gc_mark_ptr(objspace, (VALUE)p);
4675
4676 if (RVALUE_WB_PROTECTED(p)) {
4677 rgengc_report(2, objspace, "rgengc_rememberset_mark: clear %p (%s)\n", p, obj_type_name((VALUE)p));
4678 #if RGENGC_THREEGEN
4679 if (RVALUE_INFANT_P((VALUE)p)) RVALUE_PROMOTE_INFANT((VALUE)p);
4680 if (RVALUE_YOUNG_P((VALUE)p)) RVALUE_PROMOTE_YOUNG((VALUE)p);
4681 #endif
4682 CLEAR_IN_BITMAP(bits, p);
4683 #if RGENGC_PROFILE > 0
4684 clear_count++;
4685 #endif
4686 }
4687 else {
4688 #if RGENGC_PROFILE > 0
4689 shady_object_count++;
4690 #endif
4691 }
4692
4693 rgengc_report(2, objspace, "rgengc_rememberset_mark: mark %p (%s)\n", p, obj_type_name((VALUE)p));
4694 gc_mark_children(objspace, (VALUE) p);
4695 }
4696 p++;
4697 bitset >>= 1;
4698 } while (bitset);
4699 }
4700 }
4701 page = page->next;
4702 }
4703
4704 rgengc_report(2, objspace, "rgengc_rememberset_mark: finished\n");
4705
4706 #if RGENGC_PROFILE > 0
4707 rgengc_report(2, objspace, "rgengc_rememberset_mark: clear_count: %"PRIdSIZE", shady_object_count: %"PRIdSIZE"\n", clear_count, shady_object_count);
4708 if (gc_prof_record(objspace)) {
4709 gc_profile_record *record = gc_prof_record(objspace);
4710 record->remembered_normal_objects = clear_count;
4711 record->remembered_shady_objects = shady_object_count;
4712 }
4713 #endif
4714 }
4715
4716 static void
4717 rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace, rb_heap_t *heap)
4718 {
4719 struct heap_page *page = heap->pages;
4720
4721 while (page) {
4722 memset(&page->mark_bits[0], 0, HEAP_BITMAP_SIZE);
4723 memset(&page->rememberset_bits[0], 0, HEAP_BITMAP_SIZE);
4724 page = page->next;
4725 }
4726 }
4727
4728 /* RGENGC: APIs */
4729
4730 void
4731 rb_gc_writebarrier(VALUE a, VALUE b)
4732 {
4733 if (RGENGC_CHECK_MODE) {
4734 if (!RVALUE_PROMOTED_P(a)) rb_bug("rb_gc_writebarrier: referer object %p (%s) is not promoted.\n", (void *)a, obj_type_name(a));
4735 }
4736
4737 if (!RVALUE_OLD_P(b) && RVALUE_OLD_BITMAP_P(a)) {
4738 rb_objspace_t *objspace = &rb_objspace;
4739
4740 if (!rgengc_remembered(objspace, a)) {
4741 rgengc_report(2, objspace, "rb_gc_wb: %p (%s) -> %p (%s)\n",
4742 (void *)a, obj_type_name(a), (void *)b, obj_type_name(b));
4743 rgengc_remember(objspace, a);
4744 }
4745 }
4746 }
4747
4748 void
4749 rb_gc_writebarrier_unprotect_promoted(VALUE obj)
4750 {
4751 rb_objspace_t *objspace = &rb_objspace;
4752
4753 if (RGENGC_CHECK_MODE) {
4754 if (!RVALUE_PROMOTED_P(obj)) rb_bug("rb_gc_writebarrier_unprotect_promoted: called on non-promoted object");
4755 if (!RVALUE_WB_PROTECTED(obj)) rb_bug("rb_gc_writebarrier_unprotect_promoted: called on shady object");
4756 }
4757
4758 rgengc_report(0, objspace, "rb_gc_writebarrier_unprotect_promoted: %p (%s)%s\n", (void *)obj, obj_type_name(obj),
4759 rgengc_remembered(objspace, obj) ? " (already remembered)" : "");
4760
4761 if (RVALUE_OLD_P(obj)) {
4762 RVALUE_DEMOTE_FROM_OLD(obj);
4763
4764 rgengc_remember(objspace, obj);
4765 objspace->rgengc.remembered_shady_object_count++;
4766
4767 #if RGENGC_PROFILE
4768 objspace->profile.shade_operation_count++;
4769 #if RGENGC_PROFILE >= 2
4770 objspace->profile.shade_operation_count_types[BUILTIN_TYPE(obj)]++;
4771 #endif /* RGENGC_PROFILE >= 2 */
4772 #endif /* RGENGC_PROFILE */
4773 }
4774 #if RGENGC_THREEGEN
4775 else {
4776 RVALUE_DEMOTE_FROM_YOUNG(obj);
4777 }
4778 #endif
4779 }
4780
4781 void
4782 rb_gc_writebarrier_remember_promoted(VALUE obj)
4783 {
4784 rb_objspace_t *objspace = &rb_objspace;
4785 rgengc_remember(objspace, obj);
4786 }
4787
4788 static st_table *rgengc_unprotect_logging_table;
4789
4790 static int
4791 rgengc_unprotect_logging_exit_func_i(st_data_t key, st_data_t val)
4792 {
4793 fprintf(stderr, "%s\t%d\n", (char *)key, (int)val);
4794 return ST_CONTINUE;
4795 }
4796
4797 static void
4798 rgengc_unprotect_logging_exit_func(void)
4799 {
4800 st_foreach(rgengc_unprotect_logging_table, rgengc_unprotect_logging_exit_func_i, 0);
4801 }
4802
4803 void
4804 rb_gc_unprotect_logging(void *objptr, const char *filename, int line)
4805 {
4806 VALUE obj = (VALUE)objptr;
4807
4808 if (rgengc_unprotect_logging_table == 0) {
4809 rgengc_unprotect_logging_table = st_init_strtable();
4810 atexit(rgengc_unprotect_logging_exit_func);
4811 }
4812
4813 if (OBJ_WB_PROTECTED(obj)) {
4814 char buff[0x100];
4815 st_data_t cnt = 1;
4816 char *ptr = buff;
4817
4818 snprintf(ptr, 0x100 - 1, "%s|%s:%d", obj_type_name(obj), filename, line);
4819
4820 if (st_lookup(rgengc_unprotect_logging_table, (st_data_t)ptr, &cnt)) {
4821 cnt++;
4822 }
4823 else {
4824 ptr = (char *)malloc(strlen(buff) + 1);
4825 strcpy(ptr, buff);
4826 }
4827 st_insert(rgengc_unprotect_logging_table, (st_data_t)ptr, cnt);
4828 }
4829 }
4830
4831 #endif /* USE_RGENGC */
4832
4833 /* RGENGC analysis information */
4834
4835 VALUE
4836 rb_obj_rgengc_writebarrier_protected_p(VALUE obj)
4837 {
4838 return OBJ_WB_PROTECTED(obj) ? Qtrue : Qfalse;
4839 }
4840
4841 VALUE
4842 rb_obj_rgengc_promoted_p(VALUE obj)
4843 {
4844 return OBJ_PROMOTED(obj) ? Qtrue : Qfalse;
4845 }
4846
4847 size_t
4848 rb_obj_gc_flags(VALUE obj, ID* flags, size_t max)
4849 {
4850 size_t n = 0;
4851 static ID ID_marked;
4852 #if USE_RGENGC
4853 static ID ID_wb_protected, ID_old, ID_remembered;
4854 #if RGENGC_THREEGEN
4855 static ID ID_young, ID_infant;
4856 #endif
4857 #endif
4858
4859 if (!ID_marked) {
4860 #define I(s) ID_##s = rb_intern(#s);
4861 I(marked);
4862 #if USE_RGENGC
4863 I(wb_protected);
4864 I(old);
4865 I(remembered);
4866 #if RGENGC_THREEGEN
4867 I(young);
4868 I(infant);
4869 #endif
4870 #endif
4871 #undef I
4872 }
4873
4874 #if USE_RGENGC
4875 if (OBJ_WB_PROTECTED(obj) && n<max)
4876 flags[n++] = ID_wb_protected;
4877 if (RVALUE_OLD_P(obj) && n<max)
4878 flags[n++] = ID_old;
4879 #if RGENGC_THREEGEN
4880 if (RVALUE_YOUNG_P(obj) && n<max)
4881 flags[n++] = ID_young;
4882 if (RVALUE_INFANT_P(obj) && n<max)
4883 flags[n++] = ID_infant;
4884 #endif
4885 if (MARKED_IN_BITMAP(GET_HEAP_REMEMBERSET_BITS(obj), obj) && n<max)
4886 flags[n++] = ID_remembered;
4887 #endif
4888 if (MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj) && n<max)
4889 flags[n++] = ID_marked;
4890
4891 return n;
4892 }
4893
4894 /* GC */
4895
4896 void
4897 rb_gc_force_recycle(VALUE p)
4898 {
4899 rb_objspace_t *objspace = &rb_objspace;
4900
4901 #if USE_RGENGC
4902 CLEAR_IN_BITMAP(GET_HEAP_REMEMBERSET_BITS(p), p);
4903 CLEAR_IN_BITMAP(GET_HEAP_OLDGEN_BITS(p), p);
4904 if (!GET_HEAP_PAGE(p)->before_sweep) {
4905 CLEAR_IN_BITMAP(GET_HEAP_MARK_BITS(p), p);
4906 }
4907 #endif
4908
4909 objspace->profile.total_freed_object_num++;
4910 heap_page_add_freeobj(objspace, GET_HEAP_PAGE(p), p);
4911
4912 /* Disable counting swept_slots because there are no meaning.
4913 * if (!MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(p), p)) {
4914 * objspace->heap.swept_slots++;
4915 * }
4916 */
4917 }
4918
4919 void
4920 rb_gc_register_mark_object(VALUE obj)
4921 {
4922 VALUE ary = GET_THREAD()->vm->mark_object_ary;
4923 rb_ary_push(ary, obj);
4924 }
4925
4926 void
4927 rb_gc_register_address(VALUE *addr)
4928 {
4929 rb_objspace_t *objspace = &rb_objspace;
4930 struct gc_list *tmp;
4931
4932 tmp = ALLOC(struct gc_list);
4933 tmp->next = global_List;
4934 tmp->varptr = addr;
4935 global_List = tmp;
4936 }
4937
4938 void
4939 rb_gc_unregister_address(VALUE *addr)
4940 {
4941 rb_objspace_t *objspace = &rb_objspace;
4942 struct gc_list *tmp = global_List;
4943
4944 if (tmp->varptr == addr) {
4945 global_List = tmp->next;
4946 xfree(tmp);
4947 return;
4948 }
4949 while (tmp->next) {
4950 if (tmp->next->varptr == addr) {
4951 struct gc_list *t = tmp->next;
4952
4953 tmp->next = tmp->next->next;
4954 xfree(t);
4955 break;
4956 }
4957 tmp = tmp->next;
4958 }
4959 }
4960
4961 void
4962 rb_global_variable(VALUE *var)
4963 {
4964 rb_gc_register_address(var);
4965 }
4966
4967 #define GC_NOTIFY 0
4968
4969 static int
4970 garbage_collect_body(rb_objspace_t *objspace, int full_mark, int immediate_sweep, int reason)
4971 {
4972 if (ruby_gc_stress && !ruby_disable_gc_stress) {
4973 int flag = FIXNUM_P(ruby_gc_stress) ? FIX2INT(ruby_gc_stress) : 0;
4974
4975 if (flag & 0x01)
4976 reason &= ~GPR_FLAG_MAJOR_MASK;
4977 else
4978 reason |= GPR_FLAG_MAJOR_BY_STRESS;
4979 immediate_sweep = !(flag & 0x02);
4980 }
4981 else {
4982 if (!GC_ENABLE_LAZY_SWEEP || objspace->flags.dont_lazy_sweep) {
4983 immediate_sweep = TRUE;
4984 }
4985 #if USE_RGENGC
4986 if (full_mark) {
4987 reason |= GPR_FLAG_MAJOR_BY_NOFREE;
4988 }
4989 if (objspace->rgengc.need_major_gc) {
4990 reason |= objspace->rgengc.need_major_gc;
4991 objspace->rgengc.need_major_gc = GPR_FLAG_NONE;
4992 }
4993 if (objspace->rgengc.remembered_shady_object_count > objspace->rgengc.remembered_shady_object_limit) {
4994 reason |= GPR_FLAG_MAJOR_BY_SHADY;
4995 }
4996 if (objspace->rgengc.old_object_count > objspace->rgengc.old_object_limit) {
4997 reason |= GPR_FLAG_MAJOR_BY_OLDGEN;
4998 }
4999 #endif
5000 }
5001
5002 if (immediate_sweep) reason |= GPR_FLAG_IMMEDIATE_SWEEP;
5003 full_mark = (reason & GPR_FLAG_MAJOR_MASK) ? TRUE : FALSE;
5004
5005 if (GC_NOTIFY) fprintf(stderr, "start garbage_collect(%d, %d, %d)\n", full_mark, immediate_sweep, reason);
5006
5007 objspace->profile.count++;
5008 objspace->profile.latest_gc_info = reason;
5009
5010 gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_START, 0 /* TODO: pass minor/immediate flag? */);
5011
5012 objspace->profile.total_allocated_object_num_at_gc_start = objspace->profile.total_allocated_object_num;
5013 objspace->profile.heap_used_at_gc_start = heap_pages_used;
5014
5015 gc_prof_setup_new_record(objspace, reason);
5016 gc_prof_timer_start(objspace);
5017 {
5018 if (during_gc == 0) {
5019 rb_bug("during_gc should not be 0. RUBY_INTERNAL_EVENT_GC_START user should not cause GC in events.");
5020 }
5021 gc_marks(objspace, full_mark);
5022 gc_sweep(objspace, immediate_sweep);
5023 during_gc = 0;
5024 }
5025 gc_prof_timer_stop(objspace);
5026
5027 if (GC_NOTIFY) fprintf(stderr, "end garbage_collect()\n");
5028 return TRUE;
5029 }
5030
5031 static int
5032 heap_ready_to_gc(rb_objspace_t *objspace, rb_heap_t *heap)
5033 {
5034 if (dont_gc || during_gc) {
5035 if (!heap->freelist && !heap->free_pages) {
5036 if (!heap_increment(objspace, heap)) {
5037 heap_set_increment(objspace, 0);
5038 heap_increment(objspace, heap);
5039 }
5040 }
5041 return FALSE;
5042 }
5043 return TRUE;
5044 }
5045
5046 static int
5047 ready_to_gc(rb_objspace_t *objspace)
5048 {
5049 return heap_ready_to_gc(objspace, heap_eden);
5050 }
5051
5052 static int
5053 garbage_collect(rb_objspace_t *objspace, int full_mark, int immediate_sweep, int reason)
5054 {
5055 if (!heap_pages_used) {
5056 during_gc = 0;
5057 return FALSE;
5058 }
5059 if (!ready_to_gc(objspace)) {
5060 during_gc = 0;
5061 return TRUE;
5062 }
5063
5064 #if GC_PROFILE_MORE_DETAIL
5065 objspace->profile.prepare_time = getrusage_time();
5066 #endif
5067 gc_rest_sweep(objspace);
5068 #if GC_PROFILE_MORE_DETAIL
5069 objspace->profile.prepare_time = getrusage_time() - objspace->profile.prepare_time;
5070 #endif
5071
5072 during_gc++;
5073
5074 return garbage_collect_body(objspace, full_mark, immediate_sweep, reason);
5075 }
5076
5077 struct objspace_and_reason {
5078 rb_objspace_t *objspace;
5079 int reason;
5080 int full_mark;
5081 int immediate_sweep;
5082 };
5083
5084 static void *
5085 gc_with_gvl(void *ptr)
5086 {
5087 struct objspace_and_reason *oar = (struct objspace_and_reason *)ptr;
5088 return (void *)(VALUE)garbage_collect(oar->objspace, oar->full_mark, oar->immediate_sweep, oar->reason);
5089 }
5090
5091 static int
5092 garbage_collect_with_gvl(rb_objspace_t *objspace, int full_mark, int immediate_sweep, int reason)
5093 {
5094 if (dont_gc) return TRUE;
5095 if (ruby_thread_has_gvl_p()) {
5096 return garbage_collect(objspace, full_mark, immediate_sweep, reason);
5097 }
5098 else {
5099 if (ruby_native_thread_p()) {
5100 struct objspace_and_reason oar;
5101 oar.objspace = objspace;
5102 oar.reason = reason;
5103 oar.full_mark = full_mark;
5104 oar.immediate_sweep = immediate_sweep;
5105 return (int)(VALUE)rb_thread_call_with_gvl(gc_with_gvl, (void *)&oar);
5106 }
5107 else {
5108 /* no ruby thread */
5109 fprintf(stderr, "[FATAL] failed to allocate memory\n");
5110 exit(EXIT_FAILURE);
5111 }
5112 }
5113 }
5114
5115 int
5116 rb_garbage_collect(void)
5117 {
5118 return garbage_collect(&rb_objspace, TRUE, TRUE, GPR_FLAG_CAPI);
5119 }
5120
5121 #undef Init_stack
5122
5123 void
5124 Init_stack(volatile VALUE *addr)
5125 {
5126 ruby_init_stack(addr);
5127 }
5128
5129 /*
5130 * call-seq:
5131 * GC.start -> nil
5132 * GC.garbage_collect -> nil
5133 * ObjectSpace.garbage_collect -> nil
5134 * GC.start(full_mark: false) -> nil
5135 *
5136 * Initiates garbage collection, unless manually disabled.
5137 *
5138 * This method is defined with keyword arguments that default to true:
5139 *
5140 * def GC.start(full_mark: true, immediate_sweep: true) end
5141 *
5142 * Use full_mark: false to perform a minor GC.
5143 * Use immediate_sweep: false to defer sweeping (use lazy sweep).
5144 *
5145 * Note: These keyword arguments are implementation and version dependent. They
5146 * are not guaranteed to be future-compatible, and may be ignored if the
5147 * underlying implementation does not support them.
5148 */
5149
5150 static VALUE
5151 gc_start_internal(int argc, VALUE *argv, VALUE self)
5152 {
5153 rb_objspace_t *objspace = &rb_objspace;
5154 int full_mark = TRUE, immediate_sweep = TRUE;
5155 VALUE opt = Qnil;
5156 static ID keyword_ids[2];
5157
5158 rb_scan_args(argc, argv, "0:", &opt);
5159
5160 if (!NIL_P(opt)) {
5161 VALUE kwvals[2];
5162
5163 if (!keyword_ids[0]) {
5164 keyword_ids[0] = rb_intern("full_mark");
5165 keyword_ids[1] = rb_intern("immediate_sweep");
5166 }
5167
5168 rb_get_kwargs(opt, keyword_ids, 0, 2, kwvals);
5169
5170 if (kwvals[0] != Qundef)
5171 full_mark = RTEST(kwvals[0]);
5172 if (kwvals[1] != Qundef)
5173 immediate_sweep = RTEST(kwvals[1]);
5174 }
5175
5176 garbage_collect(objspace, full_mark, immediate_sweep, GPR_FLAG_METHOD);
5177 if (!finalizing) finalize_deferred(objspace);
5178
5179 return Qnil;
5180 }
5181
5182 VALUE
5183 rb_gc_start(void)
5184 {
5185 rb_gc();
5186 return Qnil;
5187 }
5188
5189 void
5190 rb_gc(void)
5191 {
5192 rb_objspace_t *objspace = &rb_objspace;
5193 garbage_collect(objspace, TRUE, TRUE, GPR_FLAG_CAPI);
5194 if (!finalizing) finalize_deferred(objspace);
5195 }
5196
5197 int
5198 rb_during_gc(void)
5199 {
5200 rb_objspace_t *objspace = &rb_objspace;
5201 return during_gc;
5202 }
5203
5204 #if RGENGC_PROFILE >= 2
5205 static void
5206 gc_count_add_each_types(VALUE hash, const char *name, const size_t *types)
5207 {
5208 VALUE result = rb_hash_new();
5209 int i;
5210 for (i=0; i<T_MASK; i++) {
5211 const char *type = type_name(i, 0);
5212 rb_hash_aset(result, ID2SYM(rb_intern(type)), SIZET2NUM(types[i]));
5213 }
5214 rb_hash_aset(hash, ID2SYM(rb_intern(name)), result);
5215 }
5216 #endif
5217
5218 size_t
5219 rb_gc_count(void)
5220 {
5221 return rb_objspace.profile.count;
5222 }
5223
5224 /*
5225 * call-seq:
5226 * GC.count -> Integer
5227 *
5228 * The number of times GC occurred.
5229 *
5230 * It returns the number of times GC occurred since the process started.
5231 *
5232 */
5233
5234 static VALUE
5235 gc_count(VALUE self)
5236 {
5237 return SIZET2NUM(rb_gc_count());
5238 }
5239
5240 static VALUE
5241 gc_info_decode(int flags, VALUE hash_or_key)
5242 {
5243 static VALUE sym_major_by = Qnil, sym_gc_by, sym_immediate_sweep, sym_have_finalizer;
5244 static VALUE sym_nofree, sym_oldgen, sym_shady, sym_rescan, sym_stress;
5245 #if RGENGC_ESTIMATE_OLDMALLOC
5246 static VALUE sym_oldmalloc;
5247 #endif
5248 static VALUE sym_newobj, sym_malloc, sym_method, sym_capi;
5249 VALUE hash = Qnil, key = Qnil;
5250 VALUE major_by;
5251
5252 if (SYMBOL_P(hash_or_key))
5253 key = hash_or_key;
5254 else if (RB_TYPE_P(hash_or_key, T_HASH))
5255 hash = hash_or_key;
5256 else
5257 rb_raise(rb_eTypeError, "non-hash or symbol given");
5258
5259 if (sym_major_by == Qnil) {
5260 #define S(s) sym_##s = ID2SYM(rb_intern_const(#s))
5261 S(major_by);
5262 S(gc_by);
5263 S(immediate_sweep);
5264 S(have_finalizer);
5265 S(nofree);
5266 S(oldgen);
5267 S(shady);
5268 S(rescan);
5269 S(stress);
5270 #if RGENGC_ESTIMATE_OLDMALLOC
5271 S(oldmalloc);
5272 #endif
5273 S(newobj);
5274 S(malloc);
5275 S(method);
5276 S(capi);
5277 #undef S
5278 }
5279
5280 #define SET(name, attr) \
5281 if (key == sym_##name) \
5282 return (attr); \
5283 else if (hash != Qnil) \
5284 rb_hash_aset(hash, sym_##name, (attr));
5285
5286 major_by =
5287 (flags & GPR_FLAG_MAJOR_BY_OLDGEN) ? sym_oldgen :
5288 (flags & GPR_FLAG_MAJOR_BY_SHADY) ? sym_shady :
5289 (flags & GPR_FLAG_MAJOR_BY_RESCAN) ? sym_rescan :
5290 (flags & GPR_FLAG_MAJOR_BY_STRESS) ? sym_stress :
5291 #if RGENGC_ESTIMATE_OLDMALLOC
5292 (flags & GPR_FLAG_MAJOR_BY_OLDMALLOC) ? sym_oldmalloc :
5293 #endif
5294 (flags & GPR_FLAG_MAJOR_BY_NOFREE) ? sym_nofree :
5295 Qnil;
5296 SET(major_by, major_by);
5297
5298 SET(gc_by,
5299 (flags & GPR_FLAG_NEWOBJ) ? sym_newobj :
5300 (flags & GPR_FLAG_MALLOC) ? sym_malloc :
5301 (flags & GPR_FLAG_METHOD) ? sym_method :
5302 (flags & GPR_FLAG_CAPI) ? sym_capi :
5303 (flags & GPR_FLAG_STRESS) ? sym_stress :
5304 Qnil
5305 );
5306
5307 SET(have_finalizer, (flags & GPR_FLAG_HAVE_FINALIZE) ? Qtrue : Qfalse);
5308 SET(immediate_sweep, (flags & GPR_FLAG_IMMEDIATE_SWEEP) ? Qtrue : Qfalse);
5309 #undef SET
5310
5311 if (key != Qnil) /* matched key should return above */
5312 rb_raise(rb_eArgError, "unknown key: %s", RSTRING_PTR(rb_id2str(SYM2ID(key))));
5313
5314 return hash;
5315 }
5316
5317 VALUE
5318 rb_gc_latest_gc_info(VALUE key)
5319 {
5320 rb_objspace_t *objspace = &rb_objspace;
5321 return gc_info_decode(objspace->profile.latest_gc_info, key);
5322 }
5323
5324 /*
5325 * call-seq:
5326 * GC.latest_gc_info -> {:gc_by=>:newobj}
5327 * GC.latest_gc_info(hash) -> hash
5328 * GC.latest_gc_info(:major_by) -> :malloc
5329 *
5330 * Returns information about the most recent garbage collection.
5331 */
5332
5333 static VALUE
5334 gc_latest_gc_info(int argc, VALUE *argv, VALUE self)
5335 {
5336 rb_objspace_t *objspace = &rb_objspace;
5337 VALUE arg = Qnil;
5338
5339 if (rb_scan_args(argc, argv, "01", &arg) == 1) {
5340 if (!SYMBOL_P(arg) && !RB_TYPE_P(arg, T_HASH)) {
5341 rb_raise(rb_eTypeError, "non-hash or symbol given");
5342 }
5343 }
5344
5345 if (arg == Qnil)
5346 arg = rb_hash_new();
5347
5348 return gc_info_decode(objspace->profile.latest_gc_info, arg);
5349 }
5350
5351 static VALUE
5352 gc_stat_internal(VALUE hash_or_sym, size_t *out)
5353 {
5354 static VALUE sym_count;
5355 static VALUE sym_heap_used, sym_heap_length, sym_heap_increment;
5356 static VALUE sym_heap_live_slot, sym_heap_free_slot, sym_heap_final_slot, sym_heap_swept_slot;
5357 static VALUE sym_heap_eden_page_length, sym_heap_tomb_page_length;
5358 static VALUE sym_total_allocated_object, sym_total_freed_object;
5359 static VALUE sym_malloc_increase, sym_malloc_limit;
5360 #if USE_RGENGC
5361 static VALUE sym_minor_gc_count, sym_major_gc_count;
5362 static VALUE sym_remembered_shady_object, sym_remembered_shady_object_limit;
5363 static VALUE sym_old_object, sym_old_object_limit;
5364 #if RGENGC_ESTIMATE_OLDMALLOC
5365 static VALUE sym_oldmalloc_increase, sym_oldmalloc_limit;
5366 #endif
5367 #if RGENGC_PROFILE
5368 static VALUE sym_generated_normal_object_count, sym_generated_shady_object_count;
5369 static VALUE sym_shade_operation_count, sym_promote_infant_count, sym_promote_young_count;
5370 static VALUE sym_remembered_normal_object_count, sym_remembered_shady_object_count;
5371 #endif /* RGENGC_PROFILE */
5372 #endif /* USE_RGENGC */
5373
5374 rb_objspace_t *objspace = &rb_objspace;
5375 VALUE hash = Qnil, key = Qnil;
5376
5377 if (RB_TYPE_P(hash_or_sym, T_HASH))
5378 hash = hash_or_sym;
5379 else if (SYMBOL_P(hash_or_sym) && out)
5380 key = hash_or_sym;
5381 else
5382 rb_raise(rb_eTypeError, "non-hash or symbol argument");
5383
5384 if (sym_count == 0) {
5385 #define S(s) sym_##s = ID2SYM(rb_intern_const(#s))
5386 S(count);
5387 S(heap_used);
5388 S(heap_length);
5389 S(heap_increment);
5390 S(heap_live_slot);
5391 S(heap_free_slot);
5392 S(heap_final_slot);
5393 S(heap_swept_slot);
5394 S(heap_eden_page_length);
5395 S(heap_tomb_page_length);
5396 S(total_allocated_object);
5397 S(total_freed_object);
5398 S(malloc_increase);
5399 S(malloc_limit);
5400 #if USE_RGENGC
5401 S(minor_gc_count);
5402 S(major_gc_count);
5403 S(remembered_shady_object);
5404 S(remembered_shady_object_limit);
5405 S(old_object);
5406 S(old_object_limit);
5407 #if RGENGC_ESTIMATE_OLDMALLOC
5408 S(oldmalloc_increase);
5409 S(oldmalloc_limit);
5410 #endif
5411 #if RGENGC_PROFILE
5412 S(generated_normal_object_count);
5413 S(generated_shady_object_count);
5414 S(shade_operation_count);
5415 S(promote_infant_count);
5416 S(promote_young_count);
5417 S(remembered_normal_object_count);
5418 S(remembered_shady_object_count);
5419 #endif /* USE_RGENGC */
5420 #endif /* RGENGC_PROFILE */
5421 #undef S
5422 }
5423
5424 #define SET(name, attr) \
5425 if (key == sym_##name) \
5426 return (*out = attr, Qnil); \
5427 else if (hash != Qnil) \
5428 rb_hash_aset(hash, sym_##name, SIZET2NUM(attr));
5429
5430 SET(count, objspace->profile.count);
5431
5432 /* implementation dependent counters */
5433 SET(heap_used, heap_pages_used);
5434 SET(heap_length, heap_pages_length);
5435 SET(heap_increment, heap_pages_increment);
5436 SET(heap_live_slot, objspace_live_slot(objspace));
5437 SET(heap_free_slot, objspace_free_slot(objspace));
5438 SET(heap_final_slot, heap_pages_final_slots);
5439 SET(heap_swept_slot, heap_pages_swept_slots);
5440 SET(heap_eden_page_length, heap_eden->page_length);
5441 SET(heap_tomb_page_length, heap_tomb->page_length);
5442 SET(total_allocated_object, objspace->profile.total_allocated_object_num);
5443 SET(total_freed_object, objspace->profile.total_freed_object_num);
5444 SET(malloc_increase, malloc_increase);
5445 SET(malloc_limit, malloc_limit);
5446 #if USE_RGENGC
5447 SET(minor_gc_count, objspace->profile.minor_gc_count);
5448 SET(major_gc_count, objspace->profile.major_gc_count);
5449 SET(remembered_shady_object, objspace->rgengc.remembered_shady_object_count);
5450 SET(remembered_shady_object_limit, objspace->rgengc.remembered_shady_object_limit);
5451 SET(old_object, objspace->rgengc.old_object_count);
5452 SET(old_object_limit, objspace->rgengc.old_object_limit);
5453 #if RGENGC_ESTIMATE_OLDMALLOC
5454 SET(oldmalloc_increase, objspace->rgengc.oldmalloc_increase);
5455 SET(oldmalloc_limit, objspace->rgengc.oldmalloc_increase_limit);
5456 #endif
5457
5458 #if RGENGC_PROFILE
5459 SET(generated_normal_object_count, objspace->profile.generated_normal_object_count);
5460 SET(generated_shady_object_count, objspace->profile.generated_shady_object_count);
5461 SET(shade_operation_count, objspace->profile.shade_operation_count);
5462 SET(promote_infant_count, objspace->profile.promote_infant_count);
5463 #if RGENGC_THREEGEN
5464 SET(promote_young_count, objspace->profile.promote_young_count);
5465 #endif
5466 SET(remembered_normal_object_count, objspace->profile.remembered_normal_object_count);
5467 SET(remembered_shady_object_count, objspace->profile.remembered_shady_object_count);
5468 #endif /* RGENGC_PROFILE */
5469 #endif /* USE_RGENGC */
5470 #undef SET
5471
5472 if (key != Qnil) /* matched key should return above */
5473 rb_raise(rb_eArgError, "unknown key: %s", RSTRING_PTR(rb_id2str(SYM2ID(key))));
5474
5475 #if defined(RGENGC_PROFILE) && RGENGC_PROFILE >= 2
5476 if (hash != Qnil) {
5477 gc_count_add_each_types(hash, "generated_normal_object_count_types", objspace->profile.generated_normal_object_count_types);
5478 gc_count_add_each_types(hash, "generated_shady_object_count_types", objspace->profile.generated_shady_object_count_types);
5479 gc_count_add_each_types(hash, "shade_operation_count_types", objspace->profile.shade_operation_count_types);
5480 gc_count_add_each_types(hash, "promote_infant_types", objspace->profile.promote_infant_types);
5481 #if RGENGC_THREEGEN
5482 gc_count_add_each_types(hash, "promote_young_types", objspace->profile.promote_young_types);
5483 #endif
5484 gc_count_add_each_types(hash, "remembered_normal_object_count_types", objspace->profile.remembered_normal_object_count_types);
5485 gc_count_add_each_types(hash, "remembered_shady_object_count_types", objspace->profile.remembered_shady_object_count_types);
5486 }
5487 #endif
5488
5489 return hash;
5490 }
5491
5492 /*
5493 * call-seq:
5494 * GC.stat -> Hash
5495 * GC.stat(hash) -> hash
5496 * GC.stat(:key) -> Numeric
5497 *
5498 * Returns a Hash containing information about the GC.
5499 *
5500 * The hash includes information about internal statistics about GC such as:
5501 *
5502 * {
5503 * :count=>2,
5504 * :heap_used=>9,
5505 * :heap_length=>11,
5506 * :heap_increment=>2,
5507 * :heap_live_slot=>6836,
5508 * :heap_free_slot=>519,
5509 * :heap_final_slot=>0,
5510 * :heap_swept_slot=>818,
5511 * :total_allocated_object=>7674,
5512 * :total_freed_object=>838,
5513 * :malloc_increase=>181034,
5514 * :malloc_limit=>16777216,
5515 * :minor_gc_count=>2,
5516 * :major_gc_count=>0,
5517 * :remembered_shady_object=>55,
5518 * :remembered_shady_object_limit=>0,
5519 * :old_object=>2422,
5520 * :old_object_limit=>0,
5521 * :oldmalloc_increase=>277386,
5522 * :oldmalloc_limit=>16777216
5523 * }
5524 *
5525 * The contents of the hash are implementation specific and may be changed in
5526 * the future.
5527 *
5528 * This method is only expected to work on C Ruby.
5529 *
5530 */
5531
5532 static VALUE
5533 gc_stat(int argc, VALUE *argv, VALUE self)
5534 {
5535 VALUE arg = Qnil;
5536
5537 if (rb_scan_args(argc, argv, "01", &arg) == 1) {
5538 if (SYMBOL_P(arg)) {
5539 size_t value = 0;
5540 gc_stat_internal(arg, &value);
5541 return SIZET2NUM(value);
5542 } else if (!RB_TYPE_P(arg, T_HASH)) {
5543 rb_raise(rb_eTypeError, "non-hash or symbol given");
5544 }
5545 }
5546
5547 if (arg == Qnil) {
5548 arg = rb_hash_new();
5549 }
5550 gc_stat_internal(arg, 0);
5551 return arg;
5552 }
5553
5554 size_t
5555 rb_gc_stat(VALUE key)
5556 {
5557 if (SYMBOL_P(key)) {
5558 size_t value = 0;
5559 gc_stat_internal(key, &value);
5560 return value;
5561 } else {
5562 gc_stat_internal(key, 0);
5563 return 0;
5564 }
5565 }
5566
5567 /*
5568 * call-seq:
5569 * GC.stress -> fixnum, true or false
5570 *
5571 * Returns current status of GC stress mode.
5572 */
5573
5574 static VALUE
5575 gc_stress_get(VALUE self)
5576 {
5577 rb_objspace_t *objspace = &rb_objspace;
5578 return ruby_gc_stress;
5579 }
5580
5581 /*
5582 * call-seq:
5583 * GC.stress = bool -> bool
5584 *
5585 * Updates the GC stress mode.
5586 *
5587 * When stress mode is enabled, the GC is invoked at every GC opportunity:
5588 * all memory and object allocations.
5589 *
5590 * Enabling stress mode will degrade performance, it is only for debugging.
5591 */
5592
5593 static VALUE
5594 gc_stress_set(VALUE self, VALUE flag)
5595 {
5596 rb_objspace_t *objspace = &rb_objspace;
5597 rb_secure(2);
5598 ruby_gc_stress = FIXNUM_P(flag) ? flag : (RTEST(flag) ? Qtrue : Qfalse);
5599 return flag;
5600 }
5601
5602 /*
5603 * call-seq:
5604 * GC.enable -> true or false
5605 *
5606 * Enables garbage collection, returning +true+ if garbage
5607 * collection was previously disabled.
5608 *
5609 * GC.disable #=> false
5610 * GC.enable #=> true
5611 * GC.enable #=> false
5612 *
5613 */
5614
5615 VALUE
5616 rb_gc_enable(void)
5617 {
5618 rb_objspace_t *objspace = &rb_objspace;
5619 int old = dont_gc;
5620
5621 dont_gc = FALSE;
5622 return old ? Qtrue : Qfalse;
5623 }
5624
5625 /*
5626 * call-seq:
5627 * GC.disable -> true or false
5628 *
5629 * Disables garbage collection, returning +true+ if garbage
5630 * collection was already disabled.
5631 *
5632 * GC.disable #=> false
5633 * GC.disable #=> true
5634 *
5635 */
5636
5637 VALUE
5638 rb_gc_disable(void)
5639 {
5640 rb_objspace_t *objspace = &rb_objspace;
5641 int old = dont_gc;
5642
5643 gc_rest_sweep(objspace);
5644
5645 dont_gc = TRUE;
5646 return old ? Qtrue : Qfalse;
5647 }
5648
5649 static int
5650 get_envparam_int(const char *name, unsigned int *default_value, int lower_bound)
5651 {
5652 char *ptr = getenv(name);
5653 int val;
5654
5655 if (ptr != NULL) {
5656 val = atoi(ptr);
5657 if (val > lower_bound) {
5658 if (RTEST(ruby_verbose)) fprintf(stderr, "%s=%d (default value: %d)\n", name, val, *default_value);
5659 *default_value = val;
5660 return 1;
5661 }
5662 else {
5663 if (RTEST(ruby_verbose)) fprintf(stderr, "%s=%d (default value: %d) is ignored because it must be greater than %d.\n", name, val, *default_value, lower_bound);
5664 }
5665 }
5666 return 0;
5667 }
5668
5669 static int
5670 get_envparam_double(const char *name, double *default_value, double lower_bound)
5671 {
5672 char *ptr = getenv(name);
5673 double val;
5674
5675 if (ptr != NULL) {
5676 val = strtod(ptr, NULL);
5677 if (val > lower_bound) {
5678 if (RTEST(ruby_verbose)) fprintf(stderr, "%s=%f (%f)\n", name, val, *default_value);
5679 *default_value = val;
5680 return 1;
5681 }
5682 else {
5683 if (RTEST(ruby_verbose)) fprintf(stderr, "%s=%f (default value: %f) is ignored because it must be greater than %f.\n", name, val, *default_value, lower_bound);
5684 }
5685 }
5686 return 0;
5687 }
5688
5689 static void
5690 gc_set_initial_pages(void)
5691 {
5692 size_t min_pages;
5693 rb_objspace_t *objspace = &rb_objspace;
5694
5695 min_pages = gc_params.heap_init_slots / HEAP_OBJ_LIMIT;
5696 if (min_pages > heap_eden->page_length) {
5697 heap_add_pages(objspace, heap_eden, min_pages - heap_eden->page_length);
5698 }
5699 }
5700
5701 /*
5702 * GC tuning environment variables
5703 *
5704 * * RUBY_GC_HEAP_INIT_SLOTS
5705 * - Initial allocation slots.
5706 * * RUBY_GC_HEAP_FREE_SLOTS
5707 * - Prepare at least this ammount of slots after GC.
5708 * - Allocate slots if there are not enough slots.
5709 * * RUBY_GC_HEAP_GROWTH_FACTOR (new from 2.1)
5710 * - Allocate slots by this factor.
5711 * - (next slots number) = (current slots number) * (this factor)
5712 * * RUBY_GC_HEAP_GROWTH_MAX_SLOTS (new from 2.1)
5713 * - Allocation rate is limited to this factor.
5714 * * RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR (new from 2.1.1)
5715 * - Do full GC when the number of old objects is more than R * N
5716 * where R is this factor and
5717 * N is the number of old objects just after last full GC.
5718 *
5719 * * obsolete
5720 * * RUBY_FREE_MIN -> RUBY_GC_HEAP_FREE_SLOTS (from 2.1)
5721 * * RUBY_HEAP_MIN_SLOTS -> RUBY_GC_HEAP_INIT_SLOTS (from 2.1)
5722 *
5723 * * RUBY_GC_MALLOC_LIMIT
5724 * * RUBY_GC_MALLOC_LIMIT_MAX (new from 2.1)
5725 * * RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR (new from 2.1)
5726 *
5727 * * RUBY_GC_OLDMALLOC_LIMIT (new from 2.1)
5728 * * RUBY_GC_OLDMALLOC_LIMIT_MAX (new from 2.1)
5729 * * RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR (new from 2.1)
5730 */
5731
5732 void
5733 ruby_gc_set_params(int safe_level)
5734 {
5735 if (safe_level > 0) return;
5736
5737 /* RUBY_GC_HEAP_FREE_SLOTS */
5738 if (get_envparam_int("RUBY_GC_HEAP_FREE_SLOTS", &gc_params.heap_free_slots, 0)) {
5739 /* ok */
5740 }
5741 else if (get_envparam_int("RUBY_FREE_MIN", &gc_params.heap_free_slots, 0)) {
5742 rb_warn("RUBY_FREE_MIN is obsolete. Use RUBY_GC_HEAP_FREE_SLOTS instead.");
5743 }
5744
5745 /* RUBY_GC_HEAP_INIT_SLOTS */
5746 if (get_envparam_int("RUBY_GC_HEAP_INIT_SLOTS", &gc_params.heap_init_slots, 0)) {
5747 gc_set_initial_pages();
5748 }
5749 else if (get_envparam_int("RUBY_HEAP_MIN_SLOTS", &gc_params.heap_init_slots, 0)) {
5750 rb_warn("RUBY_HEAP_MIN_SLOTS is obsolete. Use RUBY_GC_HEAP_INIT_SLOTS instead.");
5751 gc_set_initial_pages();
5752 }
5753
5754 get_envparam_double("RUBY_GC_HEAP_GROWTH_FACTOR", &gc_params.growth_factor, 1.0);
5755 get_envparam_int ("RUBY_GC_HEAP_GROWTH_MAX_SLOTS", &gc_params.growth_max_slots, 0);
5756 get_envparam_double("RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR", &gc_params.oldobject_limit_factor, 0.0);
5757
5758 get_envparam_int("RUBY_GC_MALLOC_LIMIT", &gc_params.malloc_limit_min, 0);
5759 get_envparam_int("RUBY_GC_MALLOC_LIMIT_MAX", &gc_params.malloc_limit_max, 0);
5760 get_envparam_double("RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR", &gc_params.malloc_limit_growth_factor, 1.0);
5761
5762 #if RGENGC_ESTIMATE_OLDMALLOC
5763 if (get_envparam_int("RUBY_GC_OLDMALLOC_LIMIT", &gc_params.oldmalloc_limit_min, 0)) {
5764 rb_objspace_t *objspace = &rb_objspace;
5765 objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min;
5766 }
5767 get_envparam_int("RUBY_GC_OLDMALLOC_LIMIT_MAX", &gc_params.oldmalloc_limit_max, 0);
5768 get_envparam_double("RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR", &gc_params.oldmalloc_limit_growth_factor, 1.0);
5769 #endif
5770 }
5771
5772 void
5773 rb_gc_set_params(void)
5774 {
5775 ruby_gc_set_params(rb_safe_level());
5776 }
5777
5778 void
5779 rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data)
5780 {
5781 rb_objspace_t *objspace = &rb_objspace;
5782
5783 if (is_markable_object(objspace, obj)) {
5784 struct mark_func_data_struct mfd;
5785 mfd.mark_func = func;
5786 mfd.data = data;
5787 objspace->mark_func_data = &mfd;
5788 gc_mark_children(objspace, obj);
5789 objspace->mark_func_data = 0;
5790 }
5791 }
5792
5793 struct root_objects_data {
5794 const char *category;
5795 void (*func)(const char *category, VALUE, void *);
5796 void *data;
5797 };
5798
5799 static void
5800 root_objects_from(VALUE obj, void *ptr)
5801 {
5802 const struct root_objects_data *data = (struct root_objects_data *)ptr;
5803 (*data->func)(data->category, obj, data->data);
5804 }
5805
5806 void
5807 rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *passing_data)
5808 {
5809 rb_objspace_t *objspace = &rb_objspace;
5810 struct root_objects_data data;
5811 struct mark_func_data_struct mfd;
5812
5813 data.func = func;
5814 data.data = passing_data;
5815
5816 mfd.mark_func = root_objects_from;
5817 mfd.data = &data;
5818
5819 objspace->mark_func_data = &mfd;
5820 {
5821 gc_mark_roots(objspace, TRUE, &data.category);
5822 }
5823 objspace->mark_func_data = 0;
5824 }
5825
5826 /*
5827 ------------------------ Extended allocator ------------------------
5828 */
5829
5830 static void objspace_xfree(rb_objspace_t *objspace, void *ptr, size_t size);
5831
5832 static void *
5833 negative_size_allocation_error_with_gvl(void *ptr)
5834 {
5835 rb_raise(rb_eNoMemError, "%s", (const char *)ptr);
5836 return 0; /* should not be reached */
5837 }
5838
5839 static void
5840 negative_size_allocation_error(const char *msg)
5841 {
5842 if (ruby_thread_has_gvl_p()) {
5843 rb_raise(rb_eNoMemError, "%s", msg);
5844 }
5845 else {
5846 if (ruby_native_thread_p()) {
5847 rb_thread_call_with_gvl(negative_size_allocation_error_with_gvl, (void *)msg);
5848 }
5849 else {
5850 fprintf(stderr, "[FATAL] %s\n", msg);
5851 exit(EXIT_FAILURE);
5852 }
5853 }
5854 }
5855
5856 static void *
5857 ruby_memerror_body(void *dummy)
5858 {
5859 rb_memerror();
5860 return 0;
5861 }
5862
5863 static void
5864 ruby_memerror(void)
5865 {
5866 if (ruby_thread_has_gvl_p()) {
5867 rb_memerror();
5868 }
5869 else {
5870 if (ruby_native_thread_p()) {
5871 rb_thread_call_with_gvl(ruby_memerror_body, 0);
5872 }
5873 else {
5874 /* no ruby thread */
5875 fprintf(stderr, "[FATAL] failed to allocate memory\n");
5876 exit(EXIT_FAILURE);
5877 }
5878 }
5879 }
5880
5881 void
5882 rb_memerror(void)
5883 {
5884 rb_thread_t *th = GET_THREAD();
5885 if (!nomem_error ||
5886 rb_thread_raised_p(th, RAISED_NOMEMORY)) {
5887 fprintf(stderr, "[FATAL] failed to allocate memory\n");
5888 exit(EXIT_FAILURE);
5889 }
5890 if (rb_thread_raised_p(th, RAISED_NOMEMORY)) {
5891 rb_thread_raised_clear(th);
5892 GET_THREAD()->errinfo = nomem_error;
5893 JUMP_TAG(TAG_RAISE);
5894 }
5895 rb_thread_raised_set(th, RAISED_NOMEMORY);
5896 rb_exc_raise(nomem_error);
5897 }
5898
5899 static void *
5900 aligned_malloc(size_t alignment, size_t size)
5901 {
5902 void *res;
5903
5904 #if defined __MINGW32__
5905 res = __mingw_aligned_malloc(size, alignment);
5906 #elif defined _WIN32 && !defined __CYGWIN__
5907 void *_aligned_malloc(size_t, size_t);
5908 res = _aligned_malloc(size, alignment);
5909 #elif defined(HAVE_POSIX_MEMALIGN)
5910 if (posix_memalign(&res, alignment, size) == 0) {
5911 return res;
5912 }
5913 else {
5914 return NULL;
5915 }
5916 #elif defined(HAVE_MEMALIGN)
5917 res = memalign(alignment, size);
5918 #else
5919 char* aligned;
5920 res = malloc(alignment + size + sizeof(void*));
5921 aligned = (char*)res + alignment + sizeof(void*);
5922 aligned -= ((VALUE)aligned & (alignment - 1));
5923 ((void**)aligned)[-1] = res;
5924 res = (void*)aligned;
5925 #endif
5926
5927 #if defined(_DEBUG) || GC_DEBUG
5928 /* alignment must be a power of 2 */
5929 assert(((alignment - 1) & alignment) == 0);
5930 assert(alignment % sizeof(void*) == 0);
5931 #endif
5932 return res;
5933 }
5934
5935 static void
5936 aligned_free(void *ptr)
5937 {
5938 #if defined __MINGW32__
5939 __mingw_aligned_free(ptr);
5940 #elif defined _WIN32 && !defined __CYGWIN__
5941 _aligned_free(ptr);
5942 #elif defined(HAVE_MEMALIGN) || defined(HAVE_POSIX_MEMALIGN)
5943 free(ptr);
5944 #else
5945 free(((void**)ptr)[-1]);
5946 #endif
5947 }
5948
5949 static inline size_t
5950 objspace_malloc_size(rb_objspace_t *objspace, void *ptr, size_t hint)
5951 {
5952 #ifdef HAVE_MALLOC_USABLE_SIZE
5953 return malloc_usable_size(ptr);
5954 #else
5955 return hint;
5956 #endif
5957 }
5958
5959 enum memop_type {
5960 MEMOP_TYPE_MALLOC = 1,
5961 MEMOP_TYPE_FREE = 2,
5962 MEMOP_TYPE_REALLOC = 3
5963 };
5964
5965 static inline void
5966 atomic_sub_nounderflow(size_t *var, size_t sub)
5967 {
5968 if (sub == 0) return;
5969
5970 while (1) {
5971 size_t val = *var;
5972 if (val < sub) sub = val;
5973 if (ATOMIC_SIZE_CAS(*var, val, val-sub) == val) break;
5974 }
5975 }
5976
5977 static void
5978 objspace_malloc_increase(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type)
5979 {
5980 if (new_size > old_size) {
5981 ATOMIC_SIZE_ADD(malloc_increase, new_size - old_size);
5982 #if RGENGC_ESTIMATE_OLDMALLOC
5983 ATOMIC_SIZE_ADD(objspace->rgengc.oldmalloc_increase, new_size - old_size);
5984 #endif
5985 }
5986 else {
5987 atomic_sub_nounderflow(&malloc_increase, old_size - new_size);
5988 #if RGENGC_ESTIMATE_OLDMALLOC
5989 atomic_sub_nounderflow(&objspace->rgengc.oldmalloc_increase, old_size - new_size);
5990 #endif
5991 }
5992
5993 if (type == MEMOP_TYPE_MALLOC) {
5994 if (ruby_gc_stress && !ruby_disable_gc_stress) {
5995 garbage_collect_with_gvl(objspace, FALSE, TRUE, GPR_FLAG_MALLOC);
5996 }
5997 else {
5998 retry:
5999 if (malloc_increase > malloc_limit) {
6000 if (ruby_thread_has_gvl_p() && is_lazy_sweeping(heap_eden)) {
6001 gc_rest_sweep(objspace); /* rest_sweep can reduce malloc_increase */
6002 goto retry;
6003 }
6004 garbage_collect_with_gvl(objspace, FALSE, TRUE, GPR_FLAG_MALLOC);
6005 }
6006 }
6007 }
6008
6009 #if MALLOC_ALLOCATED_SIZE
6010 if (new_size >= old_size) {
6011 ATOMIC_SIZE_ADD(objspace->malloc_params.allocated_size, new_size - old_size);
6012 }
6013 else {
6014 size_t dec_size = old_size - new_size;
6015 size_t allocated_size = objspace->malloc_params.allocated_size;
6016
6017 #if MALLOC_ALLOCATED_SIZE_CHECK
6018 if (allocated_size < dec_size) {
6019 rb_bug("objspace_malloc_increase: underflow malloc_params.allocated_size.");
6020 }
6021 #endif
6022 atomic_sub_nounderflow(objspace->malloc_params.allocated_size, dec_size);
6023 }
6024
6025 if (0) fprintf(stderr, "incraese - ptr: %p, type: %s, new_size: %d, old_size: %d\n",
6026 mem,
6027 type == MEMOP_TYPE_MALLOC ? "malloc" :
6028 type == MEMOP_TYPE_FREE ? "free " :
6029 type == MEMOP_TYPE_REALLOC ? "realloc": "error",
6030 (int)new_size, (int)old_size);
6031
6032 switch (type) {
6033 case MEMOP_TYPE_MALLOC:
6034 ATOMIC_SIZE_INC(objspace->malloc_params.allocations);
6035 break;
6036 case MEMOP_TYPE_FREE:
6037 {
6038 size_t allocations = objspace->malloc_params.allocations;
6039 if (allocations > 0) {
6040 atomic_sub_nounderflow(objspace->malloc_params.allocations, 1);
6041 }
6042 #if MALLOC_ALLOCATED_SIZE_CHECK
6043 else {
6044 assert(objspace->malloc_params.allocations > 0);
6045 }
6046 #endif
6047 }
6048 break;
6049 case MEMOP_TYPE_REALLOC: /* ignore */ break;
6050 }
6051 #endif
6052 }
6053
6054 static inline size_t
6055 objspace_malloc_prepare(rb_objspace_t *objspace, size_t size)
6056 {
6057 if ((ssize_t)size < 0) {
6058 negative_size_allocation_error("negative allocation size (or too big)");
6059 }
6060 if (size == 0) size = 1;
6061
6062 #if CALC_EXACT_MALLOC_SIZE
6063 size += sizeof(size_t);
6064 #endif
6065
6066 return size;
6067 }
6068
6069 static inline void *
6070 objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
6071 {
6072 #if CALC_EXACT_MALLOC_SIZE
6073 ((size_t *)mem)[0] = size;
6074 mem = (size_t *)mem + 1;
6075 #endif
6076
6077 return mem;
6078 }
6079
6080 #define TRY_WITH_GC(alloc) do { \
6081 if (!(alloc) && \
6082 (!garbage_collect_with_gvl(objspace, 1, 1, GPR_FLAG_MALLOC) || /* full mark && immediate sweep */ \
6083 !(alloc))) { \
6084 ruby_memerror(); \
6085 } \
6086 } while (0)
6087
6088 static void *
6089 objspace_xmalloc(rb_objspace_t *objspace, size_t size)
6090 {
6091 void *mem;
6092
6093 size = objspace_malloc_prepare(objspace, size);
6094 TRY_WITH_GC(mem = malloc(size));
6095 size = objspace_malloc_size(objspace, mem, size);
6096 objspace_malloc_increase(objspace, mem, size, 0, MEMOP_TYPE_MALLOC);
6097 return objspace_malloc_fixup(objspace, mem, size);
6098 }
6099
6100 static void *
6101 objspace_xrealloc(rb_objspace_t *objspace, void *ptr, size_t new_size, size_t old_size)
6102 {
6103 void *mem;
6104
6105 if ((ssize_t)new_size < 0) {
6106 negative_size_allocation_error("negative re-allocation size");
6107 }
6108
6109 if (!ptr) return objspace_xmalloc(objspace, new_size);
6110
6111 /*
6112 * The behavior of realloc(ptr, 0) is implementation defined.
6113 * Therefore we don't use realloc(ptr, 0) for portability reason.
6114 * see http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_400.htm
6115 */
6116 if (new_size == 0) {
6117 objspace_xfree(objspace, ptr, old_size);
6118 return 0;
6119 }
6120
6121 #if CALC_EXACT_MALLOC_SIZE
6122 new_size += sizeof(size_t);
6123 ptr = (size_t *)ptr - 1;
6124 oldsize = ((size_t *)ptr)[0];
6125 #endif
6126
6127 old_size = objspace_malloc_size(objspace, ptr, old_size);
6128 TRY_WITH_GC(mem = realloc(ptr, new_size));
6129 new_size = objspace_malloc_size(objspace, mem, new_size);
6130
6131 #if CALC_EXACT_MALLOC_SIZE
6132 ((size_t *)mem)[0] = new_size;
6133 mem = (size_t *)mem + 1;
6134 #endif
6135
6136 objspace_malloc_increase(objspace, mem, new_size, old_size, MEMOP_TYPE_REALLOC);
6137
6138 return mem;
6139 }
6140
6141 static void
6142 objspace_xfree(rb_objspace_t *objspace, void *ptr, size_t old_size)
6143 {
6144 #if CALC_EXACT_MALLOC_SIZE
6145 ptr = ((size_t *)ptr) - 1;
6146 oldsize = ((size_t*)ptr)[0];
6147 #endif
6148 old_size = objspace_malloc_size(objspace, ptr, old_size);
6149
6150 free(ptr);
6151
6152 objspace_malloc_increase(objspace, ptr, 0, old_size, MEMOP_TYPE_FREE);
6153 }
6154
6155 void *
6156 ruby_xmalloc(size_t size)
6157 {
6158 return objspace_xmalloc(&rb_objspace, size);
6159 }
6160
6161 static inline size_t
6162 xmalloc2_size(size_t n, size_t size)
6163 {
6164 size_t len = size * n;
6165 if (n != 0 && size != len / n) {
6166 rb_raise(rb_eArgError, "malloc: possible integer overflow");
6167 }
6168 return len;
6169 }
6170
6171 void *
6172 ruby_xmalloc2(size_t n, size_t size)
6173 {
6174 return objspace_xmalloc(&rb_objspace, xmalloc2_size(n, size));
6175 }
6176
6177 static void *
6178 objspace_xcalloc(rb_objspace_t *objspace, size_t count, size_t elsize)
6179 {
6180 void *mem;
6181 size_t size;
6182
6183 size = xmalloc2_size(count, elsize);
6184 size = objspace_malloc_prepare(objspace, size);
6185
6186 TRY_WITH_GC(mem = calloc(1, size));
6187 return objspace_malloc_fixup(objspace, mem, size);
6188 }
6189
6190 void *
6191 ruby_xcalloc(size_t n, size_t size)
6192 {
6193 return objspace_xcalloc(&rb_objspace, n, size);
6194 }
6195
6196 #ifdef ruby_sized_xrealloc
6197 #undef ruby_sized_xrealloc
6198 #endif
6199 void *
6200 ruby_sized_xrealloc(void *ptr, size_t new_size, size_t old_size)
6201 {
6202 return objspace_xrealloc(&rb_objspace, ptr, new_size, old_size);
6203 }
6204
6205 void *
6206 ruby_xrealloc(void *ptr, size_t new_size)
6207 {
6208 return ruby_sized_xrealloc(ptr, new_size, 0);
6209 }
6210
6211 #ifdef ruby_sized_xrealloc2
6212 #undef ruby_sized_xrealloc2
6213 #endif
6214 void *
6215 ruby_sized_xrealloc2(void *ptr, size_t n, size_t size, size_t old_n)
6216 {
6217 size_t len = size * n;
6218 if (n != 0 && size != len / n) {
6219 rb_raise(rb_eArgError, "realloc: possible integer overflow");
6220 }
6221 return objspace_xrealloc(&rb_objspace, ptr, len, old_n * size);
6222 }
6223
6224 void *
6225 ruby_xrealloc2(void *ptr, size_t n, size_t size)
6226 {
6227 return ruby_sized_xrealloc2(ptr, n, size, 0);
6228 }
6229
6230 #ifdef ruby_sized_xfree
6231 #undef ruby_sized_xfree
6232 #endif
6233 void
6234 ruby_sized_xfree(void *x, size_t size)
6235 {
6236 if (x) {
6237 objspace_xfree(&rb_objspace, x, size);
6238 }
6239 }
6240
6241 void
6242 ruby_xfree(void *x)
6243 {
6244 ruby_sized_xfree(x, 0);
6245 }
6246
6247 /* Mimic ruby_xmalloc, but need not rb_objspace.
6248 * should return pointer suitable for ruby_xfree
6249 */
6250 void *
6251 ruby_mimmalloc(size_t size)
6252 {
6253 void *mem;
6254 #if CALC_EXACT_MALLOC_SIZE
6255 size += sizeof(size_t);
6256 #endif
6257 mem = malloc(size);
6258 #if CALC_EXACT_MALLOC_SIZE
6259 /* set 0 for consistency of allocated_size/allocations */
6260 ((size_t *)mem)[0] = 0;
6261 mem = (size_t *)mem + 1;
6262 #endif
6263 return mem;
6264 }
6265
6266 void
6267 ruby_mimfree(void *ptr)
6268 {
6269 size_t *mem = (size_t *)ptr;
6270 #if CALC_EXACT_MALLOC_SIZE
6271 mem = mem - 1;
6272 #endif
6273 free(mem);
6274 }
6275
6276 #if MALLOC_ALLOCATED_SIZE
6277 /*
6278 * call-seq:
6279 * GC.malloc_allocated_size -> Integer
6280 *
6281 * Returns the size of memory allocated by malloc().
6282 *
6283 * Only available if ruby was built with +CALC_EXACT_MALLOC_SIZE+.
6284 */
6285
6286 static VALUE
6287 gc_malloc_allocated_size(VALUE self)
6288 {
6289 return UINT2NUM(rb_objspace.malloc_params.allocated_size);
6290 }
6291
6292 /*
6293 * call-seq:
6294 * GC.malloc_allocations -> Integer
6295 *
6296 * Returns the number of malloc() allocations.
6297 *
6298 * Only available if ruby was built with +CALC_EXACT_MALLOC_SIZE+.
6299 */
6300
6301 static VALUE
6302 gc_malloc_allocations(VALUE self)
6303 {
6304 return UINT2NUM(rb_objspace.malloc_params.allocations);
6305 }
6306 #endif
6307
6308 /*
6309 ------------------------------ WeakMap ------------------------------
6310 */
6311
6312 struct weakmap {
6313 st_table *obj2wmap; /* obj -> [ref,...] */
6314 st_table *wmap2obj; /* ref -> obj */
6315 VALUE final;
6316 };
6317
6318 #define WMAP_DELETE_DEAD_OBJECT_IN_MARK 0
6319
6320 #if WMAP_DELETE_DEAD_OBJECT_IN_MARK
6321 static int
6322 wmap_mark_map(st_data_t key, st_data_t val, st_data_t arg)
6323 {
6324 rb_objspace_t *objspace = (rb_objspace_t *)arg;
6325 VALUE obj = (VALUE)val;
6326 if (!is_live_object(objspace, obj)) return ST_DELETE;
6327 return ST_CONTINUE;
6328 }
6329 #endif
6330
6331 static void
6332 wmap_mark(void *ptr)
6333 {
6334 struct weakmap *w = ptr;
6335 #if WMAP_DELETE_DEAD_OBJECT_IN_MARK
6336 if (w->obj2wmap) st_foreach(w->obj2wmap, wmap_mark_map, (st_data_t)&rb_objspace);
6337 #endif
6338 rb_gc_mark(w->final);
6339 }
6340
6341 static int
6342 wmap_free_map(st_data_t key, st_data_t val, st_data_t arg)
6343 {
6344 VALUE *ptr = (VALUE *)val;
6345 ruby_sized_xfree(ptr, (ptr[0] + 1) * sizeof(VALUE));
6346 return ST_CONTINUE;
6347 }
6348
6349 static void
6350 wmap_free(void *ptr)
6351 {
6352 struct weakmap *w = ptr;
6353 st_foreach(w->obj2wmap, wmap_free_map, 0);
6354 st_free_table(w->obj2wmap);
6355 st_free_table(w->wmap2obj);
6356 }
6357
6358 static int
6359 wmap_memsize_map(st_data_t key, st_data_t val, st_data_t arg)
6360 {
6361 VALUE *ptr = (VALUE *)val;
6362 *(size_t *)arg += (ptr[0] + 1) * sizeof(VALUE);
6363 return ST_CONTINUE;
6364 }
6365
6366 static size_t
6367 wmap_memsize(const void *ptr)
6368 {
6369 size_t size;
6370 const struct weakmap *w = ptr;
6371 if (!w) return 0;
6372 size = sizeof(*w);
6373 size += st_memsize(w->obj2wmap);
6374 size += st_memsize(w->wmap2obj);
6375 st_foreach(w->obj2wmap, wmap_memsize_map, (st_data_t)&size);
6376 return size;
6377 }
6378
6379 static const rb_data_type_t weakmap_type = {
6380 "weakmap",
6381 {
6382 wmap_mark,
6383 wmap_free,
6384 wmap_memsize,
6385 },
6386 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
6387 };
6388
6389 static VALUE
6390 wmap_allocate(VALUE klass)
6391 {
6392 struct weakmap *w;
6393 VALUE obj = TypedData_Make_Struct(klass, struct weakmap, &weakmap_type, w);
6394 w->obj2wmap = st_init_numtable();
6395 w->wmap2obj = st_init_numtable();
6396 w->final = rb_obj_method(obj, ID2SYM(rb_intern("finalize")));
6397 return obj;
6398 }
6399
6400 static int
6401 wmap_final_func(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
6402 {
6403 VALUE wmap, *ptr, size, i, j;
6404 if (!existing) return ST_STOP;
6405 wmap = (VALUE)arg, ptr = (VALUE *)*value;
6406 for (i = j = 1, size = ptr[0]; i <= size; ++i) {
6407 if (ptr[i] != wmap) {
6408 ptr[j++] = ptr[i];
6409 }
6410 }
6411 if (j == 1) {
6412 ruby_sized_xfree(ptr, i * sizeof(VALUE));
6413 return ST_DELETE;
6414 }
6415 if (j < i) {
6416 ptr = ruby_sized_xrealloc2(ptr, j, sizeof(VALUE), i);
6417 ptr[0] = j;
6418 *value = (st_data_t)ptr;
6419 }
6420 return ST_CONTINUE;
6421 }
6422
6423 static VALUE
6424 wmap_finalize(VALUE self, VALUE objid)
6425 {
6426 st_data_t orig, wmap, data;
6427 VALUE obj, *rids, i, size;
6428 struct weakmap *w;
6429
6430 TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
6431 /* Get reference from object id. */
6432 obj = obj_id_to_ref(objid);
6433
6434 /* obj is original referenced object and/or weak reference. */
6435 orig = (st_data_t)obj;
6436 if (st_delete(w->obj2wmap, &orig, &data)) {
6437 rids = (VALUE *)data;
6438 size = *rids++;
6439 for (i = 0; i < size; ++i) {
6440 wmap = (st_data_t)rids[i];
6441 st_delete(w->wmap2obj, &wmap, NULL);
6442 }
6443 ruby_sized_xfree((VALUE *)data, (size + 1) * sizeof(VALUE));
6444 }
6445
6446 wmap = (st_data_t)obj;
6447 if (st_delete(w->wmap2obj, &wmap, &orig)) {
6448 wmap = (st_data_t)obj;
6449 st_update(w->obj2wmap, orig, wmap_final_func, wmap);
6450 }
6451 return self;
6452 }
6453
6454 struct wmap_iter_arg {
6455 rb_objspace_t *objspace;
6456 VALUE value;
6457 };
6458
6459 static int
6460 wmap_inspect_i(st_data_t key, st_data_t val, st_data_t arg)
6461 {
6462 VALUE str = (VALUE)arg;
6463 VALUE k = (VALUE)key, v = (VALUE)val;
6464
6465 if (RSTRING_PTR(str)[0] == '#') {
6466 rb_str_cat2(str, ", ");
6467 }
6468 else {
6469 rb_str_cat2(str, ": ");
6470 RSTRING_PTR(str)[0] = '#';
6471 }
6472 k = SPECIAL_CONST_P(k) ? rb_inspect(k) : rb_any_to_s(k);
6473 rb_str_append(str, k);
6474 rb_str_cat2(str, " => ");
6475 v = SPECIAL_CONST_P(v) ? rb_inspect(v) : rb_any_to_s(v);
6476 rb_str_append(str, v);
6477 OBJ_INFECT(str, k);
6478 OBJ_INFECT(str, v);
6479
6480 return ST_CONTINUE;
6481 }
6482
6483 static VALUE
6484 wmap_inspect(VALUE self)
6485 {
6486 VALUE str;
6487 VALUE c = rb_class_name(CLASS_OF(self));
6488 struct weakmap *w;
6489
6490 TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
6491 str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void *)self);
6492 if (w->wmap2obj) {
6493 st_foreach(w->wmap2obj, wmap_inspect_i, str);
6494 }
6495 RSTRING_PTR(str)[0] = '#';
6496 rb_str_cat2(str, ">");
6497 return str;
6498 }
6499
6500 static int
6501 wmap_each_i(st_data_t key, st_data_t val, st_data_t arg)
6502 {
6503 rb_objspace_t *objspace = (rb_objspace_t *)arg;
6504 VALUE obj = (VALUE)val;
6505 if (is_id_value(objspace, obj) && is_live_object(objspace, obj)) {
6506 rb_yield_values(2, (VALUE)key, obj);
6507 }
6508 return ST_CONTINUE;
6509 }
6510
6511 /* Iterates over keys and objects in a weakly referenced object */
6512 static VALUE
6513 wmap_each(VALUE self)
6514 {
6515 struct weakmap *w;
6516 rb_objspace_t *objspace = &rb_objspace;
6517
6518 TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
6519 st_foreach(w->wmap2obj, wmap_each_i, (st_data_t)objspace);
6520 return self;
6521 }
6522
6523 static int
6524 wmap_each_key_i(st_data_t key, st_data_t val, st_data_t arg)
6525 {
6526 rb_objspace_t *objspace = (rb_objspace_t *)arg;
6527 VALUE obj = (VALUE)val;
6528 if (is_id_value(objspace, obj) && is_live_object(objspace, obj)) {
6529 rb_yield((VALUE)key);
6530 }
6531 return ST_CONTINUE;
6532 }
6533
6534 /* Iterates over keys and objects in a weakly referenced object */
6535 static VALUE
6536 wmap_each_key(VALUE self)
6537 {
6538 struct weakmap *w;
6539 rb_objspace_t *objspace = &rb_objspace;
6540
6541 TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
6542 st_foreach(w->wmap2obj, wmap_each_key_i, (st_data_t)objspace);
6543 return self;
6544 }
6545
6546 static int
6547 wmap_each_value_i(st_data_t key, st_data_t val, st_data_t arg)
6548 {
6549 rb_objspace_t *objspace = (rb_objspace_t *)arg;
6550 VALUE obj = (VALUE)val;
6551 if (is_id_value(objspace, obj) && is_live_object(objspace, obj)) {
6552 rb_yield(obj);
6553 }
6554 return ST_CONTINUE;
6555 }
6556
6557 /* Iterates over keys and objects in a weakly referenced object */
6558 static VALUE
6559 wmap_each_value(VALUE self)
6560 {
6561 struct weakmap *w;
6562 rb_objspace_t *objspace = &rb_objspace;
6563
6564 TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
6565 st_foreach(w->wmap2obj, wmap_each_value_i, (st_data_t)objspace);
6566 return self;
6567 }
6568
6569 static int
6570 wmap_keys_i(st_data_t key, st_data_t val, st_data_t arg)
6571 {
6572 struct wmap_iter_arg *argp = (struct wmap_iter_arg *)arg;
6573 rb_objspace_t *objspace = argp->objspace;
6574 VALUE ary = argp->value;
6575 VALUE obj = (VALUE)val;
6576 if (is_id_value(objspace, obj) && is_live_object(objspace, obj)) {
6577 rb_ary_push(ary, (VALUE)key);
6578 }
6579 return ST_CONTINUE;
6580 }
6581
6582 /* Iterates over keys and objects in a weakly referenced object */
6583 static VALUE
6584 wmap_keys(VALUE self)
6585 {
6586 struct weakmap *w;
6587 struct wmap_iter_arg args;
6588
6589 TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
6590 args.objspace = &rb_objspace;
6591 args.value = rb_ary_new();
6592 st_foreach(w->wmap2obj, wmap_keys_i, (st_data_t)&args);
6593 return args.value;
6594 }
6595
6596 static int
6597 wmap_values_i(st_data_t key, st_data_t val, st_data_t arg)
6598 {
6599 struct wmap_iter_arg *argp = (struct wmap_iter_arg *)arg;
6600 rb_objspace_t *objspace = argp->objspace;
6601 VALUE ary = argp->value;
6602 VALUE obj = (VALUE)val;
6603 if (is_id_value(objspace, obj) && is_live_object(objspace, obj)) {
6604 rb_ary_push(ary, obj);
6605 }
6606 return ST_CONTINUE;
6607 }
6608
6609 /* Iterates over values and objects in a weakly referenced object */
6610 static VALUE
6611 wmap_values(VALUE self)
6612 {
6613 struct weakmap *w;
6614 struct wmap_iter_arg args;
6615
6616 TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
6617 args.objspace = &rb_objspace;
6618 args.value = rb_ary_new();
6619 st_foreach(w->wmap2obj, wmap_values_i, (st_data_t)&args);
6620 return args.value;
6621 }
6622
6623 static int
6624 wmap_aset_update(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
6625 {
6626 VALUE size, *ptr, *optr;
6627 if (existing) {
6628 size = (ptr = optr = (VALUE *)*val)[0];
6629 ++size;
6630 ptr = ruby_sized_xrealloc2(ptr, size + 1, sizeof(VALUE), size);
6631 }
6632 else {
6633 optr = 0;
6634 size = 1;
6635 ptr = ruby_xmalloc2(2, sizeof(VALUE));
6636 }
6637 ptr[0] = size;
6638 ptr[size] = (VALUE)arg;
6639 if (ptr == optr) return ST_STOP;
6640 *val = (st_data_t)ptr;
6641 return ST_CONTINUE;
6642 }
6643
6644 /* Creates a weak reference from the given key to the given value */
6645 static VALUE
6646 wmap_aset(VALUE self, VALUE wmap, VALUE orig)
6647 {
6648 struct weakmap *w;
6649
6650 TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
6651 should_be_finalizable(orig);
6652 should_be_finalizable(wmap);
6653 define_final0(orig, w->final);
6654 define_final0(wmap, w->final);
6655 st_update(w->obj2wmap, (st_data_t)orig, wmap_aset_update, wmap);
6656 st_insert(w->wmap2obj, (st_data_t)wmap, (st_data_t)orig);
6657 return nonspecial_obj_id(orig);
6658 }
6659
6660 /* Retrieves a weakly referenced object with the given key */
6661 static VALUE
6662 wmap_aref(VALUE self, VALUE wmap)
6663 {
6664 st_data_t data;
6665 VALUE obj;
6666 struct weakmap *w;
6667 rb_objspace_t *objspace = &rb_objspace;
6668
6669 TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
6670 if (!st_lookup(w->wmap2obj, (st_data_t)wmap, &data)) return Qnil;
6671 obj = (VALUE)data;
6672 if (!is_id_value(objspace, obj)) return Qnil;
6673 if (!is_live_object(objspace, obj)) return Qnil;
6674 return obj;
6675 }
6676
6677 /* Returns +true+ if +key+ is registered */
6678 static VALUE
6679 wmap_has_key(VALUE self, VALUE key)
6680 {
6681 return NIL_P(wmap_aref(self, key)) ? Qfalse : Qtrue;
6682 }
6683
6684 static VALUE
6685 wmap_size(VALUE self)
6686 {
6687 struct weakmap *w;
6688 st_index_t n;
6689
6690 TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
6691 n = w->wmap2obj->num_entries;
6692 #if SIZEOF_ST_INDEX_T <= SIZEOF_LONG
6693 return ULONG2NUM(n);
6694 #else
6695 return ULL2NUM(n);
6696 #endif
6697 }
6698
6699 /*
6700 ------------------------------ GC profiler ------------------------------
6701 */
6702
6703 #define GC_PROFILE_RECORD_DEFAULT_SIZE 100
6704
6705 static double
6706 getrusage_time(void)
6707 {
6708 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
6709 {
6710 static int try_clock_gettime = 1;
6711 struct timespec ts;
6712 if (try_clock_gettime && clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0) {
6713 return ts.tv_sec + ts.tv_nsec * 1e-9;
6714 }
6715 else {
6716 try_clock_gettime = 0;
6717 }
6718 }
6719 #endif
6720
6721 #ifdef RUSAGE_SELF
6722 {
6723 struct rusage usage;
6724 struct timeval time;
6725 if (getrusage(RUSAGE_SELF, &usage) == 0) {
6726 time = usage.ru_utime;
6727 return time.tv_sec + time.tv_usec * 1e-6;
6728 }
6729 }
6730 #endif
6731
6732 #ifdef _WIN32
6733 {
6734 FILETIME creation_time, exit_time, kernel_time, user_time;
6735 ULARGE_INTEGER ui;
6736 LONG_LONG q;
6737 double t;
6738
6739 if (GetProcessTimes(GetCurrentProcess(),
6740 &creation_time, &exit_time, &kernel_time, &user_time) != 0) {
6741 memcpy(&ui, &user_time, sizeof(FILETIME));
6742 q = ui.QuadPart / 10L;
6743 t = (DWORD)(q % 1000000L) * 1e-6;
6744 q /= 1000000L;
6745 #ifdef __GNUC__
6746 t += q;
6747 #else
6748 t += (double)(DWORD)(q >> 16) * (1 << 16);
6749 t += (DWORD)q & ~(~0 << 16);
6750 #endif
6751 return t;
6752 }
6753 }
6754 #endif
6755
6756 return 0.0;
6757 }
6758
6759 static inline void
6760 gc_prof_setup_new_record(rb_objspace_t *objspace, int reason)
6761 {
6762 if (objspace->profile.run) {
6763 size_t index = objspace->profile.next_index;
6764 gc_profile_record *record;
6765
6766 /* create new record */
6767 objspace->profile.next_index++;
6768
6769 if (!objspace->profile.records) {
6770 objspace->profile.size = GC_PROFILE_RECORD_DEFAULT_SIZE;
6771 objspace->profile.records = malloc(sizeof(gc_profile_record) * objspace->profile.size);
6772 }
6773 if (index >= objspace->profile.size) {
6774 objspace->profile.size += 1000;
6775 objspace->profile.records = realloc(objspace->profile.records, sizeof(gc_profile_record) * objspace->profile.size);
6776 }
6777 if (!objspace->profile.records) {
6778 rb_bug("gc_profile malloc or realloc miss");
6779 }
6780 record = objspace->profile.current_record = &objspace->profile.records[objspace->profile.next_index - 1];
6781 MEMZERO(record, gc_profile_record, 1);
6782
6783 /* setup before-GC parameter */
6784 record->flags = reason | ((ruby_gc_stress && !ruby_disable_gc_stress) ? GPR_FLAG_STRESS : 0);
6785 #if MALLOC_ALLOCATED_SIZE
6786 record->allocated_size = malloc_allocated_size;
6787 #endif
6788 #if GC_PROFILE_DETAIL_MEMORY
6789 #ifdef RUSAGE_SELF
6790 {
6791 struct rusage usage;
6792 if (getrusage(RUSAGE_SELF, &usage) == 0) {
6793 record->maxrss = usage.ru_maxrss;
6794 record->minflt = usage.ru_minflt;
6795 record->majflt = usage.ru_majflt;
6796 }
6797 }
6798 #endif
6799 #endif
6800 }
6801 }
6802
6803 static inline void
6804 gc_prof_timer_start(rb_objspace_t *objspace)
6805 {
6806 if (gc_prof_enabled(objspace)) {
6807 gc_profile_record *record = gc_prof_record(objspace);
6808 #if GC_PROFILE_MORE_DETAIL
6809 record->prepare_time = objspace->profile.prepare_time;
6810 #endif
6811 record->gc_time = 0;
6812 record->gc_invoke_time = getrusage_time();
6813 }
6814 }
6815
6816 static double
6817 elapsed_time_from(double time)
6818 {
6819 double now = getrusage_time();
6820 if (now > time) {
6821 return now - time;
6822 }
6823 else {
6824 return 0;
6825 }
6826 }
6827
6828 static inline void
6829 gc_prof_timer_stop(rb_objspace_t *objspace)
6830 {
6831 if (gc_prof_enabled(objspace)) {
6832 gc_profile_record *record = gc_prof_record(objspace);
6833 record->gc_time = elapsed_time_from(record->gc_invoke_time);
6834 record->gc_invoke_time -= objspace->profile.invoke_time;
6835 }
6836 }
6837
6838 static inline void
6839 gc_prof_mark_timer_start(rb_objspace_t *objspace)
6840 {
6841 if (RUBY_DTRACE_GC_MARK_BEGIN_ENABLED()) {
6842 RUBY_DTRACE_GC_MARK_BEGIN();
6843 }
6844 #if GC_PROFILE_MORE_DETAIL
6845 if (gc_prof_enabled(objspace)) {
6846 gc_prof_record(objspace)->gc_mark_time = getrusage_time();
6847 }
6848 #endif
6849 }
6850
6851 static inline void
6852 gc_prof_mark_timer_stop(rb_objspace_t *objspace)
6853 {
6854 if (RUBY_DTRACE_GC_MARK_END_ENABLED()) {
6855 RUBY_DTRACE_GC_MARK_END();
6856 }
6857 #if GC_PROFILE_MORE_DETAIL
6858 if (gc_prof_enabled(objspace)) {
6859 gc_profile_record *record = gc_prof_record(objspace);
6860 record->gc_mark_time = elapsed_time_from(record->gc_mark_time);
6861 }
6862 #endif
6863 }
6864
6865 static inline void
6866 gc_prof_sweep_timer_start(rb_objspace_t *objspace)
6867 {
6868 if (RUBY_DTRACE_GC_SWEEP_BEGIN_ENABLED()) {
6869 RUBY_DTRACE_GC_SWEEP_BEGIN();
6870 }
6871 if (gc_prof_enabled(objspace)) {
6872 gc_profile_record *record = gc_prof_record(objspace);
6873
6874 if (record->gc_time > 0 || GC_PROFILE_MORE_DETAIL) {
6875 objspace->profile.gc_sweep_start_time = getrusage_time();
6876 }
6877 }
6878 }
6879
6880 static inline void
6881 gc_prof_sweep_timer_stop(rb_objspace_t *objspace)
6882 {
6883 if (RUBY_DTRACE_GC_SWEEP_END_ENABLED()) {
6884 RUBY_DTRACE_GC_SWEEP_END();
6885 }
6886
6887 if (gc_prof_enabled(objspace)) {
6888 double sweep_time;
6889 gc_profile_record *record = gc_prof_record(objspace);
6890
6891 if (record->gc_time > 0) {
6892 sweep_time = elapsed_time_from(objspace->profile.gc_sweep_start_time);
6893 /* need to accumulate GC time for lazy sweep after gc() */
6894 record->gc_time += sweep_time;
6895 }
6896 else if (GC_PROFILE_MORE_DETAIL) {
6897 sweep_time = elapsed_time_from(objspace->profile.gc_sweep_start_time);
6898 }
6899
6900 #if GC_PROFILE_MORE_DETAIL
6901 record->gc_sweep_time += sweep_time;
6902 if (heap_pages_deferred_final) record->flags |= GPR_FLAG_HAVE_FINALIZE;
6903 #endif
6904 if (heap_pages_deferred_final) objspace->profile.latest_gc_info |= GPR_FLAG_HAVE_FINALIZE;
6905 }
6906 }
6907
6908 static inline void
6909 gc_prof_set_malloc_info(rb_objspace_t *objspace)
6910 {
6911 #if GC_PROFILE_MORE_DETAIL
6912 if (gc_prof_enabled(objspace)) {
6913 gc_profile_record *record = gc_prof_record(objspace);
6914 record->allocate_increase = malloc_increase;
6915 record->allocate_limit = malloc_limit;
6916 }
6917 #endif
6918 }
6919
6920 static inline void
6921 gc_prof_set_heap_info(rb_objspace_t *objspace)
6922 {
6923 if (gc_prof_enabled(objspace)) {
6924 gc_profile_record *record = gc_prof_record(objspace);
6925 size_t live = objspace->profile.total_allocated_object_num_at_gc_start - objspace->profile.total_freed_object_num;
6926 size_t total = objspace->profile.heap_used_at_gc_start * HEAP_OBJ_LIMIT;
6927
6928 #if GC_PROFILE_MORE_DETAIL
6929 record->heap_use_pages = objspace->profile.heap_used_at_gc_start;
6930 record->heap_live_objects = live;
6931 record->heap_free_objects = total - live;
6932 #endif
6933
6934 record->heap_total_objects = total;
6935 record->heap_use_size = live * sizeof(RVALUE);
6936 record->heap_total_size = total * sizeof(RVALUE);
6937 }
6938 }
6939
6940 /*
6941 * call-seq:
6942 * GC::Profiler.clear -> nil
6943 *
6944 * Clears the GC profiler data.
6945 *
6946 */
6947
6948 static VALUE
6949 gc_profile_clear(void)
6950 {
6951 rb_objspace_t *objspace = &rb_objspace;
6952 if (GC_PROFILE_RECORD_DEFAULT_SIZE * 2 < objspace->profile.size) {
6953 objspace->profile.size = GC_PROFILE_RECORD_DEFAULT_SIZE * 2;
6954 objspace->profile.records = realloc(objspace->profile.records, sizeof(gc_profile_record) * objspace->profile.size);
6955 if (!objspace->profile.records) {
6956 rb_memerror();
6957 }
6958 }
6959 MEMZERO(objspace->profile.records, gc_profile_record, objspace->profile.size);
6960 objspace->profile.next_index = 0;
6961 objspace->profile.current_record = 0;
6962 return Qnil;
6963 }
6964
6965 /*
6966 * call-seq:
6967 * GC::Profiler.raw_data -> [Hash, ...]
6968 *
6969 * Returns an Array of individual raw profile data Hashes ordered
6970 * from earliest to latest by +:GC_INVOKE_TIME+.
6971 *
6972 * For example:
6973 *
6974 * [
6975 * {
6976 * :GC_TIME=>1.3000000000000858e-05,
6977 * :GC_INVOKE_TIME=>0.010634999999999999,
6978 * :HEAP_USE_SIZE=>289640,
6979 * :HEAP_TOTAL_SIZE=>588960,
6980 * :HEAP_TOTAL_OBJECTS=>14724,
6981 * :GC_IS_MARKED=>false
6982 * },
6983 * # ...
6984 * ]
6985 *
6986 * The keys mean:
6987 *
6988 * +:GC_TIME+::
6989 * Time elapsed in seconds for this GC run
6990 * +:GC_INVOKE_TIME+::
6991 * Time elapsed in seconds from startup to when the GC was invoked
6992 * +:HEAP_USE_SIZE+::
6993 * Total bytes of heap used
6994 * +:HEAP_TOTAL_SIZE+::
6995 * Total size of heap in bytes
6996 * +:HEAP_TOTAL_OBJECTS+::
6997 * Total number of objects
6998 * +:GC_IS_MARKED+::
6999 * Returns +true+ if the GC is in mark phase
7000 *
7001 * If ruby was built with +GC_PROFILE_MORE_DETAIL+, you will also have access
7002 * to the following hash keys:
7003 *
7004 * +:GC_MARK_TIME+::
7005 * +:GC_SWEEP_TIME+::
7006 * +:ALLOCATE_INCREASE+::
7007 * +:ALLOCATE_LIMIT+::
7008 * +:HEAP_USE_PAGES+::
7009 * +:HEAP_LIVE_OBJECTS+::
7010 * +:HEAP_FREE_OBJECTS+::
7011 * +:HAVE_FINALIZE+::
7012 *
7013 */
7014
7015 static VALUE
7016 gc_profile_record_get(void)
7017 {
7018 VALUE prof;
7019 VALUE gc_profile = rb_ary_new();
7020 size_t i;
7021 rb_objspace_t *objspace = (&rb_objspace);
7022
7023 if (!objspace->profile.run) {
7024 return Qnil;
7025 }
7026
7027 for (i =0; i < objspace->profile.next_index; i++) {
7028 gc_profile_record *record = &objspace->profile.records[i];
7029
7030 prof = rb_hash_new();
7031 rb_hash_aset(prof, ID2SYM(rb_intern("GC_FLAGS")), gc_info_decode(record->flags, rb_hash_new()));
7032 rb_hash_aset(prof, ID2SYM(rb_intern("GC_TIME")), DBL2NUM(record->gc_time));
7033 rb_hash_aset(prof, ID2SYM(rb_intern("GC_INVOKE_TIME")), DBL2NUM(record->gc_invoke_time));
7034 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), SIZET2NUM(record->heap_use_size));
7035 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")), SIZET2NUM(record->heap_total_size));
7036 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")), SIZET2NUM(record->heap_total_objects));
7037 rb_hash_aset(prof, ID2SYM(rb_intern("GC_IS_MARKED")), Qtrue);
7038 #if GC_PROFILE_MORE_DETAIL
7039 rb_hash_aset(prof, ID2SYM(rb_intern("GC_MARK_TIME")), DBL2NUM(record->gc_mark_time));
7040 rb_hash_aset(prof, ID2SYM(rb_intern("GC_SWEEP_TIME")), DBL2NUM(record->gc_sweep_time));
7041 rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_INCREASE")), SIZET2NUM(record->allocate_increase));
7042 rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_LIMIT")), SIZET2NUM(record->allocate_limit));
7043 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_PAGES")), SIZET2NUM(record->heap_use_pages));
7044 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_LIVE_OBJECTS")), SIZET2NUM(record->heap_live_objects));
7045 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_FREE_OBJECTS")), SIZET2NUM(record->heap_free_objects));
7046
7047 rb_hash_aset(prof, ID2SYM(rb_intern("REMOVING_OBJECTS")), SIZET2NUM(record->removing_objects));
7048 rb_hash_aset(prof, ID2SYM(rb_intern("EMPTY_OBJECTS")), SIZET2NUM(record->empty_objects));
7049
7050 rb_hash_aset(prof, ID2SYM(rb_intern("HAVE_FINALIZE")), (record->flags & GPR_FLAG_HAVE_FINALIZE) ? Qtrue : Qfalse);
7051 #endif
7052
7053 #if RGENGC_PROFILE > 0
7054 rb_hash_aset(prof, ID2SYM(rb_intern("OLD_OBJECTS")), SIZET2NUM(record->old_objects));
7055 rb_hash_aset(prof, ID2SYM(rb_intern("REMEMBED_NORMAL_OBJECTS")), SIZET2NUM(record->remembered_normal_objects));
7056 rb_hash_aset(prof, ID2SYM(rb_intern("REMEMBED_SHADY_OBJECTS")), SIZET2NUM(record->remembered_shady_objects));
7057 #endif
7058 rb_ary_push(gc_profile, prof);
7059 }
7060
7061 return gc_profile;
7062 }
7063
7064 #if GC_PROFILE_MORE_DETAIL
7065 #define MAJOR_REASON_MAX 0x10
7066
7067 static char *
7068 gc_profile_dump_major_reason(int flags, char *buff)
7069 {
7070 int reason = flags & GPR_FLAG_MAJOR_MASK;
7071 int i = 0;
7072
7073 if (reason == GPR_FLAG_NONE) {
7074 buff[0] = '-';
7075 buff[1] = 0;
7076 }
7077 else {
7078 #define C(x, s) \
7079 if (reason & GPR_FLAG_MAJOR_BY_##x) { \
7080 buff[i++] = #x[0]; \
7081 if (i >= MAJOR_REASON_MAX) rb_bug("gc_profile_dump_major_reason: overflow"); \
7082 buff[i] = 0; \
7083 }
7084 C(NOFREE, N);
7085 C(OLDGEN, O);
7086 C(SHADY, S);
7087 C(RESCAN, R);
7088 C(STRESS, T);
7089 #if RGENGC_ESTIMATE_OLDMALLOC
7090 C(OLDMALLOC, M);
7091 #endif
7092 #undef C
7093 }
7094 return buff;
7095 }
7096 #endif
7097
7098 static void
7099 gc_profile_dump_on(VALUE out, VALUE (*append)(VALUE, VALUE))
7100 {
7101 rb_objspace_t *objspace = &rb_objspace;
7102 size_t count = objspace->profile.next_index;
7103 #ifdef MAJOR_REASON_MAX
7104 char reason_str[MAJOR_REASON_MAX];
7105 #endif
7106
7107 if (objspace->profile.run && count /* > 1 */) {
7108 size_t i;
7109 const gc_profile_record *record;
7110
7111 append(out, rb_sprintf("GC %"PRIuSIZE" invokes.\n", objspace->profile.count));
7112 append(out, rb_str_new_cstr("Index Invoke Time(sec) Use Size(byte) Total Size(byte) Total Object GC Time(ms)\n"));
7113
7114 for (i = 0; i < count; i++) {
7115 record = &objspace->profile.records[i];
7116 append(out, rb_sprintf("%5"PRIdSIZE" %19.3f %20"PRIuSIZE" %20"PRIuSIZE" %20"PRIuSIZE" %30.20f\n",
7117 i+1, record->gc_invoke_time, record->heap_use_size,
7118 record->heap_total_size, record->heap_total_objects, record->gc_time*1000));
7119 }
7120
7121 #if GC_PROFILE_MORE_DETAIL
7122 append(out, rb_str_new_cstr("\n\n" \
7123 "More detail.\n" \
7124 "Prepare Time = Previously GC's rest sweep time\n"
7125 "Index Flags Allocate Inc. Allocate Limit"
7126 #if CALC_EXACT_MALLOC_SIZE
7127 " Allocated Size"
7128 #endif
7129 " Use Page Mark Time(ms) Sweep Time(ms) Prepare Time(ms) LivingObj FreeObj RemovedObj EmptyObj"
7130 #if RGENGC_PROFILE
7131 " OldgenObj RemNormObj RemShadObj"
7132 #endif
7133 #if GC_PROFILE_DETAIL_MEMORY
7134 " MaxRSS(KB) MinorFLT MajorFLT"
7135 #endif
7136 "\n"));
7137
7138 for (i = 0; i < count; i++) {
7139 record = &objspace->profile.records[i];
7140 append(out, rb_sprintf("%5"PRIdSIZE" %4s/%c/%6s%c %13"PRIuSIZE" %15"PRIuSIZE
7141 #if CALC_EXACT_MALLOC_SIZE
7142 " %15"PRIuSIZE
7143 #endif
7144 " %9"PRIuSIZE" %17.12f %17.12f %17.12f %10"PRIuSIZE" %10"PRIuSIZE" %10"PRIuSIZE" %10"PRIuSIZE
7145 #if RGENGC_PROFILE
7146 "%10"PRIuSIZE" %10"PRIuSIZE" %10"PRIuSIZE
7147 #endif
7148 #if GC_PROFILE_DETAIL_MEMORY
7149 "%11ld %8ld %8ld"
7150 #endif
7151
7152 "\n",
7153 i+1,
7154 gc_profile_dump_major_reason(record->flags, reason_str),
7155 (record->flags & GPR_FLAG_HAVE_FINALIZE) ? 'F' : '.',
7156 (record->flags & GPR_FLAG_NEWOBJ) ? "NEWOBJ" :
7157 (record->flags & GPR_FLAG_MALLOC) ? "MALLOC" :
7158 (record->flags & GPR_FLAG_METHOD) ? "METHOD" :
7159 (record->flags & GPR_FLAG_CAPI) ? "CAPI__" : "??????",
7160 (record->flags & GPR_FLAG_STRESS) ? '!' : ' ',
7161 record->allocate_increase, record->allocate_limit,
7162 #if CALC_EXACT_MALLOC_SIZE
7163 record->allocated_size,
7164 #endif
7165 record->heap_use_pages,
7166 record->gc_mark_time*1000,
7167 record->gc_sweep_time*1000,
7168 record->prepare_time*1000,
7169
7170 record->heap_live_objects,
7171 record->heap_free_objects,
7172 record->removing_objects,
7173 record->empty_objects
7174 #if RGENGC_PROFILE
7175 ,
7176 record->old_objects,
7177 record->remembered_normal_objects,
7178 record->remembered_shady_objects
7179 #endif
7180 #if GC_PROFILE_DETAIL_MEMORY
7181 ,
7182 record->maxrss / 1024,
7183 record->minflt,
7184 record->majflt
7185 #endif
7186
7187 ));
7188 }
7189 #endif
7190 }
7191 }
7192
7193 /*
7194 * call-seq:
7195 * GC::Profiler.result -> String
7196 *
7197 * Returns a profile data report such as:
7198 *
7199 * GC 1 invokes.
7200 * Index Invoke Time(sec) Use Size(byte) Total Size(byte) Total Object GC time(ms)
7201 * 1 0.012 159240 212940 10647 0.00000000000001530000
7202 */
7203
7204 static VALUE
7205 gc_profile_result(void)
7206 {
7207 VALUE str = rb_str_buf_new(0);
7208 gc_profile_dump_on(str, rb_str_buf_append);
7209 return str;
7210 }
7211
7212 /*
7213 * call-seq:
7214 * GC::Profiler.report
7215 * GC::Profiler.report(io)
7216 *
7217 * Writes the GC::Profiler.result to <tt>$stdout</tt> or the given IO object.
7218 *
7219 */
7220
7221 static VALUE
7222 gc_profile_report(int argc, VALUE *argv, VALUE self)
7223 {
7224 VALUE out;
7225
7226 if (argc == 0) {
7227 out = rb_stdout;
7228 }
7229 else {
7230 rb_scan_args(argc, argv, "01", &out);
7231 }
7232 gc_profile_dump_on(out, rb_io_write);
7233
7234 return Qnil;
7235 }
7236
7237 /*
7238 * call-seq:
7239 * GC::Profiler.total_time -> float
7240 *
7241 * The total time used for garbage collection in seconds
7242 */
7243
7244 static VALUE
7245 gc_profile_total_time(VALUE self)
7246 {
7247 double time = 0;
7248 rb_objspace_t *objspace = &rb_objspace;
7249
7250 if (objspace->profile.run && objspace->profile.next_index > 0) {
7251 size_t i;
7252 size_t count = objspace->profile.next_index;
7253
7254 for (i = 0; i < count; i++) {
7255 time += objspace->profile.records[i].gc_time;
7256 }
7257 }
7258 return DBL2NUM(time);
7259 }
7260
7261 /*
7262 * call-seq:
7263 * GC::Profiler.enabled? -> true or false
7264 *
7265 * The current status of GC profile mode.
7266 */
7267
7268 static VALUE
7269 gc_profile_enable_get(VALUE self)
7270 {
7271 rb_objspace_t *objspace = &rb_objspace;
7272 return objspace->profile.run ? Qtrue : Qfalse;
7273 }
7274
7275 /*
7276 * call-seq:
7277 * GC::Profiler.enable -> nil
7278 *
7279 * Starts the GC profiler.
7280 *
7281 */
7282
7283 static VALUE
7284 gc_profile_enable(void)
7285 {
7286 rb_objspace_t *objspace = &rb_objspace;
7287 objspace->profile.run = TRUE;
7288 objspace->profile.current_record = 0;
7289 return Qnil;
7290 }
7291
7292 /*
7293 * call-seq:
7294 * GC::Profiler.disable -> nil
7295 *
7296 * Stops the GC profiler.
7297 *
7298 */
7299
7300 static VALUE
7301 gc_profile_disable(void)
7302 {
7303 rb_objspace_t *objspace = &rb_objspace;
7304
7305 objspace->profile.run = FALSE;
7306 objspace->profile.current_record = 0;
7307 return Qnil;
7308 }
7309
7310 /*
7311 ------------------------------ DEBUG ------------------------------
7312 */
7313
7314 static const char *
7315 type_name(int type, VALUE obj)
7316 {
7317 switch (type) {
7318 #define TYPE_NAME(t) case (t): return #t;
7319 TYPE_NAME(T_NONE);
7320 TYPE_NAME(T_OBJECT);
7321 TYPE_NAME(T_CLASS);
7322 TYPE_NAME(T_MODULE);
7323 TYPE_NAME(T_FLOAT);
7324 TYPE_NAME(T_STRING);
7325 TYPE_NAME(T_REGEXP);
7326 TYPE_NAME(T_ARRAY);
7327 TYPE_NAME(T_HASH);
7328 TYPE_NAME(T_STRUCT);
7329 TYPE_NAME(T_BIGNUM);
7330 TYPE_NAME(T_FILE);
7331 TYPE_NAME(T_MATCH);
7332 TYPE_NAME(T_COMPLEX);
7333 TYPE_NAME(T_RATIONAL);
7334 TYPE_NAME(T_NIL);
7335 TYPE_NAME(T_TRUE);
7336 TYPE_NAME(T_FALSE);
7337 TYPE_NAME(T_SYMBOL);
7338 TYPE_NAME(T_FIXNUM);
7339 TYPE_NAME(T_UNDEF);
7340 TYPE_NAME(T_NODE);
7341 TYPE_NAME(T_ICLASS);
7342 TYPE_NAME(T_ZOMBIE);
7343 case T_DATA:
7344 if (obj && rb_objspace_data_type_name(obj)) {
7345 return rb_objspace_data_type_name(obj);
7346 }
7347 return "T_DATA";
7348 #undef TYPE_NAME
7349 }
7350 return "unknown";
7351 }
7352
7353 static const char *
7354 obj_type_name(VALUE obj)
7355 {
7356 return type_name(TYPE(obj), obj);
7357 }
7358
7359 #if GC_DEBUG
7360
7361 void
7362 rb_gcdebug_print_obj_condition(VALUE obj)
7363 {
7364 rb_objspace_t *objspace = &rb_objspace;
7365
7366 fprintf(stderr, "created at: %s:%d\n", RSTRING_PTR(RANY(obj)->file), FIX2INT(RANY(obj)->line));
7367
7368 if (is_pointer_to_heap(objspace, (void *)obj)) {
7369 fprintf(stderr, "pointer to heap?: true\n");
7370 }
7371 else {
7372 fprintf(stderr, "pointer to heap?: false\n");
7373 return;
7374 }
7375
7376 fprintf(stderr, "marked? : %s\n", MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj) ? "true" : "false");
7377 #if USE_RGENGC
7378 #if RGENGC_THREEGEN
7379 fprintf(stderr, "young? : %s\n", RVALUE_YOUNG_P(obj) ? "true" : "false");
7380 #endif
7381 fprintf(stderr, "old? : %s\n", RVALUE_OLD_P(obj) ? "true" : "false");
7382 fprintf(stderr, "WB-protected?: %s\n", RVALUE_WB_PROTECTED(obj) ? "true" : "false");
7383 fprintf(stderr, "remembered? : %s\n", MARKED_IN_BITMAP(GET_HEAP_REMEMBERSET_BITS(obj), obj) ? "true" : "false");
7384 #endif
7385
7386 if (is_lazy_sweeping(heap_eden)) {
7387 fprintf(stderr, "lazy sweeping?: true\n");
7388 fprintf(stderr, "swept?: %s\n", is_swept_object(objspace, obj) ? "done" : "not yet");
7389 }
7390 else {
7391 fprintf(stderr, "lazy sweeping?: false\n");
7392 }
7393 }
7394
7395 static VALUE
7396 gcdebug_sential(VALUE obj, VALUE name)
7397 {
7398 fprintf(stderr, "WARNING: object %s(%p) is inadvertently collected\n", (char *)name, (void *)obj);
7399 return Qnil;
7400 }
7401
7402 void
7403 rb_gcdebug_sentinel(VALUE obj, const char *name)
7404 {
7405 rb_define_finalizer(obj, rb_proc_new(gcdebug_sential, (VALUE)name));
7406 }
7407 #endif /* GC_DEBUG */
7408
7409 /*
7410 * Document-module: ObjectSpace
7411 *
7412 * The ObjectSpace module contains a number of routines
7413 * that interact with the garbage collection facility and allow you to
7414 * traverse all living objects with an iterator.
7415 *
7416 * ObjectSpace also provides support for object finalizers, procs that will be
7417 * called when a specific object is about to be destroyed by garbage
7418 * collection.
7419 *
7420 * a = "A"
7421 * b = "B"
7422 *
7423 * ObjectSpace.define_finalizer(a, proc {|id| puts "Finalizer one on #{id}" })
7424 * ObjectSpace.define_finalizer(b, proc {|id| puts "Finalizer two on #{id}" })
7425 *
7426 * _produces:_
7427 *
7428 * Finalizer two on 537763470
7429 * Finalizer one on 537763480
7430 */
7431
7432 /*
7433 * Document-class: ObjectSpace::WeakMap
7434 *
7435 * An ObjectSpace::WeakMap object holds references to
7436 * any objects, but those objects can get garbage collected.
7437 *
7438 * This class is mostly used internally by WeakRef, please use
7439 * +lib/weakref.rb+ for the public interface.
7440 */
7441
7442 /* Document-class: GC::Profiler
7443 *
7444 * The GC profiler provides access to information on GC runs including time,
7445 * length and object space size.
7446 *
7447 * Example:
7448 *
7449 * GC::Profiler.enable
7450 *
7451 * require 'rdoc/rdoc'
7452 *
7453 * GC::Profiler.report
7454 *
7455 * GC::Profiler.disable
7456 *
7457 * See also GC.count, GC.malloc_allocated_size and GC.malloc_allocations
7458 */
7459
7460 /*
7461 * The GC module provides an interface to Ruby's mark and
7462 * sweep garbage collection mechanism.
7463 *
7464 * Some of the underlying methods are also available via the ObjectSpace
7465 * module.
7466 *
7467 * You may obtain information about the operation of the GC through
7468 * GC::Profiler.
7469 */
7470
7471 void
7472 Init_GC(void)
7473 {
7474 VALUE rb_mObjSpace;
7475 VALUE rb_mProfiler;
7476 VALUE gc_constants;
7477
7478 rb_mGC = rb_define_module("GC");
7479 rb_define_singleton_method(rb_mGC, "start", gc_start_internal, -1);
7480 rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0);
7481 rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
7482 rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0);
7483 rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1);
7484 rb_define_singleton_method(rb_mGC, "count", gc_count, 0);
7485 rb_define_singleton_method(rb_mGC, "stat", gc_stat, -1);
7486 rb_define_singleton_method(rb_mGC, "latest_gc_info", gc_latest_gc_info, -1);
7487 rb_define_method(rb_mGC, "garbage_collect", gc_start_internal, -1);
7488
7489 gc_constants = rb_hash_new();
7490 rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(sizeof(RVALUE)));
7491 rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_OBJ_LIMIT")), SIZET2NUM(HEAP_OBJ_LIMIT));
7492 rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_BITMAP_SIZE")), SIZET2NUM(HEAP_BITMAP_SIZE));
7493 rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_BITMAP_PLANES")), SIZET2NUM(HEAP_BITMAP_PLANES));
7494 OBJ_FREEZE(gc_constants);
7495 rb_define_const(rb_mGC, "INTERNAL_CONSTANTS", gc_constants);
7496
7497 rb_mProfiler = rb_define_module_under(rb_mGC, "Profiler");
7498 rb_define_singleton_method(rb_mProfiler, "enabled?", gc_profile_enable_get, 0);
7499 rb_define_singleton_method(rb_mProfiler, "enable", gc_profile_enable, 0);
7500 rb_define_singleton_method(rb_mProfiler, "raw_data", gc_profile_record_get, 0);
7501 rb_define_singleton_method(rb_mProfiler, "disable", gc_profile_disable, 0);
7502 rb_define_singleton_method(rb_mProfiler, "clear", gc_profile_clear, 0);
7503 rb_define_singleton_method(rb_mProfiler, "result", gc_profile_result, 0);
7504 rb_define_singleton_method(rb_mProfiler, "report", gc_profile_report, -1);
7505 rb_define_singleton_method(rb_mProfiler, "total_time", gc_profile_total_time, 0);
7506
7507 rb_mObjSpace = rb_define_module("ObjectSpace");
7508 rb_define_module_function(rb_mObjSpace, "each_object", os_each_obj, -1);
7509 rb_define_module_function(rb_mObjSpace, "garbage_collect", gc_start_internal, -1);
7510
7511 rb_define_module_function(rb_mObjSpace, "define_finalizer", define_final, -1);
7512 rb_define_module_function(rb_mObjSpace, "undefine_finalizer", undefine_final, 1);
7513
7514 rb_define_module_function(rb_mObjSpace, "_id2ref", id2ref, 1);
7515
7516 nomem_error = rb_exc_new3(rb_eNoMemError,
7517 rb_obj_freeze(rb_str_new2("failed to allocate memory")));
7518 OBJ_TAINT(nomem_error);
7519 OBJ_FREEZE(nomem_error);
7520
7521 rb_define_method(rb_cBasicObject, "__id__", rb_obj_id, 0);
7522 rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0);
7523
7524 rb_define_module_function(rb_mObjSpace, "count_objects", count_objects, -1);
7525
7526 {
7527 VALUE rb_cWeakMap = rb_define_class_under(rb_mObjSpace, "WeakMap", rb_cObject);
7528 rb_define_alloc_func(rb_cWeakMap, wmap_allocate);
7529 rb_define_method(rb_cWeakMap, "[]=", wmap_aset, 2);
7530 rb_define_method(rb_cWeakMap, "[]", wmap_aref, 1);
7531 rb_define_method(rb_cWeakMap, "include?", wmap_has_key, 1);
7532 rb_define_method(rb_cWeakMap, "member?", wmap_has_key, 1);
7533 rb_define_method(rb_cWeakMap, "key?", wmap_has_key, 1);
7534 rb_define_method(rb_cWeakMap, "inspect", wmap_inspect, 0);
7535 rb_define_method(rb_cWeakMap, "each", wmap_each, 0);
7536 rb_define_method(rb_cWeakMap, "each_pair", wmap_each, 0);
7537 rb_define_method(rb_cWeakMap, "each_key", wmap_each_key, 0);
7538 rb_define_method(rb_cWeakMap, "each_value", wmap_each_value, 0);
7539 rb_define_method(rb_cWeakMap, "keys", wmap_keys, 0);
7540 rb_define_method(rb_cWeakMap, "values", wmap_values, 0);
7541 rb_define_method(rb_cWeakMap, "size", wmap_size, 0);
7542 rb_define_method(rb_cWeakMap, "length", wmap_size, 0);
7543 rb_define_private_method(rb_cWeakMap, "finalize", wmap_finalize, 1);
7544 rb_include_module(rb_cWeakMap, rb_mEnumerable);
7545 }
7546
7547 /* internal methods */
7548 rb_define_singleton_method(rb_mGC, "verify_internal_consistency", gc_verify_internal_consistency, 0);
7549 #if MALLOC_ALLOCATED_SIZE
7550 rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);
7551 rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0);
7552 #endif
7553
7554 /* ::GC::OPTS, which shows GC build options */
7555 {
7556 VALUE opts;
7557 rb_define_const(rb_mGC, "OPTS", opts = rb_ary_new());
7558 #define OPT(o) if (o) rb_ary_push(opts, rb_str_new2(#o))
7559 OPT(GC_DEBUG);
7560 OPT(USE_RGENGC);
7561 OPT(RGENGC_DEBUG);
7562 OPT(RGENGC_CHECK_MODE);
7563 OPT(RGENGC_PROFILE);
7564 OPT(RGENGC_THREEGEN);
7565 OPT(RGENGC_ESTIMATE_OLDMALLOC);
7566 OPT(GC_PROFILE_MORE_DETAIL);
7567 OPT(GC_ENABLE_LAZY_SWEEP);
7568 OPT(CALC_EXACT_MALLOC_SIZE);
7569 OPT(MALLOC_ALLOCATED_SIZE);
7570 OPT(MALLOC_ALLOCATED_SIZE_CHECK);
7571 OPT(GC_PROFILE_DETAIL_MEMORY);
7572 #undef OPT
7573 }
7574 }
ELTS_SHARED
#define ELTS_SHARED
Definition: ruby.h:817
os_each_struct::of
VALUE of
Definition: gc.c:1783
rb_objspace::hook_events
rb_event_flag_t hook_events
Definition: gc.c:508
rgengc_unprotect_logging_exit_func_i
static int rgengc_unprotect_logging_exit_func_i(st_data_t key, st_data_t val)
Definition: gc.c:4791
method_table_wrapper
Definition: internal.h:282
rb_objspace
#define rb_objspace
Definition: gc.c:599
RBASIC_CLEAR_CLASS
#define RBASIC_CLEAR_CLASS(obj)
Definition: internal.h:607
wmap_iter_arg::value
VALUE value
Definition: gc.c:6456
objspace_malloc_fixup
static void * objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
Definition: gc.c:6070
rb_objspace::mark_func_data_struct
Definition: gc.c:511
GPR_FLAG_MALLOC
Definition: gc.c:275
rb_gc
void rb_gc(void)
Definition: gc.c:5190
mark_hash
static void mark_hash(rb_objspace_t *objspace, st_table *tbl)
Definition: gc.c:3372
rb_thread_struct::cfp
rb_control_frame_t * cfp
Definition: vm_core.h:531
rb_gc_finalize_deferred
void rb_gc_finalize_deferred(void)
Definition: gc.c:2112
rb_class_remove_from_super_subclasses
void rb_class_remove_from_super_subclasses(VALUE klass)
Definition: class.c:80
rb_method_entry_struct::mark
char mark
Definition: method.h:99
RVALUE::node
struct RNode node
Definition: gc.c:349
T_SYMBOL
#define T_SYMBOL
Definition: ruby.h:494
gc_profile_record::heap_total_objects
size_t heap_total_objects
Definition: gc.c:291
each_obj_args
Definition: gc.c:1689
T_OBJECT
#define T_OBJECT
Definition: ruby.h:477
gc_marks
static void gc_marks(rb_objspace_t *objspace, int full_mark)
Definition: gc.c:4492
NODE_CALL
Definition: node.h:93
NODE_CASE
Definition: node.h:29
NODE_BLOCK_ARG
Definition: node.h:171
NODE_ARGSCAT
Definition: node.h:163
RMatch
Definition: re.h:44
ST_DELETE
Definition: st.h:100
wmap_iter_arg
Definition: gc.c:6454
new_size
static st_index_t new_size(st_index_t size)
Definition: st.c:184
rb_thread_struct::vm
rb_vm_t * vm
Definition: vm_core.h:526
rb_class_detach_subclasses
void rb_class_detach_subclasses(VALUE klass)
Definition: class.c:131
rb_method_definition_struct
Definition: method.h:78
stack_chunk
Definition: gc.c:393
rb_objspace::flags
struct rb_objspace::@104 flags
gc_heap_prepare_minimum_pages
static void gc_heap_prepare_minimum_pages(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:2817
NODE_DASGN
Definition: node.h:67
RFloat
Definition: ruby.h:805
heap_page::oldgen_bits
bits_t oldgen_bits[HEAP_BITMAP_LIMIT]
Definition: gc.c:578
NODE_DOT2
Definition: node.h:197
R
#define R(b, x)
Definition: sha2.c:203
ruby_thread_has_gvl_p
int ruby_thread_has_gvl_p(void)
Definition: thread.c:1492
FL_EXIVAR
#define FL_EXIVAR
Definition: ruby.h:1139
RVALUE::bignum
struct RBignum bignum
Definition: gc.c:347
rb_gc_writebarrier
void rb_gc_writebarrier(VALUE a, VALUE b)
Definition: gc.c:4731
root_objects_from
static void root_objects_from(VALUE obj, void *ptr)
Definition: gc.c:5800
gc_mark_roots
static void gc_mark_roots(rb_objspace_t *objspace, int full_mark, const char **categoryp)
Definition: gc.c:4058
RARRAY_LEN
#define RARRAY_LEN(a)
Definition: ruby.h:878
root_objects_data::func
void(* func)(const char *category, VALUE, void *)
Definition: gc.c:5795
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:327
rb_method_definition_struct::type
rb_method_type_t type
Definition: method.h:79
mark_tbl_arg::objspace
rb_objspace_t * objspace
Definition: gc.c:3319
heap_pages_final_slots
#define heap_pages_final_slots
Definition: gc.c:619
gc_profile_disable
static VALUE gc_profile_disable(void)
Definition: gc.c:7301
HEAP_BITMAP_LIMIT
Definition: gc.c:558
objspace_malloc_increase
static void objspace_malloc_increase(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type)
Definition: gc.c:5978
FALSE
#define FALSE
Definition: nkf.h:174
set_zero
static int set_zero(st_data_t key, st_data_t val, st_data_t arg)
Definition: gc.c:2554
RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1015
RUBY_DTRACE_GC_SWEEP_END_ENABLED
#define RUBY_DTRACE_GC_SWEEP_END_ENABLED()
Definition: probes.h:76
rb_method_definition_struct::attr
rb_method_attr_t attr
Definition: method.h:84
GC_PROFILE_MORE_DETAIL
#define GC_PROFILE_MORE_DETAIL
Definition: gc.c:238
STACK_START
#define STACK_START
Definition: gc.c:3224
rb_obj_id
VALUE rb_obj_id(VALUE obj)
Definition: gc.c:2373
strlen
size_t strlen(const char *)
rb_gc_mark_locations
#define rb_gc_mark_locations(start, end)
Definition: gc.c:3316
gc_profile_record_flag
gc_profile_record_flag
Definition: gc.c:260
INT2NUM
#define INT2NUM(x)
Definition: ruby.h:1288
heap_page::start
RVALUE * start
Definition: gc.c:566
RData::dfree
void(* dfree)(void *)
Definition: ruby.h:960
rb_objspace_free
void rb_objspace_free(rb_objspace_t *objspace)
Definition: gc.c:890
rb_objspace::need_major_gc
int need_major_gc
Definition: gc.c:521
NODE_UNTIL
Definition: node.h:37
gc_prof_set_malloc_info
static void gc_prof_set_malloc_info(rb_objspace_t *)
Definition: gc.c:6909
RCLASS_CONST_TBL
#define RCLASS_CONST_TBL(c)
Definition: internal.h:293
rb_const_entry_struct
Definition: constant.h:19
wmap_each
static VALUE wmap_each(VALUE self)
Definition: gc.c:6513
NODE_FCALL
Definition: node.h:95
T_FIXNUM
#define T_FIXNUM
Definition: ruby.h:489
st_table
Definition: st.h:69
RUBY_DEFAULT_FREE
#define RUBY_DEFAULT_FREE
Definition: ruby.h:1009
RSTRUCT
#define RSTRUCT(obj)
Definition: ruby.h:1127
NODE_CVASGN
Definition: node.h:79
NODE_IASGN2
Definition: node.h:75
rb_id2str
VALUE rb_id2str(ID id)
Definition: ripper.c:17160
pop_mark_stack_chunk
static void pop_mark_stack_chunk(mark_stack_t *stack)
Definition: gc.c:3151
os_each_struct::num
size_t num
Definition: gc.c:1782
ST_STOP
Definition: st.h:100
wmap_each_value
static VALUE wmap_each_value(VALUE self)
Definition: gc.c:6559
T_MATCH
#define T_MATCH
Definition: ruby.h:493
rb_objspace::gc_sweep_start_time
double gc_sweep_start_time
Definition: gc.c:497
NODE_REDO
Definition: node.h:47
mark_stack::unused_cache_size
size_t unused_cache_size
Definition: gc.c:404
rb_io_memsize
size_t rb_io_memsize(const rb_io_t *)
Definition: io.c:4280
gc_prof_timer_stop
static void gc_prof_timer_stop(rb_objspace_t *)
Definition: gc.c:6829
rgengc_remembered
static int rgengc_remembered(rb_objspace_t *objspace, VALUE obj)
Definition: gc.c:4642
NODE_MASGN
Definition: node.h:63
rb_yield_values
VALUE rb_yield_values(int n,...)
Definition: vm_eval.c:953
count
int count
Definition: encoding.c:48
RAISED_NOMEMORY
Definition: eval_intern.h:219
max
static int max(int a, int b)
Definition: strftime.c:141
objspace_and_reason::reason
int reason
Definition: gc.c:5079
heap_page_header
Definition: gc.c:376
id2ref
static VALUE id2ref(VALUE obj, VALUE objid)
Definition: gc.c:2301
NODE_MODULE
Definition: node.h:187
RVALUE::file
struct RFile file
Definition: gc.c:348
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1655
FIXNUM_FLAG
#define FIXNUM_FLAG
Definition: ruby.h:430
ruby_sized_xrealloc2
void * ruby_sized_xrealloc2(void *ptr, size_t n, size_t size, size_t old_n)
Definition: gc.c:6215
mark_keyvalue
static int mark_keyvalue(st_data_t key, st_data_t value, st_data_t data)
Definition: gc.c:3363
rb_objspace::size
size_t size
Definition: gc.c:461
GC_HEAP_GROWTH_FACTOR
#define GC_HEAP_GROWTH_FACTOR
Definition: gc.c:106
RVALUE_PROMOTED_P
static VALUE RVALUE_PROMOTED_P(VALUE obj)
Definition: gc.c:781
NODE_DXSTR
Definition: node.h:145
os_each_obj
static VALUE os_each_obj(int argc, VALUE *argv, VALUE os)
Definition: gc.c:1882
is_pointer_to_heap
static int is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
Definition: gc.c:1405
ruby.h
rb_objspace::run
int run
Definition: gc.c:457
rb_method_attr_struct::location
const VALUE location
Definition: method.h:73
objspace_and_reason
Definition: gc.c:5077
objspace_and_reason::immediate_sweep
int immediate_sweep
Definition: gc.c:5081
NODE_TO_ARY
Definition: node.h:169
ruby_stack_length
size_t ruby_stack_length(VALUE **p)
Definition: gc.c:3250
FLUSH_REGISTER_WINDOWS
#define FLUSH_REGISTER_WINDOWS
Definition: defines.h:270
NODE_ZSUPER
Definition: node.h:101
run_single_final
static VALUE run_single_final(VALUE arg)
Definition: gc.c:2013
malloc_allocated_size
#define malloc_allocated_size
Definition: gc.c:609
heap_page::rememberset_bits
bits_t rememberset_bits[HEAP_BITMAP_LIMIT]
Definition: gc.c:577
FL_TAINT
#define FL_TAINT
Definition: ruby.h:1137
CLASS_OF
#define CLASS_OF(v)
Definition: ruby.h:440
GC_HEAP_OLDOBJECT_LIMIT_FACTOR
#define GC_HEAP_OLDOBJECT_LIMIT_FACTOR
Definition: gc.c:112
heap_page_free
static void heap_page_free(rb_objspace_t *objspace, struct heap_page *page)
Definition: gc.c:989
T_MODULE
#define T_MODULE
Definition: ruby.h:480
NODE_VALIAS
Definition: node.h:181
rb_const_entry_struct::file
const VALUE file
Definition: constant.h:22
RCLASS_EXT
#define RCLASS_EXT(c)
Definition: classext.h:15
N
#define N
Definition: lgamma_r.c:20
rb_class_remove_from_module_subclasses
void rb_class_remove_from_module_subclasses(VALUE klass)
Definition: class.c:98
RVALUE_PROMOTE_INFANT
static void RVALUE_PROMOTE_INFANT(VALUE obj)
Definition: gc.c:788
rb_objspace::range
RVALUE * range[2]
Definition: gc.c:434
ATOMIC_EXCHANGE
#define ATOMIC_EXCHANGE(var, val)
Definition: ruby_atomic.h:131
rb_get_kwargs
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Definition: class.c:1918
wmap_each_i
static int wmap_each_i(st_data_t key, st_data_t val, st_data_t arg)
Definition: gc.c:6501
NODE_BACK_REF
Definition: node.h:129
rb_obj_is_thread
VALUE rb_obj_is_thread(VALUE obj)
Definition: vm.c:2155
rb_objspace::parent_object_is_old
int parent_object_is_old
Definition: gc.c:519
debug.h
Qtrue
#define Qtrue
Definition: ruby.h:426
NODE_DEFINED
Definition: node.h:215
st_insert
int st_insert(st_table *, st_data_t, st_data_t)
wmap_mark
static void wmap_mark(void *ptr)
Definition: gc.c:6332
gc_verify_internal_consistency
static VALUE gc_verify_internal_consistency(VALUE self)
Definition: gc.c:4224
heap_page::final_slots
size_t final_slots
Definition: gc.c:567
rb_objspace::increment
size_t increment
Definition: gc.c:437
rb_objspace::mark_func_data_struct::data
void * data
Definition: gc.c:512
onig_memsize
size_t onig_memsize(const regex_t *reg)
Definition: regcomp.c:5596
mark_m_tbl_wrapper
static void mark_m_tbl_wrapper(rb_objspace_t *objspace, struct method_table_wrapper *wrapper)
Definition: gc.c:3431
rb_io_t
Definition: io.h:61
rb_data_type_struct::flags
VALUE flags
Definition: ruby.h:978
gc_finalize_deferred
static void gc_finalize_deferred(void *dmy)
Definition: gc.c:2102
FL_TEST2
#define FL_TEST2(x, f)
Definition: gc.c:704
NODE_BLOCK
Definition: node.h:25
RFile::fptr
struct rb_io_t * fptr
Definition: ruby.h:936
objspace_live_slot
static size_t objspace_live_slot(rb_objspace_t *objspace)
Definition: gc.c:2686
probes.h
objspace_malloc_prepare
static size_t objspace_malloc_prepare(rb_objspace_t *objspace, size_t size)
Definition: gc.c:6055
rb_method_definition_struct::orig_me
struct rb_method_entry_struct * orig_me
Definition: method.h:92
ST_CONTINUE
Definition: st.h:100
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1041
eval_intern.h
node_type
node_type
Definition: node.h:22
NODE_FLIP3
Definition: node.h:203
check_gen_consistency
static VALUE check_gen_consistency(VALUE obj)
Definition: gc.c:717
rb_objspace::mark_func_data_struct::mark_func
void(* mark_func)(VALUE v, void *data)
Definition: gc.c:513
stack_check
static int stack_check(int water_mark)
Definition: gc.c:3260
RVALUE::flonum
struct RFloat flonum
Definition: gc.c:339
BITS_BITLENGTH
Definition: gc.c:373
ruby_xmalloc2
void * ruby_xmalloc2(size_t n, size_t size)
Definition: gc.c:6172
rb_define_private_method
void rb_define_private_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1500
timeval::tv_sec
long tv_sec
Definition: ossl_asn1.c:17
gc_info_decode
static VALUE gc_info_decode(int flags, VALUE hash_or_key)
Definition: gc.c:5241
ruby_mimfree
void ruby_mimfree(void *ptr)
Definition: gc.c:6267
NODE_DSTR
Definition: node.h:141
RVALUE::rstruct
struct RStruct rstruct
Definition: gc.c:346
rb_vm_struct::mark_object_ary
VALUE mark_object_ary
Definition: vm_core.h:366
dont_gc
#define dont_gc
Definition: gc.c:623
rb_gcdebug_print_obj_condition
void rb_gcdebug_print_obj_condition(VALUE obj)
VM_METHOD_TYPE_ISEQ
Definition: method.h:48
GC_ENABLE_LAZY_SWEEP
#define GC_ENABLE_LAZY_SWEEP
Definition: gc.c:244
wmap_keys_i
static int wmap_keys_i(st_data_t key, st_data_t val, st_data_t arg)
Definition: gc.c:6570
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:548
NODE_ZARRAY
Definition: node.h:105
rb_objspace::increase
size_t increase
Definition: gc.c:420
NODE_ARRAY
Definition: node.h:103
rb_objspace::deferred_final
RVALUE * deferred_final
Definition: gc.c:445
finalizer_table
#define finalizer_table
Definition: gc.c:626
T_RATIONAL
#define T_RATIONAL
Definition: ruby.h:495
rb_newobj
VALUE rb_newobj(void)
Definition: gc.c:1348
GPR_FLAG_MAJOR_BY_RESCAN
Definition: gc.c:266
ULONG2NUM
#define ULONG2NUM(x)
Definition: ruby.h:1319
NODE_ITER
Definition: node.h:39
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:896
SIZED_REALLOC_N
#define SIZED_REALLOC_N(var, type, n, old_n)
Definition: internal.h:471
gc_prof_mark_timer_start
static void gc_prof_mark_timer_start(rb_objspace_t *)
Definition: gc.c:6839
NODE_CDECL
Definition: node.h:77
verify_internal_consistency_struct::objspace
rb_objspace_t * objspace
Definition: gc.c:4169
st_free_table
void st_free_table(st_table *)
Definition: st.c:334
RGENGC_DEBUG
#define RGENGC_DEBUG
Definition: gc.c:185
SYM2ID
#define SYM2ID(x)
Definition: ruby.h:356
rb_objspace::oldmalloc_increase
size_t oldmalloc_increase
Definition: gc.c:534
constant.h
global_List
#define global_List
Definition: gc.c:627
NODE_CVAR
Definition: node.h:125
RGENGC_ESTIMATE_OLDMALLOC
#define RGENGC_ESTIMATE_OLDMALLOC
Definition: gc.c:224
ruby_xrealloc2
void * ruby_xrealloc2(void *ptr, size_t n, size_t size)
Definition: gc.c:6225
RGENGC_PROFILE
#define RGENGC_PROFILE
Definition: gc.c:205
heap_page_create
static struct heap_page * heap_page_create(rb_objspace_t *objspace)
Definition: gc.c:1116
count_objects
static VALUE count_objects(int argc, VALUE *argv, VALUE os)
Definition: gc.c:2588
OBJ_PROMOTED
#define OBJ_PROMOTED(x)
Definition: ruby.h:1189
RGENGC_CHECK_MODE
#define RGENGC_CHECK_MODE
Definition: gc.c:196
ruby_sized_xfree
void ruby_sized_xfree(void *x, size_t size)
Definition: gc.c:6234
rb_objspace_reachable_objects_from_root
void rb_objspace_reachable_objects_from_root(void(func)(const char *category, VALUE, void *), void *passing_data)
Definition: gc.c:5807
rb_objspace::next_index
size_t next_index
Definition: gc.c:460
gc_list::next
struct gc_list * next
Definition: gc.c:388
STACK_UPPER
#define STACK_UPPER(x, a, b)
Definition: gc.h:74
elapsed_time_from
static double elapsed_time_from(double time)
Definition: gc.c:6817
objspace_xmalloc
static void * objspace_xmalloc(rb_objspace_t *objspace, size_t size)
Definition: gc.c:6089
HEAP_BITMAP_SIZE
Definition: gc.c:559
rb_protect
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *state)
Definition: eval.c:807
gc_prof_sweep_timer_start
static void gc_prof_sweep_timer_start(rb_objspace_t *)
Definition: gc.c:6866
NODE_SCOPE
Definition: node.h:23
PRIxVALUE
#define PRIxVALUE
Definition: ruby.h:135
make_deferred
static void make_deferred(rb_objspace_t *objspace, RVALUE *p)
Definition: gc.c:1473
GC_MALLOC_LIMIT_MAX
#define GC_MALLOC_LIMIT_MAX
Definition: gc.c:119
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:676
Check_Type
#define Check_Type(v, t)
Definition: ruby.h:532
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
rb_io_fptr_finalize
int rb_io_fptr_finalize(rb_io_t *)
Definition: io.c:4257
ruby_memerror
static void ruby_memerror(void)
Definition: gc.c:5864
rmatch::regs
struct re_registers regs
Definition: re.h:37
rgengc_report_body
static void rgengc_report_body(int level, rb_objspace_t *objspace, const char *fmt,...)
Definition: gc.c:4549
gc.h
HEAP_OBJ_LIMIT
Definition: gc.c:557
ruby_get_stack_grow_direction
int ruby_get_stack_grow_direction(volatile VALUE *addr)
Definition: gc.c:3239
rb_sweep_method_entry
void rb_sweep_method_entry(void *vm)
Definition: vm_method.c:137
GC_PROFILE_DETAIL_MEMORY
#define GC_PROFILE_DETAIL_MEMORY
Definition: gc.c:241
C
#define C
Definition: util.c:195
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Definition: object.c:652
T_HASH
#define T_HASH
Definition: ruby.h:485
Init_heap
void Init_heap(void)
Definition: gc.c:1661
st_init_strtable
st_table * st_init_strtable(void)
Definition: st.c:284
NODE_DEFS
Definition: node.h:177
RCLASS_M_TBL_WRAPPER
#define RCLASS_M_TBL_WRAPPER(c)
Definition: internal.h:294
NODE_TRUE
Definition: node.h:209
HEAP_ALIGN_MASK
Definition: gc.c:554
wmap_memsize_map
static int wmap_memsize_map(st_data_t key, st_data_t val, st_data_t arg)
Definition: gc.c:6359
rb_const_entry_struct::value
const VALUE value
Definition: constant.h:21
rb_method_definition_struct::proc
const VALUE proc
Definition: method.h:85
wmap_values_i
static int wmap_values_i(st_data_t key, st_data_t val, st_data_t arg)
Definition: gc.c:6597
gc_heap_rest_sweep
static void gc_heap_rest_sweep(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:3038
gc_profile_total_time
static VALUE gc_profile_total_time(VALUE self)
Definition: gc.c:7245
rb_method_definition_struct::body
union rb_method_definition_struct::@126 body
heap_page_allocate
static struct heap_page * heap_page_allocate(rb_objspace_t *objspace)
Definition: gc.c:1026
NODE_CREF
Definition: node.h:195
ruby_gc_params_t::oldobject_limit_factor
double oldobject_limit_factor
Definition: gc.c:140
obj_free
static int obj_free(rb_objspace_t *objspace, VALUE obj)
Definition: gc.c:1490
mark_key
static int mark_key(st_data_t key, st_data_t value, st_data_t data)
Definition: gc.c:3340
heap_is_swept_object
static int heap_is_swept_object(rb_objspace_t *objspace, rb_heap_t *heap, VALUE ptr)
Definition: gc.c:2230
nd_set_type
#define nd_set_type(n, t)
Definition: node.h:283
DATA_PTR
#define DATA_PTR(dta)
Definition: ruby.h:992
GPR_FLAG_MAJOR_BY_NOFREE
Definition: gc.c:263
rb_objspace_each_objects
void rb_objspace_each_objects(each_obj_callback *callback, void *data)
Definition: gc.c:1761
HEAP_BITMAP_PLANES
Definition: gc.c:560
RSTRUCT_EMBED_LEN_MASK
#define RSTRUCT_EMBED_LEN_MASK
Definition: ruby.h:1056
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Definition: class.c:827
NODE_DREGX
Definition: node.h:149
GC_PROFILE_RECORD_DEFAULT_SIZE
#define GC_PROFILE_RECORD_DEFAULT_SIZE
Definition: gc.c:6703
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:3604
rb_gc_count
size_t rb_gc_count(void)
Definition: gc.c:5219
rgengc_remembersetbits_get
static int rgengc_remembersetbits_get(rb_objspace_t *objspace, VALUE obj)
Definition: gc.c:4577
rb_objspace_markable_object_p
int rb_objspace_markable_object_p(VALUE obj)
Definition: gc.c:2281
NODE_DEFN
Definition: node.h:175
T_ARRAY
#define T_ARRAY
Definition: ruby.h:484
GPR_FLAG_MAJOR_BY_OLDGEN
Definition: gc.c:264
st_index_t
st_data_t st_index_t
Definition: st.h:48
ATOMIC_PTR_EXCHANGE
#define ATOMIC_PTR_EXCHANGE(var, val)
Definition: ruby_atomic.h:161
heap_prepare_freepage
static struct heap_page * heap_prepare_freepage(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:1198
RUBY_INTERNAL_EVENT_GC_START
#define RUBY_INTERNAL_EVENT_GC_START
Definition: ruby.h:1734
BITMAP_BIT
#define BITMAP_BIT(p)
Definition: gc.c:591
TAG_RAISE
#define TAG_RAISE
Definition: eval_intern.h:193
rb_gc_register_address
void rb_gc_register_address(VALUE *addr)
Definition: gc.c:4927
heap_pages_himem
#define heap_pages_himem
Definition: gc.c:614
st_update
int st_update(st_table *table, st_data_t key, st_update_callback_func *func, st_data_t arg)
Definition: st.c:867
rb_io_write
VALUE rb_io_write(VALUE, VALUE)
Definition: io.c:1427
RBignum
Definition: ruby.h:1081
VALGRIND_MAKE_MEM_UNDEFINED
#define VALGRIND_MAKE_MEM_UNDEFINED(p, n)
Definition: zlib.c:25
RFILE
#define RFILE(obj)
Definition: ruby.h:1129
ROBJECT_NUMIV
#define ROBJECT_NUMIV(o)
Definition: ruby.h:774
rb_objspace::used
size_t used
Definition: gc.c:432
memop_type
memop_type
Definition: gc.c:5959
S
#define S(s)
method_table_wrapper::tbl
st_table * tbl
Definition: internal.h:283
rb_setjmp
#define rb_setjmp(env)
Definition: gc.c:88
gc_list
Definition: gc.c:386
NODE_OP_ASGN_OR
Definition: node.h:89
obj_type_name
static const char * obj_type_name(VALUE obj)
Definition: gc.c:7354
rb_gc_writebarrier_unprotect_promoted
void rb_gc_writebarrier_unprotect_promoted(VALUE obj)
Definition: gc.c:4749
callback
void callback(ffi_cif *cif, void *resp, void **args, void *ctx)
Definition: closure.c:59
rb_objspace::heap_used_at_gc_start
size_t heap_used_at_gc_start
Definition: gc.c:499
wmap_each_key
static VALUE wmap_each_key(VALUE self)
Definition: gc.c:6536
rmatch::char_offset_num_allocated
int char_offset_num_allocated
Definition: re.h:40
gc_event_hook
#define gc_event_hook(objspace, event, data)
Definition: gc.c:1278
FIXNUM_P
#define FIXNUM_P(f)
Definition: ruby.h:347
rb_thread_struct
Definition: vm_core.h:524
VM_METHOD_TYPE_BMETHOD
Definition: method.h:52
heap_pages_min_free_slots
#define heap_pages_min_free_slots
Definition: gc.c:617
T_UNDEF
#define T_UNDEF
Definition: ruby.h:497
nd_type
#define nd_type(n)
Definition: node.h:282
objspace_free_slot
static size_t objspace_free_slot(rb_objspace_t *objspace)
Definition: gc.c:2698
mark_stack::limit
size_t limit
Definition: gc.c:402
LIKELY
#define LIKELY(x)
Definition: vm_core.h:108
RDATA
#define RDATA(obj)
Definition: ruby.h:1125
rb_str_buf_append
VALUE rb_str_buf_append(VALUE, VALUE)
Definition: string.c:2282
mark_const_entry_i
static int mark_const_entry_i(ID key, const rb_const_entry_t *ce, st_data_t data)
Definition: gc.c:3447
heap_increment
static int heap_increment(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:1184
objspace_malloc_size
static size_t objspace_malloc_size(rb_objspace_t *objspace, void *ptr, size_t hint)
Definition: gc.c:5950
SET
#define SET(name, attr)
garbage_collect_body
static int garbage_collect_body(rb_objspace_t *, int full_mark, int immediate_sweep, int reason)
Definition: gc.c:4970
RComplex
Definition: ruby.h:948
RData
Definition: ruby.h:957
heap_page_body
Definition: gc.c:380
wmap_free_map
static int wmap_free_map(st_data_t key, st_data_t val, st_data_t arg)
Definition: gc.c:6342
ruby_stack_grow_direction
int ruby_stack_grow_direction
Definition: gc.c:3237
io.h
FL_SET2
#define FL_SET2(x, f)
Definition: gc.c:705
gc_stat_internal
static VALUE gc_stat_internal(VALUE hash_or_sym, size_t *out)
Definition: gc.c:5352
rb_thread_struct::machine
struct rb_thread_struct::@169 machine
ruby_stack_check
int ruby_stack_check(void)
Definition: gc.c:3279
os_each_struct
Definition: gc.c:1781
rb_mark_method_entry
void rb_mark_method_entry(const rb_method_entry_t *me)
Definition: gc.c:3417
heap_page_body::header
struct heap_page_header header
Definition: gc.c:381
VM_METHOD_TYPE_REFINED
Definition: method.h:58
wmap_size
static VALUE wmap_size(VALUE self)
Definition: gc.c:6685
RTypedData
Definition: ruby.h:985
rb_eRangeError
VALUE rb_eRangeError
Definition: error.c:552
rb_obj_classname
const char * rb_obj_classname(VALUE)
Definition: variable.c:406
MEMOP_TYPE_REALLOC
Definition: gc.c:5962
gc_profile_record::flags
int flags
Definition: gc.c:286
rb_objspace::mark_func_data
struct rb_objspace::mark_func_data_struct * mark_func_data
push_mark_stack
static void push_mark_stack(mark_stack_t *, VALUE)
Definition: gc.c:3178
rb_gc_force_recycle
void rb_gc_force_recycle(VALUE p)
Definition: gc.c:4897
MARK_CHECKPOINT
#define MARK_CHECKPOINT(category)
mark_stack::chunk
stack_chunk_t * chunk
Definition: gc.c:399
ruby_gc_stress
#define ruby_gc_stress
Definition: gc.c:628
obj_memsize_of
static size_t obj_memsize_of(VALUE obj, int use_tdata)
Definition: gc.c:2426
ATOMIC_SIZE_ADD
#define ATOMIC_SIZE_ADD(var, val)
Definition: ruby_atomic.h:134
ATOMIC_SIZE_CAS
#define ATOMIC_SIZE_CAS(var, oldval, val)
Definition: ruby_atomic.h:156
REQUIRED_SIZE_BY_MALLOC
Definition: gc.c:555
objspace_each_objects
static VALUE objspace_each_objects(VALUE arg)
Definition: gc.c:1695
NODE_RESCUE
Definition: node.h:53
NODE_CLASS
Definition: node.h:185
negative_size_allocation_error
static void negative_size_allocation_error(const char *)
Definition: gc.c:5840
rb_objspace::current_record
gc_profile_record * current_record
Definition: gc.c:459
NODE_IF
Definition: node.h:27
ruby_initial_gc_stress
#define ruby_initial_gc_stress
Definition: gc.c:600
rb_objspace::tomb_heap
rb_heap_t tomb_heap
Definition: gc.c:428
NODE_ENSURE
Definition: node.h:57
timespec::tv_sec
time_t tv_sec
Definition: missing.h:51
define_final
static VALUE define_final(int argc, VALUE *argv, VALUE os)
Definition: gc.c:1949
HEAP_SIZE
Definition: gc.c:556
RUBY_DTRACE_GC_SWEEP_END
#define RUBY_DTRACE_GC_SWEEP_END()
Definition: probes.h:77
st_data_t
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
Definition: st.h:20
force_chain_object
static int force_chain_object(st_data_t key, st_data_t val, st_data_t arg)
Definition: gc.c:2132
__sFILE
Definition: vsnprintf.c:175
heap_pages_deferred_final
#define heap_pages_deferred_final
Definition: gc.c:620
GET_HEAP_OLDGEN_BITS
#define GET_HEAP_OLDGEN_BITS(x)
Definition: gc.c:587
RVALUE_DEMOTE_FROM_OLD
static void RVALUE_DEMOTE_FROM_OLD(VALUE obj)
Definition: gc.c:854
RNode
Definition: node.h:239
MEMOP_TYPE_FREE
Definition: gc.c:5961
obj_id_to_ref
#define obj_id_to_ref(objid)
Definition: gc.c:635
rb_global_variable
void rb_global_variable(VALUE *var)
Definition: gc.c:4962
wmap_allocate
static VALUE wmap_allocate(VALUE klass)
Definition: gc.c:6390
mark_current_machine_context
static void mark_current_machine_context(rb_objspace_t *objspace, rb_thread_t *th)
Definition: gc.c:3475
RVALUE_OLD_BITMAP_P
static VALUE RVALUE_OLD_BITMAP_P(VALUE obj)
Definition: gc.c:763
GC_OLDMALLOC_LIMIT_GROWTH_FACTOR
#define GC_OLDMALLOC_LIMIT_GROWTH_FACTOR
Definition: gc.c:129
RVALUE::object
struct RObject object
Definition: gc.c:337
ruby_gc_params_t::malloc_limit_min
unsigned int malloc_limit_min
Definition: gc.c:141
rb_gc_unprotect_logging
void rb_gc_unprotect_logging(void *objptr, const char *filename, int line)
Definition: gc.c:4804
mark_method_entry_i
static int mark_method_entry_i(ID key, const rb_method_entry_t *me, st_data_t data)
Definition: gc.c:3423
stack_chunk::data
VALUE data[STACK_CHUNK_SIZE]
Definition: gc.c:394
rb_objspace::during_gc
int during_gc
Definition: gc.c:451
rb_exc_raise
void rb_exc_raise(VALUE mesg)
Definition: eval.c:567
rb_objspace_set_event_hook
void rb_objspace_set_event_hook(const rb_event_flag_t event)
Definition: gc.c:1265
finalize_list
static void finalize_list(rb_objspace_t *objspace, RVALUE *p)
Definition: gc.c:2074
heap_page::heap
rb_heap_t * heap
Definition: gc.c:572
rb_objspace::limit
size_t limit
Definition: gc.c:419
malloc_increase
#define malloc_increase
Definition: gc.c:608
rb_free_m_tbl_wrapper
void rb_free_m_tbl_wrapper(struct method_table_wrapper *wrapper)
Definition: gc.c:1450
FL_SINGLETON
#define FL_SINGLETON
Definition: ruby.h:1133
rb_objspace::dont_lazy_sweep
int dont_lazy_sweep
Definition: gc.c:450
RVALUE
struct RVALUE RVALUE
rb_define_finalizer
VALUE rb_define_finalizer(VALUE obj, VALUE block)
Definition: gc.c:1990
NODE_NTH_REF
Definition: node.h:127
strtod
#define strtod(s, e)
Definition: util.h:74
gc_marks_body
static void gc_marks_body(rb_objspace_t *objspace, int full_mark)
Definition: gc.c:4143
RBASIC_SET_CLASS_RAW
#define RBASIC_SET_CLASS_RAW(obj, cls)
Definition: internal.h:608
xmalloc2_size
static size_t xmalloc2_size(size_t n, size_t size)
Definition: gc.c:6162
rb_obj_memsize_of
size_t rb_obj_memsize_of(VALUE obj)
Definition: gc.c:2548
RB_TYPE_P
#define RB_TYPE_P(obj, type)
Definition: ruby.h:1664
ruby_xcalloc
void * ruby_xcalloc(size_t n, size_t size)
Definition: gc.c:6191
RHASH
#define RHASH(obj)
Definition: ruby.h:1124
GET_STACK_BOUNDS
#define GET_STACK_BOUNDS(start, end, appendix)
Definition: gc.c:3469
GPR_FLAG_CAPI
Definition: gc.c:277
rb_args_info
Definition: node.h:510
weakmap
Definition: gc.c:6312
heap_page::next
struct heap_page * next
Definition: gc.c:569
gc_prof_timer_start
static void gc_prof_timer_start(rb_objspace_t *)
Definition: gc.c:6804
rb_control_frame_struct::self
VALUE self
Definition: vm_core.h:450
ATOMIC_SET
#define ATOMIC_SET(var, val)
Definition: ruby_atomic.h:127
Init_GC
void Init_GC(void)
Definition: gc.c:7472
st_lookup
int st_lookup(st_table *, st_data_t, st_data_t *)
MEMZERO
#define MEMZERO(p, type, n)
Definition: ruby.h:1351
rb_obj_method
VALUE rb_obj_method(VALUE, VALUE)
Definition: proc.c:1439
RString
Definition: ruby.h:820
rb_objspace::malloc_params
struct rb_objspace::@102 malloc_params
rb_objspace::oldmalloc_increase_limit
size_t oldmalloc_increase_limit
Definition: gc.c:535
heap_pages_max_free_slots
#define heap_pages_max_free_slots
Definition: gc.c:618
rb_free_generic_ivar
void rb_free_generic_ivar(VALUE)
Definition: variable.c:1030
during_gc
#define during_gc
Definition: gc.c:624
FL_TEST
#define FL_TEST(x, f)
Definition: ruby.h:1169
type_name
static const char * type_name(int type, VALUE obj)
Definition: gc.c:7315
rb_postponed_job_register_one
int rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data)
Definition: vm_trace.c:1487
rb_objspace::latest_gc_info
int latest_gc_info
Definition: gc.c:505
wmap_has_key
static VALUE wmap_has_key(VALUE self, VALUE key)
Definition: gc.c:6679
aligned_malloc
static void * aligned_malloc(size_t, size_t)
Definition: gc.c:5900
ruby_disable_gc_stress
int ruby_disable_gc_stress
Definition: gc.c:650
NODE_COLON2
Definition: node.h:191
rb_ary_free
void rb_ary_free(VALUE ary)
Definition: array.c:540
thread.h
rb_mark_end_proc
void rb_mark_end_proc(void)
Definition: eval_jump.c:80
gc_mark
static void gc_mark(rb_objspace_t *objspace, VALUE ptr)
Definition: gc.c:3589
STACK_CHUNK_SIZE
#define STACK_CHUNK_SIZE
Definition: gc.c:391
ROBJECT_IVPTR
#define ROBJECT_IVPTR(o)
Definition: ruby.h:778
GC_HEAP_GROWTH_MAX_SLOTS
#define GC_HEAP_GROWTH_MAX_SLOTS
Definition: gc.c:109
rb_class_name
VALUE rb_class_name(VALUE)
Definition: variable.c:391
rb_undefine_finalizer
VALUE rb_undefine_finalizer(VALUE obj)
Definition: gc.c:1911
rb_objspace::total_allocated_object_num
size_t total_allocated_object_num
Definition: gc.c:503
ALLOC_N
#define ALLOC_N(type, n)
Definition: ruby.h:1333
rb_vm_mark
void rb_vm_mark(void *ptr)
Definition: vm.c:1762
rb_hash_aset
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:1393
gc_profile_record::gc_invoke_time
double gc_invoke_time
Definition: gc.c:289
ruby_atomic.h
garbage_collect
static int garbage_collect(rb_objspace_t *, int full_mark, int immediate_sweep, int reason)
Definition: gc.c:5053
gc_with_gvl
static void * gc_with_gvl(void *ptr)
Definition: gc.c:5085
rb_gc_copy_finalizer
void rb_gc_copy_finalizer(VALUE dest, VALUE obj)
Definition: gc.c:1998
rb_mark_generic_ivar_tbl
void rb_mark_generic_ivar_tbl(void)
Definition: variable.c:1022
NODE_GVAR
Definition: node.h:119
nomem_error
#define nomem_error
Definition: gc.c:646
weakmap::final
VALUE final
Definition: gc.c:6315
level
#define level
timeval::tv_usec
long tv_usec
Definition: ossl_asn1.c:18
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1553
finalize_deferred
static void finalize_deferred(rb_objspace_t *objspace)
Definition: gc.c:2092
define_final0
static VALUE define_final0(VALUE obj, VALUE block)
Definition: gc.c:1966
DWORD
IUnknown DWORD
Definition: win32ole.c:149
negative_size_allocation_error_with_gvl
static void * negative_size_allocation_error_with_gvl(void *ptr)
Definition: gc.c:5833
rb_gc_unregister_address
void rb_gc_unregister_address(VALUE *addr)
Definition: gc.c:4939
gc_page_sweep
static void gc_page_sweep(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *sweep_page)
Definition: gc.c:2716
NODE_FLIP2
Definition: node.h:201
pop_mark_stack
static int pop_mark_stack(mark_stack_t *, VALUE *)
Definition: gc.c:3187
gc_stress_get
static VALUE gc_stress_get(VALUE self)
Definition: gc.c:5575
VALGRIND_MAKE_MEM_DEFINED
#define VALGRIND_MAKE_MEM_DEFINED(p, n)
Definition: zlib.c:24
rb_str_free
void rb_str_free(VALUE)
Definition: string.c:941
NODE_RESBODY
Definition: node.h:55
I
#define I(s)
T_NIL
#define T_NIL
Definition: ruby.h:476
NODE_POSTEXE
Definition: node.h:217
gc_list::varptr
VALUE * varptr
Definition: gc.c:387
gc_after_sweep
static void gc_after_sweep(rb_objspace_t *objspace)
Definition: gc.c:2952
NODE_ARGS
Definition: node.h:153
NUM2PTR
#define NUM2PTR(x)
NODE_RETURN
Definition: node.h:111
rb_objspace::finalizing
rb_atomic_t finalizing
Definition: gc.c:452
rb_str_cat2
VALUE rb_str_cat2(VALUE, const char *)
Definition: string.c:2159
RVALUE_INFANT_P
static VALUE RVALUE_INFANT_P(VALUE obj)
Definition: gc.c:756
rb_cBasicObject
RUBY_EXTERN VALUE rb_cBasicObject
Definition: ruby.h:1552
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:495
force_finalize_list::table
VALUE table
Definition: gc.c:2127
gc_marked
static int gc_marked(rb_objspace_t *objspace, VALUE ptr)
Definition: gc.c:3543
T_TRUE
#define T_TRUE
Definition: ruby.h:490
gc_profile_record
struct gc_profile_record gc_profile_record
NODE_OP_ASGN_AND
Definition: node.h:87
UINT2NUM
#define UINT2NUM(x)
Definition: ruby.h:1298
gc_mark_maybe
static void gc_mark_maybe(rb_objspace_t *objspace, VALUE ptr)
Definition: gc.c:3525
rb_objspace::mark_stack
mark_stack_t mark_stack
Definition: gc.c:455
rb_free_method_entry
void rb_free_method_entry(rb_method_entry_t *me)
Definition: vm_method.c:178
RBasic
Definition: ruby.h:747
rb_mKernel
RUBY_EXTERN VALUE rb_mKernel
Definition: ruby.h:1541
RSTRUCT_LEN
#define RSTRUCT_LEN(st)
Definition: ruby.h:1058
RUBY_DTRACE_GC_SWEEP_BEGIN_ENABLED
#define RUBY_DTRACE_GC_SWEEP_BEGIN_ENABLED()
Definition: probes.h:73
snprintf
#define snprintf
Definition: subst.h:6
heap_get_freeobj
static VALUE heap_get_freeobj(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:1249
RArray
Definition: ruby.h:860
JUMP_TAG
#define JUMP_TAG(st)
Definition: eval_intern.h:173
RVALUE
Definition: gc.c:330
push_mark_stack_chunk
static void push_mark_stack_chunk(mark_stack_t *stack)
Definition: gc.c:3130
nonspecial_obj_id
#define nonspecial_obj_id(obj)
Definition: gc.c:634
NIL_P
#define NIL_P(v)
Definition: ruby.h:438
weakmap::obj2wmap
st_table * obj2wmap
Definition: gc.c:6313
timespec::tv_nsec
long tv_nsec
Definition: missing.h:52
RUBY_DTRACE_GC_MARK_END_ENABLED
#define RUBY_DTRACE_GC_MARK_END_ENABLED()
Definition: probes.h:70
st_add_direct
void st_add_direct(st_table *, st_data_t, st_data_t)
Definition: st.c:629
heap_page_resurrect
static struct heap_page * heap_page_resurrect(rb_objspace_t *objspace)
Definition: gc.c:1104
rb_gc_latest_gc_info
VALUE rb_gc_latest_gc_info(VALUE key)
Definition: gc.c:5318
NODE_EVSTR
Definition: node.h:147
os_obj_of
static VALUE os_obj_of(VALUE of)
Definition: gc.c:1835
UNLIKELY
#define UNLIKELY(x)
Definition: vm_core.h:109
add
#define add(x, y)
Definition: date_strftime.c:23
CEILDIV
#define CEILDIV(i, mod)
Definition: gc.c:551
msg
static char msg[50]
Definition: strerror.c:8
calloc
#define calloc
Definition: ripper.c:98
wmap_memsize
static size_t wmap_memsize(const void *ptr)
Definition: gc.c:6367
NODE_ALIAS
Definition: node.h:179
gc_heap_lazy_sweep
static int gc_heap_lazy_sweep(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:3004
st_delete
int st_delete(st_table *, st_data_t *, st_data_t *)
gc_profile_record::gc_time
double gc_time
Definition: gc.c:288
RCLASS_IV_TBL
#define RCLASS_IV_TBL(c)
Definition: internal.h:292
rb_define_const
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2225
rb_heap_struct::page_length
size_t page_length
Definition: gc.c:413
GPR_FLAG_NEWOBJ
Definition: gc.c:274
rb_obj_is_mutex
VALUE rb_obj_is_mutex(VALUE obj)
Definition: thread.c:4216
MALLOC_ALLOCATED_SIZE
#define MALLOC_ALLOCATED_SIZE
Definition: gc.c:254
rb_eNoMemError
VALUE rb_eNoMemError
Definition: error.c:559
heap_add_freepage
static void heap_add_freepage(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
Definition: gc.c:967
cnt
rb_atomic_t cnt[RUBY_NSIG]
Definition: signal.c:496
ruby_gc_params_t::oldmalloc_limit_max
unsigned int oldmalloc_limit_max
Definition: gc.c:145
NODE_SELF
Definition: node.h:205
onig_region_free
void onig_region_free(OnigRegion *r, int free_self)
Definition: regexec.c:315
heap_page::mark_bits
bits_t mark_bits[HEAP_BITMAP_LIMIT]
Definition: gc.c:575
FLONUM_P
#define FLONUM_P(x)
Definition: ruby.h:367
T_FLOAT
#define T_FLOAT
Definition: ruby.h:481
rb_mGC
VALUE rb_mGC
Definition: gc.c:649
NODE_BLOCK_PASS
Definition: node.h:173
TYPE
#define TYPE(x)
Definition: ruby.h:505
argc
int argc
Definition: ruby.c:131
NODE_AND
Definition: node.h:59
heap_pages_increment
#define heap_pages_increment
Definition: gc.c:616
RBIGNUM_LEN
#define RBIGNUM_LEN(b)
Definition: ruby.h:1103
rb_heap_struct::pages
struct heap_page * pages
Definition: gc.c:408
Qfalse
#define Qfalse
Definition: ruby.h:425
M
#define M
Definition: random.c:94
rb_sourcefile
#define rb_sourcefile()
Definition: tcltklib.c:98
realloc
#define realloc
Definition: ripper.c:97
onig_region_memsize
size_t onig_region_memsize(const OnigRegion *regs)
Definition: regcomp.c:5611
rb_method_entry_struct
Definition: method.h:97
force_finalize_list::next
struct force_finalize_list * next
Definition: gc.c:2128
free_const_entry_i
static int free_const_entry_i(ID key, rb_const_entry_t *ce, st_data_t data)
Definition: gc.c:1459
RRational
Definition: ruby.h:939
T_BIGNUM
#define T_BIGNUM
Definition: ruby.h:487
heap_eden
#define heap_eden
Definition: gc.c:621
rb_gc_register_mark_object
void rb_gc_register_mark_object(VALUE obj)
Definition: gc.c:4920
if
if((ID)(DISPID) nameid!=nameid)
Definition: win32ole.c:770
rb_objspace
Definition: gc.c:417
ATOMIC_SIZE_EXCHANGE
#define ATOMIC_SIZE_EXCHANGE(var, val)
Definition: ruby_atomic.h:136
T_NODE
#define T_NODE
Definition: ruby.h:498
GC_MALLOC_LIMIT_GROWTH_FACTOR
#define GC_MALLOC_LIMIT_GROWTH_FACTOR
Definition: gc.c:122
FL_ANY
#define FL_ANY(x, f)
Definition: ruby.h:1170
NODE_OPT_ARG
Definition: node.h:157
NODE_IVAR
Definition: node.h:121
rb_str_new2
#define rb_str_new2
Definition: intern.h:840
mark_stack::index
size_t index
Definition: gc.c:401
RNODE
#define RNODE(obj)
Definition: node.h:266
err
int err
Definition: win32.c:114
GC_NOTIFY
#define GC_NOTIFY
Definition: gc.c:4967
gc_before_sweep
static void gc_before_sweep(rb_objspace_t *objspace)
Definition: gc.c:2850
STACK_END
#define STACK_END
Definition: gc.c:3225
OBJ_FREEZE
#define OBJ_FREEZE(x)
Definition: ruby.h:1186
EXIT_FAILURE
#define EXIT_FAILURE
Definition: eval_intern.h:24
is_lazy_sweeping
#define is_lazy_sweeping(heap)
Definition: gc.c:632
RUBY_DTRACE_GC_MARK_END
#define RUBY_DTRACE_GC_MARK_END()
Definition: probes.h:71
T_COMPLEX
#define T_COMPLEX
Definition: ruby.h:496
RSTRUCT_CONST_PTR
#define RSTRUCT_CONST_PTR(st)
Definition: ruby.h:1064
rgengc_rememberset_mark
static void rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:4651
heap_get_freeobj_from_next_freepage
static RVALUE * heap_get_freeobj_from_next_freepage(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:1230
rb_objspace_data_type_memsize
size_t rb_objspace_data_type_memsize(VALUE obj)
Definition: gc.c:1383
RBIGNUM_DIGITS
#define RBIGNUM_DIGITS(b)
Definition: ruby.h:1109
rb_method_entry_struct::klass
VALUE klass
Definition: method.h:102
rb_node_newnode
NODE * rb_node_newnode(enum node_type type, VALUE a0, VALUE a1, VALUE a2)
Definition: gc.c:1360
GPR_FLAG_NONE
Definition: gc.c:261
rb_objspace::profile
struct rb_objspace::@105 profile
numberof
#define numberof(array)
Definition: etc.c:595
RGENGC_WB_PROTECTED_NODE_CREF
#define RGENGC_WB_PROTECTED_NODE_CREF
Definition: ruby.h:744
rb_gc_mark_machine_stack
void rb_gc_mark_machine_stack(rb_thread_t *th)
Definition: gc.c:3506
RVALUE::as
union RVALUE::@99 as
rb_gc_guarded_ptr
volatile VALUE * rb_gc_guarded_ptr(volatile VALUE *ptr)
Definition: gc.c:93
ALLOC
#define ALLOC(type)
Definition: ruby.h:1334
wmap_values
static VALUE wmap_values(VALUE self)
Definition: gc.c:6611
run_finalizer
static void run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table)
Definition: gc.c:2021
ruby_mimmalloc
void * ruby_mimmalloc(size_t size)
Definition: gc.c:6251
PRIuVALUE
#define PRIuVALUE
Definition: ruby.h:134
gc_profile_record::heap_total_size
size_t heap_total_size
Definition: gc.c:293
rb_objspace::finalizer_table
st_table * finalizer_table
Definition: gc.c:454
rb_thread_raised_clear
#define rb_thread_raised_clear(th)
Definition: eval_intern.h:226
RUBY_INTERNAL_EVENT_GC_END_MARK
#define RUBY_INTERNAL_EVENT_GC_END_MARK
Definition: ruby.h:1735
gc_mark_locations
static void gc_mark_locations(rb_objspace_t *objspace, VALUE *start, VALUE *end)
Definition: gc.c:3301
internal_object_p
static int internal_object_p(VALUE obj)
Definition: gc.c:1787
sub
#define sub(x, y)
Definition: date_strftime.c:24
VM_METHOD_TYPE_ATTRSET
Definition: method.h:50
FL_FINALIZE
#define FL_FINALIZE
Definition: ruby.h:1136
RGENGC_THREEGEN
#define RGENGC_THREEGEN
Definition: gc.c:214
FL_ABLE
#define FL_ABLE(x)
Definition: ruby.h:1167
COUNT_TYPE
#define COUNT_TYPE(t)
OBJ_WB_PROTECTED
#define OBJ_WB_PROTECTED(x)
Definition: ruby.h:1190
gc_prof_set_heap_info
static void gc_prof_set_heap_info(rb_objspace_t *)
Definition: gc.c:6921
rb_heap_struct::total_slots
size_t total_slots
Definition: gc.c:414
is_dead_object
static int is_dead_object(rb_objspace_t *objspace, VALUE ptr)
Definition: gc.c:2248
resource.h
rb_define_module_function
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1670
rb_objspace::total_freed_object_num
size_t total_freed_object_num
Definition: gc.c:504
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:942
gc_profile_dump_on
static void gc_profile_dump_on(VALUE out, VALUE(*append)(VALUE, VALUE))
Definition: gc.c:7099
RCLASS_M_TBL
#define RCLASS_M_TBL(c)
Definition: internal.h:295
heap_tomb
#define heap_tomb
Definition: gc.c:622
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR(a)
Definition: ruby.h:886
RVALUE::rational
struct RRational rational
Definition: gc.c:351
rb_during_gc
int rb_during_gc(void)
Definition: gc.c:5198
rb_method_definition_struct::iseq
rb_iseq_t *const iseq
Definition: method.h:82
timeval
Definition: ossl_asn1.c:16
func
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:113
rgengc_unprotect_logging_exit_func
static void rgengc_unprotect_logging_exit_func(void)
Definition: gc.c:4798
lo
#define lo
Definition: siphash.c:21
NODE_ERRINFO
Definition: node.h:213
util.h
getrusage_time
static double getrusage_time(void)
Definition: gc.c:6706
TRUE
#define TRUE
Definition: nkf.h:175
gc_profile_report
static VALUE gc_profile_report(int argc, VALUE *argv, VALUE self)
Definition: gc.c:7222
ruby_initial_gc_stress_ptr
VALUE * ruby_initial_gc_stress_ptr
Definition: gc.c:601
T_DATA
#define T_DATA
Definition: ruby.h:492
root_objects_data
Definition: gc.c:5793
ruby_gc_params_t::malloc_limit_growth_factor
double malloc_limit_growth_factor
Definition: gc.c:143
GPR_FLAG_IMMEDIATE_SWEEP
Definition: gc.c:281
gc_set_initial_pages
static void gc_set_initial_pages(void)
Definition: gc.c:5690
mark_stack::cache_size
size_t cache_size
Definition: gc.c:403
gc_prof_sweep_timer_stop
static void gc_prof_sweep_timer_stop(rb_objspace_t *)
Definition: gc.c:6881
rb_mEnumerable
VALUE rb_mEnumerable
Definition: enum.c:20
rb_sprintf
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1250
rb_objspace_internal_object_p
int rb_objspace_internal_object_p(VALUE obj)
Definition: gc.c:1810
heap_page::body
struct heap_page_body * body
Definition: gc.c:564
GET_HEAP_MARK_BITS
#define GET_HEAP_MARK_BITS(x)
Definition: gc.c:585
STACKFRAME_FOR_CALL_CFUNC
#define STACKFRAME_FOR_CALL_CFUNC
Definition: gc.c:3276
ruby_gc_params_t::oldmalloc_limit_min
unsigned int oldmalloc_limit_min
Definition: gc.c:144
rb_obj_respond_to
int rb_obj_respond_to(VALUE, ID, int)
Definition: vm_method.c:1600
GC_DEBUG
#define GC_DEBUG
Definition: gc.c:173
gc_prof_mark_timer_stop
static void gc_prof_mark_timer_stop(rb_objspace_t *)
Definition: gc.c:6852
aligned_free
static void aligned_free(void *)
Definition: gc.c:5936
RBasic::klass
const VALUE klass
Definition: ruby.h:749
rb_obj_gc_flags
size_t rb_obj_gc_flags(VALUE obj, ID *flags, size_t max)
Definition: gc.c:4848
add_stack_chunk_cache
static void add_stack_chunk_cache(mark_stack_t *stack, stack_chunk_t *chunk)
Definition: gc.c:3108
MARKED_IN_BITMAP
#define MARKED_IN_BITMAP(bits, p)
Definition: gc.c:593
NODE_SPLAT
Definition: node.h:167
MEMMOVE
#define MEMMOVE(p1, p2, type, n)
Definition: ruby.h:1353
malloc
#define malloc
Definition: ripper.c:96
gc_profile_record
Definition: gc.c:285
RVALUE::hash
struct RHash hash
Definition: gc.c:343
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:298
run_final
static void run_final(rb_objspace_t *objspace, VALUE obj)
Definition: gc.c:2048
ruby_xfree
void ruby_xfree(void *x)
Definition: gc.c:6242
RStruct
Definition: ruby.h:1046
STACK_LENGTH
#define STACK_LENGTH
Definition: gc.c:3233
rb_objspace::old_object_count
size_t old_object_count
Definition: gc.c:527
wmap_aset
static VALUE wmap_aset(VALUE self, VALUE wmap, VALUE orig)
Definition: gc.c:6646
RVALUE_OLDGEN_BITMAP
#define RVALUE_OLDGEN_BITMAP(obj)
Definition: gc.c:711
os_obj_of_i
static int os_obj_of_i(void *vstart, void *vend, size_t stride, void *data)
Definition: gc.c:1816
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1728
rb_heap_struct::freelist
RVALUE * freelist
Definition: gc.c:412
root_objects_data::category
const char * category
Definition: gc.c:5794
rgengc_remember
static int rgengc_remember(rb_objspace_t *objspace, VALUE obj)
Definition: gc.c:4600
rb_thread_raised_set
#define rb_thread_raised_set(th, f)
Definition: eval_intern.h:223
RFile
Definition: ruby.h:934
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
NODE_UNDEF
Definition: node.h:183
wmap_final_func
static int wmap_final_func(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
Definition: gc.c:6401
GPR_FLAG_MAJOR_BY_SHADY
Definition: gc.c:265
PRIsVALUE
#define PRIsVALUE
Definition: ruby.h:137
internal.h
mark_const_tbl
static void mark_const_tbl(rb_objspace_t *objspace, st_table *tbl)
Definition: gc.c:3456
mark_tbl
static void mark_tbl(rb_objspace_t *objspace, st_table *tbl)
Definition: gc.c:3331
Init_stack
void Init_stack(volatile VALUE *addr)
Definition: gc.c:5124
rgengc_unprotect_logging_table
static st_table * rgengc_unprotect_logging_table
Definition: gc.c:4788
ID
unsigned long ID
Definition: ruby.h:89
objspace_total_slot
static size_t objspace_total_slot(rb_objspace_t *objspace)
Definition: gc.c:2692
rb_objspace::final_slots
size_t final_slots
Definition: gc.c:444
gc_params
static ruby_gc_params_t gc_params
Definition: gc.c:152
RVALUE::v2
VALUE v2
Definition: gc.c:356
RVALUE::free
struct RVALUE::@99::@100 free
lazy_sweep_enable
static VALUE lazy_sweep_enable(void)
Definition: gc.c:2677
ATOMIC_SIZE_INC
#define ATOMIC_SIZE_INC(var)
Definition: ruby_atomic.h:147
verify_internal_consistency_reachable_i
static void verify_internal_consistency_reachable_i(VALUE child, void *ptr)
Definition: gc.c:4176
MALLOC_ALLOCATED_SIZE_CHECK
#define MALLOC_ALLOCATED_SIZE_CHECK
Definition: gc.c:257
atomic_sub_nounderflow
static void atomic_sub_nounderflow(size_t *var, size_t sub)
Definition: gc.c:5966
rb_gc_mark_symbols
void rb_gc_mark_symbols(int full_mark)
Definition: ripper.c:16779
newobj_of
static VALUE newobj_of(VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3)
Definition: gc.c:1285
Qnil
#define Qnil
Definition: ruby.h:427
T_STRUCT
#define T_STRUCT
Definition: ruby.h:486
uintptr_t
unsigned int uintptr_t
Definition: win32.h:103
heap_pages_free_unused_pages
static void heap_pages_free_unused_pages(rb_objspace_t *objspace)
Definition: gc.c:997
is_id_value
static int is_id_value(rb_objspace_t *objspace, VALUE ptr)
Definition: gc.c:2221
rb_objspace::major_gc_count
size_t major_gc_count
Definition: gc.c:470
type
int type
Definition: tcltklib.c:112
rgengc_mark_and_rememberset_clear
static void rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:4717
heap_add_pages
static void heap_add_pages(rb_objspace_t *objspace, rb_heap_t *heap, size_t add)
Definition: gc.c:1149
BITMAP_INDEX
#define BITMAP_INDEX(p)
Definition: gc.c:589
vm_core.h
NODE_SUPER
Definition: node.h:99
rb_obj_rgengc_writebarrier_protected_p
VALUE rb_obj_rgengc_writebarrier_protected_p(VALUE obj)
Definition: gc.c:4836
BUILTIN_TYPE
#define BUILTIN_TYPE(x)
Definition: ruby.h:502
rb_objspace::dont_gc
int dont_gc
Definition: gc.c:449
OBJ_TAINT
#define OBJ_TAINT(x)
Definition: ruby.h:1177
VALUE
unsigned long VALUE
Definition: ruby.h:88
NUM_IN_PAGE
#define NUM_IN_PAGE(p)
Definition: gc.c:588
NODE_VCALL
Definition: node.h:97
rb_objspace::gc_stress
VALUE gc_stress
Definition: gc.c:509
gc_profile_enable_get
static VALUE gc_profile_enable_get(VALUE self)
Definition: gc.c:7269
rgengc_check_relation
static void rgengc_check_relation(rb_objspace_t *objspace, VALUE obj)
Definition: gc.c:3560
result
static VALUE result
Definition: nkf.c:40
gc_start_internal
static VALUE gc_start_internal(int argc, VALUE *argv, VALUE self)
Definition: gc.c:5151
mark_entry
static int mark_entry(st_data_t key, st_data_t value, st_data_t data)
Definition: gc.c:3323
gc_prof_record
#define gc_prof_record(objspace)
Definition: gc.c:690
RBASIC
#define RBASIC(obj)
Definition: ruby.h:1116
rb_objspace_data_type_name
const char * rb_objspace_data_type_name(VALUE obj)
Definition: gc.c:1394
rb_free_const_table
void rb_free_const_table(st_table *tbl)
Definition: gc.c:1466
is_markable_object
static int is_markable_object(rb_objspace_t *objspace, VALUE obj)
Definition: gc.c:2267
USE_RGENGC
#define USE_RGENGC
Definition: ruby.h:707
ruby_gc_params_t::malloc_limit_max
unsigned int malloc_limit_max
Definition: gc.c:142
FIX2INT
#define FIX2INT(x)
Definition: ruby.h:632
rb_heap_struct
Definition: gc.c:407
RVALUE_OLD_P
static VALUE RVALUE_OLD_P(VALUE obj)
Definition: gc.c:770
ruby_memerror_body
static void * ruby_memerror_body(void *dummy)
Definition: gc.c:5857
rb_mark_tbl
void rb_mark_tbl(st_table *tbl)
Definition: gc.c:3519
rgengc_report
#define rgengc_report
Definition: gc.c:693
NODE_MATCH2
Definition: node.h:133
heap_page
Definition: gc.c:563
gc_profile_record::heap_use_size
size_t heap_use_size
Definition: gc.c:292
heap_pages_swept_slots
#define heap_pages_swept_slots
Definition: gc.c:615
heap_pages_lomem
#define heap_pages_lomem
Definition: gc.c:613
rb_ary_new3
#define rb_ary_new3
Definition: intern.h:91
method_table_wrapper::serial
size_t serial
Definition: internal.h:284
rb_gc_disable
VALUE rb_gc_disable(void)
Definition: gc.c:5638
OPT
#define OPT(o)
clock_gettime
int clock_gettime(clockid_t, struct timespec *)
Definition: win32.c:4319
SET_MACHINE_STACK_END
#define SET_MACHINE_STACK_END(p)
Definition: gc.h:11
ruby_init_stack
void ruby_init_stack(volatile VALUE *)
get_envparam_double
static int get_envparam_double(const char *name, double *default_value, double lower_bound)
Definition: gc.c:5670
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:839
RBasic::flags
VALUE flags
Definition: ruby.h:748
rb_str_new_cstr
VALUE rb_str_new_cstr(const char *)
Definition: string.c:560
force_finalize_list::obj
VALUE obj
Definition: gc.c:2126
heap_page::free_next
struct heap_page * free_next
Definition: gc.c:571
rb_sigaltstack_size
int rb_sigaltstack_size(void)
ruby_xrealloc
void * ruby_xrealloc(void *ptr, size_t new_size)
Definition: gc.c:6206
heap_page_header::page
struct heap_page * page
Definition: gc.c:377
re.h
RVALUE_WB_PROTECTED
#define RVALUE_WB_PROTECTED(obj)
Definition: gc.c:709
st_init_numtable
st_table * st_init_numtable(void)
Definition: st.c:272
gc_stress_set
static VALUE gc_stress_set(VALUE self, VALUE flag)
Definition: gc.c:5594
ruby_gc_params_t::heap_free_slots
unsigned int heap_free_slots
Definition: gc.c:137
ruby_gc_set_params
void ruby_gc_set_params(int safe_level)
Definition: gc.c:5733
NODE_YIELD
Definition: node.h:113
rb_class_detach_module_subclasses
void rb_class_detach_module_subclasses(VALUE klass)
Definition: class.c:137
wmap_free
static void wmap_free(void *ptr)
Definition: gc.c:6350
is_mark_stack_empty
static int is_mark_stack_empty(mark_stack_t *stack)
Definition: gc.c:3102
rb_garbage_collect
int rb_garbage_collect(void)
Definition: gc.c:5116
root_objects_data::data
void * data
Definition: gc.c:5796
RVALUE::values
struct RVALUE::@99::@101 values
gc_latest_gc_info
static VALUE gc_latest_gc_info(int argc, VALUE *argv, VALUE self)
Definition: gc.c:5334
CHAR_BIT
#define CHAR_BIT
Definition: ruby.h:198
rmatch
Definition: re.h:36
NODE_ALLOCA
Definition: node.h:219
verify_internal_consistency_struct::err_count
int err_count
Definition: gc.c:4170
RANY
#define RANY(o)
Definition: gc.c:644
NODE_DASGN_CURR
Definition: node.h:69
FL_UNSET
#define FL_UNSET(x, f)
Definition: ruby.h:1173
rb_ary_memsize
size_t rb_ary_memsize(VALUE)
Definition: array.c:548
RTYPEDDATA_P
#define RTYPEDDATA_P(v)
Definition: ruby.h:994
objspace_and_reason::objspace
rb_objspace_t * objspace
Definition: gc.c:5078
ROBJECT
#define ROBJECT(obj)
Definition: ruby.h:1117
LONG2NUM
#define LONG2NUM(x)
Definition: ruby.h:1309
ruby_gc_params_t::growth_max_slots
unsigned int growth_max_slots
Definition: gc.c:139
weakmap_type
static const rb_data_type_t weakmap_type
Definition: gc.c:6379
NODE_DOT3
Definition: node.h:199
rb_memerror
void rb_memerror(void)
Definition: gc.c:5882
rb_define_module_under
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:766
rb_gc_set_params
void rb_gc_set_params(void)
Definition: gc.c:5773
heap_assign_page
static void heap_assign_page(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:1141
heap_unlink_page
static void heap_unlink_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
Definition: gc.c:976
getenv
#define getenv(name)
Definition: win32.c:66
rb_free_m_tbl
void rb_free_m_tbl(st_table *tbl)
Definition: gc.c:1443
ruby_xmalloc
void * ruby_xmalloc(size_t size)
Definition: gc.c:6156
gc_profile_result
static VALUE gc_profile_result(void)
Definition: gc.c:7205
HEAP_ALIGN
Definition: gc.c:553
NODE_BREAK
Definition: node.h:43
NODE_RETRY
Definition: node.h:49
MEMOP_TYPE_MALLOC
Definition: gc.c:5960
wmap_aref
static VALUE wmap_aref(VALUE self, VALUE wmap)
Definition: gc.c:6662
rb_data_typed_object_alloc
VALUE rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *type)
Definition: gc.c:1376
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:845
MARK_IN_BITMAP
#define MARK_IN_BITMAP(bits, p)
Definition: gc.c:594
rb_objspace::count
size_t count
Definition: gc.c:502
rb_exc_new3
#define rb_exc_new3
Definition: intern.h:248
heap_page::prev
struct heap_page * prev
Definition: gc.c:570
NODE_XSTR
Definition: node.h:143
finalizing
#define finalizing
Definition: gc.c:625
wmap_keys
static VALUE wmap_keys(VALUE self)
Definition: gc.c:6584
STACK_LEVEL_MAX
#define STACK_LEVEL_MAX
Definition: gc.c:3226
ruby_sized_xrealloc
void * ruby_sized_xrealloc(void *ptr, size_t new_size, size_t old_size)
Definition: gc.c:6200
RVALUE::match
struct RMatch match
Definition: gc.c:350
GC_HEAP_FREE_SLOTS
#define GC_HEAP_FREE_SLOTS
Definition: gc.c:100
rgengc_remembersetbits_set
static int rgengc_remembersetbits_set(rb_objspace_t *objspace, VALUE obj)
Definition: gc.c:4584
rb_gc_mark_parser
void rb_gc_mark_parser(void)
Definition: ripper.c:16607
STR_ASSOC
#define STR_ASSOC
free_stack_chunks
static void free_stack_chunks(mark_stack_t *)
Definition: gc.c:3164
gc_profile_record_get
static VALUE gc_profile_record_get(void)
Definition: gc.c:7016
size
int size
Definition: encoding.c:49
rb_mark_generic_ivar
void rb_mark_generic_ivar(VALUE)
Definition: variable.c:992
ruby_gc_params_t
Definition: gc.c:135
INT2FIX
#define INT2FIX(i)
Definition: ruby.h:231
each_obj_args::data
void * data
Definition: gc.c:1691
gc_rest_sweep
static void gc_rest_sweep(rb_objspace_t *objspace)
Definition: gc.c:3050
wmap_aset_update
static int wmap_aset_update(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
Definition: gc.c:6624
RCLASS_SUPER
#define RCLASS_SUPER(c)
Definition: classext.h:16
rb_sourceline
int rb_sourceline(void)
Definition: vm.c:1001
NODE_WHILE
Definition: node.h:35
NODE_SCLASS
Definition: node.h:189
ready_to_gc
static int ready_to_gc(rb_objspace_t *objspace)
Definition: gc.c:5047
RVALUE::v1
VALUE v1
Definition: gc.c:355
GPR_FLAG_HAVE_FINALIZE
Definition: gc.c:282
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: ruby.h:901
NODE_DVAR
Definition: node.h:117
NODE_NEXT
Definition: node.h:45
rb_objspace::invoke_time
double invoke_time
Definition: gc.c:466
mark_method_entry
static void mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
Definition: gc.c:3387
rb_block_proc
VALUE rb_block_proc(void)
Definition: proc.c:620
xmalloc
#define xmalloc
Definition: defines.h:108
rb_objspace_reachable_objects_from
void rb_objspace_reachable_objects_from(VALUE obj, void(func)(VALUE, void *), void *data)
Definition: gc.c:5779
rb_method_entry_struct::def
rb_method_definition_t * def
Definition: method.h:100
st_memsize
size_t st_memsize(const st_table *)
Definition: st.c:342
RUBY_INTERNAL_EVENT_NEWOBJ
#define RUBY_INTERNAL_EVENT_NEWOBJ
Definition: ruby.h:1732
BITS_SIZE
Definition: gc.c:372
RUBY_INTERNAL_EVENT_FREEOBJ
#define RUBY_INTERNAL_EVENT_FREEOBJ
Definition: ruby.h:1733
rb_gc_start
VALUE rb_gc_start(void)
Definition: gc.c:5183
rb_set_errinfo
void rb_set_errinfo(VALUE err)
Definition: eval.c:1504
wmap_inspect_i
static int wmap_inspect_i(st_data_t key, st_data_t val, st_data_t arg)
Definition: gc.c:6460
RUBY_DTRACE_GC_SWEEP_BEGIN
#define RUBY_DTRACE_GC_SWEEP_BEGIN()
Definition: probes.h:74
RUBY_DATA_FUNC
void(* RUBY_DATA_FUNC)(void *)
Definition: ruby.h:1001
ANYARGS
#define ANYARGS
Definition: defines.h:98
getrusage
int getrusage(int who, struct rusage *usage)
Definition: missing-pips.c:58
rb_data_type_struct
Definition: ruby.h:966
rb_event_flag_t
unsigned long rb_event_flag_t
Definition: ruby.h:1740
rb_gc_stat
size_t rb_gc_stat(VALUE key)
Definition: gc.c:5555
rb_mark_set
void rb_mark_set(st_table *tbl)
Definition: gc.c:3357
RVALUE::next
struct RVALUE * next
Definition: gc.c:334
rb_thread_call_with_gvl
RUBY_SYMBOL_EXPORT_BEGIN void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
Definition: thread.c:1450
NODE_NIL
Definition: node.h:207
GPR_FLAG_MAJOR_BY_STRESS
Definition: gc.c:267
RVALUE::regexp
struct RRegexp regexp
Definition: gc.c:342
verify_internal_consistency_struct
Definition: gc.c:4168
gc_count
static VALUE gc_count(VALUE self)
Definition: gc.c:5235
weakmap::wmap2obj
st_table * wmap2obj
Definition: gc.c:6314
is_swept_object
static int is_swept_object(rb_objspace_t *objspace, VALUE ptr)
Definition: gc.c:2237
rb_objspace::minor_gc_count
size_t minor_gc_count
Definition: gc.c:469
rb_newobj_of
VALUE rb_newobj_of(VALUE klass, VALUE flags)
Definition: gc.c:1354
RCLASS_IV_INDEX_TBL
#define RCLASS_IV_INDEX_TBL(c)
Definition: internal.h:296
RHASH_TBL_RAW
#define RHASH_TBL_RAW(h)
Definition: internal.h:478
heap_pages_expand_sorted
static void heap_pages_expand_sorted(rb_objspace_t *objspace)
Definition: gc.c:927
FL_WB_PROTECTED
#define FL_WB_PROTECTED
Definition: ruby.h:1134
rb_objspace::global_list
struct gc_list * global_list
Definition: gc.c:507
objspace_xrealloc
static void * objspace_xrealloc(rb_objspace_t *objspace, void *ptr, size_t new_size, size_t old_size)
Definition: gc.c:6101
heap_add_page
static void heap_add_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
Definition: gc.c:1130
objspace_and_reason::full_mark
int full_mark
Definition: gc.c:5080
wmap_inspect
static VALUE wmap_inspect(VALUE self)
Definition: gc.c:6484
key
uint8_t key[16]
Definition: random.c:1250
rb_any_to_s
VALUE rb_any_to_s(VALUE)
Definition: object.c:452
rb_objspace::max_free_slots
size_t max_free_slots
Definition: gc.c:441
gc_sweep
static void gc_sweep(rb_objspace_t *objspace, int immediate_sweep)
Definition: gc.c:3057
rb_obj_is_fiber
VALUE rb_obj_is_fiber(VALUE obj)
Definition: cont.c:370
stack_chunk_alloc
static stack_chunk_t * stack_chunk_alloc(void)
Definition: gc.c:3090
rb_special_const_p
static int rb_special_const_p(VALUE obj)
Definition: ruby.h:1687
ruby_gc_debug_indent
int ruby_gc_debug_indent
Definition: gc.c:648
RUBY_T_MASK
Definition: ruby.h:472
rb_gc_writebarrier_remember_promoted
void rb_gc_writebarrier_remember_promoted(VALUE obj)
Definition: gc.c:4782
rb_objspace::records
gc_profile_record * records
Definition: gc.c:458
RTEST
#define RTEST(v)
Definition: ruby.h:437
rb_proc_new
VALUE rb_proc_new(VALUE(*)(ANYARGS), VALUE)
Definition: proc.c:2301
NODE_STR
Definition: node.h:139
T_STRING
#define T_STRING
Definition: ruby.h:482
rb_gc_resurrect
void rb_gc_resurrect(VALUE obj)
Definition: gc.c:3612
PRIuSIZE
#define PRIuSIZE
Definition: ruby.h:179
OBJ_INFECT
#define OBJ_INFECT(x, s)
Definition: ruby.h:1180
GPR_FLAG_MAJOR_MASK
Definition: gc.c:271
RREGEXP
#define RREGEXP(obj)
Definition: ruby.h:1122
rb_objspace_call_finalizer
static void rb_objspace_call_finalizer(rb_objspace_t *objspace)
Definition: gc.c:2150
rb_objspace::total_allocated_object_num_at_gc_start
size_t total_allocated_object_num_at_gc_start
Definition: gc.c:498
GPR_FLAG_METHOD
Definition: gc.c:276
rb_obj_rgengc_promoted_p
VALUE rb_obj_rgengc_promoted_p(VALUE obj)
Definition: gc.c:4842
list
struct rb_encoding_entry * list
Definition: encoding.c:47
get_envparam_int
static int get_envparam_int(const char *name, unsigned int *default_value, int lower_bound)
Definition: gc.c:5650
wmap_each_value_i
static int wmap_each_value_i(st_data_t key, st_data_t val, st_data_t arg)
Definition: gc.c:6547
rb_gc_mark_unlinked_live_method_entries
void rb_gc_mark_unlinked_live_method_entries(void *pvm)
Definition: vm_method.c:123
rb_objspace::last_major_gc
size_t last_major_gc
Definition: gc.c:523
heap_pages_length
#define heap_pages_length
Definition: gc.c:612
each_obj_callback
int each_obj_callback(void *, void *, size_t, void *)
Definition: gc.c:1687
T_FALSE
#define T_FALSE
Definition: ruby.h:491
T_FILE
#define T_FILE
Definition: ruby.h:488
rb_heap_t
struct rb_heap_struct rb_heap_t
rb_objspace_alloc
rb_objspace_t * rb_objspace_alloc(void)
Definition: gc.c:873
rb_objspace::length
size_t length
Definition: gc.c:433
timespec
Definition: missing.h:50
rb_classext_t
struct rb_classext_struct rb_classext_t
Definition: ruby.h:788
free_method_entry_i
static int free_method_entry_i(ID key, rb_method_entry_t *me, st_data_t data)
Definition: gc.c:1434
ruby_gc_params_t::growth_factor
double growth_factor
Definition: gc.c:138
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1030
rb_eval_cmd
VALUE rb_eval_cmd(VALUE, VALUE, int)
Definition: vm_eval.c:1464
GPR_FLAG_MAJOR_BY_OLDMALLOC
Definition: gc.c:269
heap_page::freelist
RVALUE * freelist
Definition: gc.c:565
st.h
mark_stack_t
struct mark_stack mark_stack_t
rb_thread_raised_p
#define rb_thread_raised_p(th, f)
Definition: eval_intern.h:225
hash
static unsigned int hash(const char *str, unsigned int len)
Definition: lex.c:56
rb_objspace::old_object_limit
size_t old_object_limit
Definition: gc.c:528
rb_objspace::eden_heap
rb_heap_t eden_heap
Definition: gc.c:427
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
Definition: intern.h:242
rb_atomic_t
int rb_atomic_t
Definition: ruby_atomic.h:120
NODE_FALSE
Definition: node.h:211
heap_pages_sorted
#define heap_pages_sorted
Definition: gc.c:610
T_CLASS
#define T_CLASS
Definition: ruby.h:478
rmatch::char_offset
struct rmatch_offset * char_offset
Definition: re.h:41
heap_pages_used
#define heap_pages_used
Definition: gc.c:611
SET_STACK_END
#define SET_STACK_END
Definition: gc.c:3221
rb_safe_level
#define rb_safe_level()
Definition: tcltklib.c:95
RVALUE_WB_PROTECTED_RAW
#define RVALUE_WB_PROTECTED_RAW(obj)
Definition: gc.c:708
gc_event_hook_body
static void gc_event_hook_body(rb_objspace_t *objspace, const rb_event_flag_t event, VALUE data)
Definition: gc.c:1272
ROBJECT_EMBED
#define ROBJECT_EMBED
Definition: ruby.h:773
PRIdSIZE
#define PRIdSIZE
Definition: ruby.h:176
init_mark_stack
static void init_mark_stack(mark_stack_t *stack)
Definition: gc.c:3203
NODE_GASGN
Definition: node.h:71
rb_gc_mark_maybe
void rb_gc_mark_maybe(VALUE obj)
Definition: gc.c:3537
rb_vm_struct::self
VALUE self
Definition: vm_core.h:349
EXEC_EVENT_HOOK
#define EXEC_EVENT_HOOK(th_, flag_, self_, id_, klass_, data_)
Definition: vm_core.h:1034
ruby_gc_params_t::gc_stress
VALUE gc_stress
Definition: gc.c:148
mark_tbl_arg
Definition: gc.c:3318
assert
#define assert(condition)
Definition: ossl.h:45
shrink_stack_chunk_cache
static void shrink_stack_chunk_cache(mark_stack_t *stack)
Definition: gc.c:3116
name
const char * name
Definition: nkf.c:208
FL_SET
#define FL_SET(x, f)
Definition: ruby.h:1172
RVALUE::data
struct RData data
Definition: gc.c:344
rb_iseq_struct::self
VALUE self
Definition: vm_core.h:303
ID2SYM
#define ID2SYM(x)
Definition: ruby.h:355
NODE_OR
Definition: node.h:61
GC_HEAP_INIT_SLOTS
#define GC_HEAP_INIT_SLOTS
Definition: gc.c:103
heap_ready_to_gc
static int heap_ready_to_gc(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:5032
rb_id2name
const char * rb_id2name(ID id)
Definition: ripper.c:17230
NODE_COLON3
Definition: node.h:193
gc_prof_setup_new_record
static void gc_prof_setup_new_record(rb_objspace_t *objspace, int reason)
Definition: gc.c:6760
rb_gc_mark_global_tbl
void rb_gc_mark_global_tbl(void)
Definition: variable.c:562
ruby_native_thread_p
#define ruby_native_thread_p()
Definition: tcltklib.c:83
rb_objspace::heap_pages
struct rb_objspace::@103 heap_pages
GPR_FLAG_STRESS
Definition: gc.c:278
RObject
Definition: ruby.h:762
is_live_object
static int is_live_object(rb_objspace_t *objspace, VALUE ptr)
Definition: gc.c:2256
GC_OLDMALLOC_LIMIT_MIN
#define GC_OLDMALLOC_LIMIT_MIN
Definition: gc.c:126
ruby_gc_params_t::heap_init_slots
unsigned int heap_init_slots
Definition: gc.c:136
NODE_HASH
Definition: node.h:109
rb_inspect
VALUE rb_inspect(VALUE)
Definition: object.c:470
hi
#define hi
Definition: siphash.c:22
ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
#define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
Definition: gc.c:64
RMATCH
#define RMATCH(obj)
Definition: re.h:51
make_io_deferred
static void make_io_deferred(rb_objspace_t *objspace, RVALUE *p)
Definition: gc.c:1481
bits_t
uintptr_t bits_t
Definition: gc.c:370
gc_mark_stacked_objects
static void gc_mark_stacked_objects(rb_objspace_t *)
Definition: gc.c:3968
garbage_collect_with_gvl
static int garbage_collect_with_gvl(rb_objspace_t *objspace, int full_mark, int immediate_sweep, int reason)
Definition: gc.c:5092
RTYPEDDATA_DATA
#define RTYPEDDATA_DATA(v)
Definition: ruby.h:996
regint.h
rb_secure
void rb_secure(int)
Definition: safe.c:88
NODE_OPT_N
Definition: node.h:33
NODE_WHEN
Definition: node.h:31
RHash
Definition: ruby.h:920
NODE_LASGN
Definition: node.h:65
rb_heap_struct::using_page
struct heap_page * using_page
Definition: gc.c:410
rb_check_frozen
#define rb_check_frozen(obj)
Definition: intern.h:277
NODE_LVAR
Definition: node.h:115
RBIGNUM_EMBED_FLAG
#define RBIGNUM_EMBED_FLAG
Definition: ruby.h:1100
NODE_MATCH
Definition: node.h:131
RVALUE::typeddata
struct RTypedData typeddata
Definition: gc.c:345
rb_stdout
RUBY_EXTERN VALUE rb_stdout
Definition: ruby.h:1627
RUBY_DTRACE_GC_MARK_BEGIN_ENABLED
#define RUBY_DTRACE_GC_MARK_BEGIN_ENABLED()
Definition: probes.h:67
rb_gc_call_finalizer_at_exit
void rb_gc_call_finalizer_at_exit(void)
Definition: gc.c:2144
rb_generic_ivar_memsize
size_t rb_generic_ivar_memsize(VALUE)
Definition: variable.c:1040
rb_gc_enable
VALUE rb_gc_enable(void)
Definition: gc.c:5616
rb_objspace::remembered_shady_object_count
size_t remembered_shady_object_count
Definition: gc.c:525
rb_obj_freeze
VALUE rb_obj_freeze(VALUE)
Definition: object.c:1076
vsnprintf
#define vsnprintf
Definition: subst.h:7
SPECIAL_CONST_P
#define SPECIAL_CONST_P(x)
Definition: ruby.h:1165
rb_objspace_t
struct rb_objspace rb_objspace_t
RVALUE::array
struct RArray array
Definition: gc.c:341
verify_internal_consistency_i
static int verify_internal_consistency_i(void *page_start, void *page_end, size_t stride, void *ptr)
Definition: gc.c:4194
RUBY_INTERNAL_EVENT_OBJSPACE_MASK
#define RUBY_INTERNAL_EVENT_OBJSPACE_MASK
Definition: ruby.h:1737
TYPE_NAME
#define TYPE_NAME(t)
xfree
void void xfree(void *)
gc_mark_children
static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr)
Definition: gc.c:3624
NODE_FOR
Definition: node.h:41
RUBY_INTERNAL_EVENT_GC_END_SWEEP
#define RUBY_INTERNAL_EVENT_GC_END_SWEEP
Definition: ruby.h:1736
gc_before_heap_sweep
static void gc_before_heap_sweep(rb_objspace_t *objspace, rb_heap_t *heap)
Definition: gc.c:2830
RVALUE::basic
struct RBasic basic
Definition: gc.c:336
RHASH_EMPTY_P
#define RHASH_EMPTY_P(h)
Definition: ruby.h:931
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:746
RUBY_DTRACE_GC_MARK_BEGIN
#define RUBY_DTRACE_GC_MARK_BEGIN()
Definition: probes.h:68
gc_prof_enabled
#define gc_prof_enabled(objspace)
Definition: gc.c:691
heap_set_increment
static void heap_set_increment(rb_objspace_t *objspace, size_t minimum_limit)
Definition: gc.c:1162
rb_mark_hash
void rb_mark_hash(st_table *tbl)
Definition: gc.c:3381
RVALUE::v3
VALUE v3
Definition: gc.c:357
GC_MALLOC_LIMIT_MIN
#define GC_MALLOC_LIMIT_MIN
Definition: gc.c:116
rb_intern
#define rb_intern(str)
each_obj_args::callback
each_obj_callback * callback
Definition: gc.c:1690
RData::data
void * data
Definition: ruby.h:961
undefine_final
static VALUE undefine_final(VALUE os, VALUE obj)
Definition: gc.c:1905
rb_str_buf_new
VALUE rb_str_buf_new(long)
Definition: string.c:891
gc_profile_clear
static VALUE gc_profile_clear(void)
Definition: gc.c:6949
NODE_OP_ASGN1
Definition: node.h:83
T_ZOMBIE
#define T_ZOMBIE
Definition: ruby.h:499
rb_gc_mark_encodings
void rb_gc_mark_encodings(void)
Definition: encoding.c:236
SYMBOL_P
#define SYMBOL_P(x)
Definition: ruby.h:354
RCLASS
#define RCLASS(obj)
Definition: ruby.h:1118
T_NONE
#define T_NONE
Definition: ruby.h:475
objspace_xcalloc
static void * objspace_xcalloc(rb_objspace_t *objspace, size_t count, size_t elsize)
Definition: gc.c:6178
rb_objspace::during_minor_gc
int during_minor_gc
Definition: gc.c:518
HEAP_ALIGN_LOG
#define HEAP_ALIGN_LOG
Definition: gc.c:549
wmap_each_key_i
static int wmap_each_key_i(st_data_t key, st_data_t val, st_data_t arg)
Definition: gc.c:6524
RVALUE::string
struct RString string
Definition: gc.c:340
FL_UNSET2
#define FL_UNSET2(x, f)
Definition: gc.c:706
GET_HEAP_REMEMBERSET_BITS
#define GET_HEAP_REMEMBERSET_BITS(x)
Definition: gc.c:586
objspace_xfree
static void objspace_xfree(rb_objspace_t *objspace, void *ptr, size_t size)
Definition: gc.c:6142
NULL
#define NULL
Definition: _sdbm.c:103
mark_stack::cache
stack_chunk_t * cache
Definition: gc.c:400
RTYPEDDATA_TYPE
#define RTYPEDDATA_TYPE(v)
Definition: ruby.h:995
RVALUE::klass
struct RClass klass
Definition: gc.c:338
RClass
Definition: ruby.h:790
Qundef
#define Qundef
Definition: ruby.h:428
T_ICLASS
#define T_ICLASS
Definition: ruby.h:479
GC_OLDMALLOC_LIMIT_MAX
#define GC_OLDMALLOC_LIMIT_MAX
Definition: gc.c:132
RVALUE::flags
VALUE flags
Definition: gc.c:333
rb_thread_struct::errinfo
VALUE errinfo
Definition: vm_core.h:573
wmap_finalize
static VALUE wmap_finalize(VALUE self, VALUE objid)
Definition: gc.c:6424
gc_stat
static VALUE gc_stat(int argc, VALUE *argv, VALUE self)
Definition: gc.c:5533
mark_set
static void mark_set(rb_objspace_t *objspace, st_table *tbl)
Definition: gc.c:3348
onig_free
void onig_free(regex_t *reg)
Definition: regcomp.c:5587
VM_METHOD_TYPE_IVAR
Definition: method.h:51
NODE_MATCH3
Definition: node.h:135
GET_HEAP_PAGE
#define GET_HEAP_PAGE(x)
Definition: gc.c:584
st_table::num_entries
st_index_t num_entries
Definition: st.h:85
malloc_limit
#define malloc_limit
Definition: gc.c:607
GET_THREAD
static rb_thread_t * GET_THREAD(void)
Definition: vm_core.h:927
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
ruby_verbose
#define ruby_verbose
Definition: ruby.h:1475
rb_str_append
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2298
CALC_EXACT_MALLOC_SIZE
#define CALC_EXACT_MALLOC_SIZE
Definition: gc.c:247
rb_objspace::sorted
struct heap_page ** sorted
Definition: gc.c:431
st_foreach
int st_foreach(st_table *, int(*)(ANYARGS), st_data_t)
Definition: st.c:1034
mark_locations_array
static ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS void mark_locations_array(rb_objspace_t *objspace, register VALUE *x, register long n)
Definition: gc.c:3290
ruby_gc_params_t::oldmalloc_limit_growth_factor
double oldmalloc_limit_growth_factor
Definition: gc.c:146
RVALUE::complex
struct RComplex complex
Definition: gc.c:352
rb_objspace::swept_slots
size_t swept_slots
Definition: gc.c:439
NODE_IASGN
Definition: node.h:73
RSTRING_NOEMBED
#define RSTRING_NOEMBED
Definition: ruby.h:834
rb_str_memsize
size_t rb_str_memsize(VALUE)
Definition: string.c:953
stack_chunk_t
struct stack_chunk stack_chunk_t
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:223
free
free(psz)
gc_profile_enable
static VALUE gc_profile_enable(void)
Definition: gc.c:7284
heap_page::before_sweep
int before_sweep
Definition: gc.c:573
SIZET2NUM
#define SIZET2NUM(v)
Definition: ruby.h:262
force_finalize_list
Definition: gc.c:2125
rb_eArgError
VALUE rb_eArgError
Definition: error.c:549
T_REGEXP
#define T_REGEXP
Definition: ruby.h:483
NODE_ARGS_AUX
Definition: node.h:155
rb_objspace::min_free_slots
size_t min_free_slots
Definition: gc.c:440
CLEAR_IN_BITMAP
#define CLEAR_IN_BITMAP(bits, p)
Definition: gc.c:595
NODE_LIT
Definition: node.h:137
T_MASK
#define T_MASK
Definition: md5.c:131
wmap_iter_arg::objspace
rb_objspace_t * objspace
Definition: gc.c:6455
rb_jmp_buf
#define rb_jmp_buf
Definition: gc.c:89
rb_objspace::rgengc
struct rb_objspace::@106 rgengc
NODE_DREGX_ONCE
Definition: node.h:151
FL_PROMOTED
#define FL_PROMOTED
Definition: ruby.h:1135
heap_page::limit
size_t limit
Definition: gc.c:568
BDIGIT
#define BDIGIT
Definition: bigdecimal.h:47
rb_data_object_alloc
VALUE rb_data_object_alloc(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
Definition: gc.c:1369
rmatch_offset
Definition: re.h:31
should_be_finalizable
static void should_be_finalizable(VALUE obj)
Definition: gc.c:1930
argv
char ** argv
Definition: ruby.c:132
RRegexp
Definition: ruby.h:909
should_be_callable
static void should_be_callable(VALUE block)
Definition: gc.c:1922
rb_heap_struct::free_pages
struct heap_page * free_pages
Definition: gc.c:409
DBL2NUM
#define DBL2NUM(dbl)
Definition: ruby.h:815
gc_setup_mark_bits
static void gc_setup_mark_bits(struct heap_page *page)
Definition: gc.c:2704
__asm__
#define __asm__
heap_page_add_freeobj
static void heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
Definition: gc.c:957
verify_internal_consistency_struct::parent
VALUE parent
Definition: gc.c:4171
gc_finalize_deferred_register
static void gc_finalize_deferred_register(void)
Definition: gc.c:2118
TRY_WITH_GC
#define TRY_WITH_GC(alloc)
Definition: gc.c:6080
SIGNED_VALUE
#define SIGNED_VALUE
Definition: ruby.h:90
stack_chunk::next
struct stack_chunk * next
Definition: gc.c:395
mark_stack
Definition: gc.c:398
GET_VM
#define GET_VM()
Definition: vm_core.h:920
rb_heap_struct::sweep_pages
struct heap_page * sweep_pages
Definition: gc.c:411
gc_mark_ptr
static int gc_mark_ptr(rb_objspace_t *objspace, VALUE ptr)
Definition: gc.c:3551
rb_objspace::remembered_shady_object_limit
size_t remembered_shady_object_limit
Definition: gc.c:526