| Index: src/x64/code-stubs-x64.cc
|
| diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
|
| index f0f9c5d272ef926c58ac28e81d67ba6f00eeac66..1077d8bef5c606f9e0397f71153a4ff9eda28138 100644
|
| --- a/src/x64/code-stubs-x64.cc
|
| +++ b/src/x64/code-stubs-x64.cc
|
| @@ -997,16 +997,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 +1014,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 +1032,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 +1042,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 +1051,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 +1123,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 +1132,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;
|
| @@ -1221,24 +1167,32 @@ void BinaryOpStub::GenerateSmiCode(
|
| }
|
|
|
|
|
| -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 +1213,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 +1237,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 +1274,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 +1310,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 +1329,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 +1378,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 +1405,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
|
| @@ -2025,14 +1976,14 @@ void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm,
|
| Label* on_not_smis) {
|
| 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, &maybe_undefined_first);
|
| // Convert HeapNumber to smi if possible.
|
| __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset));
|
| __ movq(scratch2, xmm0);
|
| @@ -2045,11 +1996,12 @@ 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, &maybe_undefined_second);
|
| // Convert second to smi, if possible.
|
| __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset));
|
| __ movq(scratch2, xmm0);
|
| @@ -2062,8 +2014,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 +3347,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 +3412,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 +3515,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 +3562,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 +3583,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 +3623,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 +3636,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 +4396,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 +5505,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 +5529,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 +5579,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 +5606,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 +5649,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 +5735,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);
|
|
|