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 |