#597·prepack

重构 (抽象) 值创建

作者: NTillmann创建于 2017年5月8日更新于 2020年8月31日
标签enhancementhelp wantedinterpreterabstractrefactoringdesign needed

预包装将所有值封装到(子类型的)Value 类的实例中。结构上相同的值可能会被表示为多个值。对于具体的值,这意味着预包装会占用比实际需要更多的内存。但是对于抽象值,这实际上会导致错失优化机会。请考虑预包装以下代码时会发生什么情况:

javascript
(function() {
  let x = Date.now();
  global.a = x + 1 + 2 + 3;
  global.b = x + 1 + 2 + 3;
})();

预包装实际上会创建两个表示表达式 x + 1 + 2 + 3 的不同抽象值实例,并将其二次序列化。如果预包装始终将结构上等价的(抽象)值折叠为一个实例,那么所有这些问题都会消失。所以,应该发生以下情况:所有值的创建都应该通过一个新的 ValueManager 类进行。 1. 所有值构造器调用,例如 new Number(...),都应该被替换为调用如 realm.valueManager.createNumber(...) 的函数。 2. 那些创建代数表达式(即函数性/纯/无状态/副作用表达式)的 createAbstract 调用(例如,请参阅 BinaryExpression.js 中如何创建二元表达式),应该被替换为调用如 realm.valueManager.createAbstractBinary(...) 的函数。 3. 对于所有 createAbstractXXX 值,值管理器可以尝试应用常量折叠、一般简化和正则化。特别是,对于逻辑表达式,请考虑使用值编号和正则化到 if-then-else(ite)形式,请参阅 这里。 4. 使用 hash-consing 确保每个结构上唯一的值只有一个实例。 5. 设计一个方案,以便对所有这些值进行垃圾回收。这将变得必要,因为每个中间值现在都将由值管理器引用。 6. #906:一旦我们确定了一个集合中的明确的代数表达式,我们还可以考虑连接一个 SMT 解算器,例如 Z3,以便对表达式进行推理和进一步简化。特别是,能够将 !!(x)!(x) 查询简化为常量可能会大大减少执行路径的数量。请参阅 这里 了解通过连接 SMT 解算器可以进行哪些优化,包括 #620 修订。

内容来源: facebookarchive/prepack