Lattice-based representation inference, powered by left/right specific type feedback...
authorjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 14 Nov 2012 15:59:45 +0000 (15:59 +0000)
committerjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 14 Nov 2012 15:59:45 +0000 (15:59 +0000)
Review URL: https://chromiumcodereview.appspot.com/10837165

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

41 files changed:
src/arm/code-stubs-arm.cc
src/arm/code-stubs-arm.h
src/arm/full-codegen-arm.cc
src/arm/ic-arm.cc
src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/ast.cc
src/ast.h
src/code-stubs.cc
src/code-stubs.h
src/date.js
src/heap.cc
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/hydrogen.h
src/ia32/code-stubs-ia32.cc
src/ia32/code-stubs-ia32.h
src/ia32/full-codegen-ia32.cc
src/ia32/ic-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/ic.cc
src/ic.h
src/objects-inl.h
src/objects.cc
src/objects.h
src/profile-generator.cc
src/type-info.cc
src/type-info.h
src/x64/code-stubs-x64.cc
src/x64/code-stubs-x64.h
src/x64/full-codegen-x64.cc
src/x64/ic-x64.cc
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h
test/cctest/test-api.cc
test/mjsunit/math-floor-of-div-minus-zero.js

index 1e73a55871606f4ce7b2708b856ef6e2e9a3f9d8..4e3170eb943331e0323e76041139f5ff3392de9b 100644 (file)
@@ -41,8 +41,7 @@ namespace internal {
 
 static void EmitIdenticalObjectComparison(MacroAssembler* masm,
                                           Label* slow,
-                                          Condition cond,
-                                          bool never_nan_nan);
+                                          Condition cond);
 static void EmitSmiNonsmiComparison(MacroAssembler* masm,
                                     Register lhs,
                                     Register rhs,
@@ -627,24 +626,6 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
 }
 
 
-void FloatingPointHelper::LoadOperands(
-    MacroAssembler* masm,
-    FloatingPointHelper::Destination destination,
-    Register heap_number_map,
-    Register scratch1,
-    Register scratch2,
-    Label* slow) {
-
-  // Load right operand (r0) to d6 or r2/r3.
-  LoadNumber(masm, destination,
-             r0, d7, r2, r3, heap_number_map, scratch1, scratch2, slow);
-
-  // Load left operand (r1) to d7 or r0/r1.
-  LoadNumber(masm, destination,
-             r1, d6, r0, r1, heap_number_map, scratch1, scratch2, slow);
-}
-
-
 void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
                                      Destination destination,
                                      Register object,
@@ -910,14 +891,15 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
          !scratch1.is(scratch3) &&
          !scratch2.is(scratch3));
 
-  Label done;
+  Label done, maybe_undefined;
 
   __ UntagAndJumpIfSmi(dst, object, &done);
 
   __ AssertRootValue(heap_number_map,
                      Heap::kHeapNumberMapRootIndex,
                      "HeapNumberMap register clobbered.");
-  __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
+
+  __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, &maybe_undefined);
 
   // Object is a heap number.
   // Convert the floating point value to a 32-bit integer.
@@ -964,6 +946,14 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
     __ tst(scratch1, Operand(HeapNumber::kSignMask));
     __ rsb(dst, dst, Operand::Zero(), LeaveCC, mi);
   }
+  __ b(&done);
+
+  __ bind(&maybe_undefined);
+  __ CompareRoot(object, Heap::kUndefinedValueRootIndex);
+  __ b(ne, not_int32);
+  // |undefined| is truncated to 0.
+  __ mov(dst, Operand(Smi::FromInt(0)));
+  // Fall through.
 
   __ bind(&done);
 }
@@ -1148,48 +1138,43 @@ void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
 // for "identity and not NaN".
 static void EmitIdenticalObjectComparison(MacroAssembler* masm,
                                           Label* slow,
-                                          Condition cond,
-                                          bool never_nan_nan) {
+                                          Condition cond) {
   Label not_identical;
   Label heap_number, return_equal;
   __ cmp(r0, r1);
   __ b(ne, &not_identical);
 
-  // The two objects are identical.  If we know that one of them isn't NaN then
-  // we now know they test equal.
-  if (cond != eq || !never_nan_nan) {
-    // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(),
-    // so we do the second best thing - test it ourselves.
-    // They are both equal and they are not both Smis so both of them are not
-    // Smis.  If it's not a heap number, then return equal.
-    if (cond == lt || cond == gt) {
-      __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE);
+  // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(),
+  // so we do the second best thing - test it ourselves.
+  // They are both equal and they are not both Smis so both of them are not
+  // Smis.  If it's not a heap number, then return equal.
+  if (cond == lt || cond == gt) {
+    __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE);
+    __ b(ge, slow);
+  } else {
+    __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
+    __ b(eq, &heap_number);
+    // Comparing JS objects with <=, >= is complicated.
+    if (cond != eq) {
+      __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE));
       __ b(ge, slow);
-    } else {
-      __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
-      __ b(eq, &heap_number);
-      // Comparing JS objects with <=, >= is complicated.
-      if (cond != eq) {
-        __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE));
-        __ b(ge, slow);
-        // Normally here we fall through to return_equal, but undefined is
-        // special: (undefined == undefined) == true, but
-        // (undefined <= undefined) == false!  See ECMAScript 11.8.5.
-        if (cond == le || cond == ge) {
-          __ cmp(r4, Operand(ODDBALL_TYPE));
-          __ b(ne, &return_equal);
-          __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
-          __ cmp(r0, r2);
-          __ b(ne, &return_equal);
-          if (cond == le) {
-            // undefined <= undefined should fail.
-            __ mov(r0, Operand(GREATER));
-          } else  {
-            // undefined >= undefined should fail.
-            __ mov(r0, Operand(LESS));
-          }
-          __ Ret();
+      // Normally here we fall through to return_equal, but undefined is
+      // special: (undefined == undefined) == true, but
+      // (undefined <= undefined) == false!  See ECMAScript 11.8.5.
+      if (cond == le || cond == ge) {
+        __ cmp(r4, Operand(ODDBALL_TYPE));
+        __ b(ne, &return_equal);
+        __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
+        __ cmp(r0, r2);
+        __ b(ne, &return_equal);
+        if (cond == le) {
+          // undefined <= undefined should fail.
+          __ mov(r0, Operand(GREATER));
+        } else  {
+          // undefined >= undefined should fail.
+          __ mov(r0, Operand(LESS));
         }
+        __ Ret();
       }
     }
   }
@@ -1204,47 +1189,45 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm,
   }
   __ Ret();
 
-  if (cond != eq || !never_nan_nan) {
-    // For less and greater we don't have to check for NaN since the result of
-    // x < x is false regardless.  For the others here is some code to check
-    // for NaN.
-    if (cond != lt && cond != gt) {
-      __ 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.
-      // Read top bits of double representation (second word of value).
-      __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
-      // Test that exponent bits are all set.
-      __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
-      // NaNs have all-one exponents so they sign extend to -1.
-      __ cmp(r3, Operand(-1));
-      __ b(ne, &return_equal);
-
-      // Shift out flag and all exponent bits, retaining only mantissa.
-      __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord));
-      // Or with all low-bits of mantissa.
-      __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
-      __ orr(r0, r3, Operand(r2), SetCC);
-      // For equal we already have the right value in r0:  Return zero (equal)
-      // if all bits in mantissa are zero (it's an Infinity) and non-zero if
-      // not (it's a NaN).  For <= and >= we need to load r0 with the failing
-      // value if it's a NaN.
-      if (cond != eq) {
-        // All-zero means Infinity means equal.
-        __ Ret(eq);
-        if (cond == le) {
-          __ mov(r0, Operand(GREATER));  // NaN <= NaN should fail.
-        } else {
-          __ mov(r0, Operand(LESS));     // NaN >= NaN should fail.
-        }
+  // For less and greater we don't have to check for NaN since the result of
+  // x < x is false regardless.  For the others here is some code to check
+  // for NaN.
+  if (cond != lt && cond != gt) {
+    __ 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.
+    // Read top bits of double representation (second word of value).
+    __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
+    // Test that exponent bits are all set.
+    __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
+    // NaNs have all-one exponents so they sign extend to -1.
+    __ cmp(r3, Operand(-1));
+    __ b(ne, &return_equal);
+
+    // Shift out flag and all exponent bits, retaining only mantissa.
+    __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord));
+    // Or with all low-bits of mantissa.
+    __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
+    __ orr(r0, r3, Operand(r2), SetCC);
+    // For equal we already have the right value in r0:  Return zero (equal)
+    // if all bits in mantissa are zero (it's an Infinity) and non-zero if
+    // not (it's a NaN).  For <= and >= we need to load r0 with the failing
+    // value if it's a NaN.
+    if (cond != eq) {
+      // All-zero means Infinity means equal.
+      __ Ret(eq);
+      if (cond == le) {
+        __ mov(r0, Operand(GREATER));  // NaN <= NaN should fail.
+      } else {
+        __ mov(r0, Operand(LESS));     // NaN >= NaN should fail.
       }
-      __ Ret();
     }
-    // No fall through here.
+    __ Ret();
   }
+  // No fall through here.
 
   __ bind(&not_identical);
 }
@@ -1678,42 +1661,60 @@ void NumberToStringStub::Generate(MacroAssembler* masm) {
 }
 
 
-// On entry lhs_ and rhs_ are the values to be compared.
+static void ICCompareStub_CheckInputType(MacroAssembler* masm,
+                                         Register input,
+                                         Register scratch,
+                                         CompareIC::State expected,
+                                         Label* fail) {
+  Label ok;
+  if (expected == CompareIC::SMI) {
+    __ JumpIfNotSmi(input, fail);
+  } else if (expected == CompareIC::HEAP_NUMBER) {
+    __ JumpIfSmi(input, &ok);
+    __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail,
+                DONT_DO_SMI_CHECK);
+  }
+  // We could be strict about symbol/string here, but as long as
+  // hydrogen doesn't care, the stub doesn't have to care either.
+  __ bind(&ok);
+}
+
+
+// On entry r1 and r2 are the values to be compared.
 // On exit r0 is 0, positive or negative to indicate the result of
 // the comparison.
-void CompareStub::Generate(MacroAssembler* masm) {
-  ASSERT((lhs_.is(r0) && rhs_.is(r1)) ||
-         (lhs_.is(r1) && rhs_.is(r0)));
+void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
+  Register lhs = r1;
+  Register rhs = r0;
+  Condition cc = GetCondition();
+
+  Label miss;
+  ICCompareStub_CheckInputType(masm, lhs, r2, left_, &miss);
+  ICCompareStub_CheckInputType(masm, rhs, r3, right_, &miss);
 
   Label slow;  // Call builtin.
   Label not_smis, both_loaded_as_doubles, lhs_not_nan;
 
-  if (include_smi_compare_) {
-    Label not_two_smis, smi_done;
-    __ orr(r2, r1, r0);
-    __ JumpIfNotSmi(r2, &not_two_smis);
-    __ mov(r1, Operand(r1, ASR, 1));
-    __ sub(r0, r1, Operand(r0, ASR, 1));
-    __ Ret();
-    __ bind(&not_two_smis);
-  } else if (FLAG_debug_code) {
-    __ orr(r2, r1, r0);
-    __ tst(r2, Operand(kSmiTagMask));
-    __ Assert(ne, "CompareStub: unexpected smi operands.");
-  }
+  Label not_two_smis, smi_done;
+  __ orr(r2, r1, r0);
+  __ JumpIfNotSmi(r2, &not_two_smis);
+  __ mov(r1, Operand(r1, ASR, 1));
+  __ sub(r0, r1, Operand(r0, ASR, 1));
+  __ Ret();
+  __ bind(&not_two_smis);
 
   // NOTICE! This code is only reached after a smi-fast-case check, so
   // it is certain that at least one operand isn't a smi.
 
   // Handle the case where the objects are identical.  Either returns the answer
   // or goes to slow.  Only falls through if the objects were not identical.
-  EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
+  EmitIdenticalObjectComparison(masm, &slow, cc);
 
   // If either is a Smi (we know that not both are), then they can only
   // be strictly equal if the other is a HeapNumber.
   STATIC_ASSERT(kSmiTag == 0);
   ASSERT_EQ(0, Smi::FromInt(0));
-  __ and_(r2, lhs_, Operand(rhs_));
+  __ and_(r2, lhs, Operand(rhs));
   __ JumpIfNotSmi(r2, &not_smis);
   // One operand is a smi.  EmitSmiNonsmiComparison generates code that can:
   // 1) Return the answer.
@@ -1724,7 +1725,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
   // comparison.  If VFP3 is supported the double values of the numbers have
   // been loaded into d7 and d6.  Otherwise, the double values have been loaded
   // into r0, r1, r2, and r3.
-  EmitSmiNonsmiComparison(masm, lhs_, rhs_, &lhs_not_nan, &slow, strict_);
+  EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict());
 
   __ bind(&both_loaded_as_doubles);
   // The arguments have been converted to doubles and stored in d6 and d7, if
@@ -1747,7 +1748,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
     // If one of the sides was a NaN then the v flag is set.  Load r0 with
     // whatever it takes to make the comparison fail, since comparisons with NaN
     // always fail.
-    if (cc_ == lt || cc_ == le) {
+    if (cc == lt || cc == le) {
       __ mov(r0, Operand(GREATER));
     } else {
       __ mov(r0, Operand(LESS));
@@ -1756,19 +1757,19 @@ void CompareStub::Generate(MacroAssembler* masm) {
   } else {
     // Checks for NaN in the doubles we have loaded.  Can return the answer or
     // fall through if neither is a NaN.  Also binds lhs_not_nan.
-    EmitNanCheck(masm, &lhs_not_nan, cc_);
+    EmitNanCheck(masm, &lhs_not_nan, cc);
     // Compares two doubles in r0, r1, r2, r3 that are not NaNs.  Returns the
     // answer.  Never falls through.
-    EmitTwoNonNanDoubleComparison(masm, cc_);
+    EmitTwoNonNanDoubleComparison(masm, cc);
   }
 
   __ bind(&not_smis);
   // At this point we know we are dealing with two different objects,
   // and neither of them is a Smi.  The objects are in rhs_ and lhs_.
-  if (strict_) {
+  if (strict()) {
     // This returns non-equal for some object types, or falls through if it
     // was not lucky.
-    EmitStrictTwoHeapObjectCompare(masm, lhs_, rhs_);
+    EmitStrictTwoHeapObjectCompare(masm, lhs, rhs);
   }
 
   Label check_for_symbols;
@@ -1778,8 +1779,8 @@ void CompareStub::Generate(MacroAssembler* masm) {
   // that case.  If the inputs are not doubles then jumps to check_for_symbols.
   // In this case r2 will contain the type of rhs_.  Never falls through.
   EmitCheckForTwoHeapNumbers(masm,
-                             lhs_,
-                             rhs_,
+                             lhs,
+                             rhs,
                              &both_loaded_as_doubles,
                              &check_for_symbols,
                              &flat_string_check);
@@ -1787,31 +1788,31 @@ void CompareStub::Generate(MacroAssembler* masm) {
   __ bind(&check_for_symbols);
   // In the strict case the EmitStrictTwoHeapObjectCompare already took care of
   // symbols.
-  if (cc_ == eq && !strict_) {
+  if (cc == eq && !strict()) {
     // Returns an answer for two symbols or two detectable objects.
     // Otherwise jumps to string case or not both strings case.
     // Assumes that r2 is the type of rhs_ on entry.
-    EmitCheckForSymbolsOrObjects(masm, lhs_, rhs_, &flat_string_check, &slow);
+    EmitCheckForSymbolsOrObjects(masm, lhs, rhs, &flat_string_check, &slow);
   }
 
   // Check for both being sequential ASCII strings, and inline if that is the
   // case.
   __ bind(&flat_string_check);
 
-  __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, r2, r3, &slow);
+  __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs, rhs, r2, r3, &slow);
 
   __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3);
-  if (cc_ == eq) {
+  if (cc == eq) {
     StringCompareStub::GenerateFlatAsciiStringEquals(masm,
-                                                     lhs_,
-                                                     rhs_,
+                                                     lhs,
+                                                     rhs,
                                                      r2,
                                                      r3,
                                                      r4);
   } else {
     StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
-                                                       lhs_,
-                                                       rhs_,
+                                                       lhs,
+                                                       rhs,
                                                        r2,
                                                        r3,
                                                        r4,
@@ -1821,18 +1822,18 @@ void CompareStub::Generate(MacroAssembler* masm) {
 
   __ bind(&slow);
 
-  __ Push(lhs_, rhs_);
+  __ Push(lhs, rhs);
   // Figure out which native to call and setup the arguments.
   Builtins::JavaScript native;
-  if (cc_ == eq) {
-    native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  if (cc == eq) {
+    native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
   } else {
     native = Builtins::COMPARE;
     int ncr;  // NaN compare result
-    if (cc_ == lt || cc_ == le) {
+    if (cc == lt || cc == le) {
       ncr = GREATER;
     } else {
-      ASSERT(cc_ == gt || cc_ == ge);  // remaining cases
+      ASSERT(cc == gt || cc == ge);  // remaining cases
       ncr = LESS;
     }
     __ mov(r0, Operand(Smi::FromInt(ncr)));
@@ -1842,6 +1843,9 @@ void CompareStub::Generate(MacroAssembler* masm) {
   // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
   __ InvokeBuiltin(native, JUMP_FUNCTION);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
 }
 
 
@@ -2325,20 +2329,23 @@ void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
 }
 
 
+void BinaryOpStub::Initialize() {
+  platform_specific_bit_ = CpuFeatures::IsSupported(VFP2);
+}
+
+
 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
   Label get_result;
 
   __ Push(r1, r0);
 
   __ mov(r2, Operand(Smi::FromInt(MinorKey())));
-  __ mov(r1, Operand(Smi::FromInt(op_)));
-  __ mov(r0, Operand(Smi::FromInt(operands_type_)));
-  __ Push(r2, r1, r0);
+  __ push(r2);
 
   __ TailCallExternalReference(
       ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
                         masm->isolate()),
-      5,
+      3,
       1);
 }
 
@@ -2349,59 +2356,8 @@ void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(
 }
 
 
-void BinaryOpStub::Generate(MacroAssembler* masm) {
-  // Explicitly allow generation of nested stubs. It is safe here because
-  // generation code does not use any raw pointers.
-  AllowStubCallsScope allow_stub_calls(masm, true);
-
-  switch (operands_type_) {
-    case BinaryOpIC::UNINITIALIZED:
-      GenerateTypeTransition(masm);
-      break;
-    case BinaryOpIC::SMI:
-      GenerateSmiStub(masm);
-      break;
-    case BinaryOpIC::INT32:
-      GenerateInt32Stub(masm);
-      break;
-    case BinaryOpIC::HEAP_NUMBER:
-      GenerateHeapNumberStub(masm);
-      break;
-    case BinaryOpIC::ODDBALL:
-      GenerateOddballStub(masm);
-      break;
-    case BinaryOpIC::BOTH_STRING:
-      GenerateBothStringStub(masm);
-      break;
-    case BinaryOpIC::STRING:
-      GenerateStringStub(masm);
-      break;
-    case BinaryOpIC::GENERIC:
-      GenerateGeneric(masm);
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
-
-void BinaryOpStub::PrintName(StringStream* stream) {
-  const char* op_name = Token::Name(op_);
-  const char* overwrite_name;
-  switch (mode_) {
-    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
-    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
-    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
-    default: overwrite_name = "UnknownOverwrite"; break;
-  }
-  stream->Add("BinaryOpStub_%s_%s_%s",
-              op_name,
-              overwrite_name,
-              BinaryOpIC::GetName(operands_type_));
-}
-
-
-void BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) {
+void BinaryOpStub_GenerateSmiSmiOperation(MacroAssembler* masm,
+                                          Token::Value op) {
   Register left = r1;
   Register right = r0;
   Register scratch1 = r7;
@@ -2411,7 +2367,7 @@ void BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) {
   STATIC_ASSERT(kSmiTag == 0);
 
   Label not_smi_result;
-  switch (op_) {
+  switch (op) {
     case Token::ADD:
       __ add(right, left, Operand(right), SetCC);  // Add optimistically.
       __ Ret(vc);
@@ -2526,10 +2482,24 @@ void BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) {
 }
 
 
-void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
-                                       bool smi_operands,
-                                       Label* not_numbers,
-                                       Label* gc_required) {
+void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
+                                               Register result,
+                                               Register heap_number_map,
+                                               Register scratch1,
+                                               Register scratch2,
+                                               Label* gc_required,
+                                               OverwriteMode mode);
+
+
+void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
+                                      BinaryOpIC::TypeInfo left_type,
+                                      BinaryOpIC::TypeInfo right_type,
+                                      bool smi_operands,
+                                      Label* not_numbers,
+                                      Label* gc_required,
+                                      Label* miss,
+                                      Token::Value op,
+                                      OverwriteMode mode) {
   Register left = r1;
   Register right = r0;
   Register scratch1 = r7;
@@ -2541,11 +2511,17 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
     __ AssertSmi(left);
     __ AssertSmi(right);
   }
+  if (left_type == BinaryOpIC::SMI) {
+    __ JumpIfNotSmi(left, miss);
+  }
+  if (right_type == BinaryOpIC::SMI) {
+    __ JumpIfNotSmi(right, miss);
+  }
 
   Register heap_number_map = r6;
   __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
 
-  switch (op_) {
+  switch (op) {
     case Token::ADD:
     case Token::SUB:
     case Token::MUL:
@@ -2555,25 +2531,44 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
       // depending on whether VFP3 is available or not.
       FloatingPointHelper::Destination destination =
           CpuFeatures::IsSupported(VFP2) &&
-          op_ != Token::MOD ?
+          op != Token::MOD ?
           FloatingPointHelper::kVFPRegisters :
           FloatingPointHelper::kCoreRegisters;
 
       // Allocate new heap number for result.
       Register result = r5;
-      GenerateHeapResultAllocation(
-          masm, result, heap_number_map, scratch1, scratch2, gc_required);
+      BinaryOpStub_GenerateHeapResultAllocation(
+          masm, result, heap_number_map, scratch1, scratch2, gc_required, mode);
 
       // Load the operands.
       if (smi_operands) {
         FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2);
       } else {
-        FloatingPointHelper::LoadOperands(masm,
-                                          destination,
-                                          heap_number_map,
-                                          scratch1,
-                                          scratch2,
-                                          not_numbers);
+        // Load right operand to d7 or r2/r3.
+        if (right_type == BinaryOpIC::INT32) {
+          FloatingPointHelper::LoadNumberAsInt32Double(
+              masm, right, destination, d7, d8, r2, r3, heap_number_map,
+              scratch1, scratch2, s0, miss);
+        } else {
+          Label* fail = (right_type == BinaryOpIC::HEAP_NUMBER) ? miss
+                                                                : not_numbers;
+          FloatingPointHelper::LoadNumber(
+              masm, destination, right, d7, r2, r3, heap_number_map,
+              scratch1, scratch2, fail);
+        }
+        // Load left operand to d6 or r0/r1. This keeps r0/r1 intact if it
+        // jumps to |miss|.
+        if (left_type == BinaryOpIC::INT32) {
+          FloatingPointHelper::LoadNumberAsInt32Double(
+              masm, left, destination, d6, d8, r0, r1, heap_number_map,
+              scratch1, scratch2, s0, miss);
+        } else {
+          Label* fail = (left_type == BinaryOpIC::HEAP_NUMBER) ? miss
+                                                               : not_numbers;
+          FloatingPointHelper::LoadNumber(
+              masm, destination, left, d6, r0, r1, heap_number_map,
+              scratch1, scratch2, fail);
+        }
       }
 
       // Calculate the result.
@@ -2582,7 +2577,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
         // d6: Left value
         // d7: Right value
         CpuFeatures::Scope scope(VFP2);
-        switch (op_) {
+        switch (op) {
           case Token::ADD:
             __ vadd(d5, d6, d7);
             break;
@@ -2606,7 +2601,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
       } else {
         // Call the C function to handle the double operation.
         FloatingPointHelper::CallCCodeForDoubleOperation(masm,
-                                                         op_,
+                                                         op,
                                                          result,
                                                          scratch1);
         if (FLAG_debug_code) {
@@ -2647,7 +2642,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
       }
 
       Label result_not_a_smi;
-      switch (op_) {
+      switch (op) {
         case Token::BIT_OR:
           __ orr(r2, r3, Operand(r2));
           break;
@@ -2698,8 +2693,9 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
         __ AllocateHeapNumber(
             result, scratch1, scratch2, heap_number_map, gc_required);
       } else {
-        GenerateHeapResultAllocation(
-            masm, result, heap_number_map, scratch1, scratch2, gc_required);
+        BinaryOpStub_GenerateHeapResultAllocation(
+            masm, result, heap_number_map, scratch1, scratch2, gc_required,
+            mode);
       }
 
       // r2: Answer as signed int32.
@@ -2714,7 +2710,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
         // mentioned above SHR needs to always produce a positive result.
         CpuFeatures::Scope scope(VFP2);
         __ vmov(s0, r2);
-        if (op_ == Token::SHR) {
+        if (op == Token::SHR) {
           __ vcvt_f64_u32(d0, s0);
         } else {
           __ vcvt_f64_s32(d0, s0);
@@ -2739,12 +2735,14 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
 // Generate the smi code. If the operation on smis are successful this return is
 // generated. If the result is not a smi and heap number allocation is not
 // requested the code falls through. If number allocation is requested but a
-// heap number cannot be allocated the code jumps to the lable gc_required.
-void BinaryOpStub::GenerateSmiCode(
+// heap number cannot be allocated the code jumps to the label gc_required.
+void BinaryOpStub_GenerateSmiCode(
     MacroAssembler* masm,
     Label* use_runtime,
     Label* gc_required,
-    SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
+    Token::Value op,
+    BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results,
+    OverwriteMode mode) {
   Label not_smis;
 
   Register left = r1;
@@ -2757,12 +2755,14 @@ void BinaryOpStub::GenerateSmiCode(
   __ JumpIfNotSmi(scratch1, &not_smis);
 
   // If the smi-smi operation results in a smi return is generated.
-  GenerateSmiSmiOperation(masm);
+  BinaryOpStub_GenerateSmiSmiOperation(masm, op);
 
   // If heap number results are possible generate the result in an allocated
   // heap number.
-  if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) {
-    GenerateFPOperation(masm, true, use_runtime, gc_required);
+  if (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) {
+    BinaryOpStub_GenerateFPOperation(
+        masm, BinaryOpIC::UNINITIALIZED, BinaryOpIC::UNINITIALIZED, true,
+        use_runtime, gc_required, &not_smis, op, mode);
   }
   __ bind(&not_smis);
 }
@@ -2774,14 +2774,14 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
   if (result_type_ == BinaryOpIC::UNINITIALIZED ||
       result_type_ == BinaryOpIC::SMI) {
     // Only allow smi results.
-    GenerateSmiCode(masm, &call_runtime, NULL, NO_HEAPNUMBER_RESULTS);
+    BinaryOpStub_GenerateSmiCode(
+        masm, &call_runtime, NULL, op_, NO_HEAPNUMBER_RESULTS, mode_);
   } else {
     // Allow heap number result and don't make a transition if a heap number
     // cannot be allocated.
-    GenerateSmiCode(masm,
-                    &call_runtime,
-                    &call_runtime,
-                    ALLOW_HEAPNUMBER_RESULTS);
+    BinaryOpStub_GenerateSmiCode(
+        masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS,
+        mode_);
   }
 
   // Code falls through if the result is not returned as either a smi or heap
@@ -2789,23 +2789,14 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
   GenerateTypeTransition(masm);
 
   __ bind(&call_runtime);
+  GenerateRegisterArgsPush(masm);
   GenerateCallRuntime(masm);
 }
 
 
-void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
-  ASSERT(operands_type_ == BinaryOpIC::STRING);
-  ASSERT(op_ == Token::ADD);
-  // Try to add arguments as strings, otherwise, transition to the generic
-  // BinaryOpIC type.
-  GenerateAddStrings(masm);
-  GenerateTypeTransition(masm);
-}
-
-
 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
   Label call_runtime;
-  ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING);
+  ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING);
   ASSERT(op_ == Token::ADD);
   // If both arguments are strings, call the string add stub.
   // Otherwise, do a transition.
@@ -2834,7 +2825,7 @@ void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
 
 
 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
-  ASSERT(operands_type_ == BinaryOpIC::INT32);
+  ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32);
 
   Register left = r1;
   Register right = r0;
@@ -2856,7 +2847,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
   Label skip;
   __ orr(scratch1, left, right);
   __ JumpIfNotSmi(scratch1, &skip);
-  GenerateSmiSmiOperation(masm);
+  BinaryOpStub_GenerateSmiSmiOperation(masm, op_);
   // Fall through if the result is not a smi.
   __ bind(&skip);
 
@@ -2866,6 +2857,15 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
     case Token::MUL:
     case Token::DIV:
     case Token::MOD: {
+      // It could be that only SMIs have been seen at either the left
+      // or the right operand. For precise type feedback, patch the IC
+      // again if this changes.
+      if (left_type_ == BinaryOpIC::SMI) {
+        __ JumpIfNotSmi(left, &transition);
+      }
+      if (right_type_ == BinaryOpIC::SMI) {
+        __ JumpIfNotSmi(right, &transition);
+      }
       // Load both operands and check that they are 32-bit integer.
       // Jump to type transition if they are not. The registers r0 and r1 (right
       // and left) are preserved for the runtime call.
@@ -2964,12 +2964,13 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
                                                  : BinaryOpIC::INT32)) {
           // We are using vfp registers so r5 is available.
           heap_number_result = r5;
-          GenerateHeapResultAllocation(masm,
-                                       heap_number_result,
-                                       heap_number_map,
-                                       scratch1,
-                                       scratch2,
-                                       &call_runtime);
+          BinaryOpStub_GenerateHeapResultAllocation(masm,
+                                                    heap_number_result,
+                                                    heap_number_map,
+                                                    scratch1,
+                                                    scratch2,
+                                                    &call_runtime,
+                                                    mode_);
           __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
           __ vstr(d5, r0, HeapNumber::kValueOffset);
           __ mov(r0, heap_number_result);
@@ -2988,12 +2989,13 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
 
         // Allocate a heap number to store the result.
         heap_number_result = r5;
-        GenerateHeapResultAllocation(masm,
-                                     heap_number_result,
-                                     heap_number_map,
-                                     scratch1,
-                                     scratch2,
-                                     &pop_and_call_runtime);
+        BinaryOpStub_GenerateHeapResultAllocation(masm,
+                                                  heap_number_result,
+                                                  heap_number_map,
+                                                  scratch1,
+                                                  scratch2,
+                                                  &pop_and_call_runtime,
+                                                  mode_);
 
         // Load the left value from the value saved on the stack.
         __ Pop(r1, r0);
@@ -3098,12 +3100,13 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
 
       __ bind(&return_heap_number);
       heap_number_result = r5;
-      GenerateHeapResultAllocation(masm,
-                                   heap_number_result,
-                                   heap_number_map,
-                                   scratch1,
-                                   scratch2,
-                                   &call_runtime);
+      BinaryOpStub_GenerateHeapResultAllocation(masm,
+                                                heap_number_result,
+                                                heap_number_map,
+                                                scratch1,
+                                                scratch2,
+                                                &call_runtime,
+                                                mode_);
 
       if (CpuFeatures::IsSupported(VFP2)) {
         CpuFeatures::Scope scope(VFP2);
@@ -3147,6 +3150,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
   }
 
   __ bind(&call_runtime);
+  GenerateRegisterArgsPush(masm);
   GenerateCallRuntime(masm);
 }
 
@@ -3185,20 +3189,32 @@ void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
 
 
 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
-  Label call_runtime;
-  GenerateFPOperation(masm, false, &call_runtime, &call_runtime);
+  Label call_runtime, transition;
+  BinaryOpStub_GenerateFPOperation(
+      masm, left_type_, right_type_, false,
+      &transition, &call_runtime, &transition, op_, mode_);
+
+  __ bind(&transition);
+  GenerateTypeTransition(masm);
 
   __ bind(&call_runtime);
+  GenerateRegisterArgsPush(masm);
   GenerateCallRuntime(masm);
 }
 
 
 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
-  Label call_runtime, call_string_add_or_runtime;
+  Label call_runtime, call_string_add_or_runtime, transition;
 
-  GenerateSmiCode(masm, &call_runtime, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
+  BinaryOpStub_GenerateSmiCode(
+      masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS, mode_);
 
-  GenerateFPOperation(masm, false, &call_string_add_or_runtime, &call_runtime);
+  BinaryOpStub_GenerateFPOperation(
+      masm, left_type_, right_type_, false,
+      &call_string_add_or_runtime, &call_runtime, &transition, op_, mode_);
+
+  __ bind(&transition);
+  GenerateTypeTransition(masm);
 
   __ bind(&call_string_add_or_runtime);
   if (op_ == Token::ADD) {
@@ -3206,6 +3222,7 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
   }
 
   __ bind(&call_runtime);
+  GenerateRegisterArgsPush(masm);
   GenerateCallRuntime(masm);
 }
 
@@ -3241,61 +3258,20 @@ void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
 }
 
 
-void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) {
-  GenerateRegisterArgsPush(masm);
-  switch (op_) {
-    case Token::ADD:
-      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
-      break;
-    case Token::SUB:
-      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
-      break;
-    case Token::MUL:
-      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
-      break;
-    case Token::DIV:
-      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
-      break;
-    case Token::MOD:
-      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
-      break;
-    case Token::BIT_OR:
-      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
-      break;
-    case Token::BIT_AND:
-      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
-      break;
-    case Token::BIT_XOR:
-      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
-      break;
-    case Token::SAR:
-      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
-      break;
-    case Token::SHR:
-      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
-      break;
-    case Token::SHL:
-      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
-
-void BinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm,
-                                                Register result,
-                                                Register heap_number_map,
-                                                Register scratch1,
-                                                Register scratch2,
-                                                Label* gc_required) {
+void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
+                                               Register result,
+                                               Register heap_number_map,
+                                               Register scratch1,
+                                               Register scratch2,
+                                               Label* gc_required,
+                                               OverwriteMode mode) {
   // Code below will scratch result if allocation fails. To keep both arguments
   // intact for the runtime call result cannot be one of these.
   ASSERT(!result.is(r0) && !result.is(r1));
 
-  if (mode_ == OVERWRITE_LEFT || mode_ == OVERWRITE_RIGHT) {
+  if (mode == OVERWRITE_LEFT || mode == OVERWRITE_RIGHT) {
     Label skip_allocation, allocated;
-    Register overwritable_operand = mode_ == OVERWRITE_LEFT ? r1 : r0;
+    Register overwritable_operand = mode == OVERWRITE_LEFT ? r1 : r0;
     // If the overwritable operand is already an object, we skip the
     // allocation of a heap number.
     __ JumpIfNotSmi(overwritable_operand, &skip_allocation);
@@ -3308,7 +3284,7 @@ void BinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm,
     __ mov(result, Operand(overwritable_operand));
     __ bind(&allocated);
   } else {
-    ASSERT(mode_ == NO_OVERWRITE);
+    ASSERT(mode == NO_OVERWRITE);
     __ AllocateHeapNumber(
         result, scratch1, scratch2, heap_number_map, gc_required);
   }
@@ -5425,48 +5401,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
 }
 
 
-// Unfortunately you have to run without snapshots to see most of these
-// names in the profile since most compare stubs end up in the snapshot.
-void CompareStub::PrintName(StringStream* stream) {
-  ASSERT((lhs_.is(r0) && rhs_.is(r1)) ||
-         (lhs_.is(r1) && rhs_.is(r0)));
-  const char* cc_name;
-  switch (cc_) {
-    case lt: cc_name = "LT"; break;
-    case gt: cc_name = "GT"; break;
-    case le: cc_name = "LE"; break;
-    case ge: cc_name = "GE"; break;
-    case eq: cc_name = "EQ"; break;
-    case ne: cc_name = "NE"; break;
-    default: cc_name = "UnknownCondition"; break;
-  }
-  bool is_equality = cc_ == eq || cc_ == ne;
-  stream->Add("CompareStub_%s", cc_name);
-  stream->Add(lhs_.is(r0) ? "_r0" : "_r1");
-  stream->Add(rhs_.is(r0) ? "_r0" : "_r1");
-  if (strict_ && is_equality) stream->Add("_STRICT");
-  if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN");
-  if (!include_number_compare_) stream->Add("_NO_NUMBER");
-  if (!include_smi_compare_) stream->Add("_NO_SMI");
-}
-
-
-int CompareStub::MinorKey() {
-  // Encode the three parameters in a unique 16 bit value. To avoid duplicate
-  // stubs the never NaN NaN condition is only taken into account if the
-  // condition is equals.
-  ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 12));
-  ASSERT((lhs_.is(r0) && rhs_.is(r1)) ||
-         (lhs_.is(r1) && rhs_.is(r0)));
-  return ConditionField::encode(static_cast<unsigned>(cc_) >> 28)
-         | RegisterField::encode(lhs_.is(r0))
-         | StrictField::encode(strict_)
-         | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false)
-         | IncludeNumberCompareField::encode(include_number_compare_)
-         | IncludeSmiCompareField::encode(include_smi_compare_);
-}
-
-
 // StringCharCodeAtGenerator
 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
   Label flat_string;
@@ -6668,7 +6602,7 @@ void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
 
 
 void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::SMIS);
+  ASSERT(state_ == CompareIC::SMI);
   Label miss;
   __ orr(r2, r1, r0);
   __ JumpIfNotSmi(r2, &miss);
@@ -6689,31 +6623,53 @@ void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::HEAP_NUMBERS);
+  ASSERT(state_ == CompareIC::HEAP_NUMBER);
 
   Label generic_stub;
   Label unordered, maybe_undefined1, maybe_undefined2;
   Label miss;
-  __ and_(r2, r1, Operand(r0));
-  __ JumpIfSmi(r2, &generic_stub);
 
-  __ CompareObjectType(r0, r2, r2, HEAP_NUMBER_TYPE);
-  __ b(ne, &maybe_undefined1);
-  __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
-  __ b(ne, &maybe_undefined2);
+  if (left_ == CompareIC::SMI) {
+    __ JumpIfNotSmi(r1, &miss);
+  }
+  if (right_ == CompareIC::SMI) {
+    __ JumpIfNotSmi(r0, &miss);
+  }
 
   // Inlining the double comparison and falling back to the general compare
-  // stub if NaN is involved or VFP3 is unsupported.
+  // stub if NaN is involved or VFP2 is unsupported.
   if (CpuFeatures::IsSupported(VFP2)) {
     CpuFeatures::Scope scope(VFP2);
 
-    // Load left and right operand
-    __ sub(r2, r1, Operand(kHeapObjectTag));
-    __ vldr(d0, r2, HeapNumber::kValueOffset);
+    // Load left and right operand.
+    Label done, left, left_smi, right_smi;
+    __ JumpIfSmi(r0, &right_smi);
+    __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
+                DONT_DO_SMI_CHECK);
     __ sub(r2, r0, Operand(kHeapObjectTag));
     __ vldr(d1, r2, HeapNumber::kValueOffset);
+    __ b(&left);
+    __ bind(&right_smi);
+    __ SmiUntag(r2, r0);  // Can't clobber r0 yet.
+    SwVfpRegister single_scratch = d2.low();
+    __ vmov(single_scratch, r2);
+    __ vcvt_f64_s32(d1, single_scratch);
+
+    __ bind(&left);
+    __ JumpIfSmi(r1, &left_smi);
+    __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
+                DONT_DO_SMI_CHECK);
+    __ sub(r2, r1, Operand(kHeapObjectTag));
+    __ vldr(d0, r2, HeapNumber::kValueOffset);
+    __ b(&done);
+    __ bind(&left_smi);
+    __ SmiUntag(r2, r1);  // Can't clobber r1 yet.
+    single_scratch = d3.low();
+    __ vmov(single_scratch, r2);
+    __ vcvt_f64_s32(d0, single_scratch);
 
-    // Compare operands
+    __ bind(&done);
+    // Compare operands.
     __ VFPCompareAndSetFlags(d0, d1);
 
     // Don't base result on status bits when a NaN is involved.
@@ -6727,14 +6683,16 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
   }
 
   __ bind(&unordered);
-  CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
   __ bind(&generic_stub);
+  ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
+                     CompareIC::GENERIC);
   __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
 
   __ bind(&maybe_undefined1);
   if (Token::IsOrderedRelationalCompareOp(op_)) {
     __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
     __ b(ne, &miss);
+    __ JumpIfSmi(r1, &unordered);
     __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
     __ b(ne, &maybe_undefined2);
     __ jmp(&unordered);
@@ -6752,7 +6710,7 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::SYMBOLS);
+  ASSERT(state_ == CompareIC::SYMBOL);
   Label miss;
 
   // Registers containing left and right operands respectively.
@@ -6790,7 +6748,7 @@ void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::STRINGS);
+  ASSERT(state_ == CompareIC::STRING);
   Label miss;
 
   bool equality = Token::IsEqualityOp(op_);
