JavaScript / V8 中的 int 数组实际上是作为一个 int 数组实现的吗?

3
这篇文章中提到,JavaScript中的整数数组是由C++整数数组实现的。
然而,根据MDN的说明,除非特别使用BigInts,在JavaScript中所有数字都被表示为双精度浮点数。
如果我执行以下操作:
cont arr = [0, 1, 2, 3];

在V8引擎中的实际表示是什么?

V8的代码可以在github上找到这里,但我不知道该看哪里:


V8有时甚至会使用int16或更低的数据类型。它必须表现得像IEEE754-2019 float64一样,但内部表示不需要是float64。换句话说,只要从JS端无法观察到除float64行为之外的任何内容,就可以了。 - ASDFGerte
没错 - 如果这个数字根本不被用作double,为什么要浪费额外的内存呢?当你将它转换成十进制数时,它可能会开始变成double,但除此之外,它可能只是一个“int”或“long”。 - user1280483
似乎有一些范式混淆。有人能否找到我所举例的实际表示发生的代码位置?我找了但找不到。希望熟悉v8代码的人知道该示例的数据结构在哪里实现。mdn文章似乎是规范而不是接口。我认为查看实际代码(提供的链接)将澄清这一点。 - user17331023
1个回答

3
(这是一位V8开发人员的回复。)“C++ int数组”有点简化了,但该文章所描述的核心思想是正确的,一个数组[0, 1, 2, 3]会被存储为一个“Smi”数组。

什么是“Smi”?虽然JavaScript中的每个数字都必须像IEEE754双精度浮点数一样运作,但当V8可以时,它会将数字表示为“小整数”(31位有符号整数值+1位标记),即当数字在范围-2 ** 302 ** 30-1内具有整数值时,以提高效率。引擎通常可以在底层执行任何操作,只要事情的行为就像实现完全遵循规范一样。因此,当规范(或MDN文档)说“所有数字都是双精度浮点数”时,从引擎(或引擎开发人员)的角度来看,它实际上意味着“所有数字必须表现得好像它们是双精度浮点数”。

当一个数组只包含Smis时,数组本身会跟踪这一事实,以便从这样的数组加载的值知道它们的类型,而无需进行检查。这对于a [i] + 1很重要,其中+的实现在已知a是Smi数组时不必检查a [i]是否为Smi。
当存储在数组中的第一个超出Smi范围的数字时,它将转换为双精度浮点数数组(严格来说仍然不是“C ++数组”,而是垃圾回收堆上的自定义数组,但它类似于C ++数组,因此这是一种很好的解释方式)。
当存储在数组中的第一个非数字时,发生的情况取决于数组之前处于什么状态:如果它是“Smi数组”,那么只需要忘记它只包含Smis这一事实。无需重写,因为由于其标记位,Smis是有效的对象指针。如果数组以前是“double数组”,则确实需要对其进行重写,以便每个元素都是有效的对象指针。所有双精度浮点数将在此时作为所谓的“堆数字”(仅包装双精度值的托管堆上的对象)进行“装箱”。

总之,我想指出,在绝大多数情况下,没有必要担心这些内部实现技巧,甚至不需要意识到它们。尽管如此,我当然理解您的好奇心!此外,数组表示是微基准测试容易被误导的更常见原因之一,因为它们没有考虑实现细节,并可能会建议不适用于较大应用程序的结果。


回复评论:

V8有时甚至使用int16或更低。

不,它不支持 int16 存储方式。未来可能会改变,但如果有任何变化,我猜测未标记的 int32 更有可能被引入。如果实现发生任何变化,则可观察行为当然不会改变。
如果您认为您的应用程序可以从 int16 存储中受益,您可以使用 Int16Array 来强制执行,但请确保衡量其是否真正有益,因为很可能不会,并且根据应用程序对其数组执行的操作而言,甚至可能降低性能。

当将其转换为十进制时,它可能会成为 double

稍微准确地说,将 Smis 数组转换为 doubles 数组有几个原因,例如:
  • 在其中存储小数值,例如 0.5
  • 在其中存储大值,例如 2**34
  • 在其中存储 NaN 或 Infinity 或 -0

请问您能否在代码中指出具体位置?我想查看实际的C++小整数数组。 - user17331023
https://source.chromium.org/chromium/chromium/src/+/main:v8/src/objects/fixed-array.tq 定义了 FixedArray,它在 V8 中用于许多事情,包括作为 smi 或对象数组元素的后备存储。FixedDoubleArray 用于双精度数组的元素。正如我之前所说,它们不是 C++ 数组,但它们在内存中的布局类似。在整个 V8 代码库中都有处理各种类型数组的代码。 - jmrk
V8是Node和Chrome背后的引擎,我认为它应该在引擎中...,https://github.com/v8/v8/blob/master/src/builtins/builtins-array.cc,...因为它在Q中发布的链接中。 - user17331023
@user17331023:是的,V8就是引擎;我给出的链接展示了V8的源代码,只不过使用了Chromium的codesearch而非GitHub的镜像,因为这样更容易浏览。builtins-array.cc包含了一堆与数组相关的功能,但并没有数组对象的定义。 - jmrk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接