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
|