Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license
2 : :
3 : : /*
4 : : jlapi.c
5 : : miscellaneous functions for users of libjulia.so, to handle initialization
6 : : and the style of use where julia is not in control most of the time.
7 : : */
8 : : #include "platform.h"
9 : :
10 : : #include <stdlib.h>
11 : : #include <stdio.h>
12 : : #include <string.h>
13 : : #include "julia.h"
14 : : #include "options.h"
15 : : #include "julia_assert.h"
16 : : #include "julia_internal.h"
17 : :
18 : : #ifdef __cplusplus
19 : : #include <cfenv>
20 : : extern "C" {
21 : : #else
22 : : #include <fenv.h>
23 : : #endif
24 : :
25 : 0 : JL_DLLEXPORT int jl_is_initialized(void)
26 : : {
27 : 0 : return jl_main_module != NULL;
28 : : }
29 : :
30 : 15 : JL_DLLEXPORT void jl_set_ARGS(int argc, char **argv)
31 : : {
32 [ + - ]: 15 : if (jl_core_module != NULL) {
33 : 15 : jl_array_t *args = (jl_array_t*)jl_get_global(jl_core_module, jl_symbol("ARGS"));
34 [ + + ]: 15 : if (args == NULL) {
35 : 1 : args = jl_alloc_vec_any(0);
36 : 1 : JL_GC_PUSH1(&args);
37 : 1 : jl_set_const(jl_core_module, jl_symbol("ARGS"), (jl_value_t*)args);
38 : 1 : JL_GC_POP();
39 : : }
40 [ - + ]: 15 : assert(jl_array_len(args) == 0);
41 : 15 : jl_array_grow_end(args, argc);
42 : : int i;
43 [ + + ]: 30 : for (i = 0; i < argc; i++) {
44 : 15 : jl_value_t *s = (jl_value_t*)jl_cstr_to_string(argv[i]);
45 : 15 : jl_arrayset(args, s, i);
46 : : }
47 : : }
48 : 15 : }
49 : :
50 : : // First argument is the usr/bin directory where the julia binary is, or NULL to guess.
51 : : // Second argument is the path of a system image file (*.so).
52 : : // A non-absolute path is interpreted as relative to the first argument path, or
53 : : // relative to the default julia home dir.
54 : : // The default is something like ../lib/julia/sys.so
55 : 0 : JL_DLLEXPORT void jl_init_with_image(const char *julia_bindir,
56 : : const char *image_path)
57 : : {
58 [ # # ]: 0 : if (jl_is_initialized())
59 : 0 : return;
60 : 0 : libsupport_init();
61 : 0 : jl_options.julia_bindir = julia_bindir;
62 [ # # ]: 0 : if (image_path != NULL)
63 : 0 : jl_options.image_file = image_path;
64 : : else
65 : 0 : jl_options.image_file = jl_get_default_sysimg_path();
66 : 0 : julia_init(JL_IMAGE_JULIA_HOME);
67 : 0 : jl_exception_clear();
68 : : }
69 : :
70 : 0 : JL_DLLEXPORT void jl_init(void)
71 : : {
72 : 0 : char *libbindir = NULL;
73 : : #ifdef _OS_WINDOWS_
74 : : libbindir = strdup(jl_get_libdir());
75 : : #else
76 : 0 : (void)asprintf(&libbindir, "%s" PATHSEPSTRING ".." PATHSEPSTRING "%s", jl_get_libdir(), "bin");
77 : : #endif
78 [ # # ]: 0 : if (!libbindir) {
79 : 0 : printf("jl_init unable to find libjulia!\n");
80 : 0 : abort();
81 : : }
82 : 0 : jl_init_with_image(libbindir, jl_get_default_sysimg_path());
83 : 0 : free(libbindir);
84 : 0 : }
85 : :
86 : : // HACK: remove this for Julia 1.8 (see <https://github.com/JuliaLang/julia/issues/40730>)
87 : 0 : JL_DLLEXPORT void jl_init__threading(void)
88 : : {
89 : 0 : jl_init();
90 : 0 : }
91 : :
92 : : // HACK: remove this for Julia 1.8 (see <https://github.com/JuliaLang/julia/issues/40730>)
93 : 0 : JL_DLLEXPORT void jl_init_with_image__threading(const char *julia_bindir,
94 : : const char *image_relative_path)
95 : : {
96 : 0 : jl_init_with_image(julia_bindir, image_relative_path);
97 : 0 : }
98 : :
99 : 0 : JL_DLLEXPORT jl_value_t *jl_eval_string(const char *str)
100 : : {
101 : : jl_value_t *r;
102 [ # # # # ]: 0 : JL_TRY {
103 : 0 : const char filename[] = "none";
104 : 0 : jl_value_t *ast = jl_parse_all(str, strlen(str),
105 : : filename, strlen(filename), 1);
106 : 0 : JL_GC_PUSH1(&ast);
107 : 0 : r = jl_toplevel_eval_in(jl_main_module, ast);
108 : 0 : JL_GC_POP();
109 : 0 : jl_exception_clear();
110 : : }
111 [ # # ]: 0 : JL_CATCH {
112 : 0 : jl_current_task->ptls->previous_exception = jl_current_exception();
113 : 0 : r = NULL;
114 : : }
115 : 0 : return r;
116 : : }
117 : :
118 : 62 : JL_DLLEXPORT jl_value_t *jl_current_exception(void) JL_GLOBALLY_ROOTED JL_NOTSAFEPOINT
119 : : {
120 : 62 : jl_excstack_t *s = jl_current_task->excstack;
121 [ + - + - ]: 62 : return s && s->top != 0 ? jl_excstack_exception(s, s->top) : jl_nothing;
122 : : }
123 : :
124 : 0 : JL_DLLEXPORT jl_value_t *jl_exception_occurred(void)
125 : : {
126 : 0 : return jl_current_task->ptls->previous_exception;
127 : : }
128 : :
129 : 28 : JL_DLLEXPORT void jl_exception_clear(void)
130 : : {
131 : 28 : jl_current_task->ptls->previous_exception = NULL;
132 : 28 : }
133 : :
134 : : // get the name of a type as a string
135 : 646216 : JL_DLLEXPORT const char *jl_typename_str(jl_value_t *v)
136 : : {
137 [ - + ]: 646216 : if (!jl_is_datatype(v))
138 : 0 : return NULL;
139 : 646216 : return jl_symbol_name(((jl_datatype_t*)v)->name->name);
140 : : }
141 : :
142 : : // get the name of typeof(v) as a string
143 : 0 : JL_DLLEXPORT const char *jl_typeof_str(jl_value_t *v)
144 : : {
145 : 0 : return jl_typename_str((jl_value_t*)jl_typeof(v));
146 : : }
147 : :
148 : 0 : JL_DLLEXPORT void *jl_array_eltype(jl_value_t *a)
149 : : {
150 : 0 : return jl_tparam0(jl_typeof(a));
151 : : }
152 : :
153 : 0 : JL_DLLEXPORT int jl_array_rank(jl_value_t *a)
154 : : {
155 : 0 : return jl_array_ndims(a);
156 : : }
157 : :
158 : 0 : JL_DLLEXPORT size_t jl_array_size(jl_value_t *a, int d)
159 : : {
160 : 0 : return jl_array_dim(a, d);
161 : : }
162 : :
163 : 0 : JL_DLLEXPORT const char *jl_string_ptr(jl_value_t *s)
164 : : {
165 : 0 : return jl_string_data(s);
166 : : }
167 : :
168 : 0 : JL_DLLEXPORT jl_value_t *jl_call(jl_function_t *f, jl_value_t **args, uint32_t nargs)
169 : : {
170 : : jl_value_t *v;
171 : 0 : jl_task_t *ct = jl_current_task;
172 : 0 : nargs++; // add f to args
173 [ # # # # ]: 0 : JL_TRY {
174 : : jl_value_t **argv;
175 : 0 : JL_GC_PUSHARGS(argv, nargs);
176 : 0 : argv[0] = (jl_value_t*)f;
177 [ # # ]: 0 : for (int i = 1; i < nargs; i++)
178 : 0 : argv[i] = args[i - 1];
179 : 0 : size_t last_age = ct->world_age;
180 : 0 : ct->world_age = jl_get_world_counter();
181 : 0 : v = jl_apply(argv, nargs);
182 : 0 : ct->world_age = last_age;
183 : 0 : JL_GC_POP();
184 : 0 : jl_exception_clear();
185 : : }
186 [ # # ]: 0 : JL_CATCH {
187 : 0 : ct->ptls->previous_exception = jl_current_exception();
188 : 0 : v = NULL;
189 : : }
190 : 0 : return v;
191 : : }
192 : :
193 : 12 : JL_DLLEXPORT jl_value_t *jl_call0(jl_function_t *f)
194 : : {
195 : : jl_value_t *v;
196 : 12 : jl_task_t *ct = jl_current_task;
197 [ + - + + ]: 24 : JL_TRY {
198 : 12 : JL_GC_PUSH1(&f);
199 : 12 : size_t last_age = ct->world_age;
200 : 12 : ct->world_age = jl_get_world_counter();
201 : 12 : v = jl_apply_generic(f, NULL, 0);
202 : 12 : ct->world_age = last_age;
203 : 12 : JL_GC_POP();
204 : 12 : jl_exception_clear();
205 : : }
206 [ # # ]: 0 : JL_CATCH {
207 : 0 : ct->ptls->previous_exception = jl_current_exception();
208 : 0 : v = NULL;
209 : : }
210 : 12 : return v;
211 : : }
212 : :
213 : 0 : JL_DLLEXPORT jl_value_t *jl_call1(jl_function_t *f, jl_value_t *a)
214 : : {
215 : : jl_value_t *v;
216 : 0 : jl_task_t *ct = jl_current_task;
217 [ # # # # ]: 0 : JL_TRY {
218 : : jl_value_t **argv;
219 : 0 : JL_GC_PUSHARGS(argv, 2);
220 : 0 : argv[0] = f;
221 : 0 : argv[1] = a;
222 : 0 : size_t last_age = ct->world_age;
223 : 0 : ct->world_age = jl_get_world_counter();
224 : 0 : v = jl_apply(argv, 2);
225 : 0 : ct->world_age = last_age;
226 : 0 : JL_GC_POP();
227 : 0 : jl_exception_clear();
228 : : }
229 [ # # ]: 0 : JL_CATCH {
230 : 0 : ct->ptls->previous_exception = jl_current_exception();
231 : 0 : v = NULL;
232 : : }
233 : 0 : return v;
234 : : }
235 : :
236 : 0 : JL_DLLEXPORT jl_value_t *jl_call2(jl_function_t *f, jl_value_t *a, jl_value_t *b)
237 : : {
238 : : jl_value_t *v;
239 : 0 : jl_task_t *ct = jl_current_task;
240 [ # # # # ]: 0 : JL_TRY {
241 : : jl_value_t **argv;
242 : 0 : JL_GC_PUSHARGS(argv, 3);
243 : 0 : argv[0] = f;
244 : 0 : argv[1] = a;
245 : 0 : argv[2] = b;
246 : 0 : size_t last_age = ct->world_age;
247 : 0 : ct->world_age = jl_get_world_counter();
248 : 0 : v = jl_apply(argv, 3);
249 : 0 : ct->world_age = last_age;
250 : 0 : JL_GC_POP();
251 : 0 : jl_exception_clear();
252 : : }
253 [ # # ]: 0 : JL_CATCH {
254 : 0 : ct->ptls->previous_exception = jl_current_exception();
255 : 0 : v = NULL;
256 : : }
257 : 0 : return v;
258 : : }
259 : :
260 : 0 : JL_DLLEXPORT jl_value_t *jl_call3(jl_function_t *f, jl_value_t *a,
261 : : jl_value_t *b, jl_value_t *c)
262 : : {
263 : : jl_value_t *v;
264 [ # # # # ]: 0 : JL_TRY {
265 : : jl_value_t **argv;
266 : 0 : JL_GC_PUSHARGS(argv, 4);
267 : 0 : argv[0] = f;
268 : 0 : argv[1] = a;
269 : 0 : argv[2] = b;
270 : 0 : argv[3] = c;
271 : 0 : jl_task_t *ct = jl_current_task;
272 : 0 : size_t last_age = ct->world_age;
273 : 0 : ct->world_age = jl_get_world_counter();
274 : 0 : v = jl_apply(argv, 4);
275 : 0 : ct->world_age = last_age;
276 : 0 : JL_GC_POP();
277 : 0 : jl_exception_clear();
278 : : }
279 [ # # ]: 0 : JL_CATCH {
280 : 0 : jl_current_task->ptls->previous_exception = jl_current_exception();
281 : 0 : v = NULL;
282 : : }
283 : 0 : return v;
284 : : }
285 : :
286 : 0 : JL_DLLEXPORT void jl_yield(void)
287 : : {
288 : : static jl_function_t *yieldfunc = NULL;
289 [ # # ]: 0 : if (yieldfunc == NULL)
290 : 0 : yieldfunc = (jl_function_t*)jl_get_global(jl_base_module, jl_symbol("yield"));
291 [ # # ]: 0 : if (yieldfunc != NULL)
292 : 0 : jl_call0(yieldfunc);
293 : 0 : }
294 : :
295 : 16 : JL_DLLEXPORT jl_value_t *jl_get_field(jl_value_t *o, const char *fld)
296 : : {
297 : : jl_value_t *v;
298 [ + - + + ]: 32 : JL_TRY {
299 : 16 : jl_value_t *s = (jl_value_t*)jl_symbol(fld);
300 : 16 : int i = jl_field_index((jl_datatype_t*)jl_typeof(o), (jl_sym_t*)s, 1);
301 : 16 : v = jl_get_nth_field(o, i);
302 : 16 : jl_exception_clear();
303 : : }
304 [ # # ]: 0 : JL_CATCH {
305 : 0 : jl_current_task->ptls->previous_exception = jl_current_exception();
306 : 0 : v = NULL;
307 : : }
308 : 16 : return v;
309 : : }
310 : :
311 : 0 : JL_DLLEXPORT void jl_sigatomic_begin(void)
312 : : {
313 : 0 : JL_SIGATOMIC_BEGIN();
314 : 0 : }
315 : :
316 : 0 : JL_DLLEXPORT void jl_sigatomic_end(void)
317 : : {
318 : 0 : jl_task_t *ct = jl_current_task;
319 [ # # ]: 0 : if (ct->ptls->defer_signal == 0)
320 : 0 : jl_error("sigatomic_end called in non-sigatomic region");
321 [ # # ]: 0 : JL_SIGATOMIC_END();
322 : 0 : }
323 : :
324 : 10 : JL_DLLEXPORT int jl_is_debugbuild(void) JL_NOTSAFEPOINT
325 : : {
326 : : #ifdef JL_DEBUG_BUILD
327 : 10 : return 1;
328 : : #else
329 : : return 0;
330 : : #endif
331 : : }
332 : :
333 : 0 : JL_DLLEXPORT int8_t jl_is_memdebug(void) JL_NOTSAFEPOINT {
334 : : #ifdef MEMDEBUG
335 : : return 1;
336 : : #else
337 : 0 : return 0;
338 : : #endif
339 : : }
340 : :
341 : 14 : JL_DLLEXPORT jl_value_t *jl_get_julia_bindir(void)
342 : : {
343 : 14 : return jl_cstr_to_string(jl_options.julia_bindir);
344 : : }
345 : :
346 : 0 : JL_DLLEXPORT jl_value_t *jl_get_julia_bin(void)
347 : : {
348 : 0 : return jl_cstr_to_string(jl_options.julia_bin);
349 : : }
350 : :
351 : 0 : JL_DLLEXPORT jl_value_t *jl_get_image_file(void)
352 : : {
353 : 0 : return jl_cstr_to_string(jl_options.image_file);
354 : : }
355 : :
356 : 3 : JL_DLLEXPORT int jl_ver_major(void)
357 : : {
358 : 3 : return JULIA_VERSION_MAJOR;
359 : : }
360 : :
361 : 0 : JL_DLLEXPORT int jl_ver_minor(void)
362 : : {
363 : 0 : return JULIA_VERSION_MINOR;
364 : : }
365 : :
366 : 0 : JL_DLLEXPORT int jl_ver_patch(void)
367 : : {
368 : 0 : return JULIA_VERSION_PATCH;
369 : : }
370 : :
371 : 0 : JL_DLLEXPORT int jl_ver_is_release(void)
372 : : {
373 : 0 : return JULIA_VERSION_IS_RELEASE;
374 : : }
375 : :
376 : 0 : JL_DLLEXPORT const char *jl_ver_string(void)
377 : : {
378 : 0 : return JULIA_VERSION_STRING;
379 : : }
380 : :
381 : : // return char* from String field in Base.GIT_VERSION_INFO
382 : 16 : static const char *git_info_string(const char *fld)
383 : : {
384 : : static jl_value_t *GIT_VERSION_INFO = NULL;
385 [ + + ]: 16 : if (!GIT_VERSION_INFO)
386 : 8 : GIT_VERSION_INFO = jl_get_global(jl_base_module, jl_symbol("GIT_VERSION_INFO"));
387 : 16 : jl_value_t *f = jl_get_field(GIT_VERSION_INFO, fld);
388 [ - + ]: 16 : assert(jl_is_string(f));
389 : 16 : return jl_string_data(f);
390 : : }
391 : :
392 : 8 : JL_DLLEXPORT const char *jl_git_branch(void)
393 : : {
394 : : static const char *branch = NULL;
395 [ + - ]: 8 : if (!branch) branch = git_info_string("branch");
396 : 8 : return branch;
397 : : }
398 : :
399 : 8 : JL_DLLEXPORT const char *jl_git_commit(void)
400 : : {
401 : : static const char *commit = NULL;
402 [ + - ]: 8 : if (!commit) commit = git_info_string("commit");
403 : 8 : return commit;
404 : : }
405 : :
406 : : // Create function versions of some useful macros for GDB or FFI use
407 : 0 : JL_DLLEXPORT jl_taggedvalue_t *(jl_astaggedvalue)(jl_value_t *v)
408 : : {
409 : 0 : return jl_astaggedvalue(v);
410 : : }
411 : :
412 : 0 : JL_DLLEXPORT jl_value_t *(jl_valueof)(jl_taggedvalue_t *v)
413 : : {
414 : 0 : return jl_valueof(v);
415 : : }
416 : :
417 : 0 : JL_DLLEXPORT jl_value_t *(jl_typeof)(jl_value_t *v)
418 : : {
419 : 0 : return jl_typeof(v);
420 : : }
421 : :
422 : 408755 : JL_DLLEXPORT jl_value_t *(jl_get_fieldtypes)(jl_value_t *v)
423 : : {
424 [ + + ]: 408755 : return (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)v);
425 : : }
426 : :
427 : 0 : JL_DLLEXPORT int ijl_egal(jl_value_t *a, jl_value_t *b)
428 : : {
429 : 0 : return jl_egal(a, b);
430 : : }
431 : :
432 : :
433 : : #ifndef __clang_gcanalyzer__
434 : 0 : JL_DLLEXPORT int8_t (jl_gc_unsafe_enter)(void)
435 : : {
436 : 0 : jl_task_t *ct = jl_current_task;
437 : 0 : return jl_gc_unsafe_enter(ct->ptls);
438 : : }
439 : :
440 : 0 : JL_DLLEXPORT void (jl_gc_unsafe_leave)(int8_t state)
441 : : {
442 : 0 : jl_task_t *ct = jl_current_task;
443 : 0 : jl_gc_unsafe_leave(ct->ptls, state);
444 : 0 : }
445 : :
446 : 0 : JL_DLLEXPORT int8_t (jl_gc_safe_enter)(void)
447 : : {
448 : 0 : jl_task_t *ct = jl_current_task;
449 : 0 : return jl_gc_safe_enter(ct->ptls);
450 : : }
451 : :
452 : 0 : JL_DLLEXPORT void (jl_gc_safe_leave)(int8_t state)
453 : : {
454 : 0 : jl_task_t *ct = jl_current_task;
455 : 0 : jl_gc_safe_leave(ct->ptls, state);
456 : 0 : }
457 : : #endif
458 : :
459 : 39673 : JL_DLLEXPORT void jl_gc_safepoint(void)
460 : : {
461 : 39673 : jl_task_t *ct = jl_current_task;
462 : 39673 : jl_gc_safepoint_(ct->ptls);
463 : 39673 : }
464 : :
465 : 0 : JL_DLLEXPORT void (jl_cpu_pause)(void)
466 : : {
467 : : jl_cpu_pause();
468 : 0 : }
469 : :
470 : 0 : JL_DLLEXPORT void (jl_cpu_wake)(void)
471 : : {
472 : : jl_cpu_wake();
473 : 0 : }
474 : :
475 : 2 : JL_DLLEXPORT void jl_cumulative_compile_timing_enable(void)
476 : : {
477 : : // Increment the flag to allow reentrant callers to `@time`.
478 : 2 : jl_atomic_fetch_add(&jl_measure_compile_time_enabled, 1);
479 : 2 : }
480 : :
481 : 2 : JL_DLLEXPORT void jl_cumulative_compile_timing_disable(void)
482 : : {
483 : : // Decrement the flag when done measuring, allowing other callers to continue measuring.
484 : 2 : jl_atomic_fetch_add(&jl_measure_compile_time_enabled, -1);
485 : 2 : }
486 : :
487 : 4 : JL_DLLEXPORT uint64_t jl_cumulative_compile_time_ns(void)
488 : : {
489 : 4 : return jl_atomic_load_relaxed(&jl_cumulative_compile_time);
490 : : }
491 : :
492 : 4 : JL_DLLEXPORT uint64_t jl_cumulative_recompile_time_ns(void)
493 : : {
494 : 4 : return jl_atomic_load_relaxed(&jl_cumulative_recompile_time);
495 : : }
496 : :
497 : 2 : JL_DLLEXPORT void jl_get_fenv_consts(int *ret)
498 : : {
499 : 2 : ret[0] = FE_INEXACT;
500 : 2 : ret[1] = FE_UNDERFLOW;
501 : 2 : ret[2] = FE_OVERFLOW;
502 : 2 : ret[3] = FE_DIVBYZERO;
503 : 2 : ret[4] = FE_INVALID;
504 : 2 : ret[5] = FE_TONEAREST;
505 : 2 : ret[6] = FE_UPWARD;
506 : 2 : ret[7] = FE_DOWNWARD;
507 : 2 : ret[8] = FE_TOWARDZERO;
508 : 2 : }
509 : :
510 : : // TODO: Windows binaries currently load msvcrt which doesn't have these C99 functions.
511 : : // the mingw compiler ships additional definitions, but only for use in C code.
512 : : // remove this when we switch to ucrt, make the version in openlibm portable,
513 : : // or figure out how to reexport the defs from libmingwex (see JuliaLang/julia#38466).
514 : 0 : JL_DLLEXPORT int jl_get_fenv_rounding(void)
515 : : {
516 : 0 : return fegetround();
517 : : }
518 : 4 : JL_DLLEXPORT int jl_set_fenv_rounding(int i)
519 : : {
520 : 4 : return fesetround(i);
521 : : }
522 : :
523 : 3 : static int exec_program(char *program)
524 : : {
525 [ + - + + ]: 6 : JL_TRY {
526 : 3 : jl_load(jl_main_module, program);
527 : : }
528 [ # # ]: 0 : JL_CATCH {
529 : : // TODO: It is possible for this output to be mangled due to `jl_print_backtrace`
530 : : // printing directly to STDERR_FILENO.
531 : 0 : int shown_err = 0;
532 : 0 : jl_printf(JL_STDERR, "error during bootstrap:\n");
533 : 0 : jl_value_t *exc = jl_current_exception();
534 [ # # ]: 0 : jl_value_t *showf = jl_base_module ? jl_get_function(jl_base_module, "show") : NULL;
535 [ # # ]: 0 : if (showf) {
536 : 0 : jl_value_t *errs = jl_stderr_obj();
537 [ # # ]: 0 : if (errs) {
538 [ # # ]: 0 : if (jl_call2(showf, errs, exc)) {
539 : 0 : jl_printf(JL_STDERR, "\n");
540 : 0 : shown_err = 1;
541 : : }
542 : : }
543 : : }
544 [ # # ]: 0 : if (!shown_err) {
545 : 0 : jl_static_show((JL_STREAM*)STDERR_FILENO, exc);
546 : 0 : jl_printf((JL_STREAM*)STDERR_FILENO, "\n");
547 : : }
548 : 0 : jl_print_backtrace(); // written to STDERR_FILENO
549 : 0 : jl_printf((JL_STREAM*)STDERR_FILENO, "\n");
550 : 0 : return 1;
551 : : }
552 : 3 : return 0;
553 : : }
554 : :
555 : 15 : static NOINLINE int true_main(int argc, char *argv[])
556 : : {
557 : 15 : jl_set_ARGS(argc, argv);
558 : :
559 : 30 : jl_function_t *start_client = jl_base_module ?
560 [ + + ]: 15 : (jl_function_t*)jl_get_global(jl_base_module, jl_symbol("_start")) : NULL;
561 : :
562 [ + + ]: 15 : if (start_client) {
563 [ + - + + ]: 22 : JL_TRY {
564 : 12 : jl_task_t *ct = jl_current_task;
565 : 12 : size_t last_age = ct->world_age;
566 : 12 : ct->world_age = jl_get_world_counter();
567 : 12 : jl_apply(&start_client, 1);
568 : 10 : ct->world_age = last_age;
569 : : }
570 [ # # ]: 0 : JL_CATCH {
571 : 0 : jl_no_exc_handler(jl_current_exception());
572 : : }
573 : 10 : return 0;
574 : : }
575 : :
576 : : // run program if specified, otherwise enter REPL
577 [ + - ]: 3 : if (argc > 0) {
578 [ + - ]: 3 : if (strcmp(argv[0], "-")) {
579 : 3 : return exec_program(argv[0]);
580 : : }
581 : : }
582 : :
583 : 0 : jl_printf(JL_STDOUT, "WARNING: Base._start not defined, falling back to economy mode repl.\n");
584 [ # # ]: 0 : if (!jl_errorexception_type)
585 : 0 : jl_printf(JL_STDOUT, "WARNING: jl_errorexception_type not defined; any errors will be fatal.\n");
586 : :
587 [ # # ]: 0 : while (!ios_eof(ios_stdin)) {
588 : 0 : char *volatile line = NULL;
589 [ # # # # ]: 0 : JL_TRY {
590 : 0 : ios_puts("\njulia> ", ios_stdout);
591 : 0 : ios_flush(ios_stdout);
592 : 0 : line = ios_readline(ios_stdin);
593 : 0 : jl_value_t *val = (jl_value_t*)jl_eval_string(line);
594 : 0 : JL_GC_PUSH1(&val);
595 [ # # ]: 0 : if (jl_exception_occurred()) {
596 : 0 : jl_printf(JL_STDERR, "error during run:\n");
597 : 0 : jl_static_show(JL_STDERR, jl_exception_occurred());
598 : 0 : jl_exception_clear();
599 : : }
600 [ # # ]: 0 : else if (val) {
601 : 0 : jl_static_show(JL_STDOUT, val);
602 : : }
603 : 0 : JL_GC_POP();
604 : 0 : jl_printf(JL_STDOUT, "\n");
605 : 0 : free(line);
606 : 0 : line = NULL;
607 : 0 : jl_process_events();
608 : : }
609 [ # # ]: 0 : JL_CATCH {
610 [ # # ]: 0 : if (line) {
611 : 0 : free(line);
612 : 0 : line = NULL;
613 : : }
614 : 0 : jl_printf((JL_STREAM*)STDERR_FILENO, "\nparser error:\n");
615 : 0 : jl_static_show((JL_STREAM*)STDERR_FILENO, jl_current_exception());
616 : 0 : jl_printf((JL_STREAM*)STDERR_FILENO, "\n");
617 : 0 : jl_print_backtrace(); // written to STDERR_FILENO
618 : : }
619 : : }
620 : 0 : return 0;
621 : : }
622 : :
623 : 15 : static void lock_low32(void)
624 : : {
625 : : #if defined(_OS_WINDOWS_) && defined(_P64) && defined(JL_DEBUG_BUILD)
626 : : // Prevent usage of the 32-bit address space on Win64, to catch pointer cast errors.
627 : : char *const max32addr = (char*)0xffffffffL;
628 : : SYSTEM_INFO info;
629 : : MEMORY_BASIC_INFORMATION meminfo;
630 : : GetNativeSystemInfo(&info);
631 : : memset(&meminfo, 0, sizeof(meminfo));
632 : : meminfo.BaseAddress = info.lpMinimumApplicationAddress;
633 : : while ((char*)meminfo.BaseAddress < max32addr) {
634 : : size_t nbytes = VirtualQuery(meminfo.BaseAddress, &meminfo, sizeof(meminfo));
635 : : assert(nbytes == sizeof(meminfo));
636 : : if (meminfo.State == MEM_FREE) { // reserve all free pages in the first 4GB of memory
637 : : char *first = (char*)meminfo.BaseAddress;
638 : : char *last = first + meminfo.RegionSize;
639 : : if (last > max32addr)
640 : : last = max32addr;
641 : : // adjust first up to the first allocation granularity boundary
642 : : // adjust last down to the last allocation granularity boundary
643 : : first = (char*)(((long long)first + info.dwAllocationGranularity - 1) & ~(info.dwAllocationGranularity - 1));
644 : : last = (char*)((long long)last & ~(info.dwAllocationGranularity - 1));
645 : : if (last != first) {
646 : : void *p = VirtualAlloc(first, last - first, MEM_RESERVE, PAGE_NOACCESS); // reserve all memory in between
647 : : if ((char*)p != first)
648 : : // Wine and Windows10 seem to have issues with reporting memory access information correctly
649 : : // so we sometimes end up with unexpected results - this is just ignore those and continue
650 : : // this is just a debugging aid to help find accidental pointer truncation anyways,
651 : : // so it is not critical
652 : : VirtualFree(p, 0, MEM_RELEASE);
653 : : }
654 : : }
655 : : meminfo.BaseAddress = (void*)((char*)meminfo.BaseAddress + meminfo.RegionSize);
656 : : }
657 : : #endif
658 : 15 : return;
659 : : }
660 : :
661 : : // Actual definition in `ast.c`
662 : : void jl_lisp_prompt(void);
663 : :
664 : : #ifdef _OS_LINUX_
665 : 0 : static void rr_detach_teleport(void) {
666 : : #define RR_CALL_BASE 1000
667 : : #define SYS_rrcall_detach_teleport (RR_CALL_BASE + 9)
668 : 0 : int err = syscall(SYS_rrcall_detach_teleport, 0, 0, 0, 0, 0, 0);
669 [ # # # # ]: 0 : if (err < 0 || jl_running_under_rr(1)) {
670 : 0 : jl_error("Failed to detach from rr session");
671 : : }
672 : 0 : }
673 : : #endif
674 : :
675 : 15 : JL_DLLEXPORT int jl_repl_entrypoint(int argc, char *argv[])
676 : : {
677 : : // no-op on Windows, note that the caller must have already converted
678 : : // from `wchar_t` to `UTF-8` already if we're running on Windows.
679 : 15 : uv_setup_args(argc, argv);
680 : :
681 : : // No-op on non-windows
682 : 15 : lock_low32();
683 : :
684 : 15 : libsupport_init();
685 [ + - - + ]: 15 : int lisp_prompt = (argc >= 2 && strcmp((char*)argv[1],"--lisp") == 0);
686 [ - + ]: 15 : if (lisp_prompt) {
687 : 0 : memmove(&argv[1], &argv[2], (argc-2)*sizeof(void*));
688 : 0 : argc--;
689 : : }
690 : 15 : char **new_argv = argv;
691 : 15 : jl_parse_opts(&argc, (char***)&new_argv);
692 : :
693 : : // The parent process requested that we detach from the rr session.
694 : : // N.B.: In a perfect world, we would only do this for the portion of
695 : : // the execution where we actually need to exclude rr (e.g. because we're
696 : : // testing for the absence of a memory-model-dependent bug).
697 [ - + - - ]: 15 : if (jl_options.rr_detach && jl_running_under_rr(0)) {
698 : : #ifdef _OS_LINUX_
699 : 0 : rr_detach_teleport();
700 : 0 : execv("/proc/self/exe", argv);
701 : : #endif
702 : 0 : jl_error("Failed to self-execute");
703 : : }
704 : :
705 : 15 : julia_init(jl_options.image_file_specified ? JL_IMAGE_CWD : JL_IMAGE_JULIA_HOME);
706 [ - + ]: 15 : if (lisp_prompt) {
707 : 0 : jl_current_task->world_age = jl_get_world_counter();
708 : 0 : jl_lisp_prompt();
709 : 0 : return 0;
710 : : }
711 : 15 : int ret = true_main(argc, (char**)new_argv);
712 : 13 : jl_atexit_hook(ret);
713 : 13 : return ret;
714 : : }
715 : :
716 : : #ifdef __cplusplus
717 : : }
718 : : #endif
|