【发布时间】:2017-03-12 10:00:15
【问题描述】:
所以,我已经广泛阅读了 V8 引擎的公共 Wiki,并且了解了隐藏类如何查找属性的概念。 v8 design elements
但是,我真正不明白的是这比哈希表更快。
据此,它的说法是属性存储在不同的偏移量中,但是对于每个偏移量,您必须检查其是否正确的属性。那么是否意味着您必须在最坏的情况下遍历所有属性才能获得所需属性的正确偏移量?
由于哈希表是恒定时间查找,它们通常不会比这更快吗?
【问题讨论】:
所以,我已经广泛阅读了 V8 引擎的公共 Wiki,并且了解了隐藏类如何查找属性的概念。 v8 design elements
但是,我真正不明白的是这比哈希表更快。
据此,它的说法是属性存储在不同的偏移量中,但是对于每个偏移量,您必须检查其是否正确的属性。那么是否意味着您必须在最坏的情况下遍历所有属性才能获得所需属性的正确偏移量?
由于哈希表是恒定时间查找,它们通常不会比这更快吗?
【问题讨论】:
您的问题似乎已通过here、here 和here 的某种组合得到解答。
简而言之,根据我对这些链接的理解:
哈希表比常量时间查找慢,因此 V8 尽可能使用后者,但如果对象变得过于复杂而无法使用隐藏类很好地处理,则回退到前者。
线性扫描显然也很糟糕,但在我看来,V8 试图通过一种称为内联缓存的技术来优化代码以缓解数据结构的这个问题。 em>:当您的代码尝试重复访问 obj.prop 时,V8 最终决定只动态修补生成的代码,以便属性访问成为给定偏移量的恒定时间查找。
当然,如果预期的类类型错误,那么它就不得不回退并尝试慢速查找。function CompileNamedLoadFastProperty(klass, key) on this page 尝试解释:
function CompileNamedLoadFastProperty(klass, key) {
// Key is known to be constant (named load). Specialize index.
var index = klass.getIndex(key);
function KeyedLoadFastProperty(t, k, ic) {
if (t.klass !== klass) {
// Expected klass does not match. Can't use cached index.
// Fall through to the runtime system.
return NAMED_LOAD_MISS(t, k, ic);
}
return t.properties[index]; // Veni. Vidi. Vici.
}
return KeyedLoadFastProperty;
}
function NAMED_LOAD_MISS(t, k, ic) {
var v = LOAD(t, k);
if (t.klass.kind === "fast") {
// Create a load stub that is specialized for a fixed class and key k and
// loads property from a fixed offset.
var stub = CompileNamedLoadFastProperty(t.klass, k);
PatchIC("LOAD", ic, stub);
}
return v;
}
【讨论】: