Re: Observability of NaN distinctions — is this a concern?
Kenneth Russell
kbr at google.com
Tue Mar 26 19:02:36 PDT 2013
Dmitry, thank you for prototyping and benchmarking this. There should
be no question that a slowdown of 25% is too high a cost to pay.
Allen's analysis earlier in the thread indicates that no spec changes
are necessary in order to allow multiple bit patterns to be used when
storing NaNs into Float32Array and Float64Array. Can this topic be
laid to rest?
-Ken
On Tue, Mar 26, 2013 at 12:14 PM, Dmitry Lomov <dslomov at google.com> wrote:
> I would like to add some perf numbers to this discussion, if I may.
>
> I have implemented a quick patch for V8 that implements NaN normalization on
> Float64Array store. V8 does not use NaN boxing, so from implementation
> perspective NaN normalization is not required by V8.
>
> In my test, the perf penalty for Float64Array store is 25% (on ia32
> architecture in optimized regime, using sse2 instructions).
> I am attaching the test and my patch for your perusal (the patch should
> easily apply to v8's bleeding_edge).
>
> It feels like the performance hit is a very considerable factor here,
> especially given that typed arrays are all about fast math.
>
>
> Results on my machine:
>
> Normalized stores:
> $ ./out/ia32.release/d8 float-array.js
> Start
> 14033 msec
> Start
> 14059 msec
> Start
> 13983 msec
> Start
> 13979 msec
> Non-normalized stores:
> $ ./out.baseline/ia32.release/d8 float-array.js
> Start
> 11197 msec
> Start
> 11207 msec
> Start
> 11207 msec
> Start
> 11253 msec
>
> Dmitry
>
>
>
> On Tue, Mar 26, 2013 at 7:55 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>
> wrote:
>>
>>
>> On Mar 26, 2013, at 1:29 AM, Oliver Hunt wrote:
>>
>>
>> Ok, I'll try to go over this again, because for whatever reason it doesn't
>> appear to stick:
>>
>> If you have a double-typed array, and access a member:
>> typedArray[0]
>>
>> Then in ES it is a double that can be one of these values: +Infinitity,
>> -Infinity, NaN, or a discrete value representable in IEEE double spec.
>> There are no signaling NaNs, nor is there any exposure of what the
>> underlying bit pattern of the NaN is.
>>
>> So the runtime loads this double, and then stores it somewhere, anywhere,
>> it doesn't matter where, eg.
>> var tmp = typedArray[0];
>>
>> Now you store it:
>> typedArray[whatever] = tmp;
>>
>> The specification must allow a bitwise comparison of typedArray[whatever]
>> to typedArray[0] to return false, as it is not possible for any NaN-boxing
>> engine to maintain the bit equality that you would otherwise desire, as that
>> would be trivially exploitable. When I say security and correctness i mean
>> it in the "can't be remotely pwned" sense.
>>
>> Given that we can't guarantee that the bit pattern will remain unchanged
>> the spec should mandate normalizing to the non-signalling NaN.
>>
>> --Oliver
>>
>>
>> Oliver,
>>
>> Let's look at actual ES6 spec. language and see if there is actually
>> anything you would like to see changed. The encoding of NaNs is only
>> discussed in three places:
>>
>> Section 8.1.5, first paragraph says:
>>
>> The Number type has exactly 18437736874454810627 (that is, 264253+3)
>> values, representing the double-precision 64-bit format IEEE 754 values as
>> specified in the IEEE Standard for Binary Floating-Point Arithmetic, except
>> that the 9007199254740990 (that is, 2532) distinct “Not-a-Number” values of
>> the IEEE Standard are represented in ECMAScript as a single special NaN
>> value. (Note that the NaN value is produced by the program expression NaN.)
>> In some implementations, external code might be able to detect a difference
>> between various Not-a-Number values, but such behaviour is
>> implementation-dependent; to ECMAScript code, all NaN values are
>> indistinguishable from each other.
>>
>> This is very old text, most of which dates to ES1. It is defining the ES
>> Number type, which is an abstraction, not an actual bit-level encoding. To
>> me it say these things:
>> 1) Unlike the the IEEE 64-bit floating point type. The ES Number type
>> has only a single NaN value.
>> 2) An implementations are free to internally encode the Number type any
>> why it desires (as long is it observably conforms to all the requirements of
>> section 8.1.5).
>> 3) In particular, an implementation might have multiple internal bit
>> patterns all of which correspond to the single NaN element of the Number
>> type.
>> 4) A corollary of 3) is that implementation are not required to
>> internally canonicalize NaNs, that is an implementation level design
>> decision.
>> 5) Implementations are not required to canonicalize NaNs when they are
>> passed or otherwise made visible to non-ES code. Hence such code may be
>> able to observe details of the NaN encoding, including whether or not a
>> canonical NaN value is used internally by the ES implementation.
>>
>> Is there anything you think should change in the above specification text?
>>
>> Section 15.13.5.1.3 defines the GetValueFromBuffer abstraction operation
>> which is currently the only place in the ES6 spec. where a ES Number value
>> is retrieved from an ArrayBuffer. Step 8 of the specification algorithm is:
>>
>> 8 If type is “Float64” , then
>>
>> rawValue is interpreted, taking into accont the value of isBigEndian, as
>> a bit string encoding of an IEEE 754-208 binary64 value.
>> If rawValue is any an IEEE 754-208 binary64 NaN value, return the NaN
>> Number value.
>> Return the Number value that is encoded by rawValue.
>>
>> Step 7 is similar but deals with Float32 values.
>>
>> To me it say these things:
>> 1) In all cases, an ES Number value (as defined in 8.1.5) is returned.
>> 2) All IEEE NaN values are logically canonicalized as the single ES NaN
>> value.
>> 3) No additional requirements for ES Numbers, beyond those in 8.1.5 are
>> introduced. Actual representation remains up to implementation.
>>
>> Should anything change? If 8.1.5 continues to not mandate any particular
>> or single encoding representation of a NaN, I don't see why this should
>> either.
>>
>> Section 15.13.5.1.4 defines the SetValueInBuffer abstraction operation
>> which is currently the only place in the ES6 spec. where a ES Number value
>> is stored into a ArrayBuffer. Step 8 of the specification algorithm is:
>>
>> 8. Else, if type is “Float64” , then
>>
>> Set rawValue to the 8 bytes that are the IEEE-868-2005 binary64 format
>> encoding of value. If isBigEndian is true, the bytes are arranged in big
>> endian order. Otherwise, the bytes are arranged in little endian order. If
>> value is NaN, rawValue is may be set to any implementation choosen
>> non-signaling NaN encoding.
>>
>> Step 7 is similar but deals with Float32 values.
>>
>> To me it say these things:
>> 1) When storing into an ArrayBuffer, canonicalization of ES NaN to some
>> particular IEEE NaN is permitted but not required.
>> 2) The actual ArrayBuffer bit-level representation of NaN values is
>> completely implementation dependent. It need not even be consistent across
>> multiple stores. .
>> 3) External observers of such a stored value may be able to detect NaN
>> encoding differences by observing Numbers stored into ArrayBuffers. This is
>> allowed by 8.1.5
>> 4) The actual encoding of a NaN value in an ArrayBuffer is observable
>> by ES code by overly a non-float typed Array on an ArrayBuffer where a
>> Number has been stored using the above steps.
>>
>> Point 4 seems to be in conflict with the 8.1.5 requirement "to ECMAScript
>> code, all NaN values are indistinguishable from each other.". However,
>> consider that what is being observed is not directly an ES Number NaN value
>> but instead a bit pattern that according to15.13.5.1.4 above may not be a
>> direct reflection of the Number NaN that was stored. So maybe it slips by.
>>
>> So, again any change requests?
>>
>> From a spec. perspective we could require canonicalization to some
>> specific IEEE NaN (how do we pick one?) in 15.13.5.4. If we are going to do
>> that, we presumably also should require canonicalization of endian-ness
>> which is also observable and arguably a bigger interop hazard than NaNs.
>> However, I think the performance arguments for not canonicalizing
>> endian-ness in typed array are stronger. If we are going to continue to
>> let endian-ness be implementation determined then I don't think there is
>> much point in worrying about changing the the handling of NaNs in
>> 15.13.5.1.4. But, I'm flexible.
>>
>> Allen
>>
>>
>>
>>
>>
>>
>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
More information about the es-discuss
mailing list