- add third_party src.
[platform/framework/web/crosswalk.git] / src / v8 / src / mips / debug-mips.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
29
30 #include "v8.h"
31
32 #if V8_TARGET_ARCH_MIPS
33
34 #include "codegen.h"
35 #include "debug.h"
36
37 namespace v8 {
38 namespace internal {
39
40 #ifdef ENABLE_DEBUGGER_SUPPORT
41
42 bool BreakLocationIterator::IsDebugBreakAtReturn() {
43   return Debug::IsDebugBreakAtReturn(rinfo());
44 }
45
46
47 void BreakLocationIterator::SetDebugBreakAtReturn() {
48   // Mips return sequence:
49   // mov sp, fp
50   // lw fp, sp(0)
51   // lw ra, sp(4)
52   // addiu sp, sp, 8
53   // addiu sp, sp, N
54   // jr ra
55   // nop (in branch delay slot)
56
57   // Make sure this constant matches the number if instrucntions we emit.
58   ASSERT(Assembler::kJSReturnSequenceInstructions == 7);
59   CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
60   // li and Call pseudo-instructions emit two instructions each.
61   patcher.masm()->li(v8::internal::t9,
62       Operand(reinterpret_cast<int32_t>(
63         debug_info_->GetIsolate()->debug()->debug_break_return()->entry())));
64   patcher.masm()->Call(v8::internal::t9);
65   patcher.masm()->nop();
66   patcher.masm()->nop();
67   patcher.masm()->nop();
68
69   // TODO(mips): Open issue about using breakpoint instruction instead of nops.
70   // patcher.masm()->bkpt(0);
71 }
72
73
74 // Restore the JS frame exit code.
75 void BreakLocationIterator::ClearDebugBreakAtReturn() {
76   rinfo()->PatchCode(original_rinfo()->pc(),
77                      Assembler::kJSReturnSequenceInstructions);
78 }
79
80
81 // A debug break in the exit code is identified by the JS frame exit code
82 // having been patched with li/call psuedo-instrunction (liu/ori/jalr).
83 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
84   ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
85   return rinfo->IsPatchedReturnSequence();
86 }
87
88
89 bool BreakLocationIterator::IsDebugBreakAtSlot() {
90   ASSERT(IsDebugBreakSlot());
91   // Check whether the debug break slot instructions have been patched.
92   return rinfo()->IsPatchedDebugBreakSlotSequence();
93 }
94
95
96 void BreakLocationIterator::SetDebugBreakAtSlot() {
97   ASSERT(IsDebugBreakSlot());
98   // Patch the code changing the debug break slot code from:
99   //   nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
100   //   nop(DEBUG_BREAK_NOP)
101   //   nop(DEBUG_BREAK_NOP)
102   //   nop(DEBUG_BREAK_NOP)
103   // to a call to the debug break slot code.
104   //   li t9, address   (lui t9 / ori t9 instruction pair)
105   //   call t9          (jalr t9 / nop instruction pair)
106   CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
107   patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
108       debug_info_->GetIsolate()->debug()->debug_break_slot()->entry())));
109   patcher.masm()->Call(v8::internal::t9);
110 }
111
112
113 void BreakLocationIterator::ClearDebugBreakAtSlot() {
114   ASSERT(IsDebugBreakSlot());
115   rinfo()->PatchCode(original_rinfo()->pc(),
116                      Assembler::kDebugBreakSlotInstructions);
117 }
118
119 const bool Debug::FramePaddingLayout::kIsSupported = false;
120
121
122 #define __ ACCESS_MASM(masm)
123
124
125
126 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
127                                           RegList object_regs,
128                                           RegList non_object_regs) {
129   {
130     FrameScope scope(masm, StackFrame::INTERNAL);
131
132     // Store the registers containing live values on the expression stack to
133     // make sure that these are correctly updated during GC. Non object values
134     // are stored as a smi causing it to be untouched by GC.
135     ASSERT((object_regs & ~kJSCallerSaved) == 0);
136     ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
137     ASSERT((object_regs & non_object_regs) == 0);
138     if ((object_regs | non_object_regs) != 0) {
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           if (FLAG_debug_code) {
144             __ And(at, reg, 0xc0000000);
145             __ Assert(eq, kUnableToEncodeValueAsSmi, at, Operand(zero_reg));
146           }
147           __ sll(reg, reg, kSmiTagSize);
148         }
149       }
150       __ MultiPush(object_regs | non_object_regs);
151     }
152
153 #ifdef DEBUG
154     __ RecordComment("// Calling from debug break to runtime - come in - over");
155 #endif
156     __ PrepareCEntryArgs(0);  // No arguments.
157     __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate()));
158
159     CEntryStub ceb(1);
160     __ CallStub(&ceb);
161
162     // Restore the register values from the expression stack.
163     if ((object_regs | non_object_regs) != 0) {
164       __ MultiPop(object_regs | non_object_regs);
165       for (int i = 0; i < kNumJSCallerSaved; i++) {
166         int r = JSCallerSavedCode(i);
167         Register reg = { r };
168         if ((non_object_regs & (1 << r)) != 0) {
169           __ srl(reg, reg, kSmiTagSize);
170         }
171         if (FLAG_debug_code &&
172             (((object_regs |non_object_regs) & (1 << r)) == 0)) {
173           __ li(reg, kDebugZapValue);
174         }
175       }
176     }
177
178     // Leave the internal frame.
179   }
180
181   // Now that the break point has been handled, resume normal execution by
182   // jumping to the target address intended by the caller and that was
183   // overwritten by the address of DebugBreakXXX.
184   __ li(t9, Operand(
185       ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate())));
186   __ lw(t9, MemOperand(t9));
187   __ Jump(t9);
188 }
189
190
191 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
192   // Calling convention for IC load (from ic-mips.cc).
193   // ----------- S t a t e -------------
194   //  -- a2    : name
195   //  -- ra    : return address
196   //  -- a0    : receiver
197   //  -- [sp]  : receiver
198   // -----------------------------------
199   // Registers a0 and a2 contain objects that need to be pushed on the
200   // expression stack of the fake JS frame.
201   Generate_DebugBreakCallHelper(masm, a0.bit() | a2.bit(), 0);
202 }
203
204
205 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
206   // Calling convention for IC store (from ic-mips.cc).
207   // ----------- S t a t e -------------
208   //  -- a0    : value
209   //  -- a1    : receiver
210   //  -- a2    : name
211   //  -- ra    : return address
212   // -----------------------------------
213   // Registers a0, a1, and a2 contain objects that need to be pushed on the
214   // expression stack of the fake JS frame.
215   Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
216 }
217
218
219 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
220   // ---------- S t a t e --------------
221   //  -- ra  : return address
222   //  -- a0  : key
223   //  -- a1  : receiver
224   Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit(), 0);
225 }
226
227
228 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
229   // ---------- S t a t e --------------
230   //  -- a0     : value
231   //  -- a1     : key
232   //  -- a2     : receiver
233   //  -- ra     : return address
234   Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
235 }
236
237
238 void Debug::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
239   // Register state for CompareNil IC
240   // ----------- S t a t e -------------
241   //  -- a0    : value
242   // -----------------------------------
243   Generate_DebugBreakCallHelper(masm, a0.bit(), 0);
244 }
245
246
247 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
248   // Calling convention for IC call (from ic-mips.cc).
249   // ----------- S t a t e -------------
250   //  -- a2: name
251   // -----------------------------------
252   Generate_DebugBreakCallHelper(masm, a2.bit(), 0);
253 }
254
255
256 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
257   // In places other than IC call sites it is expected that v0 is TOS which
258   // is an object - this is not generally the case so this should be used with
259   // care.
260   Generate_DebugBreakCallHelper(masm, v0.bit(), 0);
261 }
262
263
264 void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
265   // Register state for CallFunctionStub (from code-stubs-mips.cc).
266   // ----------- S t a t e -------------
267   //  -- a1 : function
268   // -----------------------------------
269   Generate_DebugBreakCallHelper(masm, a1.bit(), 0);
270 }
271
272
273 void Debug::GenerateCallFunctionStubRecordDebugBreak(MacroAssembler* masm) {
274   // Register state for CallFunctionStub (from code-stubs-mips.cc).
275   // ----------- S t a t e -------------
276   //  -- a1 : function
277   //  -- a2 : cache cell for call target
278   // -----------------------------------
279   Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit(), 0);
280 }
281
282
283 void Debug::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
284   // Calling convention for CallConstructStub (from code-stubs-mips.cc).
285   // ----------- S t a t e -------------
286   //  -- a0     : number of arguments (not smi)
287   //  -- a1     : constructor function
288   // -----------------------------------
289   Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit());
290 }
291
292
293 void Debug::GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm) {
294   // Calling convention for CallConstructStub (from code-stubs-mips.cc).
295   // ----------- S t a t e -------------
296   //  -- a0     : number of arguments (not smi)
297   //  -- a1     : constructor function
298   //  -- a2     : cache cell for call target
299   // -----------------------------------
300   Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit(), a0.bit());
301 }
302
303
304 void Debug::GenerateSlot(MacroAssembler* masm) {
305   // Generate enough nop's to make space for a call instruction. Avoid emitting
306   // the trampoline pool in the debug break slot code.
307   Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
308   Label check_codesize;
309   __ bind(&check_codesize);
310   __ RecordDebugBreakSlot();
311   for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
312     __ nop(MacroAssembler::DEBUG_BREAK_NOP);
313   }
314   ASSERT_EQ(Assembler::kDebugBreakSlotInstructions,
315             masm->InstructionsGeneratedSince(&check_codesize));
316 }
317
318
319 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
320   // In the places where a debug break slot is inserted no registers can contain
321   // object pointers.
322   Generate_DebugBreakCallHelper(masm, 0, 0);
323 }
324
325
326 void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
327   masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnMips);
328 }
329
330
331 void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
332   masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnMips);
333 }
334
335
336 const bool Debug::kFrameDropperSupported = false;
337
338 #undef __
339
340
341 #endif  // ENABLE_DEBUGGER_SUPPORT
342
343 } }  // namespace v8::internal
344
345 #endif  // V8_TARGET_ARCH_MIPS