Chromium Code Reviews| Index: src/arm/code-stubs-arm.cc |
| diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc |
| index ceb108ffae69854ede01a5a33526815d07a54983..c9203375432556d25330eeec7befdb275c8df311 100644 |
| --- a/src/arm/code-stubs-arm.cc |
| +++ b/src/arm/code-stubs-arm.cc |
| @@ -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, ¬_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(¬_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, ¬_two_smis); |
| - __ mov(r1, Operand(r1, ASR, 1)); |
| - __ sub(r0, r1, Operand(r0, ASR, 1)); |
| - __ Ret(); |
| - __ bind(¬_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, ¬_two_smis); |
| + __ mov(r1, Operand(r1, ASR, 1)); |
| + __ sub(r0, r1, Operand(r0, ASR, 1)); |
| + __ Ret(); |
| + __ bind(¬_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, ¬_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(¬_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, |
|
danno
2012/11/06 11:42:59
Make into a real class method without the "_"
Jakob Kummerow
2012/11/06 12:44:05
As discussed offline, that would not be as beautif
|
| + 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, ¬_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, ¬_smis, op, mode); |
| } |
| __ bind(¬_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; |
| @@ -6663,7 +6597,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); |
| @@ -6684,31 +6618,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. |
| @@ -6722,14 +6678,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); |
| @@ -6747,7 +6705,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. |
| @@ -6785,7 +6743,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_); |
| @@ -6863,7 +6821,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); |