Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license
2 : :
3 : : /*
4 : : allocation and garbage collection
5 : : . non-moving, precise mark and sweep collector
6 : : . pool-allocates small objects, keeps big objects on a simple list
7 : : */
8 : :
9 : : #ifndef JL_GC_H
10 : : #define JL_GC_H
11 : :
12 : : #include <stdlib.h>
13 : : #include <string.h>
14 : : #include <strings.h>
15 : : #include <inttypes.h>
16 : : #include "julia.h"
17 : : #include "julia_threads.h"
18 : : #include "julia_internal.h"
19 : : #include "threading.h"
20 : : #ifndef _OS_WINDOWS_
21 : : #include <sys/mman.h>
22 : : #if defined(_OS_DARWIN_) && !defined(MAP_ANONYMOUS)
23 : : #define MAP_ANONYMOUS MAP_ANON
24 : : #endif
25 : : #endif
26 : : #include "julia_assert.h"
27 : : #include "gc-alloc-profiler.h"
28 : :
29 : : #ifdef __cplusplus
30 : : extern "C" {
31 : : #endif
32 : :
33 : : #define GC_PAGE_LG2 14 // log2(size of a page)
34 : : #define GC_PAGE_SZ (1 << GC_PAGE_LG2) // 16k
35 : : #define GC_PAGE_OFFSET (JL_HEAP_ALIGNMENT - (sizeof(jl_taggedvalue_t) % JL_HEAP_ALIGNMENT))
36 : :
37 : : #define jl_malloc_tag ((void*)0xdeadaa01)
38 : : #define jl_singleton_tag ((void*)0xdeadaa02)
39 : :
40 : : // Used by GC_DEBUG_ENV
41 : : typedef struct {
42 : : uint64_t num;
43 : : uint64_t next;
44 : :
45 : : uint64_t min;
46 : : uint64_t interv;
47 : : uint64_t max;
48 : : unsigned short random[3];
49 : : } jl_alloc_num_t;
50 : :
51 : : typedef struct {
52 : : int always_full;
53 : : int wait_for_debugger;
54 : : jl_alloc_num_t pool;
55 : : jl_alloc_num_t other;
56 : : jl_alloc_num_t print;
57 : : } jl_gc_debug_env_t;
58 : :
59 : : // This struct must be kept in sync with the Julia type of the same name in base/timing.jl
60 : : typedef struct {
61 : : int64_t allocd;
62 : : int64_t deferred_alloc;
63 : : int64_t freed;
64 : : uint64_t malloc;
65 : : uint64_t realloc;
66 : : uint64_t poolalloc;
67 : : uint64_t bigalloc;
68 : : uint64_t freecall;
69 : : uint64_t total_time;
70 : : uint64_t total_allocd;
71 : : uint64_t since_sweep;
72 : : size_t interval;
73 : : int pause;
74 : : int full_sweep;
75 : : uint64_t max_pause;
76 : : uint64_t max_memory;
77 : : uint64_t time_to_safepoint;
78 : : uint64_t max_time_to_safepoint;
79 : : uint64_t sweep_time;
80 : : uint64_t mark_time;
81 : : uint64_t total_sweep_time;
82 : : uint64_t total_mark_time;
83 : : } jl_gc_num_t;
84 : :
85 : : enum {
86 : : GC_MARK_L_marked_obj,
87 : : GC_MARK_L_scan_only,
88 : : GC_MARK_L_finlist,
89 : : GC_MARK_L_objarray,
90 : : GC_MARK_L_array8,
91 : : GC_MARK_L_array16,
92 : : GC_MARK_L_obj8,
93 : : GC_MARK_L_obj16,
94 : : GC_MARK_L_obj32,
95 : : GC_MARK_L_stack,
96 : : GC_MARK_L_excstack,
97 : : GC_MARK_L_module_binding,
98 : : _GC_MARK_L_MAX
99 : : };
100 : :
101 : : // The following structs (`gc_mark_*_t`) contain iterator state used for the
102 : : // scanning of various object types.
103 : : //
104 : : // The `nptr` member records the number of pointers slots referenced by
105 : : // an object to be used in the full collection heuristics as well as whether the object
106 : : // references young objects.
107 : : // `nptr >> 2` is the number of pointers fields referenced by the object.
108 : : // The lowest bit of `nptr` is set if the object references young object.
109 : : // The 2nd lowest bit of `nptr` is the GC old bits of the object after marking.
110 : : // A `0x3` in the low bits means that the object needs to be in the remset.
111 : :
112 : : // An generic object that's marked and needs to be scanned
113 : : // The metadata might need update too (depend on the PC)
114 : : typedef struct {
115 : : jl_value_t *obj; // The object
116 : : uintptr_t tag; // The tag with the GC bits masked out
117 : : uint8_t bits; // The GC bits after tagging (`bits & 1 == 1`)
118 : : } gc_mark_marked_obj_t;
119 : :
120 : : // An object array. This can come from an array, svec, or the using array or a module
121 : : typedef struct {
122 : : jl_value_t *parent; // The parent object to trigger write barrier on.
123 : : jl_value_t **begin; // The first slot to be scanned.
124 : : jl_value_t **end; // The end address (after the last slot to be scanned)
125 : : uint32_t step; // Number of pointers to jump between marks
126 : : uintptr_t nptr; // See notes about `nptr` above.
127 : : } gc_mark_objarray_t;
128 : :
129 : : // A normal object with 8bits field descriptors
130 : : typedef struct {
131 : : jl_value_t *parent; // The parent object to trigger write barrier on.
132 : : uint8_t *begin; // Current field descriptor.
133 : : uint8_t *end; // End of field descriptor.
134 : : uintptr_t nptr; // See notes about `nptr` above.
135 : : } gc_mark_obj8_t;
136 : :
137 : : // A normal object with 16bits field descriptors
138 : : typedef struct {
139 : : jl_value_t *parent; // The parent object to trigger write barrier on.
140 : : uint16_t *begin; // Current field descriptor.
141 : : uint16_t *end; // End of field descriptor.
142 : : uintptr_t nptr; // See notes about `nptr` above.
143 : : } gc_mark_obj16_t;
144 : :
145 : : // A normal object with 32bits field descriptors
146 : : typedef struct {
147 : : jl_value_t *parent; // The parent object to trigger write barrier on.
148 : : uint32_t *begin; // Current field descriptor.
149 : : uint32_t *end; // End of field descriptor.
150 : : uintptr_t nptr; // See notes about `nptr` above.
151 : : } gc_mark_obj32_t;
152 : :
153 : : typedef struct {
154 : : jl_value_t **begin; // The first slot to be scanned.
155 : : jl_value_t **end; // The end address (after the last slot to be scanned)
156 : : uint8_t *rebegin;
157 : : gc_mark_obj8_t elem;
158 : : } gc_mark_array8_t;
159 : :
160 : : typedef struct {
161 : : jl_value_t **begin; // The first slot to be scanned.
162 : : jl_value_t **end; // The end address (after the last slot to be scanned)
163 : : uint16_t *rebegin;
164 : : gc_mark_obj16_t elem;
165 : : } gc_mark_array16_t;
166 : :
167 : : // Stack frame
168 : : typedef struct {
169 : : jl_gcframe_t *s; // The current stack frame
170 : : uint32_t i; // The current slot index in the frame
171 : : uint32_t nroots; // `nroots` fields in the frame
172 : : // Parameters to mark the copy_stack range.
173 : : uintptr_t offset;
174 : : uintptr_t lb;
175 : : uintptr_t ub;
176 : : } gc_mark_stackframe_t;
177 : :
178 : : // Exception stack data
179 : : typedef struct {
180 : : jl_excstack_t *s; // Stack of exceptions
181 : : size_t itr; // Iterator into exception stack
182 : : size_t bt_index; // Current backtrace buffer entry index
183 : : size_t jlval_index; // Index into GC managed values for current bt entry
184 : : } gc_mark_excstack_t;
185 : :
186 : : // Module bindings. This is also the beginning of module scanning.
187 : : // The loop will start marking other references in a module after the bindings are marked
188 : : typedef struct {
189 : : jl_module_t *parent; // The parent module to trigger write barrier on.
190 : : jl_binding_t **begin; // The first slot to be scanned.
191 : : jl_binding_t **end; // The end address (after the last slot to be scanned)
192 : : uintptr_t nptr; // See notes about `nptr` above.
193 : : uint8_t bits; // GC bits of the module (the bits to mark the binding buffer with)
194 : : } gc_mark_binding_t;
195 : :
196 : : // Finalizer (or object) list
197 : : typedef struct {
198 : : jl_value_t **begin;
199 : : jl_value_t **end;
200 : : } gc_mark_finlist_t;
201 : :
202 : : // This is used to determine the max size of the data objects on the data stack.
203 : : // We'll use this size to determine the size of the data stack corresponding to a
204 : : // PC stack size. Since the data objects are not all of the same size, we'll waste
205 : : // some memory on the data stack this way but that size is unlikely going to be significant.
206 : : union _jl_gc_mark_data {
207 : : gc_mark_marked_obj_t marked;
208 : : gc_mark_objarray_t objarray;
209 : : gc_mark_array8_t array8;
210 : : gc_mark_array16_t array16;
211 : : gc_mark_obj8_t obj8;
212 : : gc_mark_obj16_t obj16;
213 : : gc_mark_obj32_t obj32;
214 : : gc_mark_stackframe_t stackframe;
215 : : gc_mark_excstack_t excstackframe;
216 : : gc_mark_binding_t binding;
217 : : gc_mark_finlist_t finlist;
218 : : };
219 : :
220 : : // Pop a data struct from the mark data stack (i.e. decrease the stack pointer)
221 : : // This should be used after dispatch and therefore the pc stack pointer is already popped from
222 : : // the stack.
223 : 1595300000 : STATIC_INLINE void *gc_pop_markdata_(jl_gc_mark_sp_t *sp, size_t size)
224 : : {
225 : 1595300000 : jl_gc_mark_data_t *data = (jl_gc_mark_data_t *)(((char*)sp->data) - size);
226 : 1595300000 : sp->data = data;
227 : 1595300000 : return data;
228 : : }
229 : : #define gc_pop_markdata(sp, type) ((type*)gc_pop_markdata_(sp, sizeof(type)))
230 : :
231 : : // Re-push a frame to the mark stack (both data and pc)
232 : : // The data and pc are expected to be on the stack (or updated in place) already.
233 : : // Mainly useful to pause the current scanning in order to scan an new object.
234 : 1580710000 : STATIC_INLINE void *gc_repush_markdata_(jl_gc_mark_sp_t *sp, size_t size) JL_NOTSAFEPOINT
235 : : {
236 : 1580710000 : jl_gc_mark_data_t *data = sp->data;
237 : 1580710000 : sp->pc++;
238 : 1580710000 : sp->data = (jl_gc_mark_data_t *)(((char*)sp->data) + size);
239 : 1580710000 : return data;
240 : : }
241 : : #define gc_repush_markdata(sp, type) ((type*)gc_repush_markdata_(sp, sizeof(type)))
242 : :
243 : : // layout for big (>2k) objects
244 : :
245 : : JL_EXTENSION typedef struct _bigval_t {
246 : : struct _bigval_t *next;
247 : : struct _bigval_t **prev; // pointer to the next field of the prev entry
248 : : union {
249 : : size_t sz;
250 : : uintptr_t age : 2;
251 : : };
252 : : #ifdef _P64 // Add padding so that the value is 64-byte aligned
253 : : // (8 pointers of 8 bytes each) - (4 other pointers in struct)
254 : : void *_padding[8 - 4];
255 : : #else
256 : : // (16 pointers of 4 bytes each) - (4 other pointers in struct)
257 : : void *_padding[16 - 4];
258 : : #endif
259 : : //struct jl_taggedvalue_t <>;
260 : : union {
261 : : uintptr_t header;
262 : : struct {
263 : : uintptr_t gc:2;
264 : : } bits;
265 : : };
266 : : // must be 64-byte aligned here, in 32 & 64 bit modes
267 : : } bigval_t;
268 : :
269 : : // data structure for tracking malloc'd arrays.
270 : :
271 : : typedef struct _mallocarray_t {
272 : : jl_array_t *a;
273 : : struct _mallocarray_t *next;
274 : : } mallocarray_t;
275 : :
276 : : // pool page metadata
277 : : typedef struct {
278 : : // index of pool that owns this page
279 : : uint8_t pool_n;
280 : : // Whether any cell in the page is marked
281 : : // This bit is set before sweeping iff there are live cells in the page.
282 : : // Note that before marking or after sweeping there can be live
283 : : // (and young) cells in the page for `!has_marked`.
284 : : uint8_t has_marked;
285 : : // Whether any cell was live and young **before sweeping**.
286 : : // For a normal sweep (quick sweep that is NOT preceded by a
287 : : // full sweep) this bit is set iff there are young or newly dead
288 : : // objects in the page and the page needs to be swept.
289 : : //
290 : : // For a full sweep, this bit should be ignored.
291 : : //
292 : : // For a quick sweep preceded by a full sweep. If this bit is set,
293 : : // the page needs to be swept. If this bit is not set, there could
294 : : // still be old dead objects in the page and `nold` and `prev_nold`
295 : : // should be used to determine if the page needs to be swept.
296 : : uint8_t has_young;
297 : : // number of old objects in this page
298 : : uint16_t nold;
299 : : // number of old objects in this page during the previous full sweep
300 : : uint16_t prev_nold;
301 : : // number of free objects in this page.
302 : : // invalid if pool that owns this page is allocating objects from this page.
303 : : uint16_t nfree;
304 : : uint16_t osize; // size of each object in this page
305 : : uint16_t fl_begin_offset; // offset of first free object in this page
306 : : uint16_t fl_end_offset; // offset of last free object in this page
307 : : uint16_t thread_n; // thread id of the heap that owns this page
308 : : char *data;
309 : : uint8_t *ages;
310 : : } jl_gc_pagemeta_t;
311 : :
312 : : // Page layout:
313 : : // Newpage freelist: sizeof(void*)
314 : : // Padding: GC_PAGE_OFFSET - sizeof(void*)
315 : : // Blocks: osize * n
316 : : // Tag: sizeof(jl_taggedvalue_t)
317 : : // Data: <= osize - sizeof(jl_taggedvalue_t)
318 : :
319 : : // Memory map:
320 : : // The complete address space is divided up into a multi-level page table.
321 : : // The three levels have similar but slightly different structures:
322 : : // - pagetable0_t: the bottom/leaf level (covers the contiguous addresses)
323 : : // - pagetable1_t: the middle level
324 : : // - pagetable2_t: the top/leaf level (covers the entire virtual address space)
325 : : // Corresponding to these similar structures is a large amount of repetitive
326 : : // code that is nearly the same but not identical. It could be made less
327 : : // repetitive with C macros, but only at the cost of debuggability. The specialized
328 : : // structure of this representation allows us to partially unroll and optimize
329 : : // various conditions at each level.
330 : :
331 : : // The following constants define the branching factors at each level.
332 : : // The constants and GC_PAGE_LG2 must therefore sum to sizeof(void*).
333 : : // They should all be multiples of 32 (sizeof(uint32_t)) except that REGION2_PG_COUNT may also be 1.
334 : : #ifdef _P64
335 : : #define REGION0_PG_COUNT (1 << 16)
336 : : #define REGION1_PG_COUNT (1 << 16)
337 : : #define REGION2_PG_COUNT (1 << 18)
338 : : #define REGION0_INDEX(p) (((uintptr_t)(p) >> 14) & 0xFFFF) // shift by GC_PAGE_LG2
339 : : #define REGION1_INDEX(p) (((uintptr_t)(p) >> 30) & 0xFFFF)
340 : : #define REGION_INDEX(p) (((uintptr_t)(p) >> 46) & 0x3FFFF)
341 : : #else
342 : : #define REGION0_PG_COUNT (1 << 8)
343 : : #define REGION1_PG_COUNT (1 << 10)
344 : : #define REGION2_PG_COUNT (1 << 0)
345 : : #define REGION0_INDEX(p) (((uintptr_t)(p) >> 14) & 0xFF) // shift by GC_PAGE_LG2
346 : : #define REGION1_INDEX(p) (((uintptr_t)(p) >> 22) & 0x3FF)
347 : : #define REGION_INDEX(p) (0)
348 : : #endif
349 : :
350 : : // define the representation of the levels of the page-table (0 to 2)
351 : : typedef struct {
352 : : jl_gc_pagemeta_t *meta[REGION0_PG_COUNT];
353 : : uint32_t allocmap[REGION0_PG_COUNT / 32];
354 : : uint32_t freemap[REGION0_PG_COUNT / 32];
355 : : // store a lower bound of the first free page in each region
356 : : int lb;
357 : : // an upper bound of the last non-free page
358 : : int ub;
359 : : } pagetable0_t;
360 : :
361 : : typedef struct {
362 : : pagetable0_t *meta0[REGION1_PG_COUNT];
363 : : uint32_t allocmap0[REGION1_PG_COUNT / 32];
364 : : uint32_t freemap0[REGION1_PG_COUNT / 32];
365 : : // store a lower bound of the first free page in each region
366 : : int lb;
367 : : // an upper bound of the last non-free page
368 : : int ub;
369 : : } pagetable1_t;
370 : :
371 : : typedef struct {
372 : : pagetable1_t *meta1[REGION2_PG_COUNT];
373 : : uint32_t allocmap1[(REGION2_PG_COUNT + 31) / 32];
374 : : uint32_t freemap1[(REGION2_PG_COUNT + 31) / 32];
375 : : // store a lower bound of the first free page in each region
376 : : int lb;
377 : : // an upper bound of the last non-free page
378 : : int ub;
379 : : } pagetable_t;
380 : :
381 : : #ifdef __clang_gcanalyzer__
382 : : unsigned ffs_u32(uint32_t bitvec) JL_NOTSAFEPOINT;
383 : : #else
384 : 450552500 : STATIC_INLINE unsigned ffs_u32(uint32_t bitvec)
385 : : {
386 : 450552500 : return __builtin_ffs(bitvec) - 1;
387 : : }
388 : : #endif
389 : :
390 : : extern jl_gc_num_t gc_num;
391 : : extern pagetable_t memory_map;
392 : : extern bigval_t *big_objects_marked;
393 : : extern arraylist_t finalizer_list_marked;
394 : : extern arraylist_t to_finalize;
395 : : extern int64_t lazy_freed_pages;
396 : :
397 : 2176080 : STATIC_INLINE bigval_t *bigval_header(jl_taggedvalue_t *o) JL_NOTSAFEPOINT
398 : : {
399 : 2176080 : return container_of(o, bigval_t, header);
400 : : }
401 : :
402 : : // round an address inside a gcpage's data to its beginning
403 :24979900849 : STATIC_INLINE char *gc_page_data(void *x) JL_NOTSAFEPOINT
404 : : {
405 :24979900849 : return (char*)(((uintptr_t)x >> GC_PAGE_LG2) << GC_PAGE_LG2);
406 : : }
407 : :
408 : 97379800 : STATIC_INLINE jl_taggedvalue_t *page_pfl_beg(jl_gc_pagemeta_t *p) JL_NOTSAFEPOINT
409 : : {
410 : 97379800 : return (jl_taggedvalue_t*)(p->data + p->fl_begin_offset);
411 : : }
412 : :
413 : 97379800 : STATIC_INLINE jl_taggedvalue_t *page_pfl_end(jl_gc_pagemeta_t *p) JL_NOTSAFEPOINT
414 : : {
415 : 97379800 : return (jl_taggedvalue_t*)(p->data + p->fl_end_offset);
416 : : }
417 : :
418 :60905395890 : STATIC_INLINE int gc_marked(uintptr_t bits) JL_NOTSAFEPOINT
419 : : {
420 :60905395890 : return (bits & GC_MARKED) != 0;
421 : : }
422 : :
423 :14728900000 : STATIC_INLINE int gc_old(uintptr_t bits) JL_NOTSAFEPOINT
424 : : {
425 :14728900000 : return (bits & GC_OLD) != 0;
426 : : }
427 : :
428 : 2304200 : STATIC_INLINE uintptr_t gc_set_bits(uintptr_t tag, int bits) JL_NOTSAFEPOINT
429 : : {
430 : 2304200 : return (tag & ~(uintptr_t)3) | bits;
431 : : }
432 : :
433 : 59606100 : STATIC_INLINE uintptr_t gc_ptr_tag(void *v, uintptr_t mask) JL_NOTSAFEPOINT
434 : : {
435 : 59606100 : return ((uintptr_t)v) & mask;
436 : : }
437 : :
438 : 8952920 : STATIC_INLINE void *gc_ptr_clear_tag(void *v, uintptr_t mask) JL_NOTSAFEPOINT
439 : : {
440 : 8952920 : return (void*)(((uintptr_t)v) & ~mask);
441 : : }
442 : :
443 : : NOINLINE uintptr_t gc_get_stack_ptr(void);
444 : :
445 : 1456360000 : STATIC_INLINE jl_gc_pagemeta_t *page_metadata(void *_data) JL_NOTSAFEPOINT
446 : : {
447 : 1456360000 : uintptr_t data = ((uintptr_t)_data);
448 : : unsigned i;
449 : 1456360000 : i = REGION_INDEX(data);
450 : 1456360000 : pagetable1_t *r1 = memory_map.meta1[i];
451 [ - + ]: 1456360000 : if (!r1)
452 : 0 : return NULL;
453 : 1456360000 : i = REGION1_INDEX(data);
454 : 1456360000 : pagetable0_t *r0 = r1->meta0[i];
455 [ + + ]: 1456360000 : if (!r0)
456 : 2171570 : return NULL;
457 : 1454190000 : i = REGION0_INDEX(data);
458 : 1454190000 : return r0->meta[i];
459 : : }
460 : :
461 : : struct jl_gc_metadata_ext {
462 : : pagetable1_t *pagetable1;
463 : : pagetable0_t *pagetable0;
464 : : jl_gc_pagemeta_t *meta;
465 : : unsigned pagetable_i32, pagetable_i;
466 : : unsigned pagetable1_i32, pagetable1_i;
467 : : unsigned pagetable0_i32, pagetable0_i;
468 : : };
469 : :
470 : 4466610 : STATIC_INLINE struct jl_gc_metadata_ext page_metadata_ext(void *_data) JL_NOTSAFEPOINT
471 : : {
472 : 4466610 : uintptr_t data = (uintptr_t)_data;
473 : : struct jl_gc_metadata_ext info;
474 : : unsigned i;
475 : 4466610 : i = REGION_INDEX(data);
476 : 4466610 : info.pagetable_i = i % 32;
477 : 4466610 : info.pagetable_i32 = i / 32;
478 : 4466610 : info.pagetable1 = memory_map.meta1[i];
479 : 4466610 : i = REGION1_INDEX(data);
480 : 4466610 : info.pagetable1_i = i % 32;
481 : 4466610 : info.pagetable1_i32 = i / 32;
482 : 4466610 : info.pagetable0 = info.pagetable1->meta0[i];
483 : 4466610 : i = REGION0_INDEX(data);
484 : 4466610 : info.pagetable0_i = i % 32;
485 : 4466610 : info.pagetable0_i32 = i / 32;
486 : 4466610 : info.meta = info.pagetable0->meta[i];
487 [ - + ]: 4466610 : assert(info.meta);
488 : 4466610 : return info;
489 : : }
490 : :
491 : 1202370 : STATIC_INLINE void gc_big_object_unlink(const bigval_t *hdr) JL_NOTSAFEPOINT
492 : : {
493 : 1202370 : *hdr->prev = hdr->next;
494 [ + + ]: 1202370 : if (hdr->next) {
495 : 337903 : hdr->next->prev = hdr->prev;
496 : : }
497 : 1202370 : }
498 : :
499 : 10388400 : STATIC_INLINE void gc_big_object_link(bigval_t *hdr, bigval_t **list) JL_NOTSAFEPOINT
500 : : {
501 : 10388400 : hdr->next = *list;
502 : 10388400 : hdr->prev = list;
503 [ + + ]: 10388400 : if (*list)
504 : 10386300 : (*list)->prev = &hdr->next;
505 : 10388400 : *list = hdr;
506 : 10388400 : }
507 : :
508 : 42072 : STATIC_INLINE void gc_mark_sp_init(jl_gc_mark_cache_t *gc_cache, jl_gc_mark_sp_t *sp)
509 : : {
510 : 42072 : sp->pc = gc_cache->pc_stack;
511 : 42072 : sp->data = gc_cache->data_stack;
512 : 42072 : sp->pc_start = gc_cache->pc_stack;
513 : 42072 : sp->pc_end = gc_cache->pc_stack_end;
514 : 42072 : }
515 : :
516 : : void gc_mark_queue_all_roots(jl_ptls_t ptls, jl_gc_mark_sp_t *sp);
517 : : void gc_mark_queue_finlist(jl_gc_mark_cache_t *gc_cache, jl_gc_mark_sp_t *sp,
518 : : arraylist_t *list, size_t start);
519 : : void gc_mark_loop(jl_ptls_t ptls, jl_gc_mark_sp_t sp);
520 : : void sweep_stack_pools(void);
521 : : void jl_gc_debug_init(void);
522 : :
523 : : extern void *gc_mark_label_addrs[_GC_MARK_L_MAX];
524 : :
525 : : // GC pages
526 : :
527 : : void jl_gc_init_page(void);
528 : : NOINLINE jl_gc_pagemeta_t *jl_gc_alloc_page(void) JL_NOTSAFEPOINT;
529 : : void jl_gc_free_page(void *p) JL_NOTSAFEPOINT;
530 : :
531 : : // GC debug
532 : :
533 : : #if defined(GC_TIME) || defined(GC_FINAL_STATS)
534 : : void gc_settime_premark_end(void);
535 : : void gc_settime_postmark_end(void);
536 : : #else
537 : : #define gc_settime_premark_end()
538 : : #define gc_settime_postmark_end()
539 : : #endif
540 : :
541 : : #ifdef GC_FINAL_STATS
542 : : void gc_final_count_page(size_t pg_cnt);
543 : : void gc_final_pause_end(int64_t t0, int64_t tend);
544 : : #else
545 : : #define gc_final_count_page(pg_cnt)
546 : : #define gc_final_pause_end(t0, tend)
547 : : #endif
548 : :
549 : : #ifdef GC_TIME
550 : : void gc_time_pool_start(void) JL_NOTSAFEPOINT;
551 : : void gc_time_count_page(int freedall, int pg_skpd) JL_NOTSAFEPOINT;
552 : : void gc_time_pool_end(int sweep_full) JL_NOTSAFEPOINT;
553 : : void gc_time_sysimg_end(uint64_t t0) JL_NOTSAFEPOINT;
554 : :
555 : : void gc_time_big_start(void) JL_NOTSAFEPOINT;
556 : : void gc_time_count_big(int old_bits, int bits) JL_NOTSAFEPOINT;
557 : : void gc_time_big_end(void) JL_NOTSAFEPOINT;
558 : :
559 : : void gc_time_mallocd_array_start(void) JL_NOTSAFEPOINT;
560 : : void gc_time_count_mallocd_array(int bits) JL_NOTSAFEPOINT;
561 : : void gc_time_mallocd_array_end(void) JL_NOTSAFEPOINT;
562 : :
563 : : void gc_time_mark_pause(int64_t t0, int64_t scanned_bytes,
564 : : int64_t perm_scanned_bytes);
565 : : void gc_time_sweep_pause(uint64_t gc_end_t, int64_t actual_allocd,
566 : : int64_t live_bytes, int64_t estimate_freed,
567 : : int sweep_full);
568 : : void gc_time_summary(int sweep_full, uint64_t start, uint64_t end,
569 : : uint64_t freed, uint64_t live, uint64_t interval,
570 : : uint64_t pause, uint64_t ttsp, uint64_t mark,
571 : : uint64_t sweep);
572 : : #else
573 : : #define gc_time_pool_start()
574 : 432737000 : STATIC_INLINE void gc_time_count_page(int freedall, int pg_skpd) JL_NOTSAFEPOINT
575 : : {
576 : : (void)freedall;
577 : : (void)pg_skpd;
578 : 432737000 : }
579 : : #define gc_time_pool_end(sweep_full) (void)(sweep_full)
580 : : #define gc_time_sysimg_end(t0) (void)(t0)
581 : : #define gc_time_big_start()
582 : 10888500 : STATIC_INLINE void gc_time_count_big(int old_bits, int bits) JL_NOTSAFEPOINT
583 : : {
584 : : (void)old_bits;
585 : : (void)bits;
586 : 10888500 : }
587 : : #define gc_time_big_end()
588 : : #define gc_time_mallocd_array_start()
589 : 919307000 : STATIC_INLINE void gc_time_count_mallocd_array(int bits) JL_NOTSAFEPOINT
590 : : {
591 : : (void)bits;
592 : 919307000 : }
593 : : #define gc_time_mallocd_array_end()
594 : : #define gc_time_mark_pause(t0, scanned_bytes, perm_scanned_bytes)
595 : : #define gc_time_sweep_pause(gc_end_t, actual_allocd, live_bytes, \
596 : : estimate_freed, sweep_full)
597 : : #define gc_time_summary(sweep_full, start, end, freed, live, \
598 : : interval, pause, ttsp, mark, sweep)
599 : : #endif
600 : :
601 : : #ifdef MEMFENCE
602 : : void gc_verify_tags(void);
603 : : #else
604 : 14024 : static inline void gc_verify_tags(void)
605 : : {
606 : 14024 : }
607 : : #endif
608 : :
609 : :
610 : : #ifdef GC_VERIFY
611 : : extern jl_value_t *lostval;
612 : : void gc_verify(jl_ptls_t ptls);
613 : : void add_lostval_parent(jl_value_t *parent);
614 : : #define verify_val(v) do { \
615 : : if (lostval == (jl_value_t*)(v) && (v) != 0) { \
616 : : jl_printf(JL_STDOUT, \
617 : : "Found lostval %p at %s:%d oftype: ", \
618 : : (void*)(lostval), __FILE__, __LINE__); \
619 : : jl_static_show(JL_STDOUT, jl_typeof(v)); \
620 : : jl_printf(JL_STDOUT, "\n"); \
621 : : } \
622 : : } while(0);
623 : :
624 : : #define verify_parent(ty, obj, slot, args...) do { \
625 : : if (gc_ptr_clear_tag(*(void**)(slot), 3) == (void*)lostval && \
626 : : (jl_value_t*)(obj) != lostval) { \
627 : : jl_printf(JL_STDOUT, "Found parent %p %p at %s:%d\n", \
628 : : (void*)(ty), (void*)(obj), __FILE__, __LINE__); \
629 : : jl_printf(JL_STDOUT, "\tloc %p : ", (void*)(slot)); \
630 : : jl_printf(JL_STDOUT, args); \
631 : : jl_printf(JL_STDOUT, "\n"); \
632 : : jl_printf(JL_STDOUT, "\ttype: "); \
633 : : jl_static_show(JL_STDOUT, jl_typeof(obj)); \
634 : : jl_printf(JL_STDOUT, "\n"); \
635 : : add_lostval_parent((jl_value_t*)(obj)); \
636 : : } \
637 : : } while(0);
638 : :
639 : : #define verify_parent1(ty,obj,slot,arg1) verify_parent(ty,obj,slot,arg1)
640 : : #define verify_parent2(ty,obj,slot,arg1,arg2) verify_parent(ty,obj,slot,arg1,arg2)
641 : : extern int gc_verifying;
642 : : #else
643 : : #define gc_verify(ptls)
644 : : #define verify_val(v)
645 : : #define verify_parent1(ty,obj,slot,arg1) do {} while (0)
646 : : #define verify_parent2(ty,obj,slot,arg1,arg2) do {} while (0)
647 : : #define gc_verifying (0)
648 : : #endif
649 : : int gc_slot_to_fieldidx(void *_obj, void *slot);
650 : : int gc_slot_to_arrayidx(void *_obj, void *begin);
651 : : NOINLINE void gc_mark_loop_unwind(jl_ptls_t ptls, jl_gc_mark_sp_t sp, int pc_offset);
652 : :
653 : : #ifdef GC_DEBUG_ENV
654 : : JL_DLLEXPORT extern jl_gc_debug_env_t jl_gc_debug_env;
655 : : #define gc_sweep_always_full jl_gc_debug_env.always_full
656 : : int jl_gc_debug_check_other(void);
657 : : int gc_debug_check_pool(void);
658 : : void jl_gc_debug_print(void);
659 : : void gc_scrub_record_task(jl_task_t *ta) JL_NOTSAFEPOINT;
660 : : void gc_scrub(void);
661 : : #else
662 : : #define gc_sweep_always_full 0
663 :14829900000 : static inline int jl_gc_debug_check_other(void)
664 : : {
665 :14829900000 : return 0;
666 : : }
667 : : static inline int gc_debug_check_pool(void)
668 : : {
669 : : return 0;
670 : : }
671 : 13380 : static inline void jl_gc_debug_print(void)
672 : : {
673 : 13380 : }
674 : 1231860 : static inline void gc_scrub_record_task(jl_task_t *ta) JL_NOTSAFEPOINT
675 : : {
676 : : (void)ta;
677 : 1231860 : }
678 : 14024 : static inline void gc_scrub(void)
679 : : {
680 : 14024 : }
681 : : #endif
682 : :
683 : : #ifdef OBJPROFILE
684 : : void objprofile_count(void *ty, int old, int sz) JL_NOTSAFEPOINT;
685 : : void objprofile_printall(void);
686 : : void objprofile_reset(void);
687 : : #else
688 : 2129970000 : static inline void objprofile_count(void *ty, int old, int sz) JL_NOTSAFEPOINT
689 : : {
690 : 2129970000 : }
691 : :
692 : 14024 : static inline void objprofile_printall(void)
693 : : {
694 : 14024 : }
695 : :
696 : 14024 : static inline void objprofile_reset(void)
697 : : {
698 : 14024 : }
699 : : #endif
700 : :
701 : : #ifdef MEMPROFILE
702 : : void gc_stats_all_pool(void);
703 : : void gc_stats_big_obj(void);
704 : : #else
705 : : #define gc_stats_all_pool()
706 : : #define gc_stats_big_obj()
707 : : #endif
708 : :
709 : : // For debugging
710 : : void gc_count_pool(void);
711 : :
712 : : size_t jl_array_nbytes(jl_array_t *a) JL_NOTSAFEPOINT;
713 : :
714 : : JL_DLLEXPORT void jl_enable_gc_logging(int enable);
715 : : void _report_gc_finished(uint64_t pause, uint64_t freed, int full, int recollect) JL_NOTSAFEPOINT;
716 : :
717 : : #ifdef __cplusplus
718 : : }
719 : : #endif
720 : :
721 : : #endif
|