| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_X64 | 7 #if V8_TARGET_ARCH_X64 |
| 8 | 8 |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 344 | 344 |
| 345 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { | 345 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { |
| 346 // Update the static counter each time a new code stub is generated. | 346 // Update the static counter each time a new code stub is generated. |
| 347 isolate()->counters()->code_stubs()->Increment(); | 347 isolate()->counters()->code_stubs()->Increment(); |
| 348 | 348 |
| 349 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(); | 349 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(); |
| 350 int param_count = descriptor->GetEnvironmentParameterCount(); | 350 int param_count = descriptor->GetEnvironmentParameterCount(); |
| 351 { | 351 { |
| 352 // Call the runtime system in a fresh internal frame. | 352 // Call the runtime system in a fresh internal frame. |
| 353 FrameScope scope(masm, StackFrame::INTERNAL); | 353 FrameScope scope(masm, StackFrame::INTERNAL); |
| 354 ASSERT(param_count == 0 || | 354 DCHECK(param_count == 0 || |
| 355 rax.is(descriptor->GetEnvironmentParameterRegister( | 355 rax.is(descriptor->GetEnvironmentParameterRegister( |
| 356 param_count - 1))); | 356 param_count - 1))); |
| 357 // Push arguments | 357 // Push arguments |
| 358 for (int i = 0; i < param_count; ++i) { | 358 for (int i = 0; i < param_count; ++i) { |
| 359 __ Push(descriptor->GetEnvironmentParameterRegister(i)); | 359 __ Push(descriptor->GetEnvironmentParameterRegister(i)); |
| 360 } | 360 } |
| 361 ExternalReference miss = descriptor->miss_handler(); | 361 ExternalReference miss = descriptor->miss_handler(); |
| 362 __ CallExternalReference(miss, param_count); | 362 __ CallExternalReference(miss, param_count); |
| 363 } | 363 } |
| 364 | 364 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 393 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. | 393 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. |
| 394 // NumberOperands assumes both are smis or heap numbers. | 394 // NumberOperands assumes both are smis or heap numbers. |
| 395 static void LoadSSE2UnknownOperands(MacroAssembler* masm, | 395 static void LoadSSE2UnknownOperands(MacroAssembler* masm, |
| 396 Label* not_numbers); | 396 Label* not_numbers); |
| 397 }; | 397 }; |
| 398 | 398 |
| 399 | 399 |
| 400 void DoubleToIStub::Generate(MacroAssembler* masm) { | 400 void DoubleToIStub::Generate(MacroAssembler* masm) { |
| 401 Register input_reg = this->source(); | 401 Register input_reg = this->source(); |
| 402 Register final_result_reg = this->destination(); | 402 Register final_result_reg = this->destination(); |
| 403 ASSERT(is_truncating()); | 403 DCHECK(is_truncating()); |
| 404 | 404 |
| 405 Label check_negative, process_64_bits, done; | 405 Label check_negative, process_64_bits, done; |
| 406 | 406 |
| 407 int double_offset = offset(); | 407 int double_offset = offset(); |
| 408 | 408 |
| 409 // Account for return address and saved regs if input is rsp. | 409 // Account for return address and saved regs if input is rsp. |
| 410 if (input_reg.is(rsp)) double_offset += 3 * kRegisterSize; | 410 if (input_reg.is(rsp)) double_offset += 3 * kRegisterSize; |
| 411 | 411 |
| 412 MemOperand mantissa_operand(MemOperand(input_reg, double_offset)); | 412 MemOperand mantissa_operand(MemOperand(input_reg, double_offset)); |
| 413 MemOperand exponent_operand(MemOperand(input_reg, | 413 MemOperand exponent_operand(MemOperand(input_reg, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 465 __ cmpl(exponent_operand, Immediate(0)); | 465 __ cmpl(exponent_operand, Immediate(0)); |
| 466 } | 466 } |
| 467 __ cmovl(greater, result_reg, scratch1); | 467 __ cmovl(greater, result_reg, scratch1); |
| 468 | 468 |
| 469 // Restore registers | 469 // Restore registers |
| 470 __ bind(&done); | 470 __ bind(&done); |
| 471 if (stash_exponent_copy) { | 471 if (stash_exponent_copy) { |
| 472 __ addp(rsp, Immediate(kDoubleSize)); | 472 __ addp(rsp, Immediate(kDoubleSize)); |
| 473 } | 473 } |
| 474 if (!final_result_reg.is(result_reg)) { | 474 if (!final_result_reg.is(result_reg)) { |
| 475 ASSERT(final_result_reg.is(rcx)); | 475 DCHECK(final_result_reg.is(rcx)); |
| 476 __ movl(final_result_reg, result_reg); | 476 __ movl(final_result_reg, result_reg); |
| 477 } | 477 } |
| 478 __ popq(save_reg); | 478 __ popq(save_reg); |
| 479 __ popq(scratch1); | 479 __ popq(scratch1); |
| 480 __ ret(0); | 480 __ ret(0); |
| 481 } | 481 } |
| 482 | 482 |
| 483 | 483 |
| 484 void FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm, | 484 void FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm, |
| 485 Label* not_numbers) { | 485 Label* not_numbers) { |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 746 // as heap number in rax. | 746 // as heap number in rax. |
| 747 __ bind(&done); | 747 __ bind(&done); |
| 748 __ AllocateHeapNumber(rax, rcx, &call_runtime); | 748 __ AllocateHeapNumber(rax, rcx, &call_runtime); |
| 749 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), double_result); | 749 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), double_result); |
| 750 __ IncrementCounter(counters->math_pow(), 1); | 750 __ IncrementCounter(counters->math_pow(), 1); |
| 751 __ ret(2 * kPointerSize); | 751 __ ret(2 * kPointerSize); |
| 752 } else { | 752 } else { |
| 753 __ bind(&call_runtime); | 753 __ bind(&call_runtime); |
| 754 // Move base to the correct argument register. Exponent is already in xmm1. | 754 // Move base to the correct argument register. Exponent is already in xmm1. |
| 755 __ movsd(xmm0, double_base); | 755 __ movsd(xmm0, double_base); |
| 756 ASSERT(double_exponent.is(xmm1)); | 756 DCHECK(double_exponent.is(xmm1)); |
| 757 { | 757 { |
| 758 AllowExternalCallThatCantCauseGC scope(masm); | 758 AllowExternalCallThatCantCauseGC scope(masm); |
| 759 __ PrepareCallCFunction(2); | 759 __ PrepareCallCFunction(2); |
| 760 __ CallCFunction( | 760 __ CallCFunction( |
| 761 ExternalReference::power_double_double_function(isolate()), 2); | 761 ExternalReference::power_double_double_function(isolate()), 2); |
| 762 } | 762 } |
| 763 // Return value is in xmm0. | 763 // Return value is in xmm0. |
| 764 __ movsd(double_result, xmm0); | 764 __ movsd(double_result, xmm0); |
| 765 | 765 |
| 766 __ bind(&done); | 766 __ bind(&done); |
| (...skipping 858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1625 // (11) Sliced string. Replace subject with parent. Go to (5a). | 1625 // (11) Sliced string. Replace subject with parent. Go to (5a). |
| 1626 // Load offset into r14 and replace subject string with parent. | 1626 // Load offset into r14 and replace subject string with parent. |
| 1627 __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset)); | 1627 __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset)); |
| 1628 __ movp(rdi, FieldOperand(rdi, SlicedString::kParentOffset)); | 1628 __ movp(rdi, FieldOperand(rdi, SlicedString::kParentOffset)); |
| 1629 __ jmp(&check_underlying); | 1629 __ jmp(&check_underlying); |
| 1630 #endif // V8_INTERPRETED_REGEXP | 1630 #endif // V8_INTERPRETED_REGEXP |
| 1631 } | 1631 } |
| 1632 | 1632 |
| 1633 | 1633 |
| 1634 static int NegativeComparisonResult(Condition cc) { | 1634 static int NegativeComparisonResult(Condition cc) { |
| 1635 ASSERT(cc != equal); | 1635 DCHECK(cc != equal); |
| 1636 ASSERT((cc == less) || (cc == less_equal) | 1636 DCHECK((cc == less) || (cc == less_equal) |
| 1637 || (cc == greater) || (cc == greater_equal)); | 1637 || (cc == greater) || (cc == greater_equal)); |
| 1638 return (cc == greater || cc == greater_equal) ? LESS : GREATER; | 1638 return (cc == greater || cc == greater_equal) ? LESS : GREATER; |
| 1639 } | 1639 } |
| 1640 | 1640 |
| 1641 | 1641 |
| 1642 static void CheckInputType(MacroAssembler* masm, | 1642 static void CheckInputType(MacroAssembler* masm, |
| 1643 Register input, | 1643 Register input, |
| 1644 CompareIC::State expected, | 1644 CompareIC::State expected, |
| 1645 Label* fail) { | 1645 Label* fail) { |
| 1646 Label ok; | 1646 Label ok; |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1816 __ j(parity_even, &unordered, Label::kNear); | 1816 __ j(parity_even, &unordered, Label::kNear); |
| 1817 // Return a result of -1, 0, or 1, based on EFLAGS. | 1817 // Return a result of -1, 0, or 1, based on EFLAGS. |
| 1818 __ setcc(above, rax); | 1818 __ setcc(above, rax); |
| 1819 __ setcc(below, rcx); | 1819 __ setcc(below, rcx); |
| 1820 __ subp(rax, rcx); | 1820 __ subp(rax, rcx); |
| 1821 __ ret(0); | 1821 __ ret(0); |
| 1822 | 1822 |
| 1823 // If one of the numbers was NaN, then the result is always false. | 1823 // If one of the numbers was NaN, then the result is always false. |
| 1824 // The cc is never not-equal. | 1824 // The cc is never not-equal. |
| 1825 __ bind(&unordered); | 1825 __ bind(&unordered); |
| 1826 ASSERT(cc != not_equal); | 1826 DCHECK(cc != not_equal); |
| 1827 if (cc == less || cc == less_equal) { | 1827 if (cc == less || cc == less_equal) { |
| 1828 __ Set(rax, 1); | 1828 __ Set(rax, 1); |
| 1829 } else { | 1829 } else { |
| 1830 __ Set(rax, -1); | 1830 __ Set(rax, -1); |
| 1831 } | 1831 } |
| 1832 __ ret(0); | 1832 __ ret(0); |
| 1833 | 1833 |
| 1834 // The number comparison code did not provide a valid result. | 1834 // The number comparison code did not provide a valid result. |
| 1835 __ bind(&non_number_comparison); | 1835 __ bind(&non_number_comparison); |
| 1836 | 1836 |
| (...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2458 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. | 2458 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. |
| 2459 // Pass argv and argc as two parameters. The arguments object will | 2459 // Pass argv and argc as two parameters. The arguments object will |
| 2460 // be created by stubs declared by DECLARE_RUNTIME_FUNCTION(). | 2460 // be created by stubs declared by DECLARE_RUNTIME_FUNCTION(). |
| 2461 if (result_size_ < 2) { | 2461 if (result_size_ < 2) { |
| 2462 // Pass a pointer to the Arguments object as the first argument. | 2462 // Pass a pointer to the Arguments object as the first argument. |
| 2463 // Return result in single register (rax). | 2463 // Return result in single register (rax). |
| 2464 __ movp(rcx, r14); // argc. | 2464 __ movp(rcx, r14); // argc. |
| 2465 __ movp(rdx, r15); // argv. | 2465 __ movp(rdx, r15); // argv. |
| 2466 __ Move(r8, ExternalReference::isolate_address(isolate())); | 2466 __ Move(r8, ExternalReference::isolate_address(isolate())); |
| 2467 } else { | 2467 } else { |
| 2468 ASSERT_EQ(2, result_size_); | 2468 DCHECK_EQ(2, result_size_); |
| 2469 // Pass a pointer to the result location as the first argument. | 2469 // Pass a pointer to the result location as the first argument. |
| 2470 __ leap(rcx, StackSpaceOperand(2)); | 2470 __ leap(rcx, StackSpaceOperand(2)); |
| 2471 // Pass a pointer to the Arguments object as the second argument. | 2471 // Pass a pointer to the Arguments object as the second argument. |
| 2472 __ movp(rdx, r14); // argc. | 2472 __ movp(rdx, r14); // argc. |
| 2473 __ movp(r8, r15); // argv. | 2473 __ movp(r8, r15); // argv. |
| 2474 __ Move(r9, ExternalReference::isolate_address(isolate())); | 2474 __ Move(r9, ExternalReference::isolate_address(isolate())); |
| 2475 } | 2475 } |
| 2476 | 2476 |
| 2477 #else // _WIN64 | 2477 #else // _WIN64 |
| 2478 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. | 2478 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. |
| 2479 __ movp(rdi, r14); // argc. | 2479 __ movp(rdi, r14); // argc. |
| 2480 __ movp(rsi, r15); // argv. | 2480 __ movp(rsi, r15); // argv. |
| 2481 __ Move(rdx, ExternalReference::isolate_address(isolate())); | 2481 __ Move(rdx, ExternalReference::isolate_address(isolate())); |
| 2482 #endif | 2482 #endif |
| 2483 __ call(rbx); | 2483 __ call(rbx); |
| 2484 // Result is in rax - do not destroy this register! | 2484 // Result is in rax - do not destroy this register! |
| 2485 | 2485 |
| 2486 #ifdef _WIN64 | 2486 #ifdef _WIN64 |
| 2487 // If return value is on the stack, pop it to registers. | 2487 // If return value is on the stack, pop it to registers. |
| 2488 if (result_size_ > 1) { | 2488 if (result_size_ > 1) { |
| 2489 ASSERT_EQ(2, result_size_); | 2489 DCHECK_EQ(2, result_size_); |
| 2490 // Read result values stored on stack. Result is stored | 2490 // Read result values stored on stack. Result is stored |
| 2491 // above the four argument mirror slots and the two | 2491 // above the four argument mirror slots and the two |
| 2492 // Arguments object slots. | 2492 // Arguments object slots. |
| 2493 __ movq(rax, Operand(rsp, 6 * kRegisterSize)); | 2493 __ movq(rax, Operand(rsp, 6 * kRegisterSize)); |
| 2494 __ movq(rdx, Operand(rsp, 7 * kRegisterSize)); | 2494 __ movq(rdx, Operand(rsp, 7 * kRegisterSize)); |
| 2495 } | 2495 } |
| 2496 #endif | 2496 #endif |
| 2497 | 2497 |
| 2498 // Runtime functions should not return 'the hole'. Allowing it to escape may | 2498 // Runtime functions should not return 'the hole'. Allowing it to escape may |
| 2499 // lead to crashes in the IC code later. | 2499 // lead to crashes in the IC code later. |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2753 kPointerSize == kInt64Size ? 0xBA49FF78 : 0xBA41FF78; | 2753 kPointerSize == kInt64Size ? 0xBA49FF78 : 0xBA41FF78; |
| 2754 // The last 4 bytes of the instruction sequence | 2754 // The last 4 bytes of the instruction sequence |
| 2755 // __ j(not_equal, &cache_miss); | 2755 // __ j(not_equal, &cache_miss); |
| 2756 // __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex); | 2756 // __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex); |
| 2757 // before the offset of the hole value in the root array. | 2757 // before the offset of the hole value in the root array. |
| 2758 static const unsigned int kWordBeforeResultValue = | 2758 static const unsigned int kWordBeforeResultValue = |
| 2759 kPointerSize == kInt64Size ? 0x458B4906 : 0x458B4106; | 2759 kPointerSize == kInt64Size ? 0x458B4906 : 0x458B4106; |
| 2760 | 2760 |
| 2761 int extra_argument_offset = HasCallSiteInlineCheck() ? 1 : 0; | 2761 int extra_argument_offset = HasCallSiteInlineCheck() ? 1 : 0; |
| 2762 | 2762 |
| 2763 ASSERT_EQ(object.code(), InstanceofStub::left().code()); | 2763 DCHECK_EQ(object.code(), InstanceofStub::left().code()); |
| 2764 ASSERT_EQ(function.code(), InstanceofStub::right().code()); | 2764 DCHECK_EQ(function.code(), InstanceofStub::right().code()); |
| 2765 | 2765 |
| 2766 // Get the object and function - they are always both needed. | 2766 // Get the object and function - they are always both needed. |
| 2767 // Go slow case if the object is a smi. | 2767 // Go slow case if the object is a smi. |
| 2768 Label slow; | 2768 Label slow; |
| 2769 StackArgumentsAccessor args(rsp, 2 + extra_argument_offset, | 2769 StackArgumentsAccessor args(rsp, 2 + extra_argument_offset, |
| 2770 ARGUMENTS_DONT_CONTAIN_RECEIVER); | 2770 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 2771 if (!HasArgsInRegisters()) { | 2771 if (!HasArgsInRegisters()) { |
| 2772 __ movp(object, args.GetArgumentOperand(0)); | 2772 __ movp(object, args.GetArgumentOperand(0)); |
| 2773 __ movp(function, args.GetArgumentOperand(1)); | 2773 __ movp(function, args.GetArgumentOperand(1)); |
| 2774 } | 2774 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2805 __ j(above, &slow); | 2805 __ j(above, &slow); |
| 2806 | 2806 |
| 2807 // Update the global instanceof or call site inlined cache with the current | 2807 // Update the global instanceof or call site inlined cache with the current |
| 2808 // map and function. The cached answer will be set when it is known below. | 2808 // map and function. The cached answer will be set when it is known below. |
| 2809 if (!HasCallSiteInlineCheck()) { | 2809 if (!HasCallSiteInlineCheck()) { |
| 2810 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); | 2810 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); |
| 2811 __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); | 2811 __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); |
| 2812 } else { | 2812 } else { |
| 2813 // The constants for the code patching are based on push instructions | 2813 // The constants for the code patching are based on push instructions |
| 2814 // at the call site. | 2814 // at the call site. |
| 2815 ASSERT(!HasArgsInRegisters()); | 2815 DCHECK(!HasArgsInRegisters()); |
| 2816 // Get return address and delta to inlined map check. | 2816 // Get return address and delta to inlined map check. |
| 2817 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); | 2817 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); |
| 2818 __ subp(kScratchRegister, args.GetArgumentOperand(2)); | 2818 __ subp(kScratchRegister, args.GetArgumentOperand(2)); |
| 2819 if (FLAG_debug_code) { | 2819 if (FLAG_debug_code) { |
| 2820 __ movl(scratch, Immediate(kWordBeforeMapCheckValue)); | 2820 __ movl(scratch, Immediate(kWordBeforeMapCheckValue)); |
| 2821 __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), scratch); | 2821 __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), scratch); |
| 2822 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCheck); | 2822 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCheck); |
| 2823 } | 2823 } |
| 2824 __ movp(kScratchRegister, | 2824 __ movp(kScratchRegister, |
| 2825 Operand(kScratchRegister, kOffsetToMapCheckValue)); | 2825 Operand(kScratchRegister, kOffsetToMapCheckValue)); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2848 STATIC_ASSERT(kSmiTag == 0); | 2848 STATIC_ASSERT(kSmiTag == 0); |
| 2849 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); | 2849 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| 2850 if (ReturnTrueFalseObject()) { | 2850 if (ReturnTrueFalseObject()) { |
| 2851 __ LoadRoot(rax, Heap::kTrueValueRootIndex); | 2851 __ LoadRoot(rax, Heap::kTrueValueRootIndex); |
| 2852 } | 2852 } |
| 2853 } else { | 2853 } else { |
| 2854 // Store offset of true in the root array at the inline check site. | 2854 // Store offset of true in the root array at the inline check site. |
| 2855 int true_offset = 0x100 + | 2855 int true_offset = 0x100 + |
| 2856 (Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; | 2856 (Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; |
| 2857 // Assert it is a 1-byte signed value. | 2857 // Assert it is a 1-byte signed value. |
| 2858 ASSERT(true_offset >= 0 && true_offset < 0x100); | 2858 DCHECK(true_offset >= 0 && true_offset < 0x100); |
| 2859 __ movl(rax, Immediate(true_offset)); | 2859 __ movl(rax, Immediate(true_offset)); |
| 2860 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); | 2860 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); |
| 2861 __ subp(kScratchRegister, args.GetArgumentOperand(2)); | 2861 __ subp(kScratchRegister, args.GetArgumentOperand(2)); |
| 2862 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); | 2862 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); |
| 2863 if (FLAG_debug_code) { | 2863 if (FLAG_debug_code) { |
| 2864 __ movl(rax, Immediate(kWordBeforeResultValue)); | 2864 __ movl(rax, Immediate(kWordBeforeResultValue)); |
| 2865 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); | 2865 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); |
| 2866 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); | 2866 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); |
| 2867 } | 2867 } |
| 2868 if (!ReturnTrueFalseObject()) { | 2868 if (!ReturnTrueFalseObject()) { |
| 2869 __ Set(rax, 0); | 2869 __ Set(rax, 0); |
| 2870 } | 2870 } |
| 2871 } | 2871 } |
| 2872 __ ret(((HasArgsInRegisters() ? 0 : 2) + extra_argument_offset) * | 2872 __ ret(((HasArgsInRegisters() ? 0 : 2) + extra_argument_offset) * |
| 2873 kPointerSize); | 2873 kPointerSize); |
| 2874 | 2874 |
| 2875 __ bind(&is_not_instance); | 2875 __ bind(&is_not_instance); |
| 2876 if (!HasCallSiteInlineCheck()) { | 2876 if (!HasCallSiteInlineCheck()) { |
| 2877 // We have to store a non-zero value in the cache. | 2877 // We have to store a non-zero value in the cache. |
| 2878 __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex); | 2878 __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex); |
| 2879 if (ReturnTrueFalseObject()) { | 2879 if (ReturnTrueFalseObject()) { |
| 2880 __ LoadRoot(rax, Heap::kFalseValueRootIndex); | 2880 __ LoadRoot(rax, Heap::kFalseValueRootIndex); |
| 2881 } | 2881 } |
| 2882 } else { | 2882 } else { |
| 2883 // Store offset of false in the root array at the inline check site. | 2883 // Store offset of false in the root array at the inline check site. |
| 2884 int false_offset = 0x100 + | 2884 int false_offset = 0x100 + |
| 2885 (Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; | 2885 (Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; |
| 2886 // Assert it is a 1-byte signed value. | 2886 // Assert it is a 1-byte signed value. |
| 2887 ASSERT(false_offset >= 0 && false_offset < 0x100); | 2887 DCHECK(false_offset >= 0 && false_offset < 0x100); |
| 2888 __ movl(rax, Immediate(false_offset)); | 2888 __ movl(rax, Immediate(false_offset)); |
| 2889 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); | 2889 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); |
| 2890 __ subp(kScratchRegister, args.GetArgumentOperand(2)); | 2890 __ subp(kScratchRegister, args.GetArgumentOperand(2)); |
| 2891 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); | 2891 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); |
| 2892 if (FLAG_debug_code) { | 2892 if (FLAG_debug_code) { |
| 2893 __ movl(rax, Immediate(kWordBeforeResultValue)); | 2893 __ movl(rax, Immediate(kWordBeforeResultValue)); |
| 2894 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); | 2894 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); |
| 2895 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); | 2895 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); |
| 2896 } | 2896 } |
| 2897 } | 2897 } |
| 2898 __ ret(((HasArgsInRegisters() ? 0 : 2) + extra_argument_offset) * | 2898 __ ret(((HasArgsInRegisters() ? 0 : 2) + extra_argument_offset) * |
| 2899 kPointerSize); | 2899 kPointerSize); |
| 2900 | 2900 |
| 2901 // Slow-case: Go through the JavaScript implementation. | 2901 // Slow-case: Go through the JavaScript implementation. |
| 2902 __ bind(&slow); | 2902 __ bind(&slow); |
| 2903 if (!ReturnTrueFalseObject()) { | 2903 if (!ReturnTrueFalseObject()) { |
| 2904 // Tail call the builtin which returns 0 or 1. | 2904 // Tail call the builtin which returns 0 or 1. |
| 2905 ASSERT(!HasArgsInRegisters()); | 2905 DCHECK(!HasArgsInRegisters()); |
| 2906 if (HasCallSiteInlineCheck()) { | 2906 if (HasCallSiteInlineCheck()) { |
| 2907 // Remove extra value from the stack. | 2907 // Remove extra value from the stack. |
| 2908 __ PopReturnAddressTo(rcx); | 2908 __ PopReturnAddressTo(rcx); |
| 2909 __ Pop(rax); | 2909 __ Pop(rax); |
| 2910 __ PushReturnAddressFrom(rcx); | 2910 __ PushReturnAddressFrom(rcx); |
| 2911 } | 2911 } |
| 2912 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 2912 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 2913 } else { | 2913 } else { |
| 2914 // Call the builtin and convert 0/1 to true/false. | 2914 // Call the builtin and convert 0/1 to true/false. |
| 2915 { | 2915 { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2988 __ CheckMap(index_, | 2988 __ CheckMap(index_, |
| 2989 factory->heap_number_map(), | 2989 factory->heap_number_map(), |
| 2990 index_not_number_, | 2990 index_not_number_, |
| 2991 DONT_DO_SMI_CHECK); | 2991 DONT_DO_SMI_CHECK); |
| 2992 call_helper.BeforeCall(masm); | 2992 call_helper.BeforeCall(masm); |
| 2993 __ Push(object_); | 2993 __ Push(object_); |
| 2994 __ Push(index_); // Consumed by runtime conversion function. | 2994 __ Push(index_); // Consumed by runtime conversion function. |
| 2995 if (index_flags_ == STRING_INDEX_IS_NUMBER) { | 2995 if (index_flags_ == STRING_INDEX_IS_NUMBER) { |
| 2996 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); | 2996 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); |
| 2997 } else { | 2997 } else { |
| 2998 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); | 2998 DCHECK(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); |
| 2999 // NumberToSmi discards numbers that are not exact integers. | 2999 // NumberToSmi discards numbers that are not exact integers. |
| 3000 __ CallRuntime(Runtime::kNumberToSmi, 1); | 3000 __ CallRuntime(Runtime::kNumberToSmi, 1); |
| 3001 } | 3001 } |
| 3002 if (!index_.is(rax)) { | 3002 if (!index_.is(rax)) { |
| 3003 // Save the conversion result before the pop instructions below | 3003 // Save the conversion result before the pop instructions below |
| 3004 // have a chance to overwrite it. | 3004 // have a chance to overwrite it. |
| 3005 __ movp(index_, rax); | 3005 __ movp(index_, rax); |
| 3006 } | 3006 } |
| 3007 __ Pop(object_); | 3007 __ Pop(object_); |
| 3008 // Reload the instance type. | 3008 // Reload the instance type. |
| (...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3589 } | 3589 } |
| 3590 | 3590 |
| 3591 // Tail call into the stub that handles binary operations with allocation | 3591 // Tail call into the stub that handles binary operations with allocation |
| 3592 // sites. | 3592 // sites. |
| 3593 BinaryOpWithAllocationSiteStub stub(isolate(), state_); | 3593 BinaryOpWithAllocationSiteStub stub(isolate(), state_); |
| 3594 __ TailCallStub(&stub); | 3594 __ TailCallStub(&stub); |
| 3595 } | 3595 } |
| 3596 | 3596 |
| 3597 | 3597 |
| 3598 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 3598 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { |
| 3599 ASSERT(state_ == CompareIC::SMI); | 3599 DCHECK(state_ == CompareIC::SMI); |
| 3600 Label miss; | 3600 Label miss; |
| 3601 __ JumpIfNotBothSmi(rdx, rax, &miss, Label::kNear); | 3601 __ JumpIfNotBothSmi(rdx, rax, &miss, Label::kNear); |
| 3602 | 3602 |
| 3603 if (GetCondition() == equal) { | 3603 if (GetCondition() == equal) { |
| 3604 // For equality we do not care about the sign of the result. | 3604 // For equality we do not care about the sign of the result. |
| 3605 __ subp(rax, rdx); | 3605 __ subp(rax, rdx); |
| 3606 } else { | 3606 } else { |
| 3607 Label done; | 3607 Label done; |
| 3608 __ subp(rdx, rax); | 3608 __ subp(rdx, rax); |
| 3609 __ j(no_overflow, &done, Label::kNear); | 3609 __ j(no_overflow, &done, Label::kNear); |
| 3610 // Correct sign of result in case of overflow. | 3610 // Correct sign of result in case of overflow. |
| 3611 __ notp(rdx); | 3611 __ notp(rdx); |
| 3612 __ bind(&done); | 3612 __ bind(&done); |
| 3613 __ movp(rax, rdx); | 3613 __ movp(rax, rdx); |
| 3614 } | 3614 } |
| 3615 __ ret(0); | 3615 __ ret(0); |
| 3616 | 3616 |
| 3617 __ bind(&miss); | 3617 __ bind(&miss); |
| 3618 GenerateMiss(masm); | 3618 GenerateMiss(masm); |
| 3619 } | 3619 } |
| 3620 | 3620 |
| 3621 | 3621 |
| 3622 void ICCompareStub::GenerateNumbers(MacroAssembler* masm) { | 3622 void ICCompareStub::GenerateNumbers(MacroAssembler* masm) { |
| 3623 ASSERT(state_ == CompareIC::NUMBER); | 3623 DCHECK(state_ == CompareIC::NUMBER); |
| 3624 | 3624 |
| 3625 Label generic_stub; | 3625 Label generic_stub; |
| 3626 Label unordered, maybe_undefined1, maybe_undefined2; | 3626 Label unordered, maybe_undefined1, maybe_undefined2; |
| 3627 Label miss; | 3627 Label miss; |
| 3628 | 3628 |
| 3629 if (left_ == CompareIC::SMI) { | 3629 if (left_ == CompareIC::SMI) { |
| 3630 __ JumpIfNotSmi(rdx, &miss); | 3630 __ JumpIfNotSmi(rdx, &miss); |
| 3631 } | 3631 } |
| 3632 if (right_ == CompareIC::SMI) { | 3632 if (right_ == CompareIC::SMI) { |
| 3633 __ JumpIfNotSmi(rax, &miss); | 3633 __ JumpIfNotSmi(rax, &miss); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3690 __ Cmp(rdx, isolate()->factory()->undefined_value()); | 3690 __ Cmp(rdx, isolate()->factory()->undefined_value()); |
| 3691 __ j(equal, &unordered); | 3691 __ j(equal, &unordered); |
| 3692 } | 3692 } |
| 3693 | 3693 |
| 3694 __ bind(&miss); | 3694 __ bind(&miss); |
| 3695 GenerateMiss(masm); | 3695 GenerateMiss(masm); |
| 3696 } | 3696 } |
| 3697 | 3697 |
| 3698 | 3698 |
| 3699 void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) { | 3699 void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) { |
| 3700 ASSERT(state_ == CompareIC::INTERNALIZED_STRING); | 3700 DCHECK(state_ == CompareIC::INTERNALIZED_STRING); |
| 3701 ASSERT(GetCondition() == equal); | 3701 DCHECK(GetCondition() == equal); |
| 3702 | 3702 |
| 3703 // Registers containing left and right operands respectively. | 3703 // Registers containing left and right operands respectively. |
| 3704 Register left = rdx; | 3704 Register left = rdx; |
| 3705 Register right = rax; | 3705 Register right = rax; |
| 3706 Register tmp1 = rcx; | 3706 Register tmp1 = rcx; |
| 3707 Register tmp2 = rbx; | 3707 Register tmp2 = rbx; |
| 3708 | 3708 |
| 3709 // Check that both operands are heap objects. | 3709 // Check that both operands are heap objects. |
| 3710 Label miss; | 3710 Label miss; |
| 3711 Condition cond = masm->CheckEitherSmi(left, right, tmp1); | 3711 Condition cond = masm->CheckEitherSmi(left, right, tmp1); |
| 3712 __ j(cond, &miss, Label::kNear); | 3712 __ j(cond, &miss, Label::kNear); |
| 3713 | 3713 |
| 3714 // Check that both operands are internalized strings. | 3714 // Check that both operands are internalized strings. |
| 3715 __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 3715 __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 3716 __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 3716 __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 3717 __ movzxbp(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 3717 __ movzxbp(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 3718 __ movzxbp(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 3718 __ movzxbp(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 3719 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); | 3719 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
| 3720 __ orp(tmp1, tmp2); | 3720 __ orp(tmp1, tmp2); |
| 3721 __ testb(tmp1, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); | 3721 __ testb(tmp1, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); |
| 3722 __ j(not_zero, &miss, Label::kNear); | 3722 __ j(not_zero, &miss, Label::kNear); |
| 3723 | 3723 |
| 3724 // Internalized strings are compared by identity. | 3724 // Internalized strings are compared by identity. |
| 3725 Label done; | 3725 Label done; |
| 3726 __ cmpp(left, right); | 3726 __ cmpp(left, right); |
| 3727 // Make sure rax is non-zero. At this point input operands are | 3727 // Make sure rax is non-zero. At this point input operands are |
| 3728 // guaranteed to be non-zero. | 3728 // guaranteed to be non-zero. |
| 3729 ASSERT(right.is(rax)); | 3729 DCHECK(right.is(rax)); |
| 3730 __ j(not_equal, &done, Label::kNear); | 3730 __ j(not_equal, &done, Label::kNear); |
| 3731 STATIC_ASSERT(EQUAL == 0); | 3731 STATIC_ASSERT(EQUAL == 0); |
| 3732 STATIC_ASSERT(kSmiTag == 0); | 3732 STATIC_ASSERT(kSmiTag == 0); |
| 3733 __ Move(rax, Smi::FromInt(EQUAL)); | 3733 __ Move(rax, Smi::FromInt(EQUAL)); |
| 3734 __ bind(&done); | 3734 __ bind(&done); |
| 3735 __ ret(0); | 3735 __ ret(0); |
| 3736 | 3736 |
| 3737 __ bind(&miss); | 3737 __ bind(&miss); |
| 3738 GenerateMiss(masm); | 3738 GenerateMiss(masm); |
| 3739 } | 3739 } |
| 3740 | 3740 |
| 3741 | 3741 |
| 3742 void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) { | 3742 void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) { |
| 3743 ASSERT(state_ == CompareIC::UNIQUE_NAME); | 3743 DCHECK(state_ == CompareIC::UNIQUE_NAME); |
| 3744 ASSERT(GetCondition() == equal); | 3744 DCHECK(GetCondition() == equal); |
| 3745 | 3745 |
| 3746 // Registers containing left and right operands respectively. | 3746 // Registers containing left and right operands respectively. |
| 3747 Register left = rdx; | 3747 Register left = rdx; |
| 3748 Register right = rax; | 3748 Register right = rax; |
| 3749 Register tmp1 = rcx; | 3749 Register tmp1 = rcx; |
| 3750 Register tmp2 = rbx; | 3750 Register tmp2 = rbx; |
| 3751 | 3751 |
| 3752 // Check that both operands are heap objects. | 3752 // Check that both operands are heap objects. |
| 3753 Label miss; | 3753 Label miss; |
| 3754 Condition cond = masm->CheckEitherSmi(left, right, tmp1); | 3754 Condition cond = masm->CheckEitherSmi(left, right, tmp1); |
| 3755 __ j(cond, &miss, Label::kNear); | 3755 __ j(cond, &miss, Label::kNear); |
| 3756 | 3756 |
| 3757 // Check that both operands are unique names. This leaves the instance | 3757 // Check that both operands are unique names. This leaves the instance |
| 3758 // types loaded in tmp1 and tmp2. | 3758 // types loaded in tmp1 and tmp2. |
| 3759 __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 3759 __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 3760 __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 3760 __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 3761 __ movzxbp(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 3761 __ movzxbp(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 3762 __ movzxbp(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 3762 __ movzxbp(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 3763 | 3763 |
| 3764 __ JumpIfNotUniqueName(tmp1, &miss, Label::kNear); | 3764 __ JumpIfNotUniqueName(tmp1, &miss, Label::kNear); |
| 3765 __ JumpIfNotUniqueName(tmp2, &miss, Label::kNear); | 3765 __ JumpIfNotUniqueName(tmp2, &miss, Label::kNear); |
| 3766 | 3766 |
| 3767 // Unique names are compared by identity. | 3767 // Unique names are compared by identity. |
| 3768 Label done; | 3768 Label done; |
| 3769 __ cmpp(left, right); | 3769 __ cmpp(left, right); |
| 3770 // Make sure rax is non-zero. At this point input operands are | 3770 // Make sure rax is non-zero. At this point input operands are |
| 3771 // guaranteed to be non-zero. | 3771 // guaranteed to be non-zero. |
| 3772 ASSERT(right.is(rax)); | 3772 DCHECK(right.is(rax)); |
| 3773 __ j(not_equal, &done, Label::kNear); | 3773 __ j(not_equal, &done, Label::kNear); |
| 3774 STATIC_ASSERT(EQUAL == 0); | 3774 STATIC_ASSERT(EQUAL == 0); |
| 3775 STATIC_ASSERT(kSmiTag == 0); | 3775 STATIC_ASSERT(kSmiTag == 0); |
| 3776 __ Move(rax, Smi::FromInt(EQUAL)); | 3776 __ Move(rax, Smi::FromInt(EQUAL)); |
| 3777 __ bind(&done); | 3777 __ bind(&done); |
| 3778 __ ret(0); | 3778 __ ret(0); |
| 3779 | 3779 |
| 3780 __ bind(&miss); | 3780 __ bind(&miss); |
| 3781 GenerateMiss(masm); | 3781 GenerateMiss(masm); |
| 3782 } | 3782 } |
| 3783 | 3783 |
| 3784 | 3784 |
| 3785 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { | 3785 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { |
| 3786 ASSERT(state_ == CompareIC::STRING); | 3786 DCHECK(state_ == CompareIC::STRING); |
| 3787 Label miss; | 3787 Label miss; |
| 3788 | 3788 |
| 3789 bool equality = Token::IsEqualityOp(op_); | 3789 bool equality = Token::IsEqualityOp(op_); |
| 3790 | 3790 |
| 3791 // Registers containing left and right operands respectively. | 3791 // Registers containing left and right operands respectively. |
| 3792 Register left = rdx; | 3792 Register left = rdx; |
| 3793 Register right = rax; | 3793 Register right = rax; |
| 3794 Register tmp1 = rcx; | 3794 Register tmp1 = rcx; |
| 3795 Register tmp2 = rbx; | 3795 Register tmp2 = rbx; |
| 3796 Register tmp3 = rdi; | 3796 Register tmp3 = rdi; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 3827 // because we already know they are not identical. We also know they are both | 3827 // because we already know they are not identical. We also know they are both |
| 3828 // strings. | 3828 // strings. |
| 3829 if (equality) { | 3829 if (equality) { |
| 3830 Label do_compare; | 3830 Label do_compare; |
| 3831 STATIC_ASSERT(kInternalizedTag == 0); | 3831 STATIC_ASSERT(kInternalizedTag == 0); |
| 3832 __ orp(tmp1, tmp2); | 3832 __ orp(tmp1, tmp2); |
| 3833 __ testb(tmp1, Immediate(kIsNotInternalizedMask)); | 3833 __ testb(tmp1, Immediate(kIsNotInternalizedMask)); |
| 3834 __ j(not_zero, &do_compare, Label::kNear); | 3834 __ j(not_zero, &do_compare, Label::kNear); |
| 3835 // Make sure rax is non-zero. At this point input operands are | 3835 // Make sure rax is non-zero. At this point input operands are |
| 3836 // guaranteed to be non-zero. | 3836 // guaranteed to be non-zero. |
| 3837 ASSERT(right.is(rax)); | 3837 DCHECK(right.is(rax)); |
| 3838 __ ret(0); | 3838 __ ret(0); |
| 3839 __ bind(&do_compare); | 3839 __ bind(&do_compare); |
| 3840 } | 3840 } |
| 3841 | 3841 |
| 3842 // Check that both strings are sequential ASCII. | 3842 // Check that both strings are sequential ASCII. |
| 3843 Label runtime; | 3843 Label runtime; |
| 3844 __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime); | 3844 __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime); |
| 3845 | 3845 |
| 3846 // Compare flat ASCII strings. Returns when done. | 3846 // Compare flat ASCII strings. Returns when done. |
| 3847 if (equality) { | 3847 if (equality) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3863 } else { | 3863 } else { |
| 3864 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 3864 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 3865 } | 3865 } |
| 3866 | 3866 |
| 3867 __ bind(&miss); | 3867 __ bind(&miss); |
| 3868 GenerateMiss(masm); | 3868 GenerateMiss(masm); |
| 3869 } | 3869 } |
| 3870 | 3870 |
| 3871 | 3871 |
| 3872 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { | 3872 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { |
| 3873 ASSERT(state_ == CompareIC::OBJECT); | 3873 DCHECK(state_ == CompareIC::OBJECT); |
| 3874 Label miss; | 3874 Label miss; |
| 3875 Condition either_smi = masm->CheckEitherSmi(rdx, rax); | 3875 Condition either_smi = masm->CheckEitherSmi(rdx, rax); |
| 3876 __ j(either_smi, &miss, Label::kNear); | 3876 __ j(either_smi, &miss, Label::kNear); |
| 3877 | 3877 |
| 3878 __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx); | 3878 __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx); |
| 3879 __ j(not_equal, &miss, Label::kNear); | 3879 __ j(not_equal, &miss, Label::kNear); |
| 3880 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); | 3880 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); |
| 3881 __ j(not_equal, &miss, Label::kNear); | 3881 __ j(not_equal, &miss, Label::kNear); |
| 3882 | 3882 |
| 3883 ASSERT(GetCondition() == equal); | 3883 DCHECK(GetCondition() == equal); |
| 3884 __ subp(rax, rdx); | 3884 __ subp(rax, rdx); |
| 3885 __ ret(0); | 3885 __ ret(0); |
| 3886 | 3886 |
| 3887 __ bind(&miss); | 3887 __ bind(&miss); |
| 3888 GenerateMiss(masm); | 3888 GenerateMiss(masm); |
| 3889 } | 3889 } |
| 3890 | 3890 |
| 3891 | 3891 |
| 3892 void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) { | 3892 void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) { |
| 3893 Label miss; | 3893 Label miss; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3933 __ jmp(rdi); | 3933 __ jmp(rdi); |
| 3934 } | 3934 } |
| 3935 | 3935 |
| 3936 | 3936 |
| 3937 void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, | 3937 void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, |
| 3938 Label* miss, | 3938 Label* miss, |
| 3939 Label* done, | 3939 Label* done, |
| 3940 Register properties, | 3940 Register properties, |
| 3941 Handle<Name> name, | 3941 Handle<Name> name, |
| 3942 Register r0) { | 3942 Register r0) { |
| 3943 ASSERT(name->IsUniqueName()); | 3943 DCHECK(name->IsUniqueName()); |
| 3944 // If names of slots in range from 1 to kProbes - 1 for the hash value are | 3944 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 3945 // not equal to the name and kProbes-th slot is not used (its name is the | 3945 // not equal to the name and kProbes-th slot is not used (its name is the |
| 3946 // undefined value), it guarantees the hash table doesn't contain the | 3946 // undefined value), it guarantees the hash table doesn't contain the |
| 3947 // property. It's true even if some slots represent deleted properties | 3947 // property. It's true even if some slots represent deleted properties |
| 3948 // (their names are the hole value). | 3948 // (their names are the hole value). |
| 3949 for (int i = 0; i < kInlinedProbes; i++) { | 3949 for (int i = 0; i < kInlinedProbes; i++) { |
| 3950 // r0 points to properties hash. | 3950 // r0 points to properties hash. |
| 3951 // Compute the masked index: (hash + i + i * i) & mask. | 3951 // Compute the masked index: (hash + i + i * i) & mask. |
| 3952 Register index = r0; | 3952 Register index = r0; |
| 3953 // Capacity is smi 2^n. | 3953 // Capacity is smi 2^n. |
| 3954 __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset)); | 3954 __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset)); |
| 3955 __ decl(index); | 3955 __ decl(index); |
| 3956 __ andp(index, | 3956 __ andp(index, |
| 3957 Immediate(name->Hash() + NameDictionary::GetProbeOffset(i))); | 3957 Immediate(name->Hash() + NameDictionary::GetProbeOffset(i))); |
| 3958 | 3958 |
| 3959 // Scale the index by multiplying by the entry size. | 3959 // Scale the index by multiplying by the entry size. |
| 3960 ASSERT(NameDictionary::kEntrySize == 3); | 3960 DCHECK(NameDictionary::kEntrySize == 3); |
| 3961 __ leap(index, Operand(index, index, times_2, 0)); // index *= 3. | 3961 __ leap(index, Operand(index, index, times_2, 0)); // index *= 3. |
| 3962 | 3962 |
| 3963 Register entity_name = r0; | 3963 Register entity_name = r0; |
| 3964 // Having undefined at this place means the name is not contained. | 3964 // Having undefined at this place means the name is not contained. |
| 3965 ASSERT_EQ(kSmiTagSize, 1); | 3965 DCHECK_EQ(kSmiTagSize, 1); |
| 3966 __ movp(entity_name, Operand(properties, | 3966 __ movp(entity_name, Operand(properties, |
| 3967 index, | 3967 index, |
| 3968 times_pointer_size, | 3968 times_pointer_size, |
| 3969 kElementsStartOffset - kHeapObjectTag)); | 3969 kElementsStartOffset - kHeapObjectTag)); |
| 3970 __ Cmp(entity_name, masm->isolate()->factory()->undefined_value()); | 3970 __ Cmp(entity_name, masm->isolate()->factory()->undefined_value()); |
| 3971 __ j(equal, done); | 3971 __ j(equal, done); |
| 3972 | 3972 |
| 3973 // Stop if found the property. | 3973 // Stop if found the property. |
| 3974 __ Cmp(entity_name, Handle<Name>(name)); | 3974 __ Cmp(entity_name, Handle<Name>(name)); |
| 3975 __ j(equal, miss); | 3975 __ j(equal, miss); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 4001 // |done| label if a property with the given name is found leaving the | 4001 // |done| label if a property with the given name is found leaving the |
| 4002 // index into the dictionary in |r1|. Jump to the |miss| label | 4002 // index into the dictionary in |r1|. Jump to the |miss| label |
| 4003 // otherwise. | 4003 // otherwise. |
| 4004 void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, | 4004 void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, |
| 4005 Label* miss, | 4005 Label* miss, |
| 4006 Label* done, | 4006 Label* done, |
| 4007 Register elements, | 4007 Register elements, |
| 4008 Register name, | 4008 Register name, |
| 4009 Register r0, | 4009 Register r0, |
| 4010 Register r1) { | 4010 Register r1) { |
| 4011 ASSERT(!elements.is(r0)); | 4011 DCHECK(!elements.is(r0)); |
| 4012 ASSERT(!elements.is(r1)); | 4012 DCHECK(!elements.is(r1)); |
| 4013 ASSERT(!name.is(r0)); | 4013 DCHECK(!name.is(r0)); |
| 4014 ASSERT(!name.is(r1)); | 4014 DCHECK(!name.is(r1)); |
| 4015 | 4015 |
| 4016 __ AssertName(name); | 4016 __ AssertName(name); |
| 4017 | 4017 |
| 4018 __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset)); | 4018 __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset)); |
| 4019 __ decl(r0); | 4019 __ decl(r0); |
| 4020 | 4020 |
| 4021 for (int i = 0; i < kInlinedProbes; i++) { | 4021 for (int i = 0; i < kInlinedProbes; i++) { |
| 4022 // Compute the masked index: (hash + i + i * i) & mask. | 4022 // Compute the masked index: (hash + i + i * i) & mask. |
| 4023 __ movl(r1, FieldOperand(name, Name::kHashFieldOffset)); | 4023 __ movl(r1, FieldOperand(name, Name::kHashFieldOffset)); |
| 4024 __ shrl(r1, Immediate(Name::kHashShift)); | 4024 __ shrl(r1, Immediate(Name::kHashShift)); |
| 4025 if (i > 0) { | 4025 if (i > 0) { |
| 4026 __ addl(r1, Immediate(NameDictionary::GetProbeOffset(i))); | 4026 __ addl(r1, Immediate(NameDictionary::GetProbeOffset(i))); |
| 4027 } | 4027 } |
| 4028 __ andp(r1, r0); | 4028 __ andp(r1, r0); |
| 4029 | 4029 |
| 4030 // Scale the index by multiplying by the entry size. | 4030 // Scale the index by multiplying by the entry size. |
| 4031 ASSERT(NameDictionary::kEntrySize == 3); | 4031 DCHECK(NameDictionary::kEntrySize == 3); |
| 4032 __ leap(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 | 4032 __ leap(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 |
| 4033 | 4033 |
| 4034 // Check if the key is identical to the name. | 4034 // Check if the key is identical to the name. |
| 4035 __ cmpp(name, Operand(elements, r1, times_pointer_size, | 4035 __ cmpp(name, Operand(elements, r1, times_pointer_size, |
| 4036 kElementsStartOffset - kHeapObjectTag)); | 4036 kElementsStartOffset - kHeapObjectTag)); |
| 4037 __ j(equal, done); | 4037 __ j(equal, done); |
| 4038 } | 4038 } |
| 4039 | 4039 |
| 4040 NameDictionaryLookupStub stub(masm->isolate(), elements, r0, r1, | 4040 NameDictionaryLookupStub stub(masm->isolate(), elements, r0, r1, |
| 4041 POSITIVE_LOOKUP); | 4041 POSITIVE_LOOKUP); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4083 kPointerSize); | 4083 kPointerSize); |
| 4084 for (int i = kInlinedProbes; i < kTotalProbes; i++) { | 4084 for (int i = kInlinedProbes; i < kTotalProbes; i++) { |
| 4085 // Compute the masked index: (hash + i + i * i) & mask. | 4085 // Compute the masked index: (hash + i + i * i) & mask. |
| 4086 __ movp(scratch, args.GetArgumentOperand(1)); | 4086 __ movp(scratch, args.GetArgumentOperand(1)); |
| 4087 if (i > 0) { | 4087 if (i > 0) { |
| 4088 __ addl(scratch, Immediate(NameDictionary::GetProbeOffset(i))); | 4088 __ addl(scratch, Immediate(NameDictionary::GetProbeOffset(i))); |
| 4089 } | 4089 } |
| 4090 __ andp(scratch, Operand(rsp, 0)); | 4090 __ andp(scratch, Operand(rsp, 0)); |
| 4091 | 4091 |
| 4092 // Scale the index by multiplying by the entry size. | 4092 // Scale the index by multiplying by the entry size. |
| 4093 ASSERT(NameDictionary::kEntrySize == 3); | 4093 DCHECK(NameDictionary::kEntrySize == 3); |
| 4094 __ leap(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. | 4094 __ leap(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. |
| 4095 | 4095 |
| 4096 // Having undefined at this place means the name is not contained. | 4096 // Having undefined at this place means the name is not contained. |
| 4097 __ movp(scratch, Operand(dictionary_, | 4097 __ movp(scratch, Operand(dictionary_, |
| 4098 index_, | 4098 index_, |
| 4099 times_pointer_size, | 4099 times_pointer_size, |
| 4100 kElementsStartOffset - kHeapObjectTag)); | 4100 kElementsStartOffset - kHeapObjectTag)); |
| 4101 | 4101 |
| 4102 __ Cmp(scratch, isolate()->factory()->undefined_value()); | 4102 __ Cmp(scratch, isolate()->factory()->undefined_value()); |
| 4103 __ j(equal, ¬_in_dictionary); | 4103 __ j(equal, ¬_in_dictionary); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4225 InformIncrementalMarker(masm); | 4225 InformIncrementalMarker(masm); |
| 4226 regs_.Restore(masm); | 4226 regs_.Restore(masm); |
| 4227 __ ret(0); | 4227 __ ret(0); |
| 4228 } | 4228 } |
| 4229 | 4229 |
| 4230 | 4230 |
| 4231 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) { | 4231 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) { |
| 4232 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_); | 4232 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_); |
| 4233 Register address = | 4233 Register address = |
| 4234 arg_reg_1.is(regs_.address()) ? kScratchRegister : regs_.address(); | 4234 arg_reg_1.is(regs_.address()) ? kScratchRegister : regs_.address(); |
| 4235 ASSERT(!address.is(regs_.object())); | 4235 DCHECK(!address.is(regs_.object())); |
| 4236 ASSERT(!address.is(arg_reg_1)); | 4236 DCHECK(!address.is(arg_reg_1)); |
| 4237 __ Move(address, regs_.address()); | 4237 __ Move(address, regs_.address()); |
| 4238 __ Move(arg_reg_1, regs_.object()); | 4238 __ Move(arg_reg_1, regs_.object()); |
| 4239 // TODO(gc) Can we just set address arg2 in the beginning? | 4239 // TODO(gc) Can we just set address arg2 in the beginning? |
| 4240 __ Move(arg_reg_2, address); | 4240 __ Move(arg_reg_2, address); |
| 4241 __ LoadAddress(arg_reg_3, | 4241 __ LoadAddress(arg_reg_3, |
| 4242 ExternalReference::isolate_address(isolate())); | 4242 ExternalReference::isolate_address(isolate())); |
| 4243 int argument_count = 3; | 4243 int argument_count = 3; |
| 4244 | 4244 |
| 4245 AllowExternalCallThatCantCauseGC scope(masm); | 4245 AllowExternalCallThatCantCauseGC scope(masm); |
| 4246 __ PrepareCallCFunction(argument_count); | 4246 __ PrepareCallCFunction(argument_count); |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4517 // rax - number of arguments | 4517 // rax - number of arguments |
| 4518 // rdi - constructor? | 4518 // rdi - constructor? |
| 4519 // rsp[0] - return address | 4519 // rsp[0] - return address |
| 4520 // rsp[8] - last argument | 4520 // rsp[8] - last argument |
| 4521 Handle<Object> undefined_sentinel( | 4521 Handle<Object> undefined_sentinel( |
| 4522 masm->isolate()->heap()->undefined_value(), | 4522 masm->isolate()->heap()->undefined_value(), |
| 4523 masm->isolate()); | 4523 masm->isolate()); |
| 4524 | 4524 |
| 4525 Label normal_sequence; | 4525 Label normal_sequence; |
| 4526 if (mode == DONT_OVERRIDE) { | 4526 if (mode == DONT_OVERRIDE) { |
| 4527 ASSERT(FAST_SMI_ELEMENTS == 0); | 4527 DCHECK(FAST_SMI_ELEMENTS == 0); |
| 4528 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); | 4528 DCHECK(FAST_HOLEY_SMI_ELEMENTS == 1); |
| 4529 ASSERT(FAST_ELEMENTS == 2); | 4529 DCHECK(FAST_ELEMENTS == 2); |
| 4530 ASSERT(FAST_HOLEY_ELEMENTS == 3); | 4530 DCHECK(FAST_HOLEY_ELEMENTS == 3); |
| 4531 ASSERT(FAST_DOUBLE_ELEMENTS == 4); | 4531 DCHECK(FAST_DOUBLE_ELEMENTS == 4); |
| 4532 ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5); | 4532 DCHECK(FAST_HOLEY_DOUBLE_ELEMENTS == 5); |
| 4533 | 4533 |
| 4534 // is the low bit set? If so, we are holey and that is good. | 4534 // is the low bit set? If so, we are holey and that is good. |
| 4535 __ testb(rdx, Immediate(1)); | 4535 __ testb(rdx, Immediate(1)); |
| 4536 __ j(not_zero, &normal_sequence); | 4536 __ j(not_zero, &normal_sequence); |
| 4537 } | 4537 } |
| 4538 | 4538 |
| 4539 // look at the first argument | 4539 // look at the first argument |
| 4540 StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 4540 StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 4541 __ movp(rcx, args.GetArgumentOperand(0)); | 4541 __ movp(rcx, args.GetArgumentOperand(0)); |
| 4542 __ testp(rcx, rcx); | 4542 __ testp(rcx, rcx); |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4881 #if defined(__MINGW64__) || defined(_WIN64) | 4881 #if defined(__MINGW64__) || defined(_WIN64) |
| 4882 Register arguments_arg = rcx; | 4882 Register arguments_arg = rcx; |
| 4883 Register callback_arg = rdx; | 4883 Register callback_arg = rdx; |
| 4884 #else | 4884 #else |
| 4885 Register arguments_arg = rdi; | 4885 Register arguments_arg = rdi; |
| 4886 Register callback_arg = rsi; | 4886 Register callback_arg = rsi; |
| 4887 #endif | 4887 #endif |
| 4888 | 4888 |
| 4889 // It's okay if api_function_address == callback_arg | 4889 // It's okay if api_function_address == callback_arg |
| 4890 // but not arguments_arg | 4890 // but not arguments_arg |
| 4891 ASSERT(!api_function_address.is(arguments_arg)); | 4891 DCHECK(!api_function_address.is(arguments_arg)); |
| 4892 | 4892 |
| 4893 // v8::InvocationCallback's argument. | 4893 // v8::InvocationCallback's argument. |
| 4894 __ leap(arguments_arg, StackSpaceOperand(0)); | 4894 __ leap(arguments_arg, StackSpaceOperand(0)); |
| 4895 | 4895 |
| 4896 ExternalReference thunk_ref = | 4896 ExternalReference thunk_ref = |
| 4897 ExternalReference::invoke_function_callback(isolate()); | 4897 ExternalReference::invoke_function_callback(isolate()); |
| 4898 | 4898 |
| 4899 // Accessor for FunctionCallbackInfo and first js arg. | 4899 // Accessor for FunctionCallbackInfo and first js arg. |
| 4900 StackArgumentsAccessor args_from_rbp(rbp, FCA::kArgsLength + 1, | 4900 StackArgumentsAccessor args_from_rbp(rbp, FCA::kArgsLength + 1, |
| 4901 ARGUMENTS_DONT_CONTAIN_RECEIVER); | 4901 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4951 | 4951 |
| 4952 // The context register (rsi) has been saved in PrepareCallApiFunction and | 4952 // The context register (rsi) has been saved in PrepareCallApiFunction and |
| 4953 // could be used to pass arguments. | 4953 // could be used to pass arguments. |
| 4954 __ leap(accessor_info_arg, StackSpaceOperand(0)); | 4954 __ leap(accessor_info_arg, StackSpaceOperand(0)); |
| 4955 | 4955 |
| 4956 ExternalReference thunk_ref = | 4956 ExternalReference thunk_ref = |
| 4957 ExternalReference::invoke_accessor_getter_callback(isolate()); | 4957 ExternalReference::invoke_accessor_getter_callback(isolate()); |
| 4958 | 4958 |
| 4959 // It's okay if api_function_address == getter_arg | 4959 // It's okay if api_function_address == getter_arg |
| 4960 // but not accessor_info_arg or name_arg | 4960 // but not accessor_info_arg or name_arg |
| 4961 ASSERT(!api_function_address.is(accessor_info_arg) && | 4961 DCHECK(!api_function_address.is(accessor_info_arg) && |
| 4962 !api_function_address.is(name_arg)); | 4962 !api_function_address.is(name_arg)); |
| 4963 | 4963 |
| 4964 // The name handler is counted as an argument. | 4964 // The name handler is counted as an argument. |
| 4965 StackArgumentsAccessor args(rbp, PropertyCallbackArguments::kArgsLength); | 4965 StackArgumentsAccessor args(rbp, PropertyCallbackArguments::kArgsLength); |
| 4966 Operand return_value_operand = args.GetArgumentOperand( | 4966 Operand return_value_operand = args.GetArgumentOperand( |
| 4967 PropertyCallbackArguments::kArgsLength - 1 - | 4967 PropertyCallbackArguments::kArgsLength - 1 - |
| 4968 PropertyCallbackArguments::kReturnValueOffset); | 4968 PropertyCallbackArguments::kReturnValueOffset); |
| 4969 __ CallApiFunctionAndReturn(api_function_address, | 4969 __ CallApiFunctionAndReturn(api_function_address, |
| 4970 thunk_ref, | 4970 thunk_ref, |
| 4971 getter_arg, | 4971 getter_arg, |
| 4972 kStackSpace, | 4972 kStackSpace, |
| 4973 return_value_operand, | 4973 return_value_operand, |
| 4974 NULL); | 4974 NULL); |
| 4975 } | 4975 } |
| 4976 | 4976 |
| 4977 | 4977 |
| 4978 #undef __ | 4978 #undef __ |
| 4979 | 4979 |
| 4980 } } // namespace v8::internal | 4980 } } // namespace v8::internal |
| 4981 | 4981 |
| 4982 #endif // V8_TARGET_ARCH_X64 | 4982 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |