V8引擎如何处理添加属性的排序?

时间:2015-04-24 05:13:50

标签: javascript performance v8

我一直在关注Google的V8 Javascript引擎的性能改进,因为我想将它合并到我自己的一个项目中。

我现在的兴趣在于隐藏的课程。基本思想是V8创建隐藏类,因为属性被添加到对象中,以便有效地查找该属性,从而避免字典搜索。

例如,当您创建一个名为Point的新p对象时,它会创建一个隐藏的类C0,这是一个没有属性的类,并将该类附加到该对象: / p>

enter image description here

语句p.x = 0将修改对象以添加属性,然后创建 new C1,指定可以在一个x属性中找到对象内的特定偏移量。

enter image description here

因此,在p.x之后到达是一个相对有效的操作。

最后,执行p.y = 0将执行类似的操作,最后是:

enter image description here

现在这实际上相当漂亮,因为如果你创建另一个Point对象p2,则不需要创建新的隐藏类,它只会被分配"到C0。同样,按顺序添加xy属性也非常有效,无需创建新的隐藏类。

但是这个方案有两个潜在的问题。第一个涉及以下代码段发生的事情:

Point p3 = new Point();
p3.y = 3141592653589;
p3.x = 2718281828459;

在我看来,这会创建两个新的隐藏类,一个在偏移零点处y,在偏移零点处另一个yx在抵消一。

这似乎有点空间效率低,因为两个案例中的最终类都有xy所以应该能够共享类C2,尽管要求您需要在对象本身中交换xy

使转换映射更加受控制会产生什么影响,例如确保按字母顺序存储属性?这样,无论您添加x然后y,还是y再添加x,您仍然会在最后一堂课中加入。

这意味着在添加属性时会有一些额外的工作,但可以大大减少隐藏类的数量。

或者这项额外的工作本身可能会造成太大的性能损失?

第二个潜在的问题是,由于这个方案的整个目的是避免在对象上进行字典查找,所以如何移动:

For x, see offset 0
For y, see offset 1

进入班级帮助?

在我看来,需要在隐藏类中查找属性名称以获取对象内的偏移量。

或者我错过了什么,并且不需要对该课程进行字典搜索?

1 个答案:

答案 0 :(得分:1)

优化后,不需要进行字典搜索(对于大多数访问)。

在属性访问时,v8(希望)将属性访问转换为内联缓存存根。这意味着,在访问x时,它的身份x已被偏移值包含。所以它不再是x了,甚至x at offset 0,它只是offset 0。即使对象表示被称为“地图”,它实际上只是一个偏移表。这就是使财产快速访问的原因。

当需要添加新属性时,问题不在于“当前对象具有所有属性的对象在哪里加上新属性?”它是“对于这个对象,我需要做些什么才能添加这个属性?”在此基础上选择过渡。在优化代码中,不考虑现有属性的名称。删除多余的隐藏类需要一些相对较大的操作才能找到匹配的地图。

您反对添加属性的假设会创建两个新的隐藏类。您可以通过d8 --allow-natives-syntax运行以下内容来了解​​相关信息:

function Point() {}

var p = new Point();

var px = new Point();
px.x = 0x10101;

var py = new Point();
py.y = 0x20202;

var pxy = new Point();
pxy.x = 0x30303;
pxy.y = 0x40404;

var pyx = new Point();
pyx.y = 0x50505;
pyx.x = 0x60606;

var newp = new Point();
checkmaps();
newp.x = 0x70707;
checkmaps();
newp.y = 0x80808;
checkmaps();

function checkmaps() {
  var sameas = [];
  if (%HaveSameMap(newp, p))
    sameas.push("p");
  if (%HaveSameMap(newp, px))
    sameas.push("px");
  if (%HaveSameMap(newp, py))
    sameas.push("py");
  if (%HaveSameMap(newp, pxy))
    sameas.push("pxy");
  if (%HaveSameMap(newp, pyx))
    sameas.push("pyx");
  print(sameas);
}

输出结果为:

p
px
pxy