clingrootsys原理剖析(1):JIT到底是怎么回事

所有的高级语言技术,都是由前端的翻译转化,源码理解,和后端的运行技术和语义实现的: 即编译-链接-运行循环这个标准过程组成的(真正了解这个三段式过程,无论是多复杂或复合了的语言系统,给其定性将不再是难事)3 / E 7 % X G [ V,而且其编译器实现一开始都是以静u [ $ |态过程式、函数为实现机制的。都是C语言E # d ;标准编译原理教程那套。而高级和复杂语言实d ; E L * [现,都是先过程元素,然后再在编译器前端实现语法增强,或封装到class和库级增强实现的。(而真正分清这个,可以分步理清很多错综复杂的编译原理过程。 特别是cling这样的复杂语言系统的定性和实现原理。包括其实现,如JIT和库级pme都大有帮助。下面细述。

什么是解释系统

解释系统与编译系统最大的区别是在一个前后端配合循环(标准编译原理上的comI 2 K $ * E b j bpile-link-run,实际上这里的compile更适合称为tran[ ] B & W h /slate才能与其它语言共享同样的编译子过程称代; N +而显得无歧义)中,它每次只取一条代码(最小生成和执行代码的单元)来运行,且纯粹依赖语~ 7 _言系统本身的后端—-往往是一个软件系统 来运行,往往无需link,因Z X _ y 1为它是运行期完成query的,类似组件(接下来本文第三部会说到这个组件有C 4 9什么魔力)。
这里的软S p p H P件系统运行设施往往还负责其它方面的工作—比如一个虚拟l ? ] ) W 7 $ d机要完成的那些当然也有可能不像虚拟机那么复杂,就是一个简A 3 h A ( B t g L单的if-case流程(这是最初脚本语言的原型),它属于整个语言系统的一部分,所以说是在线解释。由于它在翻译和链接过A Q e = M , C A程中是运行z + - # a + ,期实时完成的,运行期的那个大VM天然维护着这样一个软件从翻译到运行所需的全部设施的T ` L n l v y Y宠大环境 — 它就是} p 0 n 5 a整个软件化的语言系统连执行都是软件托管的,所以在前端它不耗时(较编译r c ? c Q _系统而言),耗时的是运行期的代码效率。
而编译系统是事先将整个应用一次全翻译好(这里耗时巨大),将每个模块链接起来(这里又一次耗时巨大),依赖后端-往往是一层薄薄的O n 0 # R支持层仅起传手传L w y L x k 2 u递作用 – 传递喂给机n M .器offline运行,此时的运行不干语言系统的事所以说是offline。由于机器执行机器码是2的8次方这个效率(这个数字还在不断增长),所以自然就快了。
解释系统每次只执行一个代码的本质无非是在g L 3 6编译器实现中在后端提供一个execframe对象就能达到,使语言系统= N ^ C D W T c具备生成动态最小可执行单元,比如一个调用路径中的函数栈,然后将代表其的ast node喂给后端执行时-那个execframe就行了。解释语言最鲜明的技术特点就是这个动态执行后端。可见它跟是否@ U k 7 c必有一个虚拟机没有关系,跟是否必生成中间码或平台码,或以其为最终目标运行没有关系。它就是一个普通后端会“emit function->feed it to execframe”的东西,免c/ # @ ! | kompiler免link,后端直接运行代码(A r w 7 } Z 4一般运行后端可直接识别的中间码)的东西。
我们称以上这种解释系统称为普通解释系统。
令我们迷或的往往是JIT式的解释系统。而实际上,它是普通解释系统加了“以平台码为翻译目标和运行目标”之后的解% q ,释系统。这里详述:

Jit到底什么东西

JIT有什么特别,你依然得联系到标准的三段编译原理过程来解释; f # { c n | }它,即translate[ 5 - t O q->link->rQ c b -un ,jit也被称为jit compiler,jit interpter,那么jit顾名思议,jitcompiler=jit$ H F g 6 0 u K Z translator,是语言都有的,所以这不是它的0 Z ; S * 特征,而我们立马发现其有jit interpter,如果说到现在为止提到了解释,编译系统和这个JIT三大语言系统,这个新事物名称就证明它属于偏向类似解释系统。也O U K s Q 5 ^ ( 9许这个名称可以再加一条v = 4 &,即jit=jit to native。
上面解释了普通interpter是什么原理的,而基于jit的interpter除了它模拟了普通解释系统后端的最小单元编译和执行机制(或者它类似TCC编译过程i B h 5十分快显得像解释器),它还显得有那么一点特殊之r ! , ] 0 C 3处,即它针v _ a U !对平台码,无论是RAW CPP源码,还是二进制DLL符号,它都能实现compile和连接不费时,和运行期直接查找到符号, 这二者都齐了所以jit才表现得像个解释器。
可见,JIT它也并? ~ 0 o ~ I 5没有带来新的东西,原理上Jit只是接通了生成到native code同时为目标翻译码和执行码的东西,别无它。是传统解释套装并列的部件。实际上也并没有破坏编译原理的外观。它依然是一整套语X M ^ Y言系统,只不过在流程上它可以与解释语言并列,F % _ + ] n ~通过开启JIT的) O ` D D选项转Z ( U g $ O | A到使用JIT套件(再重复一次,jit它代表整个JIT语言系统,同时包含前后端,需在三段式环境下理解它)。

Cling中的jit

Cling基于c/ g T . x ] ` ?lang+llvm,最主要的意义是其jit interpter机制,即解释语言那套+针对平台码平台符号,H v ~ : 0 , i o |作为Q O & G l X S一个“特殊了一+ B $ S i ; B )点的”解释器存在:即Cling jit后端可以jit to native,emit native function,( j 6 U P y +其AST可以按NODE喂给运行器。
而其实JIT不仅限这个功能,cling依赖于jit能call into native libs不需bindin| : B B B = 9 Lg,是JIT本身的功能,(当然,这事先需要在编译成二进制时保留JIT所需z $ j !的符号,rdynamic causes symbols to be exported even though this is notp D $ H u U ~ G ` a lib ,it Keep symbolk . r 9 F ] Ms for JIT resolution 这些DLL都是符号解析级的动态6 + O 9 q可载入组件,受操作系统i k Z H w 1 G R ^DLL实现支持)。这种组件免除了link。因为组件都是在运行期link的。而从DLL中获得符号,就能省去compile->tranlr k 1 u s H d } tat{ N X xe的需要。所以这也不脱离cling jit的作为解释系统的产品外观范围。
所以,这个面向DLL的特性,一定意义上可当成,cling jit视DLL为raw cpp code组件(暂时你可以把X ~ H Y 这里和接下来的组件当成脚本源码文件一类的东西来理解),为“源码”(而普通解释器面向解j q T f释单元,解释模块,是真实可视~ ! S F的源码组件,a c U pJIT只工作在二进制导出符号层,能作CPP源码和二进制混合编程)。因为它视平台DLL为组件,因此能做% * @ 7 3到动态持续从“DLL源码”(DLL其中源码实际并不可见,这里说的是其中符号类似llvm jit眼中的“源码”,被它当成了组件)加载符号和运行.
这点意义上,宠统来说,JIT就是一个更高级的”DLL“机制而已,使其还可以3 5 , J d {直接视库为开发件,具备组2 d h P { d *件的特性。这是后话更多组件的情况将在第三部分介绍。


(此处不设回复,扫码到微信参与留言,或直接点击到原 T g u : } U 8文)

clingrootsys原理剖析(1):JIT到底是怎么回事