JS_规范化spidermonkey引擎的目的是什么?

JS_规范化spidermonkey引擎的目的是什么?,spidermonkey,Spidermonkey,我想知道JS_规范化_NAN的目的是什么,是否所有平台都需要它?这是一个有趣的问题!因此,SpiderMonkey在内部使用标记值表示来表示JavScript的“非类型化值”——这允许VM确定“存储在a中的变量是一个数字,存储在b中的值是一个数字,因此运行a+b进行数字相加” 有一系列不同的值标记方案,SpiderMonkey使用一种称为“NaN-boxing”的方案。这意味着引擎中的所有非类型化值都由64位值表示,这些值可以是: 双人房,或 存在于IEEE双精度浮点值的“NaN空间”中的标记

我想知道JS_规范化_NAN的目的是什么,是否所有平台都需要它?

这是一个有趣的问题!因此,SpiderMonkey在内部使用标记值表示来表示JavScript的“非类型化值”——这允许VM确定“存储在
a
中的变量是一个数字,存储在
b
中的值是一个数字,因此运行
a+b
进行数字相加”

有一系列不同的值标记方案,SpiderMonkey使用一种称为“NaN-boxing”的方案。这意味着引擎中的所有非类型化值都由64位值表示,这些值可以是:

  • 双人房,或
  • 存在于IEEE双精度浮点值的“NaN空间”中的标记非双精度浮点值
这里真正的诀窍是现代系统通常使用一个位模式来表示NaN,您可以通过math.h的
sqrt(-1)
log(0)
来观察NaN。但是根据IEEE浮点规范,有很多位模式也被认为是NAN

double由以下子字段组成:

{sign: 1, exponent: 11, significand: 52}
通过在指数字段中填充1并在有效位中放置非零值来表示NaN

如果您运行这样的小程序来查看平台的NaN值:

#include <stdio.h>
#include <math.h>
#include <limits>

static unsigned long long 
DoubleAsULL(double d) {
    return *((unsigned long long *) &d);
}

int main() {
    double sqrtNaN = sqrt(-1);
    printf("%5f 0x%llx\n", sqrtNaN, DoubleAsULL(sqrtNaN));
    double logNaN = log(-1);
    printf("%5f 0x%llx\n", logNaN, DoubleAsULL(logNaN));
    double compilerNaN = NAN;
    printf("%5f 0x%llx\n", compilerNaN, DoubleAsULL(compilerNaN));
    double compilerSNAN = std::numeric_limits<double>::signaling_NaN();
    printf("%5f 0x%llx\n", compilerSNAN, DoubleAsULL(compilerSNAN));
    return 0;
}
请注意,安静NaN的唯一区别在于符号位,后面总是跟12位1,满足上述NaN要求。最后一个是信令NaN,它清除第12个(is_quiet)NaN位,并使第13个保持上述NaN不变

除此之外,NaN空间可以自由使用--11位来填充指数,确保significand不为零,这样就剩下了很多空间。在x64上,我们使用47位虚拟地址假设,这就为注释值类型留下了
64-47-11=6
位。在x86上,所有对象指针都适合低32位

然而,我们仍然需要确保非规范的NaN,如果它们通过js ctypes之类的东西潜入,不会产生类似于标记的非双精度值的东西,因为这可能导致VM中的可利用行为。(将数字视为对象是一个非常坏的消息。)因此,当我们形成DOUBLE(如DOUBLE_TO_JSVAL)时,我们确保规范化
d!=d
转换为规范NaN形式

更多信息在这里

 -nan 0xfff8000000000000 // Canonical qNaNs...
  nan 0x7ff8000000000000
  nan 0x7ff8000000000000
  nan 0x7ff4000000000000 // sNaN (signaling)