认识 V8 引擎( 六 )


V8引擎自诞生之日起就以性能优化作为目标,引入了众多新技术,极大了带动了整个业界JavaScript引擎性能的快速发展 。总的来说,V8引擎较为激进,青睐可以提高性能的新技术,而JavaScriptCore引擎较为稳健,渐进式的改变着自己的性能 。总的来说JavaScript引擎工作流程(包含v8和JavaScriptCore)如下所示:

认识 V8 引擎

文章插图
 
JavaScriptCore 的大致流程为:源代码-→抽象语法树-→字节码-→JIT-→本地代码 。JavaScriptCore与V8有一些不同之处,其中最大的不同就是新增了字节码的中间表示,并加入了多层JIT编译器(如:简单JIT编译器、DFG JIT编译器、LLVM等)优化性能,不停的对本地代码进行优化 。(在 V8 的 5.9 版本中,新增了一个 Ignition 字节码解释器,TurboFan 和 Ignition 结合起来共同完成JavaScript的编译,此后 V8 将与 JavaScriptCore 有大致相同的流程,Node 8.0中 V8 版本为 5.8)
还有就是在数据表示方面,V8在不同的机器上使用与机器位数相匹配的数据表示,而在JavaScriptCore中句柄都是使用64位表示,其可以表示更大范围的数字,所以即使在32位机器上,浮点类型同样可以保存在句柄中,不再需要访问堆中的数据,当也会占用更多的空间 。
4.功能扩展JavaScript引擎的主要功能是解析和执行JavaScript代码,往往不能满足使用者多样化的需要,那么就可以增加扩展以提升它的能力 。V8引擎有两种扩展机制:绑定和扩展 。
4.1.绑定机制使用IDL文件或接口文件生成绑定文件,将这些文件同V8引擎一起编译 。WebKit中使用IDL来定义JavaScript,但又与IDL有所不同,有一些改变 。定义一个新的接口的步骤大致如下:
  • 1.定义新的接口文件,可以在JavaScript代码进行调用,如mymodule.MyObj.myAttr;
module mymodule {interface [InterfaceName = MyObject] MyObj {readonly attribute long myAttr;DOMString myMethod (DOMString myArg);};}
  • 2.按照引擎定义的标准接口为基础实现接口类,生成JavaScript引擎所需的绑定文件 。WebKit提供了工具帮助生成所需的绑定类,根据引擎不同和引擎开发语言的不同而有所差异 。V8引擎会为上述示例代码生成 v8MyObj.h (MyObj类具体的实现代码)和 V8MyObj.cpp (桥接代码,辅组注册桥接的函数到V8引擎)两个绑定文件 。
JavaScript引擎绑定机制需要将扩展代码和JavaScript引擎一块编译和打包,不能根据需要在引擎启动后再动态注入这些本地代码 。在实际WEB开发中,开发者都是基于现有浏览器的,根本不可能介入到JavaScript引擎的编译中,绑定机制有很大的局限性,但其非常高效,适用于对性能要求较高的场景 。
4.2. Extension机制通过V8的基类Extension进行能力扩展,无需和V8引擎一起编译,可以动态为引擎增加功能特性,具有很大的灵活性 。
Extension机制的大致思路就是,V8提供一个基类Extension和一个全局注册函数,要想扩展JavaScript能力,需要经过以下步骤:
class MYExtension : public v8::Extension {public:MYExtension() : v8::Extension("v8/My", "native function my();") {}virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction (v8::Handle<v8::String> name) {// 可以根据name来返回不同的函数return v8::FunctionTemplate::New(MYExtention::MY);}static v8::Handle<v8::Value> MY(const v8::Arguments& args) {// Do sth herereturn v8::Undefined();}};MYExtension extension;RegisterExtension(&extension);
  • 1.基于Extension基类构建一个它的子类,并实现它的虚函数—GetNativeFunction,根据参数name来决定返回实函数;
  • 2.创建一个该子类的对象,并通过注册函数将该对象注册到V8引擎,当JavaScript调用’my’函数时就可被调用到 。
Extension机制是调用V8的接口注入新函数,动态扩展非常方便,但没有绑定机制高效,适用于对性能要求不高的场景 。
总结在过去几年,JavaScript在很多领域得到了广泛的应用,然而限于JavaScript语言本身的不足,执行效率不高 。google也推出了一些JavaScript网络应用,如Gmail、Google Maps及Google Docs office等 。这些应用的性能不仅受到服务器、网络、渲染引擎以及其他诸多因素的影响,同时也受到JavaScript本身执行速度的影响 。然而既有的JavaScript引擎无法满足新的需求,而性能不佳一直是网络应用开发者最关心的 。Google就开始了V8引擎的研究,将一系列新技术引入JavaScript引擎中,大大提高了JavaScript的执行效率 。相信随着V8引擎的不断发展,JavaScript也会有更广泛的应用场景,前端工程师也会有更好的未来! 那么结合上面对于V8引擎的介绍,我们在编程中应注意:


推荐阅读