| Index: src/x64/code-stubs-x64.cc
 | 
| diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
 | 
| index a8e52e99d306d0cedb44ab9f4ef74eedd10d85c0..be6ae99dcb4900164083e66ebcee2088dbab9a29 100644
 | 
| --- a/src/x64/code-stubs-x64.cc
 | 
| +++ b/src/x64/code-stubs-x64.cc
 | 
| @@ -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, ¬_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(¬_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, ¬_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, ¬_number);
 | 
| +  }
 | 
| +  if (right_type_ == BinaryOpIC::SMI) {
 | 
| +    BinaryOpStub_CheckSmiInput(masm, rax, ¬_number);
 | 
| +  }
 | 
| +
 | 
| +  BinaryOpStub_GenerateFloatingPointCode(
 | 
| +      masm, &gc_required, ¬_number, op_, mode_);
 | 
|  
 | 
|    __ bind(¬_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, ¬_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, ¬_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, ¬_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(¬_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);
 | 
| 
 |