您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 信息化管理 > chrome-v8-js引擎源码导读分析
v8第一章v8之整体流程第二章v8之全局环境配置及初始化2.1全局模板2.2库函数2.3初始化第三章v8之前端建立语法树3.1v8编译中重要的类3.2compile之前的查找3.3建立语法树第四章v8之后端全代码生成(fullcodegenerator)第五章v8之后端优化代码生成(crankshaft)5.1调用crankshaft的条件5.2Hydrogen5.3Lithium5.4寄存器分配第六章v8之运行时监听(runtimeprofile)第七章v8之LazyCompiler第八章v8之inlinecache8.1前提条件及实现方式8.2stubs函数第九章v8之性能分析(各流程所占时间比)第一章v8之整体流程1.)v8在进入main函数之后首先做的就是参数分析,根据参数设置Flags。2.)然后创建一个基于栈分配的HandleScope(在这里须得说明在v8中任何一个对象都是需要handle来指向的,如果没有则这个对象将很快被垃圾回收器回收掉。对象的释放意味做handle将没有用,因此在每一个v8逻辑层次中都有一个HandleScope来管理该层次中的所有handle。释放一个scope,则这个scope中的所以handle就被释放掉了)。3.)创建一个新的执行环境(即为v8执行js的环境,在创建该全局执行环境的同时,创建全局的对象模板,函数模板,编译built_infunction(详细情况请见第二章v8之环境配置及初始化)。进入该新建的全局执行环境中(所谓进入该环境变量就是设置当前isolate中执行的环境变量)。4.)然后就是编译执行*.js用户代码。a)首先进行语法分析,建立语法树。b)首次执行采用fullCodegenerator编译最外层框架代码,并开始执行。c)运行遇到还没有编译的function代码采用RuntimeLazyCompile,并用inlinecache技术将其他同名的对象指向该编译的代码。d)若在运行到该同名对象时发生CacheMiss(调用不匹配),则采用ICMissLazyCompile对调用的对象或函数进行编译(当然这里还有其他IC处理情况出现,比如ICCompare等等stubsfunction的处理)。e)在整个代码运行处理的过程中,v8还会创建一个监听线程(profilethread),该线程监听function的运行情况,收集类型信息,记录运行次数,记录function编译后的代码量等等,判断该function是否为hotfunction。(运行次数2,类型信息收集比例15%,代码量是否有5*144,是否发生IC_changed),达到要求后标记该函数为可优化,下次运行的时候采用RuntimeLazyRecompile,利用Crankshaft优化代码,并替换原来的代码。同时还有监听优化过的代码判断其是否优化过头,是否需要deoptimal。f)在产生的优化代码中常常还要用到on-stackreplacement(该技术为不中断程序继续进行的情况下,进行代码替换)。g)在Crankshaft生成优化代码的过程中,需要先建立语法树,进行一次全代码生成,模拟该代码运行,判断分析哪些数据分配到栈上,哪些变量分配到堆上,变量类型绑定等等,利用同一个语法树生成静态单赋值表示的中间表示代码Hydrogen(构建图),同时将function可能调用的代码进行inline(有充足类型信息的被调函数),然后优化图(循环不变量外移,公共子表达式消除)。遍历图生成三地址形式的中间表示Lithium,进行寄存器分配,最后生成本地代码。5.)在整个过程中垃圾回收器都紧紧的追踪v8中所有的对象,参看其是否stillalive,将其分类进行处理。在进行垃圾回收的时候要中断程序的进行,每次只处理要回收的一部分。第二章v8之全局环境配置及初始化2.1全局模板v8在运行时创建对象,函数都需要调用具体的模板方法来实现。在v8中有2个非常重要和常用的模板,分别是objectTemplate和functionTemplate。objectTemplate用来在运行时创建对象,向一个objectTemplate中添加properties,就是向所有以该对象模板创建的对象中添加这些属性。继承自Template(继承自data)。FrendclassfunctionTemplate。functionTemplate用来在运行时创建函数,在一个context中一个functionTemplate只能创建一个函数,该函数的生存周期和context的生存周期相同。每个函数模板可以有属性,并且这些属性会在创建函数的时候添加到该函数中。每个函数模板都有一个对应的实例模板,用来以该函数为构造器创建对象实例。每个函数模板还有一个prototype模板,用来创建函数的原型对象。functionTemplate的具体使用请参见include/v8.hline2109。另外functionTemplate还可以继承自另外一个函数模板,子函数模板继承父模板的属性,并且通过__proto__可以访问父模板的原型对象。functionTemplate继承自Template,friendclassObjectTemplate。2.2库函数在v8中库函数时用javaScript实现的,这样使得库函数的更新,修改更加方便。在runtime.js中,若调用这些库函数将会采用lazyCompile的方式进行编译。2.3初始化v8的初始化代码也是使用*.js实现的,在apinatives.js中调用Instantiates函数,对函数,模板,模板实例进行初始化工作。这些js代码将会在isolate-bootstrpper()-CreateEnvironment(...)中的Gensis函数中进行编译成本地代码。这些初始化的作用就是实现函数模板,对象模板。当然在初始化的过程中会调用到库函数,调用时将采用lazycompile的方式进行编译。初始化的作用其实是构造一个运行环境,在这个环境中一切为javascript所需的基本框架将会得到建立,包括库函数,js的模板,对象等。而这些*.js处理的方式和整个v8对待用户的js程序是基本一致的,这些built_injs函数都过Genesis::ConfigureApiObject再调用Execution::Call函数实现编译执行的。第三章v8之建立语法树3.1v8编译中重要的类CompilerInfo:封装一些在编译时间知道的信息,根据compiler-time时有的资源进行构造,需要用到ScriptDataImpl中的信息。CompilerInfoWithZone:和CompilerInfo类似,只是在构造的时候需要申请一块zone,并且进入该zone,在改累的对象exit的时候会释放这块zone。Zone的作用就是快速的进行小块的内存分配。Zone用来保存临时的数据结构,比如说抽象语法树,抽象语法树会在编译结束后被释放掉。OptimizingCompiler:在chrankshaft优化编译的三个阶段跟踪保存状态(三个阶段分别是:建图,图优化,code生成和install)。Compiler:v8的编译类,编译的基本策略就是将sourccode编译成匿名函数,给予参数就可被执行。如果这个sourcecode包含其他函数(调用其他函数),这些函数将会被编译,并且分配到该sourcecode中(作为其的一部分)。CompilationCache:保存编译过的script和evals的sharedfunctioninfos。这些共享的函数信息通过sourcestring作为关键来查找。3.2compile之前的查找Compilecache包含几层sub-caches,每个子cache针对每代sub-cache包含一个对应的compilationcachetables。因为对scripts和evals同样的sourcecodestring将会产生不同的编译代码,v8应用不同的sub-caches来保存不同编译modes产生的代码,来防止检索到错误结果。这些编译结果子cache,都继承自CompilationSubCache。CompileCacheScript是专门保存scripts编译结果的子cache。CompileCacheEval是专门保存evalscript编译结果的子cache。CompileCacheRegExp是专门保存正则表达式编译结果的子cache。v8在对任一sourcecode进行编译生成语法树之前,先要查找相应的compilecache,看该源代码是否已经编译过了,如果已经编译过了,可能就不需要再次编译了,直接导入就可以了。在源代码执行到Compile::Compile(...)之时,首先通过compilation_cache-lookupScript查看当前的源代码是否已经编译过,存放在cache中了,如果有,则直接导出就可。如果没有则要编译,且编译结束后要把结果存放在想对应的cache中。3.3建立语法树在查找无结果之后,v8将对源代码进行分析,建立语法树。v8在进行一系列环境配置之后(Scope,zone等配置),通过扫描器scanner,将源代码继续分析归类。分为语句(statement),和函数声明(functionDeclaration),在harmonymode下还允许有LetDeclaration,ConstDeclaration,ModuleDeclaration,ImportDeclartion,ExportDeclaration等模块元素。Parser::ParseStatement(...)是语法分析的入口,在该函数里进行实质的语法分析。它是一个分拣器,分析出每个js语句的类型,然后针对不同的类型再进一步调用相关的分析函数。具体的流程为:首先分离出语句的关键字,因为在scanner处理后每个语句都会有相应的关键字指代,有很清楚的含义。比如在js中声明变量varvalue;statement分析器将会将该变量声明语句传给Block*ParseVariableStatement()方法进行分析,并将结果放入zone中,并插入到AST树中的相应位置。v8在语法分析时将语句分为bolck,变量语句,空语句,表达式语句,if语句,Iteration语句,continue语句,break语句,return语句,with语句,labelled语句(这里须得注意,labels只会在break,continue语句中被使用,而这两种语句只有在blocks,iteration,和switch语句中才合法。因此在其他语句中的labels可以简单的忽略掉。),switch语句,throw语句,try语句,debugger语句。每一种类型的statement的处理方式基本类似,都是按照Ecma262第5版的标准进行分析的。进行匹配类似的分析,在递归的调用相应的处理方法。在建立语法树中我们可以看到每个js函数的语法树都是显示函数名,及其引用明,然后便是函数中的变量声明,接着是boby模块,在boby模块中是call,赋值,初始化等等操作。可以使用--print_ast打印所以的语法树。使用--trace_parse查看分析语法树建立的过程和花销的时间。(时间比列请参见第十章v8之性能分析)第四章v8之后端全代码生成(fullcodegenerator)v8在语法树生成之后将继续本地代码生成,在生成与平台有关的本地代码之前,需要做一系列的工作(比如判断是否采用优化编译,是否是因优化过度导致代码效率反而不高需要去优化等等),在采用代码生成的的首要条件就是判断源码是否语法编译正常。代码生成的后置条件便是生成的代码已经存放在compilationinfo中。全代码生成(直接翻译语法树,不采用优化),在mips中函数代码首先做的事情就是将a1(被调js函数本身),cp(被掉函数
本文标题:chrome-v8-js引擎源码导读分析
链接地址:https://www.777doc.com/doc-3330209 .html