您的位置:首页 > Web前端 > JavaScript

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

2013-05-23 00:34 567 查看
前面说了一些解析、生成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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