0bb0c4a802da07a9e413924291d16ce1b43a4cb0
[platform/upstream/nodejs.git] / deps / v8 / src / mips64 / debug-mips64.cc
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
3 // found in the LICENSE file.
4
5
6
7 #include "src/v8.h"
8
9 #if V8_TARGET_ARCH_MIPS64
10
11 #include "src/codegen.h"
12 #include "src/debug.h"
13
14 namespace v8 {
15 namespace internal {
16
17 bool BreakLocationIterator::IsDebugBreakAtReturn() {
18   return Debug::IsDebugBreakAtReturn(rinfo());
19 }
20
21
22 void BreakLocationIterator::SetDebugBreakAtReturn() {
23   // Mips return sequence:
24   // mov sp, fp
25   // lw fp, sp(0)
26   // lw ra, sp(4)
27   // addiu sp, sp, 8
28   // addiu sp, sp, N
29   // jr ra
30   // nop (in branch delay slot)
31
32   // Make sure this constant matches the number if instructions we emit.
33   DCHECK(Assembler::kJSReturnSequenceInstructions == 7);
34   CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
35   // li and Call pseudo-instructions emit 6 + 2 instructions.
36   patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int64_t>(
37       debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry())),
38       ADDRESS_LOAD);
39   patcher.masm()->Call(v8::internal::t9);
40   // Place nop to match return sequence size.
41   patcher.masm()->nop();
42   // TODO(mips): Open issue about using breakpoint instruction instead of nops.
43   // patcher.masm()->bkpt(0);
44 }
45
46
47 // Restore the JS frame exit code.
48 void BreakLocationIterator::ClearDebugBreakAtReturn() {
49   rinfo()->PatchCode(original_rinfo()->pc(),
50                      Assembler::kJSReturnSequenceInstructions);
51 }
52
53
54 // A debug break in the exit code is identified by the JS frame exit code
55 // having been patched with li/call psuedo-instrunction (liu/ori/jalr).
56 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
57   DCHECK(RelocInfo::IsJSReturn(rinfo->rmode()));
58   return rinfo->IsPatchedReturnSequence();
59 }
60
61
62 bool BreakLocationIterator::IsDebugBreakAtSlot() {
63   DCHECK(IsDebugBreakSlot());
64   // Check whether the debug break slot instructions have been patched.
65   return rinfo()->IsPatchedDebugBreakSlotSequence();
66 }
67
68
69 void BreakLocationIterator::SetDebugBreakAtSlot() {
70   DCHECK(IsDebugBreakSlot());
71   // Patch the code changing the debug break slot code from:
72   //   nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
73   //   nop(DEBUG_BREAK_NOP)
74   //   nop(DEBUG_BREAK_NOP)
75   //   nop(DEBUG_BREAK_NOP)
76   //   nop(DEBUG_BREAK_NOP)
77   //   nop(DEBUG_BREAK_NOP)
78   // to a call to the debug break slot code.
79   //   li t9, address   (4-instruction sequence on mips64)
80   //   call t9          (jalr t9 / nop instruction pair)
81   CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
82   patcher.masm()->li(v8::internal::t9,
83       Operand(reinterpret_cast<int64_t>(
84           debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())),
85       ADDRESS_LOAD);
86   patcher.masm()->Call(v8::internal::t9);
87 }
88
89
90 void BreakLocationIterator::ClearDebugBreakAtSlot() {
91   DCHECK(IsDebugBreakSlot());
92   rinfo()->PatchCode(original_rinfo()->pc(),
93                      Assembler::kDebugBreakSlotInstructions);
94 }
95
96
97 #define __ ACCESS_MASM(masm)
98
99
100
101 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
102                                           RegList object_regs,
103                                           RegList non_object_regs) {
104   {
105     FrameScope scope(masm, StackFrame::INTERNAL);
106
107     // Load padding words on stack.
108     __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue)));
109     __ Dsubu(sp, sp,
110             Operand(kPointerSize * LiveEdit::kFramePaddingInitialSize));
111     for (int i = LiveEdit::kFramePaddingInitialSize - 1; i >= 0; i--) {
112       __ sd(at, MemOperand(sp, kPointerSize * i));
113     }
114     __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
115     __ push(at);
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
121     // Store the registers containing live values on the expression stack to
122     // make sure that these are correctly updated during GC. Non object values
123     // are stored as a smi causing it to be untouched by GC.
124     DCHECK((object_regs & ~kJSCallerSaved) == 0);
125     DCHECK((non_object_regs & ~kJSCallerSaved) == 0);
126     DCHECK((object_regs & non_object_regs) == 0);
127     for (int i = 0; i < kNumJSCallerSaved; i++) {
128       int r = JSCallerSavedCode(i);
129       Register reg = { r };
130       if ((object_regs & (1 << r)) != 0) {
131         __ push(reg);
132       }
133       if ((non_object_regs & (1 << r)) != 0) {
134         __ PushRegisterAsTwoSmis(reg);
135       }
136     }
137
138 #ifdef DEBUG
139     __ RecordComment("// Calling from debug break to runtime - come in - over");
140 #endif
141     __ PrepareCEntryArgs(0);  // No arguments.
142     __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate()));
143
144     CEntryStub ceb(masm->isolate(), 1);
145     __ CallStub(&ceb);
146
147     // Restore the register values from the expression stack.
148     for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
149       int r = JSCallerSavedCode(i);
150       Register reg = { r };
151       if ((non_object_regs & (1 << r)) != 0) {
152         __ PopRegisterAsTwoSmis(reg, at);
153       }
154       if ((object_regs & (1 << r)) != 0) {
155         __ pop(reg);
156       }
157       if (FLAG_debug_code &&
158           (((object_regs |non_object_regs) & (1 << r)) == 0)) {
159         __ li(reg, kDebugZapValue);
160       }
161     }
162
163     // Don't bother removing padding bytes pushed on the stack
164     // as the frame is going to be restored right away.
165
166     // Leave the internal frame.
167   }
168
169   // Now that the break point has been handled, resume normal execution by
170   // jumping to the target address intended by the caller and that was
171   // overwritten by the address of DebugBreakXXX.
172   ExternalReference after_break_target =
173       ExternalReference::debug_after_break_target_address(masm->isolate());
174   __ li(t9, Operand(after_break_target));
175   __ ld(t9, MemOperand(t9));
176   __ Jump(t9);
177 }
178
179
180 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
181   // Register state for CallICStub
182   // ----------- S t a t e -------------
183   //  -- a1 : function
184   //  -- a3 : slot in feedback array (smi)
185   // -----------------------------------
186   Generate_DebugBreakCallHelper(masm, a1.bit() | a3.bit(), 0);
187 }
188
189
190 void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
191   Register receiver = LoadDescriptor::ReceiverRegister();
192   Register name = LoadDescriptor::NameRegister();
193   RegList regs = receiver.bit() | name.bit();
194   if (FLAG_vector_ics) {
195     regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
196   }
197   Generate_DebugBreakCallHelper(masm, regs, 0);
198 }
199
200
201 void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
202   Register receiver = StoreDescriptor::ReceiverRegister();
203   Register name = StoreDescriptor::NameRegister();
204   Register value = StoreDescriptor::ValueRegister();
205   Generate_DebugBreakCallHelper(
206       masm, receiver.bit() | name.bit() | value.bit(), 0);
207 }
208
209
210 void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
211   // Calling convention for keyed IC load (from ic-mips64.cc).
212   GenerateLoadICDebugBreak(masm);
213 }
214
215
216 void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
217   // Calling convention for IC keyed store call (from ic-mips64.cc).
218   Register receiver = StoreDescriptor::ReceiverRegister();
219   Register name = StoreDescriptor::NameRegister();
220   Register value = StoreDescriptor::ValueRegister();
221   Generate_DebugBreakCallHelper(
222       masm, receiver.bit() | name.bit() | value.bit(), 0);
223 }
224
225
226 void DebugCodegen::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
227   // Register state for CompareNil IC
228   // ----------- S t a t e -------------
229   //  -- a0    : value
230   // -----------------------------------
231   Generate_DebugBreakCallHelper(masm, a0.bit(), 0);
232 }
233
234
235 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
236   // In places other than IC call sites it is expected that v0 is TOS which
237   // is an object - this is not generally the case so this should be used with
238   // care.
239   Generate_DebugBreakCallHelper(masm, v0.bit(), 0);
240 }
241
242
243 void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
244   // Register state for CallFunctionStub (from code-stubs-mips.cc).
245   // ----------- S t a t e -------------
246   //  -- a1 : function
247   // -----------------------------------
248   Generate_DebugBreakCallHelper(masm, a1.bit(), 0);
249 }
250
251
252 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
253   // Calling convention for CallConstructStub (from code-stubs-mips.cc).
254   // ----------- S t a t e -------------
255   //  -- a0     : number of arguments (not smi)
256   //  -- a1     : constructor function
257   // -----------------------------------
258   Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit());
259 }
260
261
262
263 void DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
264     MacroAssembler* masm) {
265   // Calling convention for CallConstructStub (from code-stubs-mips.cc).
266   // ----------- S t a t e -------------
267   //  -- a0     : number of arguments (not smi)
268   //  -- a1     : constructor function
269   //  -- a2     : feedback array
270   //  -- a3     : feedback slot (smi)
271   // -----------------------------------
272   Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit() | a3.bit(), a0.bit());
273 }
274
275
276 void DebugCodegen::GenerateSlot(MacroAssembler* masm) {
277   // Generate enough nop's to make space for a call instruction. Avoid emitting
278   // the trampoline pool in the debug break slot code.
279   Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
280   Label check_codesize;
281   __ bind(&check_codesize);
282   __ RecordDebugBreakSlot();
283   for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
284     __ nop(MacroAssembler::DEBUG_BREAK_NOP);
285   }
286   DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
287             masm->InstructionsGeneratedSince(&check_codesize));
288 }
289
290
291 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
292   // In the places where a debug break slot is inserted no registers can contain
293   // object pointers.
294   Generate_DebugBreakCallHelper(masm, 0, 0);
295 }
296
297
298 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
299   __ Ret();
300 }
301
302
303 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
304   ExternalReference restarter_frame_function_slot =
305       ExternalReference::debug_restarter_frame_function_pointer_address(
306           masm->isolate());
307   __ li(at, Operand(restarter_frame_function_slot));
308   __ sw(zero_reg, MemOperand(at, 0));
309
310   // We do not know our frame height, but set sp based on fp.
311   __ Dsubu(sp, fp, Operand(kPointerSize));
312
313   __ Pop(ra, fp, a1);  // Return address, Frame, Function.
314
315   // Load context from the function.
316   __ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
317
318   // Get function code.
319   __ ld(at, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
320   __ ld(at, FieldMemOperand(at, SharedFunctionInfo::kCodeOffset));
321   __ Daddu(t9, at, Operand(Code::kHeaderSize - kHeapObjectTag));
322
323   // Re-run JSFunction, a1 is function, cp is context.
324   __ Jump(t9);
325 }
326
327
328 const bool LiveEdit::kFrameDropperSupported = true;
329
330 #undef __
331
332 } }  // namespace v8::internal
333
334 #endif  // V8_TARGET_ARCH_MIPS64