【问题标题】:How v8 Javascript engine performs bit operations on Int32Array valuesv8 Javascript 引擎如何对 Int32Array 值执行位操作
【发布时间】:2020-08-14 12:51:12
【问题描述】:

据我所知,V8 Javascript 引擎进行双数转换(到 i32 并返回)来执行位操作。 让我们考虑下一个例子:

const int32 = new Int32Array(2);
int32[0] = 42;
int32[1] = 2;
const y = int32[0] | int32[1];

V8 在这种情况下会进行双重转换吗? 如果不是,是否意味着对 Int32Array 值的位运算更快?

更新: 通过双重转换,我的意思是: 从 64 位(53 位精度)到 -> 32 位,再到 -> 64 位

【问题讨论】:

  • 双重转换意味着i32 -> double -> i32,对吧?
  • @D.Pardal 抱歉,我不够清楚。意思是:从 64 位(53 位精度)到 -> 32 位,再到 -> 64 位
  • @SerhiiBilyk 不,“double -> i32 -> double” 没有意义。该值存储为 i32,按位运算发生在 i32 上。它可能会被转换为一个双 in between(按照规范的要求),或者转换被优化掉。

标签: javascript performance bit-manipulation v8 typedarray


【解决方案1】:

V8 开发人员在这里。简短的回答是:这里没有转换,按位运算总是对 32 位整数执行,Int32Array 也将其元素存储为 32 位整数。

更长的答案是“视情况而定”。在未优化的代码中,所有值都使用统一的表示。在 V8 中,这意味着如果数值在范围内(包括符号在内的 31 位,即大约 -10 亿到 +10 亿),则数值要么表示为“Smi”(“小整数”),要么表示为“HeapNumbers”(64 -bit double 带有一个小对象头)否则。因此,对于像int32[0] 这样的元素加载,32 位值从数组中加载,检查范围,然后标记为 Smi 或装箱为 HeapNumber。以下| 操作查看输入,将其转换为 32 位整数(这可以像取消标记 Smi 一样简单,也可以像在对象上调用 .valueOf 一样复杂),然后执行按位“或” .然后将结果再次标记为 Smi 或装箱为 HeapNumber,以便下一个操作可以决定如何处理它。

如果函数运行频繁到最终得到优化,那么优化编译器会利用类型反馈(必要时由类型检查保护)来忽略所有这些在这种情况下不必要的转换,简单的答案就是正确的.

【讨论】:

  • 类型反馈是否认为HeapNumber和SMI相同,从而优化掉范围检查?
  • @Bergi:类型反馈系统单独跟踪 Smis,以便优化编译器可以决定是否发出 HeapNumber 处理代码。
  • 那么优化编译器是否会发出避免 HeapNumbers 和双重转换的代码,即使对于 1 <<< 30(即任何在 SMI 范围之外的 int32uint32)?
  • 在大多数情况下,这就是我所期望的。如果它实际上是1 << 30,那么它甚至应该不断地折叠它。也就是说,对于可变输入,权衡是更小的代码与以后不得不deopt的风险;因此,在任何给定情况下是否发出 HeapNumber 路径完全是团队可能会随着时间的推移而迭代的事情,所以我不想对此做出任何绝对的陈述。
  • 我的经验是优化编译器会发出一个'not a smi' depot。
猜你喜欢
  • 2013-04-21
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 2013-01-02
  • 1970-01-01
  • 2015-05-16
  • 2011-09-22
  • 1970-01-01
相关资源
最近更新 更多