LCOV - code coverage report
Current view: top level - src - gc.h (source / functions) Hit Total Coverage
Test: [test only] commit 0f242327d2cc9bd130497f44b6350c924185606a Lines: 96 97 99.0 %
Date: 2022-07-16 23:42:53 Functions: 28 28 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 8 10 80.0 %

           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

Generated by: LCOV version 1.14