1.针对上下文的Snapshot技术

什么是上下文(Contexts)?实际是JS应用程序的运行环境,避免应用程序的修改相互影响,例如一个页面js修改内置对象方法toString,不应该影响到另外页面。chrome浏览器每个process只有一个V8引擎实例,浏览器中的每个窗口、iframe都对应一个上下文。

V8启动时(在执行client js前),需要对全局上下文(第一个context)初始化,读取和解析自实现的内置JS代码(另一种技术,第2点),建立起function、array、string等内置对象及方法(参见bootstrapper中的Genesis类);后续context的创建只需要创建内置对象即可;为了减少全局上下文创建时的CPU、内存消耗,V8使用了Snapshot技术(参见v8_mksnapshot工程),(1)全局上下文初始化后,将目前堆内存序列化为字节代码,保存至磁盘文件;这个过程最重要的是空间地址和对象保存,具体操作(参见serialize文件)是:模拟线性内存空间的分配,遍历堆内存中的所有JS对象,并在模拟空间分配内存(实际是记录对象相对偏移地址),然后序列化对象大小、偏移地址、子对象、对象内容;最后是序列化global handler和stack上的context;(2)加载时,将该snapshot文件反序列化进内存,避免第一个上下文初始化,从而加快V8的启动。

2. Built-in的js代码

‍(1)利用JS自表达内置对象、方法,如上面代码实现Math.min方法,从而V8在实现代码转译时只需注重基本操作,以%符号开头的函数来自V8运行时函数(参见runtime和codegen);

(2)如何把js嵌入到V8中?利用python工具,将JS文件代码转为const char[]变量(字节代码),存到natives.cc;在执行期间首次访问相关方法时,取相关js代码进行lazy-compile。

(题外话:让面试者实现JS的一些常用函数,也是考察其基本功方法之一。)

3. 建立AST(Abstract SyntaxTree)时内存的管理

V8在建立AST后,对其进行汇编生成动态机器语言,所以AST在code generated后需要回收;针对AST建立过程中多结点内存申请和一次性回收的特点,V8使用了内存段链表管理,并结合scopelock模式,实现少数申请(Segment,8KB~1MB)、多次分配AST结点、一次回收各个Segment的管理方式,既能避免内存碎片,又可以避免遍历AST结点逐个回收内存。

‍4. CompileCache避免相同代码重复编译

对于一段JS代码,在开始进行词法分析前,会从编译缓存区CompilationCache查找该段代码是否已经被编译过,如果是,则直接取出编译过的机器代码,并返回,这样降低CPU的使用率,换来内存空间一定的占用;如果一个页面中重复加载JS文件,这方法的提速是很明显的;这种做法应该有平衡对比过。

下面先来看下这个缓存区的具体实现:

(1)数据结构采用CompilationCacheTableàHashTable,它为三种不同的JS语句类型(普通script,Eval语句,RegExp正则表达式),并使用了不太雅观的全局变量‍‍记录各种table。用三种table记录的原因:相同的script和Eval语句,编译出来的机器代码是不同的(来自annotation),因为Eval语句和执行期的上下文相关,所以缓存的时候还需要加上context作为key,所以三种类型生成的key方式不一样。一开始table数组的各个值为空,直到有编译代码需要加入时才生成hashtable。‍‍

(2)Key的生成,需要保证相同语句生成的key是稳定的:

a)普通script语句,使用StringHasher生成key,并保存到String对象中(因为该key不只是用到该处);生成规则是:当语句长度超过16K时,将直接使用它的长度作为key(经过偏移变为32位长度并确保为奇数),否则使用Bob Jenkins hash算法逐个读取语句的每个字符,计算组成一个uint的key;

b)Eval语句,同样使用到StringHasher,在这基础上结合上下文的share info(同样是语句hash,再加上语句的位置信息,详见StringSharedHashHelper)来更新hash值;

c)RegExp语句,同样使用到StringHasher,在这基础上结合RegExp的flag信息(i/g等)来更新hash值(详见RegExpObjectHash),具体见RegExpKey。

这几种key都派生自HashTableKey,后者定义了些公共接口,供hashtable统一使用。

(3)查找方式:使用hash算法,并用线性侦测来解决key的冲突,这是由HashTable继承自FixedArray的特性决定。

5. 属性的快速访问

C++、Java等语言有着类的概念,且属性、方法和类绑定在一起,访问时可根据对象地址+位移快速获得;而JS对象并没有类概念,它实际为hash map,属性可以动态增加、删除,而且在执行时才能获知对象类型。

V8没有像其它JS Engine使用词典结构或红黑树实现的map来管理属性,而是在每个对象附加一个指针,指向hidden class(如果第一次创建该类型对象,则新建hidden class);当对象每添加一个属性时,将新建一个class(记录了每个属性的位移/位置),而原来的class指向新class,即建立起一个hidden class的转换链表。

6. Heap堆内存管理

详见:

http://hi.baidu.com/hycjk/blog/item/20c9ecf87d3d1004d8f9fd6e.html

http://hi.baidu.com/hycjk/blog/item/86b2bf0e000d34ec37d1221e.html

7. Inline caching减少函数调用开销

详见http://en.wikipedia.org/wiki/Inline_caching。JS函数绑定发生在运行时,所以无法通过method tables定位函数入口;通过该技术可以记录函数入口,避免重复查找。

8. 一次性编译生成机器语言

一般JS engine会在AST生成后,将之编译为中间语言(bytecode),在执行时候再解析这些bytecode;Java 也同样编译为这些bytecode,再采用VM(实现跨平台)作为解释器,为了提高效能,Java采用混杂方式,把无关平台、常用的代码编译为机器代码。V8则是一次性把AST编译为机器语言。从assembler相关文件头的Copyright可以看出,这些不同平台(ia32, arm)下的编译器,原型来自Sun Microsystems。

附:

一、一些JS engine设计的考虑点:

1、 快速——解析、建构语法树、执行等多个方面,例如属性访问,避免字典查找;优化代码,编译生成动态机器码,而非按语句解释执行,且机器码可以存放cache后重复执行;

2、 小巧——占用内存低,分配回收内存及时和有效;

3、 安全——运行上下文切换和检查;

4、 容错性高

5、 易于与浏览器集成;

6、 跨平台;

7、 提供api接口;

8、 支持调试;

9、 其它细节:正则表达式的解析和实现、hash对象的实现(大多此类对象size较小),需要考虑JS本身特性和目的。

二、一些JS语言特性

1、对象为hash map,属性可以随时添加、修改、删除,对象类型在执行时才可知;

2、prototyp chain在执行时可以修改

3、eval能改变执行上下文

4、with动态添加对象到scope chain(作用域)

三、词法分析器

四、V8引用的第三方代码:

1、正则引擎:刚开始使用webkit项目中的JSCRE(基于剑桥大学Philip Hazel开发的,被广泛使用的PCRE库),后来替换为全新的Irregexp(Automata理论);

2、dtoa,double转为字符串,David M. Gay,under an MIT license;

3、Strongtalk assembler,是个以 C++ 封裝的 JIT (Just-In-Time) Assemble。

五、一些资料地址

http://code.google.com/intl/zh-CN/apis/v8/design.html

http://code.google.com/intl/zh-CN/apis/v8/embed.html

http://www.docin.com/p-46635034.html

http://www.greenpublishers.com/neat/200901/3coverstory.pdf

http://www.cnblogs.com/RicCC/archive/2008/02/15/javascript-object-model-execution-model.html

http://www.cnblogs.com/duguguiyu/archive/2008/10/02/1303095.html tagged pointer?

http://hllvm.group.javaeye.com/group/topic/17840

Javascript的V8引擎研究的更多相关文章

  1. Node.js和Chrome V8 引擎了解

    说起Node就不得不先介绍一个Chrome V8 引擎. 随着Web相关技术的发展,JavaScript所要承担的工作也越来越多,早就超越了“表单验证”的范畴,这就更需要快速的解析和执行JavaScr ...

  2. JavaScript深入浅出第4课:V8引擎是如何工作的?

    摘要: 性能彪悍的V8引擎. <JavaScript深入浅出>系列: JavaScript深入浅出第1课:箭头函数中的this究竟是什么鬼? JavaScript深入浅出第2课:函数是一等 ...

  3. JavaScript引擎研究与C、C++与互调用(转)

    本文转自:ice6015的专栏.为什么有些招聘需要熟悉JS和C++,这或许就是原因. 1.  概要 JavaScript是一种广泛用于Web客户端开发的脚本语言,常用来控制浏览器的DOM树,给HTML ...

  4. JavaScript工作机制:V8 引擎内部机制及如何编写优化代码的5个诀窍

    概述 JavaScript引擎是一个执行JavaScript代码的程序或解释器.JavaScript引擎可以被实现为标准解释器,或者实现为以某种形式将JavaScript编译为字节码的即时编译器. 下 ...

  5. 使用 D8 分析 javascript 如何被 V8 引擎优化的

    在上一篇文章中我们讲了如何使用 GN 编译 V8 源码,文章最后编译完成的可执行文件并不是 V8,而是 D8.这篇我们讲一下如何使用 D8 调试 javascript 代码. 如果没有 d8,可以使用 ...

  6. How Javascript works (Javascript工作原理) (二) 引擎,运行时,如何在 V8 引擎中书写最优代码的 5 条小技巧

    个人总结: 一个Javascript引擎由一个标准解释程序,或者即时编译器来实现. 解释器(Interpreter): 解释一行,执行一行. 编译器(Compiler): 全部编译成机器码,统一执行. ...

  7. v8引擎详解(摘)-- V8引擎是一个JavaScript引擎实现

    随着Web相关技术的发展,JavaScript所要承担的工作也越来越多,早就超越了“表单验证”的范畴,这就更需要快速的解析和执行JavaScript脚本.V8引擎就是为解决这一问题而生,在node中也 ...

  8. JavaScript是如何工作的02:深入V8引擎&编写优化代码的5个技巧

    概述 JavaScript引擎是执行 JavaScript 代码的程序或解释器.JavaScript引擎可以实现为标准解释器,或者以某种形式将JavaScript编译为字节码的即时编译器. 以为实现J ...

  9. JavaScript(二)——在 V8 引擎中书写最优代码

    概述 一个 JavaScript 引擎就是一个程序或者一个解释程序,它运行 JavaScript 代码.一个 JavaScript 引擎可以用标准解释程序或者即时编译器来实现,即时编译器即以某种形式把 ...

随机推荐

  1. OpenGL三维与光照

    #include<windows.h> #include<gl/glut.h> #include<gl/gl.h> #include<gl/glu.h> ...

  2. PAT 1074 宇宙无敌加法器

    https://pintia.cn/problem-sets/994805260223102976/problems/994805263297527808 地球人习惯使用十进制数,并且默认一个数字的每 ...

  3. Robot Framework 教程 (5) - 连接Oracel数据库

    Robot Framework 提供了多种Library.其中Database Library可用来连接操作数据库. 1.安装Database Library 打开Robot Framework官网, ...

  4. PHP 配置默认SSL CA证书

    1.从CURL 官网下载CA 证书(当然也可以选择自己创建SSL CA证书,详情参考 https://blog.csdn.net/scuyxi/article/details/54898870 ,或自 ...

  5. Vue 小组件input keyup.enter绑定

    <div id="todo-list-example"> <input v-model="newTodoText" v-on:keyup.en ...

  6. matlab for 运算的提速

    [1]主要思想:matlab是按列存储,定义s(nums,1)比定义s(1,nums)要快哦                       需要重复query的元素看看能不能再for之前就定义好 经典案 ...

  7. crosses initialization of “XXX” 的问题

    在switch-case中定义了变量,用g++编译的时候报错crosses initialization of “XXX” ,在网上一查,说是gcc要求变量的定义不能位于goto之后 将变量定义放在s ...

  8. THUWC2017颓废记

    2.9翘掉Wc闭幕式,和石家庄大爷们坐一辆车去杭州…路上日常orz gzz.2.10早上来报到,拍照.宿舍里另外四个人都是GD大爷.开幕式是喜闻乐见的thu日常黑pku(“在中国,世界一流大学有两所, ...

  9. QComboBox 树形视图选择

    QComboBox 控件支持树形图显示. A.  void QComboBox::setModel(QAbstractItemModel *model): B.  void QComboBox::se ...

  10. CentOS6.7的安装

    VMware9的安装请阅读:  http://www.cnblogs.com/duanji/p/yueding.html CentOS6.7在VMware9中安装 1.启动VMware的画面 2.点击 ...