Movatterモバイル変換


[0]ホーム

URL:


GitHub

Initialization of the Julia runtime

How does the Julia runtime executejulia -e 'println("Hello World!")' ?

main()

Execution starts atmain() incli/loader_exe.c, which callsjl_load_repl() incli/loader_lib.c which loads a few libraries, eventually callingjl_repl_entrypoint() insrc/jlapi.c.

jl_repl_entrypoint() callslibsupport_init() to set the C library locale and to initialize the "ios" library (seeios_init_stdstreams() andLegacyios.c library).

Nextjl_parse_opts() is called to process command line options. Note thatjl_parse_opts() only deals with options that affect code generation or early initialization. Other options are handled later byexec_options() inbase/client.jl.

jl_parse_opts() stores command line options in theglobaljl_options struct.

julia_init()

julia_init() ininit.c is called bymain() and calls_julia_init() ininit.c.

_julia_init() begins by callinglibsupport_init() again (it does nothing the second time).

restore_signals() is called to zero the signal handler mask.

jl_resolve_sysimg_location() searches configured paths for the base system image. SeeBuilding the Julia system image.

jl_gc_init() sets up allocation pools and lists for weak refs, preserved values and finalization.

jl_init_frontend() loads and initializes a pre-compiled femtolisp image containing the scanner/parser.

jl_init_types() createsjl_datatype_t type description objects for thebuilt-in types defined injulia.h. e.g.

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 thejl_datatype_t* jl_task_type object; initializes the globaljl_root_task struct; and setsjl_current_task to the root task.

jl_init_codegen() initializes theLLVM library.

jl_init_serializer() initializes 8-bit serialization tags for builtinjl_value_t values.

If there is no sysimg file (!jl_options.image_file) then theCore andMain modules are created andboot.jl is evaluated:

jl_core_module = jl_new_module(jl_symbol("Core")) creates the JuliaCore module.

jl_init_intrinsic_functions() creates a new Julia moduleIntrinsics containing constantjl_intrinsic_type symbols. These define an integer code for eachintrinsic function.emit_intrinsic() translates these symbols into LLVM instructions during code generation.

jl_init_primitives() hooks C functions up to Julia function symbols. e.g. the symbolCore.:(===)() is bound to C function pointerjl_f_is() by callingadd_builtin_func("===", jl_f_is).

jl_new_main_module() creates the global "Main" module and setsjl_current_task->current_module = jl_main_module.

Note:_julia_init()then setsjl_root_task->current_module = jl_core_module.jl_root_task is an alias ofjl_current_task at this point, so thecurrent_module set byjl_new_main_module() above is overwritten.

jl_load("boot.jl", sizeof("boot.jl")) callsjl_parse_eval_all which repeatedly callsjl_toplevel_eval_flex() to executeboot.jl. <!– TODO – drill down into eval? –>

jl_get_builtin_hooks() initializes global C pointers to Julia globals defined inboot.jl.

jl_init_box_caches() pre-allocates global boxed integer value objects for values up to 1024. This speeds up allocation of boxed ints later on. e.g.:

jl_value_t *jl_box_uint8(uint32_t x){    return boxed_uint8_cache[(uint8_t)x];}

_julia_init() iterates over thejl_core_module->bindings.table looking forjl_datatype_t values and sets the type name's module prefix tojl_core_module.

jl_add_standard_imports(jl_main_module) does "using Base" in the "Main" module.

Note:_julia_init() now reverts tojl_root_task->current_module = jl_main_module as it was before being set tojl_core_module above.

Platform specific signal handlers are initialized forSIGSEGV (OSX, Linux), andSIGFPE (Windows).

Other signals (SIGINFO, SIGBUS, SIGILL, SIGTERM, SIGABRT, SIGQUIT, SIGSYS andSIGPIPE) are hooked up tosigdie_handler() which prints a backtrace.

