Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license
2 : :
3 : : /*
4 : : precompile.c
5 : : Generating compiler output artifacts (object files, etc.)
6 : : */
7 : :
8 : : #include <stdlib.h>
9 : :
10 : : #include "julia.h"
11 : : #include "julia_internal.h"
12 : : #include "julia_assert.h"
13 : :
14 : : #ifdef __cplusplus
15 : : extern "C" {
16 : : #endif
17 : :
18 : 1578290 : JL_DLLEXPORT int jl_generating_output(void)
19 : : {
20 [ + + + - : 1578290 : return jl_options.outputo || jl_options.outputbc || jl_options.outputunoptbc || jl_options.outputji || jl_options.outputasm;
+ - + + -
+ ]
21 : : }
22 : :
23 : : static void *jl_precompile(int all);
24 : :
25 : 15 : void jl_write_compiler_output(void)
26 : : {
27 [ + + ]: 15 : if (!jl_generating_output()) {
28 : 6 : return;
29 : : }
30 : :
31 : 9 : void *native_code = NULL;
32 [ + + ]: 9 : if (!jl_options.incremental)
33 : 5 : native_code = jl_precompile(jl_options.compile_enabled == JL_OPTIONS_COMPILE_ALL);
34 : :
35 [ - + ]: 9 : if (!jl_module_init_order) {
36 : 0 : jl_printf(JL_STDERR, "WARNING: --output requested, but no modules defined during run\n");
37 : 0 : return;
38 : : }
39 : :
40 : 9 : jl_array_t *worklist = jl_module_init_order;
41 : 9 : JL_GC_PUSH1(&worklist);
42 : 9 : jl_module_init_order = jl_alloc_vec_any(0);
43 : 9 : int i, l = jl_array_len(worklist);
44 [ + + ]: 302 : for (i = 0; i < l; i++) {
45 : 293 : jl_value_t *m = jl_ptrarrayref(worklist, i);
46 : 293 : jl_value_t *f = jl_get_global((jl_module_t*)m, jl_symbol("__init__"));
47 [ + + ]: 293 : if (f) {
48 : 96 : jl_array_ptr_1d_push(jl_module_init_order, m);
49 : 96 : int setting = jl_get_module_compile((jl_module_t*)m);
50 [ + - + + ]: 96 : if (setting != JL_OPTIONS_COMPILE_OFF &&
51 : : setting != JL_OPTIONS_COMPILE_MIN) {
52 : : // TODO: this would be better handled if moved entirely to jl_precompile
53 : : // since it's a slightly duplication of effort
54 [ - + ]: 68 : jl_value_t *tt = jl_is_type(f) ? (jl_value_t*)jl_wrap_Type(f) : jl_typeof(f);
55 : 68 : JL_GC_PUSH1(&tt);
56 : 68 : tt = (jl_value_t*)jl_apply_tuple_type_v(&tt, 1);
57 : 68 : jl_compile_hint((jl_tupletype_t*)tt);
58 : 68 : JL_GC_POP();
59 : : }
60 : : }
61 : : }
62 : :
63 [ + + ]: 9 : if (jl_options.incremental) {
64 [ + - ]: 4 : if (jl_options.outputji)
65 [ - + ]: 4 : if (jl_save_incremental(jl_options.outputji, worklist))
66 : 0 : jl_exit(1);
67 [ + - - + ]: 4 : if (jl_options.outputbc || jl_options.outputunoptbc)
68 : 0 : jl_printf(JL_STDERR, "WARNING: incremental output to a .bc file is not implemented\n");
69 [ - + ]: 4 : if (jl_options.outputo)
70 : 0 : jl_printf(JL_STDERR, "WARNING: incremental output to a .o file is not implemented\n");
71 [ - + ]: 4 : if (jl_options.outputasm)
72 : 0 : jl_printf(JL_STDERR, "WARNING: incremental output to a .s file is not implemented\n");
73 : : }
74 : : else {
75 : 5 : ios_t *s = NULL;
76 [ + + + - : 5 : if (jl_options.outputo || jl_options.outputbc || jl_options.outputunoptbc || jl_options.outputasm)
+ - - + ]
77 : 2 : s = jl_create_system_image(native_code);
78 : :
79 [ + + ]: 5 : if (jl_options.outputji) {
80 [ + - ]: 3 : if (s == NULL) {
81 : 3 : jl_save_system_image(jl_options.outputji);
82 : : }
83 : : else {
84 : : ios_t f;
85 [ # # ]: 0 : if (ios_file(&f, jl_options.outputji, 1, 1, 1, 1) == NULL)
86 : 0 : jl_errorf("cannot open system image file \"%s\" for writing", jl_options.outputji);
87 : 0 : ios_write(&f, (const char*)s->buf, (size_t)s->size);
88 : 0 : ios_close(&f);
89 : : }
90 : : }
91 : :
92 [ + + + - : 5 : if (jl_options.outputo || jl_options.outputbc || jl_options.outputunoptbc || jl_options.outputasm) {
+ - - + ]
93 [ - + ]: 2 : assert(s);
94 : 2 : jl_dump_native(native_code,
95 : : jl_options.outputbc,
96 : : jl_options.outputunoptbc,
97 : : jl_options.outputo,
98 : : jl_options.outputasm,
99 : 2 : (const char*)s->buf, (size_t)s->size);
100 : 2 : jl_postoutput_hook();
101 : : }
102 : : }
103 [ + + ]: 153 : for (size_t i = 0; i < jl_current_modules.size; i += 2) {
104 [ - + ]: 144 : if (jl_current_modules.table[i + 1] != HT_NOTFOUND) {
105 : 0 : jl_printf(JL_STDERR, "\nWARNING: detected unclosed module: ");
106 : 0 : jl_static_show(JL_STDERR, (jl_value_t*)jl_current_modules.table[i]);
107 : 0 : jl_printf(JL_STDERR, "\n ** incremental compilation may be broken for this module **\n\n");
108 : : }
109 : : }
110 : 9 : JL_GC_POP();
111 : : }
112 : :
113 : : // f{<:Union{...}}(...) is a common pattern
114 : : // and expanding the Union may give a leaf function
115 : 0 : static void _compile_all_tvar_union(jl_value_t *methsig)
116 : : {
117 [ # # # # ]: 0 : if (!jl_is_unionall(methsig) && jl_is_dispatch_tupletype(methsig)) {
118 : : // usually can create a specialized version of the function,
119 : : // if the signature is already a dispatch type
120 [ # # ]: 0 : if (jl_compile_hint((jl_tupletype_t*)methsig))
121 : 0 : return;
122 : : }
123 : :
124 : 0 : int tvarslen = jl_subtype_env_size(methsig);
125 : 0 : jl_value_t *sigbody = methsig;
126 : : jl_value_t **roots;
127 : 0 : JL_GC_PUSHARGS(roots, 1 + 2 * tvarslen);
128 : 0 : jl_value_t **env = roots + 1;
129 : 0 : int *idx = (int*)alloca(sizeof(int) * tvarslen);
130 : : int i;
131 [ # # ]: 0 : for (i = 0; i < tvarslen; i++) {
132 [ # # ]: 0 : assert(jl_is_unionall(sigbody));
133 : 0 : idx[i] = 0;
134 : 0 : env[2 * i] = (jl_value_t*)((jl_unionall_t*)sigbody)->var;
135 : 0 : env[2 * i + 1] = jl_bottom_type; // initialize the list with Union{}, since T<:Union{} is always a valid option
136 : 0 : sigbody = ((jl_unionall_t*)sigbody)->body;
137 : : }
138 : :
139 [ # # ]: 0 : for (i = 0; i < tvarslen; /* incremented by inner loop */) {
140 : 0 : jl_value_t **sig = &roots[0];
141 [ # # # # ]: 0 : JL_TRY {
142 : : // TODO: wrap in UnionAll for each tvar in env[2*i + 1] ?
143 : : // currently doesn't matter much, since jl_compile_hint doesn't work on abstract types
144 : 0 : *sig = (jl_value_t*)jl_instantiate_type_with(sigbody, env, tvarslen);
145 : : }
146 [ # # ]: 0 : JL_CATCH {
147 : 0 : goto getnext; // sigh, we found an invalid type signature. should we warn the user?
148 : : }
149 [ # # ]: 0 : if (!jl_has_concrete_subtype(*sig))
150 : 0 : goto getnext; // signature wouldn't be callable / is invalid -- skip it
151 [ # # ]: 0 : if (jl_is_concrete_type(*sig)) {
152 [ # # ]: 0 : if (jl_compile_hint((jl_tupletype_t *)*sig))
153 : 0 : goto getnext; // success
154 : : }
155 : :
156 : 0 : getnext:
157 [ # # ]: 0 : for (i = 0; i < tvarslen; i++) {
158 : 0 : jl_tvar_t *tv = (jl_tvar_t*)env[2 * i];
159 [ # # ]: 0 : if (jl_is_uniontype(tv->ub)) {
160 : 0 : size_t l = jl_count_union_components(tv->ub);
161 : 0 : size_t j = idx[i];
162 [ # # ]: 0 : if (j == l) {
163 : 0 : env[2 * i + 1] = jl_bottom_type;
164 : 0 : idx[i] = 0;
165 : : }
166 : : else {
167 : 0 : jl_value_t *ty = jl_nth_union_component(tv->ub, j);
168 [ # # ]: 0 : if (!jl_is_concrete_type(ty))
169 : 0 : ty = (jl_value_t*)jl_new_typevar(tv->name, tv->lb, ty);
170 : 0 : env[2 * i + 1] = ty;
171 : 0 : idx[i] = j + 1;
172 : 0 : break;
173 : : }
174 : : }
175 : : else {
176 : 0 : env[2 * i + 1] = (jl_value_t*)tv;
177 : : }
178 : : }
179 : : }
180 : 0 : JL_GC_POP();
181 : : }
182 : :
183 : : // f(::Union{...}, ...) is a common pattern
184 : : // and expanding the Union may give a leaf function
185 : 0 : static void _compile_all_union(jl_value_t *sig)
186 : : {
187 : 0 : jl_tupletype_t *sigbody = (jl_tupletype_t*)jl_unwrap_unionall(sig);
188 : 0 : size_t count_unions = 0;
189 : 0 : size_t i, l = jl_svec_len(sigbody->parameters);
190 : 0 : jl_svec_t *p = NULL;
191 : 0 : jl_value_t *methsig = NULL;
192 : :
193 [ # # ]: 0 : for (i = 0; i < l; i++) {
194 : 0 : jl_value_t *ty = jl_svecref(sigbody->parameters, i);
195 [ # # ]: 0 : if (jl_is_uniontype(ty))
196 : 0 : ++count_unions;
197 [ # # ]: 0 : else if (ty == jl_bottom_type)
198 : 0 : return; // why does this method exist?
199 [ # # # # : 0 : else if (jl_is_datatype(ty) && !jl_has_free_typevars(ty) &&
# # ]
200 [ # # ]: 0 : ((!jl_is_kind(ty) && ((jl_datatype_t*)ty)->isconcretetype) ||
201 [ # # ]: 0 : ((jl_datatype_t*)ty)->name == jl_type_typename))
202 : 0 : return; // no amount of union splitting will make this a leaftype signature
203 : : }
204 : :
205 [ # # # # ]: 0 : if (count_unions == 0 || count_unions >= 6) {
206 : 0 : _compile_all_tvar_union(sig);
207 : 0 : return;
208 : : }
209 : :
210 : 0 : int *idx = (int*)alloca(sizeof(int) * count_unions);
211 [ # # ]: 0 : for (i = 0; i < count_unions; i++) {
212 : 0 : idx[i] = 0;
213 : : }
214 : :
215 : 0 : JL_GC_PUSH2(&p, &methsig);
216 : 0 : int idx_ctr = 0, incr = 0;
217 [ # # ]: 0 : while (!incr) {
218 : 0 : p = jl_alloc_svec_uninit(l);
219 [ # # ]: 0 : for (i = 0, idx_ctr = 0, incr = 1; i < l; i++) {
220 : 0 : jl_value_t *ty = jl_svecref(sigbody->parameters, i);
221 [ # # ]: 0 : if (jl_is_uniontype(ty)) {
222 [ # # ]: 0 : assert(idx_ctr < count_unions);
223 : 0 : size_t l = jl_count_union_components(ty);
224 : 0 : size_t j = idx[idx_ctr];
225 : 0 : jl_svecset(p, i, jl_nth_union_component(ty, j));
226 : 0 : ++j;
227 [ # # ]: 0 : if (incr) {
228 [ # # ]: 0 : if (j == l) {
229 : 0 : idx[idx_ctr] = 0;
230 : : }
231 : : else {
232 : 0 : idx[idx_ctr] = j;
233 : 0 : incr = 0;
234 : : }
235 : : }
236 : 0 : ++idx_ctr;
237 : : }
238 : : else {
239 : 0 : jl_svecset(p, i, ty);
240 : : }
241 : : }
242 : 0 : methsig = (jl_value_t*)jl_apply_tuple_type(p);
243 : 0 : methsig = jl_rewrap_unionall(methsig, sig);
244 : 0 : _compile_all_tvar_union(methsig);
245 : : }
246 : :
247 : 0 : JL_GC_POP();
248 : : }
249 : :
250 : 0 : static void _compile_all_deq(jl_array_t *found)
251 : : {
252 : 0 : int found_i, found_l = jl_array_len(found);
253 : 0 : jl_printf(JL_STDERR, "found %d uncompiled methods for compile-all\n", (int)found_l);
254 : 0 : jl_method_instance_t *mi = NULL;
255 : 0 : jl_value_t *src = NULL;
256 : 0 : JL_GC_PUSH2(&mi, &src);
257 [ # # ]: 0 : for (found_i = 0; found_i < found_l; found_i++) {
258 [ # # # # ]: 0 : if (found_i % (1 + found_l / 300) == 0 || found_i == found_l - 1) // show 300 progress steps, to show progress without overwhelming log files
259 : 0 : jl_printf(JL_STDERR, " %d / %d\r", found_i + 1, found_l);
260 : 0 : jl_typemap_entry_t *ml = (jl_typemap_entry_t*)jl_array_ptr_ref(found, found_i);
261 : 0 : jl_method_t *m = ml->func.method;
262 [ # # ]: 0 : if (m->source == NULL) // TODO: generic implementations of generated functions
263 : 0 : continue;
264 : 0 : mi = jl_get_unspecialized(m);
265 [ # # ]: 0 : assert(mi == jl_atomic_load_relaxed(&m->unspecialized)); // make sure we didn't get tricked by a generated function, since we can't handle those
266 : 0 : jl_code_instance_t *ucache = jl_get_method_inferred(mi, (jl_value_t*)jl_any_type, 1, ~(size_t)0);
267 [ # # ]: 0 : if (jl_atomic_load_relaxed(&ucache->invoke) != NULL)
268 : 0 : continue;
269 : 0 : src = m->source;
270 [ # # ]: 0 : assert(src);
271 : : // TODO: we could now enable storing inferred function pointers in the `unspecialized` cache
272 : : //src = jl_type_infer(mi, jl_atomic_load_acquire(&jl_world_counter), 1);
273 : : //if (jl_atomic_load_relaxed(&ucache->invoke) != NULL)
274 : : // continue;
275 : :
276 : : // first try to create leaf signatures from the signature declaration and compile those
277 : 0 : _compile_all_union((jl_value_t*)ml->sig);
278 : : // then also compile the generic fallback
279 : 0 : jl_generate_fptr_for_unspecialized(ucache);
280 : : }
281 : 0 : JL_GC_POP();
282 : 0 : jl_printf(JL_STDERR, "\n");
283 : 0 : }
284 : :
285 : 0 : static int compile_all_enq__(jl_typemap_entry_t *ml, void *env)
286 : : {
287 : 0 : jl_array_t *found = (jl_array_t*)env;
288 : : // method definition -- compile template field
289 : 0 : jl_method_t *m = ml->func.method;
290 [ # # ]: 0 : if (m->source) {
291 : : // found a method to compile
292 : 0 : jl_array_ptr_1d_push(found, (jl_value_t*)ml);
293 : : }
294 : 0 : return 1;
295 : : }
296 : :
297 : :
298 : 0 : static int compile_all_enq_(jl_methtable_t *mt, void *env)
299 : : {
300 : 0 : jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), compile_all_enq__, env);
301 : 0 : return 1;
302 : : }
303 : :
304 : 0 : static void jl_compile_all_defs(void)
305 : : {
306 : : // this "found" array will contain
307 : : // TypeMapEntries for Methods and MethodInstances that need to be compiled
308 : 0 : jl_array_t *m = jl_alloc_vec_any(0);
309 : 0 : JL_GC_PUSH1(&m);
310 : 0 : int _changes = -1;
311 : 0 : int attempts = 0;
312 : 0 : while (1) {
313 : 0 : jl_foreach_reachable_mtable(compile_all_enq_, m);
314 : 0 : size_t changes = jl_array_len(m);
315 [ # # ]: 0 : if (!changes)
316 : 0 : break;
317 [ # # ]: 0 : if (changes == _changes) {
318 [ # # ]: 0 : if (++attempts > 5) {
319 : 0 : jl_printf(JL_STDERR, "unable to compile %d methods for compile-all\n", (int)changes);
320 : 0 : break;
321 : : }
322 : : } else {
323 : 0 : attempts = 0;
324 : : }
325 : 0 : _compile_all_deq(m);
326 : 0 : jl_array_del_end(m, changes);
327 : 0 : _changes = changes;
328 : : }
329 : 0 : JL_GC_POP();
330 : 0 : }
331 : :
332 : 223161 : static int precompile_enq_specialization_(jl_method_instance_t *mi, void *closure)
333 : : {
334 [ - + ]: 223161 : assert(jl_is_method_instance(mi));
335 : 223161 : jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache);
336 [ + + ]: 404860 : while (codeinst) {
337 : 231485 : int do_compile = 0;
338 [ + + ]: 231485 : if (jl_atomic_load_relaxed(&codeinst->invoke) != jl_fptr_const_return) {
339 [ + + + + : 368190 : if (codeinst->inferred && codeinst->inferred != jl_nothing &&
+ - ]
340 [ + + ]: 334764 : jl_ir_flag_inferred((jl_array_t*)codeinst->inferred) &&
341 : 167382 : !jl_ir_flag_inlineable((jl_array_t*)codeinst->inferred)) {
342 : 26596 : do_compile = 1;
343 : : }
344 [ + + + + ]: 174212 : else if (jl_atomic_load_relaxed(&codeinst->invoke) != NULL || jl_atomic_load_relaxed(&codeinst->precompile)) {
345 : 23190 : do_compile = 1;
346 : : }
347 : : }
348 [ + + ]: 231485 : if (do_compile) {
349 : 49786 : jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)mi);
350 : 49786 : return 1;
351 : : }
352 : 181699 : codeinst = jl_atomic_load_relaxed(&codeinst->next);
353 : : }
354 : 173375 : return 1;
355 : : }
356 : :
357 : 127814 : static int precompile_enq_all_specializations__(jl_typemap_entry_t *def, void *closure)
358 : : {
359 : 127814 : jl_method_t *m = def->func.method;
360 [ + + - + : 127910 : if ((m->name == jl_symbol("__init__") || m->ccallable) && jl_is_dispatch_tupletype(m->sig)) {
+ - ]
361 : : // ensure `__init__()` and @ccallables get strongly-hinted, specialized, and compiled
362 : 96 : jl_method_instance_t *mi = jl_specializations_get_linfo(m, m->sig, jl_emptysvec);
363 : 96 : jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)mi);
364 : : }
365 : : else {
366 : 127718 : jl_svec_t *specializations = jl_atomic_load_relaxed(&def->func.method->specializations);
367 : 127718 : size_t i, l = jl_svec_len(specializations);
368 [ + + ]: 592402 : for (i = 0; i < l; i++) {
369 : 464684 : jl_value_t *mi = jl_svecref(specializations, i);
370 [ + + ]: 464684 : if (mi != jl_nothing)
371 : 223161 : precompile_enq_specialization_((jl_method_instance_t*)mi, closure);
372 : : }
373 : : }
374 [ - + ]: 127814 : if (m->ccallable)
375 : 0 : jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)m->ccallable);
376 : 127814 : return 1;
377 : : }
378 : :
379 : 46378 : static int precompile_enq_all_specializations_(jl_methtable_t *mt, void *env)
380 : : {
381 : 46378 : return jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), precompile_enq_all_specializations__, env);
382 : : }
383 : :
384 : 5 : static void *jl_precompile(int all)
385 : : {
386 [ - + ]: 5 : if (all)
387 : 0 : jl_compile_all_defs();
388 : : // this "found" array will contain function
389 : : // type signatures that were inferred but haven't been compiled
390 : 5 : jl_array_t *m = jl_alloc_vec_any(0);
391 : 5 : jl_array_t *m2 = NULL;
392 : 5 : jl_method_instance_t *mi = NULL;
393 : 5 : JL_GC_PUSH3(&m, &m2, &mi);
394 : 5 : jl_foreach_reachable_mtable(precompile_enq_all_specializations_, m);
395 : 5 : m2 = jl_alloc_vec_any(0);
396 [ + + ]: 49887 : for (size_t i = 0; i < jl_array_len(m); i++) {
397 : 49882 : jl_value_t *item = jl_array_ptr_ref(m, i);
398 [ + - ]: 49882 : if (jl_is_method_instance(item)) {
399 : 49882 : mi = (jl_method_instance_t*)item;
400 : 49882 : size_t min_world = 0;
401 : 49882 : size_t max_world = ~(size_t)0;
402 [ - + ]: 49882 : if (!jl_isa_compileable_sig((jl_tupletype_t*)mi->specTypes, mi->def.method))
403 : 0 : mi = jl_get_specialization1((jl_tupletype_t*)mi->specTypes, jl_atomic_load_acquire(&jl_world_counter), &min_world, &max_world, 0);
404 [ + - ]: 49882 : if (mi)
405 : 49882 : jl_array_ptr_1d_push(m2, (jl_value_t*)mi);
406 : : }
407 : : else {
408 [ # # ]: 0 : assert(jl_is_simplevector(item));
409 [ # # ]: 0 : assert(jl_svec_len(item) == 2);
410 : 0 : jl_array_ptr_1d_push(m2, item);
411 : : }
412 : : }
413 : 5 : m = NULL;
414 : 5 : void *native_code = jl_create_native(m2, NULL, NULL, 0);
415 : 5 : JL_GC_POP();
416 : 5 : return native_code;
417 : : }
418 : :
419 : : #ifdef __cplusplus
420 : : }
421 : : #endif
|