3

JS_CANONICALIZE_NANの目的は何であり、すべてのプラットフォームで常に必要かどうか疑問に思います。

4

1 に答える 1

8

これは楽しいものです!そのため、SpiderMonkey はタグ付きの値表現を内部的に使用して、JavScript の「型なし値」を表します。これにより、VM は「格納されている変数aは数値であり、格納されている値は数値bであるため、実行するa + bと数値加算が行われる」などを判断できます。 .

値のタグ付けにはさまざまなスキームがあり、SpiderMonkey は「NaN ボクシング」と呼ばれるものを使用します。これは、エンジン内のすべての型指定されていない値が、次のいずれかの 64 ビット値で表されることを意味します。

  • ダブル、または
  • IEEE 倍精度浮動小数点値の「NaN 空間」に存在するタグ付きの非 double。

ここでの本当の秘訣は、最近のシステムでは通常、単一のビット パターンを使用して NaN を表すことです。これは、math.h の結果として観察できsqrt(-1)ますlog(0)。しかし、IEEE 浮動小数点仕様に従って NaN と見なされるビット パターンも多数あります。

double はサブフィールドで構成されます。

{sign: 1, exponent: 11, significand: 52}

NaN は、指数フィールドを 1 で埋め、仮数にゼロ以外の値を配置することによって表されます。

次のような小さなプログラムを実行して、プラットフォームの 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 0xfff8000000000000 // Canonical qNaNs...
  nan 0x7ff8000000000000
  nan 0x7ff8000000000000
  nan 0x7ff4000000000000 // sNaN (signaling)

quiet NaN の唯一の違いは符号ビットであり、その後に常に 12 ビットの 1 が続き、上記の NaN 要件を満たしていることに注意してください。最後の信号 NaN は、12 番目 (is_quiet) の NaN ビットをクリアし、13 番目が上記の NaN 不変式を維持できるようにします。

それ以外では、NaN スペースは自由に使用できます。指数を埋めるのに 11 ビット、signficand がゼロでないことを確認し、十分なスペースが残っていることを確認してください。x64 では、47 ビットの仮想アドレスの仮定を使用します。これにより、64 - 47 - 11 = 6値の型に注釈を付けるためのビットが残ります。x86 では、すべてのオブジェクト ポインターが下位 32 ビットに収まります。

ただし、非正規の NaN が js-ctypes などを介して忍び込む場合、タグ付けされた非 double 値のようなものを生成しないようにする必要があります。これは、VM で悪用可能な動作につながる可能性があるためです。(数値をオブジェクトとして扱うことは非常に悪いニュースです。) したがって、(DOUBLE_TO_JSVAL のように) double を形成するときは、すべての doubled != dを正規の NaN 形式に正規化するようにします。

詳細はバグ 584168にあります。

于 2012-02-26T10:55:59.570 に答える