jl_init_restored_module() callsjl_module_run_initializer() for each deserialized module to run the__init__() function.

Finallysigint_handler() is hooked up toSIGINT and callsjl_throw(jl_interrupt_exception).

_julia_init() then returnsback tomain() incli/loader_exe.c andmain() callsrepl_entrypoint(argc, (char**)argv).

sysimg

If there is a sysimg file, it contains a pre-cooked image of theCore andMain modules (and whatever else is created byboot.jl). SeeBuilding the Julia system image.

jl_restore_system_image() deserializes the saved sysimg into the current Julia runtime environment and initialization continues afterjl_init_box_caches() below...

Note:jl_restore_system_image() (andstaticdata.c in general) uses theLegacyios.c library.

repl_entrypoint()

repl_entrypoint() loads the contents ofargv[] intoBase.ARGS.

If a.jl "program" file was supplied on the command line, thenexec_program() callsjl_load(program,len) which callsjl_parse_eval_all which repeatedly callsjl_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")) looks upBase._start andjl_apply() executes it.

Base._start

Base._start callsBase.exec_options which callsjl_parse_input_line("println("Hello World!")") to create an expression object andCore.eval(Main, ex) to execute the parsed expressionex in the module context ofMain.

Core.eval

Core.eval(Main, ex) callsjl_toplevel_eval_in(m, ex), which callsjl_toplevel_eval_flex.jl_toplevel_eval_flex implements a simple heuristic to decide whether to compile a given code thunk or run it by interpreter. When givenprintln("Hello World!"), it would usually decide to run the code by interpreter, in which case it callsjl_interpret_toplevel_thunk, which then callseval_body.

The stack dump below shows how the interpreter works its way through various methods ofBase.println() andBase.print() before arriving atwrite(s::IO, a::Array{T}) where T which doesccall(jl_uv_write()).

jl_uv_write() callsuv_write() to write "Hello World!" toJL_STDOUT. SeeLibuv wrappers for stdio.:

Hello World!
Stack frameSource codeNotes
jl_uv_write()jl_uv.ccalled thoughccall
julia_write_282942stream.jlfunctionwrite!(s::IO, a::Array{T}) where T
julia_print_284639ascii.jlprint(io::IO, s::String) = (write(io, s); nothing)
jlcall_print_284639
jl_apply()julia.h
jl_trampoline()builtins.c
jl_apply()julia.h
jl_apply_generic()gf.cBase.print(Base.TTY, String)
jl_apply()julia.h
jl_trampoline()builtins.c
jl_apply()julia.h
jl_apply_generic()gf.cBase.print(Base.TTY, String, Char, Char...)
jl_apply()julia.h
jl_f_apply()builtins.c
jl_apply()julia.h
jl_trampoline()builtins.c
jl_apply()julia.h
jl_apply_generic()gf.cBase.println(Base.TTY, String, String...)
jl_apply()julia.h
jl_trampoline()builtins.c
jl_apply()julia.h
jl_apply_generic()gf.cBase.println(String,)
jl_apply()julia.h
do_call()interpreter.c
eval_body()interpreter.c
jl_interpret_toplevel_thunkinterpreter.c
jl_toplevel_eval_flextoplevel.c
jl_toplevel_eval_intoplevel.c
Core.evalboot.jl

Since our example has just one function call, which has done its job of printing "Hello World!", the stack now rapidly unwinds back tomain().

jl_atexit_hook()

main() callsjl_atexit_hook(). This callsBase._atexit, then callsjl_gc_run_all_finalizers() and cleans up libuv handles.

julia_save()

Finally,main() callsjulia_save(), which if requested on the command line, saves the runtime state to a new system image. Seejl_compile_all() andjl_save_system_image().

Settings


This document was generated withDocumenter.jl version 1.8.0 onWednesday 9 July 2025. Using Julia version 1.11.6.


[8]ページ先頭

©2009-2025 Movatter.jp