如何分析JS引擎中的InlineCache技术

如何分析JS引擎中的Inline Cache技术,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

创新互联公司2013年至今,先为荆门等服务建站,荆门等地企业,进行企业商务咨询服务。为荆门企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。

01
 引例

     

     
function Point(x,y) {
this.x = x;
this.y = y;
}
var p = new Point(0, 1);
var q = new Point(2,3);
var r = new Point(4,5);

为了避免API调用不稳定因素的影响,通过修改V8源码,在内部插入时间戳的方式。在3.2G 8核机器上,分别测试三次调用new Point(x,y)时执行this.x=x这个语句耗时,结果如下表所示。

执行代码this.x=x耗时统计
var p = new Point(0,1);4.11ns
var q = new Point(2,3);6.63ns
var r = new Point(4,5);0.65ns

从表中的结果可以看出,事实并非想象中的从第二次执行开始,速度就会变快,相反,第二次比第一次还要慢,到第三次的时候速度才会变快。本文后面会通过分析V8 IC机制来解释为什么第二次速度最慢,第三次执行速度又变快的原因。

02      
 问题分析


1. 对象的隐藏类(Hidden Class)

由于JavaScript对象没有类型信息,几乎所有JS引擎都采用隐藏类(Hidden Class/Shape/Map等)来描述对象的布局信息,用以在虚拟机内部区分不同对象的类型,从而完成一些基于类型的优化。

V8对JavaScript对象都使用HeapObject来描述和存储,每一种JavaScript对象都是HeapObject的子类,而每个HeapObject都用Map来描述对象的布局。对象的Map描述了对象的类型,即成员数目、成员名称、成员在内存中的位置信息等。

上述源码中对象p、q、r都是由同一个构造函数Point生成,因此他们具有同样的内存布局,可以采用同一个Map来描述。

2. 隐藏类变迁(Map Transition)

因为JavaScript是高度动态的程序设计语言,对象的成员可以被随意动态地添加、删除甚至修改类型。因此,对象的隐藏类在程序的运行过程中可能会发生变化,V8内部把这种变化叫隐藏类变迁(Map Transition)。

以上文代码为例,当Point function被声明时,V8就会给Point创建隐藏类map0,由于暂时还没有属性,因此map0为空。当执行this.x=x时,V8会创建第二个Hidden Class map1,map1是基于map0,并且描述了属性x在内存中的位置,此时this对象的Hidden Class会通过Map Transition变为map1。当执行this.y=y时,会重复前面的操作,一个新的Hidden Class map2会被创建,此时this对象的Hidden Class被更新为map2。this对象的Map从map0变为map1,再变成map2的过程就叫做Map Transition。图一描述了Point类对象创建过程中Map Transition的过程。  

如何分析JS引擎中的Inline Cache技术

Map Transition示意图

3. 类型反馈向量(type feedback vector)  

前面已经提到IC机制的原理是:对于某代码语句比如this.x=x,比较上次执行到该语句时缓存的Map和对象当前的Map是否相同,如果相同则执行对应的IC-Hit代码,反之执行IC-Miss代码。那么V8是如何组织被缓存的Map和IC-Hit代码?以上文代码为例,V8会在Point函数对象上添加一个名为type_feedback_vector的数组成员,对于该函数中的每处可能产生IC的代码,Point对象中的type_feedback_vector会缓存上一次执行至该语句时对象的Map和对应的IC-Hit代码(在V8内部称为IC-Hit Handler)。上文中的Point函数中有两处可能产生IC的语句,this.x=x和this.y=y。假设某次执行至this.x=x时,对象this的Map是map0,执行至this.y=y时this的Map是map1,那么Point对象的type_feedback_vector数据内容如下所示:

数组下标IC对应的源码缓存的Map和对应的IC-Hit Handler
0this.x=x
1this.y=y

简单来说,type_feedback_vector缓存了Map和与之对应的IC-Hit handler,这样IC相关的逻辑简化为只需要通过访问type_eedback_vector就可以判断是否IC Hit并执行对应的IC-Hit Handler。

4. IC状态机

