• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 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 defined(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 
IsDebugBreakAtReturn()42 bool BreakLocationIterator::IsDebugBreakAtReturn() {
43   return Debug::IsDebugBreakAtReturn(rinfo());
44 }
45 
46 
SetDebugBreakAtReturn()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           Isolate::Current()->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.
ClearDebugBreakAtReturn()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).
IsDebugBreakAtReturn(RelocInfo * rinfo)83 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
84   ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
85   return rinfo->IsPatchedReturnSequence();
86 }
87 
88 
IsDebugBreakAtSlot()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 
SetDebugBreakAtSlot()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       Isolate::Current()->debug()->debug_break_slot()->entry())));
109   patcher.masm()->Call(v8::internal::t9);
110 }
111 
112 
ClearDebugBreakAtSlot()113 void BreakLocationIterator::ClearDebugBreakAtSlot() {
114   ASSERT(IsDebugBreakSlot());
115   rinfo()->PatchCode(original_rinfo()->pc(),
116                      Assembler::kDebugBreakSlotInstructions);
117 }
118 
119 
120 #define __ ACCESS_MASM(masm)
121 
122 
123 
Generate_DebugBreakCallHelper(MacroAssembler * masm,RegList object_regs,RegList non_object_regs)124 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
125                                           RegList object_regs,
126                                           RegList non_object_regs) {
127   {
128     FrameScope scope(masm, StackFrame::INTERNAL);
129 
130     // Store the registers containing live values on the expression stack to
131     // make sure that these are correctly updated during GC. Non object values
132     // are stored as a smi causing it to be untouched by GC.
133     ASSERT((object_regs & ~kJSCallerSaved) == 0);
134     ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
135     ASSERT((object_regs & non_object_regs) == 0);
136     if ((object_regs | non_object_regs) != 0) {
137       for (int i = 0; i < kNumJSCallerSaved; i++) {
138         int r = JSCallerSavedCode(i);
139         Register reg = { r };
140         if ((non_object_regs & (1 << r)) != 0) {
141           if (FLAG_debug_code) {
142             __ And(at, reg, 0xc0000000);
143             __ Assert(
144                 eq, "Unable to encode value as smi", at, Operand(zero_reg));
145           }
146           __ sll(reg, reg, kSmiTagSize);
147         }
148       }
149       __ MultiPush(object_regs | non_object_regs);
150     }
151 
152 #ifdef DEBUG
153     __ RecordComment("// Calling from debug break to runtime - come in - over");
154 #endif
155     __ PrepareCEntryArgs(0);  // No arguments.
156     __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate()));
157 
158     CEntryStub ceb(1);
159     __ CallStub(&ceb);
160 
161     // Restore the register values from the expression stack.
162     if ((object_regs | non_object_regs) != 0) {
163       __ MultiPop(object_regs | non_object_regs);
164       for (int i = 0; i < kNumJSCallerSaved; i++) {
165         int r = JSCallerSavedCode(i);
166         Register reg = { r };
167         if ((non_object_regs & (1 << r)) != 0) {
168           __ srl(reg, reg, kSmiTagSize);
169         }
170         if (FLAG_debug_code &&
171             (((object_regs |non_object_regs) & (1 << r)) == 0)) {
172           __ li(reg, kDebugZapValue);
173         }
174       }
175     }
176 
177     // Leave the internal frame.
178   }
179 
180   // Now that the break point has been handled, resume normal execution by
181   // jumping to the target address intended by the caller and that was
182   // overwritten by the address of DebugBreakXXX.
183   __ li(t9, Operand(
184       ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate())));
185   __ lw(t9, MemOperand(t9));
186   __ Jump(t9);
187 }
188 
189 
GenerateLoadICDebugBreak(MacroAssembler * masm)190 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
191   // Calling convention for IC load (from ic-mips.cc).
192   // ----------- S t a t e -------------
193   //  -- a2    : name
194   //  -- ra    : return address
195   //  -- a0    : receiver
196   //  -- [sp]  : receiver
197   // -----------------------------------
198   // Registers a0 and a2 contain objects that need to be pushed on the
199   // expression stack of the fake JS frame.
200   Generate_DebugBreakCallHelper(masm, a0.bit() | a2.bit(), 0);
201 }
202 
203 
GenerateStoreICDebugBreak(MacroAssembler * masm)204 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
205   // Calling convention for IC store (from ic-mips.cc).
206   // ----------- S t a t e -------------
207   //  -- a0    : value
208   //  -- a1    : receiver
209   //  -- a2    : name
210   //  -- ra    : return address
211   // -----------------------------------
212   // Registers a0, a1, and a2 contain objects that need to be pushed on the
213   // expression stack of the fake JS frame.
214   Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
215 }
216 
217 
GenerateKeyedLoadICDebugBreak(MacroAssembler * masm)218 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
219   // ---------- S t a t e --------------
220   //  -- ra  : return address
221   //  -- a0  : key
222   //  -- a1  : receiver
223   Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit(), 0);
224 }
225 
226 
GenerateKeyedStoreICDebugBreak(MacroAssembler * masm)227 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
228   // ---------- S t a t e --------------
229   //  -- a0     : value
230   //  -- a1     : key
231   //  -- a2     : receiver
232   //  -- ra     : return address
233   Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
234 }
235 
236 
GenerateCallICDebugBreak(MacroAssembler * masm)237 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
238   // Calling convention for IC call (from ic-mips.cc).
239   // ----------- S t a t e -------------
240   //  -- a2: name
241   // -----------------------------------
242   Generate_DebugBreakCallHelper(masm, a2.bit(), 0);
243 }
244 
245 
GenerateReturnDebugBreak(MacroAssembler * masm)246 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
247   // In places other than IC call sites it is expected that v0 is TOS which
248   // is an object - this is not generally the case so this should be used with
249   // care.
250   Generate_DebugBreakCallHelper(masm, v0.bit(), 0);
251 }
252 
253 
GenerateCallFunctionStubDebugBreak(MacroAssembler * masm)254 void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
255   // Register state for CallFunctionStub (from code-stubs-mips.cc).
256   // ----------- S t a t e -------------
257   //  -- a1 : function
258   // -----------------------------------
259   Generate_DebugBreakCallHelper(masm, a1.bit(), 0);
260 }
261 
262 
GenerateCallFunctionStubRecordDebugBreak(MacroAssembler * masm)263 void Debug::GenerateCallFunctionStubRecordDebugBreak(MacroAssembler* masm) {
264   // Register state for CallFunctionStub (from code-stubs-mips.cc).
265   // ----------- S t a t e -------------
266   //  -- a1 : function
267   //  -- a2 : cache cell for call target
268   // -----------------------------------
269   Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit(), 0);
270 }
271 
272 
GenerateCallConstructStubDebugBreak(MacroAssembler * masm)273 void Debug::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
274   // Calling convention for CallConstructStub (from code-stubs-mips.cc).
275   // ----------- S t a t e -------------
276   //  -- a0     : number of arguments (not smi)
277   //  -- a1     : constructor function
278   // -----------------------------------
279   Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit());
280 }
281 
282 
GenerateCallConstructStubRecordDebugBreak(MacroAssembler * masm)283 void Debug::GenerateCallConstructStubRecordDebugBreak(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   //  -- a2     : cache cell for call target
289   // -----------------------------------
290   Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit(), a0.bit());
291 }
292 
293 
GenerateSlot(MacroAssembler * masm)294 void Debug::GenerateSlot(MacroAssembler* masm) {
295   // Generate enough nop's to make space for a call instruction. Avoid emitting
296   // the trampoline pool in the debug break slot code.
297   Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
298   Label check_codesize;
299   __ bind(&check_codesize);
300   __ RecordDebugBreakSlot();
301   for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
302     __ nop(MacroAssembler::DEBUG_BREAK_NOP);
303   }
304   ASSERT_EQ(Assembler::kDebugBreakSlotInstructions,
305             masm->InstructionsGeneratedSince(&check_codesize));
306 }
307 
308 
GenerateSlotDebugBreak(MacroAssembler * masm)309 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
310   // In the places where a debug break slot is inserted no registers can contain
311   // object pointers.
312   Generate_DebugBreakCallHelper(masm, 0, 0);
313 }
314 
315 
GeneratePlainReturnLiveEdit(MacroAssembler * masm)316 void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
317   masm->Abort("LiveEdit frame dropping is not supported on mips");
318 }
319 
320 
GenerateFrameDropperLiveEdit(MacroAssembler * masm)321 void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
322   masm->Abort("LiveEdit frame dropping is not supported on mips");
323 }
324 
325 
326 const bool Debug::kFrameDropperSupported = false;
327 
328 #undef __
329 
330 
331 #endif  // ENABLE_DEBUGGER_SUPPORT
332 
333 } }  // namespace v8::internal
334 
335 #endif  // V8_TARGET_ARCH_MIPS
336