Skip to content

[js-api] Conversion from JS values to floats doesn't specify how to handle NaNs #1496

@Liamolucko

Description

@Liamolucko

The current algorithm within ToWebAssemblyValue to convert from JS values to floats looks like this:

If type is f64,

Let f64 be ? ToNumber(v).
Return f64.const f64.

It's very unclear how NaNs should be handled here. ToNumber returns a JS number, which isn't quite the same as a regular f64; it's only defined to have a single NaN value, with an unknown bit pattern. The spec should say something about how that NaN value gets converted, whether it's defined to result in a particular value or just left as implementation-defined.

The actual implementation of this currently differs between browsers. Using this code to test:

;; float-bits.wasm
(module
    (func $f64toi64 (param $float f64) (result i64)
        local.get $float
        i64.reinterpret_f64
    )
    (func $i64tof64 (param $bits i64) (result f64)
        local.get $bits
        f64.reinterpret_i64
    )
    (export "f64toi64" (func $f64toi64))
    (export "i64tof64" (func $i64tof64))
)
const wasm = fetch("./float-bits.wasm");
const { instance } = await WebAssembly.instantiateStreaming(wasm);
const { f64toi64, i64tof64 } = instance.exports;

document.body.textContent = f64toi64(i64tof64(0x7ff8000000001234n)).toString(16);

Chromium preserves the bits and shows 7ff8000000001234, whereas Firefox and Safari pick a single NaN bit pattern of 7ff8000000000000.


In the opposite direction, ToJSValue also doesn't specify how NaNs should be handled:

  1. If w is of the form f64.const f64, return the Number value for f64.

I don't find this as bad, since it's pretty obvious that any NaN should map to the JS NaN, but it wouldn't hurt to add a note about it here too.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions