ChakraCore Wiki:Architecture Overview
tem.pw主要存放原创的**翻译**文章,即知识主体并非产自我这里的文章,但同时为了补充说明,我也会在里面添加一些东西。本系列来自微软Github ChakraCore的Wiki。更多原创文章可以参考http://nul.pw。
文章翻译来源:blast
禁止转载
ChakraCore组件
ChakraCore是一款功能齐全的JavaScript虚拟机,它与Chakra支持的功能和特性基本相同。不同之处主要有两个。
1,Chakra有一套浏览器和UAP的绑定接口,这套接口没有暴露在ChakraCore中(但是你可以使用JSRT API来完成同样的功能)。
2,Chakra中使用的基于COM的诊断API没有暴露出来,因为ChakraCore想做跨平台,而COM只有Windows有,所以微软在做一套新的基于JSON的接口来支持调试。
[/img]
执行通路
ChakraCore支持多层架构—— 一个利用解释器进行快速启动的并行JIT编译器。JIT可高速生成高度优化的代码,同时还支持后台GC来减少卡顿并为应用程序和站点提供卓越的UI响应。一旦应用程序或站点的JavaScript源代码启动了JavaScript子系统,ChakraCore就会执行一个快速的解析过程来检查语法错误。之后,ChakraCore中的所有其他工作都将按照每个函数的需要进行。只要有可能,ChakraCore就会推迟那些不需要立刻执行的函数的函数解析和生成抽象语法树(AST)过程,并从主线程上撤离诸如JIT编译和GC的工作,以在保持可用性的同时保持应用和网站快速响应。
当第一次执行函数时,ChakraCore的解析器创建源函数的AST。然后将AST转换为字节码,由ChakraCore的解释器立即执行。当解释器正在执行字节码时,它会收集诸如类型信息和调用计数之类的数据,以创建正在执行的功能的配置文件。作为JIT编译功能的一部分,该配置文件数据用于生成高度优化的机器码(JIT代码)。
当ChakraCore注意到在解释器中多次调用某个函数或循环体时,它会将ChakraCore的后台JIT编译器管道中的函数排队,以生成该函数的优化的JIT代码。一旦JIT的代码准备就绪,ChakraCore将替换该函数或循环入口点,以便对函数或循环的后续调用开始执行更快的JIT代码,而不是通过解释器继续执行字节码。
ChakraCore的后台JIT编译器基于数据生成高度优化的JIT代码,并根据解释器收集的配置文件数据推测可能的使用模式。鉴于JavaScript代码的动态特性,如果代码的执行方式不满足配置文件的预先假设,则JIT的代码将“缓存”到解码器,其中较慢的字节码执行方式将会重新启动,同时引擎会继续收集更多的配置文件数据。
为了平衡JIT代码与进程内存占用的时间量之间的平衡(而不是在每次bailout发生时JIT都编译函数),ChakraCore将存储的JIT代码用于函数或循环体。如果bailout时间过长并超过特定阈值,这将会使代码重新进行JIT,并且旧的JIT代码会被丢弃。
[/img]
JIT编译器
ChakraCore具有两层JIT编译器。在同一个并发后台线程中,ChakraCore拥有一个完整的JIT编译器(Full JIT),还有一个简单的JIT编译器。完整的JIT可以生成高度优化的代码,而简单的JIT本质上是一个较少优化版本的Full JIT。
在执行流程中,ChakraCore首先将解释器中的函数执行切换到执行简单的JIT代码,然后由Full JIT生成一次完全优化的JIT代码。在大多数情况下,简单的JIT编译比完整的JIT编译所花费的时间更少,因此与单层JIT架构相比,ChakraCore可以为应用程序和站点提供更快的启动速度。具有简单JIT层的另一个固有优点是,如果发生bailout,到完全优化的重编译的JIT的代码可用前,函数执行流可以从解释器更快地切换到简单JIT。简单的JIT代码执行管道也继续收集完整JIT编译器使用的配置文件数据,以生成优化的JIT代码。
ChakraCore还可以在ChakraCore确定底层硬件潜在未充分利用的情况下,为JIT编译生成多个并发后台线程。在多个并发的后台JIT线程进行生成的情况下,Chakra的简单JIT和完整JIT都会被分割并排队等待跨多个JIT线程进行编译。这有助于减少整体JIT编译延迟,有时能相对较快地将较慢的解释代码切换到JIT代码的简单或完全优化版本。
[/img]
垃圾回收器
ChakraCore有一个称为“mark-and-sweep”的支持并发或部分处理的垃圾收集器。
当启动完全并发GC时,ChakraCore的后台GC将执行第一次标记,然后重新扫描以查找在后台GC线程标记时因主线程执行而修改的对象。第二个标记过程会标记重新扫描期间发现的对象。 一旦第二次标记完成,主线程会暂停以进行最终重新扫描的过程。
完成后,执行在主线程和专用GC线程之间分割的最终标记。后台GC线程会查找不可触达(无引用)的对象并将其添加回分配池。
[/img]