LCOV - code coverage report
Current view: top level - src - staticdata.c (source / functions) Hit Total Coverage
Test: [test only] commit 0f242327d2cc9bd130497f44b6350c924185606a Lines: 1218 1343 90.7 %
Date: 2022-07-16 23:42:53 Functions: 54 60 90.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 468 638 73.4 %

           Branch data     Line data    Source code
       1                 :            : // This file is a part of Julia. License is MIT: https://julialang.org/license
       2                 :            : 
       3                 :            : /*
       4                 :            :   saving and restoring system images
       5                 :            : 
       6                 :            :   This performs serialization and deserialization of in-memory data. The dump.c file is similar, but has less complete coverage:
       7                 :            :   dump.c has no knowledge of native code (and simply discards it), whereas this supports native code caching in .o files.
       8                 :            :   Duplication is avoided by elevating the .o-serialized versions of global variables and native-compiled functions to become
       9                 :            :   the authoritative source for such entities in the system image, with references to these objects appropriately inserted into
      10                 :            :   the (de)serialized version of Julia's internal data. This makes deserialization simple and fast: we only need to deal with
      11                 :            :   pointer relocation, registering with the garbage collector, and making note of special internal types. During serialization,
      12                 :            :   we also need to pay special attention to things like builtin functions, C-implemented types (those in jltypes.c), the metadata
      13                 :            :   for documentation, optimal layouts, integration with native system image generation, and preparing other preprocessing
      14                 :            :   directives.
      15                 :            : 
      16                 :            :   dump.c has capabilities missing from this serializer, most notably the ability to handle external references. This is not needed
      17                 :            :   for system images as they are self-contained. However, it would be needed to support incremental compilation of packages.
      18                 :            : 
      19                 :            :   During serialization, the flow has several steps:
      20                 :            : 
      21                 :            :   - step 1 inserts relevant items into `backref_table`, an `obj` => `id::Int` mapping. `id` is assigned by
      22                 :            :     order of insertion. This is effectively a recursive traversal, singling out items like pointers and symbols
      23                 :            :     that need restoration when the system image is loaded. This stage is implemented by `jl_serialize_value`
      24                 :            :     and its callees; while it would be simplest to use recursion, this risks stack overflow, so recursion is mimicked
      25                 :            :     using a work-queue managed by `jl_serialize_reachable`.
      26                 :            : 
      27                 :            :     It's worth emphasizing that despite the name `jl_serialize_value`, the only goal of this stage is to
      28                 :            :     insert objects into `backref_table`. The entire system gets inserted, either directly or indirectly via
      29                 :            :     fields of other objects. Objects requiring pointer relocation or gc registration must be inserted directly.
      30                 :            :     In later stages, such objects get referenced by their `id`.
      31                 :            : 
      32                 :            :   - step 2 (the biggest of four steps) takes all items in `backref_table` and actually serializes them ordered
      33                 :            :     by `id`. The system is serialized into several distinct streams (see `jl_serializer_state`), a "main stream"
      34                 :            :     (the `s` field) as well as parallel streams for writing specific categories of additional internal data (e.g.,
      35                 :            :     global data invisible to codegen, as well as deserialization "touch-up" tables, see below). These different streams
      36                 :            :     will be concatenated in later steps. Certain key items (e.g., builtin types & functions associated with `INSERT_TAG`
      37                 :            :     below, integers smaller than 512) get serialized via a hard-coded tag table.
      38                 :            : 
      39                 :            :     Serialization builds "touch up" tables used during deserialization. Pointers and items requiring gc
      40                 :            :     registration get encoded as `(location, target)` pairs in `relocs_list` and `gctags_list`, respectively.
      41                 :            :     `location` is the site that needs updating (e.g., the address of a pointer referencing an object), and is
      42                 :            :     set to `position(s)`, the offset of the object from the beginning of the deserialized blob.
      43                 :            :     `target` is a bitfield-encoded index into lists of different categories of data (e.g., mutable data, constant data,
      44                 :            :     symbols, functions, etc.) to which the pointer at `location` refers. The different lists and their bitfield flags
      45                 :            :     are given by the `RefTags` enum: if `t` is the category tag (one of the `RefTags` enums) and `i` is the index into
      46                 :            :     one of the corresponding categorical list, then `index = t << RELOC_TAG_OFFSET + i`. The simplest source for the
      47                 :            :     details of this encoding can be found in the pair of functions `get_reloc_for_item` and `get_item_for_reloc`.
      48                 :            : 
      49                 :            :     Most of step 2 is handled by `jl_write_values`, followed by special handling of the dedicated parallel streams.
      50                 :            : 
      51                 :            :   - step 3 combines the different sections (fields of `jl_serializer_state`) into one
      52                 :            : 
      53                 :            :   - step 4 writes the values of the hard-coded tagged items and `reinit_list`/`ccallable_list`
      54                 :            : 
      55                 :            : The tables written to the serializer stream make deserialization fairly straightforward. Much of the "real work" is
      56                 :            : done by `get_item_for_reloc`.
      57                 :            : 
      58                 :            : */
      59                 :            : #include <stdlib.h>
      60                 :            : #include <string.h>
      61                 :            : #include <stdio.h> // printf
      62                 :            : 
      63                 :            : #include "julia.h"
      64                 :            : #include "julia_internal.h"
      65                 :            : #include "builtin_proto.h"
      66                 :            : #include "processor.h"
      67                 :            : #include "serialize.h"
      68                 :            : 
      69                 :            : #ifndef _OS_WINDOWS_
      70                 :            : #include <dlfcn.h>
      71                 :            : #endif
      72                 :            : 
      73                 :            : #include "valgrind.h"
      74                 :            : #include "julia_assert.h"
      75                 :            : 
      76                 :            : #ifdef __cplusplus
      77                 :            : extern "C" {
      78                 :            : #endif
      79                 :            : 
      80                 :            : // TODO: put WeakRefs on the weak_refs list during deserialization
      81                 :            : // TODO: handle finalizers
      82                 :            : 
      83                 :            : #define NUM_TAGS    155
      84                 :            : 
      85                 :            : // An array of references that need to be restored from the sysimg
      86                 :            : // This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C.
      87                 :        569 : jl_value_t **const*const get_tags(void) {
      88                 :            :     // Make sure to keep an extra slot at the end to sentinel length
      89                 :            :     static void * _tags[NUM_TAGS] = {NULL};
      90                 :            : 
      91                 :            :     // Lazyily-initialize this list
      92         [ +  + ]:        569 :     if (_tags[0] == NULL) {
      93                 :        567 :         unsigned int i = 0;
      94                 :            : #define INSERT_TAG(sym) _tags[i++] = &(sym)
      95                 :            :         // builtin types
      96                 :        567 :         INSERT_TAG(jl_any_type);
      97                 :        567 :         INSERT_TAG(jl_symbol_type);
      98                 :        567 :         INSERT_TAG(jl_ssavalue_type);
      99                 :        567 :         INSERT_TAG(jl_datatype_type);
     100                 :        567 :         INSERT_TAG(jl_slotnumber_type);
     101                 :        567 :         INSERT_TAG(jl_simplevector_type);
     102                 :        567 :         INSERT_TAG(jl_array_type);
     103                 :        567 :         INSERT_TAG(jl_typedslot_type);
     104                 :        567 :         INSERT_TAG(jl_expr_type);
     105                 :        567 :         INSERT_TAG(jl_globalref_type);
     106                 :        567 :         INSERT_TAG(jl_string_type);
     107                 :        567 :         INSERT_TAG(jl_module_type);
     108                 :        567 :         INSERT_TAG(jl_tvar_type);
     109                 :        567 :         INSERT_TAG(jl_method_instance_type);
     110                 :        567 :         INSERT_TAG(jl_method_type);
     111                 :        567 :         INSERT_TAG(jl_code_instance_type);
     112                 :        567 :         INSERT_TAG(jl_linenumbernode_type);
     113                 :        567 :         INSERT_TAG(jl_lineinfonode_type);
     114                 :        567 :         INSERT_TAG(jl_gotonode_type);
     115                 :        567 :         INSERT_TAG(jl_quotenode_type);
     116                 :        567 :         INSERT_TAG(jl_gotoifnot_type);
     117                 :        567 :         INSERT_TAG(jl_argument_type);
     118                 :        567 :         INSERT_TAG(jl_returnnode_type);
     119                 :        567 :         INSERT_TAG(jl_const_type);
     120                 :        567 :         INSERT_TAG(jl_partial_struct_type);
     121                 :        567 :         INSERT_TAG(jl_partial_opaque_type);
     122                 :        567 :         INSERT_TAG(jl_interconditional_type);
     123                 :        567 :         INSERT_TAG(jl_method_match_type);
     124                 :        567 :         INSERT_TAG(jl_pinode_type);
     125                 :        567 :         INSERT_TAG(jl_phinode_type);
     126                 :        567 :         INSERT_TAG(jl_phicnode_type);
     127                 :        567 :         INSERT_TAG(jl_upsilonnode_type);
     128                 :        567 :         INSERT_TAG(jl_type_type);
     129                 :        567 :         INSERT_TAG(jl_bottom_type);
     130                 :        567 :         INSERT_TAG(jl_ref_type);
     131                 :        567 :         INSERT_TAG(jl_pointer_type);
     132                 :        567 :         INSERT_TAG(jl_llvmpointer_type);
     133                 :        567 :         INSERT_TAG(jl_vararg_type);
     134                 :        567 :         INSERT_TAG(jl_abstractarray_type);
     135                 :        567 :         INSERT_TAG(jl_densearray_type);
     136                 :        567 :         INSERT_TAG(jl_nothing_type);
     137                 :        567 :         INSERT_TAG(jl_function_type);
     138                 :        567 :         INSERT_TAG(jl_typeofbottom_type);
     139                 :        567 :         INSERT_TAG(jl_unionall_type);
     140                 :        567 :         INSERT_TAG(jl_typename_type);
     141                 :        567 :         INSERT_TAG(jl_builtin_type);
     142                 :        567 :         INSERT_TAG(jl_code_info_type);
     143                 :        567 :         INSERT_TAG(jl_opaque_closure_type);
     144                 :        567 :         INSERT_TAG(jl_task_type);
     145                 :        567 :         INSERT_TAG(jl_uniontype_type);
     146                 :        567 :         INSERT_TAG(jl_abstractstring_type);
     147                 :        567 :         INSERT_TAG(jl_array_any_type);
     148                 :        567 :         INSERT_TAG(jl_intrinsic_type);
     149                 :        567 :         INSERT_TAG(jl_abstractslot_type);
     150                 :        567 :         INSERT_TAG(jl_methtable_type);
     151                 :        567 :         INSERT_TAG(jl_typemap_level_type);
     152                 :        567 :         INSERT_TAG(jl_typemap_entry_type);
     153                 :        567 :         INSERT_TAG(jl_voidpointer_type);
     154                 :        567 :         INSERT_TAG(jl_uint8pointer_type);
     155                 :        567 :         INSERT_TAG(jl_newvarnode_type);
     156                 :        567 :         INSERT_TAG(jl_anytuple_type_type);
     157                 :        567 :         INSERT_TAG(jl_anytuple_type);
     158                 :        567 :         INSERT_TAG(jl_namedtuple_type);
     159                 :        567 :         INSERT_TAG(jl_emptytuple_type);
     160                 :        567 :         INSERT_TAG(jl_array_symbol_type);
     161                 :        567 :         INSERT_TAG(jl_array_uint8_type);
     162                 :        567 :         INSERT_TAG(jl_array_int32_type);
     163                 :        567 :         INSERT_TAG(jl_array_uint64_type);
     164                 :        567 :         INSERT_TAG(jl_int32_type);
     165                 :        567 :         INSERT_TAG(jl_int64_type);
     166                 :        567 :         INSERT_TAG(jl_bool_type);
     167                 :        567 :         INSERT_TAG(jl_uint8_type);
     168                 :        567 :         INSERT_TAG(jl_uint16_type);
     169                 :        567 :         INSERT_TAG(jl_uint32_type);
     170                 :        567 :         INSERT_TAG(jl_uint64_type);
     171                 :        567 :         INSERT_TAG(jl_char_type);
     172                 :        567 :         INSERT_TAG(jl_weakref_type);
     173                 :        567 :         INSERT_TAG(jl_int8_type);
     174                 :        567 :         INSERT_TAG(jl_int16_type);
     175                 :        567 :         INSERT_TAG(jl_float16_type);
     176                 :        567 :         INSERT_TAG(jl_float32_type);
     177                 :        567 :         INSERT_TAG(jl_float64_type);
     178                 :        567 :         INSERT_TAG(jl_floatingpoint_type);
     179                 :        567 :         INSERT_TAG(jl_number_type);
     180                 :        567 :         INSERT_TAG(jl_signed_type);
     181                 :        567 :         INSERT_TAG(jl_pair_type);
     182                 :            : 
     183                 :            :         // special typenames
     184                 :        567 :         INSERT_TAG(jl_tuple_typename);
     185                 :        567 :         INSERT_TAG(jl_pointer_typename);
     186                 :        567 :         INSERT_TAG(jl_llvmpointer_typename);
     187                 :        567 :         INSERT_TAG(jl_array_typename);
     188                 :        567 :         INSERT_TAG(jl_type_typename);
     189                 :        567 :         INSERT_TAG(jl_namedtuple_typename);
     190                 :        567 :         INSERT_TAG(jl_vecelement_typename);
     191                 :        567 :         INSERT_TAG(jl_opaque_closure_typename);
     192                 :            : 
     193                 :            :         // special exceptions
     194                 :        567 :         INSERT_TAG(jl_errorexception_type);
     195                 :        567 :         INSERT_TAG(jl_argumenterror_type);
     196                 :        567 :         INSERT_TAG(jl_typeerror_type);
     197                 :        567 :         INSERT_TAG(jl_methoderror_type);
     198                 :        567 :         INSERT_TAG(jl_loaderror_type);
     199                 :        567 :         INSERT_TAG(jl_initerror_type);
     200                 :        567 :         INSERT_TAG(jl_undefvarerror_type);
     201                 :        567 :         INSERT_TAG(jl_stackovf_exception);
     202                 :        567 :         INSERT_TAG(jl_diverror_exception);
     203                 :        567 :         INSERT_TAG(jl_interrupt_exception);
     204                 :        567 :         INSERT_TAG(jl_boundserror_type);
     205                 :        567 :         INSERT_TAG(jl_memory_exception);
     206                 :        567 :         INSERT_TAG(jl_undefref_exception);
     207                 :        567 :         INSERT_TAG(jl_readonlymemory_exception);
     208                 :        567 :         INSERT_TAG(jl_atomicerror_type);
     209                 :            : 
     210                 :            :         // other special values
     211                 :        567 :         INSERT_TAG(jl_emptysvec);
     212                 :        567 :         INSERT_TAG(jl_emptytuple);
     213                 :        567 :         INSERT_TAG(jl_false);
     214                 :        567 :         INSERT_TAG(jl_true);
     215                 :        567 :         INSERT_TAG(jl_an_empty_string);
     216                 :        567 :         INSERT_TAG(jl_an_empty_vec_any);
     217                 :        567 :         INSERT_TAG(jl_module_init_order);
     218                 :        567 :         INSERT_TAG(jl_core_module);
     219                 :        567 :         INSERT_TAG(jl_base_module);
     220                 :        567 :         INSERT_TAG(jl_main_module);
     221                 :        567 :         INSERT_TAG(jl_top_module);
     222                 :        567 :         INSERT_TAG(jl_typeinf_func);
     223                 :        567 :         INSERT_TAG(jl_type_type_mt);
     224                 :        567 :         INSERT_TAG(jl_nonfunction_mt);
     225                 :            : 
     226                 :            :         // some Core.Builtin Functions that we want to be able to reference:
     227                 :        567 :         INSERT_TAG(jl_builtin_throw);
     228                 :        567 :         INSERT_TAG(jl_builtin_is);
     229                 :        567 :         INSERT_TAG(jl_builtin_typeof);
     230                 :        567 :         INSERT_TAG(jl_builtin_sizeof);
     231                 :        567 :         INSERT_TAG(jl_builtin_issubtype);
     232                 :        567 :         INSERT_TAG(jl_builtin_isa);
     233                 :        567 :         INSERT_TAG(jl_builtin_typeassert);
     234                 :        567 :         INSERT_TAG(jl_builtin__apply_iterate);
     235                 :        567 :         INSERT_TAG(jl_builtin_isdefined);
     236                 :        567 :         INSERT_TAG(jl_builtin_nfields);
     237                 :        567 :         INSERT_TAG(jl_builtin_tuple);
     238                 :        567 :         INSERT_TAG(jl_builtin_svec);
     239                 :        567 :         INSERT_TAG(jl_builtin_getfield);
     240                 :        567 :         INSERT_TAG(jl_builtin_setfield);
     241                 :        567 :         INSERT_TAG(jl_builtin_swapfield);
     242                 :        567 :         INSERT_TAG(jl_builtin_modifyfield);
     243                 :        567 :         INSERT_TAG(jl_builtin_replacefield);
     244                 :        567 :         INSERT_TAG(jl_builtin_fieldtype);
     245                 :        567 :         INSERT_TAG(jl_builtin_arrayref);
     246                 :        567 :         INSERT_TAG(jl_builtin_const_arrayref);
     247                 :        567 :         INSERT_TAG(jl_builtin_arrayset);
     248                 :        567 :         INSERT_TAG(jl_builtin_arraysize);
     249                 :        567 :         INSERT_TAG(jl_builtin_apply_type);
     250                 :        567 :         INSERT_TAG(jl_builtin_applicable);
     251                 :        567 :         INSERT_TAG(jl_builtin_invoke);
     252                 :        567 :         INSERT_TAG(jl_builtin__expr);
     253                 :        567 :         INSERT_TAG(jl_builtin_ifelse);
     254                 :        567 :         INSERT_TAG(jl_builtin__typebody);
     255                 :        567 :         INSERT_TAG(jl_builtin_donotdelete);
     256                 :        567 :         INSERT_TAG(jl_builtin_getglobal);
     257                 :        567 :         INSERT_TAG(jl_builtin_setglobal);
     258                 :            :         // n.b. must update NUM_TAGS when you add something here
     259                 :            : 
     260                 :            :         // All optional tags must be placed at the end, so that we
     261                 :            :         // don't accidentally have a `NULL` in the middle
     262                 :            : #ifdef SEGV_EXCEPTION
     263                 :            :         INSERT_TAG(jl_segv_exception);
     264                 :            : #endif
     265                 :            : #undef INSERT_TAG
     266   [ +  -  +  - ]:        567 :         assert(i >= (NUM_TAGS-2) && i < NUM_TAGS);
     267                 :            :     }
     268                 :        569 :     return (jl_value_t**const*const) _tags;
     269                 :            : }
     270                 :            : 
     271                 :            : // hash of definitions for predefined tagged object
     272                 :            : static htable_t symbol_table;
     273                 :            : static uintptr_t nsym_tag;
     274                 :            : // array of definitions for the predefined tagged object types
     275                 :            : // (reverse of symbol_table)
     276                 :            : static arraylist_t deser_sym;
     277                 :            : 
     278                 :            : // table of all objects that are serialized
     279                 :            : static htable_t backref_table;
     280                 :            : static int backref_table_numel;
     281                 :            : static arraylist_t layout_table;     // cache of `position(s)` for each `id` in `backref_table`
     282                 :            : static arraylist_t object_worklist;  // used to mimic recursion by jl_serialize_reachable
     283                 :            : 
     284                 :            : // Both `reinit_list` and `ccallable_list` are lists of (size_t pos, code) entries
     285                 :            : // for the serializer to mark values in need of rework during deserialization
     286                 :            : // codes:
     287                 :            : //   1: typename   (reinit_list)
     288                 :            : //   2: module     (reinit_list)
     289                 :            : //   3: method     (ccallable_list)
     290                 :            : static arraylist_t reinit_list;
     291                 :            : 
     292                 :            : // @ccallable entry points to install
     293                 :            : static arraylist_t ccallable_list;
     294                 :            : 
     295                 :            : // hash of definitions for predefined function pointers
     296                 :            : static htable_t fptr_to_id;
     297                 :            : void *native_functions;   // opaque jl_native_code_desc_t blob used for fetching data from LLVM
     298                 :            : 
     299                 :            : // table of struct field addresses to rewrite during saving
     300                 :            : static htable_t field_replace;
     301                 :            : 
     302                 :            : // array of definitions for the predefined function pointers
     303                 :            : // (reverse of fptr_to_id)
     304                 :            : // This is a manually constructed dual of the fvars array, which would be produced by codegen for Julia code, for C.
     305                 :            : static const jl_fptr_args_t id_to_fptrs[] = {
     306                 :            :     &jl_f_throw, &jl_f_is, &jl_f_typeof, &jl_f_issubtype, &jl_f_isa,
     307                 :            :     &jl_f_typeassert, &jl_f__apply_iterate, &jl_f__apply_pure,
     308                 :            :     &jl_f__call_latest, &jl_f__call_in_world, &jl_f__call_in_world_total, &jl_f_isdefined,
     309                 :            :     &jl_f_tuple, &jl_f_svec, &jl_f_intrinsic_call, &jl_f_invoke_kwsorter,
     310                 :            :     &jl_f_getfield, &jl_f_setfield, &jl_f_swapfield, &jl_f_modifyfield,
     311                 :            :     &jl_f_replacefield, &jl_f_fieldtype, &jl_f_nfields,
     312                 :            :     &jl_f_arrayref, &jl_f_const_arrayref, &jl_f_arrayset, &jl_f_arraysize, &jl_f_apply_type,
     313                 :            :     &jl_f_applicable, &jl_f_invoke, &jl_f_sizeof, &jl_f__expr, &jl_f__typevar,
     314                 :            :     &jl_f_ifelse, &jl_f__structtype, &jl_f__abstracttype, &jl_f__primitivetype,
     315                 :            :     &jl_f__typebody, &jl_f__setsuper, &jl_f__equiv_typedef, &jl_f_get_binding_type,
     316                 :            :     &jl_f_set_binding_type, &jl_f_opaque_closure_call, &jl_f_donotdelete,
     317                 :            :     &jl_f_getglobal, &jl_f_setglobal, &jl_f_finalizer,
     318                 :            :     NULL };
     319                 :            : 
     320                 :            : typedef struct {
     321                 :            :     ios_t *s;                   // the main stream
     322                 :            :     ios_t *const_data;          // codegen-invisible internal data (e.g., datatype layouts, list-like typename fields, foreign types, internal arrays)
     323                 :            :     ios_t *symbols;             // names (char*) of symbols (some may be referenced by pointer in generated code)
     324                 :            :     ios_t *relocs;              // for (de)serializing relocs_list and gctags_list
     325                 :            :     ios_t *gvar_record;         // serialized array mapping gvid => spos
     326                 :            :     ios_t *fptr_record;         // serialized array mapping fptrid => spos
     327                 :            :     arraylist_t relocs_list;    // a list of (location, target) pairs, see description at top
     328                 :            :     arraylist_t gctags_list;    //      "
     329                 :            :     jl_ptls_t ptls;
     330                 :            : } jl_serializer_state;
     331                 :            : 
     332                 :            : static jl_value_t *jl_idtable_type = NULL;
     333                 :            : static jl_typename_t *jl_idtable_typename = NULL;
     334                 :            : static jl_value_t *jl_bigint_type = NULL;
     335                 :            : static int gmp_limb_size = 0;
     336                 :            : 
     337                 :            : static jl_sym_t *jl_docmeta_sym = NULL;
     338                 :            : 
     339                 :            : // Tags of category `t` are located at offsets `t << RELOC_TAG_OFFSET`
     340                 :            : // Consequently there is room for 2^RELOC_TAG_OFFSET pointers, etc
     341                 :            : enum RefTags {
     342                 :            :     DataRef,           // mutable data
     343                 :            :     ConstDataRef,      // constant data (e.g., layouts)
     344                 :            :     TagRef,            // items serialized via their tags
     345                 :            :     SymbolRef,         // symbols
     346                 :            :     BindingRef,        // module bindings
     347                 :            :     FunctionRef,       // generic functions
     348                 :            :     BuiltinFunctionRef // builtin functions
     349                 :            : };
     350                 :            : 
     351                 :            : // calling conventions for internal entry points.
     352                 :            : // this is used to set the method-instance->invoke field
     353                 :            : typedef enum {
     354                 :            :     JL_API_NULL,
     355                 :            :     JL_API_BOXED,
     356                 :            :     JL_API_CONST,
     357                 :            :     JL_API_WITH_PARAMETERS,
     358                 :            :     JL_API_INTERPRETED,
     359                 :            :     JL_API_BUILTIN,
     360                 :            :     JL_API_MAX
     361                 :            : } jl_callingconv_t;
     362                 :            : 
     363                 :            : 
     364                 :            : // this supports up to 8 RefTags, 512MB of pointer data, and 4/2 (64/32-bit) GB of constant data.
     365                 :            : // if a larger size is required, will need to add support for writing larger relocations in many cases below
     366                 :            : #define RELOC_TAG_OFFSET 29
     367                 :            : 
     368                 :            : // --- Static Compile ---
     369                 :            : 
     370                 :            : static void *jl_sysimg_handle = NULL;
     371                 :            : static uint64_t sysimage_base = 0;
     372                 :            : static uintptr_t *sysimg_gvars_base = NULL;
     373                 :            : static const int32_t *sysimg_gvars_offsets = NULL;
     374                 :            : static jl_sysimg_fptrs_t sysimg_fptrs;
     375                 :            : 
     376                 :    8628910 : static inline uintptr_t *sysimg_gvars(uintptr_t *base, size_t idx)
     377                 :            : {
     378                 :    8628910 :     return base + sysimg_gvars_offsets[idx] / sizeof(base[0]);
     379                 :            : }
     380                 :            : 
     381                 :        169 : JL_DLLEXPORT int jl_running_on_valgrind(void)
     382                 :            : {
     383                 :        169 :     return RUNNING_ON_VALGRIND;
     384                 :            : }
     385                 :            : 
     386                 :        560 : static void jl_load_sysimg_so(void)
     387                 :            : {
     388   [ +  +  -  + ]:        560 :     int imaging_mode = jl_generating_output() && !jl_options.incremental;
     389                 :            :     // in --build mode only use sysimg data, not precompiled native code
     390   [ +  -  +  + ]:       1118 :     if (!imaging_mode && jl_options.use_sysimage_native_code==JL_OPTIONS_USE_SYSIMAGE_NATIVE_CODE_YES) {
     391                 :        558 :         jl_dlsym(jl_sysimg_handle, "jl_sysimg_gvars_base", (void **)&sysimg_gvars_base, 1);
     392                 :        558 :         jl_dlsym(jl_sysimg_handle, "jl_sysimg_gvars_offsets", (void **)&sysimg_gvars_offsets, 1);
     393                 :        558 :         sysimg_gvars_offsets += 1;
     394         [ -  + ]:        558 :         assert(sysimg_fptrs.base);
     395                 :            : 
     396                 :            :         void *pgcstack_func_slot;
     397                 :        558 :         jl_dlsym(jl_sysimg_handle, "jl_pgcstack_func_slot", &pgcstack_func_slot, 1);
     398                 :            :         void *pgcstack_key_slot;
     399                 :        558 :         jl_dlsym(jl_sysimg_handle, "jl_pgcstack_key_slot", &pgcstack_key_slot, 1);
     400                 :        558 :         jl_pgcstack_getkey((jl_get_pgcstack_func**)pgcstack_func_slot, (jl_pgcstack_key_t*)pgcstack_key_slot);
     401                 :            : 
     402                 :            :         size_t *tls_offset_idx;
     403                 :        558 :         jl_dlsym(jl_sysimg_handle, "jl_tls_offset", (void **)&tls_offset_idx, 1);
     404         [ +  - ]:        558 :         *tls_offset_idx = (uintptr_t)(jl_tls_offset == -1 ? 0 : jl_tls_offset);
     405                 :            : 
     406                 :            : #ifdef _OS_WINDOWS_
     407                 :            :         sysimage_base = (intptr_t)jl_sysimg_handle;
     408                 :            : #else
     409                 :            :         Dl_info dlinfo;
     410         [ +  - ]:        558 :         if (dladdr((void*)sysimg_gvars_base, &dlinfo) != 0) {
     411                 :        558 :             sysimage_base = (intptr_t)dlinfo.dli_fbase;
     412                 :            :         }
     413                 :            :         else {
     414                 :          0 :             sysimage_base = 0;
     415                 :            :         }
     416                 :            : #endif
     417                 :            :     }
     418                 :            :     else {
     419                 :          2 :         memset(&sysimg_fptrs, 0, sizeof(sysimg_fptrs));
     420                 :            :     }
     421                 :            :     const char *sysimg_data;
     422                 :        560 :     jl_dlsym(jl_sysimg_handle, "jl_system_image_data", (void **)&sysimg_data, 1);
     423                 :            :     size_t *plen;
     424                 :        560 :     jl_dlsym(jl_sysimg_handle, "jl_system_image_size", (void **)&plen, 1);
     425                 :        560 :     jl_restore_system_image_data(sysimg_data, *plen);
     426                 :        559 : }
     427                 :            : 
     428                 :            : 
     429                 :            : // --- serializer ---
     430                 :            : 
     431                 :     112138 : static uintptr_t jl_fptr_id(void *fptr)
     432                 :            : {
     433                 :     112138 :     void **pbp = ptrhash_bp(&fptr_to_id, fptr);
     434   [ +  +  -  + ]:     112138 :     if (*pbp == HT_NOTFOUND || fptr == NULL)
     435                 :     111997 :         return 0;
     436                 :            :     else
     437                 :        141 :         return *(uintptr_t*)pbp;
     438                 :            : }
     439                 :            : 
     440                 :            : #define jl_serialize_value(s, v) jl_serialize_value_(s,(jl_value_t*)(v),1)
     441                 :            : static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int recursive);
     442                 :            : 
     443                 :            : 
     444                 :        270 : static void jl_serialize_module(jl_serializer_state *s, jl_module_t *m)
     445                 :            : {
     446                 :        270 :     jl_serialize_value(s, m->name);
     447                 :        270 :     jl_serialize_value(s, m->parent);
     448                 :            :     size_t i;
     449                 :        270 :     void **table = m->bindings.table;
     450         [ +  + ]:     181502 :     for (i = 0; i < m->bindings.size; i += 2) {
     451         [ +  + ]:     181232 :         if (table[i+1] != HT_NOTFOUND) {
     452                 :      70952 :             jl_serialize_value(s, (jl_value_t*)table[i]);
     453                 :      70952 :             jl_binding_t *b = (jl_binding_t*)table[i+1];
     454                 :      70952 :             jl_serialize_value(s, b->name);
     455   [ +  +  +  +  :      70952 :             if (jl_docmeta_sym && b->name == jl_docmeta_sym && jl_options.strip_metadata)
                   -  + ]
     456                 :          0 :                 jl_serialize_value(s, jl_nothing);
     457                 :            :             else
     458                 :      70952 :                 jl_serialize_value(s, jl_atomic_load_relaxed(&b->value));
     459                 :      70952 :             jl_serialize_value(s, jl_atomic_load_relaxed(&b->globalref));
     460                 :      70952 :             jl_serialize_value(s, b->owner);
     461                 :      70952 :             jl_serialize_value(s, jl_atomic_load_relaxed(&b->ty));
     462                 :            :         }
     463                 :            :     }
     464                 :            : 
     465         [ +  + ]:       1078 :     for (i = 0; i < m->usings.len; i++) {
     466                 :        808 :         jl_serialize_value(s, (jl_value_t*)m->usings.items[i]);
     467                 :            :     }
     468                 :        270 : }
     469                 :            : 
     470                 :   11390200 : static jl_value_t *get_replaceable_field(jl_value_t **addr)
     471                 :            : {
     472                 :   11390200 :     jl_value_t *fld = (jl_value_t*)ptrhash_get(&field_replace, addr);
     473         [ +  - ]:   11390200 :     if (fld == HT_NOTFOUND)
     474                 :   11390200 :         return *addr;
     475                 :          0 :     return fld;
     476                 :            : }
     477                 :            : 
     478                 :            : #define NBOX_C 1024
     479                 :            : 
     480                 :   11836400 : static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int recursive)
     481                 :            : {
     482                 :            :     // ignore items that are given a special representation
     483   [ +  +  +  +  :   11836400 :     if (v == NULL || jl_is_symbol(v) || v == jl_nothing) {
                   +  + ]
     484                 :    3565970 :         return;
     485                 :            :     }
     486         [ +  + ]:    8270410 :     else if (jl_typeis(v, jl_task_type)) {
     487         [ +  - ]:          2 :         if (v == (jl_value_t*)s->ptls->root_task) {
     488                 :          2 :             jl_serialize_value(s, ((jl_task_t*)v)->tls);
     489                 :          2 :             return;
     490                 :            :         }
     491                 :            :     }
     492         [ +  + ]:    8270410 :     else if (jl_typeis(v, jl_int64_type)) {
     493                 :      40978 :         int64_t i64 = *(int64_t*)v + NBOX_C / 2;
     494         [ +  + ]:      40978 :         if ((uint64_t)i64 < NBOX_C)
     495                 :      31445 :             return;
     496                 :            :     }
     497         [ +  + ]:    8229430 :     else if (jl_typeis(v, jl_int32_type)) {
     498                 :       1351 :         int32_t i32 = *(int32_t*)v + NBOX_C / 2;
     499         [ +  + ]:       1351 :         if ((uint32_t)i32 < NBOX_C)
     500                 :        920 :             return;
     501                 :            :     }
     502         [ +  + ]:    8228080 :     else if (jl_typeis(v, jl_uint8_type)) {
     503                 :        173 :         return;
     504                 :            :     }
     505                 :    8237870 :     arraylist_push(&object_worklist, (void*)((uintptr_t)v | recursive));
     506                 :            : }
     507                 :            : 
     508                 :    8237870 : static void jl_serialize_value__(jl_serializer_state *s, jl_value_t *v, int recursive)
     509                 :            : {
     510                 :    8237870 :     void **bp = ptrhash_bp(&backref_table, v);
     511         [ +  + ]:    8237870 :     if (*bp != HT_NOTFOUND) {
     512                 :    6237340 :         return;
     513                 :            :     }
     514                 :            : 
     515                 :    2000530 :     size_t item = ++backref_table_numel;
     516         [ -  + ]:    2000530 :     assert(item < ((uintptr_t)1 << RELOC_TAG_OFFSET) && "too many items to serialize");
     517                 :    2000530 :     char *pos = (char*)HT_NOTFOUND + item;
     518                 :    2000530 :     *bp = (void*)pos;
     519                 :            : 
     520                 :            :     // some values have special representations
     521                 :    2000530 :     jl_datatype_t *t = (jl_datatype_t*)jl_typeof(v);
     522                 :    2000530 :     jl_serialize_value(s, t);
     523                 :            : 
     524         [ +  + ]:    2000530 :     if (t->layout->npointers == 0) {
     525                 :            :         // skip it
     526                 :            :     }
     527         [ +  + ]:    1955980 :     else if (jl_is_svec(v)) {
     528         [ +  + ]:     352420 :         if (!recursive)
     529                 :       1185 :             return;
     530                 :     351235 :         size_t i, l = jl_svec_len(v);
     531                 :     351235 :         jl_value_t **data = jl_svec_data(v);
     532         [ +  + ]:    1507880 :         for (i = 0; i < l; i++) {
     533                 :    1156640 :             jl_serialize_value(s, data[i]);
     534                 :            :         }
     535                 :            :     }
     536         [ +  + ]:    1603560 :     else if (jl_is_array(v)) {
     537                 :     398595 :         jl_array_t *ar = (jl_array_t*)v;
     538                 :     398595 :         jl_serialize_value(s, jl_typeof(ar));
     539         [ +  + ]:     398595 :         if (ar->flags.ptrarray) {
     540                 :     216929 :             size_t i, l = jl_array_len(ar);
     541         [ +  + ]:    2241910 :             for (i = 0; i < l; i++) {
     542                 :    2024980 :                 jl_serialize_value(s, jl_array_ptr_ref(ar, i));
     543                 :            :             }
     544                 :            :         }
     545         [ +  + ]:     181666 :         else if (ar->flags.hasptr) {
     546                 :        262 :             const char *data = (const char*)jl_array_data(ar);
     547                 :        262 :             uint16_t elsz = ar->elsize;
     548                 :        262 :             size_t i, l = jl_array_len(ar);
     549                 :        262 :             jl_datatype_t *et = (jl_datatype_t*)jl_tparam0(jl_typeof(ar));
     550                 :        262 :             size_t j, np = et->layout->npointers;
     551         [ +  + ]:       4361 :             for (i = 0; i < l; i++) {
     552         [ +  + ]:      13954 :                 for (j = 0; j < np; j++) {
     553                 :       9855 :                     uint32_t ptr = jl_ptr_offset(et, j);
     554                 :       9855 :                     jl_value_t *fld = ((jl_value_t**)data)[ptr];
     555                 :            :                     JL_GC_PROMISE_ROOTED(fld);
     556                 :       9855 :                     jl_serialize_value(s, fld);
     557                 :            :                 }
     558                 :       4099 :                 data += elsz;
     559                 :            :             }
     560                 :            :         }
     561                 :            :     }
     562         [ +  + ]:    1204960 :     else if (jl_typeis(v, jl_module_type)) {
     563                 :        270 :         jl_serialize_module(s, (jl_module_t*)v);
     564                 :            :     }
     565         [ +  + ]:    1204690 :     else if (jl_is_typename(v)) {
     566                 :      26718 :         jl_typename_t *tn = (jl_typename_t*)v;
     567                 :      26718 :         jl_serialize_value(s, tn->name);
     568                 :      26718 :         jl_serialize_value(s, tn->module);
     569                 :      26718 :         jl_serialize_value(s, tn->names);
     570                 :      26718 :         jl_serialize_value(s, tn->wrapper);
     571                 :      26718 :         jl_serialize_value(s, tn->Typeofwrapper);
     572                 :      26718 :         jl_serialize_value_(s, (jl_value_t*)tn->cache, 0);
     573                 :      26718 :         jl_serialize_value_(s, (jl_value_t*)tn->linearcache, 0);
     574                 :      26718 :         jl_serialize_value(s, tn->mt);
     575                 :      26718 :         jl_serialize_value(s, tn->partial);
     576                 :            :     }
     577         [ +  + ]:    1177980 :     else if (t->layout->nfields > 0) {
     578                 :    1056100 :         char *data = (char*)jl_data_ptr(v);
     579                 :    1056100 :         size_t i, np = t->layout->npointers;
     580         [ +  + ]:    6630980 :         for (i = 0; i < np; i++) {
     581                 :    5574880 :             uint32_t ptr = jl_ptr_offset(t, i);
     582                 :    5574880 :             jl_value_t *fld = get_replaceable_field(&((jl_value_t**)data)[ptr]);
     583                 :    5574880 :             jl_serialize_value(s, fld);
     584                 :            :         }
     585                 :            :     }
     586                 :            : }
     587                 :            : 
     588                 :            : // Do a pre-order traversal of the to-serialize worklist, in the identical order
     589                 :            : // to the calls to jl_serialize_value would occur in a purely recursive
     590                 :            : // implementation, but without potentially running out of stack.
     591                 :          6 : static void jl_serialize_reachable(jl_serializer_state *s)
     592                 :            : {
     593                 :          6 :     size_t i, prevlen = 0;
     594         [ +  + ]:    8237880 :     while (object_worklist.len) {
     595                 :            :         // reverse!(object_worklist.items, prevlen:end);
     596                 :            :         // prevlen is the index of the first new object
     597         [ +  + ]:   16475700 :         for (i = prevlen; i < object_worklist.len; i++) {
     598                 :    8237870 :             size_t j = object_worklist.len - i + prevlen - 1;
     599                 :    8237870 :             void *tmp = object_worklist.items[i];
     600                 :    8237870 :             object_worklist.items[i] = object_worklist.items[j];
     601                 :    8237870 :             object_worklist.items[j] = tmp;
     602                 :            :         }
     603                 :    8237870 :         prevlen = --object_worklist.len;
     604                 :    8237870 :         uintptr_t v = (uintptr_t)object_worklist.items[prevlen];
     605                 :    8237870 :         int recursive = v & 1;
     606                 :    8237870 :         v &= ~(uintptr_t)1; // untag v
     607                 :    8237870 :         jl_serialize_value__(s, (jl_value_t*)v, recursive);
     608                 :            :     }
     609                 :          6 : }
     610                 :            : 
     611                 :      43548 : static void ios_ensureroom(ios_t *s, size_t newsize) JL_NOTSAFEPOINT
     612                 :            : {
     613                 :      43548 :     size_t prevsize = s->size;
     614         [ +  + ]:      43548 :     if (prevsize < newsize) {
     615                 :         36 :         ios_trunc(s, newsize);
     616         [ -  + ]:         36 :         assert(s->size == newsize);
     617                 :         36 :         memset(&s->buf[prevsize], 0, newsize - prevsize);
     618                 :            :     }
     619                 :      43548 : }
     620                 :            : 
     621                 :            : // Maybe encode a global variable. `gid` is the LLVM index, 0 if the object is not serialized
     622                 :            : // in the generated code (and thus not a gvar from that standpoint, maybe only stored in the internal-data sysimg).
     623                 :            : // `reloc_id` is the RefTags-encoded `target`.
     624                 :    2072500 : static void record_gvar(jl_serializer_state *s, int gid, uintptr_t reloc_id) JL_NOTSAFEPOINT
     625                 :            : {
     626         [ +  + ]:    2072500 :     if (gid == 0)
     627                 :    2057040 :         return;
     628                 :      15464 :     ios_ensureroom(s->gvar_record, gid * sizeof(uint32_t));
     629                 :      15464 :     ios_seek(s->gvar_record, (gid - 1) * sizeof(uint32_t));
     630         [ -  + ]:      15464 :     assert(reloc_id < UINT32_MAX);
     631                 :      15464 :     write_uint32(s->gvar_record, reloc_id);
     632                 :            : }
     633                 :            : 
     634                 :            : 
     635                 :   20137100 : static void write_padding(ios_t *s, size_t nb) JL_NOTSAFEPOINT
     636                 :            : {
     637                 :            :     static const char zeros[16] = {0};
     638         [ +  + ]:   20214400 :     while (nb > 16) {
     639                 :      77278 :         ios_write(s, zeros, 16);
     640                 :      77278 :         nb -= 16;
     641                 :            :     }
     642         [ +  + ]:   20137100 :     if (nb != 0)
     643                 :    9063480 :         ios_write(s, zeros, nb);
     644                 :   20137100 : }
     645                 :            : 
     646                 :            : 
     647                 :    6660380 : static void write_pointer(ios_t *s) JL_NOTSAFEPOINT
     648                 :            : {
     649         [ +  - ]:    6660380 :     assert((ios_pos(s) & (sizeof(void*) - 1)) == 0 && "stream misaligned for writing a word-sized value");
     650                 :    6660380 :     write_padding(s, sizeof(void*));
     651                 :    6660380 : }
     652                 :            : 
     653                 :            : // Return the integer `id` for `v`. Generically this is looked up in `backref_table`,
     654                 :            : // but symbols, small integers, and a couple of special items (`nothing` and the root Task)
     655                 :            : // have special handling.
     656                 :            : #define backref_id(s, v) _backref_id(s, (jl_value_t*)(v))
     657                 :    9379320 : static uintptr_t _backref_id(jl_serializer_state *s, jl_value_t *v) JL_NOTSAFEPOINT
     658                 :            : {
     659         [ -  + ]:    9379320 :     assert(v != NULL && "cannot get backref to NULL object");
     660                 :    9379320 :     void *idx = HT_NOTFOUND;
     661         [ +  + ]:    9379320 :     if (jl_is_symbol(v)) {
     662                 :     792273 :         void **pidx = ptrhash_bp(&symbol_table, v);
     663                 :     792273 :         idx = *pidx;
     664         [ +  + ]:     792273 :         if (idx == HT_NOTFOUND) {
     665                 :      59397 :             size_t l = strlen(jl_symbol_name((jl_sym_t*)v));
     666                 :      59397 :             write_uint32(s->symbols, l);
     667                 :      59397 :             ios_write(s->symbols, jl_symbol_name((jl_sym_t*)v), l + 1);
     668                 :      59397 :             size_t offset = ++nsym_tag;
     669         [ -  + ]:      59397 :             assert(offset < ((uintptr_t)1 << RELOC_TAG_OFFSET) && "too many symbols");
     670                 :      59397 :             idx = (void*)((char*)HT_NOTFOUND + ((uintptr_t)SymbolRef << RELOC_TAG_OFFSET) + offset);
     671                 :      59397 :             *pidx = idx;
     672                 :            :         }
     673                 :            :     }
     674         [ +  + ]:    8587040 :     else if (v == (jl_value_t*)s->ptls->root_task) {
     675                 :          2 :         return (uintptr_t)TagRef << RELOC_TAG_OFFSET;
     676                 :            :     }
     677         [ +  + ]:    8587040 :     else if (v == jl_nothing) {
     678                 :     608183 :         return ((uintptr_t)TagRef << RELOC_TAG_OFFSET) + 1;
     679                 :            :     }
     680         [ +  + ]:    7978860 :     else if (jl_typeis(v, jl_int64_type)) {
     681                 :      41022 :         int64_t i64 = *(int64_t*)v + NBOX_C / 2;
     682         [ +  + ]:      41022 :         if ((uint64_t)i64 < NBOX_C)
     683                 :      31489 :             return ((uintptr_t)TagRef << RELOC_TAG_OFFSET) + i64 + 2;
     684                 :            :     }
     685         [ +  + ]:    7937840 :     else if (jl_typeis(v, jl_int32_type)) {
     686                 :       1352 :         int32_t i32 = *(int32_t*)v + NBOX_C / 2;
     687         [ +  + ]:       1352 :         if ((uint32_t)i32 < NBOX_C)
     688                 :        921 :             return ((uintptr_t)TagRef << RELOC_TAG_OFFSET) + i32 + 2 + NBOX_C;
     689                 :            :     }
     690         [ +  + ]:    7936480 :     else if (jl_typeis(v, jl_uint8_type)) {
     691                 :        179 :         uint8_t u8 = *(uint8_t*)v;
     692                 :        179 :         return ((uintptr_t)TagRef << RELOC_TAG_OFFSET) + u8 + 2 + NBOX_C + NBOX_C;
     693                 :            :     }
     694         [ +  + ]:    8738540 :     if (idx == HT_NOTFOUND) {
     695                 :    7946270 :         idx = ptrhash_get(&backref_table, v);
     696         [ -  + ]:    7946270 :         assert(idx != HT_NOTFOUND && "object missed during jl_serialize_value pass");
     697                 :            :     }
     698                 :    8738540 :     return (char*)idx - 1 - (char*)HT_NOTFOUND;
     699                 :            : }
     700                 :            : 
     701                 :            : 
     702                 :            : // Save blank space in stream `s` for a pointer `fld`, storing both location and target
     703                 :            : // in `relocs_list`.
     704                 :    3972090 : static void write_pointerfield(jl_serializer_state *s, jl_value_t *fld) JL_NOTSAFEPOINT
     705                 :            : {
     706         [ +  + ]:    3972090 :     if (fld != NULL) {
     707                 :    2841400 :         arraylist_push(&s->relocs_list, (void*)(uintptr_t)ios_pos(s->s));
     708                 :    2841400 :         arraylist_push(&s->relocs_list, (void*)backref_id(s, fld));
     709                 :            :     }
     710                 :    3972090 :     write_pointer(s->s);
     711                 :    3972090 : }
     712                 :            : 
     713                 :            : // Save blank space in stream `s` for a pointer `fld`, storing both location and target
     714                 :            : // in `gctags_list`.
     715                 :    2071480 : static void write_gctaggedfield(jl_serializer_state *s, uintptr_t ref) JL_NOTSAFEPOINT
     716                 :            : {
     717                 :    2071480 :     arraylist_push(&s->gctags_list, (void*)(uintptr_t)ios_pos(s->s));
     718                 :    2071480 :     arraylist_push(&s->gctags_list, (void*)ref);
     719                 :    2071480 :     write_pointer(s->s);
     720                 :    2071480 : }
     721                 :            : 
     722                 :            : // Special handling from `jl_write_values` for modules
     723                 :        270 : static void jl_write_module(jl_serializer_state *s, uintptr_t item, jl_module_t *m)
     724                 :            : {
     725                 :        270 :     size_t reloc_offset = ios_pos(s->s);
     726                 :        270 :     size_t tot = sizeof(jl_module_t);
     727                 :        270 :     ios_write(s->s, (char*)m, tot);     // raw memory dump of the `jl_module_t` structure
     728                 :            : 
     729                 :            :     // Handle the fields requiring special attention
     730                 :        270 :     jl_module_t *newm = (jl_module_t*)&s->s->buf[reloc_offset];
     731                 :        270 :     newm->name = NULL;
     732                 :        270 :     arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, name)));
     733                 :        270 :     arraylist_push(&s->relocs_list, (void*)backref_id(s, m->name));
     734                 :        270 :     newm->parent = NULL;
     735                 :        270 :     arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, parent)));
     736                 :        270 :     arraylist_push(&s->relocs_list, (void*)backref_id(s, m->parent));
     737                 :        270 :     newm->primary_world = jl_atomic_load_acquire(&jl_world_counter);
     738                 :            : 
     739                 :            :     // write out the bindings table as a list
     740                 :            :     // immediately after jl_module_t
     741                 :            :     // (the ptrhash will need to be recreated on load)
     742                 :        270 :     size_t count = 0;
     743                 :            :     size_t i;
     744                 :        270 :     void **table = m->bindings.table;
     745         [ +  + ]:     181502 :     for (i = 0; i < m->bindings.size; i += 2) {
     746         [ +  + ]:     181232 :         if (table[i+1] != HT_NOTFOUND) {
     747                 :      70952 :             jl_binding_t *b = (jl_binding_t*)table[i+1];
     748                 :      70952 :             write_pointerfield(s, (jl_value_t*)table[i]);
     749                 :      70952 :             tot += sizeof(void*);
     750                 :      70952 :             write_gctaggedfield(s, (uintptr_t)BindingRef << RELOC_TAG_OFFSET);
     751                 :      70952 :             tot += sizeof(void*);
     752                 :      70952 :             size_t binding_reloc_offset = ios_pos(s->s);
     753                 :      70952 :             record_gvar(s, jl_get_llvm_gv(native_functions, (jl_value_t*)b),
     754                 :            :                     ((uintptr_t)DataRef << RELOC_TAG_OFFSET) + binding_reloc_offset);
     755                 :      70952 :             write_pointerfield(s, (jl_value_t*)b->name);
     756   [ +  +  +  +  :      70952 :             if (jl_docmeta_sym && b->name == jl_docmeta_sym && jl_options.strip_metadata)
                   -  + ]
     757                 :          0 :                 write_pointerfield(s, jl_nothing);
     758                 :            :             else
     759                 :      70952 :                 write_pointerfield(s, jl_atomic_load_relaxed(&b->value));
     760                 :      70952 :             write_pointerfield(s, jl_atomic_load_relaxed(&b->globalref));
     761                 :      70952 :             write_pointerfield(s, (jl_value_t*)b->owner);
     762                 :      70952 :             write_pointerfield(s, jl_atomic_load_relaxed(&b->ty));
     763                 :      70952 :             size_t flag_offset = offsetof(jl_binding_t, ty) + sizeof(b->ty);
     764                 :      70952 :             ios_write(s->s, (char*)b + flag_offset, sizeof(*b) - flag_offset);
     765                 :      70952 :             tot += sizeof(jl_binding_t);
     766                 :      70952 :             count += 1;
     767                 :            :         }
     768                 :            :     }
     769         [ -  + ]:        270 :     assert(ios_pos(s->s) - reloc_offset == tot);
     770                 :        270 :     newm = (jl_module_t*)&s->s->buf[reloc_offset]; // buf might have been reallocated
     771                 :        270 :     newm->bindings.size = count; // stash the count in newm->size
     772                 :        270 :     newm->bindings.table = NULL;
     773                 :        270 :     memset(&newm->bindings._space, 0, sizeof(newm->bindings._space));
     774                 :            : 
     775                 :            :     // write out the usings list
     776                 :        270 :     memset(&newm->usings._space, 0, sizeof(newm->usings._space));
     777         [ +  - ]:        270 :     if (m->usings.items == &m->usings._space[0]) {
     778                 :        270 :         newm->usings.items = (void**)offsetof(jl_module_t, usings._space);
     779                 :        270 :         arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, usings.items)));
     780                 :        270 :         arraylist_push(&s->relocs_list, (void*)(((uintptr_t)DataRef << RELOC_TAG_OFFSET) + item));
     781                 :            :         size_t i;
     782         [ +  + ]:       1078 :         for (i = 0; i < m->usings.len; i++) {
     783                 :        808 :             arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, usings._space[i])));
     784                 :        808 :             arraylist_push(&s->relocs_list, (void*)backref_id(s, m->usings._space[i]));
     785                 :            :         }
     786                 :            :     }
     787                 :            :     else {
     788                 :          0 :         newm->usings.items = (void**)tot;
     789                 :          0 :         arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, usings.items)));
     790                 :          0 :         arraylist_push(&s->relocs_list, (void*)(((uintptr_t)DataRef << RELOC_TAG_OFFSET) + item));
     791                 :            :         size_t i;
     792         [ #  # ]:          0 :         for (i = 0; i < m->usings.len; i++) {
     793                 :          0 :             write_pointerfield(s, (jl_value_t*)m->usings.items[i]);
     794                 :          0 :             tot += sizeof(void*);
     795                 :            :         }
     796         [ #  # ]:          0 :         for (; i < m->usings.max; i++) {
     797                 :          0 :             write_pointer(s->s);
     798                 :          0 :             tot += sizeof(void*);
     799                 :            :         }
     800                 :            :     }
     801                 :        270 : }
     802                 :            : 
     803                 :            : #if 0
     804                 :            : static size_t jl_sort_size(jl_datatype_t *dt)
     805                 :            : {
     806                 :            :     if (dt == jl_simplevector_type)
     807                 :            :         return SIZE_MAX - 5;
     808                 :            :     if (dt == jl_string_type)
     809                 :            :         return SIZE_MAX - 4;
     810                 :            :     if (dt->name == jl_array_typename)
     811                 :            :         return SIZE_MAX - 3;
     812                 :            :     if (dt == jl_datatype_type)
     813                 :            :         return SIZE_MAX - 2;
     814                 :            :     if (dt == jl_module_type)
     815                 :            :         return SIZE_MAX - 1;
     816                 :            :     return jl_datatype_size(dt);
     817                 :            : }
     818                 :            : #endif
     819                 :            : 
     820                 :            : // Used by `qsort` to order `backref_table` by `id`
     821                 :   36702100 : static int sysimg_sort_order(const void *pa, const void *pb)
     822                 :            : {
     823                 :   36702100 :     uintptr_t sa = ((uintptr_t*)pa)[1];
     824                 :   36702100 :     uintptr_t sb = ((uintptr_t*)pb)[1];
     825   [ +  +  +  - ]:   36702100 :     return (sa > sb ? 1 : (sa < sb ? -1 : 0));
     826                 :            : #if 0
     827                 :            :     jl_value_t *a = *(jl_value_t**)pa;
     828                 :            :     jl_datatype_t *tya = (jl_datatype_t*)jl_typeof(a);
     829                 :            :     size_t sa = jl_sort_size(tya);
     830                 :            :     jl_value_t *b = *(jl_value_t**)pb;
     831                 :            :     jl_datatype_t *tyb = (jl_datatype_t*)jl_typeof(b);
     832                 :            :     size_t sb = jl_sort_size(tyb);
     833                 :            :     if (sa == sb) {
     834                 :            :         sa = tya->uid;
     835                 :            :         sb = tyb->uid;
     836                 :            :     }
     837                 :            :     return (sa > sb ? 1 : (sa < sb ? -1 : 0));
     838                 :            : #endif
     839                 :            : }
     840                 :            : 
     841                 :            : jl_value_t *jl_find_ptr = NULL;
     842                 :            : // The main function for serializing all the items queued in `backref_table`
     843                 :          3 : static void jl_write_values(jl_serializer_state *s)
     844                 :            : {
     845                 :            :     arraylist_t objects_list;
     846                 :          3 :     arraylist_new(&objects_list, backref_table_numel * 2);
     847                 :            : 
     848                 :          3 :     arraylist_new(&layout_table, 0);
     849                 :          3 :     arraylist_grow(&layout_table, backref_table_numel);
     850                 :          3 :     memset(layout_table.items, 0, backref_table_numel * sizeof(void*));
     851                 :            : 
     852                 :            :     // Order `backref_table` by `id`
     853                 :          3 :     size_t i, len = backref_table.size;
     854                 :          3 :     void **p = backref_table.table;
     855         [ +  + ]:    3407880 :     for (i = 0; i < len; i += 2) {
     856                 :    3407870 :         char *reloc_id = (char*)p[i + 1];
     857         [ +  + ]:    3407870 :         if (reloc_id != HT_NOTFOUND) {
     858                 :    2000530 :             jl_value_t *v = (jl_value_t*)p[i];
     859                 :    2000530 :             uintptr_t item = reloc_id - 1 - (char*)HT_NOTFOUND;
     860                 :    2000530 :             objects_list.items[objects_list.len++] = (void*)v;
     861                 :    2000530 :             objects_list.items[objects_list.len++] = (void*)item;
     862                 :            :         }
     863                 :            :     }
     864         [ -  + ]:          3 :     assert(backref_table_numel * 2 == objects_list.len);
     865                 :          3 :     qsort(objects_list.items, backref_table_numel, sizeof(void*) * 2, sysimg_sort_order);
     866                 :            : 
     867                 :            :     // Serialize all entries
     868         [ +  + ]:    2000530 :     for (i = 0, len = backref_table_numel * 2; i < len; i += 2) {
     869                 :    2000530 :         jl_value_t *v = (jl_value_t*)objects_list.items[i];           // the object
     870                 :            :         JL_GC_PROMISE_ROOTED(v);
     871                 :    2000530 :         uintptr_t item = (uintptr_t)objects_list.items[i + 1];        // the id
     872                 :    2000530 :         jl_datatype_t *t = (jl_datatype_t*)jl_typeof(v);
     873   [ +  +  -  + ]:    2000530 :         assert((t->instance == NULL || t->instance == v) && "detected singleton construction corruption");
     874                 :            :         // realign stream to expected gc alignment (16 bytes)
     875                 :    2000530 :         uintptr_t skip_header_pos = ios_pos(s->s) + sizeof(jl_taggedvalue_t);
     876                 :    2000530 :         write_padding(s->s, LLT_ALIGN(skip_header_pos, 16) - skip_header_pos);
     877                 :            :         // write header
     878                 :    2000530 :         write_gctaggedfield(s, backref_id(s, t));
     879                 :    2000530 :         size_t reloc_offset = ios_pos(s->s);
     880   [ +  -  +  - ]:    2000530 :         assert(item < layout_table.len && layout_table.items[item] == NULL);
     881                 :    2000530 :         layout_table.items[item] = (void*)reloc_offset;               // store the inverse mapping of `backref_table` (`id` => object)
     882                 :    2000530 :         record_gvar(s, jl_get_llvm_gv(native_functions, v), ((uintptr_t)DataRef << RELOC_TAG_OFFSET) + reloc_offset);
     883                 :            : 
     884                 :            :         // write data
     885         [ +  + ]:    2000530 :         if (jl_is_cpointer(v)) {
     886                 :         44 :             write_pointer(s->s);
     887                 :            :         }
     888         [ +  + ]:    2000490 :         else if (jl_is_array(v)) {
     889                 :            :             // Internal data for types in julia.h with `jl_array_t` field(s)
     890                 :            : #define JL_ARRAY_ALIGN(jl_value, nbytes) LLT_ALIGN(jl_value, nbytes)
     891                 :     398595 :             jl_array_t *ar = (jl_array_t*)v;
     892                 :     398595 :             jl_value_t *et = jl_tparam0(jl_typeof(v));
     893                 :     398595 :             size_t alen = jl_array_len(ar);
     894                 :     398595 :             size_t datasize = alen * ar->elsize;
     895                 :     398595 :             size_t tot = datasize;
     896   [ +  +  -  + ]:     398595 :             int isbitsunion = jl_array_isbitsunion(ar);
     897         [ -  + ]:     398595 :             if (isbitsunion)
     898                 :          0 :                 tot += alen;
     899         [ +  + ]:     398595 :             else if (ar->elsize == 1)
     900                 :     180780 :                 tot += 1;
     901                 :     398595 :             int ndimwords = jl_array_ndimwords(ar->flags.ndims);
     902                 :     398595 :             size_t headersize = sizeof(jl_array_t) + ndimwords*sizeof(size_t);
     903                 :            :             // copy header
     904                 :     398595 :             ios_write(s->s, (char*)v, headersize);
     905                 :     398595 :             size_t alignment_amt = JL_SMALL_BYTE_ALIGNMENT;
     906         [ +  + ]:     398595 :             if (tot >= ARRAY_CACHE_ALIGN_THRESHOLD)
     907                 :       7715 :                 alignment_amt = JL_CACHE_BYTE_ALIGNMENT;
     908                 :            :             // make some header modifications in-place
     909                 :     398595 :             jl_array_t *newa = (jl_array_t*)&s->s->buf[reloc_offset];
     910         [ +  + ]:     398595 :             if (newa->flags.ndims == 1)
     911                 :     398589 :                 newa->maxsize = alen;
     912                 :     398595 :             newa->offset = 0;
     913                 :     398595 :             newa->flags.how = 0;
     914                 :     398595 :             newa->flags.pooled = 0;
     915                 :     398595 :             newa->flags.isshared = 0;
     916                 :            : 
     917                 :            :             // write data
     918   [ +  +  +  + ]:     579999 :             if (!ar->flags.ptrarray && !ar->flags.hasptr) {
     919                 :            :                 // Non-pointer eltypes get encoded in the const_data section
     920                 :     181404 :                 uintptr_t data = LLT_ALIGN(ios_pos(s->const_data), alignment_amt);
     921                 :     181404 :                 write_padding(s->const_data, data - ios_pos(s->const_data));
     922                 :            :                 // write data and relocations
     923                 :     181404 :                 newa->data = NULL; // relocation offset
     924                 :     181404 :                 data /= sizeof(void*);
     925         [ -  + ]:     181404 :                 assert(data < ((uintptr_t)1 << RELOC_TAG_OFFSET) && "offset to constant data too large");
     926                 :     181404 :                 arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_array_t, data))); // relocation location
     927                 :     181404 :                 arraylist_push(&s->relocs_list, (void*)(((uintptr_t)ConstDataRef << RELOC_TAG_OFFSET) + data)); // relocation target
     928         [ +  + ]:     181404 :                 if (jl_is_cpointer_type(et)) {
     929                 :            :                     // reset Ptr elements to C_NULL
     930                 :            :                     size_t i;
     931         [ +  + ]:          4 :                     for (i = 0; i < alen; i++)
     932                 :          2 :                         write_pointer(s->const_data);
     933                 :            :                 }
     934                 :            :                 else {
     935         [ -  + ]:     181402 :                     if (isbitsunion) {
     936                 :          0 :                         ios_write(s->const_data, (char*)jl_array_data(ar), datasize);
     937                 :          0 :                         ios_write(s->const_data, jl_array_typetagdata(ar), alen);
     938                 :            :                     }
     939                 :            :                     else {
     940                 :     181402 :                         ios_write(s->const_data, (char*)jl_array_data(ar), tot);
     941                 :            :                     }
     942                 :            :                 }
     943                 :            :             }
     944                 :            :             else {
     945                 :            :                 // Pointer eltypes are encoded in the mutable data section
     946                 :     217191 :                 size_t data = LLT_ALIGN(ios_pos(s->s), alignment_amt);
     947                 :     217191 :                 size_t padding_amt = data - ios_pos(s->s);
     948                 :     217191 :                 write_padding(s->s, padding_amt);
     949                 :     217191 :                 headersize += padding_amt;
     950                 :     217191 :                 newa->data = (void*)headersize; // relocation offset
     951                 :     217191 :                 arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_array_t, data))); // relocation location
     952                 :     217191 :                 arraylist_push(&s->relocs_list, (void*)(((uintptr_t)DataRef << RELOC_TAG_OFFSET) + item)); // relocation target
     953         [ +  + ]:     217191 :                 if (ar->flags.hasptr) {
     954                 :            :                     // copy all of the data first
     955                 :        262 :                     const char *data = (const char*)jl_array_data(ar);
     956                 :        262 :                     ios_write(s->s, data, datasize);
     957                 :            :                     // the rewrite all of the embedded pointers to null+relocation
     958                 :        262 :                     uint16_t elsz = ar->elsize;
     959                 :        262 :                     size_t j, np = ((jl_datatype_t*)et)->layout->npointers;
     960                 :            :                     size_t i;
     961         [ +  + ]:       4361 :                     for (i = 0; i < alen; i++) {
     962         [ +  + ]:      13954 :                         for (j = 0; j < np; j++) {
     963                 :       9855 :                             size_t offset = i * elsz + jl_ptr_offset(((jl_datatype_t*)et), j) * sizeof(jl_value_t*);
     964                 :       9855 :                             jl_value_t *fld = *(jl_value_t**)&data[offset];
     965         [ +  + ]:       9855 :                             if (fld != NULL) {
     966                 :       4657 :                                 arraylist_push(&s->relocs_list, (void*)(uintptr_t)(reloc_offset + headersize + offset)); // relocation location
     967                 :       4657 :                                 arraylist_push(&s->relocs_list, (void*)backref_id(s, fld)); // relocation target
     968                 :       4657 :                                 memset(&s->s->buf[reloc_offset + headersize + offset], 0, sizeof(fld)); // relocation offset (none)
     969                 :            :                             }
     970                 :            :                             else {
     971         [ -  + ]:       5198 :                                 assert(*(jl_value_t**)&s->s->buf[reloc_offset + headersize + offset] == NULL);
     972                 :            :                             }
     973                 :            :                         }
     974                 :            :                     }
     975                 :            :                 }
     976                 :            :                 else {
     977                 :            :                     size_t i;
     978         [ +  + ]:    2241910 :                     for (i = 0; i < alen; i++) {
     979                 :    2024980 :                         jl_value_t *e = jl_array_ptr_ref(v, i);
     980                 :    2024980 :                         write_pointerfield(s, e);
     981                 :            :                     }
     982                 :            :                 }
     983                 :            :             }
     984                 :            :         }
     985         [ +  + ]:    1601890 :         else if (jl_typeis(v, jl_module_type)) {
     986                 :        270 :             jl_write_module(s, item, (jl_module_t*)v);
     987                 :            :             // will need to recreate the binding table for this
     988                 :        270 :             arraylist_push(&reinit_list, (void*)item);
     989                 :        270 :             arraylist_push(&reinit_list, (void*)2);
     990                 :            :         }
     991         [ -  + ]:    1601620 :         else if (jl_typeis(v, jl_task_type)) {
     992                 :          0 :             jl_error("Task cannot be serialized");
     993                 :            :         }
     994         [ +  + ]:    1601620 :         else if (jl_is_svec(v)) {
     995                 :     352420 :             ios_write(s->s, (char*)v, sizeof(void*));
     996                 :     352420 :             size_t i, l = jl_svec_len(v);
     997   [ +  +  -  + ]:     352420 :             assert(l > 0 || (jl_svec_t*)v == jl_emptysvec);
     998         [ +  + ]:    1873810 :             for (i = 0; i < l; i++) {
     999                 :    1521390 :                 write_pointerfield(s, jl_svecref(v, i));
    1000                 :            :             }
    1001                 :            :         }
    1002         [ +  + ]:    1249200 :         else if (jl_is_string(v)) {
    1003                 :     121873 :             ios_write(s->s, (char*)v, sizeof(void*) + jl_string_len(v));
    1004                 :     121873 :             write_uint8(s->s, '\0'); // null-terminated strings for easier C-compatibility
    1005                 :            :         }
    1006         [ +  + ]:    1127330 :         else if (jl_datatype_nfields(t) == 0) {
    1007         [ -  + ]:      38117 :             assert(t->layout->npointers == 0);
    1008         [ +  + ]:      38117 :             if (t->size > 0)
    1009                 :      15742 :                 ios_write(s->s, (char*)v, t->size);
    1010                 :            :         }
    1011   [ +  +  +  + ]:    1089220 :         else if (jl_bigint_type && jl_typeis(v, jl_bigint_type)) {
    1012                 :            :             // foreign types require special handling
    1013                 :          6 :             jl_value_t *sizefield = jl_get_nth_field(v, 1);
    1014                 :          6 :             int32_t sz = jl_unbox_int32(sizefield);
    1015         [ +  + ]:          6 :             int32_t nw = (sz == 0 ? 1 : (sz < 0 ? -sz : sz));
    1016                 :          6 :             size_t nb = nw * gmp_limb_size;
    1017                 :          6 :             ios_write(s->s, (char*)&nw, sizeof(int32_t));
    1018                 :          6 :             ios_write(s->s, (char*)&sz, sizeof(int32_t));
    1019                 :          6 :             uintptr_t data = LLT_ALIGN(ios_pos(s->const_data), 8);
    1020                 :          6 :             write_padding(s->const_data, data - ios_pos(s->const_data));
    1021                 :          6 :             data /= sizeof(void*);
    1022         [ -  + ]:          6 :             assert(data < ((uintptr_t)1 << RELOC_TAG_OFFSET) && "offset to constant data too large");
    1023                 :          6 :             arraylist_push(&s->relocs_list, (void*)(reloc_offset + 8)); // relocation location
    1024                 :          6 :             arraylist_push(&s->relocs_list, (void*)(((uintptr_t)ConstDataRef << RELOC_TAG_OFFSET) + data)); // relocation target
    1025                 :          6 :             void *pdata = jl_unbox_voidpointer(jl_get_nth_field(v, 2));
    1026                 :          6 :             ios_write(s->const_data, (char*)pdata, nb);
    1027                 :          6 :             write_pointer(s->s);
    1028                 :            :         }
    1029                 :            :         else {
    1030                 :            :             // Generic object::DataType serialization by field
    1031                 :    1089200 :             const char *data = (const char*)v;
    1032                 :    1089200 :             size_t i, nf = jl_datatype_nfields(t);
    1033                 :    1089200 :             size_t tot = 0;
    1034         [ +  + ]:   11405000 :             for (i = 0; i < nf; i++) {
    1035                 :   10315700 :                 size_t offset = jl_field_offset(t, i);
    1036                 :   10315700 :                 const char *slot = data + offset;
    1037                 :   10315700 :                 write_padding(s->s, offset - tot);
    1038                 :   10315700 :                 tot = offset;
    1039                 :   10315700 :                 size_t fsz = jl_field_size(t, i);
    1040   [ +  +  +  + ]:   10315700 :                 if (t->name->mutabl && jl_is_cpointer_type(jl_field_type(t, i))) {
    1041                 :            :                     // reset Ptr fields to C_NULL
    1042         [ -  + ]:     616760 :                     assert(!jl_field_isptr(t, i));
    1043                 :     616760 :                     write_pointer(s->s);
    1044                 :            :                 }
    1045         [ +  + ]:    9698990 :                 else if (fsz > 0) {
    1046                 :    9691420 :                     ios_write(s->s, slot, fsz);
    1047                 :            :                 }
    1048                 :   10315700 :                 tot += fsz;
    1049                 :            :             }
    1050                 :            : 
    1051                 :    1089200 :             size_t np = t->layout->npointers;
    1052         [ +  + ]:    6904540 :             for (i = 0; i < np; i++) {
    1053                 :    5815340 :                 size_t offset = jl_ptr_offset(t, i) * sizeof(jl_value_t*);
    1054                 :    5815340 :                 jl_value_t *fld = get_replaceable_field((jl_value_t**)&data[offset]);
    1055         [ +  + ]:    5815340 :                 if (fld != NULL) {
    1056                 :    4529900 :                     arraylist_push(&s->relocs_list, (void*)(uintptr_t)(offset + reloc_offset)); // relocation location
    1057                 :    4529900 :                     arraylist_push(&s->relocs_list, (void*)backref_id(s, fld)); // relocation target
    1058                 :    4529900 :                     memset(&s->s->buf[offset + reloc_offset], 0, sizeof(fld)); // relocation offset (none)
    1059                 :            :                 }
    1060                 :            :             }
    1061                 :            : 
    1062                 :            :             // A few objects need additional handling beyond the generic serialization above
    1063         [ +  + ]:    1089200 :             if (jl_is_method(v)) {
    1064                 :      66486 :                 write_padding(s->s, sizeof(jl_method_t) - tot);
    1065         [ -  + ]:      66486 :                 if (((jl_method_t*)v)->ccallable) {
    1066                 :          0 :                     arraylist_push(&ccallable_list, (void*)item);
    1067                 :          0 :                     arraylist_push(&ccallable_list, (void*)3);
    1068                 :            :                 }
    1069                 :            :             }
    1070         [ +  + ]:    1022720 :             else if (jl_is_code_instance(v)) {
    1071                 :            :                 // Handle the native-code pointers
    1072                 :     128102 :                 jl_code_instance_t *m = (jl_code_instance_t*)v;
    1073                 :     128102 :                 jl_code_instance_t *newm = (jl_code_instance_t*)&s->s->buf[reloc_offset];
    1074                 :            : 
    1075                 :     128102 :                 newm->invoke = NULL;
    1076                 :     128102 :                 newm->isspecsig = 0;
    1077                 :     128102 :                 newm->specptr.fptr = NULL;
    1078                 :     128102 :                 int8_t fptr_id = JL_API_NULL;
    1079                 :     128102 :                 int8_t builtin_id = 0;
    1080         [ +  + ]:     128102 :                 if (m->invoke == jl_fptr_const_return) {
    1081                 :      15964 :                     fptr_id = JL_API_CONST;
    1082                 :            :                 }
    1083                 :            :                 else {
    1084         [ +  - ]:     112138 :                     if (jl_is_method(m->def->def.method)) {
    1085                 :     112138 :                         builtin_id = jl_fptr_id(m->specptr.fptr);
    1086         [ +  + ]:     112138 :                         if (builtin_id) { // found in the table of builtins
    1087         [ -  + ]:        141 :                             assert(builtin_id >= 2);
    1088                 :        141 :                             fptr_id = JL_API_BUILTIN;
    1089                 :            :                         }
    1090                 :            :                         else {
    1091                 :     111997 :                             int32_t invokeptr_id = 0;
    1092                 :     111997 :                             int32_t specfptr_id = 0;
    1093                 :     111997 :                             jl_get_function_id(native_functions, m, &invokeptr_id, &specfptr_id); // see if we generated code for it
    1094         [ +  + ]:     111997 :                             if (invokeptr_id) {
    1095         [ +  + ]:      14900 :                                 if (invokeptr_id == -1) {
    1096                 :       1716 :                                     fptr_id = JL_API_BOXED;
    1097                 :            :                                 }
    1098         [ -  + ]:      13184 :                                 else if (invokeptr_id == -2) {
    1099                 :          0 :                                     fptr_id = JL_API_WITH_PARAMETERS;
    1100                 :            :                                 }
    1101                 :            :                                 else {
    1102         [ -  + ]:      13184 :                                     assert(invokeptr_id > 0);
    1103                 :      13184 :                                     ios_ensureroom(s->fptr_record, invokeptr_id * sizeof(void*));
    1104                 :      13184 :                                     ios_seek(s->fptr_record, (invokeptr_id - 1) * sizeof(void*));
    1105                 :      13184 :                                     write_uint32(s->fptr_record, ~reloc_offset);
    1106                 :            : #ifdef _P64
    1107                 :      13184 :                                     write_padding(s->fptr_record, 4);
    1108                 :            : #endif
    1109                 :            :                                 }
    1110         [ +  - ]:      14900 :                                 if (specfptr_id) {
    1111   [ +  -  +  - ]:      14900 :                                     assert(specfptr_id > invokeptr_id && specfptr_id > 0);
    1112                 :      14900 :                                     ios_ensureroom(s->fptr_record, specfptr_id * sizeof(void*));
    1113                 :      14900 :                                     ios_seek(s->fptr_record, (specfptr_id - 1) * sizeof(void*));
    1114                 :      14900 :                                     write_uint32(s->fptr_record, reloc_offset);
    1115                 :            : #ifdef _P64
    1116                 :      14900 :                                     write_padding(s->fptr_record, 4);
    1117                 :            : #endif
    1118                 :            :                                 }
    1119                 :            :                             }
    1120                 :            :                         }
    1121                 :            :                     }
    1122                 :            :                 }
    1123                 :     128102 :                 newm->invoke = NULL; // relocation offset
    1124         [ +  + ]:     128102 :                 if (fptr_id != JL_API_NULL) {
    1125                 :      17821 :                     arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_code_instance_t, invoke))); // relocation location
    1126                 :      17821 :                     arraylist_push(&s->relocs_list, (void*)(((uintptr_t)FunctionRef << RELOC_TAG_OFFSET) + fptr_id)); // relocation target
    1127                 :            :                 }
    1128         [ +  + ]:     128102 :                 if (builtin_id >= 2) {
    1129                 :        141 :                     arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_code_instance_t, specptr.fptr))); // relocation location
    1130                 :        141 :                     arraylist_push(&s->relocs_list, (void*)(((uintptr_t)BuiltinFunctionRef << RELOC_TAG_OFFSET) + builtin_id - 2)); // relocation target
    1131                 :            :                 }
    1132                 :            :             }
    1133         [ +  + ]:     894617 :             else if (jl_is_datatype(v)) {
    1134                 :     306733 :                 jl_datatype_t *dt = (jl_datatype_t*)v;
    1135                 :     306733 :                 jl_datatype_t *newdt = (jl_datatype_t*)&s->s->buf[reloc_offset];
    1136         [ +  + ]:     306733 :                 if (dt->layout != NULL) {
    1137                 :     111792 :                     size_t nf = dt->layout->nfields;
    1138                 :     111792 :                     size_t np = dt->layout->npointers;
    1139                 :     111792 :                     size_t fieldsize = jl_fielddesc_size(dt->layout->fielddesc_type);
    1140                 :     111792 :                     char *flddesc = (char*)dt->layout;
    1141                 :     111792 :                     size_t fldsize = sizeof(jl_datatype_layout_t) + nf * fieldsize;
    1142         [ +  + ]:     111792 :                     if (dt->layout->first_ptr != -1)
    1143                 :      69700 :                         fldsize += np << dt->layout->fielddesc_type;
    1144                 :     111792 :                     uintptr_t layout = LLT_ALIGN(ios_pos(s->const_data), sizeof(void*));
    1145                 :     111792 :                     write_padding(s->const_data, layout - ios_pos(s->const_data)); // realign stream
    1146                 :     111792 :                     newdt->layout = NULL; // relocation offset
    1147                 :     111792 :                     layout /= sizeof(void*);
    1148                 :     111792 :                     arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_datatype_t, layout))); // relocation location
    1149                 :     111792 :                     arraylist_push(&s->relocs_list, (void*)(((uintptr_t)ConstDataRef << RELOC_TAG_OFFSET) + layout)); // relocation target
    1150                 :     111792 :                     ios_write(s->const_data, flddesc, fldsize);
    1151                 :            :                 }
    1152                 :            :             }
    1153         [ +  + ]:     587884 :             else if (jl_is_typename(v)) {
    1154                 :      26718 :                 jl_typename_t *tn = (jl_typename_t*)v;
    1155                 :      26718 :                 jl_typename_t *newtn = (jl_typename_t*)&s->s->buf[reloc_offset];
    1156         [ +  + ]:      26718 :                 if (tn->atomicfields != NULL) {
    1157                 :         33 :                     size_t nb = (jl_svec_len(tn->names) + 31) / 32 * sizeof(uint32_t);
    1158                 :         33 :                     uintptr_t layout = LLT_ALIGN(ios_pos(s->const_data), sizeof(void*));
    1159                 :         33 :                     write_padding(s->const_data, layout - ios_pos(s->const_data)); // realign stream
    1160                 :         33 :                     newtn->atomicfields = NULL; // relocation offset
    1161                 :         33 :                     layout /= sizeof(void*);
    1162                 :         33 :                     arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_typename_t, atomicfields))); // relocation location
    1163                 :         33 :                     arraylist_push(&s->relocs_list, (void*)(((uintptr_t)ConstDataRef << RELOC_TAG_OFFSET) + layout)); // relocation target
    1164                 :         33 :                     ios_write(s->const_data, (char*)tn->atomicfields, nb);
    1165                 :            :                 }
    1166         [ +  + ]:      26718 :                 if (tn->constfields != NULL) {
    1167                 :         29 :                     size_t nb = (jl_svec_len(tn->names) + 31) / 32 * sizeof(uint32_t);
    1168                 :         29 :                     uintptr_t layout = LLT_ALIGN(ios_pos(s->const_data), sizeof(void*));
    1169                 :         29 :                     write_padding(s->const_data, layout - ios_pos(s->const_data)); // realign stream
    1170                 :         29 :                     newtn->constfields = NULL; // relocation offset
    1171                 :         29 :                     layout /= sizeof(void*);
    1172                 :         29 :                     arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_typename_t, constfields))); // relocation location
    1173                 :         29 :                     arraylist_push(&s->relocs_list, (void*)(((uintptr_t)ConstDataRef << RELOC_TAG_OFFSET) + layout)); // relocation target
    1174                 :         29 :                     ios_write(s->const_data, (char*)tn->constfields, nb);
    1175                 :            :                 }
    1176                 :            :             }
    1177         [ +  + ]:     561166 :             else if (((jl_datatype_t*)(jl_typeof(v)))->name == jl_idtable_typename) {
    1178                 :            :                 // will need to rehash this, later (after types are fully constructed)
    1179                 :       5740 :                 arraylist_push(&reinit_list, (void*)item);
    1180                 :       5740 :                 arraylist_push(&reinit_list, (void*)1);
    1181                 :            :             }
    1182                 :            :             else {
    1183                 :     555426 :                 write_padding(s->s, t->size - tot);
    1184                 :            :             }
    1185                 :            :         }
    1186                 :            :     }
    1187                 :          3 : }
    1188                 :            : 
    1189                 :            : 
    1190                 :            : // Record all symbols that get referenced by the generated code
    1191                 :            : // and queue them for pointer relocation
    1192                 :      79566 : static void jl_write_gv_syms(jl_serializer_state *s, jl_sym_t *v)
    1193                 :            : {
    1194                 :            :     // since symbols are static, they might not have had a
    1195                 :            :     // reference anywhere in the code image other than here
    1196                 :      79566 :     int32_t gv = jl_get_llvm_gv(native_functions, (jl_value_t*)v);
    1197         [ +  + ]:      79566 :     if (gv != 0) {
    1198                 :        967 :         uintptr_t item = backref_id(s, v);
    1199         [ -  + ]:        967 :         assert(item >> RELOC_TAG_OFFSET == SymbolRef);
    1200                 :        967 :         record_gvar(s, gv, item);
    1201                 :            :     }
    1202         [ +  + ]:      79566 :     if (v->left)
    1203                 :      39823 :         jl_write_gv_syms(s, v->left);
    1204         [ +  + ]:      79566 :     if (v->right)
    1205                 :      39740 :         jl_write_gv_syms(s, v->right);
    1206                 :      79566 : }
    1207                 :            : 
    1208                 :            : // Record all hardcoded-tagged items that get referenced by
    1209                 :            : // the generated code and queue them for pointer relocation
    1210                 :       6921 : static void jl_write_gv_tagref(jl_serializer_state *s, jl_value_t *v)
    1211                 :            : {
    1212                 :       6921 :     int32_t gv = jl_get_llvm_gv(native_functions, (jl_value_t*)v);
    1213         [ +  + ]:       6921 :     if (gv != 0) {
    1214                 :         52 :         uintptr_t item = backref_id(s, v);
    1215         [ -  + ]:         52 :         assert(item >> RELOC_TAG_OFFSET == TagRef);
    1216                 :         52 :         record_gvar(s, gv, item);
    1217                 :            :     }
    1218                 :       6921 : }
    1219                 :          3 : static void jl_write_gv_tagrefs(jl_serializer_state *s)
    1220                 :            : {
    1221                 :            :     // this also ensures all objects referenced in the code have
    1222                 :            :     // references in the system image to their global variable
    1223                 :            :     // since codegen knows that some integer boxes are static,
    1224                 :            :     // they might not have had a reference anywhere in the code
    1225                 :            :     // image other than here
    1226                 :            :     size_t i;
    1227                 :          3 :     jl_write_gv_tagref(s, (jl_value_t*)s->ptls->root_task);
    1228                 :          3 :     jl_write_gv_tagref(s, s->ptls->root_task->tls);
    1229                 :          3 :     jl_write_gv_tagref(s, jl_nothing);
    1230         [ +  + ]:       3075 :     for (i = 0; i < NBOX_C; i++) {
    1231                 :       3072 :         jl_write_gv_tagref(s, jl_box_int32((int32_t)i - NBOX_C / 2));
    1232                 :       3072 :         jl_write_gv_tagref(s, jl_box_int64((int64_t)i - NBOX_C / 2));
    1233                 :            :     }
    1234         [ +  + ]:        771 :     for (i = 0; i < 256; i++) {
    1235                 :        768 :         jl_write_gv_tagref(s, jl_box_uint8(i));
    1236                 :            :     }
    1237                 :          3 : }
    1238                 :            : 
    1239                 : 3869560000 : static inline uint32_t load_uint32(uintptr_t *base)
    1240                 :            : {
    1241                 : 3869560000 :     uint32_t v = jl_load_unaligned_i32((void*)*base);
    1242                 : 3869560000 :     *base += 4;
    1243                 : 3869560000 :     return v;
    1244                 :            : }
    1245                 :            : 
    1246                 :            : 
    1247                 :            : // In deserialization, create Symbols and set up the
    1248                 :            : // index for backreferencing
    1249                 :        566 : static void jl_read_symbols(jl_serializer_state *s)
    1250                 :            : {
    1251         [ -  + ]:        566 :     assert(deser_sym.len == nsym_tag);
    1252                 :        566 :     uintptr_t base = (uintptr_t)&s->symbols->buf[0];
    1253                 :        566 :     uintptr_t end = base + s->symbols->size;
    1254         [ +  + ]:   15192700 :     while (base < end) {
    1255                 :   15192100 :         uint32_t len = load_uint32(&base);
    1256                 :   15192100 :         const char *str = (const char*)base;
    1257                 :   15192100 :         base += len + 1;
    1258                 :            :         //printf("symbol %3d: %s\n", len, str);
    1259                 :   15192100 :         jl_sym_t *sym = _jl_symbol(str, len);
    1260                 :   15192100 :         arraylist_push(&deser_sym, (void*)sym);
    1261                 :            :     }
    1262                 :        566 : }
    1263                 :            : 
    1264                 :            : 
    1265                 :            : // In serialization, extract the appropriate serializer position for RefTags-encoded index `reloc_item`.
    1266                 :            : // Used for hard-coded tagged items, `relocs_list`, and `gctags_list`
    1267                 :    9977940 : static uintptr_t get_reloc_for_item(uintptr_t reloc_item, size_t reloc_offset)
    1268                 :            : {
    1269                 :    9977940 :     enum RefTags tag = (enum RefTags)(reloc_item >> RELOC_TAG_OFFSET);
    1270         [ +  + ]:    9977940 :     if (tag == DataRef) {
    1271                 :            :         // first serialized segment
    1272                 :            :         // need to compute the final relocation offset via the layout table
    1273         [ -  + ]:    8163730 :         assert(reloc_item < layout_table.len);
    1274                 :    8163730 :         uintptr_t reloc_base = (uintptr_t)layout_table.items[reloc_item];
    1275         [ -  + ]:    8163730 :         assert(reloc_base != 0 && "layout offset missing for relocation item");
    1276                 :            :         // write reloc_offset into s->s at pos
    1277                 :    8163730 :         return reloc_base + reloc_offset;
    1278                 :            :     }
    1279                 :            :     else {
    1280                 :            :         // just write the item reloc_id directly
    1281                 :            : #ifndef JL_NDEBUG
    1282         [ -  + ]:    1814210 :         assert(reloc_offset == 0 && "offsets for relocations to builtin objects should be precomposed in the reloc_item");
    1283                 :    1814210 :         size_t offset = (reloc_item & (((uintptr_t)1 << RELOC_TAG_OFFSET) - 1));
    1284   [ +  +  +  +  :    1814210 :         switch (tag) {
                +  +  - ]
    1285                 :     293264 :         case ConstDataRef:
    1286                 :     293264 :             break;
    1287                 :     791306 :         case SymbolRef:
    1288         [ -  + ]:     791306 :             assert(offset < nsym_tag && "corrupt relocation item id");
    1289                 :     791306 :             break;
    1290                 :     640722 :         case TagRef:
    1291         [ -  + ]:     640722 :             assert(offset < 2 * NBOX_C + 258 && "corrupt relocation item id");
    1292                 :     640722 :             break;
    1293                 :      70952 :         case BindingRef:
    1294         [ -  + ]:      70952 :             assert(offset == 0 && "corrupt relocation offset");
    1295                 :      70952 :             break;
    1296                 :        141 :         case BuiltinFunctionRef:
    1297         [ -  + ]:        141 :             assert(offset < sizeof(id_to_fptrs) / sizeof(*id_to_fptrs) && "unknown function pointer id");
    1298                 :        141 :             break;
    1299                 :      17821 :         case FunctionRef:
    1300         [ -  + ]:      17821 :             assert(offset < JL_API_MAX && "unknown function pointer id");
    1301                 :      17821 :             break;
    1302                 :          0 :         case DataRef:
    1303                 :            :         default:
    1304                 :          0 :             assert(0 && "corrupt relocation item id");
    1305                 :            :             abort();
    1306                 :            :         }
    1307                 :            : #endif
    1308                 :    1814210 :         return reloc_item; // pre-composed relocation + offset
    1309                 :            :     }
    1310                 :            : }
    1311                 :            : 
    1312                 :            : // Compute target location at deserialization
    1313                 : 3117710000 : static inline uintptr_t get_item_for_reloc(jl_serializer_state *s, uintptr_t base, size_t size, uint32_t reloc_id)
    1314                 :            : {
    1315                 : 3117710000 :     enum RefTags tag = (enum RefTags)(reloc_id >> RELOC_TAG_OFFSET);
    1316                 : 3117710000 :     size_t offset = (reloc_id & (((uintptr_t)1 << RELOC_TAG_OFFSET) - 1));
    1317   [ +  +  +  +  : 3117710000 :     switch (tag) {
             +  +  +  - ]
    1318                 : 2581050000 :     case DataRef:
    1319         [ -  + ]: 2581050000 :         assert(offset <= size);
    1320                 : 2581050000 :         return base + offset;
    1321                 :   93431500 :     case ConstDataRef:
    1322                 :   93431500 :         return (uintptr_t)s->const_data->buf + (offset * sizeof(void*));
    1323                 :  214020000 :     case SymbolRef:
    1324   [ +  -  +  - ]:  214020000 :         assert(offset < deser_sym.len && deser_sym.items[offset] && "corrupt relocation item id");
    1325                 :  214020000 :         return (uintptr_t)deser_sym.items[offset];
    1326                 :   19348400 :     case BindingRef:
    1327                 :   19348400 :         return jl_buff_tag | GC_OLD_MARKED;
    1328                 :  203292000 :     case TagRef:
    1329         [ +  + ]:  203292000 :         if (offset == 0)
    1330                 :        565 :             return (uintptr_t)s->ptls->root_task;
    1331         [ +  + ]:  203292000 :         if (offset == 1)
    1332                 :  193825000 :             return (uintptr_t)jl_nothing;
    1333                 :    9466460 :         offset -= 2;
    1334         [ +  + ]:    9466460 :         if (offset < NBOX_C)
    1335                 :    9162000 :             return (uintptr_t)jl_box_int64((int64_t)offset - NBOX_C / 2);
    1336                 :     304459 :         offset -= NBOX_C;
    1337         [ +  + ]:     304459 :         if (offset < NBOX_C)
    1338                 :     263225 :             return (uintptr_t)jl_box_int32((int32_t)offset - NBOX_C / 2);
    1339                 :      41234 :         offset -= NBOX_C;
    1340         [ +  - ]:      41234 :         if (offset < 256)
    1341                 :      41234 :             return (uintptr_t)jl_box_uint8(offset);
    1342                 :            :         // offset -= 256;
    1343                 :          0 :         assert(0 && "corrupt relocation item id");
    1344                 :            :         jl_unreachable(); // terminate control flow if assertion is disabled.
    1345                 :      26602 :     case BuiltinFunctionRef:
    1346         [ -  + ]:      26602 :         assert(offset < sizeof(id_to_fptrs) / sizeof(*id_to_fptrs) && "unknown function pointer ID");
    1347                 :      26602 :         return (uintptr_t)id_to_fptrs[offset];
    1348                 :    6535130 :     case FunctionRef:
    1349   [ +  -  +  -  :    6535130 :         switch ((jl_callingconv_t)offset) {
                +  -  - ]
    1350                 :     960960 :         case JL_API_BOXED:
    1351         [ +  + ]:     960960 :             if (sysimg_fptrs.base)
    1352                 :     957528 :                 return (uintptr_t)jl_fptr_args;
    1353                 :            :             JL_FALLTHROUGH;
    1354                 :            :         case JL_API_WITH_PARAMETERS:
    1355         [ -  + ]:       3432 :             if (sysimg_fptrs.base)
    1356                 :          0 :                 return (uintptr_t)jl_fptr_sparam;
    1357                 :       3432 :             return (uintptr_t)NULL;
    1358                 :    5547560 :         case JL_API_CONST:
    1359                 :    5547560 :             return (uintptr_t)jl_fptr_const_return;
    1360                 :          0 :         case JL_API_INTERPRETED:
    1361                 :          0 :             return (uintptr_t)jl_fptr_interpret_call;
    1362                 :      26602 :         case JL_API_BUILTIN:
    1363                 :      26602 :             return (uintptr_t)jl_fptr_args;
    1364                 :          0 :         case JL_API_NULL:
    1365                 :            :         case JL_API_MAX:
    1366                 :            :         //default:
    1367                 :            :             assert("corrupt relocation item id");
    1368                 :            :         }
    1369                 :            :     }
    1370                 :          0 :     abort();
    1371                 :            : }
    1372                 :            : 
    1373                 :            : 
    1374                 :          6 : static void jl_write_skiplist(ios_t *s, char *base, size_t size, arraylist_t *list)
    1375                 :            : {
    1376                 :            :     size_t i;
    1377         [ +  + ]:    9977480 :     for (i = 0; i < list->len; i += 2) {
    1378                 :    9977470 :         size_t pos = (size_t)list->items[i];
    1379                 :    9977470 :         size_t item = (size_t)list->items[i + 1];
    1380                 :    9977470 :         uintptr_t *pv = (uintptr_t*)(base + pos);
    1381   [ +  -  +  - ]:    9977470 :         assert(pos < size && pos != 0);
    1382                 :    9977470 :         *pv = get_reloc_for_item(item, *pv);
    1383                 :            :         // record pos in relocations list
    1384                 :            :         // TODO: save space by using delta-compression
    1385         [ -  + ]:    9977470 :         assert(pos < UINT32_MAX);
    1386                 :    9977470 :         write_uint32(s, pos);
    1387                 :            :     }
    1388                 :          6 :     write_uint32(s, 0);
    1389                 :          6 : }
    1390                 :            : 
    1391                 :            : 
    1392                 :          3 : static void jl_write_relocations(jl_serializer_state *s)
    1393                 :            : {
    1394                 :          3 :     char *base = &s->s->buf[0];
    1395                 :          3 :     jl_write_skiplist(s->relocs, base, s->s->size, &s->gctags_list);
    1396                 :          3 :     jl_write_skiplist(s->relocs, base, s->s->size, &s->relocs_list);
    1397                 :          3 : }
    1398                 :            : 
    1399                 :            : 
    1400                 :       1132 : static void jl_read_relocations(jl_serializer_state *s, uint8_t bits)
    1401                 :            : {
    1402                 :       1132 :     uintptr_t base = (uintptr_t)&s->s->buf[0];
    1403                 :       1132 :     size_t size = s->s->size;
    1404                 : 3108990000 :     while (1) {
    1405                 : 3108990000 :         uintptr_t val = (uintptr_t)&s->relocs->buf[s->relocs->bpos];
    1406                 : 3108990000 :         uint32_t offset = load_uint32(&val);
    1407                 : 3108990000 :         s->relocs->bpos += sizeof(uint32_t);
    1408         [ +  + ]: 3108990000 :         if (offset == 0)
    1409                 :       1132 :             break;
    1410                 : 3108990000 :         uintptr_t *pv = (uintptr_t*)(base + offset);
    1411                 : 3108990000 :         uintptr_t v = *pv;
    1412                 : 3108990000 :         v = get_item_for_reloc(s, base, size, v);
    1413                 : 3108990000 :         *pv = v | bits;
    1414                 :            :     }
    1415                 :       1132 : }
    1416                 :            : 
    1417                 :            : static char* sysimg_base;
    1418                 :            : static char* sysimg_relocs;
    1419                 :        644 : void gc_sweep_sysimg(void)
    1420                 :            : {
    1421                 :        644 :     uintptr_t base = (uintptr_t)sysimg_base;
    1422                 :        644 :     uintptr_t relocs = (uintptr_t)sysimg_relocs;
    1423         [ +  + ]:        644 :     if (relocs == 0)
    1424                 :          1 :         return;
    1425                 :  720784000 :     while (1) {
    1426                 :  720784000 :         uint32_t offset = load_uint32(&relocs);
    1427         [ +  + ]:  720784000 :         if (offset == 0)
    1428                 :        643 :             break;
    1429                 :  720784000 :         jl_taggedvalue_t *o = (jl_taggedvalue_t*)(base + offset);
    1430                 :  720784000 :         o->bits.gc = GC_OLD;
    1431                 :            :     }
    1432                 :            : }
    1433                 :            : 
    1434                 :            : #define jl_write_value(s, v) _jl_write_value((s), (jl_value_t*)(v))
    1435                 :        465 : static void _jl_write_value(jl_serializer_state *s, jl_value_t *v)
    1436                 :            : {
    1437         [ +  + ]:        465 :     if (v == NULL) {
    1438                 :          1 :         write_uint32(s->s, 0);
    1439                 :          1 :         return;
    1440                 :            :     }
    1441                 :        464 :     uintptr_t item = backref_id(s, v);
    1442                 :        464 :     uintptr_t reloc = get_reloc_for_item(item, 0);
    1443         [ -  + ]:        464 :     assert(reloc < UINT32_MAX);
    1444                 :        464 :     write_uint32(s->s, reloc);
    1445                 :            : }
    1446                 :            : 
    1447                 :            : 
    1448                 :      87730 : static jl_value_t *jl_read_value(jl_serializer_state *s)
    1449                 :            : {
    1450                 :      87730 :     uintptr_t base = (uintptr_t)&s->s->buf[0];
    1451                 :      87730 :     size_t size = s->s->size;
    1452                 :      87730 :     uintptr_t val = base + s->s->bpos;
    1453                 :      87730 :     uint32_t offset = load_uint32(&val);
    1454                 :      87730 :     s->s->bpos += sizeof(uint32_t);
    1455         [ +  + ]:      87730 :     if (offset == 0)
    1456                 :          1 :         return NULL;
    1457                 :      87729 :     return (jl_value_t*)get_item_for_reloc(s, base, size, offset);
    1458                 :            : }
    1459                 :            : 
    1460                 :            : 
    1461                 :        565 : static void jl_update_all_fptrs(jl_serializer_state *s)
    1462                 :            : {
    1463                 :        565 :     jl_sysimg_fptrs_t fvars = sysimg_fptrs;
    1464                 :            :     // make these NULL now so we skip trying to restore GlobalVariable pointers later
    1465                 :        565 :     sysimg_gvars_base = NULL;
    1466                 :        565 :     sysimg_fptrs.base = NULL;
    1467         [ +  + ]:        565 :     if (fvars.base == NULL)
    1468                 :          8 :         return;
    1469                 :        557 :     int sysimg_fvars_max = s->fptr_record->size / sizeof(void*);
    1470                 :            :     size_t i;
    1471                 :        557 :     uintptr_t base = (uintptr_t)&s->s->buf[0];
    1472                 :            :     // These will become MethodInstance references, but they start out as a list of
    1473                 :            :     // offsets into `s` for CodeInstances
    1474                 :        557 :     jl_method_instance_t **linfos = (jl_method_instance_t**)&s->fptr_record->buf[0];
    1475                 :        557 :     uint32_t clone_idx = 0;
    1476         [ +  + ]:   15872300 :     for (i = 0; i < sysimg_fvars_max; i++) {
    1477                 :   15871700 :         uintptr_t val = (uintptr_t)&linfos[i];
    1478                 :   15871700 :         uint32_t offset = load_uint32(&val);
    1479                 :   15871700 :         linfos[i] = NULL;
    1480         [ +  + ]:   15871700 :         if (offset != 0) {
    1481                 :   15642800 :             int specfunc = 1;
    1482         [ +  + ]:   15642800 :             if (offset & ((uintptr_t)1 << (8 * sizeof(uint32_t) - 1))) {
    1483                 :            :                 // if high bit is set, this is the func wrapper, not the specfunc
    1484                 :    7343490 :                 specfunc = 0;
    1485                 :    7343490 :                 offset = ~offset;
    1486                 :            :             }
    1487                 :   15642800 :             jl_code_instance_t *codeinst = (jl_code_instance_t*)(base + offset);
    1488                 :   15642800 :             uintptr_t base = (uintptr_t)fvars.base;
    1489   [ +  -  +  - ]:   15642800 :             assert(jl_is_method(codeinst->def->def.method) && codeinst->invoke != jl_fptr_const_return);
    1490   [ +  +  -  + ]:   15642800 :             assert(specfunc ? codeinst->invoke != NULL : codeinst->invoke == NULL);
    1491                 :   15642800 :             linfos[i] = codeinst->def;     // now it's a MethodInstance
    1492                 :   15642800 :             int32_t offset = fvars.offsets[i];
    1493         [ -  + ]:   15642800 :             for (; clone_idx < fvars.nclones; clone_idx++) {
    1494                 :          0 :                 uint32_t idx = fvars.clone_idxs[clone_idx] & jl_sysimg_val_mask;
    1495         [ #  # ]:          0 :                 if (idx < i)
    1496                 :          0 :                     continue;
    1497         [ #  # ]:          0 :                 if (idx == i)
    1498                 :          0 :                     offset = fvars.clone_offsets[clone_idx];
    1499                 :          0 :                 break;
    1500                 :            :             }
    1501                 :   15642800 :             void *fptr = (void*)(base + offset);
    1502         [ +  + ]:   15642800 :             if (specfunc) {
    1503                 :    8299300 :                 codeinst->specptr.fptr = fptr;
    1504                 :    8299300 :                 codeinst->isspecsig = 1; // TODO: set only if confirmed to be true
    1505                 :            :             }
    1506                 :            :             else {
    1507                 :    7343490 :                 codeinst->invoke = (jl_callptr_t)fptr;
    1508                 :            :             }
    1509                 :            :         }
    1510                 :            :     }
    1511                 :            :     // Tell LLVM about the native code
    1512                 :        557 :     jl_register_fptrs(sysimage_base, &fvars, linfos, sysimg_fvars_max);
    1513                 :            : }
    1514                 :            : 
    1515                 :            : 
    1516                 :            : // Pointer relocation for native-code referenced global variables
    1517                 :        566 : static void jl_update_all_gvars(jl_serializer_state *s)
    1518                 :            : {
    1519         [ +  + ]:        566 :     if (sysimg_gvars_base == NULL)
    1520                 :          8 :         return;
    1521                 :        558 :     size_t gvname_index = 0;
    1522                 :        558 :     uintptr_t base = (uintptr_t)&s->s->buf[0];
    1523                 :        558 :     size_t size = s->s->size;
    1524                 :        558 :     uintptr_t gvars = (uintptr_t)&s->gvar_record->buf[0];
    1525                 :        558 :     uintptr_t end = gvars + s->gvar_record->size;
    1526         [ +  + ]:    8630590 :     while (gvars < end) {
    1527                 :    8630030 :         uint32_t offset = load_uint32(&gvars);
    1528         [ +  + ]:    8630030 :         if (offset) {
    1529                 :    8628910 :             uintptr_t v = get_item_for_reloc(s, base, size, offset);
    1530                 :    8628910 :             *sysimg_gvars(sysimg_gvars_base, gvname_index) = v;
    1531                 :            :         }
    1532                 :    8630030 :         gvname_index += 1;
    1533                 :            :     }
    1534                 :            : }
    1535                 :            : 
    1536                 :            : 
    1537                 :            : // Reinitialization
    1538                 :          6 : static void jl_finalize_serializer(jl_serializer_state *s, arraylist_t *list)
    1539                 :            : {
    1540                 :            :     size_t i, l;
    1541                 :            : 
    1542                 :            :     // record list of reinitialization functions
    1543                 :          6 :     l = list->len;
    1544         [ +  + ]:       6016 :     for (i = 0; i < l; i += 2) {
    1545                 :       6010 :         size_t item = (size_t)list->items[i];
    1546                 :       6010 :         size_t reloc_offset = (size_t)layout_table.items[item];
    1547         [ -  + ]:       6010 :         assert(reloc_offset != 0);
    1548                 :       6010 :         write_uint32(s->s, (uint32_t)reloc_offset);
    1549                 :       6010 :         write_uint32(s->s, (uint32_t)((uintptr_t)list->items[i + 1]));
    1550                 :            :     }
    1551                 :          6 :     write_uint32(s->s, 0);
    1552                 :          6 : }
    1553                 :            : 
    1554                 :            : 
    1555                 :    1695000 : static void jl_reinit_item(jl_value_t *v, int how) JL_GC_DISABLED
    1556                 :            : {
    1557   [ +  +  -  - ]:    1695000 :     switch (how) {
    1558                 :    1621550 :         case 1: { // rehash IdDict
    1559                 :    1621550 :             jl_array_t **a = (jl_array_t**)v;
    1560         [ -  + ]:    1621550 :             assert(jl_is_array(*a));
    1561                 :            :             // Assume *a don't need a write barrier
    1562                 :    1621550 :             *a = jl_idtable_rehash(*a, jl_array_len(*a));
    1563                 :    1621550 :             jl_gc_wb(v, *a);
    1564                 :    1621550 :             break;
    1565                 :            :         }
    1566                 :      73452 :         case 2: { // rebuild the binding table for module v
    1567                 :      73452 :             jl_module_t *mod = (jl_module_t*)v;
    1568         [ -  + ]:      73452 :             assert(jl_is_module(mod));
    1569                 :      73452 :             size_t nbindings = mod->bindings.size;
    1570                 :      73452 :             htable_new(&mod->bindings, nbindings);
    1571                 :            :             struct binding {
    1572                 :            :                 jl_sym_t *asname;
    1573                 :            :                 uintptr_t tag;
    1574                 :            :                 jl_binding_t b;
    1575                 :            :             } *b;
    1576                 :      73452 :             b = (struct binding*)&mod[1];
    1577         [ +  + ]:   19421900 :             while (nbindings > 0) {
    1578                 :   19348400 :                 ptrhash_put(&mod->bindings, b->asname, &b->b);
    1579                 :   19348400 :                 b += 1;
    1580                 :   19348400 :                 nbindings -= 1;
    1581                 :            :             }
    1582         [ -  + ]:      73452 :             if (mod->usings.items != &mod->usings._space[0]) {
    1583                 :          0 :                 void **newitems = (void**)malloc_s(mod->usings.max * sizeof(void*));
    1584                 :          0 :                 memcpy(newitems, mod->usings.items, mod->usings.len * sizeof(void*));
    1585                 :          0 :                 mod->usings.items = newitems;
    1586                 :            :             }
    1587                 :      73452 :             break;
    1588                 :            :         }
    1589                 :          0 :         case 3: { // install ccallable entry point in JIT
    1590                 :          0 :             jl_svec_t *sv = ((jl_method_t*)v)->ccallable;
    1591                 :          0 :             int success = jl_compile_extern_c(NULL, NULL, jl_sysimg_handle, jl_svecref(sv, 0), jl_svecref(sv, 1));
    1592         [ #  # ]:          0 :             assert(success); (void)success;
    1593                 :          0 :             break;
    1594                 :            :         }
    1595                 :          0 :         default:
    1596                 :          0 :             assert(0 && "corrupt deserialization state");
    1597                 :            :             abort();
    1598                 :            :     }
    1599                 :    1695000 : }
    1600                 :            : 
    1601                 :            : 
    1602                 :       1131 : static void jl_finalize_deserializer(jl_serializer_state *s) JL_GC_DISABLED
    1603                 :            : {
    1604                 :            :     // run reinitialization functions
    1605                 :       1131 :     uintptr_t base = (uintptr_t)&s->s->buf[0];
    1606                 :    1695000 :     while (1) {
    1607                 :    1696130 :         size_t offset = read_uint32(s->s);
    1608         [ +  + ]:    1696130 :         if (offset == 0)
    1609                 :       1131 :             break;
    1610                 :    1695000 :         jl_value_t *v = (jl_value_t*)(base + offset);
    1611                 :    1695000 :         jl_reinit_item(v, read_uint32(s->s));
    1612                 :            :     }
    1613                 :       1131 : }
    1614                 :            : 
    1615                 :            : 
    1616                 :            : 
    1617                 :            : // Code below helps slim down the images
    1618                 :      53436 : static void jl_scan_type_cache_gv(jl_serializer_state *s, jl_svec_t *cache)
    1619                 :            : {
    1620                 :      53436 :     size_t l = jl_svec_len(cache), i;
    1621         [ +  + ]:     418182 :     for (i = 0; i < l; i++) {
    1622                 :     364746 :         jl_value_t *ti = jl_svecref(cache, i);
    1623   [ +  +  +  + ]:     364746 :         if (ti == NULL || ti == jl_nothing)
    1624                 :     247869 :             continue;
    1625         [ +  + ]:     116877 :         if (jl_get_llvm_gv(native_functions, ti)) {
    1626                 :       2825 :             jl_serialize_value(s, ti);
    1627                 :            :         }
    1628         [ +  - ]:     114052 :         else if (jl_is_datatype(ti)) {
    1629                 :     114052 :             jl_value_t *singleton = ((jl_datatype_t*)ti)->instance;
    1630   [ +  +  +  + ]:     114052 :             if (singleton && jl_get_llvm_gv(native_functions, singleton))
    1631                 :         83 :                 jl_serialize_value(s, ti);
    1632                 :            :         }
    1633                 :            :     }
    1634                 :      53436 : }
    1635                 :            : 
    1636                 :            : // remove cached types not referenced in the stream
    1637                 :      26718 : static void jl_prune_type_cache_hash(jl_svec_t *cache)
    1638                 :            : {
    1639                 :      26718 :     size_t l = jl_svec_len(cache), i;
    1640         [ +  + ]:     388798 :     for (i = 0; i < l; i++) {
    1641                 :     362080 :         jl_value_t *ti = jl_svecref(cache, i);
    1642   [ +  +  +  + ]:     362080 :         if (ti == NULL || ti == jl_nothing)
    1643                 :     247170 :             continue;
    1644         [ +  + ]:     114910 :         if (ptrhash_get(&backref_table, ti) == HT_NOTFOUND)
    1645                 :       6693 :             jl_svecset(cache, i, jl_nothing);
    1646                 :            :     }
    1647                 :      26718 : }
    1648                 :            : 
    1649                 :      26718 : static void jl_prune_type_cache_linear(jl_svec_t *cache)
    1650                 :            : {
    1651                 :      26718 :     size_t l = jl_svec_len(cache), ins = 0, i;
    1652         [ +  + ]:      28685 :     for (i = 0; i < l; i++) {
    1653                 :       2040 :         jl_value_t *ti = jl_svecref(cache, i);
    1654         [ +  + ]:       2040 :         if (ti == NULL)
    1655                 :         73 :             break;
    1656         [ +  + ]:       1967 :         if (ptrhash_get(&backref_table, ti) != HT_NOTFOUND)
    1657                 :       1683 :             jl_svecset(cache, ins++, ti);
    1658                 :            :     }
    1659         [ +  + ]:      26718 :     if (i > ins) {
    1660                 :         25 :         memset(&jl_svec_data(cache)[ins], 0, (i - ins) * sizeof(jl_value_t*));
    1661                 :            :     }
    1662                 :      26718 : }
    1663                 :            : 
    1664                 :          0 : static jl_value_t *strip_codeinfo_meta(jl_method_t *m, jl_value_t *ci_, int orig)
    1665                 :            : {
    1666                 :          0 :     jl_code_info_t *ci = NULL;
    1667                 :          0 :     JL_GC_PUSH1(&ci);
    1668                 :          0 :     int compressed = 0;
    1669         [ #  # ]:          0 :     if (!jl_is_code_info(ci_)) {
    1670                 :          0 :         compressed = 1;
    1671                 :          0 :         ci = jl_uncompress_ir(m, NULL, (jl_array_t*)ci_);
    1672                 :            :     }
    1673                 :            :     else {
    1674                 :          0 :         ci = (jl_code_info_t*)ci_;
    1675                 :            :     }
    1676                 :            :     // leave codelocs length the same so the compiler can assume that; just zero it
    1677                 :          0 :     memset(jl_array_data(ci->codelocs), 0, jl_array_len(ci->codelocs)*sizeof(int32_t));
    1678                 :            :     // empty linetable
    1679         [ #  # ]:          0 :     if (jl_is_array(ci->linetable))
    1680                 :          0 :         jl_array_del_end((jl_array_t*)ci->linetable, jl_array_len(ci->linetable));
    1681                 :            :     // replace slot names with `?`, except unused_sym since the compiler looks at it
    1682                 :          0 :     jl_sym_t *questionsym = jl_symbol("?");
    1683                 :          0 :     int i, l = jl_array_len(ci->slotnames);
    1684         [ #  # ]:          0 :     for (i = 0; i < l; i++) {
    1685                 :          0 :         jl_value_t *s = jl_array_ptr_ref(ci->slotnames, i);
    1686         [ #  # ]:          0 :         if (s != (jl_value_t*)jl_unused_sym)
    1687                 :          0 :             jl_array_ptr_set(ci->slotnames, i, questionsym);
    1688                 :            :     }
    1689         [ #  # ]:          0 :     if (orig) {
    1690                 :          0 :         m->slot_syms = jl_compress_argnames(ci->slotnames);
    1691                 :          0 :         jl_gc_wb(m, m->slot_syms);
    1692                 :            :     }
    1693                 :          0 :     jl_value_t *ret = (jl_value_t*)ci;
    1694         [ #  # ]:          0 :     if (compressed)
    1695                 :          0 :         ret = (jl_value_t*)jl_compress_ir(m, ci);
    1696                 :          0 :     JL_GC_POP();
    1697                 :          0 :     return ret;
    1698                 :            : }
    1699                 :            : 
    1700                 :          0 : static void record_field_change(jl_value_t **addr, jl_value_t *newval)
    1701                 :            : {
    1702                 :          0 :     ptrhash_put(&field_replace, (void*)addr, newval);
    1703                 :          0 : }
    1704                 :            : 
    1705                 :          0 : static void strip_specializations_(jl_method_instance_t *mi)
    1706                 :            : {
    1707         [ #  # ]:          0 :     assert(jl_is_method_instance(mi));
    1708                 :          0 :     jl_code_instance_t *codeinst = mi->cache;
    1709         [ #  # ]:          0 :     while (codeinst) {
    1710   [ #  #  #  # ]:          0 :         if (codeinst->inferred && codeinst->inferred != jl_nothing) {
    1711         [ #  # ]:          0 :             if (jl_options.strip_ir) {
    1712                 :          0 :                 record_field_change(&codeinst->inferred, jl_nothing);
    1713                 :            :             }
    1714         [ #  # ]:          0 :             else if (jl_options.strip_metadata) {
    1715                 :          0 :                 codeinst->inferred = strip_codeinfo_meta(mi->def.method, codeinst->inferred, 0);
    1716                 :          0 :                 jl_gc_wb(codeinst, codeinst->inferred);
    1717                 :            :             }
    1718                 :            :         }
    1719                 :          0 :         codeinst = jl_atomic_load_relaxed(&codeinst->next);
    1720                 :            :     }
    1721         [ #  # ]:          0 :     if (jl_options.strip_ir) {
    1722                 :          0 :         record_field_change(&mi->uninferred, NULL);
    1723                 :            :     }
    1724                 :          0 : }
    1725                 :            : 
    1726                 :          0 : static int strip_all_codeinfos__(jl_typemap_entry_t *def, void *_env)
    1727                 :            : {
    1728                 :          0 :     jl_method_t *m = def->func.method;
    1729         [ #  # ]:          0 :     if (m->source) {
    1730                 :          0 :         int stripped_ir = 0;
    1731         [ #  # ]:          0 :         if (jl_options.strip_ir) {
    1732         [ #  # ]:          0 :             if (m->unspecialized) {
    1733                 :          0 :                 jl_code_instance_t *unspec = jl_atomic_load_relaxed(&m->unspecialized->cache);
    1734   [ #  #  #  # ]:          0 :                 if (unspec && jl_atomic_load_relaxed(&unspec->invoke)) {
    1735                 :            :                     // we have a generic compiled version, so can remove the IR
    1736                 :          0 :                     record_field_change(&m->source, jl_nothing);
    1737                 :          0 :                     stripped_ir = 1;
    1738                 :            :                 }
    1739                 :            :             }
    1740         [ #  # ]:          0 :             if (!stripped_ir) {
    1741                 :          0 :                 int mod_setting = jl_get_module_compile(m->module);
    1742                 :            :                 // if the method is declared not to be compiled, keep IR for interpreter
    1743   [ #  #  #  # ]:          0 :                 if (!(mod_setting == JL_OPTIONS_COMPILE_OFF || mod_setting == JL_OPTIONS_COMPILE_MIN)) {
    1744                 :          0 :                     record_field_change(&m->source, jl_nothing);
    1745                 :          0 :                     stripped_ir = 1;
    1746                 :            :                 }
    1747                 :            :             }
    1748                 :            :         }
    1749   [ #  #  #  # ]:          0 :         if (jl_options.strip_metadata && !stripped_ir) {
    1750                 :          0 :             m->source = strip_codeinfo_meta(m, m->source, 1);
    1751                 :          0 :             jl_gc_wb(m, m->source);
    1752                 :            :         }
    1753                 :            :     }
    1754                 :          0 :     jl_svec_t *specializations = m->specializations;
    1755                 :          0 :     size_t i, l = jl_svec_len(specializations);
    1756         [ #  # ]:          0 :     for (i = 0; i < l; i++) {
    1757                 :          0 :         jl_value_t *mi = jl_svecref(specializations, i);
    1758         [ #  # ]:          0 :         if (mi != jl_nothing)
    1759                 :          0 :             strip_specializations_((jl_method_instance_t*)mi);
    1760                 :            :     }
    1761         [ #  # ]:          0 :     if (m->unspecialized)
    1762                 :          0 :         strip_specializations_(m->unspecialized);
    1763                 :          0 :     return 1;
    1764                 :            : }
    1765                 :            : 
    1766                 :          0 : static int strip_all_codeinfos_(jl_methtable_t *mt, void *_env)
    1767                 :            : {
    1768                 :          0 :     return jl_typemap_visitor(mt->defs, strip_all_codeinfos__, NULL);
    1769                 :            : }
    1770                 :            : 
    1771                 :          0 : static void jl_strip_all_codeinfos(void)
    1772                 :            : {
    1773                 :          0 :     jl_foreach_reachable_mtable(strip_all_codeinfos_, NULL);
    1774                 :          0 : }
    1775                 :            : 
    1776                 :            : // Method roots created during sysimg construction are exempted from
    1777                 :            : // triggering non-relocatability of compressed CodeInfos.
    1778                 :            : // Set the number of such roots in each method when the sysimg is
    1779                 :            : // serialized.
    1780                 :      66473 : static int set_nroots_sysimg__(jl_typemap_entry_t *def, void *_env)
    1781                 :            : {
    1782                 :      66473 :     jl_method_t *m = def->func.method;
    1783         [ +  + ]:      66473 :     m->nroots_sysimg = m->roots ? jl_array_len(m->roots) : 0;
    1784                 :      66473 :     return 1;
    1785                 :            : }
    1786                 :            : 
    1787                 :      24161 : static int set_nroots_sysimg_(jl_methtable_t *mt, void *_env)
    1788                 :            : {
    1789                 :      24161 :     return jl_typemap_visitor(mt->defs, set_nroots_sysimg__, NULL);
    1790                 :            : }
    1791                 :            : 
    1792                 :          3 : static void jl_set_nroots_sysimg(void)
    1793                 :            : {
    1794                 :          3 :     jl_foreach_reachable_mtable(set_nroots_sysimg_, NULL);
    1795                 :          3 : }
    1796                 :            : 
    1797                 :            : // --- entry points ---
    1798                 :            : 
    1799                 :            : static void jl_init_serializer2(int);
    1800                 :            : static void jl_cleanup_serializer2(void);
    1801                 :            : 
    1802                 :          3 : static void jl_save_system_image_to_stream(ios_t *f) JL_GC_DISABLED
    1803                 :            : {
    1804                 :          3 :     jl_gc_collect(JL_GC_FULL);
    1805                 :          3 :     jl_gc_collect(JL_GC_INCREMENTAL);   // sweep finalizers
    1806                 :            :     JL_TIMING(SYSIMG_DUMP);
    1807                 :            : 
    1808                 :          3 :     htable_new(&field_replace, 10000);
    1809                 :            :     // strip metadata and IR when requested
    1810   [ +  -  -  + ]:          3 :     if (jl_options.strip_metadata || jl_options.strip_ir)
    1811                 :          0 :         jl_strip_all_codeinfos();
    1812                 :          3 :     jl_set_nroots_sysimg();
    1813                 :            : 
    1814                 :          3 :     int en = jl_gc_enable(0);
    1815                 :          3 :     jl_init_serializer2(1);
    1816                 :          3 :     htable_reset(&backref_table, 250000);
    1817                 :          3 :     arraylist_new(&reinit_list, 0);
    1818                 :          3 :     arraylist_new(&ccallable_list, 0);
    1819                 :          3 :     arraylist_new(&object_worklist, 0);
    1820                 :          3 :     backref_table_numel = 0;
    1821                 :            :     ios_t sysimg, const_data, symbols, relocs, gvar_record, fptr_record;
    1822                 :          3 :     ios_mem(&sysimg,     1000000);
    1823                 :          3 :     ios_mem(&const_data,  100000);
    1824                 :          3 :     ios_mem(&symbols,     100000);
    1825                 :          3 :     ios_mem(&relocs,      100000);
    1826                 :          3 :     ios_mem(&gvar_record, 100000);
    1827                 :          3 :     ios_mem(&fptr_record, 100000);
    1828                 :            :     jl_serializer_state s;
    1829                 :          3 :     s.s = &sysimg;
    1830                 :          3 :     s.const_data = &const_data;
    1831                 :          3 :     s.symbols = &symbols;
    1832                 :          3 :     s.relocs = &relocs;
    1833                 :          3 :     s.gvar_record = &gvar_record;
    1834                 :          3 :     s.fptr_record = &fptr_record;
    1835                 :          3 :     s.ptls = jl_current_task->ptls;
    1836                 :          3 :     arraylist_new(&s.relocs_list, 0);
    1837                 :          3 :     arraylist_new(&s.gctags_list, 0);
    1838                 :          3 :     jl_value_t **const*const tags = get_tags();
    1839                 :            : 
    1840                 :            :     // empty!(Core.ARGS)
    1841         [ +  - ]:          3 :     if (jl_core_module != NULL) {
    1842                 :          3 :         jl_array_t *args = (jl_array_t*)jl_get_global(jl_core_module, jl_symbol("ARGS"));
    1843         [ +  - ]:          3 :         if (args != NULL) {
    1844                 :          3 :             jl_array_del_end(args, jl_array_len(args));
    1845                 :            :         }
    1846                 :            :     }
    1847                 :            : 
    1848         [ +  + ]:          3 :     jl_idtable_type = jl_base_module ? jl_get_global(jl_base_module, jl_symbol("IdDict")) : NULL;
    1849         [ +  + ]:          3 :     jl_idtable_typename = jl_base_module ? ((jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)jl_idtable_type))->name : NULL;
    1850         [ +  + ]:          3 :     jl_bigint_type = jl_base_module ? jl_get_global(jl_base_module, jl_symbol("BigInt")) : NULL;
    1851         [ +  + ]:          3 :     if (jl_bigint_type) {
    1852                 :          2 :         gmp_limb_size = jl_unbox_long(jl_get_global((jl_module_t*)jl_get_global(jl_base_module, jl_symbol("GMP")),
    1853                 :          2 :                                                     jl_symbol("BITS_PER_LIMB"))) / 8;
    1854                 :            :     }
    1855         [ +  + ]:          3 :     if (jl_base_module) {
    1856                 :          2 :         jl_value_t *docs = jl_get_global(jl_base_module, jl_symbol("Docs"));
    1857   [ +  -  +  - ]:          2 :         if (docs && jl_is_module(docs)) {
    1858                 :          2 :             jl_docmeta_sym = (jl_sym_t*)jl_get_global((jl_module_t*)docs, jl_symbol("META"));
    1859                 :            :         }
    1860                 :            :     }
    1861                 :            : 
    1862                 :            :     { // step 1: record values (recursively) that need to go in the image
    1863                 :            :         size_t i;
    1864         [ +  + ]:        465 :         for (i = 0; tags[i] != NULL; i++) {
    1865                 :        462 :             jl_value_t *tag = *tags[i];
    1866                 :        462 :             jl_serialize_value(&s, tag);
    1867                 :            :         }
    1868                 :          3 :         jl_serialize_reachable(&s);
    1869                 :            :         // step 1.1: check for values only found in the generated code
    1870                 :            :         arraylist_t typenames;
    1871                 :          3 :         arraylist_new(&typenames, 0);
    1872         [ +  + ]:    3407880 :         for (i = 0; i < backref_table.size; i += 2) {
    1873                 :    3407870 :             jl_typename_t *tn = (jl_typename_t*)backref_table.table[i];
    1874   [ +  +  +  + ]:    3407870 :             if (tn == HT_NOTFOUND || !jl_is_typename(tn))
    1875                 :    3381150 :                 continue;
    1876                 :      26718 :             arraylist_push(&typenames, tn);
    1877                 :            :         }
    1878         [ +  + ]:      26721 :         for (i = 0; i < typenames.len; i++) {
    1879                 :      26718 :             jl_typename_t *tn = (jl_typename_t*)typenames.items[i];
    1880                 :      26718 :             jl_scan_type_cache_gv(&s, tn->cache);
    1881                 :      26718 :             jl_scan_type_cache_gv(&s, tn->linearcache);
    1882                 :            :         }
    1883                 :          3 :         jl_serialize_reachable(&s);
    1884                 :            :         // step 1.2: prune (garbage collect) some special weak references from
    1885                 :            :         // built-in type caches
    1886         [ +  + ]:      26721 :         for (i = 0; i < typenames.len; i++) {
    1887                 :      26718 :             jl_typename_t *tn = (jl_typename_t*)typenames.items[i];
    1888                 :      26718 :             jl_prune_type_cache_hash(tn->cache);
    1889                 :      26718 :             jl_prune_type_cache_linear(tn->linearcache);
    1890                 :            :         }
    1891                 :          3 :         arraylist_free(&typenames);
    1892                 :            :     }
    1893                 :            : 
    1894                 :            :     { // step 2: build all the sysimg sections
    1895                 :          3 :         write_padding(&sysimg, sizeof(uint32_t));
    1896                 :          3 :         jl_write_values(&s);
    1897                 :          3 :         jl_write_relocations(&s);
    1898                 :          3 :         jl_write_gv_syms(&s, jl_get_root_symbol());
    1899                 :          3 :         jl_write_gv_tagrefs(&s);
    1900                 :            :     }
    1901                 :            : 
    1902         [ +  - ]:          3 :     if (sysimg.size > ((uintptr_t)1 << RELOC_TAG_OFFSET) ||
    1903         [ -  + ]:          3 :         const_data.size > ((uintptr_t)1 << RELOC_TAG_OFFSET)*sizeof(void*)) {
    1904                 :          0 :         jl_printf(JL_STDERR, "ERROR: system image too large\n");
    1905                 :          0 :         jl_exit(1);
    1906                 :            :     }
    1907                 :            : 
    1908                 :            :     // step 3: combine all of the sections into one file
    1909                 :          3 :     write_uint32(f, sysimg.size - sizeof(uint32_t));
    1910                 :          3 :     ios_seek(&sysimg, sizeof(uint32_t));
    1911                 :          3 :     ios_copyall(f, &sysimg);
    1912                 :          3 :     ios_close(&sysimg);
    1913                 :            : 
    1914                 :          3 :     write_uint32(f, const_data.size);
    1915                 :            :     // realign stream to max-alignment for data
    1916                 :          3 :     write_padding(f, LLT_ALIGN(ios_pos(f), 16) - ios_pos(f));
    1917                 :          3 :     ios_seek(&const_data, 0);
    1918                 :          3 :     ios_copyall(f, &const_data);
    1919                 :          3 :     ios_close(&const_data);
    1920                 :            : 
    1921                 :          3 :     write_uint32(f, symbols.size);
    1922                 :          3 :     ios_seek(&symbols, 0);
    1923                 :          3 :     ios_copyall(f, &symbols);
    1924                 :          3 :     ios_close(&symbols);
    1925                 :            : 
    1926                 :          3 :     write_uint32(f, relocs.size);
    1927                 :          3 :     ios_seek(&relocs, 0);
    1928                 :          3 :     ios_copyall(f, &relocs);
    1929                 :          3 :     ios_close(&relocs);
    1930                 :            : 
    1931                 :          3 :     write_uint32(f, gvar_record.size);
    1932                 :          3 :     ios_seek(&gvar_record, 0);
    1933                 :          3 :     ios_copyall(f, &gvar_record);
    1934                 :          3 :     ios_close(&gvar_record);
    1935                 :            : 
    1936                 :          3 :     write_uint32(f, fptr_record.size);
    1937                 :          3 :     ios_seek(&fptr_record, 0);
    1938                 :          3 :     ios_copyall(f, &fptr_record);
    1939                 :          3 :     ios_close(&fptr_record);
    1940                 :            : 
    1941                 :            :     { // step 4: record locations of special roots
    1942                 :          3 :         s.s = f;
    1943                 :            :         size_t i;
    1944         [ +  + ]:        465 :         for (i = 0; tags[i] != NULL; i++) {
    1945                 :        462 :             jl_value_t *tag = *tags[i];
    1946                 :        462 :             jl_write_value(&s, tag);
    1947                 :            :         }
    1948                 :          3 :         jl_write_value(&s, s.ptls->root_task->tls);
    1949                 :          3 :         write_uint32(f, jl_get_gs_ctr());
    1950                 :          3 :         write_uint32(f, jl_atomic_load_acquire(&jl_world_counter));
    1951                 :          3 :         write_uint32(f, jl_typeinf_world);
    1952                 :          3 :         jl_finalize_serializer(&s, &reinit_list);
    1953                 :          3 :         jl_finalize_serializer(&s, &ccallable_list);
    1954                 :            :     }
    1955                 :            : 
    1956         [ -  + ]:          3 :     assert(object_worklist.len == 0);
    1957                 :          3 :     arraylist_free(&object_worklist);
    1958                 :          3 :     arraylist_free(&layout_table);
    1959                 :          3 :     arraylist_free(&reinit_list);
    1960                 :          3 :     arraylist_free(&ccallable_list);
    1961                 :          3 :     arraylist_free(&s.relocs_list);
    1962                 :          3 :     arraylist_free(&s.gctags_list);
    1963                 :          3 :     htable_free(&field_replace);
    1964                 :          3 :     jl_cleanup_serializer2();
    1965                 :            : 
    1966                 :          3 :     jl_gc_enable(en);
    1967                 :          3 : }
    1968                 :            : 
    1969                 :          1 : JL_DLLEXPORT ios_t *jl_create_system_image(void *_native_data)
    1970                 :            : {
    1971                 :          1 :     ios_t *f = (ios_t*)malloc_s(sizeof(ios_t));
    1972                 :          1 :     ios_mem(f, 0);
    1973                 :          1 :     native_functions = _native_data;
    1974                 :          1 :     jl_save_system_image_to_stream(f);
    1975                 :          1 :     return f;
    1976                 :            : }
    1977                 :            : 
    1978                 :            : JL_DLLEXPORT size_t ios_write_direct(ios_t *dest, ios_t *src);
    1979                 :          2 : JL_DLLEXPORT void jl_save_system_image(const char *fname)
    1980                 :            : {
    1981                 :            :     ios_t f;
    1982         [ -  + ]:          2 :     if (ios_file(&f, fname, 1, 1, 1, 1) == NULL) {
    1983                 :          0 :         jl_errorf("cannot open system image file \"%s\" for writing", fname);
    1984                 :            :     }
    1985                 :          2 :     JL_SIGATOMIC_BEGIN();
    1986                 :          2 :     jl_save_system_image_to_stream(&f);
    1987                 :          2 :     ios_close(&f);
    1988         [ +  - ]:          2 :     JL_SIGATOMIC_END();
    1989                 :          2 : }
    1990                 :            : 
    1991                 :            : // Takes in a path of the form "usr/lib/julia/sys.so" (jl_restore_system_image should be passed the same string)
    1992                 :        572 : JL_DLLEXPORT void jl_preload_sysimg_so(const char *fname)
    1993                 :            : {
    1994         [ -  + ]:        572 :     if (jl_sysimg_handle)
    1995                 :          0 :         return; // embedded target already called jl_set_sysimg_so
    1996                 :            : 
    1997                 :        572 :     char *dot = (char*) strrchr(fname, '.');
    1998   [ +  +  +  + ]:        572 :     int is_ji = (dot && !strcmp(dot, ".ji"));
    1999                 :            : 
    2000                 :            :     // Get handle to sys.so
    2001         [ +  + ]:        572 :     if (!is_ji) // .ji extension => load .ji file only
    2002                 :        566 :         jl_set_sysimg_so(jl_load_dynamic_library(fname, JL_RTLD_LOCAL | JL_RTLD_NOW, 1));
    2003                 :            : }
    2004                 :            : 
    2005                 :            : // Allow passing in a module handle directly, rather than a path
    2006                 :        564 : JL_DLLEXPORT void jl_set_sysimg_so(void *handle)
    2007                 :            : {
    2008                 :            :     void* *jl_RTLD_DEFAULT_handle_pointer;
    2009                 :        564 :     int symbol_found = jl_dlsym(handle, "jl_RTLD_DEFAULT_handle_pointer", (void **)&jl_RTLD_DEFAULT_handle_pointer, 0);
    2010   [ +  +  -  + ]:        564 :     if (!symbol_found || (void*)&jl_RTLD_DEFAULT_handle != *jl_RTLD_DEFAULT_handle_pointer)
    2011                 :          1 :         jl_error("System image file failed consistency check: maybe opened the wrong version?");
    2012         [ +  + ]:        563 :     if (jl_options.cpu_target == NULL)
    2013                 :          3 :         jl_options.cpu_target = "native";
    2014                 :        563 :     jl_sysimg_handle = handle;
    2015                 :        563 :     sysimg_fptrs = jl_init_processor_sysimg(handle);
    2016                 :        560 : }
    2017                 :            : 
    2018                 :        566 : static void jl_restore_system_image_from_stream(ios_t *f) JL_GC_DISABLED
    2019                 :            : {
    2020                 :            :     JL_TIMING(SYSIMG_LOAD);
    2021                 :        566 :     int en = jl_gc_enable(0);
    2022                 :        566 :     jl_init_serializer2(0);
    2023                 :            :     ios_t sysimg, const_data, symbols, relocs, gvar_record, fptr_record;
    2024                 :            :     jl_serializer_state s;
    2025                 :        566 :     s.s = NULL;
    2026                 :        566 :     s.const_data = &const_data;
    2027                 :        566 :     s.symbols = &symbols;
    2028                 :        566 :     s.relocs = &relocs;
    2029                 :        566 :     s.gvar_record = &gvar_record;
    2030                 :        566 :     s.fptr_record = &fptr_record;
    2031                 :        566 :     s.ptls = jl_current_task->ptls;
    2032                 :        566 :     arraylist_new(&s.relocs_list, 0);
    2033                 :        566 :     arraylist_new(&s.gctags_list, 0);
    2034                 :        566 :     jl_value_t **const*const tags = get_tags();
    2035                 :            : 
    2036                 :            :     // step 1: read section map
    2037   [ +  -  +  - ]:        566 :     assert(ios_pos(f) == 0 && f->bm == bm_mem);
    2038                 :        566 :     size_t sizeof_sysimg = read_uint32(f);
    2039                 :        566 :     ios_static_buffer(&sysimg, f->buf, sizeof_sysimg + sizeof(uint32_t));
    2040                 :        566 :     ios_skip(f, sizeof_sysimg);
    2041                 :            : 
    2042                 :        566 :     size_t sizeof_constdata = read_uint32(f);
    2043                 :            :     // realign stream to max-alignment for data
    2044                 :        566 :     ios_seek(f, LLT_ALIGN(ios_pos(f), 16));
    2045                 :        566 :     ios_static_buffer(&const_data, f->buf + f->bpos, sizeof_constdata);
    2046                 :        566 :     ios_skip(f, sizeof_constdata);
    2047                 :            : 
    2048                 :        566 :     size_t sizeof_symbols = read_uint32(f);
    2049                 :        566 :     ios_static_buffer(&symbols, f->buf + f->bpos, sizeof_symbols);
    2050                 :        566 :     ios_skip(f, sizeof_symbols);
    2051                 :            : 
    2052                 :        566 :     size_t sizeof_relocations = read_uint32(f);
    2053         [ -  + ]:        566 :     assert(!ios_eof(f));
    2054                 :        566 :     ios_static_buffer(&relocs, f->buf + f->bpos, sizeof_relocations);
    2055                 :        566 :     ios_skip(f, sizeof_relocations);
    2056                 :            : 
    2057                 :        566 :     size_t sizeof_gvar_record = read_uint32(f);
    2058         [ -  + ]:        566 :     assert(!ios_eof(f));
    2059                 :        566 :     ios_static_buffer(&gvar_record, f->buf + f->bpos, sizeof_gvar_record);
    2060                 :        566 :     ios_skip(f, sizeof_gvar_record);
    2061                 :            : 
    2062                 :        566 :     size_t sizeof_fptr_record = read_uint32(f);
    2063         [ -  + ]:        566 :     assert(!ios_eof(f));
    2064                 :        566 :     ios_static_buffer(&fptr_record, f->buf + f->bpos, sizeof_fptr_record);
    2065                 :        566 :     ios_skip(f, sizeof_fptr_record);
    2066                 :            : 
    2067                 :            :     // step 2: get references to special values
    2068                 :        566 :     s.s = f;
    2069                 :            :     size_t i;
    2070         [ +  + ]:      87730 :     for (i = 0; tags[i] != NULL; i++) {
    2071                 :      87164 :         jl_value_t **tag = tags[i];
    2072                 :      87164 :         *tag = jl_read_value(&s);
    2073                 :            :     }
    2074                 :            :     // set typeof extra-special values now that we have the type set by tags above
    2075                 :        566 :     jl_astaggedvalue(jl_current_task)->header = (uintptr_t)jl_task_type | jl_astaggedvalue(jl_current_task)->header;
    2076                 :        566 :     jl_astaggedvalue(jl_nothing)->header = (uintptr_t)jl_nothing_type | jl_astaggedvalue(jl_nothing)->header;
    2077                 :        566 :     s.ptls->root_task->tls = jl_read_value(&s);
    2078                 :        566 :     jl_gc_wb(s.ptls->root_task, s.ptls->root_task->tls);
    2079                 :        566 :     jl_init_int32_int64_cache();
    2080                 :        566 :     jl_init_box_caches();
    2081                 :            : 
    2082                 :        566 :     uint32_t gs_ctr = read_uint32(f);
    2083                 :        566 :     jl_atomic_store_release(&jl_world_counter, read_uint32(f));
    2084                 :        566 :     jl_typeinf_world = read_uint32(f);
    2085                 :        566 :     jl_set_gs_ctr(gs_ctr);
    2086                 :        566 :     s.s = NULL;
    2087                 :            : 
    2088                 :            :     // step 3: apply relocations
    2089         [ -  + ]:        566 :     assert(!ios_eof(f));
    2090                 :        566 :     jl_read_symbols(&s);
    2091                 :        566 :     ios_close(&symbols);
    2092                 :            : 
    2093                 :        566 :     sysimg_base = &sysimg.buf[0];
    2094                 :        566 :     sysimg_relocs = &relocs.buf[0];
    2095                 :        566 :     jl_gc_set_permalloc_region((void*)sysimg_base, (void*)(sysimg_base + sysimg.size));
    2096                 :            : 
    2097                 :        566 :     s.s = &sysimg;
    2098                 :        566 :     jl_read_relocations(&s, GC_OLD_MARKED); // gctags
    2099                 :        566 :     size_t sizeof_tags = ios_pos(&relocs);
    2100                 :            :     (void)sizeof_tags;
    2101                 :        566 :     jl_read_relocations(&s, 0); // general relocs
    2102                 :        566 :     ios_close(&relocs);
    2103                 :        566 :     ios_close(&const_data);
    2104                 :        566 :     jl_update_all_gvars(&s); // gvars relocs
    2105                 :        566 :     ios_close(&gvar_record);
    2106                 :        566 :     s.s = NULL;
    2107                 :            : 
    2108                 :        566 :     s.s = f;
    2109                 :            :     // reinit items except ccallables
    2110                 :        566 :     jl_finalize_deserializer(&s);
    2111                 :        566 :     s.s = NULL;
    2112                 :            : 
    2113                 :            :     if (0) {
    2114                 :            :         printf("sysimg size breakdown:\n"
    2115                 :            :                "     sys data: %8u\n"
    2116                 :            :                "  isbits data: %8u\n"
    2117                 :            :                "      symbols: %8u\n"
    2118                 :            :                "    tags list: %8u\n"
    2119                 :            :                "   reloc list: %8u\n"
    2120                 :            :                "    gvar list: %8u\n"
    2121                 :            :                "    fptr list: %8u\n",
    2122                 :            :             (unsigned)sizeof_sysimg,
    2123                 :            :             (unsigned)sizeof_constdata,
    2124                 :            :             (unsigned)sizeof_symbols,
    2125                 :            :             (unsigned)sizeof_tags,
    2126                 :            :             (unsigned)(sizeof_relocations - sizeof_tags),
    2127                 :            :             (unsigned)sizeof_gvar_record,
    2128                 :            :             (unsigned)sizeof_fptr_record);
    2129                 :            :     }
    2130                 :            : 
    2131                 :        566 :     s.s = &sysimg;
    2132                 :        566 :     jl_init_codegen();
    2133                 :        565 :     jl_update_all_fptrs(&s); // fptr relocs and registration
    2134                 :            :     // reinit ccallables, which require codegen to be initialized
    2135                 :        565 :     s.s = f;
    2136                 :        565 :     jl_finalize_deserializer(&s);
    2137                 :            : 
    2138                 :        565 :     ios_close(&fptr_record);
    2139                 :        565 :     ios_close(&sysimg);
    2140                 :        565 :     s.s = NULL;
    2141                 :            : 
    2142                 :        565 :     jl_gc_reset_alloc_count();
    2143                 :        565 :     jl_gc_enable(en);
    2144                 :        565 :     jl_cleanup_serializer2();
    2145                 :        565 : }
    2146                 :            : 
    2147                 :            : // TODO: need to enforce that the alignment of the buffer is suitable for vectors
    2148                 :        566 : JL_DLLEXPORT void jl_restore_system_image(const char *fname)
    2149                 :            : {
    2150                 :            : #ifndef JL_NDEBUG
    2151         [ +  - ]:        566 :     char *dot = fname ? (char*)strrchr(fname, '.') : NULL;
    2152   [ +  -  +  + ]:        566 :     int is_ji = (dot && !strcmp(dot, ".ji"));
    2153   [ +  +  -  + ]:        566 :     assert((is_ji || jl_sysimg_handle) && "System image file not preloaded");
    2154                 :            : #endif
    2155                 :            : 
    2156         [ +  + ]:        566 :     if (jl_sysimg_handle) {
    2157                 :            :         // load the pre-compiled sysimage from jl_sysimg_handle
    2158                 :        560 :         jl_load_sysimg_so();
    2159                 :            :     }
    2160                 :            :     else {
    2161                 :            :         ios_t f;
    2162         [ -  + ]:          6 :         if (ios_file(&f, fname, 1, 0, 0, 0) == NULL)
    2163                 :          0 :             jl_errorf("System image file \"%s\" not found.", fname);
    2164                 :          6 :         ios_bufmode(&f, bm_none);
    2165                 :          6 :         JL_SIGATOMIC_BEGIN();
    2166                 :          6 :         ios_seek_end(&f);
    2167                 :          6 :         size_t len = ios_pos(&f);
    2168                 :          6 :         char *sysimg = (char*)jl_gc_perm_alloc(len, 0, 64, 0);
    2169                 :          6 :         ios_seek(&f, 0);
    2170         [ -  + ]:          6 :         if (ios_readall(&f, sysimg, len) != len)
    2171                 :          0 :             jl_errorf("Error reading system image file.");
    2172                 :          6 :         ios_close(&f);
    2173                 :          6 :         ios_static_buffer(&f, sysimg, len);
    2174                 :          6 :         jl_restore_system_image_from_stream(&f);
    2175                 :          6 :         ios_close(&f);
    2176         [ +  - ]:          6 :         JL_SIGATOMIC_END();
    2177                 :            :     }
    2178                 :        565 : }
    2179                 :            : 
    2180                 :        560 : JL_DLLEXPORT void jl_restore_system_image_data(const char *buf, size_t len)
    2181                 :            : {
    2182                 :            :     ios_t f;
    2183                 :        560 :     JL_SIGATOMIC_BEGIN();
    2184                 :        560 :     ios_static_buffer(&f, (char*)buf, len);
    2185                 :        560 :     jl_restore_system_image_from_stream(&f);
    2186                 :        559 :     ios_close(&f);
    2187         [ +  - ]:        559 :     JL_SIGATOMIC_END();
    2188                 :        559 : }
    2189                 :            : 
    2190                 :            : // --- init ---
    2191                 :            : 
    2192                 :        569 : static void jl_init_serializer2(int for_serialize)
    2193                 :            : {
    2194         [ +  + ]:        569 :     if (for_serialize) {
    2195                 :          3 :         htable_new(&symbol_table, 0);
    2196                 :          3 :         htable_new(&fptr_to_id, sizeof(id_to_fptrs) / sizeof(*id_to_fptrs));
    2197                 :          3 :         htable_new(&backref_table, 0);
    2198                 :            :         uintptr_t i;
    2199         [ +  + ]:        144 :         for (i = 0; id_to_fptrs[i] != NULL; i++) {
    2200                 :        141 :             ptrhash_put(&fptr_to_id, (void*)(uintptr_t)id_to_fptrs[i], (void*)(i + 2));
    2201                 :            :         }
    2202                 :            :     }
    2203                 :            :     else {
    2204                 :        566 :         arraylist_new(&deser_sym, 0);
    2205                 :            :     }
    2206                 :        569 :     nsym_tag = 0;
    2207                 :        569 : }
    2208                 :            : 
    2209                 :        568 : static void jl_cleanup_serializer2(void)
    2210                 :            : {
    2211                 :        568 :     htable_reset(&symbol_table, 0);
    2212                 :        568 :     htable_reset(&fptr_to_id, 0);
    2213                 :        568 :     htable_reset(&backref_table, 0);
    2214                 :        568 :     arraylist_free(&deser_sym);
    2215                 :        568 : }
    2216                 :            : 
    2217                 :            : #ifdef __cplusplus
    2218                 :            : }
    2219                 :            : #endif

Generated by: LCOV version 1.14