OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 <limits.h> // For LONG_MIN, LONG_MAX. | 5 #include <limits.h> // For LONG_MIN, LONG_MAX. |
6 | 6 |
7 #if V8_TARGET_ARCH_MIPS64 | 7 #if V8_TARGET_ARCH_MIPS64 |
8 | 8 |
9 #include "src/base/division-by-constant.h" | 9 #include "src/base/division-by-constant.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 | 95 |
96 void MacroAssembler::StoreRoot(Register source, | 96 void MacroAssembler::StoreRoot(Register source, |
97 Heap::RootListIndex index, | 97 Heap::RootListIndex index, |
98 Condition cond, | 98 Condition cond, |
99 Register src1, const Operand& src2) { | 99 Register src1, const Operand& src2) { |
100 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); | 100 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); |
101 Branch(2, NegateCondition(cond), src1, src2); | 101 Branch(2, NegateCondition(cond), src1, src2); |
102 sd(source, MemOperand(s6, index << kPointerSizeLog2)); | 102 sd(source, MemOperand(s6, index << kPointerSizeLog2)); |
103 } | 103 } |
104 | 104 |
| 105 void MacroAssembler::PushCommonFrame(Register marker_reg) { |
| 106 if (marker_reg.is_valid()) { |
| 107 Push(ra, fp, marker_reg); |
| 108 Daddu(fp, sp, Operand(kPointerSize)); |
| 109 } else { |
| 110 Push(ra, fp); |
| 111 mov(fp, sp); |
| 112 } |
| 113 } |
| 114 |
| 115 void MacroAssembler::PopCommonFrame(Register marker_reg) { |
| 116 if (marker_reg.is_valid()) { |
| 117 Pop(ra, fp, marker_reg); |
| 118 } else { |
| 119 Pop(ra, fp); |
| 120 } |
| 121 } |
| 122 |
| 123 void MacroAssembler::PushStandardFrame(Register function_reg) { |
| 124 int offset = -StandardFrameConstants::kContextOffset; |
| 125 if (function_reg.is_valid()) { |
| 126 Push(ra, fp, cp, function_reg); |
| 127 offset += kPointerSize; |
| 128 } else { |
| 129 Push(ra, fp, cp); |
| 130 } |
| 131 Daddu(fp, sp, Operand(offset)); |
| 132 } |
105 | 133 |
106 // Push and pop all registers that can hold pointers. | 134 // Push and pop all registers that can hold pointers. |
107 void MacroAssembler::PushSafepointRegisters() { | 135 void MacroAssembler::PushSafepointRegisters() { |
108 // Safepoints expect a block of kNumSafepointRegisters values on the | 136 // Safepoints expect a block of kNumSafepointRegisters values on the |
109 // stack, so adjust the stack for unsaved registers. | 137 // stack, so adjust the stack for unsaved registers. |
110 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; | 138 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; |
111 DCHECK(num_unsaved >= 0); | 139 DCHECK(num_unsaved >= 0); |
112 if (num_unsaved > 0) { | 140 if (num_unsaved > 0) { |
113 Dsubu(sp, sp, Operand(num_unsaved * kPointerSize)); | 141 Dsubu(sp, sp, Operand(num_unsaved * kPointerSize)); |
114 } | 142 } |
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 | 510 |
483 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, | 511 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, |
484 Register scratch, | 512 Register scratch, |
485 Label* miss) { | 513 Label* miss) { |
486 Label same_contexts; | 514 Label same_contexts; |
487 | 515 |
488 DCHECK(!holder_reg.is(scratch)); | 516 DCHECK(!holder_reg.is(scratch)); |
489 DCHECK(!holder_reg.is(at)); | 517 DCHECK(!holder_reg.is(at)); |
490 DCHECK(!scratch.is(at)); | 518 DCHECK(!scratch.is(at)); |
491 | 519 |
492 // Load current lexical context from the stack frame. | 520 // Load current lexical context from the active StandardFrame, which |
493 ld(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 521 // my require crawling past STUB frames. |
| 522 Label load_context; |
| 523 Label has_context; |
| 524 mov(at, fp); |
| 525 bind(&load_context); |
| 526 ld(scratch, MemOperand(at, CommonFrameConstants::kContextOrFrameTypeOffset)); |
| 527 JumpIfNotSmi(scratch, &has_context); |
| 528 ld(at, MemOperand(at, CommonFrameConstants::kCallerFPOffset)); |
| 529 b(&load_context); |
| 530 bind(&has_context); |
| 531 |
494 // In debug mode, make sure the lexical context is set. | 532 // In debug mode, make sure the lexical context is set. |
495 #ifdef DEBUG | 533 #ifdef DEBUG |
496 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext, | 534 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext, |
497 scratch, Operand(zero_reg)); | 535 scratch, Operand(zero_reg)); |
498 #endif | 536 #endif |
499 | 537 |
500 // Load the native context of the current context. | 538 // Load the native context of the current context. |
501 ld(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX)); | 539 ld(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX)); |
502 | 540 |
503 // Check the context is a native context. | 541 // Check the context is a native context. |
(...skipping 5055 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5559 if (emit_debug_code()) { | 5597 if (emit_debug_code()) { |
5560 Label ok, fail; | 5598 Label ok, fail; |
5561 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); | 5599 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); |
5562 Branch(&ok); | 5600 Branch(&ok); |
5563 bind(&fail); | 5601 bind(&fail); |
5564 Abort(kGlobalFunctionsMustHaveInitialMap); | 5602 Abort(kGlobalFunctionsMustHaveInitialMap); |
5565 bind(&ok); | 5603 bind(&ok); |
5566 } | 5604 } |
5567 } | 5605 } |
5568 | 5606 |
5569 | 5607 void MacroAssembler::StubPrologue(StackFrame::Type type) { |
5570 void MacroAssembler::StubPrologue() { | 5608 li(at, Operand(Smi::FromInt(type))); |
5571 Push(ra, fp, cp); | 5609 PushCommonFrame(at); |
5572 Push(Smi::FromInt(StackFrame::STUB)); | |
5573 // Adjust FP to point to saved FP. | |
5574 Daddu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); | |
5575 } | 5610 } |
5576 | 5611 |
5577 | 5612 |
5578 void MacroAssembler::Prologue(bool code_pre_aging) { | 5613 void MacroAssembler::Prologue(bool code_pre_aging) { |
5579 PredictableCodeSizeScope predictible_code_size_scope( | 5614 PredictableCodeSizeScope predictible_code_size_scope( |
5580 this, kNoCodeAgeSequenceLength); | 5615 this, kNoCodeAgeSequenceLength); |
5581 // The following three instructions must remain together and unmodified | 5616 // The following three instructions must remain together and unmodified |
5582 // for code aging to work properly. | 5617 // for code aging to work properly. |
5583 if (code_pre_aging) { | 5618 if (code_pre_aging) { |
5584 // Pre-age the code. | 5619 // Pre-age the code. |
5585 Code* stub = Code::GetPreAgedCodeAgeStub(isolate()); | 5620 Code* stub = Code::GetPreAgedCodeAgeStub(isolate()); |
5586 nop(Assembler::CODE_AGE_MARKER_NOP); | 5621 nop(Assembler::CODE_AGE_MARKER_NOP); |
5587 // Load the stub address to t9 and call it, | 5622 // Load the stub address to t9 and call it, |
5588 // GetCodeAgeAndParity() extracts the stub address from this instruction. | 5623 // GetCodeAgeAndParity() extracts the stub address from this instruction. |
5589 li(t9, | 5624 li(t9, |
5590 Operand(reinterpret_cast<uint64_t>(stub->instruction_start())), | 5625 Operand(reinterpret_cast<uint64_t>(stub->instruction_start())), |
5591 ADDRESS_LOAD); | 5626 ADDRESS_LOAD); |
5592 nop(); // Prevent jalr to jal optimization. | 5627 nop(); // Prevent jalr to jal optimization. |
5593 jalr(t9, a0); | 5628 jalr(t9, a0); |
5594 nop(); // Branch delay slot nop. | 5629 nop(); // Branch delay slot nop. |
5595 nop(); // Pad the empty space. | 5630 nop(); // Pad the empty space. |
5596 } else { | 5631 } else { |
5597 Push(ra, fp, cp, a1); | 5632 PushStandardFrame(a1); |
5598 nop(Assembler::CODE_AGE_SEQUENCE_NOP); | 5633 nop(Assembler::CODE_AGE_SEQUENCE_NOP); |
5599 nop(Assembler::CODE_AGE_SEQUENCE_NOP); | 5634 nop(Assembler::CODE_AGE_SEQUENCE_NOP); |
5600 nop(Assembler::CODE_AGE_SEQUENCE_NOP); | 5635 nop(Assembler::CODE_AGE_SEQUENCE_NOP); |
5601 // Adjust fp to point to caller's fp. | |
5602 Daddu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); | |
5603 } | 5636 } |
5604 } | 5637 } |
5605 | 5638 |
5606 | |
5607 void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) { | 5639 void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) { |
5608 ld(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 5640 ld(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
5609 ld(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset)); | 5641 ld(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset)); |
5610 ld(vector, | 5642 ld(vector, |
5611 FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset)); | 5643 FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset)); |
5612 } | 5644 } |
5613 | 5645 |
5614 | 5646 |
5615 void MacroAssembler::EnterFrame(StackFrame::Type type, | 5647 void MacroAssembler::EnterFrame(StackFrame::Type type, |
5616 bool load_constant_pool_pointer_reg) { | 5648 bool load_constant_pool_pointer_reg) { |
5617 // Out-of-line constant pool not implemented on mips64. | 5649 // Out-of-line constant pool not implemented on mips64. |
5618 UNREACHABLE(); | 5650 UNREACHABLE(); |
5619 } | 5651 } |
5620 | 5652 |
5621 | 5653 |
5622 void MacroAssembler::EnterFrame(StackFrame::Type type) { | 5654 void MacroAssembler::EnterFrame(StackFrame::Type type) { |
5623 daddiu(sp, sp, -5 * kPointerSize); | 5655 int stack_offset, fp_offset; |
5624 li(t8, Operand(Smi::FromInt(type))); | 5656 if (type == StackFrame::INTERNAL) { |
5625 li(t9, Operand(CodeObject()), CONSTANT_SIZE); | 5657 stack_offset = -4 * kPointerSize; |
5626 sd(ra, MemOperand(sp, 4 * kPointerSize)); | 5658 fp_offset = 2 * kPointerSize; |
5627 sd(fp, MemOperand(sp, 3 * kPointerSize)); | 5659 } else { |
5628 sd(cp, MemOperand(sp, 2 * kPointerSize)); | 5660 stack_offset = -3 * kPointerSize; |
5629 sd(t8, MemOperand(sp, 1 * kPointerSize)); | 5661 fp_offset = 1 * kPointerSize; |
5630 sd(t9, MemOperand(sp, 0 * kPointerSize)); | 5662 } |
| 5663 daddiu(sp, sp, stack_offset); |
| 5664 stack_offset = -stack_offset - kPointerSize; |
| 5665 sd(ra, MemOperand(sp, stack_offset)); |
| 5666 stack_offset -= kPointerSize; |
| 5667 sd(fp, MemOperand(sp, stack_offset)); |
| 5668 stack_offset -= kPointerSize; |
| 5669 li(t9, Operand(Smi::FromInt(type))); |
| 5670 sd(t9, MemOperand(sp, stack_offset)); |
| 5671 if (type == StackFrame::INTERNAL) { |
| 5672 DCHECK_EQ(stack_offset, kPointerSize); |
| 5673 li(t9, Operand(CodeObject())); |
| 5674 sd(t9, MemOperand(sp, 0)); |
| 5675 } else { |
| 5676 DCHECK_EQ(stack_offset, 0); |
| 5677 } |
5631 // Adjust FP to point to saved FP. | 5678 // Adjust FP to point to saved FP. |
5632 Daddu(fp, sp, | 5679 Daddu(fp, sp, Operand(fp_offset)); |
5633 Operand(StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize)); | |
5634 } | 5680 } |
5635 | 5681 |
5636 | 5682 |
5637 void MacroAssembler::LeaveFrame(StackFrame::Type type) { | 5683 void MacroAssembler::LeaveFrame(StackFrame::Type type) { |
5638 mov(sp, fp); | 5684 daddiu(sp, fp, 2 * kPointerSize); |
5639 ld(fp, MemOperand(sp, 0 * kPointerSize)); | 5685 ld(ra, MemOperand(fp, 1 * kPointerSize)); |
5640 ld(ra, MemOperand(sp, 1 * kPointerSize)); | 5686 ld(fp, MemOperand(fp, 0 * kPointerSize)); |
5641 daddiu(sp, sp, 2 * kPointerSize); | |
5642 } | 5687 } |
5643 | 5688 |
5644 | 5689 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) { |
5645 void MacroAssembler::EnterExitFrame(bool save_doubles, | |
5646 int stack_space) { | |
5647 // Set up the frame structure on the stack. | 5690 // Set up the frame structure on the stack. |
5648 STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement); | 5691 STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement); |
5649 STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset); | 5692 STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset); |
5650 STATIC_ASSERT(0 * kPointerSize == ExitFrameConstants::kCallerFPOffset); | 5693 STATIC_ASSERT(0 * kPointerSize == ExitFrameConstants::kCallerFPOffset); |
5651 | 5694 |
5652 // This is how the stack will look: | 5695 // This is how the stack will look: |
5653 // fp + 2 (==kCallerSPDisplacement) - old stack's end | 5696 // fp + 2 (==kCallerSPDisplacement) - old stack's end |
5654 // [fp + 1 (==kCallerPCOffset)] - saved old ra | 5697 // [fp + 1 (==kCallerPCOffset)] - saved old ra |
5655 // [fp + 0 (==kCallerFPOffset)] - saved old fp | 5698 // [fp + 0 (==kCallerFPOffset)] - saved old fp |
5656 // [fp - 1 (==kSPOffset)] - sp of the called function | 5699 // [fp - 1 StackFrame::EXIT Smi |
5657 // [fp - 2 (==kCodeOffset)] - CodeObject | 5700 // [fp - 2 (==kSPOffset)] - sp of the called function |
| 5701 // [fp - 3 (==kCodeOffset)] - CodeObject |
5658 // fp - (2 + stack_space + alignment) == sp == [fp - kSPOffset] - top of the | 5702 // fp - (2 + stack_space + alignment) == sp == [fp - kSPOffset] - top of the |
5659 // new stack (will contain saved ra) | 5703 // new stack (will contain saved ra) |
5660 | 5704 |
5661 // Save registers. | 5705 // Save registers and reserve room for saved entry sp and code object. |
5662 daddiu(sp, sp, -4 * kPointerSize); | 5706 daddiu(sp, sp, -2 * kPointerSize - ExitFrameConstants::kFixedFrameSizeFromFp); |
5663 sd(ra, MemOperand(sp, 3 * kPointerSize)); | 5707 sd(ra, MemOperand(sp, 4 * kPointerSize)); |
5664 sd(fp, MemOperand(sp, 2 * kPointerSize)); | 5708 sd(fp, MemOperand(sp, 3 * kPointerSize)); |
5665 daddiu(fp, sp, 2 * kPointerSize); // Set up new frame pointer. | 5709 li(at, Operand(Smi::FromInt(StackFrame::EXIT))); |
| 5710 sd(at, MemOperand(sp, 2 * kPointerSize)); |
| 5711 // Set up new frame pointer. |
| 5712 daddiu(fp, sp, ExitFrameConstants::kFixedFrameSizeFromFp); |
5666 | 5713 |
5667 if (emit_debug_code()) { | 5714 if (emit_debug_code()) { |
5668 sd(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset)); | 5715 sd(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset)); |
5669 } | 5716 } |
5670 | 5717 |
5671 // Accessed from ExitFrame::code_slot. | 5718 // Accessed from ExitFrame::code_slot. |
5672 li(t8, Operand(CodeObject()), CONSTANT_SIZE); | 5719 li(t8, Operand(CodeObject()), CONSTANT_SIZE); |
5673 sd(t8, MemOperand(fp, ExitFrameConstants::kCodeOffset)); | 5720 sd(t8, MemOperand(fp, ExitFrameConstants::kCodeOffset)); |
5674 | 5721 |
5675 // Save the frame pointer and the context in top. | 5722 // Save the frame pointer and the context in top. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5708 } | 5755 } |
5709 | 5756 |
5710 | 5757 |
5711 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count, | 5758 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count, |
5712 bool restore_context, bool do_return, | 5759 bool restore_context, bool do_return, |
5713 bool argument_count_is_length) { | 5760 bool argument_count_is_length) { |
5714 // Optionally restore all double registers. | 5761 // Optionally restore all double registers. |
5715 if (save_doubles) { | 5762 if (save_doubles) { |
5716 // Remember: we only need to restore every 2nd double FPU value. | 5763 // Remember: we only need to restore every 2nd double FPU value. |
5717 int kNumOfSavedRegisters = FPURegister::kMaxNumRegisters / 2; | 5764 int kNumOfSavedRegisters = FPURegister::kMaxNumRegisters / 2; |
5718 Dsubu(t8, fp, Operand(ExitFrameConstants::kFrameSize + | 5765 Dsubu(t8, fp, Operand(ExitFrameConstants::kFixedFrameSizeFromFp + |
5719 kNumOfSavedRegisters * kDoubleSize)); | 5766 kNumOfSavedRegisters * kDoubleSize)); |
5720 for (int i = 0; i < kNumOfSavedRegisters; i++) { | 5767 for (int i = 0; i < kNumOfSavedRegisters; i++) { |
5721 FPURegister reg = FPURegister::from_code(2 * i); | 5768 FPURegister reg = FPURegister::from_code(2 * i); |
5722 ldc1(reg, MemOperand(t8, i * kDoubleSize)); | 5769 ldc1(reg, MemOperand(t8, i * kDoubleSize)); |
5723 } | 5770 } |
5724 } | 5771 } |
5725 | 5772 |
5726 // Clear top frame. | 5773 // Clear top frame. |
5727 li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); | 5774 li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); |
5728 sd(zero_reg, MemOperand(t8)); | 5775 sd(zero_reg, MemOperand(t8)); |
5729 | 5776 |
(...skipping 935 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6665 if (mag.shift > 0) sra(result, result, mag.shift); | 6712 if (mag.shift > 0) sra(result, result, mag.shift); |
6666 srl(at, dividend, 31); | 6713 srl(at, dividend, 31); |
6667 Addu(result, result, Operand(at)); | 6714 Addu(result, result, Operand(at)); |
6668 } | 6715 } |
6669 | 6716 |
6670 | 6717 |
6671 } // namespace internal | 6718 } // namespace internal |
6672 } // namespace v8 | 6719 } // namespace v8 |
6673 | 6720 |
6674 #endif // V8_TARGET_ARCH_MIPS64 | 6721 #endif // V8_TARGET_ARCH_MIPS64 |
OLD | NEW |