为了描述V8中IC状态的变化情况,本节将以状态机的形式描述V8中最常见IC种类的状态变化情况。V8中最常用 的IC分为五个状态,如图二所示。初始为uninitialized状态,当发生一次IC-Miss时会变为pre-monomorphic态,再次IC-Miss会进入monomorphic态,如果继续IC-Miss,则会进入polymorphic状态。进入polymorphic之后如果继续IC-Miss 3次,则会进入megamorphic态,并最终稳定在megamophic态。

如何分析JS引擎中的Inline Cache技术

IC状态机

引例中代码会涉及到IC状态机的前三种状态。

以Point函数走红this.x=x语句为例,第一次执行时,由于Point.type_feedback_vetor为空,因此此时会发生IC-Miss,并将该处IC状态从uninitialized设置为pre-monomorphic,IC-Miss Handler会分析出此时this对象的Map中不包含属性x,因此会添加成员x,接着会发生Map Transition,即前文提到的this对象的隐藏类从map0变为map1。由于考虑到大部分函数可能只会被调用一次,因此V8的策略是发生第一次IC-Miss时,并不会缓存此时的map,也不会产生IC-Hit handler;

第二次调用构造函数执行this.x=x时,由于Point.type_feedback_vector仍然为空,因此会发生第二次IC-Miss,并将IC状态修改为monomorphic,此次IC-Miss Hanlder除了发生Map Transition之外,还会编译生成IC-Hit Handler,并将map0和IC Hit Handler缓存到Point.type_feedback_vector中。由于此次IC-Miss Handler需要编译IC-Hit Handler的操作比较耗时,因此第二次执行this.x=x是最慢的;

第三次调用构造函数中this.x=x时,发现Point.type_feedback_vector不为空,且此时缓存的map0与此时this对象的Map也是一致的,因此会直接调用IC-Hit Handler来添加成员x并进行Map transition。由于此次无需对map0进行分析,也无需编译IC-Hit Handler,因此此时执行效率比前两次都高。

至此,已经解释清楚为什么V8执行构造函数时,第二遍最慢而第三遍最快的原因。
5. Polymorphic和Megamorphic
function f(o) {

  return o.x;
}

f({x:1}) //pre-monomorphic

f({x:2}) //monomorphic

f({x:3, y:1}) // polymorphic degree 2

f({x:4, z:1}) // polymorphic degree 3

f({x:5, a:1}) // polymorphic degree 4

f({x:6, b:1}) // megamorphic
上述代码描述了图二状态机中polymorphic态和megamophic态的两种情形。上面3中提到type_feedback_vector会缓存Map和IC-Hit Handler,但是如果IC状态太多比如到达megamorphic态,此时Map和IC-Hit Handler便不会再缓存在Point对象的feedback_vector中,而是存储在固定大小的全局hashtable中,如果IC态多于hashtable的大小,则会对之前的缓存进行覆盖。通过上述分析,可以总结得出不同IC态的性能:
  • 如果每次都能在monomorphic态IC-Hit,代码的运行速度是最快的;
  • 在polymorphic态IC-Hit时,需要对缓存进行线性查找;
  • Megamorphic是性能最低的IC-Hit,因为需要每次对hashtable进行查找,但是megamorphic ic hit性能仍然优 于IC-Miss;
  • IC-Miss性能是最差的;

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注创新互联行业资讯频道,感谢您对创新互联的支持。


文章标题:如何分析JS引擎中的InlineCache技术
地址分享:http://bzwzjz.com/article/ijsjds.html

其他资讯

Copyright © 2007-2020 广东宝晨空调科技有限公司 All Rights Reserved 粤ICP备2022107769号
友情链接: 重庆网站建设 网站建设公司 上市集团网站建设 重庆网站制作 定制级高端网站建设 成都企业网站设计 成都网站设计 成都企业网站制作 响应式网站建设 网站制作公司 营销型网站建设 成都网站建设 成都网站制作 外贸网站设计方案 成都网站制作 成都营销网站建设 成都网站制作公司 成都网站建设 自适应网站设计 成都响应式网站建设公司 网站建设 成都网站建设公司