本文主要从两个维度简要介绍下V8
1、V8的源码结构(version 8.6)
2、V8在运行流程上的衍变
V8源码结构概览
这个在某些目录的介绍上可能存在理解问题,需要在阅读源码过程中逐步完善
v8
|
|_ _ _
|_ _ _ _ include
| |
| |_ _ _ _ v8.h 所有v8提供的接口
|
|_ _ _ _ src
|
|_ _ _ _ api **对外接口
|
|_ _ _ _ asmjs **js汇编
|
|_ _ _ _ ast **虚拟语法树
|
|_ _ _ _ base **基础内容,如cpu 内存的处理
|
|_ _ _ _ builtins **内置处理
|
|_ _ _ _ common
|
|_ _ _ _ codegen ** (猜)ast到机器语言或bytecode到机器语言
|
|_ _ _ _ compiler ** (猜)ast到bytecode,之前是没有从ast到bytecode这一步骤的,2017年引入,Android移动端内存紧张(编译可配置)
|
|_ _ _ _ d8 **一个调试程序
|
|_ _ _ _ date
|
|_ _ _ _ debug
|
|_ _ _ _ deoptimizer
|
|_ _ _ _ diagnostics
|
|_ _ _ _ execution
|
|_ _ _ _ extensions
|
|_ _ _ _ flags
|
|_ _ _ _ handles
|
|_ _ _ _ heap **V8堆处理
|
|_ _ _ _ ic
|
|_ _ _ _ init **初始化
|
|_ _ _ _ inspector
|
|_ _ _ _ interpreter
|
|_ _ _ _ json
|
|_ _ _ _ libplatform
|
|_ _ _ _ libsampler
|
|_ _ _ _ logging
|
|_ _ _ _ numbers
|
|_ _ _ _ objects **js数据类型
|
|_ _ _ _ parsing **解析js源码
|
|_ _ _ _ profiler
|
|_ _ _ _ protobuf
|
|_ _ _ _ regexp
|
|_ _ _ _ roots
|
|_ _ _ _ runtime ** 运行时处理,lazy JIT
|
|_ _ _ _ sanitizer
|
|_ _ _ _ snapshot **快照,减少全局上下文创建时的CPU、内存消耗,V8使用了Snapshot技术,全局上下文初始化后,将目前堆内存序列化为字节代码,保存至磁盘文件,加载时,将该snapshot文件反序列化进内存
|
|_ _ _ _ strings
|
|_ _ _ _ tasks
|
|_ _ _ _ third_party
|
|_ _ _ _ torque ** v8的TQ, CSA(c++写TurboFan(生成机器码的阶段)),TQ是用类似js(更像ts)代码编译成CSA
|
|_ _ _ _ tracing
|
|_ _ _ _ trap-handler
|
|_ _ _ _ utils
|
|_ _ _ _ wasm **webAssembly
|
|_ _ _ _ zone
V8 pipeline衍变
主要介绍编译阶段的一些优化衍变,在生成AST前的优化比如lazy parse等单独介绍
v8-pipelines.png
V8执行js代码的整个流程
Parser阶段其实分为了两个,一个是scanner,一个是parser,scanner用来做分词,根据输入的utf-16字符流解析Token,parser根据scanner的解析出的Token做语法的解析然后生成ast
后面的部分是从ast到机器码的过程,可以看到有很多的分支,这个是一个整体的图,v8运行优化ast前变动不大,大部分是在ast之后的优化
下面简单的介绍下这个过程
pipe-2008.jpg
上图是2008年最原始的版本,就是简单的把ast转换成简单优化的机器码
pipe-2010.jpg
上图在V8里面引入了crankshaft优化机制,这个优化主要是对于热点函数(就是经常用到的函数),从js code层面做优化,然后替换原来未优化的代码
pipe-2015.jpg
上图是2015年的一个优化,这个阶段可以看到引入了TurboFan,引入它的原因主要是crankshaft的一些限制,比如一些关键字try cache代码块里面的内容他没法优化,然后如果有新的语法,他需要针对不同的cpu架构写各自的优化策略,turbofan的引入就是为了解决这些问题的
pipe-2016.jpg
我觉得这个是2016年的一个过度版本,Crankshaft是不支持从ByteCode直接做优化的,而在这个版本中实现Turbofan可以支持从字节码来做优化,提供一个可选的方案。
pipe-moblie.jpg
这个是针对移动端支持的一个架构,正式引入了字节码,如果还是使用原来的架构,那编译完成的机器码会占用很多的内存,移动端的内存还是比较吃紧的,所以引入了这么一套架构,移动端编译V8的时候,可以使用带字节码的这一个流程,其实这个是一个用时间来换空间的解决方案,之前的架构直接从AST到机器码的性能大部分情况是比加入字节码要快很多的。
pipe-2017.jpg
这个是目前最后的一个版本。
直接编译机器码的主要弊端:占用内存大,导致的问题就是不能全编译,大部分时候方法内部的执行逻辑都是在第一次运行时候懒加载(区分Lasy parse 和 Lasy compile)的,改成字节码中转后带来的另一个好处启动时间(区别于运行时间)缩短了。因为可以提前编译所有代码了,可以提前把字节码缓存。权衡利弊,走向了和js core一样的道路。
网友评论