Initializing the Julia Runtime Environment
main()
Execution begins with https://github.com/JuliaLang/julia/blob/master/cli/loader_exe.c [main()
in cli/loader_exe.c'], which calls `jl_load_repl()
in https://github.com/JuliaLang/julia/blob/master/cli/loader_lib.c [cli/loader_lib.c
], which loads several libraries, eventually calling https://github.com/JuliaLang/julia/blob/master/src/jlapi.c [jl_repl_entrypoint()
in src/jlapi.c
].
'jl_repl_entrypoint()` calls https://github.com/JuliaLang/julia/blob/master/src/support/libsupportinit.c [libsupport_init()
] to install the C library language standard and initialize the ios library (see the page https://github.com/JuliaLang/julia/blob/master/src/support/ios.c [ios_init_stdstreams()
] and description outdated library `ios.c').
Next, it is called https://github.com/JuliaLang/julia/blob/master/src/jloptions.c [jl_parse_opts()
] for processing command line parameters. Note that jl_parse_opts()
only works with parameters that affect code generation or early initialization. Other parameters are processed later by the function https://github.com/JuliaLang/julia/blob/master/base/client.jl [exec_options()
in the base/client.jl
file].
'jl_parse_opts()` stores command line parameters in https://github.com/JuliaLang/julia/blob/master/src/julia.h [the global structure of `jl_options'].
julia_init()
https://github.com/JuliaLang/julia/blob/master/src/init.c [julia_init()
in init.c
] is called by the function main()
and calls https://github.com/JuliaLang/julia/blob/master/src/init.c ['_julia_init()` in init.c
].
The '_julia_init()` function starts by calling libsupport_init()
again (it doesn’t do anything the second time).
https://github.com/JuliaLang/julia/blob/master/src/signals-unix.c [restore_signals()
] is called to reset the mask of the signal handler.
https://github.com/JuliaLang/julia/blob/master/src/init.c ['jl_resolve_sysimg_location()`] searches for configured paths for the base system image. See the chapter Julia system image build.
https://github.com/JuliaLang/julia/blob/master/src/gc.c ['jl_gc_init()`] specifies allocation pools and lists for weak references, stored values, and finalizing.
https://github.com/JuliaLang/julia/blob/master/src/ast.c ['jl_init_frontend()`] loads and initializes a precompiled femtolisp image containing a scanner or analyzer.
jl_init_types()
creates objects of type description jl_datatype_t
for https://github.com/JuliaLang/julia/blob/master/src/julia.h [built-in types defined in julia.h
]. For example:
jl_any_type = jl_new_abstracttype(jl_symbol("Any"), core, NULL, jl_emptysvec);
jl_any_type->super = jl_any_type;
jl_type_type = jl_new_abstracttype(jl_symbol("Type"), core, jl_any_type, jl_emptysvec);
jl_int32_type = jl_new_primitivetype(jl_symbol("Int32"), core,
jl_any_type, jl_emptysvec, 32);
jl_init_tasks()
creates the object jl_datatype_t* jl_task_type', initializes the global structure `jl_root_task
and sets the jl_current_task
for the root task.
https://github.com/JuliaLang/julia/blob/master/src/codegen.cpp [jl_init_codegen()
] initializes https://llvm.org [the LLVM library].
https://github.com/JuliaLang/julia/blob/master/src/staticdata.c ['jl_init_serializer()`] initializes 8-bit serialization tags for embedded values of `jl_value_t'.
If the sysimg file ('!jl_options.image_file`) is missing, the Core
and Main' modules are created and the `boot.jl
file is calculated.
jl_core_module = jl_new_module(jl_symbol("Core"))
creates the Julia Core
module.
https://github.com/JuliaLang/julia/blob/master/src/intrinsics.cpp ['jl_init_intrinsic_functions()] creates a new Julia `Intrinsics
module containing the constant characters jl_intrinsic_type'. They define an integer code for each https://github.com/JuliaLang/julia/blob/master/src/intrinsics.cpp [internal function]. https://github.com/JuliaLang/julia/blob/master/src/intrinsics.cpp ['emit_intrinsic()
] converts these characters into LLVM instructions during code generation.
https://github.com/JuliaLang/julia/blob/master/src/builtins.c ['jl_init_primitives()] binds C functions to Julia function symbols. For example, the character `Core.:(===)()
binds to the pointer of the C`jl_f_is() function` by calling `add_builtin_func("===", jl_f_is)'.
https://github.com/JuliaLang/julia/blob/master/src/toplevel.c [jl_new_main_module()'] creates a global Main module and sets `+jl_current_task→current_module = jl_main_module+
.
Note. _julia_init()
https://github.com/JuliaLang/julia/blob/master/src/init.c [then sets] jl_root_task->current_module = jl_core_module
. 'jl_root_task` is an alias of jl_current_task
at this point, so the current_module
set above with jl_new_main_module()
is overwritten.
jl_load("boot.jl", sizeof("boot.jl"))
calls the function https://github.com/JuliaLang/julia/blob/master/src/ast.c [jl_parse_eval_all
], which repeatedly calls https://github.com/JuliaLang/julia/blob/master/src/toplevel.c [jl_toplevel_eval_flex()
] to perform https://github.com/JuliaLang/julia/blob/master/base/boot.jl [boot.jl
]. <!-- TODO — drill down into eval? -→
https://github.com/JuliaLang/julia/blob/master/src/init.c [jl_get_builtin_hooks()
] initializes C global pointers to Julia global objects defined in `boot.jl'.
https://github.com/JuliaLang/julia/blob/master/src/datatype.c ['jl_init_box_caches()`] pre-allocates global objects of packed integer values for values up to 1024. This speeds up the distribution of packed integer values later on. For example:
jl_value_t *jl_box_uint8(uint32_t x)
{
return boxed_uint8_cache[(uint8_t)x];
}
https://github.com/JuliaLang/julia/blob/master/src/init.c ['_julia_init()` iterates] jl_core_module->bindings.table
in search of the values of jl_datatype_t
and sets jl_core_module
as the prefix of the type name module.
jl_add_standard_imports(jl_main_module)
applies "using Base" in the Main module.
Note. '_julia_init()` now reverts to jl_root_task->current_module = jl_main_module
as it was before installing jl_core_module
above.
Platform-specific signal handlers are initialized for SIGSEGV
(OSX, Linux) and `SIGFPE' (Windows).
Other signals (SIGINFO, SIGBUS, SIGILL, SIGTERM, SIGABRT, SIGQUIT, SIGSYS
and SIGPIPE') are attached to the function https://github.com/JuliaLang/julia/blob/master/src/signals-unix.c [`sigdie_handler()
], which outputs a backtrace.
https://github.com/JuliaLang/julia/blob/master/src/staticdata.c ['jl_init_restored_module()] calls https://github.com/JuliaLang/julia/blob/master/src/module.c ['jl_module_run_initializer()
] for each deserialized module to execute the function `__init__()'.
Finally, https://github.com/JuliaLang/julia/blob/master/src/signals-unix.c [sigint_handler()
] joins SIGINT
and causes jl_throw(jl_interrupt_exception)
.
'_julia_init()` then returns https://github.com/JuliaLang/julia/blob/master/cli/loader_exe.c [back to main()
in cli/loader_exe.c'], and `main()
calls repl_entrypoint(argc, (char**)argv)
.
sysimg
If there is a sysimg file, it contains a pre-prepared image of the https://github.com/JuliaLang/julia/blob/master/src/staticdata.c ['jl_restore_system_image() Note. https://github.com/JuliaLang/julia/blob/master/src/staticdata.c ['jl_restore_system_image()` (and |
repl_entrypoint()
https://github.com/JuliaLang/julia/blob/master/src/jlapi.c [repl_entrypoint()'] loads the contents of `argv[]
into Base.ARGS
.
If the .jl
file of the program was specified on the command line, https://github.com/JuliaLang/julia/blob/master/src/jlapi.c [exec_program()
] calls https://github.com/JuliaLang/julia/blob/master/src/toplevel.c [jl_load(program,len)
], which calls https://github.com/JuliaLang/julia/blob/master/src/ast.c [jl_parse_eval_all
], which repeatedly calls https://github.com/JuliaLang/julia/blob/master/src/toplevel.c [jl_toplevel_eval_flex()
] to execute the program.
However, in our example (julia -e 'println("Hello World!")'
) jl_get_global(jl_base_module, jl_symbol("_start"))
is looking for https://github.com/JuliaLang/julia/blob/master/base/client.jl [Base._start
] and https://github.com/JuliaLang/julia/blob/master/src/julia.h ['jl_apply()`] executes it.
Base._start
https://github.com/JuliaLang/julia/blob/master/base/client.jl [Base._start
] causes https://github.com/JuliaLang/julia/blob/master/base/client.jl [Base.exec_options
], which calls https://github.com/JuliaLang/julia/blob/master/src/ast.c [jl_parse_input_line("println("Hello World!")")
] to create an expression object and Core.eval(Main, ex)
to execute the analyzed expression ex
in the context of the Main
module.
Core.eval
Core.eval(Main, ex)
calls the function https://github.com/JuliaLang/julia/blob/master/src/toplevel.c [jl_toplevel_eval_in(m, ex)
], which causes https://github.com/JuliaLang/julia/blob/master/src/toplevel.c [jl_toplevel_eval_flex
]. 'jl_toplevel_eval_flex` implements a simple heuristic for deciding whether to compile a given piece of code or run it with an interpreter. When println("Hello World!")
is set, it is usually decided to run the code using an interpreter. In this case, it is called https://github.com/JuliaLang/julia/blob/master/src/interpreter.c [jl_interpret_toplevel_thunk
], which then calls https://github.com/JuliaLang/julia/blob/master/src/interpreter.c [eval_body
].
The stack dump below shows how the interpreter goes through the various methods. Base.println()
and Base.print()
before reaching https://github.com/JuliaLang/julia/blob/master/base/stream.jl [write(s::IO, a::Array{T}) where T
], which executes `ccall(jl_uv_write())'.
https://github.com/JuliaLang/julia/blob/master/src/jl_uv.c ['jl_uv_write()'] calls uv_write()
to write Hello World! in `JL_STDOUT'. See the chapter libuv wrappers for stdio.
Hello World!
Stack frame | The source code | Notes |
---|---|---|
|
|
it is called using a keyword |
|
|
The |
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Since in our example there is only one call to the function that has done its job and output Hello World!, now the stack quickly returns to `main()'.
jl_atexit_hook()
main()
calls https://github.com/JuliaLang/julia/blob/master/src/init.c [jl_atexit_hook()
]. It calls Base._atexit', then calls https://github.com/JuliaLang/julia/blob/master/src/gc.c [`jl_gc_run_all_finalizers()
] and clears libuv handlers.
julia_save()
Finally, main()
calls https://github.com/JuliaLang/julia/blob/master/src/init.c [julia_save()
], which (upon request on the command line) saves the state of the runtime environment to a new system image. See https://github.com/JuliaLang/julia/blob/master/src/gf.c [jl_compile_all()
] and https://github.com/JuliaLang/julia/blob/master/src/staticdata.c [jl_save_system_image()
].