【问题标题】:Is an array of ints actually implemented as an array of ints in JavaScript / V8?在 JavaScript / V8 中,整数数组实际上是作为整数数组实现的吗?
【发布时间】:2022-01-20 18:41:21
【问题描述】:

this article 中声称 JavaScript 中的整数数组是由 C++ 整数数组实现的。

但是;根据MDN,除非您专门使用 BigInts,否则在 JavaScript 中所有数字都被抑制为双精度数。

如果我这样做:

cont arr = [0, 1, 2, 3];

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

V8的代码是here on github,但是不知道去哪里看:

【问题讨论】:

  • V8 有时甚至使用 int16 或更低版本。它必须表现得像 IEEE754-2019 float64,但内部表示不需要是 float64。换句话说,只要从 JS 端观察不到 float64 行为以外的任何东西,就可以了。
  • 这是真的——如果这个数字根本不被用作双精度数,为什么要用掉额外的内存?当您将其设为小数时,它可能开始为双精度数,否则,它可能只是 intlong
  • 似乎有些范式混为一谈。有人可以在代码中找到我给出的示例的实际表示吗?我看了但找不到。希望熟悉 v8 代码的人能够确切地知道该示例的数据结构在哪里实现。 mdn文章似乎是规范而不是接口。我认为查看实际代码(上面提供的链接)可以解决这个问题。

标签: javascript arrays double v8


【解决方案1】:

(这里是 V8 开发人员。) “C++ 整数数组”有点简化,但那篇文章中描述的关键思想是正确的,数组[0, 1, 2, 3] 将存储为“Smis”数组。

什么是“Smi”?虽然 JavaScript 中的每个数字都必须表现得像 IEEE754 双精度数,但 V8 在内部将数字表示为“小整数”(31 位有符号整数值 + 1 位标记),即当数字具有 -2**30 范围内的整数值时到2**30-1,提高效率。引擎通常可以在引擎盖下做任何他们想做的事情,只要事情表现得好像实现完全遵循规范。因此,当规范(或 MDN 文档)说“所有数字都是双精度数”时,从引擎(或引擎开发人员)的角度来看,它的真正含义是“所有数字必须像双精度数一样表现”。

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

总之,我想指出的是,在绝大多数情况下,无需担心任何这些内部实现技巧,甚至无需了解它们。我当然理解你的好奇心!此外,数组表示是不考虑实现细节的微基准测试很容易通过建议不会延续到更大应用程序的结果而容易产生误导的更常见原因之一。


寻址 cmets:

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

不,它没有。它将来可能会或可能不会开始这样做;虽然如果有什么改变,我猜未标记的 int32 比 int16 更有可能被引入;此外,如果实施发生任何变化,那么可观察到的行为当然不会改变。
如果您认为您的应用程序将从 int16 存储中受益,您可以使用 Int16Array 来强制执行此操作,但请务必衡量这是否真的有利于您,因为很可能不会,甚至可能会降低性能,具体取决于你的应用会处理它的数组。

当你将它设为小数时,它可能会开始为双精度

稍微准确一点:需要将 Smis 数组转换为双精度数组的原因有几个,例如:

  • 在其中存储一个小数值,例如0.5
  • 在其中存储较大的值,例如2**34
  • 在其中存储NaNInfinity-0

【讨论】:

  • 能否请您发布有关它在代码中的位置的信息。我想看看实际的 C++ 小整数数组。
  • source.chromium.org/chromium/chromium/src/+/main:v8/src/objects/… 定义了FixedArray,它在 V8 中用于许多事情,包括作为 smi 或对象数组元素的后备存储。 FixedDoubleArray 用于双数组的元素。正如我之前所说,它们不是 C++ 数组,但它们的内存布局是相似的。 V8 代码库中都有处理各种数组的代码。
  • V8 是引擎,在 Node 和 Chrome 之后,我假设它会在引擎中,...,github.com/v8/v8/blob/master/src/builtins/builtins-array.cc,...因为它发布在 Q 的链接中.
  • @user17331023:是的,V8 是引擎;我提供的链接向您展示了 V8 源代码,只是使用 Chromium 的代码搜索而不是 GitHub 镜像,因为这样更容易浏览。 builtins-array.cc 有一堆数组相关的功能,但没有数组对象的定义。
猜你喜欢
  • 2012-03-03
  • 2011-10-27
  • 2015-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-29
  • 1970-01-01
相关资源
最近更新 更多