正如拉尔斯巴克和康罗德在几个视频和论文中所描述的,V8中隐藏类的主要思想是存储具体的偏移量或转换到另一个可能包含每个对象属性的隐藏类,而不是在包含所有属性的哈希表中进行“缓慢”查找。
在传统的属性访问方式中,例如要获得point.x
,我们需要从x
中计算哈希码,然后遍历数组(如果在添加属性时没有哈希码冲突,我们将立即得到值)。但以一种新的方式,我们有一个隐藏类(只是一个Map
?)并且需要对其进行迭代以找到是否包含x
键,只有在此之后,我们才能通过x
字段中的偏移来获取属性值。或者在更复杂的情况下,我们需要通过转换到另一个隐藏类来完成一些额外的步骤。因此,我不认为在哈希表中存储所有属性与使用隐藏类有什么区别。也许有什么我不懂的装配技巧?
发布于 2015-03-22 15:05:46
V8和其他使用类似技术的语言实现都是即时编译器.它们生成代码,并对生成的代码进行了投机性优化(如果专门化被证明是无效的,则检查返回到更慢、更一般的代码)。因此,在生成代码时,JIT编译器通常能够很好地猜测对象的隐藏类是什么--来自类型推断或运行程序时收集的数据--它生成如下代码:
compare hidden class pointer to address of assumed
if not equal, de-optimize, otherwise:
access the property at a hard-coded offset
上面的每一行都可以是x86上的单个汇编程序指令。由于它在生成此代码时假定为隐藏类,因此JIT编译器可以在JIT编译时从隐藏类中检索偏移量,并在代码中对其进行硬编码,因此运行的代码通常从未触及隐藏类。
发布于 2015-03-22 15:15:21
关键是这是在产生专门代码的JIT中使用的。
比方说,它有一个类似这样的函数:
function add_points(a, b) {
return new Point(a.x + b.x, a.y + b.y);
}
V8实际上将为传递给您的不同可能的参数生成此函数的不同版本。例如,它将生成函数的一个版本,仅当a和b都是隐藏的Point类的成员时才使用。
Point add_points(Point a, Point b) {
return new Point(a.x + b.x, a.y + b.y);
}
那么诀窍是,由于我们知道这个函数实际上只用于具有隐藏点类的对象,所以x和y总是处于相同的偏移量。因此,我们不必每次都查找它,编译器在构建此函数时只查找一次,并将偏移量插入生成的代码中。
https://softwareengineering.stackexchange.com/questions/277036
复制相似问题