Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / v8 / src / mips / debug-mips.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 "v8.h"
8
9 #if V8_TARGET_ARCH_MIPS
10
11 #include "codegen.h"
12 #include "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 instrucntions we emit.
33   ASSERT(Assembler::kJSReturnSequenceInstructions == 7);
34   CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
35   // li and Call pseudo-instructions emit two instructions each.
36   patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
37       debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry())));
38   patcher.masm()->Call(v8::internal::t9);
39   patcher.masm()->nop();
40   patcher.masm()->nop();
41   patcher.masm()->nop();
42
43   // TODO(mips): Open issue about using breakpoint instruction instead of nops.
44   // patcher.masm()->bkpt(0);
45 }
46
47
48 // Restore the JS frame exit code.
49 void BreakLocationIterator::ClearDebugBreakAtReturn() {
50   rinfo()->PatchCode(original_rinfo()->pc(),
51                      Assembler::kJSReturnSequenceInstructions);
52 }
53
54
55 // A debug break in the exit code is identified by the JS frame exit code
56 // having been patched with li/call psuedo-instrunction (liu/ori/jalr).
57 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
58   ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
59   return rinfo->IsPatchedReturnSequence();
60 }
61
62
63 bool BreakLocationIterator::IsDebugBreakAtSlot() {
64   ASSERT(IsDebugBreakSlot());
65   // Check whether the debug break slot instructions have been patched.
66   return rinfo()->IsPatchedDebugBreakSlotSequence();
67 }
68
69
70 void BreakLocationIterator::SetDebugBreakAtSlot() {
71   ASSERT(IsDebugBreakSlot());
72   // Patch the code changing the debug break slot code from:
73   //   nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
74   //   nop(DEBUG_BREAK_NOP)
75   //   nop(DEBUG_BREAK_NOP)
76   //   nop(DEBUG_BREAK_NOP)
77   // to a call to the debug break slot code.
78   //   li t9, address   (lui t9 / ori t9 instruction pair)
79   //   call t9          (jalr t9 / nop instruction pair)
80   CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
81   patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
82       debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())));
83   patcher.masm()->Call(v8::internal::t9);
84 }
85
86
87 void BreakLocationIterator::ClearDebugBreakAtSlot() {
88   ASSERT(IsDebugBreakSlot());
89   rinfo()->PatchCode(original_rinfo()->pc(),
90                      Assembler::kDebugBreakSlotInstructions);
91 }
92
93 const bool Debug::FramePaddingLayout::kIsSupported = false;
94
95
96 #define __ ACCESS_MASM(masm)
97
98
99
100 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
101                                           RegList object_regs,
102                                           RegList non_object_regs) {
103   {
104     FrameScope scope(masm, StackFrame::INTERNAL);
105
106     // Store the registers containing live values on the expression stack to
107     // make sure that these are correctly updated during GC. Non object values
108     // are stored as a smi causing it to be untouched by GC.
109     ASSERT((object_regs & ~kJSCallerSaved) == 0);
110     ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
111     ASSERT((object_regs & non_object_regs) == 0);
112     if ((object_regs | non_object_regs) != 0) {
113       for (int i = 0; i < kNumJSCallerSaved; i++) {
114         int r = JSCallerSavedCode(i);
115         Register reg = { r };
116         if ((non_object_regs & (1 << r)) != 0) {
117           if (FLAG_debug_code) {
118             __ And(at, reg, 0xc0000000);
119             __ Assert(eq, kUnableToEncodeValueAsSmi, at, Operand(zero_reg));
120           }
121           __ sll(reg, reg, kSmiTagSize);
122         }
123       }
124       __ MultiPush(object_regs | non_object_regs);
125     }
126
127 #ifdef DEBUG
128     __ RecordComment("// Calling from debug break to runtime - come in - over");
129 #endif
130     __ PrepareCEntryArgs(0);  // No arguments.
131     __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate()));
132
133     CEntryStub ceb(masm->isolate(), 1);
134     __ CallStub(&ceb);
135
136     // Restore the register values from the expression stack.
137     if ((object_regs | non_object_regs) != 0) {
138       __ MultiPop(object_regs | non_object_regs);
139       for (int i = 0; i < kNumJSCallerSaved; i++) {
140         int r = JSCallerSavedCode(i);
141         Register reg = { r };
142         if ((non_object_regs & (1 << r)) != 0) {
143           __ srl(reg, reg, kSmiTagSize);
144         }
145         if (FLAG_debug_code &&
146             (((object_regs |non_object_regs) & (1 << r)) == 0)) {
147           __ li(reg, kDebugZapValue);
148         }
149       }
150     }
151
152     // Leave the internal frame.
153   }
154
155   // Now that the break point has been handled, resume normal execution by
156   // jumping to the target address intended by the caller and that was
157   // overwritten by the address of DebugBreakXXX.
158   __ li(t9, Operand(
159       ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate())));
160   __ lw(t9, MemOperand(t9));
161   __ Jump(t9);
162 }
163
164
165 void Debug::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
166   // Register state for CallICStub
167   // ----------- S t a t e -------------
168   //  -- a1 : function
169   //  -- a3 : slot in feedback array (smi)
170   // -----------------------------------
171   Generate_DebugBreakCallHelper(masm, a1.bit() | a3.bit(), 0);
172 }
173
174
175 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
176   // Calling convention for IC load (from ic-mips.cc).
177   // ----------- S t a t e -------------
178   //  -- a2    : name
179   //  -- ra    : return address
180   //  -- a0    : receiver
181   //  -- [sp]  : receiver
182   // -----------------------------------
183   // Registers a0 and a2 contain objects that need to be pushed on the
184   // expression stack of the fake JS frame.
185   Generate_DebugBreakCallHelper(masm, a0.bit() | a2.bit(), 0);
186 }
187
188
189 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
190   // Calling convention for IC store (from ic-mips.cc).
191   // ----------- S t a t e -------------
192   //  -- a0    : value
193   //  -- a1    : receiver
194   //  -- a2    : name
195   //  -- ra    : return address
196   // -----------------------------------
197   // Registers a0, a1, and a2 contain objects that need to be pushed on the
198   // expression stack of the fake JS frame.
199   Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
200 }
201
202
203 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
204   // ---------- S t a t e --------------
205   //  -- ra  : return address
206   //  -- a0  : key
207   //  -- a1  : receiver
208   Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit(), 0);
209 }
210
211
212 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
213   // ---------- S t a t e --------------
214   //  -- a0     : value
215   //  -- a1     : key
216   //  -- a2     : receiver
217   //  -- ra     : return address
218   Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
219 }
220
221
222 void Debug::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
223   // Register state for CompareNil IC
224   // ----------- S t a t e -------------
225   //  -- a0    : value
226   // -----------------------------------
227   Generate_DebugBreakCallHelper(masm, a0.bit(), 0);
228 }
229
230
231 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
232   // In places other than IC call sites it is expected that v0 is TOS which
233   // is an object - this is not generally the case so this should be used with
234   // care.
235   Generate_DebugBreakCallHelper(masm, v0.bit(), 0);
236 }
237
238
239 void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
240   // Register state for CallFunctionStub (from code-stubs-mips.cc).
241   // ----------- S t a t e -------------
242   //  -- a1 : function
243   // -----------------------------------
244   Generate_DebugBreakCallHelper(masm, a1.bit(), 0);
245 }
246
247
248 void Debug::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
249   // Calling convention for CallConstructStub (from code-stubs-mips.cc).
250   // ----------- S t a t e -------------
251   //  -- a0     : number of arguments (not smi)
252   //  -- a1     : constructor function
253   // -----------------------------------
254   Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit());
255 }
256
257
258 void Debug::GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm) {
259   // Calling convention for CallConstructStub (from code-stubs-mips.cc).
260   // ----------- S t a t e -------------
261   //  -- a0     : number of arguments (not smi)
262   //  -- a1     : constructor function
263   //  -- a2     : feedback array
264   //  -- a3     : feedback slot (smi)
265   // -----------------------------------
266   Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit() | a3.bit(), a0.bit());
267 }
268
269
270 void Debug::GenerateSlot(MacroAssembler* masm) {
271   // Generate enough nop's to make space for a call instruction. Avoid emitting
272   // the trampoline pool in the debug break slot code.
273   Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
274   Label check_codesize;
275   __ bind(&check_codesize);
276   __ RecordDebugBreakSlot();
277   for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
278     __ nop(MacroAssembler::DEBUG_BREAK_NOP);
279   }
280   ASSERT_EQ(Assembler::kDebugBreakSlotInstructions,
281             masm->InstructionsGeneratedSince(&check_codesize));
282 }
283
284
285 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
286   // In the places where a debug break slot is inserted no registers can contain
287   // object pointers.
288   Generate_DebugBreakCallHelper(masm, 0, 0);
289 }
290
291
292 void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
293   masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnMips);
294 }
295
296
297 void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
298   masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnMips);
299 }
300
301
302 const bool Debug::kFrameDropperSupported = false;
303
304 #undef __
305
306 } }  // namespace v8::internal
307
308 #endif  // V8_TARGET_ARCH_MIPS