Initialization of the Julia runtime
Julia runtime, julia -e 'println("Hello World!")'
, executes the command as follows:
main()
Yürütme main()
in cli/loader_exe.c
ile başlar, bu da jl_load_repl()
çağrısını cli/loader_lib.c
içinde yapar, birkaç kütüphaneyi yükler ve nihayetinde jl_repl_entrypoint()
in src/jlapi.c
çağrısını yapar.
jl_repl_entrypoint()
libsupport_init()
C kütüphanesi yerel ayarını ayarlamak ve "ios" kütüphanesini başlatmak için çağrılır (bkz. ios_init_stdstreams()
ve Legacy ios.c
library).
Son jl_parse_opts()
komut satırı seçeneklerini işlemek için çağrılır. jl_parse_opts()
yalnızca kod üretimi veya erken başlatmayı etkileyen seçeneklerle ilgilenir. Diğer seçenekler daha sonra exec_options()
in base/client.jl
tarafından işlenir.
jl_parse_opts()
komut satırı seçeneklerini global jl_options
struct içinde saklar.
julia_init()
julia_init()
in init.c
main()
tarafından çağrılır ve _julia_init()
in init.c
çağrılır.
_julia_init()
önce libsupport_init()
çağrısı yapar (ikinci kez hiçbir şey yapmaz).
restore_signals()
sinyal işleyici maskesini sıfırlamak için çağrılır.
jl_resolve_sysimg_location()
temel sistem görüntüsü için yapılandırılmış yolları arar. Building the Julia system image için.
jl_gc_init()
zayıf referanslar, korunmuş değerler ve sonlandırma için tahsis havuzları ve listeleri kurar.
jl_init_frontend()
bir tarayıcı/parsing içeren önceden derlenmiş bir femtolisp görüntüsünü yükler ve başlatır.
jl_init_types()
jl_datatype_t
türü tanım nesneleri oluşturur built-in types defined in julia.h
. örneğin.
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
nesnesini oluşturur; global jl_root_task
yapısını başlatır; ve jl_current_task
'ı kök göreve ayarlar.
jl_init_codegen()
LLVM library olarak başlatır.
jl_init_serializer()
8-bit serileştirme etiketlerini yerleşik jl_value_t
değerleri için başlatır.
Eğer bir sysimg dosyası yoksa (!jl_options.image_file
), o zaman Core
ve Main
modülleri oluşturulur ve boot.jl
değerlendirilir:
jl_core_module = jl_new_module(jl_symbol("Core"))
Julia Core
modülünü oluşturur.
jl_init_intrinsic_functions()
yeni bir Julia modülü Intrinsics
oluşturur ve jl_intrinsic_type
sabitlerini içerir. Bu sabitler, her bir intrinsic function için bir tamsayı kodu tanımlar. emit_intrinsic()
bu sembolleri kod üretimi sırasında LLVM talimatlarına çevirir.
jl_init_primitives()
C fonksiyonlarını Julia fonksiyon sembollerine bağlar. Örneğin, Core.:(===)()
sembolü, add_builtin_func("===", jl_f_is)
çağrısı ile C fonksiyon işaretçisi jl_f_is()
'e bağlanır.
jl_new_main_module()
global "Main" modülünü oluşturur ve jl_current_task->current_module = jl_main_module
olarak ayarlar.
Not: _julia_init()
then sets jl_root_task->current_module = jl_core_module
. jl_root_task
bu noktada jl_current_task
'ın bir takma adıdır, bu nedenle yukarıda jl_new_main_module()
tarafından ayarlanan current_module
üzerine yazılır.
jl_load("boot.jl", sizeof("boot.jl"))
çağrılır jl_parse_eval_all
bu da sürekli olarak çağrılır jl_toplevel_eval_flex()
çalıştırmak için boot.jl
. <!– TODO – eval içine in? –>
jl_get_builtin_hooks()
Julia globals'ı boot.jl
dosyasında tanımlanan global C işaretçilerini başlatır.
jl_init_box_caches()
global kutulu tam sayılar için 1024'e kadar değerler için önceden tahsis eder. Bu, daha sonra kutulu int'lerin tahsisatını hızlandırır. örn.:
jl_value_t *jl_box_uint8(uint32_t x)
{
return boxed_uint8_cache[(uint8_t)x];
}
_julia_init()
iterates jl_core_module->bindings.table
üzerinde jl_datatype_t
değerlerini arar ve tür adının modül ön ekini jl_core_module
olarak ayarlar.
jl_add_standard_imports(jl_main_module)
"Ana Modül" içinde "Base" kullanıyor.
Not: _julia_init()
artık yukarıda jl_core_module
olarak ayarlandığı gibi değil, jl_root_task->current_module = jl_main_module
olarak geri dönmektedir.
Platform spesifik sinyal işleyicileri SIGSEGV
(OSX, Linux) ve SIGFPE
(Windows) için başlatılır.
Diğer sinyaller (SIGINFO, SIGBUS, SIGILL, SIGTERM, SIGABRT, SIGQUIT, SIGSYS
ve SIGPIPE
), sigdie_handler()
ile bağlanmıştır ve bir geri izleme (backtrace) yazdırır.
jl_init_restored_module()
her jl_module_run_initializer()
her her deserialized modül için __init__()
fonksiyonunu çalıştırmak üzere çağrılır.
Sonunda sigint_handler()
SIGINT
ile bağlandı ve jl_throw(jl_interrupt_exception)
çağrısı yapıyor.
_julia_init()
ardından back to main()
in cli/loader_exe.c
ve main()
repl_entrypoint(argc, (char**)argv)
çağrısını yapar.
repl_entrypoint()
repl_entrypoint()
argv[]
'in içeriklerini Base.ARGS
'ya yükler.
Eğer bir .jl
"program" dosyası komut satırında sağlandıysa, o zaman exec_program()
jl_load(program,len)
çağırır, bu da jl_parse_eval_all
çağırır, bu da sürekli olarak jl_toplevel_eval_flex()
çağırarak programı çalıştırır.
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)
Core.eval
Core.eval(Main, ex)
çağrıları jl_toplevel_eval_in(m, ex)
, bu da jl_toplevel_eval_flex
çağrısını yapar. jl_toplevel_eval_flex
, verilen bir kod thunk'unu derleyip derlemeyeceğine veya yorumlayıcı tarafından çalıştırıp çalıştırmayacağına karar vermek için basit bir sezgi uygular. println("Hello World!")
verildiğinde, genellikle kodu yorumlayıcı tarafından çalıştırmaya karar verir; bu durumda jl_interpret_toplevel_thunk
çağrısını yapar, bu da eval_body
çağrısını yapar.
Aşağıdaki yığın dökümü, yorumlayıcının Base.println()
ve Base.print()
çeşitli yöntemleri aracılığıyla nasıl ilerlediğini göstermektedir ve write(s::IO, a::Array{T}) where T
ile sonuçlanır ve ccall(jl_uv_write())
işlemini gerçekleştirir.
jl_uv_write()
uv_write()
'i JL_STDOUT
'a "Hello World!" yazmak için çağrılır. 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 |
Örneğimizde sadece bir fonksiyon çağrısı olduğu için, "Hello World!" yazdırma işini yaptıktan sonra, yığın hızla main()
'e geri sarılır.
jl_atexit_hook()
main()
jl_atexit_hook()
çağrısını yapar. Bu Base._atexit
çağrısını yapar, ardından jl_gc_run_all_finalizers()
çağrısını yapar ve libuv handle'larını temizler.
julia_save()
Sonunda, main()
julia_save()
çağrısını yapar; bu, komut satırında istendiğinde çalışma durumunu yeni bir sistem görüntüsüne kaydeder. jl_compile_all()
ve jl_save_system_image()
'e bakın.