diff options
Diffstat (limited to 'deps/v8/src/x64/code-stubs-x64.cc')
-rw-r--r-- | deps/v8/src/x64/code-stubs-x64.cc | 711 |
1 files changed, 349 insertions, 362 deletions
diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc index 3fa93b2983..970571840b 100644 --- a/deps/v8/src/x64/code-stubs-x64.cc +++ b/deps/v8/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). @@ -1297,11 +1267,9 @@ void BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm, &allocation_failed, TAG_OBJECT); // Set the map. - if (FLAG_debug_code) { - __ AbortIfNotRootValue(heap_number_map, - Heap::kHeapNumberMapRootIndex, - "HeapNumberMap register clobbered."); - } + __ AssertRootValue(heap_number_map, + Heap::kHeapNumberMapRootIndex, + "HeapNumberMap register clobbered."); __ movq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); __ cvtqsi2sd(xmm0, rbx); @@ -1322,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; @@ -1358,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 @@ -1418,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. @@ -1469,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. @@ -1496,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 @@ -2024,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); @@ -2047,14 +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); - if (FLAG_debug_code) { - // Second should be non-smi if we get here. - __ AbortIfSmi(second); - } + __ 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); @@ -2067,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); } @@ -2234,7 +2221,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X) __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X) - __ faddp(1); // 1, 2^(X-rnd(X)), rnd(X) + __ faddp(1); // 2^(X-rnd(X)), rnd(X) // FSCALE calculates st(0) * 2^st(1) __ fscale(); // 2^X, rnd(X) __ fstp(1); @@ -2262,21 +2249,28 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ movsd(double_scratch2, double_result); // Load double_exponent with 1. // Get absolute value of exponent. - Label no_neg, while_true, no_multiply; + Label no_neg, while_true, while_false; __ testl(scratch, scratch); __ j(positive, &no_neg, Label::kNear); __ negl(scratch); __ bind(&no_neg); - __ bind(&while_true); + __ j(zero, &while_false, Label::kNear); __ shrl(scratch, Immediate(1)); - __ j(not_carry, &no_multiply, Label::kNear); - __ mulsd(double_result, double_scratch); - __ bind(&no_multiply); + // Above condition means CF==0 && ZF==0. This means that the + // bit that has been shifted out is 0 and the result is not 0. + __ j(above, &while_true, Label::kNear); + __ movsd(double_result, double_scratch); + __ j(zero, &while_false, Label::kNear); + __ bind(&while_true); + __ shrl(scratch, Immediate(1)); __ mulsd(double_scratch, double_scratch); + __ j(above, &while_true, Label::kNear); + __ mulsd(double_result, double_scratch); __ j(not_zero, &while_true); + __ bind(&while_false); // If the exponent is negative, return 1/result. __ testl(exponent, exponent); __ j(greater, &done); @@ -2602,7 +2596,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { __ bind(&runtime); __ Integer32ToSmi(rcx, rcx); __ movq(Operand(rsp, 1 * kPointerSize), rcx); // Patch argument count. - __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); + __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); } @@ -3020,8 +3014,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // r15: original subject string __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. __ j(zero, &setup_two_byte, Label::kNear); - __ lea(arg4, FieldOperand(rdi, r14, times_1, SeqAsciiString::kHeaderSize)); - __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqAsciiString::kHeaderSize)); + __ lea(arg4, FieldOperand(rdi, r14, times_1, SeqOneByteString::kHeaderSize)); + __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqOneByteString::kHeaderSize)); __ jmp(&setup_rest, Label::kNear); __ bind(&setup_two_byte); __ lea(arg4, FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize)); @@ -3161,7 +3155,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { } __ movq(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); __ subq(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); STATIC_ASSERT(kTwoByteStringTag == 0); __ testb(rbx, Immediate(kStringEncodingMask)); @@ -3235,14 +3229,14 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) { // Set length. __ Integer32ToSmi(rdx, rbx); __ movq(FieldOperand(rcx, FixedArray::kLengthOffset), rdx); - // Fill contents of fixed-array with the-hole. - __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); + // Fill contents of fixed-array with undefined. + __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); __ lea(rcx, FieldOperand(rcx, FixedArray::kHeaderSize)); - // Fill fixed array elements with hole. + // Fill fixed array elements with undefined. // rax: JSArray. // rbx: Number of elements in array that remains to be filled, as int32. // rcx: Start of elements in FixedArray. - // rdx: the hole. + // rdx: undefined. Label loop; __ testl(rbx, rbx); __ bind(&loop); @@ -3376,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. @@ -3412,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. { @@ -3523,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); @@ -3572,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, @@ -3593,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. @@ -3633,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. @@ -3646,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); } @@ -4419,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 @@ -4694,8 +4656,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { &call_runtime); // Get the two characters forming the sub string. - __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); - __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); + __ movzxbq(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); + __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); // Try to lookup two character string in symbol table. If it is not found // just allocate a new one. @@ -4711,11 +4673,11 @@ void StringAddStub::Generate(MacroAssembler* masm) { // rbx - first byte: first character // rbx - second byte: *maybe* second character // Make sure that the second byte of rbx contains the second character. - __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); + __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); __ shll(rcx, Immediate(kBitsPerByte)); __ orl(rbx, rcx); // Write both characters to the new string. - __ movw(FieldOperand(rax, SeqAsciiString::kHeaderSize), rbx); + __ movw(FieldOperand(rax, SeqOneByteString::kHeaderSize), rbx); __ IncrementCounter(counters->string_add_native(), 1); __ ret(2 * kPointerSize); @@ -4738,7 +4700,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { Label non_ascii, allocated, ascii_data; __ movl(rcx, r8); __ and_(rcx, r9); - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ testl(rcx, Immediate(kStringEncodingMask)); __ j(zero, &non_ascii); @@ -4763,11 +4725,6 @@ void StringAddStub::Generate(MacroAssembler* masm) { // r9: second instance type. __ testb(rcx, Immediate(kAsciiDataHintMask)); __ j(not_zero, &ascii_data); - __ xor_(r8, r9); - STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); - __ andb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); - __ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); - __ j(equal, &ascii_data); // Allocate a two byte cons string. __ AllocateTwoByteConsString(rcx, rdi, no_reg, &call_runtime); __ jmp(&allocated); @@ -4797,8 +4754,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ movq(rcx, FieldOperand(rax, ExternalString::kResourceDataOffset)); __ jmp(&first_prepared, Label::kNear); __ bind(&first_is_sequential); - STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); - __ lea(rcx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); + STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); + __ lea(rcx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); __ bind(&first_prepared); // Check whether both strings have same encoding. @@ -4818,8 +4775,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ movq(rdx, FieldOperand(rdx, ExternalString::kResourceDataOffset)); __ jmp(&second_prepared, Label::kNear); __ bind(&second_is_sequential); - STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); - __ lea(rdx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); + STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); + __ lea(rdx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); __ bind(&second_prepared); Label non_ascii_string_add_flat_result; @@ -4835,7 +4792,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ AllocateAsciiString(rax, rbx, rdi, r8, r9, &call_runtime); // rax: result string // Locate first character of result. - __ lea(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); + __ lea(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); // rcx: first char of first string // rbx: first character of result // r14: length of first string @@ -5108,7 +5065,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, temp, temp, &next_probe[i]); // Check if the two characters match. - __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); + __ movl(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize)); __ andl(temp, Immediate(0x0000ffff)); __ cmpl(chars, temp); __ j(equal, &found_in_symbol_table); @@ -5286,7 +5243,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { // string's encoding is wrong because we always have to recheck encoding of // the newly created string's parent anyways due to externalized strings. Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ testb(rbx, Immediate(kStringEncodingMask)); __ j(zero, &two_byte_slice, Label::kNear); @@ -5326,11 +5283,11 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ j(not_zero, &runtime); __ movq(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); __ subq(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); __ bind(&sequential_string); - STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0); + STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); __ testb(rbx, Immediate(kStringEncodingMask)); __ j(zero, &two_byte_sequential); @@ -5343,10 +5300,10 @@ void SubStringStub::Generate(MacroAssembler* masm) { { // Locate character of sub string start. SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_1); __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, - SeqAsciiString::kHeaderSize - kHeapObjectTag)); + SeqOneByteString::kHeaderSize - kHeapObjectTag)); } // Locate first character of result. - __ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize)); + __ lea(rdi, FieldOperand(rax, SeqOneByteString::kHeaderSize)); // rax: result string // rcx: result length @@ -5368,7 +5325,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { { // Locate character of sub string start. SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_2); __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, - SeqAsciiString::kHeaderSize - kHeapObjectTag)); + SeqOneByteString::kHeaderSize - kHeapObjectTag)); } // Locate first character of result. __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); @@ -5508,9 +5465,9 @@ void StringCompareStub::GenerateAsciiCharsCompareLoop( // doesn't need an additional compare. __ SmiToInteger32(length, length); __ lea(left, - FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize)); + FieldOperand(left, length, times_1, SeqOneByteString::kHeaderSize)); __ lea(right, - FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); + FieldOperand(right, length, times_1, SeqOneByteString::kHeaderSize)); __ neg(length); Register index = length; // index = -length; @@ -5566,7 +5523,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); @@ -5578,7 +5535,7 @@ void ICCompareStub::GenerateSmis(MacroAssembler* masm) { __ subq(rdx, rax); __ j(no_overflow, &done, Label::kNear); // Correct sign of result in case of overflow. - __ SmiNot(rdx, rdx); + __ not_(rdx); __ bind(&done); __ movq(rax, rdx); } @@ -5590,23 +5547,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); @@ -5622,14 +5597,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); @@ -5647,7 +5624,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. @@ -5690,7 +5667,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_); @@ -5776,7 +5753,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); @@ -5922,8 +5899,7 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, ASSERT(!name.is(r0)); ASSERT(!name.is(r1)); - // Assert that name contains a string. - if (FLAG_debug_code) __ AbortIfNotString(name); + __ AssertString(name); __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset)); __ decl(r0); @@ -6137,6 +6113,11 @@ void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() { } +bool CodeStub::CanUseFPRegisters() { + return true; // Always have SSE2 on x64. +} + + // Takes the input in 3 registers: address_ value_ and object_. A pointer to // the value has just been written into the object, now this stub makes sure // we keep the GC informed. The word in the object where the value has been @@ -6233,13 +6214,8 @@ void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) { ASSERT(!address.is(arg1)); __ Move(address, regs_.address()); __ Move(arg1, regs_.object()); - if (mode == INCREMENTAL_COMPACTION) { - // TODO(gc) Can we just set address arg2 in the beginning? - __ Move(arg2, address); - } else { - ASSERT(mode == INCREMENTAL); - __ movq(arg2, Operand(address, 0)); - } + // TODO(gc) Can we just set address arg2 in the beginning? + __ Move(arg2, address); __ LoadAddress(arg3, ExternalReference::isolate_address()); int argument_count = 3; @@ -6269,6 +6245,17 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker( Label need_incremental; Label need_incremental_pop_object; + __ movq(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask)); + __ and_(regs_.scratch0(), regs_.object()); + __ movq(regs_.scratch1(), + Operand(regs_.scratch0(), + MemoryChunk::kWriteBarrierCounterOffset)); + __ subq(regs_.scratch1(), Immediate(1)); + __ movq(Operand(regs_.scratch0(), + MemoryChunk::kWriteBarrierCounterOffset), + regs_.scratch1()); + __ j(negative, &need_incremental); + // Let's look at the color of the object: If it is not black we don't have // to inform the incremental marker. __ JumpIfBlack(regs_.object(), |