JavaScript引擎V8快速属性访问

3
当我查看v8设计元素快速属性访问时,它在此主题的最后一段中提到了这一点:
“使用隐藏类有两个优点:属性访问不需要字典查找,并且它们使V8能够使用经典的基于类的优化,内联缓存。”
对我来说,这有点模糊。有人可以详细说明一下为什么隐藏类不需要进行字典查找并启用v8使用经典的基于类的优化,内联缓存吗?
请尽可能详细地解释。

3
为什么隐藏类不需要进行字典查找,有人可以阐述一下吗? --- 因为那里没有字典。请再次阅读“快速属性访问”部分。 - zerkms
@Bergi: https://developers.google.com/v8/design - zerkms
1个回答

4

我认为你提到的文章已经很好地解释了隐藏类的概念。每当向一个对象添加新的属性时,都会创建一个新的隐藏类。对象会保留对这个隐藏类的引用。此外,隐藏类还会保留对先前创建的隐藏类的引用。例如:

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var point = new Point(10, 10);

当调用new Point()时,会创建一个新的hidden-classpoint保留对该hidden-class的引用。初始的hidden-class为空,也就是说,它不包含任何属性。然后,当调用this.x时,会创建一个新的hidden-class。该隐藏类保留对先前隐藏类的引用,并且点更新其引用以指向该新的hidden-class。当执行this.y = y时,同样会发生这种情况。
由于在JavaScript中可以动态地添加和删除对象的属性,因此解析属性访问的方法是使用map。另一方面,hidden-classes将属性按顺序线性存储,就像C语言中的struct。由于hidden-classes,访问属性与访问数组元素一样快。
现在让我们来看看什么是inline caching。内联缓存是一种旧的优化技术,用于诸如Smalltak 80或Self等动态语言,并由JavaScript广泛使用。当在运行时访问属性时,需要确定调用对象的类型,以便知道要调用哪个实现代码。这称为dynamic dispatchlate binding,并且在JavaScript访问属性或将两个操作数相加时发生(它们可以是integerdouble等)。考虑以下代码:
var x = 10;
var y = 10;
var total = x + y;

使用内联缓存时,当编译var total = x + y时,不会编译一个通用的加法子程序过程调用。相反,该代码被编译为一个存根(内联缓存)。在内联缓存中生成的代码查看接收到的参数类型并生成专门针对这些类型的代码。稍后,如果调用另一个加法,则执行内联缓存,假设类型与之前相同。但是类型可能不同,因此内联缓存要做的第一件事就是检查参数的类型。如果类型不同,则导致缓存未命中,并为那些特定类型生成新代码。如果内联缓存可以处理许多不同类型,则称其为多态内联缓存(具有多个类型集的条目)。 内联缓存节省了推断函数调用中的参数类型的计算,如果在循环中发生调用,它们的效益更大。 内联缓存发生在JavaScript访问对象属性时,在此之前我们看到如何使用隐藏类来快速访问属性。
有关隐藏类内联缓存的更多信息,请参见以下文章(特别是来自V8黑客Vyacheslav Egorov的前两篇文章):

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接