Initialization of the Julia runtime
julia -e 'println("Hello World!")'
の実行方法は以下の通りです。
main()
実行は main()
in cli/loader_exe.c
で開始され、jl_load_repl()
を呼び出します cli/loader_lib.c
これはいくつかのライブラリを読み込み、最終的に jl_repl_entrypoint()
in src/jlapi.c
を呼び出します。
jl_repl_entrypoint()
は libsupport_init()
を呼び出して C ライブラリのロケールを設定し、「ios」ライブラリを初期化します(ios_init_stdstreams()
と Legacy ios.c
library)。
次 jl_parse_opts()
はコマンドラインオプションを処理するために呼び出されます。 jl_parse_opts()
は、コード生成や初期化に影響を与えるオプションのみを扱うことに注意してください。他のオプションは、後で exec_options()
in base/client.jl
によって後で処理されます。
jl_parse_opts()
はコマンドラインオプションを global jl_options
struct に保存します。
julia_init()
julia_init()
in init.c
は main()
によって呼び出され、_julia_init()
in init.c
を呼び出します。
_julia_init()
は再度 libsupport_init()
を呼び出します(2回目は何もしません)。
restore_signals()
は、シグナルハンドラーマスクをゼロにするために呼び出されます。
jl_resolve_sysimg_location()
は、基本システムイメージのために構成されたパスを検索します。 Building the Julia system image を参照してください。
jl_gc_init()
は、弱参照、保持された値、およびファイナライゼーションのためのアロケーションプールとリストを設定します。
jl_init_frontend()
は、スキャナー/パーサーを含む事前コンパイルされたfemtolispイメージをロードして初期化します。
jl_init_types()
は jl_datatype_t
型の説明オブジェクトを built-in types defined in julia.h
のために作成します。例えば、
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()
は jl_datatype_t* jl_task_type
オブジェクトを作成し、グローバル jl_root_task
構造体を初期化し、jl_current_task
をルートタスクに設定します。
jl_init_codegen()
は LLVM library を初期化します。
jl_init_serializer()
は、組み込みの jl_value_t
値のための 8 ビットシリアル化タグを初期化します。
もし sysimg ファイル (!jl_options.image_file
) が存在しない場合、Core
および Main
モジュールが作成され、boot.jl
が評価されます:
jl_core_module = jl_new_module(jl_symbol("Core"))
は、Juliaの Core
モジュールを作成します。
jl_init_intrinsic_functions()
は、新しいJuliaモジュール Intrinsics
を作成し、定数 jl_intrinsic_type
シンボルを含みます。これらは、各 intrinsic function に対する整数コードを定義します。 emit_intrinsic()
は、コード生成中にこれらのシンボルをLLVM命令に変換します。
jl_init_primitives()
は、C関数をJulia関数シンボルにフックします。例えば、シンボル Core.:(===)()
は、add_builtin_func("===", jl_f_is)
を呼び出すことによってC関数ポインタ jl_f_is()
にバインドされています。
jl_new_main_module()
はグローバル "Main" モジュールを作成し、jl_current_task->current_module = jl_main_module
を設定します。
注意: _julia_init()
then sets jl_root_task->current_module = jl_core_module
。この時点で jl_root_task
は jl_current_task
のエイリアスであるため、上記の jl_new_main_module()
によって設定された current_module
は上書きされます。
jl_load("boot.jl", sizeof("boot.jl"))
は jl_parse_eval_all
を呼び出し、これは繰り返し jl_toplevel_eval_flex()
を呼び出して boot.jl
を実行します。 <!– TODO – evalを詳しく調べる? –>
jl_get_builtin_hooks()
は、boot.jl
で定義された Julia グローバルに対するグローバル C ポインタを初期化します。
jl_init_box_caches()
は、1024までの値のためにグローバルなボックス化された整数値オブジェクトを事前に割り当てます。これにより、後でボックス化された整数の割り当てが高速化されます。例えば:
jl_value_t *jl_box_uint8(uint32_t x)
{
return boxed_uint8_cache[(uint8_t)x];
}
_julia_init()
iterates は jl_core_module->bindings.table
の上で jl_datatype_t
値を探し、型名のモジュールプレフィックスを jl_core_module
に設定します。
jl_add_standard_imports(jl_main_module)
does "using Base" in the "Main" module.
注意: _julia_init()
は、上で jl_core_module
に設定される前のように jl_root_task->current_module = jl_main_module
に戻ります。
プラットフォーム固有のシグナルハンドラは、SIGSEGV
(OSX、Linux)および SIGFPE
(Windows)用に初期化されます。
他のシグナル(SIGINFO, SIGBUS, SIGILL, SIGTERM, SIGABRT, SIGQUIT, SIGSYS
および SIGPIPE
)は sigdie_handler()
に接続されており、バックトレースを出力します。
jl_init_restored_module()
は、各デシリアライズされたモジュールに対してjl_module_run_initializer()
を呼び出し、__init__()
関数を実行します。
最後に sigint_handler()
が SIGINT
に接続され、jl_throw(jl_interrupt_exception)
を呼び出します。
_julia_init()
は back to main()
in cli/loader_exe.c
を返し、main()
は repl_entrypoint(argc, (char**)argv)
を呼び出します。
repl_entrypoint()
repl_entrypoint()
は argv[]
の内容を Base.ARGS
にロードします。
もしコマンドラインに.jl
の「プログラム」ファイルが供給された場合、exec_program()
はjl_load(program,len)
を呼び出し、これはjl_parse_eval_all
を呼び出し、これは繰り返しjl_toplevel_eval_flex()
を呼び出してプログラムを実行します。
However, in our example (julia -e 'println("Hello World!")'
), jl_get_global(jl_base_module, jl_symbol("_start"))
looks up Base._start
and jl_apply()
executes it.
Base._start
Base._start
は Base.exec_options
を呼び出し、さらに jl_parse_input_line("println("Hello World!")")
を呼び出して式オブジェクトを作成し、Core.eval(Main, ex)
を呼び出して Main
のモジュールコンテキストで解析された式 ex
を実行します。
Core.eval
Core.eval(Main, ex)
は jl_toplevel_eval_in(m, ex)
を呼び出し、さらに jl_toplevel_eval_flex
を呼び出します。 jl_toplevel_eval_flex
は、与えられたコードスンクをコンパイルするか、インタプリタで実行するかを決定するための単純なヒューリスティックを実装しています。 println("Hello World!")
が与えられた場合、通常はインタプリタでコードを実行することを決定し、その場合は jl_interpret_toplevel_thunk
を呼び出し、次に eval_body
を呼び出します。
スタックダンプは、インタープリタが Base.println()
と Base.print()
のさまざまなメソッドを通過して、最終的に write(s::IO, a::Array{T}) where T
に到達する様子を示しています。これは ccall(jl_uv_write())
を実行します。
jl_uv_write()
は、JL_STDOUT
に「Hello World!」を書き込むためにuv_write()
を呼び出します。Libuv wrappers for stdioを参照してください。
Hello World!
Stack frame | Source code | Notes |
---|---|---|
jl_uv_write() | jl_uv.c | called though ccall |
julia_write_282942 | stream.jl | function write!(s::IO, a::Array{T}) where T |
julia_print_284639 | ascii.jl | print(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.c | Base.print(Base.TTY, String) |
jl_apply() | julia.h | |
jl_trampoline() | builtins.c | |
jl_apply() | julia.h | |
jl_apply_generic() | gf.c | Base.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.c | Base.println(Base.TTY, String, String...) |
jl_apply() | julia.h | |
jl_trampoline() | builtins.c | |
jl_apply() | julia.h | |
jl_apply_generic() | gf.c | Base.println(String,) |
jl_apply() | julia.h | |
do_call() | interpreter.c | |
eval_body() | interpreter.c | |
jl_interpret_toplevel_thunk | interpreter.c | |
jl_toplevel_eval_flex | toplevel.c | |
jl_toplevel_eval_in | toplevel.c | |
Core.eval | boot.jl |
私たちの例には関数呼び出しが1つだけあり、それが「Hello World!」を印刷する仕事を終えたので、スタックはすぐにmain()
に戻ります。
jl_atexit_hook()
main()
は jl_atexit_hook()
を呼び出します。これにより Base._atexit
が呼び出され、その後 jl_gc_run_all_finalizers()
が呼び出され、libuv ハンドルがクリーンアップされます。
julia_save()
最後に、main()
はjulia_save()
を呼び出します。これはコマンドラインで要求されると、ランタイム状態を新しいシステムイメージに保存します。jl_compile_all()
およびjl_save_system_image()
を参照してください。