[WebKit] JavaScriptCore解析--基础篇(三)从脚本代码到JIT编译的代码实现

前面说了一些解析、生成ByteCode直至JIT的基本概念,下面是对照JavaScriptCore源代码来大致了解它的实现。


从JS Script到Byte Code

首先说明Lexer, Parser和ByteCode的生成都是由ProgramExecutable初始化过程完成的。先在JSC的API evaluate()中会创建ProgramExecutable并指定脚本代码。然后传入Interpreter时,再透过CodeCache获取的UnlinkedProgramCodeBlock就是已经生成ByteCode后的Code Block了。


下图是CodeCache调用Parser和ByteCodeGenerator的序列图:


而Lexer则是在Parser过程中调用的,如下图:


再从类图来观察所涉及的几个类之间的关系:



关于CodeBlock、UnlinkedCodeBlock和ScriptExecutable

CodeBlock可以理解为代码管理的类,按类型分为GlobalCodeBlock, ProgramCodeBlock, FunctionCodeBlock及EvalCodeBlock, 与之对应的UnlinkedCodeBlock和ScriptExecutable也有相似的继承体系,如下所示:


UnlinkedCodeBlock存储的是编译后的ByteCode,而CodeBlock则会用于LLint和JIT。

ProgramExecutable则可以理解为当前所执行脚本的大总管,从其名字上可以看出来是代表一个可执行程序。

它们的作用也很容易理解。


关于LLint的slow path

前面说过了LLint是基于offlineasm的汇编语言,这里只是介绍一下它的slow path. 为了处理一些操作,需要在LLint执行指令时调用一些C函数进行扩展处理,比如后面要说明的JIT统计功能,LLint提供一个调用C函数的接口,并将所有会被调用的C函数称为slow path,如下图所示:


代码可以在LowLevelInterpreterXXX.asm中看到。所以可以C函数声明看到带有SLOW_PATH的宏。


关于JIT优化的触发

首先JSC使用的是基于计数器的热点探测方法。前面提到函数或循环体被执行若干次后会触发JIT, 首先这个次数是可以通过JSC::Options中的thresholdForOptimizeSoon来设定的。然后在LLint在执行循环的ByteCode指令loop_hint和函数返回指令ret时会调用slow path中的C函数,进行次数统计和判断,过程如下:


  其中会根据checkIfJITThresholdReached()返回结果来决定是否进行jitCompile.一旦要进行JIT编译时,也是根据当前CodeBlock的类型,而执行针对不同函数或代码段的优化。下面显示的是对一个频繁使用的函数进行JIT编译的操作:


其中计数的功能并非由CodeBlock直接实现,而是通过ExecutionCounter来管理的。主要关系如下:

     


转载请注明出处:http://blog.csdn.net/horkychen

参考:WebKit研究

相关的UML图可以到这里下载 :WebKit Documentation on GitHub

系列索引:

基础篇 (一)JSC与WebCore

基础篇(二)解释器基础与JSC核心组件

基础篇(三)从脚本代码到JIT编译的代码实现

基础篇(四) 页面解析与JavaScript元素的执行

高级篇(一) SSA (static single assignment)

高级篇(二) 类型推导(Type Inference)

高级篇(三) Register Allocation & Trampoline



展开阅读全文

没有更多推荐了,返回首页