v8 专家的问题。
最近,我在 v8 中发现了多态的情况。正是多态性仅对 4 个对象“形状”进行了很好的优化,之后性能显着下降。类和对象继承被忽略。这是一个非常令人沮丧的发现,因为在这些限制下,结构良好的代码将无法执行。自 2017 年以来,这似乎是一个众所周知的问题,而且在不久的将来不太可能发生任何变化。
所以,我愿意在用户空间实现更好的多态性:https ://github.com/canonic-epicure/monopoly
这不是一个新问题,它已经用几乎任何其他语言解决了,包括 vtables、代码专业化等。非常欢迎任何关于如何在 JavaScript 中完成的建议。
我目前试图解决的问题是从任意对象单态检索一些元信息。此元信息将是一个 vtable 模拟,包含方法分派的信息。这是为了避免包含此信息的额外框。
JS 中的元信息(很多其他对象共享的某个对象)自然映射到原型,所以第一步就是获取对象的原型。这可以用 单态完成Object.getPrototypeOf()
。但是,似乎无论你尝试什么,你都会失去单态性。
例如,在以下代码中,对对象的构造函数的访问将是超态的:
class HasVTable {}
HasVTable.prototype.vtable = {}
class Class1 extends HasVTable {}
class Class2 extends HasVTable {}
class Class3 extends HasVTable {}
class Class4 extends HasVTable {}
class Class5 extends HasVTable {}
function access(obj) {
console.log(Object.getPrototypeOf(obj).constructor.name);
}
%OptimizeFunctionOnNextCall(access);
access(new Class1);
access(new Class2);
access(new Class3);
access(new Class4);
access(new Class5);
所以问题是,如何在原型中存储一些信息然后检索它,而不会失去单态性?也许,一些“知名”符号可以在这里提供帮助?还是有其他解决方案?
谢谢!
例如,我刚刚尝试使用迭代器符号,但没有成功 -proto
在迭代器位置访问仍然是超态的:
class HasVTable {}
class Class1 extends HasVTable {
*[Symbol.iterator] () {
yield 'Class1'
}
}
class Class2 extends HasVTable {
*[Symbol.iterator] () {
yield 'Class2'
}
}
class Class3 extends HasVTable {
*[Symbol.iterator] () {
yield 'Class3'
}
}
class Class4 extends HasVTable {
*[Symbol.iterator] () {
yield 'Class4'
}
}
class Class5 extends HasVTable {
*[Symbol.iterator] () {
yield 'Class5'
}
}
function access(obj) {
const proto = Object.getPrototypeOf(obj)
let res
for (res of proto) break
console.log(res)
}
%OptimizeFunctionOnNextCall(access);
access(new Class1);
access(new Class2);
access(new Class3);
access(new Class4);
access(new Class5);
更新 2020/10/21
我使用了一个出色的deoptigate
工具来跟踪代码反优化:
npx deoptigate --allow-natives-syntax -r esm src_js/draft3.js