Engee 文档

初始化Julia运行时环境

Julia运行时如何执行’julia-e’println("Hello World!")"?

'主要()`

执行开始于https://github.com/JuliaLang/julia/blob/master/cli/loader_exe.c [main()`in’cli/loader_exe.c'],其中调用`jl_load_repl()'在https://github.com/JuliaLang/julia/blob/master/cli/loader_lib.c ['cli/loader_lib.c'],它加载了几个库,最终调用https://github.com/JuliaLang/julia/blob/master/src/jlapi.c [`jl_repl_entrypoint()`在’src/jlapi.c']。 `jl_repl_entrypoint()'调用https://github.com/JuliaLang/julia/blob/master/src/support/libsupportinit.c ['libsupport_init()]安装C库语言标准并初始化ios库(见页面https://github.com/JuliaLang/julia/blob/master/src/support/ios.c ['ios_init_stdstreams()`]和描述 过时的库’的ios。c')。

接下来,它被称为https://github.com/JuliaLang/julia/blob/master/src/jloptions.c [`jl_parse_opts()']用于处理命令行参数。 请注意’jl_parse_opts()'仅适用于影响代码生成或早期初始化的参数。 其他参数稍后由函数处理https://github.com/JuliaLang/julia/blob/master/base/client.jl [`base/client中的`exec_options()'。jl’文件]。 `jl_parse_opts()'将命令行参数存储在https://github.com/JuliaLang/julia/blob/master/src/julia.h [`jl_options’的全局结构]。

`julia_init()'

https://github.com/JuliaLang/julia/blob/master/src/init.c [`julia_init()`in’init.c']由函数’main()'调用并调用https://github.com/JuliaLang/julia/blob/master/src/init.c [`_julia_init()`在’init.c']。

`_julia_init()`函数通过再次调用`libsupport_init()'开始(第二次它不做任何事情)。

https://github.com/JuliaLang/julia/blob/master/src/signals-unix.c 调用[`restore_signals()']来重置信号处理程序的掩码。

https://github.com/JuliaLang/julia/blob/master/src/init.c [`jl_resolve_sysimg_location()']搜索基本系统映像的配置路径。 见章节 Julia系统映像构建

https://github.com/JuliaLang/julia/blob/master/src/gc.c [`jl_gc_init()']指定弱引用、存储值和最终确定的分配池和列表。

https://github.com/JuliaLang/julia/blob/master/src/ast.c [`jl_init_frontend()']加载并初始化包含扫描仪或分析器的预编译femtolisp图像。

`jl_init_types()'创建类型为`jl_datatype_t`的对象https://github.com/JuliaLang/julia/blob/master/src/julia.h [在’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'。

https://github.com/JuliaLang/julia/blob/master/src/codegen.cpp [`jl_init_codegen()']初始化https://llvm.org [LLVM库]。

https://github.com/JuliaLang/julia/blob/master/src/staticdata.c ['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’模块。

https://github.com/JuliaLang/julia/blob/master/src/intrinsics.cpp [`jl_init_intrinsic_functions()']创建一个新的Julia’Intrinsics’模块,其中包含常量字符’jl_intrinsic_type'。 它们为每个定义一个整数代码https://github.com/JuliaLang/julia/blob/master/src/intrinsics.cpp [内部功能]。 https://github.com/JuliaLang/julia/blob/master/src/intrinsics.cpp ['emit_intrinsic(’]在代码生成期间将这些字符转换为LLVM指令。

https://github.com/JuliaLang/julia/blob/master/src/builtins.c ['jl_init_primitives()`]将C函数绑定到Julia函数符号。 例如,角色的核心。:(===)()`通过调用’add_builtin_func("===",jl_f_is)'绑定到c’jl_f_is()函数的指针。

https://github.com/JuliaLang/julia/blob/master/src/toplevel.c ['jl_new_main_module()']创建一个全局主模块并设置'jl_current_task->current_module=jl_main_module'。

注意。 `_julia_init()`https://github.com/JuliaLang/julia/blob/master/src/init.c [然后设置]'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")’调用函数https://github.com/JuliaLang/julia/blob/master/src/ast.c [`jl_parse_eval_all'],重复调用https://github.com/JuliaLang/julia/blob/master/src/toplevel.c [`jl_toplevel_eval_flex()']执行https://github.com/JuliaLang/julia/blob/master/base/boot.jl ['靴子。jl']。 <!--TODO-深入到eval? -→

https://github.com/JuliaLang/julia/blob/master/src/init.c [`jl_get_builtin_hooks()']初始化C全局指针到`boot中定义的Julia全局对象。jl'。

https://github.com/JuliaLang/julia/blob/master/src/datatype.c ['jl_init_box_caches()`]为最多1024的值预先分配打包整数值的全局对象。 这将加快稍后打包整数值的分发速度。 例如:

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()'迭代]'jl_core_module->绑定。表'在搜索’jl_datatype_t’的值,并设置’jl_core_module’作为类型名称模块的前缀。

jl_add_standard_imports(jl_main_module)在主模块中应用"使用Base"。

注意。 _julia_init()`现在恢复为+jl_root_task→current_module=jl_main_module+`,就像上面安装`jl_core_module’之前一样。

针对"SIGSEGV"(OSX,Linux)和"SIGFPE"(Windows)初始化特定于平台的信号处理程序。

其他信号(`SIGINFO,SIGBUS,SIGILL,SIGTERM,SIGABRT,SIGQUIT,SIGSYS`和’SIGPIPE')附加到函数https://github.com/JuliaLang/julia/blob/master/src/signals-unix.c [`sigdie_handler()'],输出回溯。

https://github.com/JuliaLang/julia/blob/master/src/staticdata.c [jl_init_restored_module()']调用https://github.com/JuliaLang/julia/blob/master/src/module.c ['jl_module_run_initializer()]为每个反序列化模块执行函数'__init__()'。

最后,https://github.com/JuliaLang/julia/blob/master/src/signals-unix.c [sigint_handler()']连接’SIGINT’并导致’jl_throw(jl_interrupt_exception)

_julia_init()'然后返回https://github.com/JuliaLang/julia/blob/master/cli/loader_exe.c [回到`cli/loader_exe中的`main()'。c],和’main()调用+repl_entrypoint(argc,(char**)argv)+'。

系统/系统

如果有sysimg文件,它包含`Core`和`Main`模块的预先准备的映像(以及使用`boot创建的任何其他内容。jl`)。 见章节 Julia系统映像构建

https://github.com/JuliaLang/julia/blob/master/src/staticdata.c ['jl_restore_system_image()`]将保存的sysimg反序列化到当前Julia运行时,并在下面的`jl_init_box_caches()`之后继续初始化。

注意。 https://github.com/JuliaLang/julia/blob/master/src/staticdata.c ['jl_restore_system_image`)'(和’staticdata。c’一般)]使用[过时的库’ios.c'](stdio.md#Legacy-ios.c-library)。

`repl_entrypoint()'

https://github.com/JuliaLang/julia/blob/master/src/jlapi.c ['repl_entrypoint()`]将’argv[]'的内容加载到 '基地。ARGS'

如果`。在命令行上指定了程序的jl’文件,https://github.com/JuliaLang/julia/blob/master/src/jlapi.c [exec_program()']调用https://github.com/JuliaLang/julia/blob/master/src/toplevel.c [`jl_load(program,len)'],它调用https://github.com/JuliaLang/julia/blob/master/src/ast.c [`jl_parse_eval_all'],重复调用https://github.com/JuliaLang/julia/blob/master/src/toplevel.c ['jl_toplevel_eval_flex()]来执行程序。

但是,在我们的例子中('julia-e’println("Hello World!")")https://github.com/JuliaLang/julia/blob/master/src/module.c['jl_get_global(jl_base_module,jl_symbol("_start"))`]正在寻找https://github.com/JuliaLang/julia/blob/master/base/client.jl ['基地。_start']和https://github.com/JuliaLang/julia/blob/master/src/julia.h [`jl_apply()']执行它。

"基地。_启动`

https://github.com/JuliaLang/julia/blob/master/base/client.jl ['基地。_start']原因https://github.com/JuliaLang/julia/blob/master/base/client.jl ['基地。exec_options'],它调用https://github.com/JuliaLang/julia/blob/master/src/ast.c ['jl_parse_input_line("println("Hello World!")")']创建表达式对象和 '核心。eval(Main,ex)`在`Main`模块的上下文中执行分析的表达式`ex'。

'核心。eval`

'核心。eval(Main,ex)调用函数https://github.com/JuliaLang/julia/blob/master/src/toplevel.c ['jl_toplevel_eval_in(m,ex)],这导致https://github.com/JuliaLang/julia/blob/master/src/toplevel.c ['jl_toplevel_eval_flex']。 'jl_toplevel_eval_flex’实现了一个简单的启发式,用于决定是编译给定的代码片段还是使用解释器运行它。 当’println("你好世界!"’设置,通常决定使用解释器运行代码。 在这种情况下,它被称为https://github.com/JuliaLang/julia/blob/master/src/interpreter.c ['jl_interpret_toplevel_thunk'],然后调用https://github.com/JuliaLang/julia/blob/master/src/interpreter.c ['eval_body']。

下面的堆栈转储显示了解释器如何通过各种方法。 '基地。println()`'基地。print(’到达前https://github.com/JuliaLang/julia/blob/master/base/stream.jl ['+写(S::IO,A::数组{T})其中T’],执行’ccall(jl_uv_write())'。

https://github.com/JuliaLang/julia/blob/master/src/jl_uv.c ['jl_uv_write()']调用’uv_write()'来编写Hello World! 在’JL_STDOUT’中。 见章节 libuv包装为stdio

Hello World!
堆栈帧 源代码 注意事项

'jl_uv_write()`

jl_uv。c

它被称为使用关键字 'ccall'

'julia_write_282942`

"流。jl`

'写!'函数(s::IO,A::数组{T})其中T`

'julia_print_284639`

'ascii。jl`

'print(io::IO,S::String)=(write(io,s);nothing)`

'jlcall_print_284639`

jl_apply()

"朱莉娅。h`

'jl_蹦床()`

"建造。c`

jl_apply()

"朱莉娅。h`

jl_apply_generic()

"gf。c`

"基地。打印(基地。TTY,字符串)`

jl_apply()

"朱莉娅。h`

'jl_蹦床()`

"建造。c`

jl_apply()

"朱莉娅。h`

jl_apply_generic()

"gf。c`

'基地。打印(基地。TTY,字符串,Char,Char。..)`

jl_apply()

"朱莉娅。h`

jl_f_apply()

"建造。c`

jl_apply()

"朱莉娅。h`

'jl_蹦床()`

"建造。c`

jl_apply()

"朱莉娅。h`

jl_apply_generic()

"gf。c`

'基地。println(Base.TTY,字符串,字符串。..)`

jl_apply()

"朱莉娅。h`

'jl_蹦床()`

"建造。c`

jl_apply()

"朱莉娅。h`

jl_apply_generic()

"gf。c`

"基地。println(字符串,)`

jl_apply()

"朱莉娅。h`

'do_call()`

""翻译。c`

'eval_body()`

""翻译。c`

jl_interpret_toplevel_thunk

""翻译。c`

jl_toplevel_eval_flex

""顶层。c`

jl_toplevel_eval_in

""顶层。c`

'核心。eval`

""靴子。jl`

因为在我们的例子中,只有一个函数的调用已经完成了它的工作并输出了Hello World!,现在堆栈快速返回到’main()'。

jl_atexit_hook()

'main()'调用https://github.com/JuliaLang/julia/blob/master/src/init.c ['jl_atexit_hook()]。 它叫基地。_atexit',然后调用https://github.com/JuliaLang/julia/blob/master/src/gc.c ['jl_gc_run_all_finalizers()]并清除libuv处理程序。

`julia_save()'

最后,'main()'调用https://github.com/JuliaLang/julia/blob/master/src/init.c ['julia_save()'],它(根据命令行的请求)将运行时环境的状态保存到新的系统映像中。 见https://github.com/JuliaLang/julia/blob/master/src/gf.c ['jl_compile_all(']和https://github.com/JuliaLang/julia/blob/master/src/staticdata.c ['jl_save_system_image()]。