If a HeapNumber is the incoming value, it must be converted to Smi before
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 3 Nov 2008 13:33:13 +0000 (13:33 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 3 Nov 2008 13:33:13 +0000 (13:33 +0000)
checking. This is not done in a fast way.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@679 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/codegen-arm.cc
src/codegen-ia32.cc
src/runtime.cc
src/runtime.h
test/mjsunit/regress/regress-137.js [new file with mode: 0644]
test/mjsunit/switch.js

index 35522b19adb71c5f49637acd2a772f3f031d6adb..5bf0637ca13a07173dbec83ebf1f032742151e16 100644 (file)
@@ -1247,6 +1247,19 @@ void CodeGenerator::GenerateFastCaseSwitchJumpTable(
   ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
 
   __ pop(r0);
+
+  // Test for a Smi value in a HeapNumber.
+  Label is_smi;
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &is_smi);
+  __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag));
+  __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag));
+  __ cmp(r1, Operand(HEAP_NUMBER_TYPE));
+  __ b(ne, fail_label);
+  __ push(r0);
+  __ CallRuntime(Runtime::kNumberToSmi, 1);
+  __ bind(&is_smi);
+
   if (min_index != 0) {
     // small positive numbers can be immediate operands.
     if (min_index < 0) {
index eaac989061443e469179a1fedc4448e2f0d753b6..cac0f44871ea55dc58c3fc0a82e1b9e49efdf557 100644 (file)
@@ -1623,9 +1623,24 @@ void CodeGenerator::GenerateFastCaseSwitchJumpTable(
   // placeholders, and fill in the addresses after the labels have been
   // bound.
 
-  frame_->Pop(eax);  // supposed smi
+  frame_->Pop(eax);  // supposed Smi
   // check range of value, if outside [0..length-1] jump to default/end label.
   ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+
+  // Test whether input is a HeapNumber that is really a Smi
+  Label is_smi;
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(equal, &is_smi);
+  // It's a heap object, not a Smi or a Failure
+  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+  __ cmp(ebx, HEAP_NUMBER_TYPE);
+  __ j(not_equal, fail_label);
+  // eax points to a heap number.
+  __ push(eax);
+  __ CallRuntime(Runtime::kNumberToSmi, 1);
+  __ bind(&is_smi);
+
   if (min_index != 0) {
     __ sub(Operand(eax), Immediate(min_index << kSmiTagSize));
   }
index 6d9f2a3bed710b8ff7904f63a95a634838883584..1949cc44a3ec55e6867afb5b2127931b2381ed3b 100644 (file)
@@ -2587,6 +2587,26 @@ static Object* Runtime_NumberToJSInt32(Arguments args) {
 }
 
 
+// Converts a Number to a Smi, if possible. Returns NaN if the number is not
+// a small integer.
+static Object* Runtime_NumberToSmi(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  Object* obj = args[0];
+  if (obj->IsSmi()) {
+    return obj;
+  }
+  if (obj->IsHeapNumber()) {
+    double value = HeapNumber::cast(obj)->value();
+    int int_value = FastD2I(value);
+    if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
+      return Smi::FromInt(int_value);
+    }
+  }
+  return Heap::nan_value();
+}
+
 static Object* Runtime_NumberAdd(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 2);
index f546231a6f04506abeef6cd7fe1b2a6a1012577a..36a7180eb28711d6e1916b9acf8541d4449b0690 100644 (file)
@@ -84,6 +84,7 @@ namespace v8 { namespace internal {
   F(NumberToInteger, 1) \
   F(NumberToJSUint32, 1) \
   F(NumberToJSInt32, 1) \
+  F(NumberToSmi, 1) \
   \
   /* Arithmetic operations */ \
   F(NumberAdd, 2) \
diff --git a/test/mjsunit/regress/regress-137.js b/test/mjsunit/regress/regress-137.js
new file mode 100644 (file)
index 0000000..cc7b68c
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2008 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.
+
+// See <URL:http://code.google.com/p/v8/issues/detail?id=137>
+
+(function () {
+  var strNum = 170;
+  var base = strNum / 16;
+  var rem = strNum % 16;
+  var base = base - (rem / 16);  // base is now HeapNumber with valid Smi value.
+
+  switch(base) {
+    case 10: return "A";  // Expected result.
+    case 11: return "B";
+    case 12: return "C";
+    case 13: return "D";
+    case 14: return "E";
+    case 15: return "F";  // Enough cases to trigger fast-case Smi switch.
+  };
+  fail("case 10", "Default case", "Heap number not recognized as Smi value");
+})();
+
index ae5ce2bdcdad80afd1503496b849906e3638eb2b..821a4f30f721f3446bcedf30d8b5825cccb142ab 100644 (file)
@@ -224,4 +224,46 @@ assertEquals(2016, f6(64), "largeSwitch.64");
 assertEquals(4032, f6(128), "largeSwitch.128");
 assertEquals(4222, f6(148), "largeSwitch.148"); 
  
+
+function f7(value) {
+  switch (value) {
+  case 0: return "0";
+  case -0: return "-0";
+  case 1: case 2: case 3: case 4:  // Dummy fillers.
+  }
+  switch (value) {
+  case 0x3fffffff: return "MaxSmi";
+  case 0x3ffffffe:
+  case 0x3ffffffd:
+  case 0x3ffffffc:
+  case 0x3ffffffb:
+  case 0x3ffffffa:  // Dummy fillers
+  }
+  switch (value) {
+  case -0x40000000: return "MinSmi";
+  case -0x3fffffff:
+  case -0x3ffffffe:
+  case -0x3ffffffd:
+  case -0x3ffffffc:
+  case -0x3ffffffb:  // Dummy fillers
+  }
+  switch (value) {
+  case 10: return "A";
+  case 11:
+  case 12:
+  case 13:
+  case 14: 
+  case 15:  // Dummy fillers
+  }
+  return "default";
+}
+
+
+assertEquals("default", f7(0.1), "0-1-switch.double-0.1");
+assertEquals("0", f7(-0), "0-1-switch.double-neg0");
+assertEquals("MaxSmi", f7((1<<30)-1), "0-1-switch.maxsmi");
+assertEquals("MinSmi", f7(-(1<<30)), "0-1-switch.minsmi");
+assertEquals("default", f7(1<<30), "0-1-switch.maxsmi++");
+assertEquals("default", f7(-(1<<30)-1), "0-1-switch.minsmi--");
+assertEquals("A", f7((170/16)-(170%16/16)), "0-1-switch.heapnum");
+