@@ -6868,7 +6826,7 @@ void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::OBJECTS);
+  ASSERT(state_ == CompareIC::OBJECT);
   Label miss;
   __ and_(r2, r1, Operand(r0));
   __ JumpIfSmi(r2, &miss);
index 3e796249c8435f97f7a14f0454f5c2e8835446ed..0443cf799cc08e5d83e8ebe88f6de929dc8b5d12 100644 (file)
@@ -142,108 +142,6 @@ class UnaryOpStub: public CodeStub {
 };
 
 
-class BinaryOpStub: public CodeStub {
- public:
-  BinaryOpStub(Token::Value op, OverwriteMode mode)
-      : op_(op),
-        mode_(mode),
-        operands_type_(BinaryOpIC::UNINITIALIZED),
-        result_type_(BinaryOpIC::UNINITIALIZED) {
-    use_vfp2_ = CpuFeatures::IsSupported(VFP2);
-    ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
-  }
-
-  BinaryOpStub(
-      int key,
-      BinaryOpIC::TypeInfo operands_type,
-      BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
-      : op_(OpBits::decode(key)),
-        mode_(ModeBits::decode(key)),
-        use_vfp2_(VFP2Bits::decode(key)),
-        operands_type_(operands_type),
-        result_type_(result_type) { }
-
- private:
-  enum SmiCodeGenerateHeapNumberResults {
-    ALLOW_HEAPNUMBER_RESULTS,
-    NO_HEAPNUMBER_RESULTS
-  };
-
-  Token::Value op_;
-  OverwriteMode mode_;
-  bool use_vfp2_;
-
-  // Operand type information determined at runtime.
-  BinaryOpIC::TypeInfo operands_type_;
-  BinaryOpIC::TypeInfo result_type_;
-
-  virtual void PrintName(StringStream* stream);
-
-  // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM.
-  class ModeBits: public BitField<OverwriteMode, 0, 2> {};
-  class OpBits: public BitField<Token::Value, 2, 7> {};
-  class VFP2Bits: public BitField<bool, 9, 1> {};
-  class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
-  class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
-
-  Major MajorKey() { return BinaryOp; }
-  int MinorKey() {
-    return OpBits::encode(op_)
-           | ModeBits::encode(mode_)
-           | VFP2Bits::encode(use_vfp2_)
-           | OperandTypeInfoBits::encode(operands_type_)
-           | ResultTypeInfoBits::encode(result_type_);
-  }
-
-  void Generate(MacroAssembler* masm);
-  void GenerateGeneric(MacroAssembler* masm);
-  void GenerateSmiSmiOperation(MacroAssembler* masm);
-  void GenerateFPOperation(MacroAssembler* masm,
-                           bool smi_operands,
-                           Label* not_numbers,
-                           Label* gc_required);
-  void GenerateSmiCode(MacroAssembler* masm,
-                       Label* use_runtime,
-                       Label* gc_required,
-                       SmiCodeGenerateHeapNumberResults heapnumber_results);
-  void GenerateLoadArguments(MacroAssembler* masm);
-  void GenerateReturn(MacroAssembler* masm);
-  void GenerateUninitializedStub(MacroAssembler* masm);
-  void GenerateSmiStub(MacroAssembler* masm);
-  void GenerateInt32Stub(MacroAssembler* masm);
-  void GenerateHeapNumberStub(MacroAssembler* masm);
-  void GenerateOddballStub(MacroAssembler* masm);
-  void GenerateStringStub(MacroAssembler* masm);
-  void GenerateBothStringStub(MacroAssembler* masm);
-  void GenerateGenericStub(MacroAssembler* masm);
-  void GenerateAddStrings(MacroAssembler* masm);
-  void GenerateCallRuntime(MacroAssembler* masm);
-
-  void GenerateHeapResultAllocation(MacroAssembler* masm,
-                                    Register result,
-                                    Register heap_number_map,
-                                    Register scratch1,
-                                    Register scratch2,
-                                    Label* gc_required);
-  void GenerateRegisterArgsPush(MacroAssembler* masm);
-  void GenerateTypeTransition(MacroAssembler* masm);
-  void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
-
-  virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
-
-  virtual InlineCacheState GetICState() {
-    return BinaryOpIC::ToState(operands_type_);
-  }
-
-  virtual void FinishCode(Handle<Code> code) {
-    code->set_binary_op_type(operands_type_);
-    code->set_binary_op_result_type(result_type_);
-  }
-
-  friend class CodeGenerator;
-};
-
-
 class StringHelper : public AllStatic {
  public:
   // Generate code for copying characters using a simple loop. This should only
@@ -724,20 +622,6 @@ class FloatingPointHelper : public AllStatic {
                        Register scratch1,
                        Register scratch2);
 
-  // Loads objects from r0 and r1 (right and left in binary operations) into
-  // floating point registers. Depending on the destination the values ends up
-  // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
-  // floating point registers VFP3 must be supported. If core registers are
-  // requested when VFP3 is supported d6 and d7 will still be scratched. If
-  // either r0 or r1 is not a number (not smi and not heap number object) the
-  // not_number label is jumped to with r0 and r1 intact.
-  static void LoadOperands(MacroAssembler* masm,
-                           FloatingPointHelper::Destination destination,
-                           Register heap_number_map,
-                           Register scratch1,
-                           Register scratch2,
-                           Label* not_number);
-
   // Convert the smi or heap number in object to an int32 using the rules
   // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
   // and brought into the range -2^31 .. +2^31 - 1.
@@ -836,7 +720,12 @@ class FloatingPointHelper : public AllStatic {
                                           Register heap_number_result,
                                           Register scratch);
 
- private:
+  // Loads the objects from |object| into floating point registers.
+  // Depending on |destination| the value ends up either in |dst| or
+  // in |dst1|/|dst2|. If |destination| is kVFPRegisters, then VFP3
+  // must be supported. If kCoreRegisters are requested and VFP3 is
+  // supported, |dst| will be scratched. If |object| is neither smi nor
+  // heap number, |not_number| is jumped to with |object| still intact.
   static void LoadNumber(MacroAssembler* masm,
                          FloatingPointHelper::Destination destination,
                          Register object,
index 03d50676fb652e30a00e4f374c8af786e791de96..50544dea4347669f9857fac8fab5e6d0902122f8 100644 (file)
@@ -4073,7 +4073,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
     // Call stub. Undo operation first.
     __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
   }
-  __ mov(r1, Operand(Smi::FromInt(count_value)));
+  __ mov(r1, r0);
+  __ mov(r0, Operand(Smi::FromInt(count_value)));
 
   // Record position before stub call.
   SetSourcePosition(expr->position());
@@ -4298,29 +4299,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
 
     default: {
       VisitForAccumulatorValue(expr->right());
-      Condition cond = eq;
-      switch (op) {
-        case Token::EQ_STRICT:
-        case Token::EQ:
-          cond = eq;
-          break;
-        case Token::LT:
-          cond = lt;
-          break;
-        case Token::GT:
-          cond = gt;
-         break;
-        case Token::LTE:
-          cond = le;
-          break;
-        case Token::GTE:
-          cond = ge;
-          break;
-        case Token::IN:
-        case Token::INSTANCEOF:
-        default:
-          UNREACHABLE();
-      }
+      Condition cond = CompareIC::ComputeCondition(op);
       __ pop(r1);
 
       bool inline_smi_code = ShouldInlineSmiCase(op);
index 48395897da826b34adad426cabf92407376d1075..6345922cfd00aa05098e7cdd16b4f36b994dc8e4 100644 (file)
@@ -1699,36 +1699,15 @@ Condition CompareIC::ComputeCondition(Token::Value op) {
 }
 
 
-void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
-  HandleScope scope;
-  Handle<Code> rewritten;
-  State previous_state = GetState();
-  State state = TargetState(previous_state, false, x, y);
-  if (state == GENERIC) {
-    CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
-    rewritten = stub.GetCode();
-  } else {
-    ICCompareStub stub(op_, state);
-    if (state == KNOWN_OBJECTS) {
-      stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
-    }
-    rewritten = stub.GetCode();
-  }
-  set_target(*rewritten);
-
-#ifdef DEBUG
-  if (FLAG_trace_ic) {
-    PrintF("[CompareIC (%s->%s)#%s]\n",
-           GetStateName(previous_state),
-           GetStateName(state),
-           Token::Name(op_));
-  }
-#endif
+bool CompareIC::HasInlinedSmiCode(Address address) {
+  // The address of the instruction following the call.
+  Address cmp_instruction_address =
+      Assembler::return_address_from_call_start(address);
 
-  // Activate inlined smi code.
-  if (previous_state == UNINITIALIZED) {
-    PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
-  }
+  // If the instruction following the call is not a cmp rx, #yyy, nothing
+  // was inlined.
+  Instr instr = Assembler::instr_at(cmp_instruction_address);
+  return Assembler::IsCmpImmediate(instr);
 }
 
 
index 1d5f0ec4f7095256eee63ba2e1b8dbf379e26b5a..5cd691461f6308949bb47ef62e66fc5f4edcd355 100644 (file)
@@ -1437,7 +1437,7 @@ LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
 
 LInstruction* LChunkBuilder::DoCompareIDAndBranch(
     HCompareIDAndBranch* instr) {
-  Representation r = instr->GetInputRepresentation();
+  Representation r = instr->representation();
   if (r.IsInteger32()) {
     ASSERT(instr->left()->representation().IsInteger32());
     ASSERT(instr->right()->representation().IsInteger32());
@@ -2196,7 +2196,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
   env->set_ast_id(instr->ast_id());
 
   env->Drop(instr->pop_count());
-  for (int i = 0; i < instr->values()->length(); ++i) {
+  for (int i = instr->values()->length() - 1; i >= 0; --i) {
     HValue* value = instr->values()->at(i);
     if (instr->HasAssignedIndexAt(i)) {
       env->Bind(instr->GetAssignedIndexAt(i), value);
index 678d07740bb0f36099800424eb8e134d3a55a5e8..0367fd3234abed7a836df1ca8d95bf1828476732 100644 (file)
@@ -655,7 +655,7 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> {
 
   Token::Value op() const { return hydrogen()->token(); }
   bool is_double() const {
-    return hydrogen()->GetInputRepresentation().IsDouble();
+    return hydrogen()->representation().IsDouble();
   }
 
   virtual void PrintDataTo(StringStream* stream);
index b773ca9ea1c16d245dcebb3c9e29518fe2e91f2f..0a28d343bac887ccdeb673f9b8ea4180e05da031 100644 (file)
@@ -230,7 +230,30 @@ bool LCodeGen::GenerateBody() {
     }
 
     if (emit_instructions) {
-      Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
+      if (FLAG_code_comments) {
+        HValue* hydrogen = instr->hydrogen_value();
+        if (hydrogen != NULL) {
+          if (hydrogen->IsChange()) {
+            HValue* changed_value = HChange::cast(hydrogen)->value();
+            int use_id = 0;
+            const char* use_mnemo = "dead";
+            if (hydrogen->UseCount() >= 1) {
+              HValue* use_value = hydrogen->uses().value();
+              use_id = use_value->id();
+              use_mnemo = use_value->Mnemonic();
+            }
+            Comment(";;; @%d: %s. <of #%d %s for #%d %s>",
+                    current_instruction_, instr->Mnemonic(),
+                    changed_value->id(), changed_value->Mnemonic(),
+                    use_id, use_mnemo);
+          } else {
+            Comment(";;; @%d: %s. <#%d>", current_instruction_,
+                    instr->Mnemonic(), hydrogen->id());
+          }
+        } else {
+          Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
+        }
+      }
       instr->CompileToNative(this);
     }
   }
index 52990b8feedeb93109e7465913ec746c64b24c6f..9cdae545da4f9d586e0f43fe556c32354103d4a4 100644 (file)
@@ -476,6 +476,7 @@ void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle,
 
 void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
   TypeInfo info = oracle->SwitchType(this);
+  if (info.IsUninitialized()) info = TypeInfo::Unknown();
   if (info.IsSmi()) {
     compare_type_ = SMI_ONLY;
   } else if (info.IsSymbol()) {
@@ -604,18 +605,6 @@ void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
 }
 
 
-void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  TypeInfo info = oracle->CompareType(this);
-  if (info.IsSmi()) {
-    compare_type_ = SMI_ONLY;
-  } else if (info.IsNonPrimitive()) {
-    compare_type_ = OBJECT_ONLY;
-  } else {
-    ASSERT(compare_type_ == NONE);
-  }
-}
-
-
 void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
   receiver_type_ = oracle->ObjectLiteralStoreIsMonomorphic(this)
       ? oracle->GetObjectLiteralStoreMap(this)
index 802ac65962501dfa47db0f43f4e4de95c984a145..6fb930973cc859e08b31f20deb4b09cba9aab43e 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -1777,9 +1777,6 @@ class CompareOperation: public Expression {
 
   // Type feedback information.
   TypeFeedbackId CompareOperationFeedbackId() const { return reuse(id()); }
-  void RecordTypeFeedback(TypeFeedbackOracle* oracle);
-  bool IsSmiCompare() { return compare_type_ == SMI_ONLY; }
-  bool IsObjectCompare() { return compare_type_ == OBJECT_ONLY; }
 
   // Match special cases.
   bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
@@ -1796,8 +1793,7 @@ class CompareOperation: public Expression {
         op_(op),
         left_(left),
         right_(right),
-        pos_(pos),
-        compare_type_(NONE) {
+        pos_(pos) {
     ASSERT(Token::IsCompareOp(op));
   }
 
@@ -1806,9 +1802,6 @@ class CompareOperation: public Expression {
   Expression* left_;
   Expression* right_;
   int pos_;
-
-  enum CompareTypeFeedback { NONE, SMI_ONLY, OBJECT_ONLY };
-  CompareTypeFeedback compare_type_;
 };
 
 
index 7a720592db20bf8117b833071f08b7d6815ebf4b..117b3b12d80094f97ebd71803ed1e3f043f6af33 100644 (file)
@@ -169,6 +169,122 @@ void CodeStub::PrintName(StringStream* stream) {
 }
 
 
+void BinaryOpStub::Generate(MacroAssembler* masm) {
+  // Explicitly allow generation of nested stubs. It is safe here because
+  // generation code does not use any raw pointers.
+  AllowStubCallsScope allow_stub_calls(masm, true);
+
+  BinaryOpIC::TypeInfo operands_type = Max(left_type_, right_type_);
+  if (left_type_ == BinaryOpIC::ODDBALL && right_type_ == BinaryOpIC::ODDBALL) {
+    // The OddballStub handles a number and an oddball, not two oddballs.
+    operands_type = BinaryOpIC::GENERIC;
+  }
+  switch (operands_type) {
+    case BinaryOpIC::UNINITIALIZED:
+      GenerateTypeTransition(masm);
+      break;
+    case BinaryOpIC::SMI:
+      GenerateSmiStub(masm);
+      break;
+    case BinaryOpIC::INT32:
+      GenerateInt32Stub(masm);
+      break;
+    case BinaryOpIC::HEAP_NUMBER:
+      GenerateHeapNumberStub(masm);
+      break;
+    case BinaryOpIC::ODDBALL:
+      GenerateOddballStub(masm);
+      break;
+    case BinaryOpIC::STRING:
+      GenerateStringStub(masm);
+      break;
+    case BinaryOpIC::GENERIC:
+      GenerateGeneric(masm);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+#define __ ACCESS_MASM(masm)
+
+
+void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) {
+  switch (op_) {
+    case Token::ADD:
+      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
+      break;
+    case Token::SUB:
+      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
+      break;
+    case Token::MUL:
+      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
+      break;
+    case Token::DIV:
+      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
+      break;
+    case Token::MOD:
+      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
+      break;
+    case Token::BIT_OR:
+      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
+      break;
+    case Token::BIT_AND:
+      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
+      break;
+    case Token::BIT_XOR:
+      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
+      break;
+    case Token::SAR:
+      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
+      break;
+    case Token::SHR:
+      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
+      break;
+    case Token::SHL:
+      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+#undef __
+
+
+void BinaryOpStub::PrintName(StringStream* stream) {
+  const char* op_name = Token::Name(op_);
+  const char* overwrite_name;
+  switch (mode_) {
+    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
+    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
+    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
+    default: overwrite_name = "UnknownOverwrite"; break;
+  }
+  stream->Add("BinaryOpStub_%s_%s_%s+%s",
+              op_name,
+              overwrite_name,
+              BinaryOpIC::GetName(left_type_),
+              BinaryOpIC::GetName(right_type_));
+}
+
+
+void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
+  ASSERT(left_type_ == BinaryOpIC::STRING || right_type_ == BinaryOpIC::STRING);
+  ASSERT(op_ == Token::ADD);
+  if (left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING) {
+    GenerateBothStringStub(masm);
+    return;
+  }
+  // Try to add arguments as strings, otherwise, transition to the generic
+  // BinaryOpIC type.
+  GenerateAddStrings(masm);
+  GenerateTypeTransition(masm);
+}
+
+
 void ICCompareStub::AddToSpecialCache(Handle<Code> new_object) {
   ASSERT(*known_map_ != NULL);
   Isolate* isolate = new_object->GetIsolate();
@@ -196,7 +312,12 @@ bool ICCompareStub::FindCodeInSpecialCache(Code** code_out) {
         flags));
   if (probe->IsCode()) {
     *code_out = Code::cast(*probe);
-    ASSERT(op_ == (*code_out)->compare_operation() + Token::EQ);
+#ifdef DEBUG
+    Token::Value cached_op;
+    ICCompareStub::DecodeMinorKey((*code_out)->stub_info(), NULL, NULL, NULL,
+                                  &cached_op);
+    ASSERT(op_ == cached_op);
+#endif
     return true;
   }
   return false;
@@ -204,7 +325,33 @@ bool ICCompareStub::FindCodeInSpecialCache(Code** code_out) {
 
 
 int ICCompareStub::MinorKey() {
-  return OpField::encode(op_ - Token::EQ) | StateField::encode(state_);
+  return OpField::encode(op_ - Token::EQ) |
+         LeftStateField::encode(left_) |
+         RightStateField::encode(right_) |
+         HandlerStateField::encode(state_);
+}
+
+
+void ICCompareStub::DecodeMinorKey(int minor_key,
+                                   CompareIC::State* left_state,
+                                   CompareIC::State* right_state,
+                                   CompareIC::State* handler_state,
+                                   Token::Value* op) {
+  if (left_state) {
+    *left_state =
+        static_cast<CompareIC::State>(LeftStateField::decode(minor_key));
+  }
+  if (right_state) {
+    *right_state =
+        static_cast<CompareIC::State>(RightStateField::decode(minor_key));
+  }
+  if (handler_state) {
+    *handler_state =
+        static_cast<CompareIC::State>(HandlerStateField::decode(minor_key));
+  }
+  if (op) {
+    *op = static_cast<Token::Value>(OpField::decode(minor_key) + Token::EQ);
+  }
 }
 
 
@@ -213,27 +360,28 @@ void ICCompareStub::Generate(MacroAssembler* masm) {
     case CompareIC::UNINITIALIZED:
       GenerateMiss(masm);
       break;
-    case CompareIC::SMIS:
+    case CompareIC::SMI:
       GenerateSmis(masm);
       break;
-    case CompareIC::HEAP_NUMBERS:
+    case CompareIC::HEAP_NUMBER:
       GenerateHeapNumbers(masm);
       break;
-    case CompareIC::STRINGS:
+    case CompareIC::STRING:
       GenerateStrings(masm);
       break;
-    case CompareIC::SYMBOLS:
+    case CompareIC::SYMBOL:
       GenerateSymbols(masm);
       break;
-    case CompareIC::OBJECTS:
+    case CompareIC::OBJECT:
       GenerateObjects(masm);
       break;
     case CompareIC::KNOWN_OBJECTS:
       ASSERT(*known_map_ != NULL);
       GenerateKnownObjects(masm);
       break;
-    default:
-      UNREACHABLE();
+    case CompareIC::GENERIC:
+      GenerateGeneric(masm);
+      break;
   }
 }
 
index e4384e7573d592af78df0d5166252db8eb087404..3110b54b996afbd6223c5f4ebc59492d93219593 100644 (file)
@@ -482,10 +482,132 @@ class MathPowStub: public CodeStub {
 };
 
 
+class BinaryOpStub: public CodeStub {
+ public:
+  BinaryOpStub(Token::Value op, OverwriteMode mode)
+      : op_(op),
+        mode_(mode),
+        platform_specific_bit_(false),
+        left_type_(BinaryOpIC::UNINITIALIZED),
+        right_type_(BinaryOpIC::UNINITIALIZED),
+        result_type_(BinaryOpIC::UNINITIALIZED) {
+    Initialize();
+    ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
+  }
+
+  BinaryOpStub(
+      int key,
+      BinaryOpIC::TypeInfo left_type,
+      BinaryOpIC::TypeInfo right_type,
+      BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
+      : op_(OpBits::decode(key)),
+        mode_(ModeBits::decode(key)),
+        platform_specific_bit_(PlatformSpecificBits::decode(key)),
+        left_type_(left_type),
+        right_type_(right_type),
+        result_type_(result_type) { }
+
+  static void decode_types_from_minor_key(int minor_key,
+                                          BinaryOpIC::TypeInfo* left_type,
+                                          BinaryOpIC::TypeInfo* right_type,
+                                          BinaryOpIC::TypeInfo* result_type) {
+    *left_type =
+        static_cast<BinaryOpIC::TypeInfo>(LeftTypeBits::decode(minor_key));
+    *right_type =
+        static_cast<BinaryOpIC::TypeInfo>(RightTypeBits::decode(minor_key));
+    *result_type =
+        static_cast<BinaryOpIC::TypeInfo>(ResultTypeBits::decode(minor_key));
+  }
+
+  static Token::Value decode_op_from_minor_key(int minor_key) {
+    return static_cast<Token::Value>(OpBits::decode(minor_key));
+  }
+
+  enum SmiCodeGenerateHeapNumberResults {
+    ALLOW_HEAPNUMBER_RESULTS,
+    NO_HEAPNUMBER_RESULTS
+  };
+
+ private:
+  Token::Value op_;
+  OverwriteMode mode_;
+  bool platform_specific_bit_;  // Indicates SSE3 on IA32, VFP2 on ARM.
+
+  // Operand type information determined at runtime.
+  BinaryOpIC::TypeInfo left_type_;
+  BinaryOpIC::TypeInfo right_type_;
+  BinaryOpIC::TypeInfo result_type_;
+
+  virtual void PrintName(StringStream* stream);
+
+  // Minor key encoding in 19 bits TTTRRRLLLSOOOOOOOMM.
+  class ModeBits: public BitField<OverwriteMode, 0, 2> {};
+  class OpBits: public BitField<Token::Value, 2, 7> {};
+  class PlatformSpecificBits: public BitField<bool, 9, 1> {};
+  class LeftTypeBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
+  class RightTypeBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
+  class ResultTypeBits: public BitField<BinaryOpIC::TypeInfo, 16, 3> {};
+
+  Major MajorKey() { return BinaryOp; }
+  int MinorKey() {
+    return OpBits::encode(op_)
+           | ModeBits::encode(mode_)
+           | PlatformSpecificBits::encode(platform_specific_bit_)
+           | LeftTypeBits::encode(left_type_)
+           | RightTypeBits::encode(right_type_)
+           | ResultTypeBits::encode(result_type_);
+  }
+
+
+  // Platform-independent implementation.
+  void Generate(MacroAssembler* masm);
+  void GenerateCallRuntime(MacroAssembler* masm);
+
+  // Platform-independent signature, platform-specific implementation.
+  void Initialize();
+  void GenerateAddStrings(MacroAssembler* masm);
+  void GenerateBothStringStub(MacroAssembler* masm);
+  void GenerateGeneric(MacroAssembler* masm);
+  void GenerateGenericStub(MacroAssembler* masm);
+  void GenerateHeapNumberStub(MacroAssembler* masm);
+  void GenerateInt32Stub(MacroAssembler* masm);
+  void GenerateLoadArguments(MacroAssembler* masm);
+  void GenerateOddballStub(MacroAssembler* masm);
+  void GenerateRegisterArgsPush(MacroAssembler* masm);
+  void GenerateReturn(MacroAssembler* masm);
+  void GenerateSmiStub(MacroAssembler* masm);
+  void GenerateStringStub(MacroAssembler* masm);
+  void GenerateTypeTransition(MacroAssembler* masm);
+  void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
+  void GenerateUninitializedStub(MacroAssembler* masm);
+
+  // Entirely platform-specific methods are defined as static helper
+  // functions in the <arch>/code-stubs-<arch>.cc files.
+
+  virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
+
+  virtual InlineCacheState GetICState() {
+    return BinaryOpIC::ToState(Max(left_type_, right_type_));
+  }
+
+  virtual void FinishCode(Handle<Code> code) {
+    code->set_stub_info(MinorKey());
+  }
+
+  friend class CodeGenerator;
+};
+
+
 class ICCompareStub: public CodeStub {
  public:
-  ICCompareStub(Token::Value op, CompareIC::State state)
-      : op_(op), state_(state) {
+  ICCompareStub(Token::Value op,
+                CompareIC::State left,
+                CompareIC::State right,
+                CompareIC::State handler)
+      : op_(op),
+        left_(left),
+        right_(right),
+        state_(handler) {
     ASSERT(Token::IsCompareOp(op));
   }
 
@@ -493,13 +615,24 @@ class ICCompareStub: public CodeStub {
 
   void set_known_map(Handle<Map> map) { known_map_ = map; }
 
+  static void DecodeMinorKey(int minor_key,
+                             CompareIC::State* left_state,
+                             CompareIC::State* right_state,
+                             CompareIC::State* handler_state,
+                             Token::Value* op);
+
+  static CompareIC::State CompareState(int minor_key) {
+    return static_cast<CompareIC::State>(HandlerStateField::decode(minor_key));
+  }
+
  private:
   class OpField: public BitField<int, 0, 3> { };
-  class StateField: public BitField<int, 3, 5> { };
+  class LeftStateField: public BitField<int, 3, 3> { };
+  class RightStateField: public BitField<int, 6, 3> { };
+  class HandlerStateField: public BitField<int, 9, 3> { };
 
   virtual void FinishCode(Handle<Code> code) {
-    code->set_compare_state(state_);
-    code->set_compare_operation(op_ - Token::EQ);
+    code->set_stub_info(MinorKey());
   }
 
   virtual CodeStub::Major MajorKey() { return CompareIC; }
@@ -514,6 +647,7 @@ class ICCompareStub: public CodeStub {
   void GenerateObjects(MacroAssembler* masm);
   void GenerateMiss(MacroAssembler* masm);
   void GenerateKnownObjects(MacroAssembler* masm);
+  void GenerateGeneric(MacroAssembler* masm);
 
   bool strict() const { return op_ == Token::EQ_STRICT; }
   Condition GetCondition() const { return CompareIC::ComputeCondition(op_); }
@@ -523,108 +657,13 @@ class ICCompareStub: public CodeStub {
   virtual bool UseSpecialCache() { return state_ == CompareIC::KNOWN_OBJECTS; }
 
   Token::Value op_;
+  CompareIC::State left_;
+  CompareIC::State right_;
   CompareIC::State state_;
   Handle<Map> known_map_;
 };
 
 
-// Flags that control the compare stub code generation.
-enum CompareFlags {
-  NO_COMPARE_FLAGS = 0,
-  NO_SMI_COMPARE_IN_STUB = 1 << 0,
-  NO_NUMBER_COMPARE_IN_STUB = 1 << 1,
-  CANT_BOTH_BE_NAN = 1 << 2
-};
-
-
-enum NaNInformation {
-  kBothCouldBeNaN,
-  kCantBothBeNaN
-};
-
-
-class CompareStub: public CodeStub {
- public:
-  CompareStub(Condition cc,
-              bool strict,
-              CompareFlags flags,
-              Register lhs,
-              Register rhs) :
-     cc_(cc),
-      strict_(strict),
-      never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0),
-      include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0),
-      include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0),
-      lhs_(lhs),
-      rhs_(rhs) { }
-
-  CompareStub(Condition cc,
-              bool strict,
-              CompareFlags flags) :
-      cc_(cc),
-      strict_(strict),
-      never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0),
-      include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0),
-      include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0),
-      lhs_(no_reg),
-      rhs_(no_reg) { }
-
-  void Generate(MacroAssembler* masm);
-
- private:
-  Condition cc_;
-  bool strict_;
-  // Only used for 'equal' comparisons.  Tells the stub that we already know
-  // that at least one side of the comparison is not NaN.  This allows the
-  // stub to use object identity in the positive case.  We ignore it when
-  // generating the minor key for other comparisons to avoid creating more
-  // stubs.
-  bool never_nan_nan_;
-  // Do generate the number comparison code in the stub. Stubs without number
-  // comparison code is used when the number comparison has been inlined, and
-  // the stub will be called if one of the operands is not a number.
-  bool include_number_compare_;
-
-  // Generate the comparison code for two smi operands in the stub.
-  bool include_smi_compare_;
-
-  // Register holding the left hand side of the comparison if the stub gives
-  // a choice, no_reg otherwise.
-
-  Register lhs_;
-  // Register holding the right hand side of the comparison if the stub gives
-  // a choice, no_reg otherwise.
-  Register rhs_;
-
-  // Encoding of the minor key in 16 bits.
-  class StrictField: public BitField<bool, 0, 1> {};
-  class NeverNanNanField: public BitField<bool, 1, 1> {};
-  class IncludeNumberCompareField: public BitField<bool, 2, 1> {};
-  class IncludeSmiCompareField: public  BitField<bool, 3, 1> {};
-  class RegisterField: public BitField<bool, 4, 1> {};
-  class ConditionField: public BitField<int, 5, 11> {};
-
-  Major MajorKey() { return Compare; }
-
-  int MinorKey();
-
-  virtual int GetCodeKind() { return Code::COMPARE_IC; }
-  virtual void FinishCode(Handle<Code> code) {
-    code->set_compare_state(CompareIC::GENERIC);
-  }
-
-  // Branch to the label if the given object isn't a symbol.
-  void BranchIfNonSymbol(MacroAssembler* masm,
-                         Label* label,
-                         Register object,
-                         Register scratch);
-
-  // Unfortunately you have to run without snapshots to see most of these
-  // names in the profile since most compare stubs end up in the snapshot.
-  virtual void PrintName(StringStream* stream);
-};
-
-
 class CEntryStub : public CodeStub {
  public:
   explicit CEntryStub(int result_size,
@@ -1053,6 +1092,9 @@ class ToBooleanStub: public CodeStub {
 
     bool IsEmpty() const { return set_.IsEmpty(); }
     bool Contains(Type type) const { return set_.Contains(type); }
+    bool ContainsAnyOf(Types types) const {
+      return set_.ContainsAnyOf(types.set_);
+    }
     void Add(Type type) { set_.Add(type); }
     byte ToByte() const { return set_.ToIntegral(); }
     void Print(StringStream* stream) const;
index a54cb238c51b35bdea282d3c71fb4612072ae164..c75d12c651c6d6cb2228ee78e89f70674ee19376 100644 (file)
@@ -107,7 +107,7 @@ function MakeDay(year, month, date) {
   }
 
   // Now we rely on year and month being SMIs.
-  return %DateMakeDay(year, month) + date - 1;
+  return %DateMakeDay(year | 0, month | 0) + date - 1;
 }
 
 
index e1090176c9709d9815a3e1c1fdca4f758eeeab84..998ba49a34ed5a097cde7fd1570ba10cea476035 100644 (file)
@@ -3787,7 +3787,7 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc,
     code->set_check_type(RECEIVER_MAP_CHECK);
   }
   code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER);
-  code->set_type_feedback_info(undefined_value(), SKIP_WRITE_BARRIER);
+  code->InitializeTypeFeedbackInfoNoWriteBarrier(undefined_value());
   code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
   code->set_gc_metadata(Smi::FromInt(0));
   code->set_ic_age(global_ic_age_);
index feac1be0bcfcdf45f6c435f7899acd645d24e4e8..ec23e1971b7923d14b11ca23622cb900dbcbcd24 100644 (file)
@@ -85,6 +85,81 @@ void HValue::AssumeRepresentation(Representation r) {
 }
 
 
+void HValue::InferRepresentation(HInferRepresentation* h_infer) {
+  ASSERT(CheckFlag(kFlexibleRepresentation));
+  Representation new_rep = RepresentationFromInputs();
+  UpdateRepresentation(new_rep, h_infer, "inputs");
+  new_rep = RepresentationFromUses();
+  UpdateRepresentation(new_rep, h_infer, "uses");
+}
+
+
+Representation HValue::RepresentationFromUses() {
+  if (HasNoUses()) return Representation::None();
+
+  // Array of use counts for each representation.
+  int use_count[Representation::kNumRepresentations] = { 0 };
+
+  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
+    HValue* use = it.value();
+    Representation rep = use->observed_input_representation(it.index());
+    if (rep.IsNone()) continue;
+    if (FLAG_trace_representation) {
+      PrintF("#%d %s is used by #%d %s as %s%s\n",
+             id(), Mnemonic(), use->id(), use->Mnemonic(), rep.Mnemonic(),
+             (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : ""));
+    }
+    use_count[rep.kind()] += use->LoopWeight();
+  }
+  if (IsPhi()) HPhi::cast(this)->AddIndirectUsesTo(&use_count[0]);
+  int tagged_count = use_count[Representation::kTagged];
+  int double_count = use_count[Representation::kDouble];
+  int int32_count = use_count[Representation::kInteger32];
+
+  if (tagged_count > 0) return Representation::Tagged();
+  if (double_count > 0) return Representation::Double();
+  if (int32_count > 0) return Representation::Integer32();
+
+  return Representation::None();
+}
+
+
+void HValue::UpdateRepresentation(Representation new_rep,
+                                  HInferRepresentation* h_infer,
+                                  const char* reason) {
+  Representation r = representation();
+  if (new_rep.is_more_general_than(r)) {
+    // When an HConstant is marked "not convertible to integer", then
+    // never try to represent it as an integer.
+    if (new_rep.IsInteger32() && !IsConvertibleToInteger()) {
+      new_rep = Representation::Tagged();
+      if (FLAG_trace_representation) {
+        PrintF("Changing #%d %s representation %s -> %s because it's NCTI"
+               " (%s want i)\n",
+               id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason);
+      }
+    } else {
+      if (FLAG_trace_representation) {
+        PrintF("Changing #%d %s representation %s -> %s based on %s\n",
+               id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason);
+      }
+    }
+    ChangeRepresentation(new_rep);
+    AddDependantsToWorklist(h_infer);
+  }
+}
+
+
+void HValue::AddDependantsToWorklist(HInferRepresentation* h_infer) {
+  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
+    h_infer->AddToWorklist(it.value());
+  }
+  for (int i = 0; i < OperandCount(); ++i) {
+    h_infer->AddToWorklist(OperandAt(i));
+  }
+}
+
+
 static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) {
   if (result > kMaxInt) {
     *overflow = true;
@@ -301,6 +376,7 @@ HUseListNode* HUseListNode::tail() {
 
 bool HValue::CheckUsesForFlag(Flag f) {
   for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
+    if (it.value()->IsSimulate()) continue;
     if (!it.value()->CheckFlag(f)) return false;
   }
   return true;
@@ -764,6 +840,24 @@ void HReturn::PrintDataTo(StringStream* stream) {
 }
 
 
+Representation HBranch::observed_input_representation(int index) {
+  static const ToBooleanStub::Types tagged_types(
+      ToBooleanStub::UNDEFINED |
+      ToBooleanStub::NULL_TYPE |
+      ToBooleanStub::SPEC_OBJECT |
+      ToBooleanStub::STRING);
+  if (expected_input_types_.ContainsAnyOf(tagged_types)) {
+    return Representation::Tagged();
+  } else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
+    return Representation::Double();
+  } else if (expected_input_types_.Contains(ToBooleanStub::SMI)) {
+    return Representation::Integer32();
+  } else {
+    return Representation::None();
+  }
+}
+
+
 void HCompareMap::PrintDataTo(StringStream* stream) {
   value()->PrintNameTo(stream);
   stream->Add(" (%p)", *map());
@@ -1339,15 +1433,11 @@ void HPhi::InitRealUses(int phi_id) {
   for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
     HValue* value = it.value();
     if (!value->IsPhi()) {
-      Representation rep = value->ObservedInputRepresentation(it.index());
+      Representation rep = value->observed_input_representation(it.index());
       non_phi_uses_[rep.kind()] += value->LoopWeight();
       if (FLAG_trace_representation) {
-        PrintF("%d %s is used by %d %s as %s\n",
-               this->id(),
-               this->Mnemonic(),
-               value->id(),
-               value->Mnemonic(),
-               rep.Mnemonic());
+        PrintF("#%d Phi is used by real #%d %s as %s\n",
+               id(), value->id(), value->Mnemonic(), rep.Mnemonic());
       }
     }
   }
@@ -1356,11 +1446,8 @@ void HPhi::InitRealUses(int phi_id) {
 
 void HPhi::AddNonPhiUsesFrom(HPhi* other) {
   if (FLAG_trace_representation) {
-    PrintF("adding to %d %s uses of %d %s: i%d d%d t%d\n",
-           this->id(),
-           this->Mnemonic(),
-           other->id(),
-           other->Mnemonic(),
+    PrintF("adding to #%d Phi uses of #%d Phi: i%d d%d t%d\n",
+           id(), other->id(),
            other->non_phi_uses_[Representation::kInteger32],
            other->non_phi_uses_[Representation::kDouble],
            other->non_phi_uses_[Representation::kTagged]);
@@ -1379,9 +1466,20 @@ void HPhi::AddIndirectUsesTo(int* dest) {
 }
 
 
-void HPhi::ResetInteger32Uses() {
-  non_phi_uses_[Representation::kInteger32] = 0;
-  indirect_uses_[Representation::kInteger32] = 0;
+void HSimulate::MergeInto(HSimulate* other) {
+  for (int i = 0; i < values_.length(); ++i) {
+    HValue* value = values_[i];
+    if (HasAssignedIndexAt(i)) {
+      other->AddAssignedValue(GetAssignedIndexAt(i), value);
+    } else {
+      if (other->pop_count_ > 0) {
+        other->pop_count_--;
+      } else {
+        other->AddPushedValue(value);
+      }
+    }
+  }
+  other->pop_count_ += pop_count();
 }
 
 
@@ -1390,7 +1488,7 @@ void HSimulate::PrintDataTo(StringStream* stream) {
   if (pop_count_ > 0) stream->Add(" pop %d", pop_count_);
   if (values_.length() > 0) {
     if (pop_count_ > 0) stream->Add(" /");
-    for (int i = 0; i < values_.length(); ++i) {
+    for (int i = values_.length() - 1; i >= 0; --i) {
       if (i > 0) stream->Add(",");
       if (HasAssignedIndexAt(i)) {
         stream->Add(" var[%d] = ", GetAssignedIndexAt(i));
@@ -1429,7 +1527,6 @@ HConstant::HConstant(Handle<Object> handle, Representation r)
     : handle_(handle),
       has_int32_value_(false),
       has_double_value_(false) {
-  set_representation(r);
   SetFlag(kUseGVN);
   if (handle_->IsNumber()) {
     double n = handle_->Number();
@@ -1438,6 +1535,16 @@ HConstant::HConstant(Handle<Object> handle, Representation r)
     double_value_ = n;
     has_double_value_ = true;
   }
+  if (r.IsNone()) {
+    if (has_int32_value_) {
+      r = Representation::Integer32();
+    } else if (has_double_value_) {
+      r = Representation::Double();
+    } else {
+      r = Representation::Tagged();
+    }
+  }
+  set_representation(r);
 }
 
 
@@ -1536,6 +1643,52 @@ void HBinaryOperation::PrintDataTo(StringStream* stream) {
 }
 
 
+void HBinaryOperation::InferRepresentation(HInferRepresentation* h_infer) {
+  ASSERT(CheckFlag(kFlexibleRepresentation));
+  Representation new_rep = RepresentationFromInputs();
+  UpdateRepresentation(new_rep, h_infer, "inputs");
+  // When the operation has information about its own output type, don't look
+  // at uses.
+  if (!observed_output_representation_.IsNone()) return;
+  new_rep = RepresentationFromUses();
+  UpdateRepresentation(new_rep, h_infer, "uses");
+}
+
+
+Representation HBinaryOperation::RepresentationFromInputs() {
+  // Determine the worst case of observed input representations and
+  // the currently assumed output representation.
+  Representation rep = representation();
+  if (observed_output_representation_.is_more_general_than(rep)) {
+    rep = observed_output_representation_;
+  }
+  for (int i = 1; i <= 2; ++i) {
+    Representation input_rep = observed_input_representation(i);
+    if (input_rep.is_more_general_than(rep)) rep = input_rep;
+  }
+  // If any of the actual input representation is more general than what we
+  // have so far but not Tagged, use that representation instead.
+  Representation left_rep = left()->representation();
+  Representation right_rep = right()->representation();
+
+  if (left_rep.is_more_general_than(rep) &&
+      left()->CheckFlag(kFlexibleRepresentation)) {
+    rep = left_rep;
+  }
+  if (right_rep.is_more_general_than(rep) &&
+      right()->CheckFlag(kFlexibleRepresentation)) {
+    rep = right_rep;
+  }
+  return rep;
+}
+
+
+void HBinaryOperation::AssumeRepresentation(Representation r) {
+  set_observed_input_representation(r, r);
+  HValue::AssumeRepresentation(r);
+}
+
+
 Range* HBitwise::InferRange(Zone* zone) {
   if (op() == Token::BIT_XOR) return HValue::InferRange(zone);
   const int32_t kDefaultMask = static_cast<int32_t>(0xffffffff);
@@ -1667,9 +1820,19 @@ void HGoto::PrintDataTo(StringStream* stream) {
 }
 
 
-void HCompareIDAndBranch::SetInputRepresentation(Representation r) {
-  input_representation_ = r;
-  if (r.IsDouble()) {
+void HCompareIDAndBranch::InferRepresentation(HInferRepresentation* h_infer) {
+  Representation rep = Representation::None();
+  Representation left_rep = left()->representation();
+  Representation right_rep = right()->representation();
+  bool observed_integers =
+      observed_input_representation(0).IsInteger32() &&
+      observed_input_representation(1).IsInteger32();
+  bool inputs_are_not_doubles =
+      !left_rep.IsDouble() && !right_rep.IsDouble();
+  if (observed_integers && inputs_are_not_doubles) {
+    rep = Representation::Integer32();
+  } else {
+    rep = Representation::Double();
     // According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, ===
     // and !=) have special handling of undefined, e.g. undefined == undefined
     // is 'true'. Relational comparisons have a different semantic, first
@@ -1686,9 +1849,8 @@ void HCompareIDAndBranch::SetInputRepresentation(Representation r) {
     if (!Token::IsOrderedRelationalCompareOp(token_)) {
       SetFlag(kDeoptimizeOnUndefined);
     }
-  } else {
-    ASSERT(r.IsInteger32());
   }
+  ChangeRepresentation(rep);
 }
 
 
@@ -2451,7 +2613,41 @@ void HBitwise::PrintDataTo(StringStream* stream) {
 }
 
 
-Representation HPhi::InferredRepresentation() {
+void HPhi::InferRepresentation(HInferRepresentation* h_infer) {
+  ASSERT(CheckFlag(kFlexibleRepresentation));
+  // If there are non-Phi uses, and all of them have observed the same
+  // representation, than that's what this Phi is going to use.
+  Representation new_rep = RepresentationObservedByAllNonPhiUses();
+  if (!new_rep.IsNone()) {
+    UpdateRepresentation(new_rep, h_infer, "unanimous use observations");
+    return;
+  }
+  new_rep = RepresentationFromInputs();
+  UpdateRepresentation(new_rep, h_infer, "inputs");
+  new_rep = RepresentationFromUses();
+  UpdateRepresentation(new_rep, h_infer, "uses");
+  new_rep = RepresentationFromUseRequirements();
+  UpdateRepresentation(new_rep, h_infer, "use requirements");
+}
+
+
+Representation HPhi::RepresentationObservedByAllNonPhiUses() {
+  int non_phi_use_count = 0;
+  for (int i = Representation::kInteger32;
+       i < Representation::kNumRepresentations; ++i) {
+    non_phi_use_count += non_phi_uses_[i];
+  }
+  if (non_phi_use_count <= 1) return Representation::None();
+  for (int i = 0; i < Representation::kNumRepresentations; ++i) {
+    if (non_phi_uses_[i] == non_phi_use_count) {
+      return Representation::FromKind(static_cast<Representation::Kind>(i));
+    }
+  }
+  return Representation::None();
+}
+
+
+Representation HPhi::RepresentationFromInputs() {
   bool double_occurred = false;
   bool int32_occurred = false;
   for (int i = 0; i < OperandCount(); ++i) {
@@ -2460,6 +2656,7 @@ Representation HPhi::InferredRepresentation() {
       HPhi* hint_value = HUnknownOSRValue::cast(value)->incoming_value();
       if (hint_value != NULL) {
         Representation hint = hint_value->representation();
+        if (hint.IsTagged()) return hint;
         if (hint.IsDouble()) double_occurred = true;
         if (hint.IsInteger32()) int32_occurred = true;
       }
@@ -2478,7 +2675,9 @@ Representation HPhi::InferredRepresentation() {
           return Representation::Tagged();
         }
       } else {
-        return Representation::Tagged();
+        if (value->IsPhi() && !IsConvertibleToInteger()) {
+          return Representation::Tagged();
+        }
       }
     }
   }
@@ -2491,6 +2690,37 @@ Representation HPhi::InferredRepresentation() {
 }
 
 
+Representation HPhi::RepresentationFromUseRequirements() {
+  Representation all_uses_require = Representation::None();
+  bool all_uses_require_the_same = true;
+  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
+    // We check for observed_input_representation elsewhere.
+    Representation use_rep =
+        it.value()->RequiredInputRepresentation(it.index());
+    // No useful info from this use -> look at the next one.
+    if (use_rep.IsNone()) {
+      continue;
+    }
+    if (use_rep.Equals(all_uses_require)) {
+      continue;
+    }
+    // This use's representation contradicts what we've seen so far.
+    if (!all_uses_require.IsNone()) {
+      ASSERT(!use_rep.Equals(all_uses_require));
+      all_uses_require_the_same = false;
+      break;
+    }
+    // Otherwise, initialize observed representation.
+    all_uses_require = use_rep;
+  }
+  if (all_uses_require_the_same) {
+    return all_uses_require;
+  }
+
+  return Representation::None();
+}
+
+
 // Node-specific verification code is only included in debug mode.
 #ifdef DEBUG
 
index d11835452c72d7024f2a38bb49a854eba7ce45f1..e5290783d5a858aef51c860bb5fdc2e19d220401 100644 (file)
@@ -45,6 +45,7 @@ namespace internal {
 // Forward declarations.
 class HBasicBlock;
 class HEnvironment;
+class HInferRepresentation;
 class HInstruction;
 class HLoopInformation;
 class HValue;
@@ -308,9 +309,9 @@ class Representation {
  public:
   enum Kind {
     kNone,
-    kTagged,
-    kDouble,
     kInteger32,
+    kDouble,
+    kTagged,
     kExternal,
     kNumRepresentations
   };
@@ -323,10 +324,18 @@ class Representation {
   static Representation Double() { return Representation(kDouble); }
   static Representation External() { return Representation(kExternal); }
 
+  static Representation FromKind(Kind kind) { return Representation(kind); }
+
   bool Equals(const Representation& other) {
     return kind_ == other.kind_;
   }
 
+  bool is_more_general_than(const Representation& other) {
+    ASSERT(kind_ != kExternal);
+    ASSERT(other.kind_ != kExternal);
+    return kind_ > other.kind_;
+  }
+
   Kind kind() const { return static_cast<Kind>(kind_); }
   bool IsNone() const { return kind_ == kNone; }
   bool IsTagged() const { return kind_ == kTagged; }
@@ -629,13 +638,15 @@ class HValue: public ZoneObject {
   virtual bool EmitAtUses() { return false; }
   Representation representation() const { return representation_; }
   void ChangeRepresentation(Representation r) {
-    // Representation was already set and is allowed to be changed.
-    ASSERT(!r.IsNone());
     ASSERT(CheckFlag(kFlexibleRepresentation));
     RepresentationChanged(r);
     representation_ = r;
+    if (r.IsTagged()) {
+      // Tagged is the bottom of the lattice, don't go any further.
+      ClearFlag(kFlexibleRepresentation);
+    }
   }
-  void AssumeRepresentation(Representation r);
+  virtual void AssumeRepresentation(Representation r);
 
   virtual bool IsConvertibleToInteger() const { return true; }
 
@@ -733,16 +744,11 @@ class HValue: public ZoneObject {
   void ComputeInitialRange(Zone* zone);
 
   // Representation helpers.
-  virtual Representation RequiredInputRepresentation(int index) = 0;
-
-  virtual Representation InferredRepresentation() {
-    return representation();
-  }
-
-  // Type feedback access.
-  virtual Representation ObservedInputRepresentation(int index) {
-    return RequiredInputRepresentation(index);
+  virtual Representation observed_input_representation(int index) {
+    return Representation::None();
   }
+  virtual Representation RequiredInputRepresentation(int index) = 0;
+  virtual void InferRepresentation(HInferRepresentation* h_infer);
 
   // This gives the instruction an opportunity to replace itself with an
   // instruction that does the same in some better way.  To replace an
@@ -790,7 +796,18 @@ class HValue: public ZoneObject {
     UNREACHABLE();
     return false;
   }
+
+  virtual Representation RepresentationFromInputs() {
+    return representation();
+  }
+  Representation RepresentationFromUses();
+  virtual void UpdateRepresentation(Representation new_rep,
+                                    HInferRepresentation* h_infer,
+                                    const char* reason);
+  void AddDependantsToWorklist(HInferRepresentation* h_infer);
+
   virtual void RepresentationChanged(Representation to) { }
+
   virtual Range* InferRange(Zone* zone);
   virtual void DeleteFromGraph() = 0;
   virtual void InternalSetOperandAt(int index, HValue* value) = 0;
@@ -800,7 +817,6 @@ class HValue: public ZoneObject {
   }
 
   void set_representation(Representation r) {
-    // Representation is set-once.
     ASSERT(representation_.IsNone() && !r.IsNone());
     representation_ = r;
   }
@@ -1113,6 +1129,7 @@ class HBranch: public HUnaryControlInstruction {
   virtual Representation RequiredInputRepresentation(int index) {
     return Representation::None();
   }
+  virtual Representation observed_input_representation(int index);
 
   ToBooleanStub::Types expected_input_types() const {
     return expected_input_types_;
@@ -1317,14 +1334,24 @@ class HClampToUint8: public HUnaryOperation {
 };
 
 
+enum RemovableSimulate {
+  REMOVABLE_SIMULATE,
+  FIXED_SIMULATE
+};
+
+
 class HSimulate: public HInstruction {
  public:
-  HSimulate(BailoutId ast_id, int pop_count, Zone* zone)
+  HSimulate(BailoutId ast_id,
+            int pop_count,
+            Zone* zone,
+            RemovableSimulate removable)
       : ast_id_(ast_id),
         pop_count_(pop_count),
         values_(2, zone),
         assigned_indexes_(2, zone),
-        zone_(zone) {}
+        zone_(zone),
+        removable_(removable) {}
   virtual ~HSimulate() {}
 
   virtual void PrintDataTo(StringStream* stream);
@@ -1358,6 +1385,9 @@ class HSimulate: public HInstruction {
     return Representation::None();
   }
 
+  void MergeInto(HSimulate* other);
+  bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
+
   DECLARE_CONCRETE_INSTRUCTION(Simulate)
 
 #ifdef DEBUG
@@ -1384,6 +1414,7 @@ class HSimulate: public HInstruction {
   ZoneList<HValue*> values_;
   ZoneList<int> assigned_indexes_;
   Zone* zone_;
+  RemovableSimulate removable_;
 };
 
 
@@ -2010,6 +2041,9 @@ class HBitNot: public HUnaryOperation {
   virtual Representation RequiredInputRepresentation(int index) {
     return Representation::Integer32();
   }
+  virtual Representation observed_input_representation(int index) {
+    return Representation::Integer32();
+  }
   virtual HType CalculateInferredType();
 
   virtual HValue* Canonicalize();
@@ -2037,7 +2071,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> {
         set_representation(Representation::Integer32());
         break;
       case kMathAbs:
-        set_representation(Representation::Tagged());
+        // Not setting representation here: it is None intentionally.
         SetFlag(kFlexibleRepresentation);
         SetGVNFlag(kChangesNewSpacePromotion);
         break;
@@ -2217,6 +2251,7 @@ class HCheckMaps: public HTemplateInstruction<2> {
   virtual Representation RequiredInputRepresentation(int index) {
     return Representation::Tagged();
   }
+
   virtual void PrintDataTo(StringStream* stream);
   virtual HType CalculateInferredType();
 
@@ -2444,13 +2479,15 @@ class HPhi: public HValue {
       indirect_uses_[i] = 0;
     }
     ASSERT(merged_index >= 0);
-    set_representation(Representation::Tagged());
     SetFlag(kFlexibleRepresentation);
   }
 
-  virtual Representation InferredRepresentation();
+  virtual Representation RepresentationFromInputs();
 
   virtual Range* InferRange(Zone* zone);
+  virtual void InferRepresentation(HInferRepresentation* h_infer);
+  Representation RepresentationObservedByAllNonPhiUses();
+  Representation RepresentationFromUseRequirements();
   virtual Representation RequiredInputRepresentation(int index) {
     return representation();
   }
@@ -2514,14 +2551,17 @@ class HPhi: public HValue {
   bool AllOperandsConvertibleToInteger() {
     for (int i = 0; i < OperandCount(); ++i) {
       if (!OperandAt(i)->IsConvertibleToInteger()) {
+        if (FLAG_trace_representation) {
+          HValue* input = OperandAt(i);
+          PrintF("#%d %s: Input #%d %s at %d is NCTI\n",
+                 id(), Mnemonic(), input->id(), input->Mnemonic(), i);
+        }
         return false;
       }
     }
     return true;
   }
 
-  void ResetInteger32Uses();
-
  protected:
   virtual void DeleteFromGraph();
   virtual void InternalSetOperandAt(int index, HValue* value) {
@@ -2704,11 +2744,14 @@ class HConstant: public HTemplateInstruction<0> {
 
 class HBinaryOperation: public HTemplateInstruction<3> {
  public:
-  HBinaryOperation(HValue* context, HValue* left, HValue* right) {
+  HBinaryOperation(HValue* context, HValue* left, HValue* right)
+      : observed_output_representation_(Representation::None()) {
     ASSERT(left != NULL && right != NULL);
     SetOperandAt(0, context);
     SetOperandAt(1, left);
     SetOperandAt(2, right);
+    observed_input_representation_[0] = Representation::None();
+    observed_input_representation_[1] = Representation::None();
   }
 
   HValue* context() { return OperandAt(0); }
@@ -2727,11 +2770,34 @@ class HBinaryOperation: public HTemplateInstruction<3> {
     return right();
   }
 
+  void set_observed_input_representation(Representation left,
+                                         Representation right) {
+    observed_input_representation_[0] = left;
+    observed_input_representation_[1] = right;
+  }
+
+  virtual void initialize_output_representation(Representation observed) {
+    observed_output_representation_ = observed;
+  }
+
+  virtual Representation observed_input_representation(int index) {
+    if (index == 0) return Representation::Tagged();
+    return observed_input_representation_[index - 1];
+  }
+
+  virtual void InferRepresentation(HInferRepresentation* h_infer);
+  virtual Representation RepresentationFromInputs();
+  virtual void AssumeRepresentation(Representation r);
+
   virtual bool IsCommutative() const { return false; }
 
   virtual void PrintDataTo(StringStream* stream);
 
   DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
+
+ private:
+  Representation observed_input_representation_[2];
+  Representation observed_output_representation_;
 };
 
 
@@ -2901,6 +2967,9 @@ class HBoundsCheck: public HTemplateInstruction<2> {
     }
     return Representation::Integer32();
   }
+  virtual Representation observed_input_representation(int index) {
+    return Representation::Integer32();
+  }
 
   virtual void PrintDataTo(StringStream* stream);
 
@@ -2919,12 +2988,9 @@ class HBitwiseBinaryOperation: public HBinaryOperation {
  public:
   HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right)
       : HBinaryOperation(context, left, right) {
-    set_representation(Representation::Tagged());
     SetFlag(kFlexibleRepresentation);
+    SetFlag(kTruncatingToInt32);
     SetAllSideEffects();
-    observed_input_representation_[0] = Representation::Tagged();
-    observed_input_representation_[1] = Representation::None();
-    observed_input_representation_[2] = Representation::None();
   }
 
   virtual Representation RequiredInputRepresentation(int index) {
@@ -2937,28 +3003,32 @@ class HBitwiseBinaryOperation: public HBinaryOperation {
     if (!to.IsTagged()) {
       ASSERT(to.IsInteger32());
       ClearAllSideEffects();
-      SetFlag(kTruncatingToInt32);
       SetFlag(kUseGVN);
+    } else {
+      SetAllSideEffects();
+      ClearFlag(kUseGVN);
     }
   }
 
-  virtual HType CalculateInferredType();
-
-  virtual Representation ObservedInputRepresentation(int index) {
-    return observed_input_representation_[index];
+  virtual void UpdateRepresentation(Representation new_rep,
+                                    HInferRepresentation* h_infer,
+                                    const char* reason) {
+    // We only generate either int32 or generic tagged bitwise operations.
+    if (new_rep.IsDouble()) new_rep = Representation::Integer32();
+    HValue::UpdateRepresentation(new_rep, h_infer, reason);
   }
 
-  void InitializeObservedInputRepresentation(Representation r) {
-    observed_input_representation_[1] = r;
-    observed_input_representation_[2] = r;
+  virtual void initialize_output_representation(Representation observed) {
+    if (observed.IsDouble()) observed = Representation::Integer32();
+    HBinaryOperation::initialize_output_representation(observed);
   }
 
+  virtual HType CalculateInferredType();
+
   DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
 
  private:
   virtual bool IsDeletable() const { return true; }
-
-  Representation observed_input_representation_[3];
 };
 
 
@@ -2991,13 +3061,15 @@ class HArithmeticBinaryOperation: public HBinaryOperation {
  public:
   HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
       : HBinaryOperation(context, left, right) {
-    set_representation(Representation::Tagged());
-    SetFlag(kFlexibleRepresentation);
     SetAllSideEffects();
+    SetFlag(kFlexibleRepresentation);
   }
 
   virtual void RepresentationChanged(Representation to) {
-    if (!to.IsTagged()) {
+    if (to.IsTagged()) {
+      SetAllSideEffects();
+      ClearFlag(kUseGVN);
+    } else {
       ClearAllSideEffects();
       SetFlag(kUseGVN);
     }
@@ -3010,13 +3082,6 @@ class HArithmeticBinaryOperation: public HBinaryOperation {
         : representation();
   }
 
-  virtual Representation InferredRepresentation() {
-    if (left()->representation().Equals(right()->representation())) {
-      return left()->representation();
-    }
-    return HValue::InferredRepresentation();
-  }
-
  private:
   virtual bool IsDeletable() const { return true; }
 };
@@ -3035,11 +3100,9 @@ class HCompareGeneric: public HBinaryOperation {
   }
 
   virtual Representation RequiredInputRepresentation(int index) {
-    return Representation::Tagged();
-  }
-
-  Representation GetInputRepresentation() const {
-    return Representation::Tagged();
+    return index == 0
+        ? Representation::Tagged()
+        : representation();
   }
 
   Token::Value token() const { return token_; }
@@ -3058,6 +3121,7 @@ class HCompareIDAndBranch: public HTemplateControlInstruction<2, 2> {
  public:
   HCompareIDAndBranch(HValue* left, HValue* right, Token::Value token)
       : token_(token) {
+    SetFlag(kFlexibleRepresentation);
     ASSERT(Token::IsCompareOp(token));
     SetOperandAt(0, left);
     SetOperandAt(1, right);
@@ -3067,20 +3131,26 @@ class HCompareIDAndBranch: public HTemplateControlInstruction<2, 2> {
   HValue* right() { return OperandAt(1); }
   Token::Value token() const { return token_; }
 
-  void SetInputRepresentation(Representation r);
-  Representation GetInputRepresentation() const {
-    return input_representation_;
+  void set_observed_input_representation(Representation left,
+                                         Representation right) {
+      observed_input_representation_[0] = left;
+      observed_input_representation_[1] = right;
   }
 
+  virtual void InferRepresentation(HInferRepresentation* h_infer);
+
   virtual Representation RequiredInputRepresentation(int index) {
-    return input_representation_;
+    return representation();
+  }
+  virtual Representation observed_input_representation(int index) {
+    return observed_input_representation_[index];
   }
   virtual void PrintDataTo(StringStream* stream);
 
   DECLARE_CONCRETE_INSTRUCTION(CompareIDAndBranch)
 
  private:
-  Representation input_representation_;
+  Representation observed_input_representation_[2];
   Token::Value token_;
 };
 
@@ -3141,6 +3211,9 @@ class HIsNilAndBranch: public HUnaryControlInstruction {
   virtual Representation RequiredInputRepresentation(int index) {
     return Representation::Tagged();
   }
+  virtual Representation observed_input_representation(int index) {
+    return Representation::Tagged();
+  }
 
   DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch)
 
@@ -3418,6 +3491,9 @@ class HPower: public HTemplateInstruction<2> {
       ? Representation::Double()
       : Representation::None();
   }
+  virtual Representation observed_input_representation(int index) {
+    return RequiredInputRepresentation(index);
+  }
 
   DECLARE_CONCRETE_INSTRUCTION(Power)
 
@@ -3603,14 +3679,19 @@ class HMathMinMax: public HArithmeticBinaryOperation {
         operation_(op) { }
 
   virtual Representation RequiredInputRepresentation(int index) {
-      return index == 0
-          ? Representation::Tagged()
-          : representation();
-    }
+    return index == 0 ? Representation::Tagged()
+                      : representation();
+  }
 
-  virtual Representation InferredRepresentation() {
-    if (left()->representation().IsInteger32() &&
-        right()->representation().IsInteger32()) {
+  virtual Representation observed_input_representation(int index) {
+    return RequiredInputRepresentation(index);
+  }
+
+  virtual Representation RepresentationFromInputs() {
+    Representation left_rep = left()->representation();
+    Representation right_rep = right()->representation();
+    if ((left_rep.IsNone() || left_rep.IsInteger32()) &&
+        (right_rep.IsNone() || right_rep.IsInteger32())) {
       return Representation::Integer32();
     }
     return Representation::Double();
@@ -4336,6 +4417,10 @@ class HLoadKeyed
     return Representation::None();
   }
 
+  virtual Representation observed_input_representation(int index) {
+    return RequiredInputRepresentation(index);
+  }
+
   virtual void PrintDataTo(StringStream* stream);
 
   bool RequiresHoleCheck() const;
@@ -4527,6 +4612,12 @@ class HStoreKeyed
     } else {
       SetGVNFlag(kChangesArrayElements);
     }
+
+    // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
+    if (elements_kind >= EXTERNAL_BYTE_ELEMENTS &&
+        elements_kind <= EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+      SetFlag(kTruncatingToInt32);
+    }
   }
 
   virtual Representation RequiredInputRepresentation(int index) {
@@ -4552,6 +4643,19 @@ class HStoreKeyed
   bool is_external() const {
     return IsExternalArrayElementsKind(elements_kind());
   }
+
+  virtual Representation observed_input_representation(int index) {
+    if (index < 2) return RequiredInputRepresentation(index);
+    if (IsDoubleOrFloatElementsKind(elements_kind())) {
+      return Representation::Double();
+    }
+    if (is_external()) {
+      return Representation::Integer32();
+    }
+    // For fast object elements kinds, don't assume anything.
+    return Representation::None();
+  }
+
   HValue* elements() { return OperandAt(0); }
   HValue* key() { return OperandAt(1); }
   HValue* value() { return OperandAt(2); }
index 0a25bb039ae0ffeb4d62ee77fa6d8fbca69484f0..ea3a070a16bcd469fda5c6eb23198d2162e24518 100644 (file)
@@ -133,7 +133,8 @@ HDeoptimize* HBasicBlock::CreateDeoptimize(
 }
 
 
-HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id) {
+HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id,
+                                       RemovableSimulate removable) {
   ASSERT(HasEnvironment());
   HEnvironment* environment = last_environment();
   ASSERT(ast_id.IsNone() ||
@@ -142,8 +143,12 @@ HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id) {
   int push_count = environment->push_count();
   int pop_count = environment->pop_count();
 
-  HSimulate* instr = new(zone()) HSimulate(ast_id, pop_count, zone());
-  for (int i = push_count - 1; i >= 0; --i) {
+  HSimulate* instr =
+      new(zone()) HSimulate(ast_id, pop_count, zone(), removable);
+  // Order of pushed values: newest (top of stack) first. This allows
+  // HSimulate::MergeInto() to easily append additional pushed values
+  // that are older (from further down the stack).
+  for (int i = 0; i < push_count; ++i) {
     instr->AddPushedValue(environment->ExpressionStackAt(i));
   }
   for (int i = 0; i < environment->assigned_variables()->length(); ++i) {
@@ -1291,7 +1296,7 @@ void HRangeAnalysis::Analyze(HBasicBlock* block) {
 void HRangeAnalysis::InferControlFlowRange(HCompareIDAndBranch* test,
                                            HBasicBlock* dest) {
   ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
-  if (test->GetInputRepresentation().IsInteger32()) {
+  if (test->representation().IsInteger32()) {
     Token::Value op = test->token();
     if (test->SecondSuccessor() == dest) {
       op = Token::NegateCompareOp(op);
@@ -2239,32 +2244,8 @@ void HGlobalValueNumberer::AnalyzeGraph() {
 }
 
 
-class HInferRepresentation BASE_EMBEDDED {
- public:
-  explicit HInferRepresentation(HGraph* graph)
-      : graph_(graph),
-        worklist_(8, graph->zone()),
-        in_worklist_(graph->GetMaximumValueID(), graph->zone()) { }
-
-  void Analyze();
-
- private:
-  Representation TryChange(HValue* current);
-  void AddToWorklist(HValue* current);
-  void InferBasedOnInputs(HValue* current);
-  void AddDependantsToWorklist(HValue* current);
-  void InferBasedOnUses(HValue* current);
-
-  Zone* zone() const { return graph_->zone(); }
-
-  HGraph* graph_;
-  ZoneList<HValue*> worklist_;
-  BitVector in_worklist_;
-};
-
-
 void HInferRepresentation::AddToWorklist(HValue* current) {
-  if (current->representation().IsSpecialization()) return;
+  if (current->representation().IsTagged()) return;
   if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return;
   if (in_worklist_.Contains(current->id())) return;
   worklist_.Add(current, zone());
@@ -2272,105 +2253,6 @@ void HInferRepresentation::AddToWorklist(HValue* current) {
 }
 
 
-// This method tries to specialize the representation type of the value
-// given as a parameter. The value is asked to infer its representation type
-// based on its inputs. If the inferred type is more specialized, then this
-// becomes the new representation type of the node.
-void HInferRepresentation::InferBasedOnInputs(HValue* current) {
-  Representation r = current->representation();
-  if (r.IsSpecialization()) return;
-  ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation));
-  Representation inferred = current->InferredRepresentation();
-  if (inferred.IsSpecialization()) {
-    if (FLAG_trace_representation) {
-      PrintF("Changing #%d representation %s -> %s based on inputs\n",
-             current->id(),
-             r.Mnemonic(),
-             inferred.Mnemonic());
-    }
-    current->ChangeRepresentation(inferred);
-    AddDependantsToWorklist(current);
-  }
-}
-
-
-void HInferRepresentation::AddDependantsToWorklist(HValue* value) {
-  for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
-    AddToWorklist(it.value());
-  }
-  for (int i = 0; i < value->OperandCount(); ++i) {
-    AddToWorklist(value->OperandAt(i));
-  }
-}
-
-
-// This method calculates whether specializing the representation of the value
-// given as the parameter has a benefit in terms of less necessary type
-// conversions. If there is a benefit, then the representation of the value is
-// specialized.
-void HInferRepresentation::InferBasedOnUses(HValue* value) {
-  Representation r = value->representation();
-  if (r.IsSpecialization() || value->HasNoUses()) return;
-  ASSERT(value->CheckFlag(HValue::kFlexibleRepresentation));
-  Representation new_rep = TryChange(value);
-  if (!new_rep.IsNone()) {
-    if (!value->representation().Equals(new_rep)) {
-      if (FLAG_trace_representation) {
-        PrintF("Changing #%d representation %s -> %s based on uses\n",
-               value->id(),
-               r.Mnemonic(),
-               new_rep.Mnemonic());
-      }
-      value->ChangeRepresentation(new_rep);
-      AddDependantsToWorklist(value);
-    }
-  }
-}
-
-
-Representation HInferRepresentation::TryChange(HValue* value) {
-  // Array of use counts for each representation.
-  int use_count[Representation::kNumRepresentations] = { 0 };
-
-  for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
-    HValue* use = it.value();
-    Representation rep = use->ObservedInputRepresentation(it.index());
-    if (rep.IsNone()) continue;
-    if (FLAG_trace_representation) {
-      PrintF("%d %s is used by %d %s as %s\n",
-             value->id(),
-             value->Mnemonic(),
-             use->id(),
-             use->Mnemonic(),
-             rep.Mnemonic());
-    }
-    if (use->IsPhi()) HPhi::cast(use)->AddIndirectUsesTo(&use_count[0]);
-    use_count[rep.kind()] += use->LoopWeight();
-  }
-  int tagged_count = use_count[Representation::kTagged];
-  int double_count = use_count[Representation::kDouble];
-  int int32_count = use_count[Representation::kInteger32];
-  int non_tagged_count = double_count + int32_count;
-
-  // If a non-loop phi has tagged uses, don't convert it to untagged.
-  if (value->IsPhi() && !value->block()->IsLoopHeader() && tagged_count > 0) {
-    return Representation::None();
-  }
-
-  // Prefer unboxing over boxing, the latter is more expensive.
-  if (tagged_count > non_tagged_count) return Representation::None();
-
-  // Prefer Integer32 over Double, if possible.
-  if (int32_count > 0 && value->IsConvertibleToInteger()) {
-    return Representation::Integer32();
-  }
-
-  if (double_count > 0) return Representation::Double();
-
-  return Representation::None();
-}
-
-
 void HInferRepresentation::Analyze() {
   HPhase phase("H_Infer representations", graph_);
 
@@ -2421,7 +2303,6 @@ void HInferRepresentation::Analyze() {
          it.Advance()) {
       HPhi* phi = phi_list->at(it.Current());
       phi->set_is_convertible_to_integer(false);
-      phi->ResetInteger32Uses();
     }
   }
 
@@ -2457,8 +2338,74 @@ void HInferRepresentation::Analyze() {
   while (!worklist_.is_empty()) {
     HValue* current = worklist_.RemoveLast();
     in_worklist_.Remove(current->id());
-    InferBasedOnInputs(current);
-    InferBasedOnUses(current);
+    current->InferRepresentation(this);
+  }
+
+  // Lastly: any instruction that we don't have representation information
+  // for defaults to Tagged.
+  for (int i = 0; i < graph_->blocks()->length(); ++i) {
+    HBasicBlock* block = graph_->blocks()->at(i);
+    const ZoneList<HPhi*>* phis = block->phis();
+    for (int j = 0; j < phis->length(); ++j) {
+      HPhi* phi = phis->at(j);
+      if (phi->representation().IsNone()) {
+        phi->ChangeRepresentation(Representation::Tagged());
+      }
+    }
+    for (HInstruction* current = block->first();
+         current != NULL; current = current->next()) {
+      if (current->representation().IsNone() &&
+          current->CheckFlag(HInstruction::kFlexibleRepresentation)) {
+        current->ChangeRepresentation(Representation::Tagged());
+      }
+    }
+  }
+}
+
+
+void HGraph::MergeRemovableSimulates() {
+  for (int i = 0; i < blocks()->length(); ++i) {
+    HBasicBlock* block = blocks()->at(i);
+    // Always reset the folding candidate at the start of a block.
+    HSimulate* folding_candidate = NULL;
+    // Nasty heuristic: Never remove the first simulate in a block. This
+    // just so happens to have a beneficial effect on register allocation.
+    bool first = true;
+    for (HInstruction* current = block->first();
+         current != NULL; current = current->next()) {
+      if (current->IsLeaveInlined()) {
+        // Never fold simulates from inlined environments into simulates
+        // in the outer environment.
+        // (Before each HEnterInlined, there is a non-foldable HSimulate
+        // anyway, so we get the barrier in the other direction for free.)
+        if (folding_candidate != NULL) {
+          folding_candidate->DeleteAndReplaceWith(NULL);
+        }
+        folding_candidate = NULL;
+        continue;
+      }
+      // If we have an HSimulate and a candidate, perform the folding.
+      if (!current->IsSimulate()) continue;
+      if (first) {
+        first = false;
+        continue;
+      }
+      HSimulate* current_simulate = HSimulate::cast(current);
+      if (folding_candidate != NULL) {
+        folding_candidate->MergeInto(current_simulate);
+        folding_candidate->DeleteAndReplaceWith(NULL);
+        folding_candidate = NULL;
+      }
+      // Check if the current simulate is a candidate for folding.
+      if (current_simulate->previous()->HasObservableSideEffects() &&
+          !current_simulate->next()->IsSimulate()) {
+        continue;
+      }
+      if (!current_simulate->is_candidate_for_removal()) {
+        continue;
+      }
+      folding_candidate = current_simulate;
+    }
   }
 }
 
@@ -2553,7 +2500,6 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value,
   } else {
     next = HInstruction::cast(use_value);
   }
-
   // For constants we try to make the representation change at compile
   // time. When a representation change is not possible without loss of
   // information we treat constants like normal instructions and insert the
@@ -2565,7 +2511,7 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value,
   if (value->IsConstant()) {
     HConstant* constant = HConstant::cast(value);
     // Try to create a new copy of the constant with the new representation.
-    new_value = is_truncating
+    new_value = (is_truncating && to.IsInteger32())
         ? constant->CopyToTruncatedInt32(zone())
         : constant->CopyToRepresentation(to, zone());
   }
@@ -2625,9 +2571,23 @@ void HGraph::InsertRepresentationChanges() {
     for (int i = 0; i < phi_list()->length(); i++) {
       HPhi* phi = phi_list()->at(i);
       if (!phi->CheckFlag(HValue::kTruncatingToInt32)) continue;
-      if (!phi->CheckUsesForFlag(HValue::kTruncatingToInt32)) {
-        phi->ClearFlag(HValue::kTruncatingToInt32);
-        change = true;
+      for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
+        // If a Phi is used as a non-truncating int32 or as a double,
+        // clear its "truncating" flag.
+        HValue* use = it.value();
+        Representation input_representation =
+            use->RequiredInputRepresentation(it.index());
+        if ((input_representation.IsInteger32() &&
+             !use->CheckFlag(HValue::kTruncatingToInt32)) ||
+            input_representation.IsDouble()) {
+          if (FLAG_trace_representation) {
+            PrintF("#%d Phi is not truncating because of #%d %s\n",
+                   phi->id(), it.value()->id(), it.value()->Mnemonic());
+          }
+          phi->ClearFlag(HValue::kTruncatingToInt32);
+          change = true;
+          break;
+        }
       }
     }
   }
@@ -2642,8 +2602,9 @@ void HGraph::InsertRepresentationChanges() {
     // Process normal instructions.
     HInstruction* current = blocks_[i]->first();
     while (current != NULL) {
+      HInstruction* next = current->next();
       InsertRepresentationChangesForValue(current);
-      current = current->next();
+      current = next;
     }
   }
 }
@@ -3038,7 +2999,9 @@ void TestContext::ReturnValue(HValue* value) {
 void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
   ASSERT(!instr->IsControlInstruction());
   owner()->AddInstruction(instr);
-  if (instr->HasObservableSideEffects()) owner()->AddSimulate(ast_id);
+  if (instr->HasObservableSideEffects()) {
+    owner()->AddSimulate(ast_id, REMOVABLE_SIMULATE);
+  }
 }
 
 
@@ -3062,7 +3025,9 @@ void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
   }
   owner()->AddInstruction(instr);
   owner()->Push(instr);
-  if (instr->HasObservableSideEffects()) owner()->AddSimulate(ast_id);
+  if (instr->HasObservableSideEffects()) {
+    owner()->AddSimulate(ast_id, REMOVABLE_SIMULATE);
+  }
 }
 
 
@@ -3094,7 +3059,7 @@ void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
   // this one isn't actually needed (and wouldn't work if it were targeted).
   if (instr->HasObservableSideEffects()) {
     builder->Push(instr);
-    builder->AddSimulate(ast_id);
+    builder->AddSimulate(ast_id, REMOVABLE_SIMULATE);
     builder->Pop();
   }
   BuildBranch(instr);
@@ -3321,6 +3286,11 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) {
   HInferRepresentation rep(this);
   rep.Analyze();
 
+  // Remove HSimulate instructions that have turned out not to be needed
+  // after all by folding them into the following HSimulate.
+  // This must happen after inferring representations.
+  MergeRemovableSimulates();
+
   MarkDeoptimizeOnUndefined();
   InsertRepresentationChanges();
 
@@ -3810,9 +3780,9 @@ HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
 }
 
 
-void HGraphBuilder::AddSimulate(BailoutId ast_id) {
+void HGraphBuilder::AddSimulate(BailoutId ast_id, RemovableSimulate removable) {
   ASSERT(current_block() != NULL);
-  current_block()->AddSimulate(ast_id);
+  current_block()->AddSimulate(ast_id, removable);
 }
 
 
@@ -4169,7 +4139,7 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
                 !clause->label()->IsStringLiteral()) ||
                (switch_type == SMI_SWITCH &&
                 !clause->label()->IsSmiLiteral())) {
-      return Bailout("SwitchStatemnt: mixed label types are not supported");
+      return Bailout("SwitchStatement: mixed label types are not supported");
     }
   }
 
@@ -4223,12 +4193,13 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
           new(zone()) HCompareIDAndBranch(tag_value,
                                           label_value,
                                           Token::EQ_STRICT);
-      compare_->SetInputRepresentation(Representation::Integer32());
+      compare_->set_observed_input_representation(
+          Representation::Integer32(), Representation::Integer32());
       compare = compare_;
     } else {
       compare = new(zone()) HStringCompareAndBranch(context, tag_value,
-                                                     label_value,
-                                                     Token::EQ_STRICT);
+                                                    label_value,
+                                                    Token::EQ_STRICT);
     }
 
     compare->SetSuccessorAt(0, body_block);
@@ -4587,7 +4558,8 @@ void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
   // Check that we still have more keys.
   HCompareIDAndBranch* compare_index =
       new(zone()) HCompareIDAndBranch(index, limit, Token::LT);
-  compare_index->SetInputRepresentation(Representation::Integer32());
+  compare_index->set_observed_input_representation(
+      Representation::Integer32(), Representation::Integer32());
 
   HBasicBlock* loop_body = graph()->CreateBasicBlock();
   HBasicBlock* loop_successor = graph()->CreateBasicBlock();
@@ -4862,7 +4834,7 @@ void HGraphBuilder::VisitLiteral(Literal* expr) {
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
   HConstant* instr =
-      new(zone()) HConstant(expr->handle(), Representation::Tagged());
+      new(zone()) HConstant(expr->handle(), Representation::None());
   return ast_context()->ReturnInstruction(instr, expr->id());
 }
 
@@ -5099,7 +5071,9 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
                                                              map));
             }
             AddInstruction(store);
-            if (store->HasObservableSideEffects()) AddSimulate(key->id());
+            if (store->HasObservableSideEffects()) {
+              AddSimulate(key->id(), REMOVABLE_SIMULATE);
+            }
           } else {
             CHECK_ALIVE(VisitForEffect(value));
           }
@@ -5480,10 +5454,10 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
       // unoptimized code).
       if (instr->HasObservableSideEffects()) {
         if (ast_context()->IsEffect()) {
-          AddSimulate(expr->id());
+          AddSimulate(expr->id(), REMOVABLE_SIMULATE);
         } else {
           Push(value);
-          AddSimulate(expr->id());
+          AddSimulate(expr->id(), REMOVABLE_SIMULATE);
           Drop(1);
         }
       }
@@ -5553,7 +5527,9 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
     Push(value);
     instr->set_position(expr->position());
     AddInstruction(instr);
-    if (instr->HasObservableSideEffects()) AddSimulate(expr->AssignmentId());
+    if (instr->HasObservableSideEffects()) {
+      AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE);
+    }
     return ast_context()->ReturnValue(Pop());
 
   } else {
@@ -5570,7 +5546,7 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
                              &has_side_effects);
     Push(value);
     ASSERT(has_side_effects);  // Stores always have side effects.
-    AddSimulate(expr->AssignmentId());
+    AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE);
     return ast_context()->ReturnValue(Pop());
   }
 }
@@ -5592,7 +5568,9 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
         new(zone()) HStoreGlobalCell(value, cell, lookup.GetPropertyDetails());
     instr->set_position(position);
     AddInstruction(instr);
-    if (instr->HasObservableSideEffects()) AddSimulate(ast_id);
+    if (instr->HasObservableSideEffects()) {
+      AddSimulate(ast_id, REMOVABLE_SIMULATE);
+    }
   } else {
     HValue* context =  environment()->LookupContext();
     HGlobalObject* global_object = new(zone()) HGlobalObject(context);
@@ -5606,7 +5584,7 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
     instr->set_position(position);
     AddInstruction(instr);
     ASSERT(instr->HasObservableSideEffects());
-    if (instr->HasObservableSideEffects()) AddSimulate(ast_id);
+    AddSimulate(ast_id, REMOVABLE_SIMULATE);
   }
 }
 
@@ -5683,7 +5661,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
             new(zone()) HStoreContextSlot(context, var->index(), mode, Top());
         AddInstruction(instr);
         if (instr->HasObservableSideEffects()) {
-          AddSimulate(expr->AssignmentId());
+          AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE);
         }
         break;
       }
@@ -5723,7 +5701,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
         load = BuildLoadNamedGeneric(object, name, prop);
       }
       PushAndAdd(load);
-      if (load->HasObservableSideEffects()) AddSimulate(prop->LoadId());
+      if (load->HasObservableSideEffects()) {
+        AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
+      }
 
       CHECK_ALIVE(VisitForValue(expr->value()));
       HValue* right = Pop();
@@ -5731,7 +5711,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
 
       HInstruction* instr = BuildBinaryOperation(operation, left, right);
       PushAndAdd(instr);
-      if (instr->HasObservableSideEffects()) AddSimulate(operation->id());
+      if (instr->HasObservableSideEffects()) {
+        AddSimulate(operation->id(), REMOVABLE_SIMULATE);
+      }
 
       HInstruction* store;
       if (!monomorphic) {
@@ -5753,7 +5735,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
       // Drop the simulated receiver and value.  Return the value.
       Drop(2);
       Push(instr);
-      if (store->HasObservableSideEffects()) AddSimulate(expr->AssignmentId());
+      if (store->HasObservableSideEffects()) {
+        AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE);
+      }
       return ast_context()->ReturnValue(Pop());
 
     } else {
@@ -5769,7 +5753,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
           false,  // is_store
           &has_side_effects);
       Push(load);
-      if (has_side_effects) AddSimulate(prop->LoadId());
+      if (has_side_effects) AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
 
 
       CHECK_ALIVE(VisitForValue(expr->value()));
@@ -5778,7 +5762,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
 
       HInstruction* instr = BuildBinaryOperation(operation, left, right);
       PushAndAdd(instr);
-      if (instr->HasObservableSideEffects()) AddSimulate(operation->id());
+      if (instr->HasObservableSideEffects()) {
+        AddSimulate(operation->id(), REMOVABLE_SIMULATE);
+      }
 
       expr->RecordTypeFeedback(oracle(), zone());
       HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(),
@@ -5790,7 +5776,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
       Drop(3);
       Push(instr);
       ASSERT(has_side_effects);  // Stores always have side effects.
-      AddSimulate(expr->AssignmentId());
+      AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE);
       return ast_context()->ReturnValue(Pop());
     }
 
@@ -5913,7 +5899,7 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
             context, var->index(), mode, Top());
         AddInstruction(instr);
         if (instr->HasObservableSideEffects()) {
-          AddSimulate(expr->AssignmentId());
+          AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE);
         }
         return ast_context()->ReturnValue(Pop());
       }
@@ -6051,13 +6037,6 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
       case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
       case EXTERNAL_INT_ELEMENTS:
       case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
-        if (!val->representation().IsInteger32()) {
-          val = AddInstruction(new(zone()) HChange(
-              val,
-              Representation::Integer32(),
-              true,  // Truncate to int32.
-              false));  // Don't deoptimize undefined (irrelevant here).
-        }
         break;
       }
       case EXTERNAL_FLOAT_ELEMENTS:
@@ -6678,10 +6657,10 @@ void HGraphBuilder::VisitProperty(Property* expr) {
         &has_side_effects);
     if (has_side_effects) {
       if (ast_context()->IsEffect()) {
-        AddSimulate(expr->id());
+        AddSimulate(expr->id(), REMOVABLE_SIMULATE);
       } else {
         Push(load);
-        AddSimulate(expr->id());
+        AddSimulate(expr->id(), REMOVABLE_SIMULATE);
         Drop(1);
       }
     }
@@ -7989,14 +7968,13 @@ void HGraphBuilder::VisitSub(UnaryOperation* expr) {
   HInstruction* instr =
       new(zone()) HMul(context, value, graph_->GetConstantMinus1());
   TypeInfo info = oracle()->UnaryType(expr);
+  Representation rep = ToRepresentation(info);
   if (info.IsUninitialized()) {
     AddInstruction(new(zone()) HSoftDeoptimize);
     current_block()->MarkAsDeoptimizing();
     info = TypeInfo::Unknown();
   }
-  Representation rep = ToRepresentation(info);
-  TraceRepresentation(expr->op(), info, instr, rep);
-  instr->AssumeRepresentation(rep);
+  HBinaryOperation::cast(instr)->set_observed_input_representation(rep, rep);
   return ast_context()->ReturnInstruction(instr, expr->id());
 }
 
@@ -8085,8 +8063,11 @@ HInstruction* HGraphBuilder::BuildIncrement(bool returns_original_input,
       : graph_->GetConstantMinus1();
   HValue* context = environment()->LookupContext();
   HInstruction* instr = new(zone()) HAdd(context, Top(), delta);
-  TraceRepresentation(expr->op(), info, instr, rep);
+  // We can't insert a simulate here, because it would break deoptimization,
+  // so the HAdd must not have side effects, so we must freeze its
+  // representation.
   instr->AssumeRepresentation(rep);
+  instr->ClearAllSideEffects();
   AddInstruction(instr);
   return instr;
 }
@@ -8160,7 +8141,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
             new(zone()) HStoreContextSlot(context, var->index(), mode, after);
         AddInstruction(instr);
         if (instr->HasObservableSideEffects()) {
-          AddSimulate(expr->AssignmentId());
+          AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE);
         }
         break;
       }
@@ -8201,7 +8182,9 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
         load = BuildLoadNamedGeneric(object, name, prop);
       }
       PushAndAdd(load);
-      if (load->HasObservableSideEffects()) AddSimulate(prop->LoadId());
+      if (load->HasObservableSideEffects()) {
+        AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
+      }
 
       after = BuildIncrement(returns_original_input, expr);
       input = Pop();
@@ -8229,7 +8212,9 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
       // necessary.
       environment()->SetExpressionStackAt(0, after);
       if (returns_original_input) environment()->SetExpressionStackAt(1, input);
-      if (store->HasObservableSideEffects()) AddSimulate(expr->AssignmentId());
+      if (store->HasObservableSideEffects()) {
+        AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE);
+      }
 
     } else {
       // Keyed property.
@@ -8246,7 +8231,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
           false,  // is_store
           &has_side_effects);
       Push(load);
-      if (has_side_effects) AddSimulate(prop->LoadId());
+      if (has_side_effects) AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
 
       after = BuildIncrement(returns_original_input, expr);
       input = Pop();
@@ -8264,7 +8249,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
       environment()->SetExpressionStackAt(0, after);
       if (returns_original_input) environment()->SetExpressionStackAt(1, input);
       ASSERT(has_side_effects);  // Stores always have side effects.
-      AddSimulate(expr->AssignmentId());
+      AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE);
     }
   }
 
@@ -8345,16 +8330,22 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
                                                   HValue* left,
                                                   HValue* right) {
   HValue* context = environment()->LookupContext();
-  TypeInfo info = oracle()->BinaryType(expr);
-  if (info.IsUninitialized()) {
+  TypeInfo left_info, right_info, result_info, combined_info;
+  oracle()->BinaryType(expr, &left_info, &right_info, &result_info);
+  Representation left_rep = ToRepresentation(left_info);
+  Representation right_rep = ToRepresentation(right_info);
+  Representation result_rep = ToRepresentation(result_info);
+  if (left_info.IsUninitialized()) {
+    // Can't have initialized one but not the other.
+    ASSERT(right_info.IsUninitialized());
     AddInstruction(new(zone()) HSoftDeoptimize);
     current_block()->MarkAsDeoptimizing();
-    info = TypeInfo::Unknown();
+    left_info = right_info = TypeInfo::Unknown();
   }
   HInstruction* instr = NULL;
   switch (expr->op()) {
     case Token::ADD:
-      if (info.IsString()) {
+      if (left_info.IsString() && right_info.IsString()) {
         AddInstruction(new(zone()) HCheckNonSmi(left));
         AddInstruction(HCheckInstanceType::NewIsString(left, zone()));
         AddInstruction(new(zone()) HCheckNonSmi(right));
@@ -8382,7 +8373,7 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
       break;
     case Token::BIT_OR: {
       HValue* operand, *shift_amount;
-      if (info.IsInteger32() &&
+      if (left_info.IsInteger32() && right_info.IsInteger32() &&
           MatchRotateRight(left, right, &operand, &shift_amount)) {
         instr = new(zone()) HRor(context, operand, shift_amount);
       } else {
@@ -8407,23 +8398,11 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
       UNREACHABLE();
   }
 
-  // If we hit an uninitialized binary op stub we will get type info
-  // for a smi operation. If one of the operands is a constant string
-  // do not generate code assuming it is a smi operation.
-  if (info.IsSmi() &&
-      ((left->IsConstant() && HConstant::cast(left)->handle()->IsString()) ||
-       (right->IsConstant() && HConstant::cast(right)->handle()->IsString()))) {
-    return instr;
-  }
-  Representation rep = ToRepresentation(info);
-  // We only generate either int32 or generic tagged bitwise operations.
-  if (instr->IsBitwiseBinaryOperation()) {
-    HBitwiseBinaryOperation::cast(instr)->
-         InitializeObservedInputRepresentation(rep);
-    if (rep.IsDouble()) rep = Representation::Integer32();
+  if (instr->IsBinaryOperation()) {
+    HBinaryOperation* binop = HBinaryOperation::cast(instr);
+    binop->set_observed_input_representation(left_rep, right_rep);
+    binop->initialize_output_representation(result_rep);
   }
-  TraceRepresentation(expr->op(), info, instr, rep);
-  instr->AssumeRepresentation(rep);
   return instr;
 }
 
@@ -8567,27 +8546,8 @@ void HGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
 }
 
 
-void HGraphBuilder::TraceRepresentation(Token::Value op,
-                                        TypeInfo info,
-                                        HValue* value,
-                                        Representation rep) {
-  if (!FLAG_trace_representation) return;
-  // TODO(svenpanne) Under which circumstances are we actually not flexible?
-  // At first glance, this looks a bit weird...
-  bool flexible = value->CheckFlag(HValue::kFlexibleRepresentation);
-  PrintF("Operation %s has type info %s, %schange representation assumption "
-         "for %s (ID %d) from %s to %s\n",
-         Token::Name(op),
-         info.ToString(),
-         flexible ? "" : " DO NOT ",
-         value->Mnemonic(),
-         graph_->GetMaximumValueID(),
-         value->representation().Mnemonic(),
-         rep.Mnemonic());
-}
-
-
 Representation HGraphBuilder::ToRepresentation(TypeInfo info) {
+  if (info.IsUninitialized()) return Representation::None();
   if (info.IsSmi()) return Representation::Integer32();
   if (info.IsInteger32()) return Representation::Integer32();
   if (info.IsDouble()) return Representation::Double();
@@ -8685,13 +8645,17 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     return ast_context()->ReturnControl(instr, expr->id());
   }
 
-  TypeInfo type_info = oracle()->CompareType(expr);
+  TypeInfo left_type, right_type, overall_type_info;
+  oracle()->CompareType(expr, &left_type, &right_type, &overall_type_info);
+  Representation combined_rep = ToRepresentation(overall_type_info);
+  Representation left_rep = ToRepresentation(left_type);
+  Representation right_rep = ToRepresentation(right_type);
   // Check if this expression was ever executed according to type feedback.
   // Note that for the special typeof/null/undefined cases we get unknown here.
-  if (type_info.IsUninitialized()) {
+  if (overall_type_info.IsUninitialized()) {
     AddInstruction(new(zone()) HSoftDeoptimize);
     current_block()->MarkAsDeoptimizing();
-    type_info = TypeInfo::Unknown();
+    overall_type_info = left_type = right_type = TypeInfo::Unknown();
   }
 
   CHECK_ALIVE(VisitForValue(expr->left()));
@@ -8763,7 +8727,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     HIn* result = new(zone()) HIn(context, left, right);
     result->set_position(expr->position());
     return ast_context()->ReturnInstruction(result, expr->id());
-  } else if (type_info.IsNonPrimitive()) {
+  } else if (overall_type_info.IsNonPrimitive()) {
     switch (op) {
       case Token::EQ:
       case Token::EQ_STRICT: {
@@ -8790,8 +8754,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
       default:
         return Bailout("Unsupported non-primitive compare");
     }
-  } else if (type_info.IsString() && oracle()->IsSymbolCompare(expr) &&
-             (op == Token::EQ || op == Token::EQ_STRICT)) {
+  } else if (overall_type_info.IsSymbol() && Token::IsEqualityOp(op)) {
     AddInstruction(new(zone()) HCheckNonSmi(left));
     AddInstruction(HCheckInstanceType::NewIsSymbol(left, zone()));
     AddInstruction(new(zone()) HCheckNonSmi(right));
@@ -8801,17 +8764,17 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     result->set_position(expr->position());
     return ast_context()->ReturnControl(result, expr->id());
   } else {
-    Representation r = ToRepresentation(type_info);
-    if (r.IsTagged()) {
+    if (combined_rep.IsTagged() || combined_rep.IsNone()) {
       HCompareGeneric* result =
           new(zone()) HCompareGeneric(context, left, right, op);
+      result->set_observed_input_representation(left_rep, right_rep);
       result->set_position(expr->position());
       return ast_context()->ReturnInstruction(result, expr->id());
     } else {
       HCompareIDAndBranch* result =
           new(zone()) HCompareIDAndBranch(left, right, op);
+      result->set_observed_input_representation(left_rep, right_rep);
       result->set_position(expr->position());
-      result->SetInputRepresentation(r);
       return ast_context()->ReturnControl(result, expr->id());
     }
   }
@@ -8898,7 +8861,9 @@ void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* declaration) {
         HStoreContextSlot* store = new(zone()) HStoreContextSlot(
             context, variable->index(), HStoreContextSlot::kNoCheck, value);
         AddInstruction(store);
-        if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
+        if (store->HasObservableSideEffects()) {
+          AddSimulate(proxy->id(), REMOVABLE_SIMULATE);
+        }
       }
       break;
     case Variable::LOOKUP:
@@ -8934,7 +8899,9 @@ void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
       HStoreContextSlot* store = new(zone()) HStoreContextSlot(
           context, variable->index(), HStoreContextSlot::kNoCheck, value);
       AddInstruction(store);
-      if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
+      if (store->HasObservableSideEffects()) {
+        AddSimulate(proxy->id(), REMOVABLE_SIMULATE);
+      }
       break;
     }
     case Variable::LOOKUP:
index 3748970585155bb876219b0a70a777aa9b49e32f..78ab571b5c52376549a07423a1dfcc2b9decd74f 100644 (file)
@@ -125,7 +125,10 @@ class HBasicBlock: public ZoneObject {
   void Goto(HBasicBlock* block, FunctionState* state = NULL);
 
   int PredecessorIndexOf(HBasicBlock* predecessor) const;
-  void AddSimulate(BailoutId ast_id) { AddInstruction(CreateSimulate(ast_id)); }
+  void AddSimulate(BailoutId ast_id,
+                   RemovableSimulate removable = FIXED_SIMULATE) {
+    AddInstruction(CreateSimulate(ast_id, removable));
+  }
   void AssignCommonDominator(HBasicBlock* other);
   void AssignLoopSuccessorDominators();
 
@@ -166,7 +169,7 @@ class HBasicBlock: public ZoneObject {
   void RegisterPredecessor(HBasicBlock* pred);
   void AddDominatedBlock(HBasicBlock* block);
 
-  HSimulate* CreateSimulate(BailoutId ast_id);
+  HSimulate* CreateSimulate(BailoutId ast_id, RemovableSimulate removable);
   HDeoptimize* CreateDeoptimize(HDeoptimize::UseEnvironment has_uses);
 
   int block_id_;
@@ -255,6 +258,7 @@ class HGraph: public ZoneObject {
 
   void InitializeInferredTypes();
   void InsertTypeConversions();
+  void MergeRemovableSimulates();
   void InsertRepresentationChanges();
   void MarkDeoptimizeOnUndefined();
   void ComputeMinusZeroChecks();
@@ -613,6 +617,25 @@ class HEnvironment: public ZoneObject {
 };
 
 
+class HInferRepresentation BASE_EMBEDDED {
+ public:
+  explicit HInferRepresentation(HGraph* graph)
+      : graph_(graph),
+        worklist_(8, graph->zone()),
+        in_worklist_(graph->GetMaximumValueID(), graph->zone()) { }
+
+  void Analyze();
+  void AddToWorklist(HValue* current);
+
+ private:
+  Zone* zone() const { return graph_->zone(); }
+
+  HGraph* graph_;
+  ZoneList<HValue*> worklist_;
+  BitVector in_worklist_;
+};
+
+
 class HGraphBuilder;
 
 enum ArgumentsAllowedFlag {
@@ -880,7 +903,8 @@ class HGraphBuilder: public AstVisitor {
 
   // Adding instructions.
   HInstruction* AddInstruction(HInstruction* instr);
-  void AddSimulate(BailoutId ast_id);
+  void AddSimulate(BailoutId ast_id,
+                   RemovableSimulate removable = FIXED_SIMULATE);
 
   // Bailout environment manipulation.
   void Push(HValue* value) { environment()->Push(value); }
@@ -1025,10 +1049,6 @@ class HGraphBuilder: public AstVisitor {
   // to push them as outgoing parameters.
   template <class Instruction> HInstruction* PreProcessCall(Instruction* call);
 
-  void TraceRepresentation(Token::Value op,
-                           TypeInfo info,
-                           HValue* value,
-                           Representation rep);
   static Representation ToRepresentation(TypeInfo info);
 
   void SetUpScope(Scope* scope);
index 7ea71e47eb059b1cf788c2970eddc211e00a5a02..e92957479aae158c4d593a0889cb57d2d8d29e6b 100644 (file)
@@ -735,6 +735,12 @@ class FloatingPointHelper : public AllStatic {
   static void CheckSSE2OperandsAreInt32(MacroAssembler* masm,
                                         Label* non_int32,
                                         Register scratch);
+
+  static void CheckSSE2OperandIsInt32(MacroAssembler* masm,
+                                      Label* non_int32,
+                                      XMMRegister operand,
+                                      Register scratch,
+                                      XMMRegister xmm_scratch);
 };
 
 
@@ -755,11 +761,20 @@ static void IntegerConvert(MacroAssembler* masm,
   // Get exponent alone in scratch2.
   __ mov(scratch2, scratch);
   __ and_(scratch2, HeapNumber::kExponentMask);
+  __ shr(scratch2, HeapNumber::kExponentShift);
+  __ sub(scratch2, Immediate(HeapNumber::kExponentBias));
+  // Load ecx with zero.  We use this either for the final shift or
+  // for the answer.
+  __ xor_(ecx, ecx);
+  // If the exponent is above 83, the number contains no significant
+  // bits in the range 0..2^31, so the result is zero.
+  static const uint32_t kResultIsZeroExponent = 83;
+  __ cmp(scratch2, Immediate(kResultIsZeroExponent));
+  __ j(above, &done);
   if (use_sse3) {
     CpuFeatures::Scope scope(SSE3);
     // Check whether the exponent is too big for a 64 bit signed integer.
-    static const uint32_t kTooBigExponent =
-        (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
+    static const uint32_t kTooBigExponent = 63;
     __ cmp(scratch2, Immediate(kTooBigExponent));
     __ j(greater_equal, conversion_failure);
     // Load x87 register with heap number.
@@ -771,15 +786,11 @@ static void IntegerConvert(MacroAssembler* masm,
     __ mov(ecx, Operand(esp, 0));  // Load low word of answer into ecx.
     __ add(esp, Immediate(sizeof(uint64_t)));  // Nolint.
   } else {
-    // Load ecx with zero.  We use this either for the final shift or
-    // for the answer.
-    __ xor_(ecx, ecx);
     // Check whether the exponent matches a 32 bit signed int that cannot be
     // represented by a Smi.  A non-smi 32 bit integer is 1.xxx * 2^30 so the
     // exponent is 30 (biased).  This is the exponent that we are fastest at and
     // also the highest exponent we can handle here.
-    const uint32_t non_smi_exponent =
-        (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
+    const uint32_t non_smi_exponent = 30;
     __ cmp(scratch2, Immediate(non_smi_exponent));
     // If we have a match of the int32-but-not-Smi exponent then skip some
     // logic.
@@ -791,8 +802,7 @@ static void IntegerConvert(MacroAssembler* masm,
     {
       // Handle a big exponent.  The only reason we have this code is that the
       // >>> operator has a tendency to generate numbers with an exponent of 31.
-      const uint32_t big_non_smi_exponent =
-          (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift;
+      const uint32_t big_non_smi_exponent = 31;
       __ cmp(scratch2, Immediate(big_non_smi_exponent));
       __ j(not_equal, conversion_failure);
       // We have the big exponent, typically from >>>.  This means the number is
@@ -821,19 +831,8 @@ static void IntegerConvert(MacroAssembler* masm,
     }
 
     __ bind(&normal_exponent);
-    // Exponent word in scratch, exponent part of exponent word in scratch2.
-    // Zero in ecx.
-    // We know the exponent is smaller than 30 (biased).  If it is less than
-    // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e.
-    // it rounds to zero.
-    const uint32_t zero_exponent =
-        (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
-    __ sub(scratch2, Immediate(zero_exponent));
-    // ecx already has a Smi zero.
-    __ j(less, &done, Label::kNear);
-
-    // We have a shifted exponent between 0 and 30 in scratch2.
-    __ shr(scratch2, HeapNumber::kExponentShift);
+    // Exponent word in scratch, exponent in scratch2. Zero in ecx.
+    // We know that 0 <= exponent < 30.
     __ mov(ecx, Immediate(30));
     __ sub(ecx, scratch2);
 
@@ -868,8 +867,8 @@ static void IntegerConvert(MacroAssembler* masm,
     __ jmp(&done, Label::kNear);
     __ bind(&negative);
     __ sub(ecx, scratch2);
-    __ bind(&done);
   }
+  __ bind(&done);
 }
 
 
@@ -1192,16 +1191,17 @@ void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
 }
 
 
+void BinaryOpStub::Initialize() {
+  platform_specific_bit_ = CpuFeatures::IsSupported(SSE3);
+}
+
+
 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
   __ pop(ecx);  // Save return address.
   __ push(edx);
   __ push(eax);
   // Left and right arguments are now on top.
-  // Push this stub's key. Although the operation and the type info are
-  // encoded into the key, the encoding is opaque, so push them too.
   __ push(Immediate(Smi::FromInt(MinorKey())));
-  __ push(Immediate(Smi::FromInt(op_)));
-  __ push(Immediate(Smi::FromInt(operands_type_)));
 
   __ push(ecx);  // Push return address.
 
@@ -1210,7 +1210,7 @@ void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
   __ TailCallExternalReference(
       ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
                         masm->isolate()),
-      5,
+      3,
       1);
 }
 
@@ -1220,11 +1220,7 @@ void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) {
   __ pop(ecx);  // Save return address.
   // Left and right arguments are already on top of the stack.
-  // Push this stub's key. Although the operation and the type info are
-  // encoded into the key, the encoding is opaque, so push them too.
   __ push(Immediate(Smi::FromInt(MinorKey())));
-  __ push(Immediate(Smi::FromInt(op_)));
-  __ push(Immediate(Smi::FromInt(operands_type_)));
 
   __ push(ecx);  // Push return address.
 
@@ -1233,73 +1229,22 @@ void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) {
   __ TailCallExternalReference(
       ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
                         masm->isolate()),
-      5,
+      3,
       1);
 }
 
 
-void BinaryOpStub::Generate(MacroAssembler* masm) {
-  // Explicitly allow generation of nested stubs. It is safe here because
-  // generation code does not use any raw pointers.
-  AllowStubCallsScope allow_stub_calls(masm, true);
-
-  switch (operands_type_) {
-    case BinaryOpIC::UNINITIALIZED:
-      GenerateTypeTransition(masm);
-      break;
-    case BinaryOpIC::SMI:
-      GenerateSmiStub(masm);
-      break;
-    case BinaryOpIC::INT32:
-      GenerateInt32Stub(masm);
-      break;
-    case BinaryOpIC::HEAP_NUMBER:
-      GenerateHeapNumberStub(masm);
-      break;
-    case BinaryOpIC::ODDBALL:
-      GenerateOddballStub(masm);
-      break;
-    case BinaryOpIC::BOTH_STRING:
-      GenerateBothStringStub(masm);
-      break;
-    case BinaryOpIC::STRING:
-      GenerateStringStub(masm);
-      break;
-    case BinaryOpIC::GENERIC:
-      GenerateGeneric(masm);
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
-
-void BinaryOpStub::PrintName(StringStream* stream) {
-  const char* op_name = Token::Name(op_);
-  const char* overwrite_name;
-  switch (mode_) {
-    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
-    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
-    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
-    default: overwrite_name = "UnknownOverwrite"; break;
-  }
-  stream->Add("BinaryOpStub_%s_%s_%s",
-              op_name,
-              overwrite_name,
-              BinaryOpIC::GetName(operands_type_));
-}
-
-
-void BinaryOpStub::GenerateSmiCode(
+static void BinaryOpStub_GenerateSmiCode(
     MacroAssembler* masm,
     Label* slow,
-    SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
+    BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results,
+    Token::Value op) {
   // 1. Move arguments into edx, eax except for DIV and MOD, which need the
   // dividend in eax and edx free for the division.  Use eax, ebx for those.
   Comment load_comment(masm, "-- Load arguments");
   Register left = edx;
   Register right = eax;
-  if (op_ == Token::DIV || op_ == Token::MOD) {
+  if (op == Token::DIV || op == Token::MOD) {
     left = eax;
     right = ebx;
     __ mov(ebx, eax);
@@ -1312,7 +1257,7 @@ void BinaryOpStub::GenerateSmiCode(
   Label not_smis;
   Register combined = ecx;
   ASSERT(!left.is(combined) && !right.is(combined));
-  switch (op_) {
+  switch (op) {
     case Token::BIT_OR:
       // Perform the operation into eax and smi check the result.  Preserve
       // eax in case the result is not a smi.
@@ -1356,7 +1301,7 @@ void BinaryOpStub::GenerateSmiCode(
   // eax and check the result if necessary.
   Comment perform_smi(masm, "-- Perform smi operation");
   Label use_fp_on_smis;
-  switch (op_) {
+  switch (op) {
     case Token::BIT_OR:
       // Nothing to do.
       break;
@@ -1490,7 +1435,7 @@ void BinaryOpStub::GenerateSmiCode(
   }
 
   // 5. Emit return of result in eax.  Some operations have registers pushed.
-  switch (op_) {
+  switch (op) {
     case Token::ADD:
     case Token::SUB:
     case Token::MUL:
@@ -1513,9 +1458,9 @@ void BinaryOpStub::GenerateSmiCode(
   // 6. For some operations emit inline code to perform floating point
   // operations on known smis (e.g., if the result of the operation
   // overflowed the smi range).
-  if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) {
+  if (allow_heapnumber_results == BinaryOpStub::NO_HEAPNUMBER_RESULTS) {
     __ bind(&use_fp_on_smis);
-    switch (op_) {
+    switch (op) {
       // Undo the effects of some operations, and some register moves.
       case Token::SHL:
         // The arguments are saved on the stack, and only used from there.
@@ -1543,8 +1488,8 @@ void BinaryOpStub::GenerateSmiCode(
     }
     __ jmp(&not_smis);
   } else {
-    ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS);
-    switch (op_) {
+    ASSERT(allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS);
+    switch (op) {
       case Token::SHL:
       case Token::SHR: {
         Comment perform_float(masm, "-- Perform float operation on smis");
@@ -1555,13 +1500,13 @@ void BinaryOpStub::GenerateSmiCode(
         // Store the result in the HeapNumber and return.
         // It's OK to overwrite the arguments on the stack because we
         // are about to return.
-        if (op_ == Token::SHR) {
+        if (op == Token::SHR) {
           __ mov(Operand(esp, 1 * kPointerSize), left);
           __ mov(Operand(esp, 2 * kPointerSize), Immediate(0));
           __ fild_d(Operand(esp, 1 * kPointerSize));
           __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
         } else {
-          ASSERT_EQ(Token::SHL, op_);
+          ASSERT_EQ(Token::SHL, op);
           if (CpuFeatures::IsSupported(SSE2)) {
             CpuFeatures::Scope use_sse2(SSE2);
             __ cvtsi2sd(xmm0, left);
@@ -1583,7 +1528,7 @@ void BinaryOpStub::GenerateSmiCode(
         Comment perform_float(masm, "-- Perform float operation on smis");
         __ bind(&use_fp_on_smis);
         // Restore arguments to edx, eax.
-        switch (op_) {
+        switch (op) {
           case Token::ADD:
             // Revert right = right + left.
             __ sub(right, left);
@@ -1609,7 +1554,7 @@ void BinaryOpStub::GenerateSmiCode(
         if (CpuFeatures::IsSupported(SSE2)) {
           CpuFeatures::Scope use_sse2(SSE2);
           FloatingPointHelper::LoadSSE2Smis(masm, ebx);
-          switch (op_) {
+          switch (op) {
             case Token::ADD: __ addsd(xmm0, xmm1); break;
             case Token::SUB: __ subsd(xmm0, xmm1); break;
             case Token::MUL: __ mulsd(xmm0, xmm1); break;
@@ -1619,7 +1564,7 @@ void BinaryOpStub::GenerateSmiCode(
           __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0);
         } else {  // SSE2 not available, use FPU.
           FloatingPointHelper::LoadFloatSmis(masm, ebx);
-          switch (op_) {
+          switch (op) {
             case Token::ADD: __ faddp(1); break;
             case Token::SUB: __ fsubp(1); break;
             case Token::MUL: __ fmulp(1); break;
@@ -1642,7 +1587,7 @@ void BinaryOpStub::GenerateSmiCode(
   // edx and eax.
   Comment done_comment(masm, "-- Enter non-smi code");
   __ bind(&not_smis);
-  switch (op_) {
+  switch (op) {
     case Token::BIT_OR:
     case Token::SHL:
     case Token::SAR:
@@ -1689,9 +1634,11 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
 
   if (result_type_ == BinaryOpIC::UNINITIALIZED ||
       result_type_ == BinaryOpIC::SMI) {
-    GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS);
+    BinaryOpStub_GenerateSmiCode(
+        masm, &call_runtime, NO_HEAPNUMBER_RESULTS, op_);
   } else {
-    GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
+    BinaryOpStub_GenerateSmiCode(
+        masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_);
   }
   __ bind(&call_runtime);
   switch (op_) {
@@ -1716,19 +1663,9 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
 }
 
 
-void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
-  ASSERT(operands_type_ == BinaryOpIC::STRING);
-  ASSERT(op_ == Token::ADD);
-  // Try to add arguments as strings, otherwise, transition to the generic
-  // BinaryOpIC type.
-  GenerateAddStrings(masm);
-  GenerateTypeTransition(masm);
-}
-
-
 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
   Label call_runtime;
-  ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING);
+  ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING);
   ASSERT(op_ == Token::ADD);
   // If both arguments are strings, call the string add stub.
   // Otherwise, do a transition.
@@ -1756,6 +1693,11 @@ void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
 }
 
 
+static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
+                                                      Label* alloc_failure,
+                                                      OverwriteMode mode);
+
+
 // Input:
 //    edx: left operand (tagged)
 //    eax: right operand (tagged)
@@ -1763,7 +1705,7 @@ void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
 //    eax: result (tagged)
 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
   Label call_runtime;
-  ASSERT(operands_type_ == BinaryOpIC::INT32);
+  ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32);
 
   // Floating point case.
   switch (op_) {
@@ -1776,6 +1718,18 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
       Label not_int32;
       if (CpuFeatures::IsSupported(SSE2)) {
         CpuFeatures::Scope use_sse2(SSE2);
+        // It could be that only SMIs have been seen at either the left
+        // or the right operand. For precise type feedback, patch the IC
+        // again if this changes.
+        // In theory, we would need the same check in the non-SSE2 case,
+        // but since we don't support Crankshaft on such hardware we can
+        // afford not to care about precise type feedback.
+        if (left_type_ == BinaryOpIC::SMI) {
+          __ JumpIfNotSmi(edx, &not_int32);
+        }
+        if (right_type_ == BinaryOpIC::SMI) {
+          __ JumpIfNotSmi(eax, &not_int32);
+        }
         FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
         FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
         if (op_ == Token::MOD) {
@@ -1798,7 +1752,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
             __ test(ecx, Immediate(1));
             __ j(zero, &not_int32);
           }
-          GenerateHeapResultAllocation(masm, &call_runtime);
+          BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_);
           __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
           __ ret(0);
         }
@@ -1824,7 +1778,8 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
             default: UNREACHABLE();
           }
           Label after_alloc_failure;
-          GenerateHeapResultAllocation(masm, &after_alloc_failure);
+          BinaryOpStub_GenerateHeapResultAllocation(
+              masm, &after_alloc_failure, mode_);
           __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
           __ ret(0);
           __ bind(&after_alloc_failure);
@@ -1849,10 +1804,14 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
       Label not_floats;
       Label not_int32;
       Label non_smi_result;
+      // We do not check the input arguments here, as any value is
+      // unconditionally truncated to an int32 anyway. To get the
+      // right optimized code, int32 type feedback is just right.
+      bool use_sse3 = platform_specific_bit_;
       FloatingPointHelper::LoadUnknownsAsIntegers(masm,
-                                                  use_sse3_,
+                                                  use_sse3,
                                                   &not_floats);
-      FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_,
+      FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3,
                                                         &not_int32);
       switch (op_) {
         case Token::BIT_OR:  __ or_(eax, ecx); break;
@@ -1925,44 +1884,24 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
 
   switch (op_) {
     case Token::ADD:
-      GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
-      break;
     case Token::SUB:
-      GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
-      break;
     case Token::MUL:
-      GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
-      break;
     case Token::DIV:
       GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
       break;
     case Token::MOD:
-      break;
+      return;  // Handled above.
     case Token::BIT_OR:
-      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
-      break;
     case Token::BIT_AND:
-      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
-      break;
     case Token::BIT_XOR:
-      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
-      break;
     case Token::SAR:
-      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
-      break;
     case Token::SHL:
-      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
-      break;
     case Token::SHR:
-      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
       break;
     default:
       UNREACHABLE();
   }
+  GenerateCallRuntime(masm);
 }
 
 
@@ -2011,7 +1950,28 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
       Label not_floats;
       if (CpuFeatures::IsSupported(SSE2)) {
         CpuFeatures::Scope use_sse2(SSE2);
+
+        // It could be that only SMIs have been seen at either the left
+        // or the right operand. For precise type feedback, patch the IC
+        // again if this changes.
+        // In theory, we would need the same check in the non-SSE2 case,
+        // but since we don't support Crankshaft on such hardware we can
+        // afford not to care about precise type feedback.
+        if (left_type_ == BinaryOpIC::SMI) {
+          __ JumpIfNotSmi(edx, &not_floats);
+        }
+        if (right_type_ == BinaryOpIC::SMI) {
+          __ JumpIfNotSmi(eax, &not_floats);
+        }
         FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
+        if (left_type_ == BinaryOpIC::INT32) {
+          FloatingPointHelper::CheckSSE2OperandIsInt32(
+              masm, &not_floats, xmm0, ecx, xmm2);
+        }
+        if (right_type_ == BinaryOpIC::INT32) {
+          FloatingPointHelper::CheckSSE2OperandIsInt32(
+              masm, &not_floats, xmm1, ecx, xmm2);
+        }
 
         switch (op_) {
           case Token::ADD: __ addsd(xmm0, xmm1); break;
@@ -2020,7 +1980,7 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
           case Token::DIV: __ divsd(xmm0, xmm1); break;
           default: UNREACHABLE();
         }
-        GenerateHeapResultAllocation(masm, &call_runtime);
+        BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_);
         __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
         __ ret(0);
       } else {  // SSE2 not available, use FPU.
@@ -2037,7 +1997,8 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
           default: UNREACHABLE();
         }
         Label after_alloc_failure;
-        GenerateHeapResultAllocation(masm, &after_alloc_failure);
+        BinaryOpStub_GenerateHeapResultAllocation(
+            masm, &after_alloc_failure, mode_);
         __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
         __ ret(0);
         __ bind(&after_alloc_failure);
@@ -2063,8 +2024,12 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
       GenerateRegisterArgsPush(masm);
       Label not_floats;
       Label non_smi_result;
+      // We do not check the input arguments here, as any value is
+      // unconditionally truncated to an int32 anyway. To get the
+      // right optimized code, int32 type feedback is just right.
+      bool use_sse3 = platform_specific_bit_;
       FloatingPointHelper::LoadUnknownsAsIntegers(masm,
-                                                  use_sse3_,
+                                                  use_sse3,
                                                   &not_floats);
       switch (op_) {
         case Token::BIT_OR:  __ or_(eax, ecx); break;
@@ -2136,46 +2101,23 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
 
   switch (op_) {
     case Token::ADD:
-      GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
-      break;
     case Token::SUB:
-      GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
-      break;
     case Token::MUL:
-      GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
-      break;
     case Token::DIV:
-      GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
-      break;
     case Token::MOD:
       GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
       break;
     case Token::BIT_OR:
-      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
-      break;
     case Token::BIT_AND:
-      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
-      break;
     case Token::BIT_XOR:
-      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
-      break;
     case Token::SAR:
-      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
-      break;
     case Token::SHL:
-      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
-      break;
     case Token::SHR:
-      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
       break;
     default:
       UNREACHABLE();
   }
+  GenerateCallRuntime(masm);
 }
 
 
@@ -2204,7 +2146,8 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
       UNREACHABLE();
   }
 
-  GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
+  BinaryOpStub_GenerateSmiCode(
+      masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_);
 
   // Floating point case.
   switch (op_) {
@@ -2224,7 +2167,7 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
           case Token::DIV: __ divsd(xmm0, xmm1); break;
           default: UNREACHABLE();
         }
-        GenerateHeapResultAllocation(masm, &call_runtime);
+        BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_);
         __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
         __ ret(0);
       } else {  // SSE2 not available, use FPU.
@@ -2241,7 +2184,8 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
           default: UNREACHABLE();
         }
         Label after_alloc_failure;
-        GenerateHeapResultAllocation(masm, &after_alloc_failure);
+        BinaryOpStub_GenerateHeapResultAllocation(
+            masm, &after_alloc_failure, mode_);
         __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
         __ ret(0);
         __ bind(&after_alloc_failure);
@@ -2262,8 +2206,9 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
     case Token::SHL:
     case Token::SHR: {
       Label non_smi_result;
+      bool use_sse3 = platform_specific_bit_;
       FloatingPointHelper::LoadUnknownsAsIntegers(masm,
-                                                  use_sse3_,
+                                                  use_sse3,
                                                   &call_runtime);
       switch (op_) {
         case Token::BIT_OR:  __ or_(eax, ecx); break;
@@ -2330,48 +2275,26 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
   // result.
   __ bind(&call_runtime);
   switch (op_) {
-    case Token::ADD: {
+    case Token::ADD:
       GenerateAddStrings(masm);
-      GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
-      break;
-    }
+      // Fall through.
     case Token::SUB:
-      GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
-      break;
     case Token::MUL:
-      GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
-      break;
     case Token::DIV:
       GenerateRegisterArgsPush(masm);
-      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
       break;
     case Token::MOD:
-      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
-      break;
     case Token::BIT_OR:
-      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
-      break;
     case Token::BIT_AND:
-      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
-      break;
     case Token::BIT_XOR:
-      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
-      break;
     case Token::SAR:
-      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
-      break;
     case Token::SHL:
-      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
-      break;
     case Token::SHR:
-      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
       break;
     default:
       UNREACHABLE();
   }
+  GenerateCallRuntime(masm);
 }
 
 
@@ -2407,11 +2330,10 @@ void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
 }
 
 
-void BinaryOpStub::GenerateHeapResultAllocation(
-    MacroAssembler* masm,
-    Label* alloc_failure) {
+static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
+                                                      Label* alloc_failure,
+                                                      OverwriteMode mode) {
   Label skip_allocation;
-  OverwriteMode mode = mode_;
   switch (mode) {
     case OVERWRITE_LEFT: {
       // If the argument in edx is already an object, we skip the
@@ -2923,16 +2845,22 @@ void FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm,
 void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm,
                                                     Label* non_int32,
                                                     Register scratch) {
-  __ cvttsd2si(scratch, Operand(xmm0));
-  __ cvtsi2sd(xmm2, scratch);
-  __ ucomisd(xmm0, xmm2);
-  __ j(not_zero, non_int32);
-  __ j(carry, non_int32);
-  __ cvttsd2si(scratch, Operand(xmm1));
-  __ cvtsi2sd(xmm2, scratch);
-  __ ucomisd(xmm1, xmm2);
-  __ j(not_zero, non_int32);
-  __ j(carry, non_int32);
+  CheckSSE2OperandIsInt32(masm, non_int32, xmm0, scratch, xmm2);
+  CheckSSE2OperandIsInt32(masm, non_int32, xmm1, scratch, xmm2);
+}
+
+
+void FloatingPointHelper::CheckSSE2OperandIsInt32(MacroAssembler* masm,
+                                                  Label* non_int32,
+                                                  XMMRegister operand,
+                                                  Register scratch,
+                                                  XMMRegister xmm_scratch) {
+  __ cvttsd2si(scratch, Operand(operand));
+  __ cvtsi2sd(xmm_scratch, scratch);
+  __ pcmpeqd(xmm_scratch, operand);
+  __ movmskpd(scratch, xmm_scratch);
+  __ test(scratch, Immediate(1));
+  __ j(zero, non_int32);
 }
 
 
@@ -4321,30 +4249,59 @@ static int NegativeComparisonResult(Condition cc) {
   return (cc == greater || cc == greater_equal) ? LESS : GREATER;
 }
 
-void CompareStub::Generate(MacroAssembler* masm) {
-  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
 
+static void CheckInputType(MacroAssembler* masm,
+                           Register input,
+                           CompareIC::State expected,
+                           Label* fail) {
+  Label ok;
+  if (expected == CompareIC::SMI) {
+    __ JumpIfNotSmi(input, fail);
+  } else if (expected == CompareIC::HEAP_NUMBER) {
+    __ JumpIfSmi(input, &ok);
+    __ cmp(FieldOperand(input, HeapObject::kMapOffset),
+           Immediate(masm->isolate()->factory()->heap_number_map()));
+    __ j(not_equal, fail);
+  }
+  // We could be strict about symbol/string here, but as long as
+  // hydrogen doesn't care, the stub doesn't have to care either.
+  __ bind(&ok);
+}
+
+
+static void BranchIfNonSymbol(MacroAssembler* masm,
+                              Label* label,
+                              Register object,
+                              Register scratch) {
+  __ JumpIfSmi(object, label);
+  __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset));
+  __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
+  __ and_(scratch, kIsSymbolMask | kIsNotStringMask);
+  __ cmp(scratch, kSymbolTag | kStringTag);
+  __ j(not_equal, label);
+}
+
+
+void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
   Label check_unequal_objects;
+  Condition cc = GetCondition();
 
-  // Compare two smis if required.
-  if (include_smi_compare_) {
-    Label non_smi, smi_done;
-    __ mov(ecx, edx);
-    __ or_(ecx, eax);
-    __ JumpIfNotSmi(ecx, &non_smi, Label::kNear);
-    __ sub(edx, eax);  // Return on the result of the subtraction.
-    __ j(no_overflow, &smi_done, Label::kNear);
-    __ not_(edx);  // Correct sign in case of overflow. edx is never 0 here.
-    __ bind(&smi_done);
-    __ mov(eax, edx);
-    __ ret(0);
-    __ bind(&non_smi);
-  } else if (FLAG_debug_code) {
-    __ mov(ecx, edx);
-    __ or_(ecx, eax);
-    __ test(ecx, Immediate(kSmiTagMask));
-    __ Assert(not_zero, "Unexpected smi operands.");
-  }
+  Label miss;
+  CheckInputType(masm, edx, left_, &miss);
+  CheckInputType(masm, eax, right_, &miss);
+
+  // Compare two smis.
+  Label non_smi, smi_done;
+  __ mov(ecx, edx);
+  __ or_(ecx, eax);
+  __ JumpIfNotSmi(ecx, &non_smi, Label::kNear);
+  __ sub(edx, eax);  // Return on the result of the subtraction.
+  __ j(no_overflow, &smi_done, Label::kNear);
+  __ not_(edx);  // Correct sign in case of overflow. edx is never 0 here.
+  __ bind(&smi_done);
+  __ mov(eax, edx);
+  __ ret(0);
+  __ bind(&non_smi);
 
   // NOTICE! This code is only reached after a smi-fast-case check, so
   // it is certain that at least one operand isn't a smi.
@@ -4356,67 +4313,61 @@ void CompareStub::Generate(MacroAssembler* masm) {
     __ cmp(eax, edx);
     __ j(not_equal, &not_identical);
 
-    if (cc_ != equal) {
+    if (cc != equal) {
       // Check for undefined.  undefined OP undefined is false even though
       // undefined == undefined.
       Label check_for_nan;
       __ cmp(edx, masm->isolate()->factory()->undefined_value());
       __ j(not_equal, &check_for_nan, Label::kNear);
-      __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
+      __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
       __ ret(0);
       __ 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.
-    // Note: if cc_ != equal, never_nan_nan_ is not used.
-    if (never_nan_nan_ && (cc_ == equal)) {
-      __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
+    Label heap_number;
+    __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
+           Immediate(masm->isolate()->factory()->heap_number_map()));
+    __ j(equal, &heap_number, Label::kNear);
+    if (cc != equal) {
+      // Call runtime on identical JSObjects.  Otherwise return equal.
+      __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
+      __ j(above_equal, &not_identical);
+    }
+    __ 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 heap_number;
-      __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
-             Immediate(masm->isolate()->factory()->heap_number_map()));
-      __ j(equal, &heap_number, Label::kNear);
-      if (cc_ != equal) {
-        // Call runtime on identical JSObjects.  Otherwise return equal.
-        __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
-        __ j(above_equal, &not_identical);
-      }
+      Label nan;
+      __ j(above_equal, &nan, Label::kNear);
       __ 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(&nan);
+      __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
+      __ ret(0);
     }
 
     __ bind(&not_identical);
@@ -4424,7 +4375,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
 
   // Strict equality can quickly decide whether objects are equal.
   // Non-strict object equality is slower, so it is handled later in the stub.
-  if (cc_ == equal && strict_) {
+  if (cc == equal && strict()) {
     Label slow;  // Fallthrough label.
     Label not_smis;
     // If we're doing a strict equality comparison, we don't have to do
@@ -4495,70 +4446,68 @@ void CompareStub::Generate(MacroAssembler* masm) {
   }
 
   // Generate the number comparison code.
-  if (include_number_compare_) {
-    Label non_number_comparison;
-    Label unordered;
-    if (CpuFeatures::IsSupported(SSE2)) {
-      CpuFeatures::Scope use_sse2(SSE2);
-      CpuFeatures::Scope use_cmov(CMOV);
-
-      FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
-      __ ucomisd(xmm0, xmm1);
+  Label non_number_comparison;
+  Label unordered;
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope use_sse2(SSE2);
+    CpuFeatures::Scope use_cmov(CMOV);
 
-      // Don't base result on EFLAGS when a NaN is involved.
-      __ j(parity_even, &unordered, Label::kNear);
-      // Return a result of -1, 0, or 1, based on EFLAGS.
-      __ mov(eax, 0);  // equal
-      __ mov(ecx, Immediate(Smi::FromInt(1)));
-      __ cmov(above, eax, ecx);
-      __ mov(ecx, Immediate(Smi::FromInt(-1)));
-      __ cmov(below, eax, ecx);
-      __ ret(0);
-    } else {
-      FloatingPointHelper::CheckFloatOperands(
-          masm, &non_number_comparison, ebx);
-      FloatingPointHelper::LoadFloatOperand(masm, eax);
-      FloatingPointHelper::LoadFloatOperand(masm, edx);
-      __ FCmp();
+    FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
+    __ ucomisd(xmm0, xmm1);
 
-      // Don't base result on EFLAGS when a NaN is involved.
-      __ j(parity_even, &unordered, Label::kNear);
+    // Don't base result on EFLAGS when a NaN is involved.
+    __ j(parity_even, &unordered, Label::kNear);
+    // Return a result of -1, 0, or 1, based on EFLAGS.
+    __ mov(eax, 0);  // equal
+    __ mov(ecx, Immediate(Smi::FromInt(1)));
+    __ cmov(above, eax, ecx);
+    __ mov(ecx, Immediate(Smi::FromInt(-1)));
+    __ cmov(below, eax, ecx);
+    __ ret(0);
+  } else {
+    FloatingPointHelper::CheckFloatOperands(
+        masm, &non_number_comparison, ebx);
+    FloatingPointHelper::LoadFloatOperand(masm, eax);
+    FloatingPointHelper::LoadFloatOperand(masm, edx);
+    __ FCmp();
 
-      Label below_label, above_label;
-      // Return a result of -1, 0, or 1, based on EFLAGS.
-      __ j(below, &below_label, Label::kNear);
-      __ j(above, &above_label, Label::kNear);
+    // Don't base result on EFLAGS when a NaN is involved.
+    __ j(parity_even, &unordered, Label::kNear);
 
-      __ Set(eax, Immediate(0));
-      __ ret(0);
+    Label below_label, above_label;
+    // Return a result of -1, 0, or 1, based on EFLAGS.
+    __ j(below, &below_label, Label::kNear);
+    __ j(above, &above_label, Label::kNear);
 
-      __ bind(&below_label);
-      __ mov(eax, Immediate(Smi::FromInt(-1)));
-      __ ret(0);
+    __ Set(eax, Immediate(0));
+    __ ret(0);
 
-      __ bind(&above_label);
-      __ mov(eax, Immediate(Smi::FromInt(1)));
-      __ ret(0);
-    }
+    __ bind(&below_label);
+    __ mov(eax, Immediate(Smi::FromInt(-1)));
+    __ ret(0);
 
-    // If one of the numbers was NaN, then the result is always false.
-    // The cc is never not-equal.
-    __ bind(&unordered);
-    ASSERT(cc_ != not_equal);
-    if (cc_ == less || cc_ == less_equal) {
-      __ mov(eax, Immediate(Smi::FromInt(1)));
-    } else {
-      __ mov(eax, Immediate(Smi::FromInt(-1)));
-    }
+    __ bind(&above_label);
+    __ mov(eax, Immediate(Smi::FromInt(1)));
     __ ret(0);
+  }
 
-    // The number comparison code did not provide a valid result.
-    __ bind(&non_number_comparison);
+  // If one of the numbers was NaN, then the result is always false.
+  // The cc is never not-equal.
+  __ bind(&unordered);
+  ASSERT(cc != not_equal);
+  if (cc == less || cc == less_equal) {
+    __ mov(eax, Immediate(Smi::FromInt(1)));
+  } else {
+    __ mov(eax, Immediate(Smi::FromInt(-1)));
   }
+  __ ret(0);
+
+  // The number comparison code did not provide a valid result.
+  __ bind(&non_number_comparison);
 
   // Fast negative check for symbol-to-symbol equality.
   Label check_for_strings;
-  if (cc_ == equal) {
+  if (cc == equal) {
     BranchIfNonSymbol(masm, &check_for_strings, eax, ecx);
     BranchIfNonSymbol(masm, &check_for_strings, edx, ecx);
 
@@ -4574,7 +4523,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
                                          &check_unequal_objects);
 
   // Inline comparison of ASCII strings.
-  if (cc_ == equal) {
+  if (cc == equal) {
     StringCompareStub::GenerateFlatAsciiStringEquals(masm,
                                                      edx,
                                                      eax,
@@ -4593,7 +4542,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
 #endif
 
   __ bind(&check_unequal_objects);
-  if (cc_ == equal && !strict_) {
+  if (cc == equal && !strict()) {
     // Non-strict equality.  Objects are unequal if
     // they are both JSObjects and not undetectable,
     // and their pointers are different.
@@ -4637,11 +4586,11 @@ void CompareStub::Generate(MacroAssembler* masm) {
 
   // Figure out which native to call and setup the arguments.
   Builtins::JavaScript builtin;
-  if (cc_ == equal) {
-    builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  if (cc == equal) {
+    builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
   } else {
     builtin = Builtins::COMPARE;
-    __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
+    __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
   }
 
   // Restore return address on the stack.
@@ -4650,19 +4599,9 @@ void CompareStub::Generate(MacroAssembler* masm) {
   // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
   __ InvokeBuiltin(builtin, JUMP_FUNCTION);
-}
-
 
-void CompareStub::BranchIfNonSymbol(MacroAssembler* masm,
-                                    Label* label,
-                                    Register object,
-                                    Register scratch) {
-  __ JumpIfSmi(object, label);
-  __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset));
-  __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
-  __ and_(scratch, kIsSymbolMask | kIsNotStringMask);
-  __ cmp(scratch, kSymbolTag | kStringTag);
-  __ j(not_equal, label);
+  __ bind(&miss);
+  GenerateMiss(masm);
 }
 
 
@@ -5407,44 +5346,6 @@ Register InstanceofStub::left() { return eax; }
 Register InstanceofStub::right() { return edx; }
 
 
-int CompareStub::MinorKey() {
-  // Encode the three parameters in a unique 16 bit value. To avoid duplicate
-  // stubs the never NaN NaN condition is only taken into account if the
-  // condition is equals.
-  ASSERT(static_cast<unsigned>(cc_) < (1 << 12));
-  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
-  return ConditionField::encode(static_cast<unsigned>(cc_))
-         | RegisterField::encode(false)   // lhs_ and rhs_ are not used
-         | StrictField::encode(strict_)
-         | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
-         | IncludeNumberCompareField::encode(include_number_compare_)
-         | IncludeSmiCompareField::encode(include_smi_compare_);
-}
-
-
-// Unfortunately you have to run without snapshots to see most of these
-// names in the profile since most compare stubs end up in the snapshot.
-void CompareStub::PrintName(StringStream* stream) {
-  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
-  const char* cc_name;
-  switch (cc_) {
-    case less: cc_name = "LT"; break;
-    case greater: cc_name = "GT"; break;
-    case less_equal: cc_name = "LE"; break;
-    case greater_equal: cc_name = "GE"; break;
-    case equal: cc_name = "EQ"; break;
-    case not_equal: cc_name = "NE"; break;
-    default: cc_name = "UnknownCondition"; break;
-  }
-  bool is_equality = cc_ == equal || cc_ == not_equal;
-  stream->Add("CompareStub_%s", cc_name);
-  if (strict_ && is_equality) stream->Add("_STRICT");
-  if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN");
-  if (!include_number_compare_) stream->Add("_NO_NUMBER");
-  if (!include_smi_compare_) stream->Add("_NO_SMI");
-}
-
-
 // -------------------------------------------------------------------------
 // StringCharCodeAtGenerator
 
@@ -6606,7 +6507,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::SMIS);
+  ASSERT(state_ == CompareIC::SMI);
   Label miss;
   __ mov(ecx, edx);
   __ or_(ecx, eax);
@@ -6632,31 +6533,52 @@ void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::HEAP_NUMBERS);
+  ASSERT(state_ == CompareIC::HEAP_NUMBER);
 
   Label generic_stub;
   Label unordered, maybe_undefined1, maybe_undefined2;
   Label miss;
-  __ mov(ecx, edx);
-  __ and_(ecx, eax);
-  __ JumpIfSmi(ecx, &generic_stub, Label::kNear);
 
-  __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
-  __ j(not_equal, &maybe_undefined1, Label::kNear);
-  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
-  __ j(not_equal, &maybe_undefined2, Label::kNear);
+  if (left_ == CompareIC::SMI) {
+    __ JumpIfNotSmi(edx, &miss);
+  }
+  if (right_ == CompareIC::SMI) {
+    __ JumpIfNotSmi(eax, &miss);
+  }
 
   // Inlining the double comparison and falling back to the general compare
-  // stub if NaN is involved or SS2 or CMOV is unsupported.
+  // stub if NaN is involved or SSE2 or CMOV is unsupported.
   if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) {
     CpuFeatures::Scope scope1(SSE2);
     CpuFeatures::Scope scope2(CMOV);
 
-    // Load left and right operand
-    __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
+    // Load left and right operand.
+    Label done, left, left_smi, right_smi;
+    __ JumpIfSmi(eax, &right_smi, Label::kNear);
+    __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
+           masm->isolate()->factory()->heap_number_map());
+    __ j(not_equal, &maybe_undefined1, Label::kNear);
     __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
+    __ jmp(&left, Label::kNear);
+    __ bind(&right_smi);
+    __ mov(ecx, eax);  // Can't clobber eax because we can still jump away.
+    __ SmiUntag(ecx);
+    __ cvtsi2sd(xmm1, ecx);
+
+    __ bind(&left);
+    __ JumpIfSmi(edx, &left_smi, Label::kNear);
+    __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
+           masm->isolate()->factory()->heap_number_map());
+    __ j(not_equal, &maybe_undefined2, Label::kNear);
+    __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
+    __ jmp(&done);
+    __ bind(&left_smi);
+    __ mov(ecx, edx);  // Can't clobber edx because we can still jump away.
+    __ SmiUntag(ecx);
+    __ cvtsi2sd(xmm0, ecx);
 
-    // Compare operands
+    __ bind(&done);
+    // Compare operands.
     __ ucomisd(xmm0, xmm1);
 
     // Don't base result on EFLAGS when a NaN is involved.
@@ -6670,17 +6592,30 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
     __ mov(ecx, Immediate(Smi::FromInt(-1)));
     __ cmov(below, eax, ecx);
     __ ret(0);
+  } else {
+    __ mov(ecx, edx);
+    __ and_(ecx, eax);
+    __ JumpIfSmi(ecx, &generic_stub, Label::kNear);
+
+    __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
+           masm->isolate()->factory()->heap_number_map());
+    __ j(not_equal, &maybe_undefined1, Label::kNear);
+    __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
+           masm->isolate()->factory()->heap_number_map());
+    __ j(not_equal, &maybe_undefined2, Label::kNear);
   }
 
   __ bind(&unordered);
-  CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
   __ bind(&generic_stub);
+  ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
+                     CompareIC::GENERIC);
   __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
 
   __ bind(&maybe_undefined1);
   if (Token::IsOrderedRelationalCompareOp(op_)) {
     __ cmp(eax, Immediate(masm->isolate()->factory()->undefined_value()));
     __ j(not_equal, &miss);
+    __ JumpIfSmi(edx, &unordered);
     __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
     __ j(not_equal, &maybe_undefined2, Label::kNear);
     __ jmp(&unordered);
@@ -6698,7 +6633,7 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::SYMBOLS);
+  ASSERT(state_ == CompareIC::SYMBOL);
   ASSERT(GetCondition() == equal);
 
   // Registers containing left and right operands respectively.
@@ -6743,7 +6678,7 @@ void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::STRINGS);
+  ASSERT(state_ == CompareIC::STRING);
   Label miss;
 
   bool equality = Token::IsEqualityOp(op_);
@@ -6832,7 +6767,7 @@ void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::OBJECTS);
+  ASSERT(state_ == CompareIC::OBJECT);
   Label miss;
   __ mov(ecx, edx);
   __ and_(ecx, eax);
index 803a711de9694efeacc907db44d1f7342980d006..29c16e1304ba17f5520dfcbe67dcd23de197a38f 100644 (file)
@@ -154,96 +154,6 @@ class UnaryOpStub: public CodeStub {
 };
 
 
-class BinaryOpStub: public CodeStub {
- public:
-  BinaryOpStub(Token::Value op, OverwriteMode mode)
-      : op_(op),
-        mode_(mode),
-        operands_type_(BinaryOpIC::UNINITIALIZED),
-        result_type_(BinaryOpIC::UNINITIALIZED) {
-    use_sse3_ = CpuFeatures::IsSupported(SSE3);
-    ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
-  }
-
-  BinaryOpStub(
-      int key,
-      BinaryOpIC::TypeInfo operands_type,
-      BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
-      : op_(OpBits::decode(key)),
-        mode_(ModeBits::decode(key)),
-        use_sse3_(SSE3Bits::decode(key)),
-        operands_type_(operands_type),
-        result_type_(result_type) { }
-
- private:
-  enum SmiCodeGenerateHeapNumberResults {
-    ALLOW_HEAPNUMBER_RESULTS,
-    NO_HEAPNUMBER_RESULTS
-  };
-
-  Token::Value op_;
-  OverwriteMode mode_;
-  bool use_sse3_;
-
-  // Operand type information determined at runtime.
-  BinaryOpIC::TypeInfo operands_type_;
-  BinaryOpIC::TypeInfo result_type_;
-
-  virtual void PrintName(StringStream* stream);
-
-  // Minor key encoding in 16 bits RRRTTTSOOOOOOOMM.
-  class ModeBits: public BitField<OverwriteMode, 0, 2> {};
-  class OpBits: public BitField<Token::Value, 2, 7> {};
-  class SSE3Bits: public BitField<bool, 9, 1> {};
-  class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
-  class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
-
-  Major MajorKey() { return BinaryOp; }
-  int MinorKey() {
-    return OpBits::encode(op_)
-           | ModeBits::encode(mode_)
-           | SSE3Bits::encode(use_sse3_)
-           | OperandTypeInfoBits::encode(operands_type_)
-           | ResultTypeInfoBits::encode(result_type_);
-  }
-
-  void Generate(MacroAssembler* masm);
-  void GenerateGeneric(MacroAssembler* masm);
-  void GenerateSmiCode(MacroAssembler* masm,
-                       Label* slow,
-                       SmiCodeGenerateHeapNumberResults heapnumber_results);
-  void GenerateLoadArguments(MacroAssembler* masm);
-  void GenerateReturn(MacroAssembler* masm);
-  void GenerateUninitializedStub(MacroAssembler* masm);
-  void GenerateSmiStub(MacroAssembler* masm);
-  void GenerateInt32Stub(MacroAssembler* masm);
-  void GenerateHeapNumberStub(MacroAssembler* masm);
-  void GenerateOddballStub(MacroAssembler* masm);
-  void GenerateStringStub(MacroAssembler* masm);
-  void GenerateBothStringStub(MacroAssembler* masm);
-  void GenerateGenericStub(MacroAssembler* masm);
-  void GenerateAddStrings(MacroAssembler* masm);
-
-  void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure);
-  void GenerateRegisterArgsPush(MacroAssembler* masm);
-  void GenerateTypeTransition(MacroAssembler* masm);
-  void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
-
-  virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
-
-  virtual InlineCacheState GetICState() {
-    return BinaryOpIC::ToState(operands_type_);
-  }
-
-  virtual void FinishCode(Handle<Code> code) {
-    code->set_binary_op_type(operands_type_);
-    code->set_binary_op_result_type(result_type_);
-  }
-
-  friend class CodeGenerator;
-};
-
-
 class StringHelper : public AllStatic {
  public:
   // Generate code for copying characters using a simple loop. This should only
index 159c2cabcc928d6c36d8bfccfeb81738825a573d..ee2abaaa4d4aebed483b395873b64f9c4892d742 100644 (file)
@@ -4290,29 +4290,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
 
     default: {
       VisitForAccumulatorValue(expr->right());
-      Condition cc = no_condition;
-      switch (op) {
-        case Token::EQ_STRICT:
-        case Token::EQ:
-          cc = equal;
-          break;
-        case Token::LT:
-          cc = less;
-          break;
-        case Token::GT:
-          cc = greater;
-         break;
-        case Token::LTE:
-          cc = less_equal;
-          break;
-        case Token::GTE:
-          cc = greater_equal;
-          break;
-        case Token::IN:
-        case Token::INSTANCEOF:
-        default:
-          UNREACHABLE();
-      }
+      Condition cc = CompareIC::ComputeCondition(op);
       __ pop(edx);
 
       bool inline_smi_code = ShouldInlineSmiCase(op);
index dae3bbd63b8f3c94b770cd1f765506f723d442b6..ac5af2bf66a3f504a9e130ed6e866e2ae7a89814 100644 (file)
@@ -1715,7 +1715,7 @@ Condition CompareIC::ComputeCondition(Token::Value op) {
 }
 
 
-static bool HasInlinedSmiCode(Address address) {
+bool CompareIC::HasInlinedSmiCode(Address address) {
   // The address of the instruction following the call.
   Address test_instruction_address =
       address + Assembler::kCallTargetAddressOffset;
@@ -1726,40 +1726,6 @@ static bool HasInlinedSmiCode(Address address) {
 }
 
 
-void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
-  HandleScope scope;
-  Handle<Code> rewritten;
-  State previous_state = GetState();
-
-  State state = TargetState(previous_state, HasInlinedSmiCode(address()), x, y);
-  if (state == GENERIC) {
-    CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
-    rewritten = stub.GetCode();
-  } else {
-    ICCompareStub stub(op_, state);
-    if (state == KNOWN_OBJECTS) {
-      stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
-    }
-    rewritten = stub.GetCode();
-  }
-  set_target(*rewritten);
-
-#ifdef DEBUG
-  if (FLAG_trace_ic) {
-    PrintF("[CompareIC (%s->%s)#%s]\n",
-           GetStateName(previous_state),
-           GetStateName(state),
-           Token::Name(op_));
-  }
-#endif
-
-  // Activate inlined smi code.
-  if (previous_state == UNINITIALIZED) {
-    PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
-  }
-}
-
-
 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
   // The address of the instruction following the call.
   Address test_instruction_address =
index 6e86d920a26fcea1546ddf6e6a56254b7b59d4e1..3e19c39ba24de278a78f128739f899402e46735a 100644 (file)
@@ -302,7 +302,30 @@ bool LCodeGen::GenerateBody() {
     }
 
     if (emit_instructions) {
-      Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
+      if (FLAG_code_comments) {
+        HValue* hydrogen = instr->hydrogen_value();
+        if (hydrogen != NULL) {
+          if (hydrogen->IsChange()) {
+            HValue* changed_value = HChange::cast(hydrogen)->value();
+            int use_id = 0;
+            const char* use_mnemo = "dead";
+            if (hydrogen->UseCount() >= 1) {
+              HValue* use_value = hydrogen->uses().value();
+              use_id = use_value->id();
+              use_mnemo = use_value->Mnemonic();
+            }
+            Comment(";;; @%d: %s. <of #%d %s for #%d %s>",
+                    current_instruction_, instr->Mnemonic(),
+                    changed_value->id(), changed_value->Mnemonic(),
+                    use_id, use_mnemo);
+          } else {
+            Comment(";;; @%d: %s. <#%d>", current_instruction_,
+                    instr->Mnemonic(), hydrogen->id());
+          }
+        } else {
+          Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
+        }
+      }
       instr->CompileToNative(this);
     }
   }
@@ -4411,6 +4434,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
     // Check for undefined. Undefined is converted to zero for truncating
     // conversions.
     __ cmp(input_reg, factory()->undefined_value());
+    __ RecordComment("Deferred TaggedToI: cannot truncate");
     DeoptimizeIf(not_equal, instr->environment());
     __ mov(input_reg, 0);
     __ jmp(&done, Label::kNear);
@@ -4431,6 +4455,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
       __ j(less, &convert, Label::kNear);
       // Pop FPU stack before deoptimizing.
       __ fstp(0);
+      __ RecordComment("Deferred TaggedToI: exponent too big");
       DeoptimizeIf(no_condition, instr->environment());
 
       // Reserve space for 64 bit answer.
@@ -4456,6 +4481,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
     }
   } else {
     // Deoptimize if we don't have a heap number.
+    __ RecordComment("Deferred TaggedToI: not a heap number");
     DeoptimizeIf(not_equal, instr->environment());
 
     XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
@@ -4463,13 +4489,16 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
     __ cvttsd2si(input_reg, Operand(xmm0));
     __ cvtsi2sd(xmm_temp, Operand(input_reg));
     __ ucomisd(xmm0, xmm_temp);
+    __ RecordComment("Deferred TaggedToI: lost precision");
     DeoptimizeIf(not_equal, instr->environment());
+    __ RecordComment("Deferred TaggedToI: NaN");
     DeoptimizeIf(parity_even, instr->environment());  // NaN.
     if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
       __ test(input_reg, Operand(input_reg));
       __ j(not_zero, &done);
       __ movmskpd(input_reg, xmm0);
       __ and_(input_reg, 1);
+      __ RecordComment("Deferred TaggedToI: minus zero");
       DeoptimizeIf(not_zero, instr->environment());
     }
   }
index 4207410cdf28c4dbc5c9c779da85436c7ac0a32f..a07b8d944daf187a2d745a847ee6df49268df361 100644 (file)
@@ -1449,7 +1449,7 @@ LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
 
 LInstruction* LChunkBuilder::DoCompareIDAndBranch(
     HCompareIDAndBranch* instr) {
-  Representation r = instr->GetInputRepresentation();
+  Representation r = instr->representation();
   if (r.IsInteger32()) {
     ASSERT(instr->left()->representation().IsInteger32());
     ASSERT(instr->right()->representation().IsInteger32());
@@ -2289,7 +2289,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
   env->set_ast_id(instr->ast_id());
 
   env->Drop(instr->pop_count());
-  for (int i = 0; i < instr->values()->length(); ++i) {
+  for (int i = instr->values()->length() - 1; i >= 0; --i) {
     HValue* value = instr->values()->at(i);
     if (instr->HasAssignedIndexAt(i)) {
       env->Bind(instr->GetAssignedIndexAt(i), value);
index 88b1ef01ea04092fc083f07b3b662abb3849af7c..8ee3ca078cb84ee43cf8c1ce26b9de925e53f82a 100644 (file)
@@ -614,7 +614,7 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> {
 
   Token::Value op() const { return hydrogen()->token(); }
   bool is_double() const {
-    return hydrogen()->GetInputRepresentation().IsDouble();
+    return hydrogen()->representation().IsDouble();
   }
 
   virtual void PrintDataTo(StringStream* stream);
index 1418f02fbe889bcb5c5c935b4599b4d8a57742d3..d46a24b7b9b484ee1c7e9f5e0d81220589777875 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -414,11 +414,13 @@ void KeyedStoreIC::Clear(Address address, Code* target) {
 
 
 void CompareIC::Clear(Address address, Code* target) {
-  // Only clear ICCompareStubs, we currently cannot clear generic CompareStubs.
-  if (target->major_key() != CodeStub::CompareIC) return;
+  ASSERT(target->major_key() == CodeStub::CompareIC);
+  CompareIC::State handler_state;
+  Token::Value op;
+  ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL,
+                                &handler_state, &op);
   // Only clear CompareICs that can retain objects.
-  if (target->compare_state() != KNOWN_OBJECTS) return;
-  Token::Value op = CompareIC::ComputeOperation(target);
+  if (handler_state != KNOWN_OBJECTS) return;
   SetTargetAtAddress(address, GetRawUninitialized(op));
   PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
 }
@@ -2313,11 +2315,10 @@ const char* BinaryOpIC::GetName(TypeInfo type_info) {
   switch (type_info) {
     case UNINITIALIZED: return "Uninitialized";
     case SMI: return "SMI";
-    case INT32: return "Int32s";
-    case HEAP_NUMBER: return "HeapNumbers";
+    case INT32: return "Int32";
+    case HEAP_NUMBER: return "HeapNumber";
     case ODDBALL: return "Oddball";
-    case BOTH_STRING: return "BothStrings";
-    case STRING: return "Strings";
+    case STRING: return "String";
     case GENERIC: return "Generic";
     default: return "Invalid";
   }
@@ -2332,7 +2333,6 @@ BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) {
     case INT32:
     case HEAP_NUMBER:
     case ODDBALL:
-    case BOTH_STRING:
     case STRING:
       return MONOMORPHIC;
     case GENERIC:
@@ -2343,58 +2343,6 @@ BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) {
 }
 
 
-BinaryOpIC::TypeInfo BinaryOpIC::JoinTypes(BinaryOpIC::TypeInfo x,
-                                           BinaryOpIC::TypeInfo y) {
-  if (x == UNINITIALIZED) return y;
-  if (y == UNINITIALIZED) return x;
-  if (x == y) return x;
-  if (x == BOTH_STRING && y == STRING) return STRING;
-  if (x == STRING && y == BOTH_STRING) return STRING;
-  if (x == STRING || x == BOTH_STRING || y == STRING || y == BOTH_STRING) {
-    return GENERIC;
-  }
-  if (x > y) return x;
-  return y;
-}
-
-
-BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Handle<Object> left,
-                                             Handle<Object> right) {
-  ::v8::internal::TypeInfo left_type =
-      ::v8::internal::TypeInfo::TypeFromValue(left);
-  ::v8::internal::TypeInfo right_type =
-      ::v8::internal::TypeInfo::TypeFromValue(right);
-
-  if (left_type.IsSmi() && right_type.IsSmi()) {
-    return SMI;
-  }
-
-  if (left_type.IsInteger32() && right_type.IsInteger32()) {
-    // Platforms with 32-bit Smis have no distinct INT32 type.
-    if (kSmiValueSize == 32) return SMI;
-    return INT32;
-  }
-
-  if (left_type.IsNumber() && right_type.IsNumber()) {
-    return HEAP_NUMBER;
-  }
-
-  // Patching for fast string ADD makes sense even if only one of the
-  // arguments is a string.
-  if (left_type.IsString())  {
-    return right_type.IsString() ? BOTH_STRING : STRING;
-  } else if (right_type.IsString()) {
-    return STRING;
-  }
-
-  // Check for oddball objects.
-  if (left->IsUndefined() && right->IsNumber()) return ODDBALL;
-  if (left->IsNumber() && right->IsUndefined()) return ODDBALL;
-
-  return GENERIC;
-}
-
-
 RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) {
   ASSERT(args.length() == 4);
 
@@ -2446,25 +2394,72 @@ RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) {
   return *result;
 }
 
+
+static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value,
+                                              Token::Value op) {
+  ::v8::internal::TypeInfo type =
+      ::v8::internal::TypeInfo::TypeFromValue(value);
+  if (type.IsSmi()) return BinaryOpIC::SMI;
+  if (type.IsInteger32()) {
+    if (kSmiValueSize == 32) return BinaryOpIC::SMI;
+    return BinaryOpIC::INT32;
+  }
+  if (type.IsNumber()) return BinaryOpIC::HEAP_NUMBER;
+  if (type.IsString()) return BinaryOpIC::STRING;
+  if (value->IsUndefined()) {
+    if (op == Token::BIT_AND ||
+        op == Token::BIT_OR ||
+        op == Token::BIT_XOR ||
+        op == Token::SAR ||
+        op == Token::SHL ||
+        op == Token::SHR) {
+      if (kSmiValueSize == 32) return BinaryOpIC::SMI;
+      return BinaryOpIC::INT32;
+    }
+    return BinaryOpIC::ODDBALL;
+  }
+  return BinaryOpIC::GENERIC;
+}
+
+
+static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type,
+                                       Handle<Object> value,
+                                       Token::Value op) {
+  BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op);
+  if (old_type == BinaryOpIC::STRING) {
+    if (new_type == BinaryOpIC::STRING) return new_type;
+    return BinaryOpIC::GENERIC;
+  }
+  return Max(old_type, new_type);
+}
+
+
 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
-  ASSERT(args.length() == 5);
+  ASSERT(args.length() == 3);
 
   HandleScope scope(isolate);
   Handle<Object> left = args.at<Object>(0);
   Handle<Object> right = args.at<Object>(1);
   int key = args.smi_at(2);
-  Token::Value op = static_cast<Token::Value>(args.smi_at(3));
-  BinaryOpIC::TypeInfo previous_type =
-      static_cast<BinaryOpIC::TypeInfo>(args.smi_at(4));
+  Token::Value op = BinaryOpStub::decode_op_from_minor_key(key);
+  BinaryOpIC::TypeInfo previous_left, previous_right, unused_previous_result;
+  BinaryOpStub::decode_types_from_minor_key(
+      key, &previous_left, &previous_right, &unused_previous_result);
 
-  BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(left, right);
-  type = BinaryOpIC::JoinTypes(type, previous_type);
+  BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op);
+  BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op);
   BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED;
-  if ((type == BinaryOpIC::STRING || type == BinaryOpIC::BOTH_STRING) &&
+
+  // STRING is only used for ADD operations.
+  if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) &&
       op != Token::ADD) {
-    type = BinaryOpIC::GENERIC;
+    new_left = new_right = BinaryOpIC::GENERIC;
   }
-  if (type == BinaryOpIC::SMI && previous_type == BinaryOpIC::SMI) {
+
+  BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right);
+  BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right);
+
+  if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) {
     if (op == Token::DIV ||
         op == Token::MUL ||
         op == Token::SHR ||
@@ -2479,26 +2474,35 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
       result_type = BinaryOpIC::INT32;
     }
   }
-  if (type == BinaryOpIC::INT32 && previous_type == BinaryOpIC::INT32) {
-    // We must be here because an operation on two INT32 types overflowed.
-    result_type = BinaryOpIC::HEAP_NUMBER;
+  if (new_overall == BinaryOpIC::INT32 &&
+      previous_overall == BinaryOpIC::INT32) {
+    if (new_left == previous_left && new_right == previous_right) {
+      result_type = BinaryOpIC::HEAP_NUMBER;
+    }
   }
 
-  BinaryOpStub stub(key, type, result_type);
+  BinaryOpStub stub(key, new_left, new_right, result_type);
   Handle<Code> code = stub.GetCode();
   if (!code.is_null()) {
+#ifdef DEBUG
     if (FLAG_trace_ic) {
-      PrintF("[BinaryOpIC (%s->(%s->%s))#%s]\n",
-             BinaryOpIC::GetName(previous_type),
-             BinaryOpIC::GetName(type),
+      PrintF("[BinaryOpIC in ");
+      JavaScriptFrame::PrintTop(stdout, false, true);
+      PrintF(" ((%s+%s)->((%s+%s)->%s))#%s @ %p]\n",
+             BinaryOpIC::GetName(previous_left),
+             BinaryOpIC::GetName(previous_right),
+             BinaryOpIC::GetName(new_left),
+             BinaryOpIC::GetName(new_right),
              BinaryOpIC::GetName(result_type),
-             Token::Name(op));
+             Token::Name(op),
+             static_cast<void*>(*code));
     }
+#endif
     BinaryOpIC ic(isolate);
     ic.patch(*code);
 
     // Activate inlined smi code.
-    if (previous_type == BinaryOpIC::UNINITIALIZED) {
+    if (previous_overall == BinaryOpIC::UNINITIALIZED) {
       PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK);
     }
   }
@@ -2561,7 +2565,7 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
 
 
 Code* CompareIC::GetRawUninitialized(Token::Value op) {
-  ICCompareStub stub(op, UNINITIALIZED);
+  ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
   Code* code = NULL;
   CHECK(stub.FindCodeInCache(&code));
   return code;
@@ -2569,35 +2573,20 @@ Code* CompareIC::GetRawUninitialized(Token::Value op) {
 
 
 Handle<Code> CompareIC::GetUninitialized(Token::Value op) {
-  ICCompareStub stub(op, UNINITIALIZED);
+  ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
   return stub.GetCode();
 }
 
 
-CompareIC::State CompareIC::ComputeState(Code* target) {
-  int key = target->major_key();
-  if (key == CodeStub::Compare) return GENERIC;
-  ASSERT(key == CodeStub::CompareIC);
-  return static_cast<State>(target->compare_state());
-}
-
-
-Token::Value CompareIC::ComputeOperation(Code* target) {
-  ASSERT(target->major_key() == CodeStub::CompareIC);
-  return static_cast<Token::Value>(
-      target->compare_operation() + Token::EQ);
-}
-
-
 const char* CompareIC::GetStateName(State state) {
   switch (state) {
     case UNINITIALIZED: return "UNINITIALIZED";
-    case SMIS: return "SMIS";
-    case HEAP_NUMBERS: return "HEAP_NUMBERS";
-    case OBJECTS: return "OBJECTS";
+    case SMI: return "SMI";
+    case HEAP_NUMBER: return "HEAP_NUMBER";
+    case OBJECT: return "OBJECTS";
     case KNOWN_OBJECTS: return "KNOWN_OBJECTS";
-    case SYMBOLS: return "SYMBOLS";
-    case STRINGS: return "STRINGS";
+    case SYMBOL: return "SYMBOL";
+    case STRING: return "STRING";
     case GENERIC: return "GENERIC";
     default:
       UNREACHABLE();
@@ -2606,28 +2595,67 @@ const char* CompareIC::GetStateName(State state) {
 }
 
 
-CompareIC::State CompareIC::TargetState(State state,
+static CompareIC::State InputState(CompareIC::State old_state,
+                                   Handle<Object> value) {
+  switch (old_state) {
+    case CompareIC::UNINITIALIZED:
+      if (value->IsSmi()) return CompareIC::SMI;
+      if (value->IsHeapNumber()) return CompareIC::HEAP_NUMBER;
+      if (value->IsSymbol()) return CompareIC::SYMBOL;
+      if (value->IsString()) return CompareIC::STRING;
+      if (value->IsJSObject()) return CompareIC::OBJECT;
+      break;
+    case CompareIC::SMI:
+      if (value->IsSmi()) return CompareIC::SMI;
+      if (value->IsHeapNumber()) return CompareIC::HEAP_NUMBER;
+      break;
+    case CompareIC::HEAP_NUMBER:
+      if (value->IsNumber()) return CompareIC::HEAP_NUMBER;
+      break;
+    case CompareIC::SYMBOL:
+      if (value->IsSymbol()) return CompareIC::SYMBOL;
+      if (value->IsString()) return CompareIC::STRING;
+      break;
+    case CompareIC::STRING:
+      if (value->IsSymbol() || value->IsString()) return CompareIC::STRING;
+      break;
+    case CompareIC::OBJECT:
+      if (value->IsJSObject()) return CompareIC::OBJECT;
+      break;
+    case CompareIC::GENERIC:
+      break;
+    case CompareIC::KNOWN_OBJECTS:
+      UNREACHABLE();
+      break;
+  }
+  return CompareIC::GENERIC;
+}
+
+
+CompareIC::State CompareIC::TargetState(State old_state,
+                                        State old_left,
+                                        State old_right,
                                         bool has_inlined_smi_code,
                                         Handle<Object> x,
                                         Handle<Object> y) {
-  switch (state) {
+  switch (old_state) {
     case UNINITIALIZED:
-      if (x->IsSmi() && y->IsSmi()) return SMIS;
-      if (x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS;
+      if (x->IsSmi() && y->IsSmi()) return SMI;
+      if (x->IsNumber() && y->IsNumber()) return HEAP_NUMBER;
       if (Token::IsOrderedRelationalCompareOp(op_)) {
         // Ordered comparisons treat undefined as NaN, so the
         // HEAP_NUMBER stub will do the right thing.
         if ((x->IsNumber() && y->IsUndefined()) ||
             (y->IsNumber() && x->IsUndefined())) {
-          return HEAP_NUMBERS;
+          return HEAP_NUMBER;
         }
       }
       if (x->IsSymbol() && y->IsSymbol()) {
         // We compare symbols as strings if we need to determine
         // the order in a non-equality compare.
-        return Token::IsEqualityOp(op_) ? SYMBOLS : STRINGS;
+        return Token::IsEqualityOp(op_) ? SYMBOL : STRING;
       }
-      if (x->IsString() && y->IsString()) return STRINGS;
+      if (x->IsString() && y->IsString()) return STRING;
       if (!Token::IsEqualityOp(op_)) return GENERIC;
       if (x->IsJSObject() && y->IsJSObject()) {
         if (Handle<JSObject>::cast(x)->map() ==
@@ -2635,30 +2663,70 @@ CompareIC::State CompareIC::TargetState(State state,
             Token::IsEqualityOp(op_)) {
           return KNOWN_OBJECTS;
         } else {
-          return OBJECTS;
+          return OBJECT;
         }
       }
       return GENERIC;
-    case SMIS:
-      return has_inlined_smi_code && x->IsNumber() && y->IsNumber()
-          ? HEAP_NUMBERS
+    case SMI:
+      return x->IsNumber() && y->IsNumber()
+          ? HEAP_NUMBER
           : GENERIC;
-    case SYMBOLS:
+    case SYMBOL:
       ASSERT(Token::IsEqualityOp(op_));
-      return x->IsString() && y->IsString() ? STRINGS : GENERIC;
-    case HEAP_NUMBERS:
-    case STRINGS:
-    case OBJECTS:
+      return x->IsString() && y->IsString() ? STRING : GENERIC;
+    case HEAP_NUMBER:
+      if (old_left == SMI && x->IsHeapNumber()) return HEAP_NUMBER;
+      if (old_right == SMI && y->IsHeapNumber()) return HEAP_NUMBER;
+    case STRING:
+    case OBJECT:
     case KNOWN_OBJECTS:
     case GENERIC:
       return GENERIC;
   }
   UNREACHABLE();
-  return GENERIC;
+  return GENERIC;  // Make the compiler happy.
+}
+
+
+void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
+  HandleScope scope;
+  State previous_left, previous_right, previous_state;
+  ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left,
+                                &previous_right, &previous_state, NULL);
+  State new_left = InputState(previous_left, x);
+  State new_right = InputState(previous_right, y);
+  State state = TargetState(previous_state, previous_left, previous_right,
+                            HasInlinedSmiCode(address()), x, y);
+  ICCompareStub stub(op_, new_left, new_right, state);
+  if (state == KNOWN_OBJECTS) {
+    stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
+  }
+  set_target(*stub.GetCode());
+
+#ifdef DEBUG
+  if (FLAG_trace_ic) {
+    PrintF("[CompareIC in ");
+    JavaScriptFrame::PrintTop(stdout, false, true);
+    PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
+           GetStateName(previous_left),
+           GetStateName(previous_right),
+           GetStateName(previous_state),
+           GetStateName(new_left),
+           GetStateName(new_right),
+           GetStateName(state),
+           Token::Name(op_),
+           static_cast<void*>(*stub.GetCode()));
+  }
+#endif
+
+  // Activate inlined smi code.
+  if (previous_state == UNINITIALIZED) {
+    PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
+  }
 }
 
 
-// Used from ic_<arch>.cc.
+// Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc.
 RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
   NoHandleAllocation na;
   ASSERT(args.length() == 3);
index 8767f988a2936554007b0147bed95515e9f8d328..bfccd10a6ad3c790764100be0e400dd73cf426dc 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -771,8 +771,7 @@ class BinaryOpIC: public IC {
     INT32,
     HEAP_NUMBER,
     ODDBALL,
-    BOTH_STRING,  // Only used for addition operation.
-    STRING,  // Only used for addition operation.  At least one string operand.
+    STRING,  // Only used for addition operation.
     GENERIC
   };
 
@@ -783,10 +782,6 @@ class BinaryOpIC: public IC {
   static const char* GetName(TypeInfo type_info);
 
   static State ToState(TypeInfo type_info);
-
-  static TypeInfo GetTypeInfo(Handle<Object> left, Handle<Object> right);
-
-  static TypeInfo JoinTypes(TypeInfo x, TypeInfo y);
 };
 
 
@@ -794,11 +789,11 @@ class CompareIC: public IC {
  public:
   enum State {
     UNINITIALIZED,
-    SMIS,
-    HEAP_NUMBERS,
-    SYMBOLS,
-    STRINGS,
-    OBJECTS,
+    SMI,
+    HEAP_NUMBER,
+    SYMBOL,
+    STRING,
+    OBJECT,
     KNOWN_OBJECTS,
     GENERIC
   };
@@ -809,27 +804,27 @@ class CompareIC: public IC {
   // Update the inline cache for the given operands.
   void UpdateCaches(Handle<Object> x, Handle<Object> y);
 
+
   // Factory method for getting an uninitialized compare stub.
   static Handle<Code> GetUninitialized(Token::Value op);
 
   // Helper function for computing the condition for a compare operation.
   static Condition ComputeCondition(Token::Value op);
 
-  // Helper function for determining the state of a compare IC.
-  static State ComputeState(Code* target);
-
-  // Helper function for determining the operation a compare IC is for.
-  static Token::Value ComputeOperation(Code* target);
-
   static const char* GetStateName(State state);
 
  private:
-  State TargetState(State state, bool has_inlined_smi_code,
-                    Handle<Object> x, Handle<Object> y);
+  static bool HasInlinedSmiCode(Address address);
+
+  State TargetState(State old_state,
+                    State old_left,
+                    State old_right,
+                    bool has_inlined_smi_code,
+                    Handle<Object> x,
+                    Handle<Object> y);
 
   bool strict() const { return op_ == Token::EQ_STRICT; }
   Condition GetCondition() const { return ComputeCondition(op_); }
-  State GetState() { return ComputeState(target()); }
 
   static Code* GetRawUninitialized(Token::Value op);
 
index ab9ce1af127c07043a0909ec3908cb1b90a14696..24b693f46f06b76a2af87dfbce9caf7a07a5f928 100644 (file)
@@ -3416,66 +3416,6 @@ void Code::set_unary_op_type(byte value) {
 }
 
 
-byte Code::binary_op_type() {
-  ASSERT(is_binary_op_stub());
-  return BinaryOpTypeField::decode(
-      READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
-}
-
-
-void Code::set_binary_op_type(byte value) {
-  ASSERT(is_binary_op_stub());
-  int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
-  int updated = BinaryOpTypeField::update(previous, value);
-  WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
-}
-
-
-byte Code::binary_op_result_type() {
-  ASSERT(is_binary_op_stub());
-  return BinaryOpResultTypeField::decode(
-      READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
-}
-
-
-void Code::set_binary_op_result_type(byte value) {
-  ASSERT(is_binary_op_stub());
-  int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
-  int updated = BinaryOpResultTypeField::update(previous, value);
-  WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
-}
-
-
-byte Code::compare_state() {
-  ASSERT(is_compare_ic_stub());
-  return CompareStateField::decode(
-      READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
-}
-
-
-void Code::set_compare_state(byte value) {
-  ASSERT(is_compare_ic_stub());
-  int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
-  int updated = CompareStateField::update(previous, value);
-  WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
-}
-
-
-byte Code::compare_operation() {
-  ASSERT(is_compare_ic_stub());
-  return CompareOperationField::decode(
-      READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
-}
-
-
-void Code::set_compare_operation(byte value) {
-  ASSERT(is_compare_ic_stub());
-  int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
-  int updated = CompareOperationField::update(previous, value);
-  WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
-}
-
-
 byte Code::to_boolean_state() {
   ASSERT(is_to_boolean_ic_stub());
   return ToBooleanStateField::decode(
@@ -4630,10 +4570,45 @@ INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset)
 ACCESSORS(Code, relocation_info, ByteArray, kRelocationInfoOffset)
 ACCESSORS(Code, handler_table, FixedArray, kHandlerTableOffset)
 ACCESSORS(Code, deoptimization_data, FixedArray, kDeoptimizationDataOffset)
-ACCESSORS(Code, type_feedback_info, Object, kTypeFeedbackInfoOffset)
+
+
+// Type feedback slot: type_feedback_info for FUNCTIONs, stub_info for STUBs.
+void Code::InitializeTypeFeedbackInfoNoWriteBarrier(Object* value) {
+  WRITE_FIELD(this, kTypeFeedbackInfoOffset, value);
+}
+
+
+Object* Code::type_feedback_info() {
+  ASSERT(kind() == FUNCTION);
+  return Object::cast(READ_FIELD(this, kTypeFeedbackInfoOffset));
+}
+
+
+void Code::set_type_feedback_info(Object* value, WriteBarrierMode mode) {
+  ASSERT(kind() == FUNCTION);
+  WRITE_FIELD(this, kTypeFeedbackInfoOffset, value);
+  CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kTypeFeedbackInfoOffset,
+                            value, mode);
+}
+
+
+int Code::stub_info() {
+  ASSERT(kind() == COMPARE_IC || kind() == BINARY_OP_IC);
+  Object* value = READ_FIELD(this, kTypeFeedbackInfoOffset);
+  return Smi::cast(value)->value();
+}
+
+
+void Code::set_stub_info(int value) {
+  ASSERT(kind() == COMPARE_IC || kind() == BINARY_OP_IC);
+  WRITE_FIELD(this, kTypeFeedbackInfoOffset, Smi::FromInt(value));
+}
+
+
 ACCESSORS(Code, gc_metadata, Object, kGCMetadataOffset)
 INT_ACCESSORS(Code, ic_age, kICAgeOffset)
 
+
 byte* Code::instruction_start()  {
   return FIELD_ADDR(this, kHeaderSize);
 }
index a03054653aa16cf014d8ffd83783a7ccd4d7c223..1f7c0286e1c95feb868228df2ee5154383be4105 100644 (file)
@@ -8781,6 +8781,7 @@ void Code::ClearInlineCaches() {
 
 
 void Code::ClearTypeFeedbackCells(Heap* heap) {
+  if (kind() != FUNCTION) return;
   Object* raw_info = type_feedback_info();
   if (raw_info->IsTypeFeedbackInfo()) {
     TypeFeedbackCells* type_feedback_cells =
@@ -8795,7 +8796,8 @@ void Code::ClearTypeFeedbackCells(Heap* heap) {
 
 bool Code::allowed_in_shared_map_code_cache() {
   return is_keyed_load_stub() || is_keyed_store_stub() ||
-      (is_compare_ic_stub() && compare_state() == CompareIC::KNOWN_OBJECTS);
+      (is_compare_ic_stub() &&
+       ICCompareStub::CompareState(stub_info()) == CompareIC::KNOWN_OBJECTS);
 }
 
 
@@ -9150,11 +9152,15 @@ void Code::Disassemble(const char* name, FILE* out) {
       PrintF(out, "argc = %d\n", arguments_count());
     }
     if (is_compare_ic_stub()) {
-      CompareIC::State state = CompareIC::ComputeState(this);
-      PrintF(out, "compare_state = %s\n", CompareIC::GetStateName(state));
-    }
-    if (is_compare_ic_stub() && major_key() == CodeStub::CompareIC) {
-      Token::Value op = CompareIC::ComputeOperation(this);
+      ASSERT(major_key() == CodeStub::CompareIC);
+      CompareIC::State left_state, right_state, handler_state;
+      Token::Value op;
+      ICCompareStub::DecodeMinorKey(stub_info(), &left_state, &right_state,
+                                    &handler_state, &op);
+      PrintF(out, "compare_state = %s*%s -> %s\n",
+             CompareIC::GetStateName(left_state),
+             CompareIC::GetStateName(right_state),
+             CompareIC::GetStateName(handler_state));
       PrintF(out, "compare_operation = %s\n", Token::Name(op));
     }
   }
@@ -9200,8 +9206,6 @@ void Code::Disassemble(const char* name, FILE* out) {
       PrintF(out, "\n");
     }
     PrintF(out, "\n");
-    // Just print if type feedback info is ever used for optimized code.
-    ASSERT(type_feedback_info()->IsUndefined());
   } else if (kind() == FUNCTION) {
     unsigned offset = stack_check_table_offset();
     // If there is no stack check table, the "table start" will at or after
index 3dc6188997bdead58671bc9982202033e64f5e38..9d1951a85f656400a63cf9f00dcc22e9d93d0ec4 100644 (file)
@@ -4306,8 +4306,12 @@ class Code: public HeapObject {
   DECL_ACCESSORS(deoptimization_data, FixedArray)
 
   // [type_feedback_info]: Struct containing type feedback information.
-  // Will contain either a TypeFeedbackInfo object, or undefined.
+  // STUBs can use this slot to store arbitrary information as a Smi.
+  // Will contain either a TypeFeedbackInfo object, or undefined, or a Smi.
   DECL_ACCESSORS(type_feedback_info, Object)
+  inline void InitializeTypeFeedbackInfoNoWriteBarrier(Object* value);
+  inline int stub_info();
+  inline void set_stub_info(int info);
 
   // [gc_metadata]: Field used to hold GC related metadata. The contents of this
   // field does not have to be traced during garbage collection since
@@ -4413,21 +4417,6 @@ class Code: public HeapObject {
   inline byte unary_op_type();
   inline void set_unary_op_type(byte value);
 
-  // [type-recording binary op type]: For kind BINARY_OP_IC.
-  inline byte binary_op_type();
-  inline void set_binary_op_type(byte value);
-  inline byte binary_op_result_type();
-  inline void set_binary_op_result_type(byte value);
-
-  // [compare state]: For kind COMPARE_IC, tells what state the stub is in.
-  inline byte compare_state();
-  inline void set_compare_state(byte value);
-
-  // [compare_operation]: For kind COMPARE_IC tells what compare operation the
-  // stub was generated for.
-  inline byte compare_operation();
-  inline void set_compare_operation(byte value);
-
   // [to_boolean_foo]: For kind TO_BOOLEAN_IC tells what state the stub is in.
   inline byte to_boolean_state();
   inline void set_to_boolean_state(byte value);
@@ -4637,18 +4626,6 @@ class Code: public HeapObject {
   static const int kUnaryOpTypeFirstBit =
       kStackSlotsFirstBit + kStackSlotsBitCount;
   static const int kUnaryOpTypeBitCount = 3;
-  static const int kBinaryOpTypeFirstBit =
-      kStackSlotsFirstBit + kStackSlotsBitCount;
-  static const int kBinaryOpTypeBitCount = 3;
-  static const int kBinaryOpResultTypeFirstBit =
-      kBinaryOpTypeFirstBit + kBinaryOpTypeBitCount;
-  static const int kBinaryOpResultTypeBitCount = 3;
-  static const int kCompareStateFirstBit =
-      kStackSlotsFirstBit + kStackSlotsBitCount;
-  static const int kCompareStateBitCount = 3;
-  static const int kCompareOperationFirstBit =
-      kCompareStateFirstBit + kCompareStateBitCount;
-  static const int kCompareOperationBitCount = 4;
   static const int kToBooleanStateFirstBit =
       kStackSlotsFirstBit + kStackSlotsBitCount;
   static const int kToBooleanStateBitCount = 8;
@@ -4658,11 +4635,6 @@ class Code: public HeapObject {
 
   STATIC_ASSERT(kStackSlotsFirstBit + kStackSlotsBitCount <= 32);
   STATIC_ASSERT(kUnaryOpTypeFirstBit + kUnaryOpTypeBitCount <= 32);
-  STATIC_ASSERT(kBinaryOpTypeFirstBit + kBinaryOpTypeBitCount <= 32);
-  STATIC_ASSERT(kBinaryOpResultTypeFirstBit +
-                kBinaryOpResultTypeBitCount <= 32);
-  STATIC_ASSERT(kCompareStateFirstBit + kCompareStateBitCount <= 32);
-  STATIC_ASSERT(kCompareOperationFirstBit + kCompareOperationBitCount <= 32);
   STATIC_ASSERT(kToBooleanStateFirstBit + kToBooleanStateBitCount <= 32);
   STATIC_ASSERT(kHasFunctionCacheFirstBit + kHasFunctionCacheBitCount <= 32);
 
@@ -4670,14 +4642,6 @@ class Code: public HeapObject {
       kStackSlotsFirstBit, kStackSlotsBitCount> {};  // NOLINT
   class UnaryOpTypeField: public BitField<int,
       kUnaryOpTypeFirstBit, kUnaryOpTypeBitCount> {};  // NOLINT
-  class BinaryOpTypeField: public BitField<int,
-      kBinaryOpTypeFirstBit, kBinaryOpTypeBitCount> {};  // NOLINT
-  class BinaryOpResultTypeField: public BitField<int,
-      kBinaryOpResultTypeFirstBit, kBinaryOpResultTypeBitCount> {};  // NOLINT
-  class CompareStateField: public BitField<int,
-      kCompareStateFirstBit, kCompareStateBitCount> {};  // NOLINT
-  class CompareOperationField: public BitField<int,
-      kCompareOperationFirstBit, kCompareOperationBitCount> {};  // NOLINT
   class ToBooleanStateField: public BitField<int,
       kToBooleanStateFirstBit, kToBooleanStateBitCount> {};  // NOLINT
   class HasFunctionCacheField: public BitField<bool,
index 25ce2ba2bdfefbdbc338e5ff367193045f37c9c8..8bcd6a16fbddb566a6d48be63d78e80871cb450c 100644 (file)
@@ -2130,9 +2130,11 @@ void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) {
   SetInternalReference(code, entry,
                        "deoptimization_data", code->deoptimization_data(),
                        Code::kDeoptimizationDataOffset);
-  SetInternalReference(code, entry,
-                       "type_feedback_info", code->type_feedback_info(),
-                       Code::kTypeFeedbackInfoOffset);
+  if (code->kind() == Code::FUNCTION) {
+    SetInternalReference(code, entry,
+                         "type_feedback_info", code->type_feedback_info(),
+                         Code::kTypeFeedbackInfoOffset);
+  }
   SetInternalReference(code, entry,
                        "gc_metadata", code->gc_metadata(),
                        Code::kGCMetadataOffset);
index bc6a46b4b664f095e6587ed8fa873df9868b5093..f97fb52af31d6c581aee013bc86157c818b9e77c 100644 (file)
@@ -312,43 +312,53 @@ bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) {
 }
 
 
-TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) {
-  Handle<Object> object = GetInfo(expr->CompareOperationFeedbackId());
-  TypeInfo unknown = TypeInfo::Unknown();
-  if (!object->IsCode()) return unknown;
-  Handle<Code> code = Handle<Code>::cast(object);
-  if (!code->is_compare_ic_stub()) return unknown;
-
-  CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
+static TypeInfo TypeFromCompareType(CompareIC::State state) {
   switch (state) {
     case CompareIC::UNINITIALIZED:
       // Uninitialized means never executed.
       return TypeInfo::Uninitialized();
-    case CompareIC::SMIS:
+    case CompareIC::SMI:
       return TypeInfo::Smi();
-    case CompareIC::HEAP_NUMBERS:
+    case CompareIC::HEAP_NUMBER:
       return TypeInfo::Number();
-    case CompareIC::SYMBOLS:
-    case CompareIC::STRINGS:
+    case CompareIC::SYMBOL:
+      return TypeInfo::Symbol();
+    case CompareIC::STRING:
       return TypeInfo::String();
-    case CompareIC::OBJECTS:
+    case CompareIC::OBJECT:
     case CompareIC::KNOWN_OBJECTS:
       // TODO(kasperl): We really need a type for JS objects here.
       return TypeInfo::NonPrimitive();
     case CompareIC::GENERIC:
     default:
-      return unknown;
+      return TypeInfo::Unknown();
   }
 }
 
 
-bool TypeFeedbackOracle::IsSymbolCompare(CompareOperation* expr) {
+void TypeFeedbackOracle::CompareType(CompareOperation* expr,
+                                     TypeInfo* left_type,
+                                     TypeInfo* right_type,
+                                     TypeInfo* overall_type) {
   Handle<Object> object = GetInfo(expr->CompareOperationFeedbackId());
-  if (!object->IsCode()) return false;
+  TypeInfo unknown = TypeInfo::Unknown();
+  if (!object->IsCode()) {
+    *left_type = *right_type = *overall_type = unknown;
+    return;
+  }
   Handle<Code> code = Handle<Code>::cast(object);
-  if (!code->is_compare_ic_stub()) return false;
-  CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
-  return state == CompareIC::SYMBOLS;
+  if (!code->is_compare_ic_stub()) {
+    *left_type = *right_type = *overall_type = unknown;
+    return;
+  }
+
+  int stub_minor_key = code->stub_info();
+  CompareIC::State left_state, right_state, handler_state;
+  ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state,
+                                &handler_state, NULL);
+  *left_type = TypeFromCompareType(left_state);
+  *right_type = TypeFromCompareType(right_state);
+  *overall_type = TypeFromCompareType(handler_state);
 }
 
 
@@ -357,7 +367,7 @@ Handle<Map> TypeFeedbackOracle::GetCompareMap(CompareOperation* expr) {
   if (!object->IsCode()) return Handle<Map>::null();
   Handle<Code> code = Handle<Code>::cast(object);
   if (!code->is_compare_ic_stub()) return Handle<Map>::null();
-  CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
+  CompareIC::State state = ICCompareStub::CompareState(code->stub_info());
   if (state != CompareIC::KNOWN_OBJECTS) {
     return Handle<Map>::null();
   }
@@ -388,55 +398,44 @@ TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) {
 }
 
 
-TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr) {
+static TypeInfo TypeFromBinaryOpType(BinaryOpIC::TypeInfo binary_type) {
+  switch (binary_type) {
+    // Uninitialized means never executed.
+    case BinaryOpIC::UNINITIALIZED:  return TypeInfo::Uninitialized();
+    case BinaryOpIC::SMI:            return TypeInfo::Smi();
+    case BinaryOpIC::INT32:          return TypeInfo::Integer32();
+    case BinaryOpIC::HEAP_NUMBER:    return TypeInfo::Double();
+    case BinaryOpIC::ODDBALL:        return TypeInfo::Unknown();
+    case BinaryOpIC::STRING:         return TypeInfo::String();
+    case BinaryOpIC::GENERIC:        return TypeInfo::Unknown();
+  }
+  UNREACHABLE();
+  return TypeInfo::Unknown();
+}
+
+
+void TypeFeedbackOracle::BinaryType(BinaryOperation* expr,
+                                    TypeInfo* left,
+                                    TypeInfo* right,
+                                    TypeInfo* result) {
   Handle<Object> object = GetInfo(expr->BinaryOperationFeedbackId());
   TypeInfo unknown = TypeInfo::Unknown();
-  if (!object->IsCode()) return unknown;
+  if (!object->IsCode()) {
+    *left = *right = *result = unknown;
+    return;
+  }
   Handle<Code> code = Handle<Code>::cast(object);
   if (code->is_binary_op_stub()) {
-    BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
-        code->binary_op_type());
-    BinaryOpIC::TypeInfo result_type = static_cast<BinaryOpIC::TypeInfo>(
-        code->binary_op_result_type());
-
-    switch (type) {
-      case BinaryOpIC::UNINITIALIZED:
-        // Uninitialized means never executed.
-        return TypeInfo::Uninitialized();
-      case BinaryOpIC::SMI:
-        switch (result_type) {
-          case BinaryOpIC::UNINITIALIZED:
-            if (expr->op() == Token::DIV) {
-              return TypeInfo::Double();
-            }
-            return TypeInfo::Smi();
-          case BinaryOpIC::SMI:
-            return TypeInfo::Smi();
-          case BinaryOpIC::INT32:
-            return TypeInfo::Integer32();
-          case BinaryOpIC::HEAP_NUMBER:
-            return TypeInfo::Double();
-          default:
-            return unknown;
-        }
-      case BinaryOpIC::INT32:
-        if (expr->op() == Token::DIV ||
-            result_type == BinaryOpIC::HEAP_NUMBER) {
-          return TypeInfo::Double();
-        }
-        return TypeInfo::Integer32();
-      case BinaryOpIC::HEAP_NUMBER:
-        return TypeInfo::Double();
-      case BinaryOpIC::BOTH_STRING:
-        return TypeInfo::String();
-      case BinaryOpIC::STRING:
-      case BinaryOpIC::GENERIC:
-        return unknown;
-     default:
-        return unknown;
-    }
+    BinaryOpIC::TypeInfo left_type, right_type, result_type;
+    BinaryOpStub::decode_types_from_minor_key(code->stub_info(), &left_type,
+                                              &right_type, &result_type);
+    *left = TypeFromBinaryOpType(left_type);
+    *right = TypeFromBinaryOpType(right_type);
+    *result = TypeFromBinaryOpType(result_type);
+    return;
   }
-  return unknown;
+  // Not a binary op stub.
+  *left = *right = *result = unknown;
 }
 
 
@@ -447,28 +446,8 @@ TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) {
   Handle<Code> code = Handle<Code>::cast(object);
   if (!code->is_compare_ic_stub()) return unknown;
 
-  CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
-  switch (state) {
-    case CompareIC::UNINITIALIZED:
-      // Uninitialized means never executed.
-      // TODO(fschneider): Introduce a separate value for never-executed ICs.
-      return unknown;
-    case CompareIC::SMIS:
-      return TypeInfo::Smi();
-    case CompareIC::STRINGS:
-      return TypeInfo::String();
-    case CompareIC::SYMBOLS:
-      return TypeInfo::Symbol();
-    case CompareIC::HEAP_NUMBERS:
-      return TypeInfo::Number();
-    case CompareIC::OBJECTS:
-    case CompareIC::KNOWN_OBJECTS:
-      // TODO(kasperl): We really need a type for JS objects here.
-      return TypeInfo::NonPrimitive();
-    case CompareIC::GENERIC:
-    default:
-      return unknown;
-  }
+  CompareIC::State state = ICCompareStub::CompareState(code->stub_info());
+  return TypeFromCompareType(state);
 }
 
 
@@ -479,9 +458,14 @@ TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) {
   Handle<Code> code = Handle<Code>::cast(object);
   if (!code->is_binary_op_stub()) return unknown;
 
-  BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
-      code->binary_op_type());
-  switch (type) {
+  BinaryOpIC::TypeInfo left_type, right_type, unused_result_type;
+  BinaryOpStub::decode_types_from_minor_key(code->stub_info(), &left_type,
+                                            &right_type, &unused_result_type);
+  // CountOperations should always have +1 or -1 as their right input.
+  ASSERT(right_type == BinaryOpIC::SMI ||
+         right_type == BinaryOpIC::UNINITIALIZED);
+
+  switch (left_type) {
     case BinaryOpIC::UNINITIALIZED:
     case BinaryOpIC::SMI:
       return TypeInfo::Smi();
@@ -489,7 +473,6 @@ TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) {
       return TypeInfo::Integer32();
     case BinaryOpIC::HEAP_NUMBER:
       return TypeInfo::Double();
-    case BinaryOpIC::BOTH_STRING:
     case BinaryOpIC::STRING:
     case BinaryOpIC::GENERIC:
       return unknown;
index 00d88c2afccae57570b8e4df23be88bff6fa2c95..8b2ec49310de9730da50a790d7b8093f0eb9e41e 100644 (file)
@@ -204,6 +204,7 @@ class TypeInfo {
     kNonPrimitive = 0x40,  // 1000000
     kUninitialized = 0x7f  // 1111111
   };
+
   explicit inline TypeInfo(Type t) : type_(t) { }
 
   Type type_;
@@ -287,9 +288,14 @@ class TypeFeedbackOracle: public ZoneObject {
 
   // Get type information for arithmetic operations and compares.
   TypeInfo UnaryType(UnaryOperation* expr);
-  TypeInfo BinaryType(BinaryOperation* expr);
-  TypeInfo CompareType(CompareOperation* expr);
-  bool IsSymbolCompare(CompareOperation* expr);
+  void BinaryType(BinaryOperation* expr,
+                  TypeInfo* left,
+                  TypeInfo* right,
+                  TypeInfo* result);
+  void CompareType(CompareOperation* expr,
+                   TypeInfo* left_type,
+                   TypeInfo* right_type,
+                   TypeInfo* overall_type);
   Handle<Map> GetCompareMap(CompareOperation* expr);
   TypeInfo SwitchType(CaseClause* clause);
   TypeInfo IncrementType(CountOperation* expr);
index a8e52e99d306d0cedb44ab9f4ef74eedd10d85c0..be6ae99dcb4900164083e66ebcee2088dbab9a29 100644 (file)
@@ -637,6 +637,10 @@ void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
 
 class FloatingPointHelper : public AllStatic {
  public:
+  enum ConvertUndefined {
+    CONVERT_UNDEFINED_TO_ZERO,
+    BAILOUT_ON_UNDEFINED
+  };
   // Load the operands from rdx and rax into xmm0 and xmm1, as doubles.
   // If the operands are not both numbers, jump to not_numbers.
   // Leaves rdx and rax unchanged.  SmiOperands assumes both are smis.
@@ -672,7 +676,8 @@ class FloatingPointHelper : public AllStatic {
                             Register scratch2,
                             Register scratch3,
                             Label* on_success,
-                            Label* on_not_smis);
+                            Label* on_not_smis,
+                            ConvertUndefined convert_undefined);
 };
 
 
@@ -997,16 +1002,15 @@ void UnaryOpStub::PrintName(StringStream* stream) {
 }
 
 
+void BinaryOpStub::Initialize() {}
+
+
 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
   __ pop(rcx);  // Save return address.
   __ push(rdx);
   __ push(rax);
   // Left and right arguments are now on top.
-  // Push this stub's key. Although the operation and the type info are
-  // encoded into the key, the encoding is opaque, so push them too.
   __ Push(Smi::FromInt(MinorKey()));
-  __ Push(Smi::FromInt(op_));
-  __ Push(Smi::FromInt(operands_type_));
 
   __ push(rcx);  // Push return address.
 
@@ -1015,69 +1019,16 @@ void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
   __ TailCallExternalReference(
       ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
                         masm->isolate()),
-      5,
+      3,
       1);
 }
 
 
-void BinaryOpStub::Generate(MacroAssembler* masm) {
-  // Explicitly allow generation of nested stubs. It is safe here because
-  // generation code does not use any raw pointers.
-  AllowStubCallsScope allow_stub_calls(masm, true);
-
-  switch (operands_type_) {
-    case BinaryOpIC::UNINITIALIZED:
-      GenerateTypeTransition(masm);
-      break;
-    case BinaryOpIC::SMI:
-      GenerateSmiStub(masm);
-      break;
-    case BinaryOpIC::INT32:
-      UNREACHABLE();
-      // The int32 case is identical to the Smi case.  We avoid creating this
-      // ic state on x64.
-      break;
-    case BinaryOpIC::HEAP_NUMBER:
-      GenerateHeapNumberStub(masm);
-      break;
-    case BinaryOpIC::ODDBALL:
-      GenerateOddballStub(masm);
-      break;
-    case BinaryOpIC::BOTH_STRING:
-      GenerateBothStringStub(masm);
-      break;
-    case BinaryOpIC::STRING:
-      GenerateStringStub(masm);
-      break;
-    case BinaryOpIC::GENERIC:
-      GenerateGeneric(masm);
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
-
-void BinaryOpStub::PrintName(StringStream* stream) {
-  const char* op_name = Token::Name(op_);
-  const char* overwrite_name;
-  switch (mode_) {
-    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
-    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
-    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
-    default: overwrite_name = "UnknownOverwrite"; break;
-  }
-  stream->Add("BinaryOpStub_%s_%s_%s",
-              op_name,
-              overwrite_name,
-              BinaryOpIC::GetName(operands_type_));
-}
-
-
-void BinaryOpStub::GenerateSmiCode(
+static void BinaryOpStub_GenerateSmiCode(
     MacroAssembler* masm,
     Label* slow,
-    SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
+    BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results,
+    Token::Value op) {
 
   // Arguments to BinaryOpStub are in rdx and rax.
   const Register left = rdx;
@@ -1086,9 +1037,9 @@ void BinaryOpStub::GenerateSmiCode(
   // We only generate heapnumber answers for overflowing calculations
   // for the four basic arithmetic operations and logical right shift by 0.
   bool generate_inline_heapnumber_results =
-      (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) &&
-      (op_ == Token::ADD || op_ == Token::SUB ||
-       op_ == Token::MUL || op_ == Token::DIV || op_ == Token::SHR);
+      (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) &&
+      (op == Token::ADD || op == Token::SUB ||
+       op == Token::MUL || op == Token::DIV || op == Token::SHR);
 
   // Smi check of both operands.  If op is BIT_OR, the check is delayed
   // until after the OR operation.
@@ -1096,7 +1047,7 @@ void BinaryOpStub::GenerateSmiCode(
   Label use_fp_on_smis;
   Label fail;
 
-  if (op_ != Token::BIT_OR) {
+  if (op != Token::BIT_OR) {
     Comment smi_check_comment(masm, "-- Smi check arguments");
     __ JumpIfNotBothSmi(left, right, &not_smis);
   }
@@ -1105,7 +1056,7 @@ void BinaryOpStub::GenerateSmiCode(
   __ bind(&smi_values);
   // Perform the operation.
   Comment perform_smi(masm, "-- Perform smi operation");
-  switch (op_) {
+  switch (op) {
     case Token::ADD:
       ASSERT(right.is(rax));
       __ SmiAdd(right, right, left, &use_fp_on_smis);  // ADD is commutative.
@@ -1177,7 +1128,7 @@ void BinaryOpStub::GenerateSmiCode(
     //    operations on known smis (e.g., if the result of the operation
     //    overflowed the smi range).
     __ bind(&use_fp_on_smis);
-    if (op_ == Token::DIV || op_ == Token::MOD) {
+    if (op == Token::DIV || op == Token::MOD) {
       // Restore left and right to rdx and rax.
       __ movq(rdx, rcx);
       __ movq(rax, rbx);
@@ -1186,12 +1137,12 @@ void BinaryOpStub::GenerateSmiCode(
     if (generate_inline_heapnumber_results) {
       __ AllocateHeapNumber(rcx, rbx, slow);
       Comment perform_float(masm, "-- Perform float operation on smis");
-      if (op_ == Token::SHR) {
+      if (op == Token::SHR) {
         __ SmiToInteger32(left, left);
         __ cvtqsi2sd(xmm0, left);
       } else {
         FloatingPointHelper::LoadSSE2SmiOperands(masm);
-        switch (op_) {
+        switch (op) {
         case Token::ADD: __ addsd(xmm0, xmm1); break;
         case Token::SUB: __ subsd(xmm0, xmm1); break;
         case Token::MUL: __ mulsd(xmm0, xmm1); break;
@@ -1214,31 +1165,50 @@ void BinaryOpStub::GenerateSmiCode(
   //    values that could be smi.
   __ bind(&not_smis);
   Comment done_comment(masm, "-- Enter non-smi code");
+  FloatingPointHelper::ConvertUndefined convert_undefined =
+      FloatingPointHelper::BAILOUT_ON_UNDEFINED;
+  // This list must be in sync with BinaryOpPatch() behavior in ic.cc.
+  if (op == Token::BIT_AND ||
+      op == Token::BIT_OR ||
+      op == Token::BIT_XOR ||
+      op == Token::SAR ||
+      op == Token::SHL ||
+      op == Token::SHR) {
+    convert_undefined = FloatingPointHelper::CONVERT_UNDEFINED_TO_ZERO;
+  }
   FloatingPointHelper::NumbersToSmis(masm, left, right, rbx, rdi, rcx,
-                                     &smi_values, &fail);
+                                     &smi_values, &fail, convert_undefined);
   __ jmp(&smi_values);
   __ bind(&fail);
 }
 
 
-void BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm,
-                                             Label* allocation_failure,
-                                             Label* non_numeric_failure) {
-  switch (op_) {
+static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
+                                                      Label* alloc_failure,
+                                                      OverwriteMode mode);
+
+
+static void BinaryOpStub_GenerateFloatingPointCode(MacroAssembler* masm,
+                                                   Label* allocation_failure,
+                                                   Label* non_numeric_failure,
+                                                   Token::Value op,
+                                                   OverwriteMode mode) {
+  switch (op) {
     case Token::ADD:
     case Token::SUB:
     case Token::MUL:
     case Token::DIV: {
       FloatingPointHelper::LoadSSE2UnknownOperands(masm, non_numeric_failure);
 
-      switch (op_) {
+      switch (op) {
         case Token::ADD: __ addsd(xmm0, xmm1); break;
         case Token::SUB: __ subsd(xmm0, xmm1); break;
         case Token::MUL: __ mulsd(xmm0, xmm1); break;
         case Token::DIV: __ divsd(xmm0, xmm1); break;
         default: UNREACHABLE();
       }
-      GenerateHeapResultAllocation(masm, allocation_failure);
+      BinaryOpStub_GenerateHeapResultAllocation(
+          masm, allocation_failure, mode);
       __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
       __ ret(0);
       break;
@@ -1259,7 +1229,7 @@ void BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm,
       __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
       FloatingPointHelper::LoadAsIntegers(masm, non_numeric_failure,
                                           heap_number_map);
-      switch (op_) {
+      switch (op) {
         case Token::BIT_OR:  __ orl(rax, rcx); break;
         case Token::BIT_AND: __ andl(rax, rcx); break;
         case Token::BIT_XOR: __ xorl(rax, rcx); break;
@@ -1283,7 +1253,7 @@ void BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm,
       // Logical shift right can produce an unsigned int32 that is not
       // an int32, and so is not in the smi range.  Allocate a heap number
       // in that case.
-      if (op_ == Token::SHR) {
+      if (op == Token::SHR) {
         __ bind(&non_smi_shr_result);
         Label allocation_failed;
         __ movl(rbx, rax);  // rbx holds result value (uint32 value as int64).
@@ -1320,12 +1290,12 @@ void BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm,
   // No fall-through from this generated code.
   if (FLAG_debug_code) {
     __ Abort("Unexpected fall-through in "
-             "BinaryStub::GenerateFloatingPointCode.");
+             "BinaryStub_GenerateFloatingPointCode.");
   }
 }
 
 
-void BinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) {
+void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
   ASSERT(op_ == Token::ADD);
   Label left_not_string, call_runtime;
 
@@ -1356,58 +1326,17 @@ void BinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) {
 }
 
 
-void BinaryOpStub::GenerateCallRuntimeCode(MacroAssembler* masm) {
-  GenerateRegisterArgsPush(masm);
-  switch (op_) {
-    case Token::ADD:
-      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
-      break;
-    case Token::SUB:
-      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
-      break;
-    case Token::MUL:
-      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
-      break;
-    case Token::DIV:
-      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
-      break;
-    case Token::MOD:
-      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
-      break;
-    case Token::BIT_OR:
-      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
-      break;
-    case Token::BIT_AND:
-      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
-      break;
-    case Token::BIT_XOR:
-      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
-      break;
-    case Token::SAR:
-      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
-      break;
-    case Token::SHL:
-      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
-      break;
-    case Token::SHR:
-      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
-
 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
   Label call_runtime;
   if (result_type_ == BinaryOpIC::UNINITIALIZED ||
       result_type_ == BinaryOpIC::SMI) {
     // Only allow smi results.
-    GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS);
+    BinaryOpStub_GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS, op_);
   } else {
     // Allow heap number result and don't make a transition if a heap number
     // cannot be allocated.
-    GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
+    BinaryOpStub_GenerateSmiCode(
+        masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_);
   }
 
   // Code falls through if the result is not returned as either a smi or heap
@@ -1416,24 +1345,22 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
 
   if (call_runtime.is_linked()) {
     __ bind(&call_runtime);
-    GenerateCallRuntimeCode(masm);
+    GenerateRegisterArgsPush(masm);
+    GenerateCallRuntime(masm);
   }
 }
 
 
-void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
-  ASSERT(operands_type_ == BinaryOpIC::STRING);
-  ASSERT(op_ == Token::ADD);
-  GenerateStringAddCode(masm);
-  // Try to add arguments as strings, otherwise, transition to the generic
-  // BinaryOpIC type.
-  GenerateTypeTransition(masm);
+void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
+  // The int32 case is identical to the Smi case.  We avoid creating this
+  // ic state on x64.
+  UNREACHABLE();
 }
 
 
 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
   Label call_runtime;
-  ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING);
+  ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING);
   ASSERT(op_ == Token::ADD);
   // If both arguments are strings, call the string add stub.
   // Otherwise, do a transition.
@@ -1467,7 +1394,7 @@ void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
   if (op_ == Token::ADD) {
     // Handle string addition here, because it is the only operation
     // that does not do a ToNumber conversion on the operands.
-    GenerateStringAddCode(masm);
+    GenerateAddStrings(masm);
   }
 
   // Convert oddball arguments to numbers.
@@ -1494,39 +1421,79 @@ void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
 }
 
 
+static void BinaryOpStub_CheckSmiInput(MacroAssembler* masm,
+                                       Register input,
+                                       Label* fail) {
+  Label ok;
+  __ JumpIfSmi(input, &ok, Label::kNear);
+  Register heap_number_map = r8;
+  Register scratch1 = r9;
+  Register scratch2 = r10;
+  // HeapNumbers containing 32bit integer values are also allowed.
+  __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+  __ cmpq(FieldOperand(input, HeapObject::kMapOffset), heap_number_map);
+  __ j(not_equal, fail);
+  __ movsd(xmm0, FieldOperand(input, HeapNumber::kValueOffset));
+  // Convert, convert back, and compare the two doubles' bits.
+  __ cvttsd2siq(scratch2, xmm0);
+  __ cvtlsi2sd(xmm1, scratch2);
+  __ movq(scratch1, xmm0);
+  __ movq(scratch2, xmm1);
+  __ cmpq(scratch1, scratch2);
+  __ j(not_equal, fail);
+  __ bind(&ok);
+}
+
+
 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
   Label gc_required, not_number;
-  GenerateFloatingPointCode(masm, &gc_required, &not_number);
+
+  // It could be that only SMIs have been seen at either the left
+  // or the right operand. For precise type feedback, patch the IC
+  // again if this changes.
+  if (left_type_ == BinaryOpIC::SMI) {
+    BinaryOpStub_CheckSmiInput(masm, rdx, &not_number);
+  }
+  if (right_type_ == BinaryOpIC::SMI) {
+    BinaryOpStub_CheckSmiInput(masm, rax, &not_number);
+  }
+
+  BinaryOpStub_GenerateFloatingPointCode(
+      masm, &gc_required, &not_number, op_, mode_);
 
   __ bind(&not_number);
   GenerateTypeTransition(masm);
 
   __ bind(&gc_required);
-  GenerateCallRuntimeCode(masm);
+  GenerateRegisterArgsPush(masm);
+  GenerateCallRuntime(masm);
 }
 
 
 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
   Label call_runtime, call_string_add_or_runtime;
 
-  GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
+  BinaryOpStub_GenerateSmiCode(
+      masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_);
 
-  GenerateFloatingPointCode(masm, &call_runtime, &call_string_add_or_runtime);
+  BinaryOpStub_GenerateFloatingPointCode(
+      masm, &call_runtime, &call_string_add_or_runtime, op_, mode_);
 
   __ bind(&call_string_add_or_runtime);
   if (op_ == Token::ADD) {
-    GenerateStringAddCode(masm);
+    GenerateAddStrings(masm);
   }
 
   __ bind(&call_runtime);
-  GenerateCallRuntimeCode(masm);
+  GenerateRegisterArgsPush(masm);
+  GenerateCallRuntime(masm);
 }
 
 
-void BinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm,
-                                                Label* alloc_failure) {
+static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
+                                                      Label* alloc_failure,
+                                                      OverwriteMode mode) {
   Label skip_allocation;
-  OverwriteMode mode = mode_;
   switch (mode) {
     case OVERWRITE_LEFT: {
       // If the argument in rdx is already an object, we skip the
@@ -2022,17 +1989,21 @@ void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm,
                                         Register scratch2,
                                         Register scratch3,
                                         Label* on_success,
-                                        Label* on_not_smis)   {
+                                        Label* on_not_smis,
+                                        ConvertUndefined convert_undefined) {
   Register heap_number_map = scratch3;
   Register smi_result = scratch1;
-  Label done;
+  Label done, maybe_undefined_first, maybe_undefined_second, first_done;
 
   __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
 
   Label first_smi;
   __ JumpIfSmi(first, &first_smi, Label::kNear);
   __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map);
-  __ j(not_equal, on_not_smis);
+  __ j(not_equal,
+       (convert_undefined == CONVERT_UNDEFINED_TO_ZERO)
+           ? &maybe_undefined_first
+           : on_not_smis);
   // Convert HeapNumber to smi if possible.
   __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset));
   __ movq(scratch2, xmm0);
@@ -2045,11 +2016,15 @@ void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm,
   __ j(not_equal, on_not_smis);
   __ Integer32ToSmi(first, smi_result);
 
+  __ bind(&first_done);
   __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done);
   __ bind(&first_smi);
   __ AssertNotSmi(second);
   __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map);
-  __ j(not_equal, on_not_smis);
+  __ j(not_equal,
+       (convert_undefined == CONVERT_UNDEFINED_TO_ZERO)
+           ? &maybe_undefined_second
+           : on_not_smis);
   // Convert second to smi, if possible.
   __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset));
   __ movq(scratch2, xmm0);
@@ -2062,8 +2037,25 @@ void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm,
   if (on_success != NULL) {
     __ jmp(on_success);
   } else {
-    __ bind(&done);
+    __ jmp(&done);
+  }
+
+  __ bind(&maybe_undefined_first);
+  __ CompareRoot(first, Heap::kUndefinedValueRootIndex);
+  __ j(not_equal, on_not_smis);
+  __ xor_(first, first);
+  __ jmp(&first_done);
+
+  __ bind(&maybe_undefined_second);
+  __ CompareRoot(second, Heap::kUndefinedValueRootIndex);
+  __ j(not_equal, on_not_smis);
+  __ xor_(second, second);
+  if (on_success != NULL) {
+    __ jmp(on_success);
   }
+  // Else: fall through.
+
+  __ bind(&done);
 }
 
 
@@ -3378,30 +3370,59 @@ static int NegativeComparisonResult(Condition cc) {
 }
 
 
-void CompareStub::Generate(MacroAssembler* masm) {
-  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
+static void CheckInputType(MacroAssembler* masm,
+                           Register input,
+                           CompareIC::State expected,
+                           Label* fail) {
+  Label ok;
+  if (expected == CompareIC::SMI) {
+    __ JumpIfNotSmi(input, fail);
+  } else if (expected == CompareIC::HEAP_NUMBER) {
+    __ JumpIfSmi(input, &ok);
+    __ CompareMap(input, masm->isolate()->factory()->heap_number_map(), NULL);
+    __ j(not_equal, fail);
+  }
+  // We could be strict about symbol/string here, but as long as
+  // hydrogen doesn't care, the stub doesn't have to care either.
+  __ bind(&ok);
+}
+
+
+static void BranchIfNonSymbol(MacroAssembler* masm,
+                              Label* label,
+                              Register object,
+                              Register scratch) {
+  __ JumpIfSmi(object, label);
+  __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset));
+  __ movzxbq(scratch,
+             FieldOperand(scratch, Map::kInstanceTypeOffset));
+  // Ensure that no non-strings have the symbol bit set.
+  STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask);
+  STATIC_ASSERT(kSymbolTag != 0);
+  __ testb(scratch, Immediate(kIsSymbolMask));
+  __ j(zero, label);
+}
+
 
+void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
   Label check_unequal_objects, done;
+  Condition cc = GetCondition();
   Factory* factory = masm->isolate()->factory();
 
-  // Compare two smis if required.
-  if (include_smi_compare_) {
-    Label non_smi, smi_done;
-    __ JumpIfNotBothSmi(rax, rdx, &non_smi);
-    __ subq(rdx, rax);
-    __ j(no_overflow, &smi_done);
-    __ not_(rdx);  // Correct sign in case of overflow. rdx cannot be 0 here.
-    __ bind(&smi_done);
-    __ movq(rax, rdx);
-    __ ret(0);
-    __ bind(&non_smi);
-  } else if (FLAG_debug_code) {
-    Label ok;
-    __ JumpIfNotSmi(rdx, &ok);
-    __ JumpIfNotSmi(rax, &ok);
-    __ Abort("CompareStub: smi operands");
-    __ bind(&ok);
-  }
+  Label miss;
+  CheckInputType(masm, rdx, left_, &miss);
+  CheckInputType(masm, rax, right_, &miss);
+
+  // Compare two smis.
+  Label non_smi, smi_done;
+  __ JumpIfNotBothSmi(rax, rdx, &non_smi);
+  __ subq(rdx, rax);
+  __ j(no_overflow, &smi_done);
+  __ not_(rdx);  // Correct sign in case of overflow. rdx cannot be 0 here.
+  __ bind(&smi_done);
+  __ movq(rax, rdx);
+  __ ret(0);
+  __ bind(&non_smi);
 
   // The compare stub returns a positive, negative, or zero 64-bit integer
   // value in rax, corresponding to result of comparing the two inputs.
@@ -3414,66 +3435,58 @@ void CompareStub::Generate(MacroAssembler* masm) {
     __ cmpq(rax, rdx);
     __ j(not_equal, &not_identical, Label::kNear);
 
-    if (cc_ != equal) {
+    if (cc != equal) {
       // Check for undefined.  undefined OP undefined is false even though
       // undefined == undefined.
       Label check_for_nan;
       __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
       __ j(not_equal, &check_for_nan, Label::kNear);
-      __ Set(rax, NegativeComparisonResult(cc_));
+      __ Set(rax, NegativeComparisonResult(cc));
       __ ret(0);
       __ 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.
-    // Note: if cc_ != equal, never_nan_nan_ is not used.
-    // We cannot set rax to EQUAL until just before return because
-    // rax must be unchanged on jump to not_identical.
-    if (never_nan_nan_ && (cc_ == equal)) {
-      __ Set(rax, EQUAL);
-      __ ret(0);
-    } else {
-      Label heap_number;
-      // If it's not a heap number, then return equal for (in)equality operator.
-      __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
-             factory->heap_number_map());
-      __ j(equal, &heap_number, Label::kNear);
-      if (cc_ != equal) {
-        // Call runtime on identical objects.  Otherwise return equal.
-        __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
-        __ j(above_equal, &not_identical, Label::kNear);
-      }
-      __ Set(rax, EQUAL);
-      __ ret(0);
+    Label heap_number;
+    // If it's not a heap number, then return equal for (in)equality operator.
+    __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
+           factory->heap_number_map());
+    __ j(equal, &heap_number, Label::kNear);
+    if (cc != equal) {
+      // Call runtime on identical objects.  Otherwise return equal.
+      __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
+      __ j(above_equal, &not_identical, Label::kNear);
+    }
+    __ Set(rax, EQUAL);
+    __ ret(0);
 
-      __ bind(&heap_number);
-      // It is a heap number, so return  equal if it's not NaN.
-      // For NaN, return 1 for every condition except greater and
-      // greater-equal.  Return -1 for them, so the comparison yields
-      // false for all conditions except not-equal.
-      __ Set(rax, EQUAL);
-      __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
-      __ ucomisd(xmm0, xmm0);
-      __ setcc(parity_even, rax);
-      // rax is 0 for equal non-NaN heapnumbers, 1 for NaNs.
-      if (cc_ == greater_equal || cc_ == greater) {
-        __ neg(rax);
-      }
-      __ ret(0);
+    __ bind(&heap_number);
+    // It is a heap number, so return  equal if it's not NaN.
+    // For NaN, return 1 for every condition except greater and
+    // greater-equal.  Return -1 for them, so the comparison yields
+    // false for all conditions except not-equal.
+    __ Set(rax, EQUAL);
+    __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
+    __ ucomisd(xmm0, xmm0);
+    __ setcc(parity_even, rax);
+    // rax is 0 for equal non-NaN heapnumbers, 1 for NaNs.
+    if (cc == greater_equal || cc == greater) {
+      __ neg(rax);
     }
+    __ ret(0);
 
     __ bind(&not_identical);
   }
 
-  if (cc_ == equal) {  // Both strict and non-strict.
+  if (cc == equal) {  // Both strict and non-strict.
     Label slow;  // Fallthrough label.
 
     // If we're doing a strict equality comparison, we don't have to do
     // type conversion, so we generate code to do fast comparison for objects
     // and oddballs. Non-smi numbers and strings still go through the usual
     // slow-case code.
-    if (strict_) {
+    if (strict()) {
       // If either is a Smi (we know that not both are), then they can only
       // be equal if the other is a HeapNumber. If so, use the slow case.
       {
@@ -3525,40 +3538,38 @@ void CompareStub::Generate(MacroAssembler* masm) {
   }
 
   // Generate the number comparison code.
-  if (include_number_compare_) {
-    Label non_number_comparison;
-    Label unordered;
-    FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison);
-    __ xorl(rax, rax);
-    __ xorl(rcx, rcx);
-    __ ucomisd(xmm0, xmm1);
-
-    // Don't base result on EFLAGS when a NaN is involved.
-    __ j(parity_even, &unordered, Label::kNear);
-    // Return a result of -1, 0, or 1, based on EFLAGS.
-    __ setcc(above, rax);
-    __ setcc(below, rcx);
-    __ subq(rax, rcx);
-    __ ret(0);
+  Label non_number_comparison;
+  Label unordered;
+  FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison);
+  __ xorl(rax, rax);
+  __ xorl(rcx, rcx);
+  __ ucomisd(xmm0, xmm1);
 
-    // If one of the numbers was NaN, then the result is always false.
-    // The cc is never not-equal.
-    __ bind(&unordered);
-    ASSERT(cc_ != not_equal);
-    if (cc_ == less || cc_ == less_equal) {
-      __ Set(rax, 1);
-    } else {
-      __ Set(rax, -1);
-    }
-    __ ret(0);
+  // Don't base result on EFLAGS when a NaN is involved.
+  __ j(parity_even, &unordered, Label::kNear);
+  // Return a result of -1, 0, or 1, based on EFLAGS.
+  __ setcc(above, rax);
+  __ setcc(below, rcx);
+  __ subq(rax, rcx);
+  __ ret(0);
 
-    // The number comparison code did not provide a valid result.
-    __ bind(&non_number_comparison);
+  // If one of the numbers was NaN, then the result is always false.
+  // The cc is never not-equal.
+  __ bind(&unordered);
+  ASSERT(cc != not_equal);
+  if (cc == less || cc == less_equal) {
+    __ Set(rax, 1);
+  } else {
+    __ Set(rax, -1);
   }
+  __ ret(0);
+
+  // The number comparison code did not provide a valid result.
+  __ bind(&non_number_comparison);
 
   // Fast negative check for symbol-to-symbol equality.
   Label check_for_strings;
-  if (cc_ == equal) {
+  if (cc == equal) {
     BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister);
     BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister);
 
@@ -3574,7 +3585,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
       rdx, rax, rcx, rbx, &check_unequal_objects);
 
   // Inline comparison of ASCII strings.
-  if (cc_ == equal) {
+  if (cc == equal) {
     StringCompareStub::GenerateFlatAsciiStringEquals(masm,
                                                      rdx,
                                                      rax,
@@ -3595,7 +3606,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
 #endif
 
   __ bind(&check_unequal_objects);
-  if (cc_ == equal && !strict_) {
+  if (cc == equal && !strict()) {
     // Not strict equality.  Objects are unequal if
     // they are both JSObjects and not undetectable,
     // and their pointers are different.
@@ -3635,11 +3646,11 @@ void CompareStub::Generate(MacroAssembler* masm) {
 
   // Figure out which native to call and setup the arguments.
   Builtins::JavaScript builtin;
-  if (cc_ == equal) {
-    builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  if (cc == equal) {
+    builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
   } else {
     builtin = Builtins::COMPARE;
-    __ Push(Smi::FromInt(NegativeComparisonResult(cc_)));
+    __ Push(Smi::FromInt(NegativeComparisonResult(cc)));
   }
 
   // Restore return address on the stack.
@@ -3648,22 +3659,9 @@ void CompareStub::Generate(MacroAssembler* masm) {
   // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
   __ InvokeBuiltin(builtin, JUMP_FUNCTION);
-}
-
 
-void CompareStub::BranchIfNonSymbol(MacroAssembler* masm,
-                                    Label* label,
-                                    Register object,
-                                    Register scratch) {
-  __ JumpIfSmi(object, label);
-  __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset));
-  __ movzxbq(scratch,
-             FieldOperand(scratch, Map::kInstanceTypeOffset));
-  // Ensure that no non-strings have the symbol bit set.
-  STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask);
-  STATIC_ASSERT(kSymbolTag != 0);
-  __ testb(scratch, Immediate(kIsSymbolMask));
-  __ j(zero, label);
+  __ bind(&miss);
+  GenerateMiss(masm);
 }
 
 
@@ -4421,44 +4419,6 @@ Register InstanceofStub::left() { return no_reg; }
 Register InstanceofStub::right() { return no_reg; }
 
 
-int CompareStub::MinorKey() {
-  // Encode the three parameters in a unique 16 bit value. To avoid duplicate
-  // stubs the never NaN NaN condition is only taken into account if the
-  // condition is equals.
-  ASSERT(static_cast<unsigned>(cc_) < (1 << 12));
-  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
-  return ConditionField::encode(static_cast<unsigned>(cc_))
-         | RegisterField::encode(false)    // lhs_ and rhs_ are not used
-         | StrictField::encode(strict_)
-         | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
-         | IncludeNumberCompareField::encode(include_number_compare_)
-         | IncludeSmiCompareField::encode(include_smi_compare_);
-}
-
-
-// Unfortunately you have to run without snapshots to see most of these
-// names in the profile since most compare stubs end up in the snapshot.
-void CompareStub::PrintName(StringStream* stream) {
-  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
-  const char* cc_name;
-  switch (cc_) {
-    case less: cc_name = "LT"; break;
-    case greater: cc_name = "GT"; break;
-    case less_equal: cc_name = "LE"; break;
-    case greater_equal: cc_name = "GE"; break;
-    case equal: cc_name = "EQ"; break;
-    case not_equal: cc_name = "NE"; break;
-    default: cc_name = "UnknownCondition"; break;
-  }
-  bool is_equality = cc_ == equal || cc_ == not_equal;
-  stream->Add("CompareStub_%s", cc_name);
-  if (strict_ && is_equality) stream->Add("_STRICT");
-  if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN");
-  if (!include_number_compare_) stream->Add("_NO_NUMBER");
-  if (!include_smi_compare_) stream->Add("_NO_SMI");
-}
-
-
 // -------------------------------------------------------------------------
 // StringCharCodeAtGenerator
 
@@ -5568,7 +5528,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::SMIS);
+  ASSERT(state_ == CompareIC::SMI);
   Label miss;
   __ JumpIfNotBothSmi(rdx, rax, &miss, Label::kNear);
 
@@ -5592,23 +5552,41 @@ void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::HEAP_NUMBERS);
+  ASSERT(state_ == CompareIC::HEAP_NUMBER);
 
   Label generic_stub;
   Label unordered, maybe_undefined1, maybe_undefined2;
   Label miss;
-  Condition either_smi = masm->CheckEitherSmi(rax, rdx);
-  __ j(either_smi, &generic_stub, Label::kNear);
 
-  __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx);
+  if (left_ == CompareIC::SMI) {
+    __ JumpIfNotSmi(rdx, &miss);
+  }
+  if (right_ == CompareIC::SMI) {
+    __ JumpIfNotSmi(rax, &miss);
+  }
+
+  // Load left and right operand.
+  Label done, left, left_smi, right_smi;
+  __ JumpIfSmi(rax, &right_smi, Label::kNear);
+  __ CompareMap(rax, masm->isolate()->factory()->heap_number_map(), NULL);
   __ j(not_equal, &maybe_undefined1, Label::kNear);
-  __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
+  __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
+  __ jmp(&left, Label::kNear);
+  __ bind(&right_smi);
+  __ SmiToInteger32(rcx, rax);  // Can't clobber rax yet.
+  __ cvtlsi2sd(xmm1, rcx);
+
+  __ bind(&left);
+  __ JumpIfSmi(rdx, &left_smi, Label::kNear);
+  __ CompareMap(rdx, masm->isolate()->factory()->heap_number_map(), NULL);
   __ j(not_equal, &maybe_undefined2, Label::kNear);
-
-  // Load left and right operand
   __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
-  __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
+  __ jmp(&done);
+  __ bind(&left_smi);
+  __ SmiToInteger32(rcx, rdx);  // Can't clobber rdx yet.
+  __ cvtlsi2sd(xmm0, rcx);
 
+  __ bind(&done);
   // Compare operands
   __ ucomisd(xmm0, xmm1);
 
@@ -5624,14 +5602,16 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
   __ ret(0);
 
   __ bind(&unordered);
-  CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
   __ bind(&generic_stub);
+  ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
+                     CompareIC::GENERIC);
   __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
 
   __ bind(&maybe_undefined1);
   if (Token::IsOrderedRelationalCompareOp(op_)) {
     __ Cmp(rax, masm->isolate()->factory()->undefined_value());
     __ j(not_equal, &miss);
+    __ JumpIfSmi(rdx, &unordered);
     __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
     __ j(not_equal, &maybe_undefined2, Label::kNear);
     __ jmp(&unordered);
@@ -5649,7 +5629,7 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::SYMBOLS);
+  ASSERT(state_ == CompareIC::SYMBOL);
   ASSERT(GetCondition() == equal);
 
   // Registers containing left and right operands respectively.
@@ -5692,7 +5672,7 @@ void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::STRINGS);
+  ASSERT(state_ == CompareIC::STRING);
   Label miss;
 
   bool equality = Token::IsEqualityOp(op_);
@@ -5778,7 +5758,7 @@ void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
 
 
 void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
-  ASSERT(state_ == CompareIC::OBJECTS);
+  ASSERT(state_ == CompareIC::OBJECT);
   Label miss;
   Condition either_smi = masm->CheckEitherSmi(rdx, rax);
   __ j(either_smi, &miss, Label::kNear);
index 6a1a18f830a6c78f6b024b1e65b897a121835e7e..ab8ea76c8f617893c4292ad0c07ed81961665021 100644 (file)
@@ -79,13 +79,6 @@ class StoreBufferOverflowStub: public CodeStub {
 };
 
 
-// Flag that indicates how to generate code for the stub GenericBinaryOpStub.
-enum GenericBinaryFlags {
-  NO_GENERIC_BINARY_FLAGS = 0,
-  NO_SMI_CODE_IN_STUB = 1 << 0  // Omit smi code in stub.
-};
-
-
 class UnaryOpStub: public CodeStub {
  public:
   UnaryOpStub(Token::Value op,
@@ -157,95 +150,6 @@ class UnaryOpStub: public CodeStub {
 };
 
 
-class BinaryOpStub: public CodeStub {
- public:
-  BinaryOpStub(Token::Value op, OverwriteMode mode)
-      : op_(op),
-        mode_(mode),
-        operands_type_(BinaryOpIC::UNINITIALIZED),
-        result_type_(BinaryOpIC::UNINITIALIZED) {
-    ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
-  }
-
-  BinaryOpStub(
-      int key,
-      BinaryOpIC::TypeInfo operands_type,
-      BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
-      : op_(OpBits::decode(key)),
-        mode_(ModeBits::decode(key)),
-        operands_type_(operands_type),
-        result_type_(result_type) { }
-
- private:
-  enum SmiCodeGenerateHeapNumberResults {
-    ALLOW_HEAPNUMBER_RESULTS,
-    NO_HEAPNUMBER_RESULTS
-  };
-
-  Token::Value op_;
-  OverwriteMode mode_;
-
-  // Operand type information determined at runtime.
-  BinaryOpIC::TypeInfo operands_type_;
-  BinaryOpIC::TypeInfo result_type_;
-
-  virtual void PrintName(StringStream* stream);
-
-  // Minor key encoding in 15 bits RRRTTTOOOOOOOMM.
-  class ModeBits: public BitField<OverwriteMode, 0, 2> {};
-  class OpBits: public BitField<Token::Value, 2, 7> {};
-  class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 9, 3> {};
-  class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 12, 3> {};
-
-  Major MajorKey() { return BinaryOp; }
-  int MinorKey() {
-    return OpBits::encode(op_)
-           | ModeBits::encode(mode_)
-           | OperandTypeInfoBits::encode(operands_type_)
-           | ResultTypeInfoBits::encode(result_type_);
-  }
-
-  void Generate(MacroAssembler* masm);
-  void GenerateGeneric(MacroAssembler* masm);
-  void GenerateSmiCode(MacroAssembler* masm,
-                       Label* slow,
-                       SmiCodeGenerateHeapNumberResults heapnumber_results);
-  void GenerateFloatingPointCode(MacroAssembler* masm,
-                                 Label* allocation_failure,
-                                 Label* non_numeric_failure);
-  void GenerateStringAddCode(MacroAssembler* masm);
-  void GenerateCallRuntimeCode(MacroAssembler* masm);
-  void GenerateLoadArguments(MacroAssembler* masm);
-  void GenerateReturn(MacroAssembler* masm);
-  void GenerateUninitializedStub(MacroAssembler* masm);
-  void GenerateSmiStub(MacroAssembler* masm);
-  void GenerateInt32Stub(MacroAssembler* masm);
-  void GenerateHeapNumberStub(MacroAssembler* masm);
-  void GenerateOddballStub(MacroAssembler* masm);
-  void GenerateStringStub(MacroAssembler* masm);
-  void GenerateBothStringStub(MacroAssembler* masm);
-  void GenerateGenericStub(MacroAssembler* masm);
-
-  void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure);
-  void GenerateRegisterArgsPush(MacroAssembler* masm);
-  void GenerateTypeTransition(MacroAssembler* masm);
-  void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
-
-  virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
-
-  virtual InlineCacheState GetICState() {
-    return BinaryOpIC::ToState(operands_type_);
-  }
-
-  virtual void FinishCode(Handle<Code> code) {
-    code->set_binary_op_type(operands_type_);
-    code->set_binary_op_result_type(result_type_);
-  }
-
-  friend class CodeGenerator;
-};
-
-
 class StringHelper : public AllStatic {
  public:
   // Generate code for copying characters using a simple loop. This should only
index a198739a4244b420a404fe0483308898ecc2e3bd..a1f3f4ec2a226572f145feb4ebfc7c236d44310f 100644 (file)
@@ -4060,13 +4060,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   SetSourcePosition(expr->position());
 
   // Call stub for +1/-1.
+  __ movq(rdx, rax);
+  __ Move(rax, Smi::FromInt(1));
   BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
-  if (expr->op() == Token::INC) {
-    __ Move(rdx, Smi::FromInt(1));
-  } else {
-    __ movq(rdx, rax);
-    __ Move(rax, Smi::FromInt(1));
-  }
   CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountBinOpFeedbackId());
   patch_site.EmitPatchInfo();
   __ bind(&done);
@@ -4285,29 +4281,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
 
     default: {
       VisitForAccumulatorValue(expr->right());
-      Condition cc = no_condition;
-      switch (op) {
-        case Token::EQ_STRICT:
-        case Token::EQ:
-          cc = equal;
-          break;
-        case Token::LT:
-          cc = less;
-          break;
-        case Token::GT:
-          cc = greater;
-         break;
-        case Token::LTE:
-          cc = less_equal;
-          break;
-        case Token::GTE:
-          cc = greater_equal;
-          break;
-        case Token::IN:
-        case Token::INSTANCEOF:
-        default:
-          UNREACHABLE();
-      }
+      Condition cc = CompareIC::ComputeCondition(op);
       __ pop(rdx);
 
       bool inline_smi_code = ShouldInlineSmiCase(op);
index efa07a80b5a3ad52abbd8afa349115d35f6e89ec..641e243300e011429465f501ec0b03124ee7cf21 100644 (file)
@@ -1729,7 +1729,7 @@ Condition CompareIC::ComputeCondition(Token::Value op) {
 }
 
 
-static bool HasInlinedSmiCode(Address address) {
+bool CompareIC::HasInlinedSmiCode(Address address) {
   // The address of the instruction following the call.
   Address test_instruction_address =
       address + Assembler::kCallTargetAddressOffset;
@@ -1740,39 +1740,6 @@ static bool HasInlinedSmiCode(Address address) {
 }
 
 
-void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
-  HandleScope scope;
-  Handle<Code> rewritten;
-  State previous_state = GetState();
-
-  State state = TargetState(previous_state, HasInlinedSmiCode(address()), x, y);
-  if (state == GENERIC) {
-    CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
-    rewritten = stub.GetCode();
-  } else {
-    ICCompareStub stub(op_, state);
-    if (state == KNOWN_OBJECTS) {
-      stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
-    }
-    rewritten = stub.GetCode();
-  }
-  set_target(*rewritten);
-
-#ifdef DEBUG
-  if (FLAG_trace_ic) {
-    PrintF("[CompareIC (%s->%s)#%s]\n",
-           GetStateName(previous_state),
-           GetStateName(state),
-           Token::Name(op_));
-  }
-#endif
-
-  // Activate inlined smi code.
-  if (previous_state == UNINITIALIZED) {
-    PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
-  }
-}
-
 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
   // The address of the instruction following the call.
   Address test_instruction_address =
index 2bcf943ab6cb3963fe9c8b53f0a3679355c9048e..13c5fa51fda9e8e7d390e69a1ba2d3b64c4313cd 100644 (file)
@@ -236,7 +236,30 @@ bool LCodeGen::GenerateBody() {
     }
 
     if (emit_instructions) {
-      Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
+      if (FLAG_code_comments) {
+        HValue* hydrogen = instr->hydrogen_value();
+        if (hydrogen != NULL) {
+          if (hydrogen->IsChange()) {
+            HValue* changed_value = HChange::cast(hydrogen)->value();
+            int use_id = 0;
+            const char* use_mnemo = "dead";
+            if (hydrogen->UseCount() >= 1) {
+              HValue* use_value = hydrogen->uses().value();
+              use_id = use_value->id();
+              use_mnemo = use_value->Mnemonic();
+            }
+            Comment(";;; @%d: %s. <of #%d %s for #%d %s>",
+                    current_instruction_, instr->Mnemonic(),
+                    changed_value->id(), changed_value->Mnemonic(),
+                    use_id, use_mnemo);
+          } else {
+            Comment(";;; @%d: %s. <#%d>", current_instruction_,
+                    instr->Mnemonic(), hydrogen->id());
+          }
+        } else {
+          Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
+        }
+      }
       instr->CompileToNative(this);
     }
   }
index a874a2400aa1a850eb924ceb83c0df8f02b03519..45b15723dc7ac856ee6c7b19be4c7ea6ec524af9 100644 (file)
@@ -1389,7 +1389,7 @@ LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
 
 LInstruction* LChunkBuilder::DoCompareIDAndBranch(
     HCompareIDAndBranch* instr) {
-  Representation r = instr->GetInputRepresentation();
+  Representation r = instr->representation();
   if (r.IsInteger32()) {
     ASSERT(instr->left()->representation().IsInteger32());
     ASSERT(instr->right()->representation().IsInteger32());
@@ -2152,7 +2152,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
   env->set_ast_id(instr->ast_id());
 
   env->Drop(instr->pop_count());
-  for (int i = 0; i < instr->values()->length(); ++i) {
+  for (int i = instr->values()->length() - 1; i >= 0; --i) {
     HValue* value = instr->values()->at(i);
     if (instr->HasAssignedIndexAt(i)) {
       env->Bind(instr->GetAssignedIndexAt(i), value);
index 79ce9689994f76b463284623f89137d9cfba0560..52fe7aa8123c75f371228c84a5172ed162de00f9 100644 (file)
@@ -620,7 +620,7 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> {
 
   Token::Value op() const { return hydrogen()->token(); }
   bool is_double() const {
-    return hydrogen()->GetInputRepresentation().IsDouble();
+    return hydrogen()->representation().IsDouble();
   }
 
   virtual void PrintDataTo(StringStream* stream);
index 206e95ac1e751022f45fbd6a7ab078dd95308df0..f9880bdaee4b75e2b1b9659a59d9e2bda4e95ca4 100644 (file)
@@ -11372,6 +11372,7 @@ static void RunLoopInNewEnv() {
 
 TEST(SetFunctionEntryHook) {
   i::FLAG_allow_natives_syntax = true;
+  i::FLAG_use_inlining = false;
 
   // Test setting and resetting the entry hook.
   // Nulling it should always succeed.
index 27434908472d36133e611a42890cd4c0d67a1125..734916585494bab5046706a01a99f938b12b24a4 100644 (file)
@@ -34,6 +34,7 @@ function test_div_no_deopt_minus_zero() {
   assertTrue(0 === (Math.floor((zero_in_array[0] | 0) / -1) | 0));
 }
 
+test_div_no_deopt_minus_zero();
 test_div_no_deopt_minus_zero();
 %OptimizeFunctionOnNextCall(test_div_no_deopt_minus_zero);
 test_div_no_deopt_minus_zero();