// Identical objects can be compared fast, but there are some tricky cases
// for NaN and undefined.
+ Label generic_heap_number_comparison;
{
Label not_identical;
__ cmp(eax, edx);
__ bind(&check_for_nan);
}
- // Test for NaN. Sadly, we can't just compare to factory->nan_value(),
- // so we do the second best thing - test it ourselves.
- Label heap_number;
+ // Test for NaN. Compare heap numbers in a general way,
+ // to hanlde NaNs correctly.
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
Immediate(masm->isolate()->factory()->heap_number_map()));
- __ j(equal, &heap_number, Label::kNear);
+ __ j(equal, &generic_heap_number_comparison, Label::kNear);
if (cc != equal) {
// Call runtime on identical JSObjects. Otherwise return equal.
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
__ Set(eax, Immediate(Smi::FromInt(EQUAL)));
__ ret(0);
- __ bind(&heap_number);
- // It is a heap number, so return non-equal if it's NaN and equal if
- // it's not NaN.
- // The representation of NaN values has all exponent bits (52..62) set,
- // and not all mantissa bits (0..51) clear.
- // We only accept QNaNs, which have bit 51 set.
- // Read top bits of double representation (second word of value).
-
- // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e.,
- // all bits in the mask are set. We only need to check the word
- // that contains the exponent and high bit of the mantissa.
- STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0);
- __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset));
- __ Set(eax, Immediate(0));
- // Shift value and mask so kQuietNaNHighBitsMask applies to topmost
- // bits.
- __ add(edx, edx);
- __ cmp(edx, kQuietNaNHighBitsMask << 1);
- if (cc == equal) {
- STATIC_ASSERT(EQUAL != 1);
- __ setcc(above_equal, eax);
- __ ret(0);
- } else {
- Label nan;
- __ j(above_equal, &nan, Label::kNear);
- __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
- __ ret(0);
- __ bind(&nan);
- __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
- __ ret(0);
- }
__ bind(¬_identical);
}
// Generate the number comparison code.
Label non_number_comparison;
Label unordered;
+ __ bind(&generic_heap_number_comparison);
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope use_sse2(masm, SSE2);
CpuFeatureScope use_cmov(masm, CMOV);
--- /dev/null
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+
+// Test that both kinds of NaNs (signaling or quiet) do not signal
+
+function TestAllModes(f) {
+ f(); // Runtime
+ f(); // IC
+ f(); // IC second time
+ %OptimizeFunctionOnNextCall(f);
+ f(); // hydrogen
+}
+
+function TestDoubleSignalingNan() {
+ // NaN with signal bit set
+ function f() {
+ var bytes = new Uint32Array([1, 0x7FF00000]);
+ var doubles = new Float64Array(bytes.buffer);
+ assertTrue(isNaN(doubles[0]));
+ assertTrue(isNaN(doubles[0]*2.0));
+ assertTrue(isNaN(doubles[0] + 0.5));
+ }
+
+ TestAllModes(f);
+}
+
+TestDoubleSignalingNan();
+
+function TestDoubleQuietNan() {
+ // NaN with signal bit cleared
+ function f() {
+ var bytes = new Uint32Array([0, 0x7FF80000]);
+ var doubles = new Float64Array(bytes.buffer);
+ assertTrue(isNaN(doubles[0]));
+ assertTrue(isNaN(doubles[0]*2.0));
+ assertTrue(isNaN(doubles[0] + 0.5));
+ }
+
+ TestAllModes(f);
+}
+
+TestDoubleQuietNan();
+
+function TestFloatSignalingNan() {
+ // NaN with signal bit set
+ function f() {
+ var bytes = new Uint32Array([0x7F800001]);
+ var floats = new Float32Array(bytes.buffer);
+ assertTrue(isNaN(floats[0]));
+ assertTrue(isNaN(floats[0]*2.0));
+ assertTrue(isNaN(floats[0] + 0.5));
+ }
+
+ TestAllModes(f);
+}
+
+TestFloatSignalingNan();
+
+function TestFloatQuietNan() {
+ // NaN with signal bit cleared
+ function f() {
+ var bytes = new Uint32Array([0x7FC00000]);
+ var floats = new Float32Array(bytes.buffer);
+ assertTrue(isNaN(floats[0]));
+ assertTrue(isNaN(floats[0]*2.0));
+ assertTrue(isNaN(floats[0] + 0.5));
+ }
+
+ TestAllModes(f);
+}
+
+TestFloatQuietNan();
+
+
+
+