| 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 | 5 |
| 6 | 6 |
| 7 #include "src/v8.h" | 7 #include "src/v8.h" |
| 8 | 8 |
| 9 #if V8_TARGET_ARCH_MIPS | 9 #if V8_TARGET_ARCH_MIPS |
| 10 | 10 |
| 11 #include "src/codegen.h" | 11 #include "src/codegen.h" |
| 12 #include "src/debug.h" | 12 #include "src/debug.h" |
| 13 | 13 |
| 14 namespace v8 { | 14 namespace v8 { |
| 15 namespace internal { | 15 namespace internal { |
| 16 | 16 |
| 17 void BreakLocation::SetDebugBreakAtReturn() { | 17 #define __ ACCESS_MASM(masm) |
| 18 // Mips return sequence: | |
| 19 // mov sp, fp | |
| 20 // lw fp, sp(0) | |
| 21 // lw ra, sp(4) | |
| 22 // addiu sp, sp, 8 | |
| 23 // addiu sp, sp, N | |
| 24 // jr ra | |
| 25 // nop (in branch delay slot) | |
| 26 | 18 |
| 27 // Make sure this constant matches the number if instrucntions we emit. | |
| 28 DCHECK(Assembler::kJSReturnSequenceInstructions == 7); | |
| 29 CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions); | |
| 30 // li and Call pseudo-instructions emit two instructions each. | |
| 31 patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>( | |
| 32 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry()))); | |
| 33 patcher.masm()->Call(v8::internal::t9); | |
| 34 patcher.masm()->nop(); | |
| 35 patcher.masm()->nop(); | |
| 36 patcher.masm()->nop(); | |
| 37 | 19 |
| 38 // TODO(mips): Open issue about using breakpoint instruction instead of nops. | 20 void EmitDebugBreakSlot(MacroAssembler* masm) { |
| 39 // patcher.masm()->bkpt(0); | 21 Label check_size; |
| 22 __ bind(&check_size); |
| 23 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) { |
| 24 __ nop(MacroAssembler::DEBUG_BREAK_NOP); |
| 25 } |
| 26 DCHECK_EQ(Assembler::kDebugBreakSlotInstructions, |
| 27 masm->InstructionsGeneratedSince(&check_size)); |
| 40 } | 28 } |
| 41 | 29 |
| 42 | 30 |
| 43 void BreakLocation::SetDebugBreakAtSlot() { | 31 void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode, |
| 44 DCHECK(IsDebugBreakSlot()); | 32 int call_argc) { |
| 33 // Generate enough nop's to make space for a call instruction. Avoid emitting |
| 34 // the trampoline pool in the debug break slot code. |
| 35 Assembler::BlockTrampolinePoolScope block_pool(masm); |
| 36 masm->RecordDebugBreakSlot(mode, call_argc); |
| 37 EmitDebugBreakSlot(masm); |
| 38 } |
| 39 |
| 40 |
| 41 void DebugCodegen::ClearDebugBreakSlot(Address pc) { |
| 42 CodePatcher patcher(pc, Assembler::kDebugBreakSlotInstructions); |
| 43 EmitDebugBreakSlot(patcher.masm()); |
| 44 } |
| 45 |
| 46 |
| 47 void DebugCodegen::PatchDebugBreakSlot(Address pc, Handle<Code> code) { |
| 48 DCHECK_EQ(Code::BUILTIN, code->kind()); |
| 49 CodePatcher patcher(pc, Assembler::kDebugBreakSlotInstructions); |
| 45 // Patch the code changing the debug break slot code from: | 50 // Patch the code changing the debug break slot code from: |
| 46 // nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1) | 51 // nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1) |
| 47 // nop(DEBUG_BREAK_NOP) | 52 // nop(DEBUG_BREAK_NOP) |
| 48 // nop(DEBUG_BREAK_NOP) | 53 // nop(DEBUG_BREAK_NOP) |
| 49 // nop(DEBUG_BREAK_NOP) | 54 // nop(DEBUG_BREAK_NOP) |
| 50 // to a call to the debug break slot code. | 55 // to a call to the debug break slot code. |
| 51 // li t9, address (lui t9 / ori t9 instruction pair) | 56 // li t9, address (lui t9 / ori t9 instruction pair) |
| 52 // call t9 (jalr t9 / nop instruction pair) | 57 // call t9 (jalr t9 / nop instruction pair) |
| 53 CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions); | 58 patcher.masm()->li(v8::internal::t9, |
| 54 patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>( | 59 Operand(reinterpret_cast<int32_t>(code->entry()))); |
| 55 debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry()))); | |
| 56 patcher.masm()->Call(v8::internal::t9); | 60 patcher.masm()->Call(v8::internal::t9); |
| 57 } | 61 } |
| 58 | 62 |
| 59 | 63 |
| 60 #define __ ACCESS_MASM(masm) | 64 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, |
| 61 | 65 DebugBreakCallHelperMode mode) { |
| 62 | 66 __ RecordComment("Debug break"); |
| 63 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, | |
| 64 RegList object_regs) { | |
| 65 { | 67 { |
| 66 FrameScope scope(masm, StackFrame::INTERNAL); | 68 FrameScope scope(masm, StackFrame::INTERNAL); |
| 67 | 69 |
| 68 // Load padding words on stack. | 70 // Load padding words on stack. |
| 69 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue))); | 71 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue))); |
| 70 __ Subu(sp, sp, | 72 __ Subu(sp, sp, |
| 71 Operand(kPointerSize * LiveEdit::kFramePaddingInitialSize)); | 73 Operand(kPointerSize * LiveEdit::kFramePaddingInitialSize)); |
| 72 for (int i = LiveEdit::kFramePaddingInitialSize - 1; i >= 0; i--) { | 74 for (int i = LiveEdit::kFramePaddingInitialSize - 1; i >= 0; i--) { |
| 73 __ sw(at, MemOperand(sp, kPointerSize * i)); | 75 __ sw(at, MemOperand(sp, kPointerSize * i)); |
| 74 } | 76 } |
| 75 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); | 77 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); |
| 76 __ push(at); | 78 __ push(at); |
| 77 | 79 |
| 78 // Store the registers containing live values on the expression stack to | 80 if (mode == SAVE_RESULT_REGISTER) __ push(v0); |
| 79 // make sure that these are correctly updated during GC. Non object values | |
| 80 // are stored as a smi causing it to be untouched by GC. | |
| 81 DCHECK((object_regs & ~kJSCallerSaved) == 0); | |
| 82 if (object_regs != 0) { | |
| 83 __ MultiPush(object_regs); | |
| 84 } | |
| 85 | 81 |
| 86 #ifdef DEBUG | |
| 87 __ RecordComment("// Calling from debug break to runtime - come in - over"); | |
| 88 #endif | |
| 89 __ PrepareCEntryArgs(0); // No arguments. | 82 __ PrepareCEntryArgs(0); // No arguments. |
| 90 __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate())); | 83 __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate())); |
| 91 | 84 |
| 92 CEntryStub ceb(masm->isolate(), 1); | 85 CEntryStub ceb(masm->isolate(), 1); |
| 93 __ CallStub(&ceb); | 86 __ CallStub(&ceb); |
| 94 | 87 |
| 95 // Restore the register values from the expression stack. | 88 if (FLAG_debug_code) { |
| 96 if (object_regs != 0) { | 89 for (int i = 0; i < kNumJSCallerSaved; i++) { |
| 97 __ MultiPop(object_regs); | 90 Register reg = {JSCallerSavedCode(i)}; |
| 98 } | |
| 99 for (int i = 0; i < kNumJSCallerSaved; i++) { | |
| 100 int r = JSCallerSavedCode(i); | |
| 101 Register reg = {r}; | |
| 102 if (FLAG_debug_code && ((object_regs & (1 << r)) == 0)) { | |
| 103 __ li(reg, kDebugZapValue); | 91 __ li(reg, kDebugZapValue); |
| 104 } | 92 } |
| 105 } | 93 } |
| 106 | 94 |
| 95 if (mode == SAVE_RESULT_REGISTER) __ pop(v0); |
| 96 |
| 107 // Don't bother removing padding bytes pushed on the stack | 97 // Don't bother removing padding bytes pushed on the stack |
| 108 // as the frame is going to be restored right away. | 98 // as the frame is going to be restored right away. |
| 109 | 99 |
| 110 // Leave the internal frame. | 100 // Leave the internal frame. |
| 111 } | 101 } |
| 112 | 102 |
| 113 // Now that the break point has been handled, resume normal execution by | 103 // Now that the break point has been handled, resume normal execution by |
| 114 // jumping to the target address intended by the caller and that was | 104 // jumping to the target address intended by the caller and that was |
| 115 // overwritten by the address of DebugBreakXXX. | 105 // overwritten by the address of DebugBreakXXX. |
| 116 ExternalReference after_break_target = | 106 ExternalReference after_break_target = |
| 117 ExternalReference::debug_after_break_target_address(masm->isolate()); | 107 ExternalReference::debug_after_break_target_address(masm->isolate()); |
| 118 __ li(t9, Operand(after_break_target)); | 108 __ li(t9, Operand(after_break_target)); |
| 119 __ lw(t9, MemOperand(t9)); | 109 __ lw(t9, MemOperand(t9)); |
| 120 __ Jump(t9); | 110 __ Jump(t9); |
| 121 } | 111 } |
| 122 | 112 |
| 123 | 113 |
| 124 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) { | |
| 125 // In places other than IC call sites it is expected that v0 is TOS which | |
| 126 // is an object - this is not generally the case so this should be used with | |
| 127 // care. | |
| 128 Generate_DebugBreakCallHelper(masm, v0.bit()); | |
| 129 } | |
| 130 | |
| 131 | |
| 132 void DebugCodegen::GenerateSlot(MacroAssembler* masm, | |
| 133 DebugCodegen::SlotLocation location, | |
| 134 int call_argc) { | |
| 135 // Generate enough nop's to make space for a call instruction. Avoid emitting | |
| 136 // the trampoline pool in the debug break slot code. | |
| 137 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm); | |
| 138 Label check_codesize; | |
| 139 __ bind(&check_codesize); | |
| 140 RecordRelocInfo(masm, location, call_argc); | |
| 141 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) { | |
| 142 __ nop(MacroAssembler::DEBUG_BREAK_NOP); | |
| 143 } | |
| 144 DCHECK_EQ(Assembler::kDebugBreakSlotInstructions, | |
| 145 masm->InstructionsGeneratedSince(&check_codesize)); | |
| 146 } | |
| 147 | |
| 148 | |
| 149 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) { | |
| 150 // In the places where a debug break slot is inserted no registers can contain | |
| 151 // object pointers. | |
| 152 Generate_DebugBreakCallHelper(masm, 0); | |
| 153 } | |
| 154 | |
| 155 | |
| 156 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { | 114 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { |
| 157 __ Ret(); | 115 __ Ret(); |
| 158 } | 116 } |
| 159 | 117 |
| 160 | 118 |
| 161 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { | 119 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { |
| 162 ExternalReference restarter_frame_function_slot = | 120 ExternalReference restarter_frame_function_slot = |
| 163 ExternalReference::debug_restarter_frame_function_pointer_address( | 121 ExternalReference::debug_restarter_frame_function_pointer_address( |
| 164 masm->isolate()); | 122 masm->isolate()); |
| 165 __ li(at, Operand(restarter_frame_function_slot)); | 123 __ li(at, Operand(restarter_frame_function_slot)); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 184 | 142 |
| 185 | 143 |
| 186 const bool LiveEdit::kFrameDropperSupported = true; | 144 const bool LiveEdit::kFrameDropperSupported = true; |
| 187 | 145 |
| 188 #undef __ | 146 #undef __ |
| 189 | 147 |
| 190 } // namespace internal | 148 } // namespace internal |
| 191 } // namespace v8 | 149 } // namespace v8 |
| 192 | 150 |
| 193 #endif // V8_TARGET_ARCH_MIPS | 151 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |