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_MIPS64 |
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 bool BreakLocationIterator::IsDebugBreakAtReturn() { | 17 bool BreakLocationIterator::IsDebugBreakAtReturn() { |
18 return Debug::IsDebugBreakAtReturn(rinfo()); | 18 return Debug::IsDebugBreakAtReturn(rinfo()); |
19 } | 19 } |
20 | 20 |
21 | 21 |
22 void BreakLocationIterator::SetDebugBreakAtReturn() { | 22 void BreakLocationIterator::SetDebugBreakAtReturn() { |
23 // Mips return sequence: | 23 // Mips return sequence: |
24 // mov sp, fp | 24 // mov sp, fp |
25 // lw fp, sp(0) | 25 // lw fp, sp(0) |
26 // lw ra, sp(4) | 26 // lw ra, sp(4) |
27 // addiu sp, sp, 8 | 27 // addiu sp, sp, 8 |
28 // addiu sp, sp, N | 28 // addiu sp, sp, N |
29 // jr ra | 29 // jr ra |
30 // nop (in branch delay slot) | 30 // nop (in branch delay slot) |
31 | 31 |
32 // Make sure this constant matches the number if instrucntions we emit. | 32 // Make sure this constant matches the number if instructions we emit. |
33 ASSERT(Assembler::kJSReturnSequenceInstructions == 7); | 33 ASSERT(Assembler::kJSReturnSequenceInstructions == 7); |
34 CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions); | 34 CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions); |
35 // li and Call pseudo-instructions emit two instructions each. | 35 // li and Call pseudo-instructions emit 6 + 2 instructions. |
36 patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>( | 36 patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int64_t>( |
37 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry()))); | 37 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry())), |
| 38 ADDRESS_LOAD); |
38 patcher.masm()->Call(v8::internal::t9); | 39 patcher.masm()->Call(v8::internal::t9); |
| 40 // Place nop to match return sequence size. |
39 patcher.masm()->nop(); | 41 patcher.masm()->nop(); |
40 patcher.masm()->nop(); | |
41 patcher.masm()->nop(); | |
42 | |
43 // TODO(mips): Open issue about using breakpoint instruction instead of nops. | 42 // TODO(mips): Open issue about using breakpoint instruction instead of nops. |
44 // patcher.masm()->bkpt(0); | 43 // patcher.masm()->bkpt(0); |
45 } | 44 } |
46 | 45 |
47 | 46 |
48 // Restore the JS frame exit code. | 47 // Restore the JS frame exit code. |
49 void BreakLocationIterator::ClearDebugBreakAtReturn() { | 48 void BreakLocationIterator::ClearDebugBreakAtReturn() { |
50 rinfo()->PatchCode(original_rinfo()->pc(), | 49 rinfo()->PatchCode(original_rinfo()->pc(), |
51 Assembler::kJSReturnSequenceInstructions); | 50 Assembler::kJSReturnSequenceInstructions); |
52 } | 51 } |
(...skipping 14 matching lines...) Expand all Loading... |
67 } | 66 } |
68 | 67 |
69 | 68 |
70 void BreakLocationIterator::SetDebugBreakAtSlot() { | 69 void BreakLocationIterator::SetDebugBreakAtSlot() { |
71 ASSERT(IsDebugBreakSlot()); | 70 ASSERT(IsDebugBreakSlot()); |
72 // Patch the code changing the debug break slot code from: | 71 // Patch the code changing the debug break slot code from: |
73 // nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1) | 72 // nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1) |
74 // nop(DEBUG_BREAK_NOP) | 73 // nop(DEBUG_BREAK_NOP) |
75 // nop(DEBUG_BREAK_NOP) | 74 // nop(DEBUG_BREAK_NOP) |
76 // nop(DEBUG_BREAK_NOP) | 75 // nop(DEBUG_BREAK_NOP) |
| 76 // nop(DEBUG_BREAK_NOP) |
| 77 // nop(DEBUG_BREAK_NOP) |
77 // to a call to the debug break slot code. | 78 // to a call to the debug break slot code. |
78 // li t9, address (lui t9 / ori t9 instruction pair) | 79 // li t9, address (4-instruction sequence on mips64) |
79 // call t9 (jalr t9 / nop instruction pair) | 80 // call t9 (jalr t9 / nop instruction pair) |
80 CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions); | 81 CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions); |
81 patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>( | 82 patcher.masm()->li(v8::internal::t9, |
82 debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry()))); | 83 Operand(reinterpret_cast<int64_t>( |
| 84 debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())), |
| 85 ADDRESS_LOAD); |
83 patcher.masm()->Call(v8::internal::t9); | 86 patcher.masm()->Call(v8::internal::t9); |
84 } | 87 } |
85 | 88 |
86 | 89 |
87 void BreakLocationIterator::ClearDebugBreakAtSlot() { | 90 void BreakLocationIterator::ClearDebugBreakAtSlot() { |
88 ASSERT(IsDebugBreakSlot()); | 91 ASSERT(IsDebugBreakSlot()); |
89 rinfo()->PatchCode(original_rinfo()->pc(), | 92 rinfo()->PatchCode(original_rinfo()->pc(), |
90 Assembler::kDebugBreakSlotInstructions); | 93 Assembler::kDebugBreakSlotInstructions); |
91 } | 94 } |
92 | 95 |
93 | 96 |
94 #define __ ACCESS_MASM(masm) | 97 #define __ ACCESS_MASM(masm) |
95 | 98 |
96 | 99 |
97 | 100 |
98 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, | 101 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, |
99 RegList object_regs, | 102 RegList object_regs, |
100 RegList non_object_regs) { | 103 RegList non_object_regs) { |
101 { | 104 { |
102 FrameScope scope(masm, StackFrame::INTERNAL); | 105 FrameScope scope(masm, StackFrame::INTERNAL); |
103 | 106 |
104 // Load padding words on stack. | 107 // Load padding words on stack. |
105 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue))); | 108 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue))); |
106 __ Subu(sp, sp, | 109 __ Dsubu(sp, sp, |
107 Operand(kPointerSize * LiveEdit::kFramePaddingInitialSize)); | 110 Operand(kPointerSize * LiveEdit::kFramePaddingInitialSize)); |
108 for (int i = LiveEdit::kFramePaddingInitialSize - 1; i >= 0; i--) { | 111 for (int i = LiveEdit::kFramePaddingInitialSize - 1; i >= 0; i--) { |
109 __ sw(at, MemOperand(sp, kPointerSize * i)); | 112 __ sd(at, MemOperand(sp, kPointerSize * i)); |
110 } | 113 } |
111 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); | 114 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); |
112 __ push(at); | 115 __ push(at); |
113 | 116 |
| 117 |
| 118 // TODO(plind): This needs to be revised to store pairs of smi's per |
| 119 // the other 64-bit arch's. |
| 120 |
114 // Store the registers containing live values on the expression stack to | 121 // Store the registers containing live values on the expression stack to |
115 // make sure that these are correctly updated during GC. Non object values | 122 // make sure that these are correctly updated during GC. Non object values |
116 // are stored as a smi causing it to be untouched by GC. | 123 // are stored as a smi causing it to be untouched by GC. |
117 ASSERT((object_regs & ~kJSCallerSaved) == 0); | 124 ASSERT((object_regs & ~kJSCallerSaved) == 0); |
118 ASSERT((non_object_regs & ~kJSCallerSaved) == 0); | 125 ASSERT((non_object_regs & ~kJSCallerSaved) == 0); |
119 ASSERT((object_regs & non_object_regs) == 0); | 126 ASSERT((object_regs & non_object_regs) == 0); |
120 if ((object_regs | non_object_regs) != 0) { | 127 for (int i = 0; i < kNumJSCallerSaved; i++) { |
121 for (int i = 0; i < kNumJSCallerSaved; i++) { | 128 int r = JSCallerSavedCode(i); |
122 int r = JSCallerSavedCode(i); | 129 Register reg = { r }; |
123 Register reg = { r }; | 130 if ((object_regs & (1 << r)) != 0) { |
124 if ((non_object_regs & (1 << r)) != 0) { | 131 __ push(reg); |
125 if (FLAG_debug_code) { | |
126 __ And(at, reg, 0xc0000000); | |
127 __ Assert(eq, kUnableToEncodeValueAsSmi, at, Operand(zero_reg)); | |
128 } | |
129 __ sll(reg, reg, kSmiTagSize); | |
130 } | |
131 } | 132 } |
132 __ MultiPush(object_regs | non_object_regs); | 133 if ((non_object_regs & (1 << r)) != 0) { |
| 134 __ PushRegisterAsTwoSmis(reg); |
| 135 } |
133 } | 136 } |
134 | 137 |
135 #ifdef DEBUG | 138 #ifdef DEBUG |
136 __ RecordComment("// Calling from debug break to runtime - come in - over"); | 139 __ RecordComment("// Calling from debug break to runtime - come in - over"); |
137 #endif | 140 #endif |
138 __ PrepareCEntryArgs(0); // No arguments. | 141 __ PrepareCEntryArgs(0); // No arguments. |
139 __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate())); | 142 __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate())); |
140 | 143 |
141 CEntryStub ceb(masm->isolate(), 1); | 144 CEntryStub ceb(masm->isolate(), 1); |
142 __ CallStub(&ceb); | 145 __ CallStub(&ceb); |
143 | 146 |
144 // Restore the register values from the expression stack. | 147 // Restore the register values from the expression stack. |
145 if ((object_regs | non_object_regs) != 0) { | 148 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) { |
146 __ MultiPop(object_regs | non_object_regs); | 149 int r = JSCallerSavedCode(i); |
147 for (int i = 0; i < kNumJSCallerSaved; i++) { | 150 Register reg = { r }; |
148 int r = JSCallerSavedCode(i); | 151 if ((non_object_regs & (1 << r)) != 0) { |
149 Register reg = { r }; | 152 __ PopRegisterAsTwoSmis(reg, at); |
150 if ((non_object_regs & (1 << r)) != 0) { | 153 } |
151 __ srl(reg, reg, kSmiTagSize); | 154 if ((object_regs & (1 << r)) != 0) { |
152 } | 155 __ pop(reg); |
153 if (FLAG_debug_code && | 156 } |
154 (((object_regs |non_object_regs) & (1 << r)) == 0)) { | 157 if (FLAG_debug_code && |
155 __ li(reg, kDebugZapValue); | 158 (((object_regs |non_object_regs) & (1 << r)) == 0)) { |
156 } | 159 __ li(reg, kDebugZapValue); |
157 } | 160 } |
158 } | 161 } |
159 | 162 |
160 // Don't bother removing padding bytes pushed on the stack | 163 // Don't bother removing padding bytes pushed on the stack |
161 // as the frame is going to be restored right away. | 164 // as the frame is going to be restored right away. |
162 | 165 |
163 // Leave the internal frame. | 166 // Leave the internal frame. |
164 } | 167 } |
165 | 168 |
166 // Now that the break point has been handled, resume normal execution by | 169 // Now that the break point has been handled, resume normal execution by |
167 // jumping to the target address intended by the caller and that was | 170 // jumping to the target address intended by the caller and that was |
168 // overwritten by the address of DebugBreakXXX. | 171 // overwritten by the address of DebugBreakXXX. |
169 ExternalReference after_break_target = | 172 ExternalReference after_break_target = |
170 ExternalReference::debug_after_break_target_address(masm->isolate()); | 173 ExternalReference::debug_after_break_target_address(masm->isolate()); |
171 __ li(t9, Operand(after_break_target)); | 174 __ li(t9, Operand(after_break_target)); |
172 __ lw(t9, MemOperand(t9)); | 175 __ ld(t9, MemOperand(t9)); |
173 __ Jump(t9); | 176 __ Jump(t9); |
174 } | 177 } |
175 | 178 |
176 | 179 |
177 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) { | 180 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) { |
178 // Register state for CallICStub | 181 // Register state for CallICStub |
179 // ----------- S t a t e ------------- | 182 // ----------- S t a t e ------------- |
180 // -- a1 : function | 183 // -- a1 : function |
181 // -- a3 : slot in feedback array (smi) | 184 // -- a3 : slot in feedback array (smi) |
182 // ----------------------------------- | 185 // ----------------------------------- |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) { | 253 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) { |
251 // Calling convention for CallConstructStub (from code-stubs-mips.cc). | 254 // Calling convention for CallConstructStub (from code-stubs-mips.cc). |
252 // ----------- S t a t e ------------- | 255 // ----------- S t a t e ------------- |
253 // -- a0 : number of arguments (not smi) | 256 // -- a0 : number of arguments (not smi) |
254 // -- a1 : constructor function | 257 // -- a1 : constructor function |
255 // ----------------------------------- | 258 // ----------------------------------- |
256 Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit()); | 259 Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit()); |
257 } | 260 } |
258 | 261 |
259 | 262 |
| 263 |
260 void DebugCodegen::GenerateCallConstructStubRecordDebugBreak( | 264 void DebugCodegen::GenerateCallConstructStubRecordDebugBreak( |
261 MacroAssembler* masm) { | 265 MacroAssembler* masm) { |
262 // Calling convention for CallConstructStub (from code-stubs-mips.cc). | 266 // Calling convention for CallConstructStub (from code-stubs-mips.cc). |
263 // ----------- S t a t e ------------- | 267 // ----------- S t a t e ------------- |
264 // -- a0 : number of arguments (not smi) | 268 // -- a0 : number of arguments (not smi) |
265 // -- a1 : constructor function | 269 // -- a1 : constructor function |
266 // -- a2 : feedback array | 270 // -- a2 : feedback array |
267 // -- a3 : feedback slot (smi) | 271 // -- a3 : feedback slot (smi) |
268 // ----------------------------------- | 272 // ----------------------------------- |
269 Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit() | a3.bit(), a0.bit()); | 273 Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit() | a3.bit(), a0.bit()); |
(...skipping 28 matching lines...) Expand all Loading... |
298 | 302 |
299 | 303 |
300 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { | 304 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { |
301 ExternalReference restarter_frame_function_slot = | 305 ExternalReference restarter_frame_function_slot = |
302 ExternalReference::debug_restarter_frame_function_pointer_address( | 306 ExternalReference::debug_restarter_frame_function_pointer_address( |
303 masm->isolate()); | 307 masm->isolate()); |
304 __ li(at, Operand(restarter_frame_function_slot)); | 308 __ li(at, Operand(restarter_frame_function_slot)); |
305 __ sw(zero_reg, MemOperand(at, 0)); | 309 __ sw(zero_reg, MemOperand(at, 0)); |
306 | 310 |
307 // We do not know our frame height, but set sp based on fp. | 311 // We do not know our frame height, but set sp based on fp. |
308 __ Subu(sp, fp, Operand(kPointerSize)); | 312 __ Dsubu(sp, fp, Operand(kPointerSize)); |
309 | 313 |
310 __ Pop(ra, fp, a1); // Return address, Frame, Function. | 314 __ Pop(ra, fp, a1); // Return address, Frame, Function. |
311 | 315 |
312 // Load context from the function. | 316 // Load context from the function. |
313 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); | 317 __ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); |
314 | 318 |
315 // Get function code. | 319 // Get function code. |
316 __ lw(at, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); | 320 __ ld(at, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); |
317 __ lw(at, FieldMemOperand(at, SharedFunctionInfo::kCodeOffset)); | 321 __ ld(at, FieldMemOperand(at, SharedFunctionInfo::kCodeOffset)); |
318 __ Addu(t9, at, Operand(Code::kHeaderSize - kHeapObjectTag)); | 322 __ Daddu(t9, at, Operand(Code::kHeaderSize - kHeapObjectTag)); |
319 | 323 |
320 // Re-run JSFunction, a1 is function, cp is context. | 324 // Re-run JSFunction, a1 is function, cp is context. |
321 __ Jump(t9); | 325 __ Jump(t9); |
322 } | 326 } |
323 | 327 |
324 | 328 |
325 const bool LiveEdit::kFrameDropperSupported = true; | 329 const bool LiveEdit::kFrameDropperSupported = true; |
326 | 330 |
327 #undef __ | 331 #undef __ |
328 | 332 |
329 } } // namespace v8::internal | 333 } } // namespace v8::internal |
330 | 334 |
331 #endif // V8_TARGET_ARCH_MIPS | 335 #endif // V8_TARGET_ARCH_MIPS64 |
OLD | NEW |