Page 25 - 《软件学报》2025年第12期
P. 25

5406                                                      软件学报  2025  年第  36  卷第  12  期


                 得一提的是, ORCJIT   在兼容   MCJIT (machine code JIT) 功能的同时, 还特别支持了惰性编译, 其详细执行流程可参
                 见图  3. 操作中使用的伪指令功能如下: MV          用于将源寄存器或地址中的内容移动到目的寄存器, LD                  用于从确定
                 的内存地址中加载数据到目的寄存器, ST             用于从寄存器向确定的内存地址中存储数据, JMP                用于寄存器间接转
                 移, CALL  用于函数调用, RET    用于函数返回. 操作中使用的寄存器功能如下: $pv               用于存储被调函数入口地址,
                 $pc 用于存储当前的     PC  值, $ra 用于存储返回地址, $t11  为  Caller-Saved  临时寄存器, $sp  用于存储栈指针, $v0  用
                 于存储返回值, $a0   和$a1  用于传递函数参数.


                                                                             Julia hybrid code
                                  MPE code                @saca                 CPE code



                                                        MPE compiler            SACA.jl
                                    Parser
                                                                              CPE compiler

                                                     High-level               SACA wrapper
                                   Julia IR                          Reused
                                                    optimizations              SIMD exts
                                                                              Runtime APIs
                                   Lowering

                                                     Low-level
                                   LLVM IR
                                                    optimizations               LLVM.jl
                                                                     Support  LLVM wrapper
                                 ORCJIT engine
                                                                             LLVM ToolChains



                                  Executable             Runtime               CPE DyLink
                                   stream                  libs                 objects
                                                                          SW26010Pro executable image
                                              图 2 swJulia 编译系统组成结构框图

                    ORCJIT  提供了  LLLazyJITBuilder 类专门用于处理惰性编译, 其在初始化阶段构建             LLLazyJIT  实例并设置惰
                 性编译的相关属性, 包括是否允许将             JIT  实例保存到缓存文件中、选择编译            module  还是  function  等. 然后,
                 LLLazyJITBuilder 构建  Stub  管理器和  Trampoline 管理器, 并根据  IR module 实例化与符号入口一一对应的       Stub
                 及  Trampoline.
                    Stub  是一段充当占位符的汇编代码, 用于检查被调函数               Callee 是否已被  JIT  编译. 当程序尝试调用    Callee 函
                 数时, 首先会跳转到      Callee 对应的  Stub  入口, 然后从固定内存地址    TargetAddr 中获取目标地址并执行寄存器间接
                 转移. 当  Callee 函数首次被调用时, TargetAddr 中存储的是其对应的         Trampoline 入口地址. 而当   Callee 再次被调
                 用时, 由于其已被     JIT  编译, TargetAddr 中的内容被更新为   Callee 的实际入口地址.
                    与  Stub  类似, Trampoline 也是一段动态生成的汇编代码, 其长度固定为           32 B, 用于保存  Callee 函数的返回地
                 址并跳转到    Resolver, 进而实现对  Callee 的  JIT  编译. Trampoline 首先将$ra 中存储的  Callee 函数返回地址保存到
                 Caller-Saved  寄存器$t11  中, 以确保其不会被后续的函数调用所修改, 然后将更新后的                 PC  值存入$ra  并跳转到
                 Resolver 入口.
                    Resolver 是一段较为复杂的汇编代码, 其主要功能是调用               Reentry  函数完成对  Callee 的  JIT  编译, 并且管理
   20   21   22   23   24   25   26   27   28   29   30