v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
debug-arm.cc
Go to the documentation of this file.
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 #include "v8.h"
29 
30 #if V8_TARGET_ARCH_ARM
31 
32 #include "codegen.h"
33 #include "debug.h"
34 
35 namespace v8 {
36 namespace internal {
37 
38 #ifdef ENABLE_DEBUGGER_SUPPORT
39 bool BreakLocationIterator::IsDebugBreakAtReturn() {
40  return Debug::IsDebugBreakAtReturn(rinfo());
41 }
42 
43 
44 void BreakLocationIterator::SetDebugBreakAtReturn() {
45  // Patch the code changing the return from JS function sequence from
46  // mov sp, fp
47  // ldmia sp!, {fp, lr}
48  // add sp, sp, #4
49  // bx lr
50  // to a call to the debug break return code.
51  // ldr ip, [pc, #0]
52  // blx ip
53  // <debug break return code entry point address>
54  // bktp 0
55  CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
56  patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
57  patcher.masm()->blx(v8::internal::ip);
58  patcher.Emit(
59  debug_info_->GetIsolate()->debug()->debug_break_return()->entry());
60  patcher.masm()->bkpt(0);
61 }
62 
63 
64 // Restore the JS frame exit code.
65 void BreakLocationIterator::ClearDebugBreakAtReturn() {
66  rinfo()->PatchCode(original_rinfo()->pc(),
68 }
69 
70 
71 // A debug break in the frame exit code is identified by the JS frame exit code
72 // having been patched with a call instruction.
73 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
74  ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
75  return rinfo->IsPatchedReturnSequence();
76 }
77 
78 
79 bool BreakLocationIterator::IsDebugBreakAtSlot() {
80  ASSERT(IsDebugBreakSlot());
81  // Check whether the debug break slot instructions have been patched.
82  return rinfo()->IsPatchedDebugBreakSlotSequence();
83 }
84 
85 
86 void BreakLocationIterator::SetDebugBreakAtSlot() {
87  ASSERT(IsDebugBreakSlot());
88  // Patch the code changing the debug break slot code from
89  // mov r2, r2
90  // mov r2, r2
91  // mov r2, r2
92  // to a call to the debug break slot code.
93  // ldr ip, [pc, #0]
94  // blx ip
95  // <debug break slot code entry point address>
96  CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
97  patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
98  patcher.masm()->blx(v8::internal::ip);
99  patcher.Emit(
100  debug_info_->GetIsolate()->debug()->debug_break_slot()->entry());
101 }
102 
103 
104 void BreakLocationIterator::ClearDebugBreakAtSlot() {
105  ASSERT(IsDebugBreakSlot());
106  rinfo()->PatchCode(original_rinfo()->pc(),
108 }
109 
110 const bool Debug::FramePaddingLayout::kIsSupported = false;
111 
112 
113 #define __ ACCESS_MASM(masm)
114 
115 
116 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
117  RegList object_regs,
118  RegList non_object_regs) {
119  {
120  FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
121 
122  // Store the registers containing live values on the expression stack to
123  // make sure that these are correctly updated during GC. Non object values
124  // are stored as a smi causing it to be untouched by GC.
125  ASSERT((object_regs & ~kJSCallerSaved) == 0);
126  ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
127  ASSERT((object_regs & non_object_regs) == 0);
128  if ((object_regs | non_object_regs) != 0) {
129  for (int i = 0; i < kNumJSCallerSaved; i++) {
130  int r = JSCallerSavedCode(i);
131  Register reg = { r };
132  if ((non_object_regs & (1 << r)) != 0) {
133  if (FLAG_debug_code) {
134  __ tst(reg, Operand(0xc0000000));
135  __ Assert(eq, kUnableToEncodeValueAsSmi);
136  }
137  __ SmiTag(reg);
138  }
139  }
140  __ stm(db_w, sp, object_regs | non_object_regs);
141  }
142 
143 #ifdef DEBUG
144  __ RecordComment("// Calling from debug break to runtime - come in - over");
145 #endif
146  __ mov(r0, Operand::Zero()); // no arguments
147  __ mov(r1, Operand(ExternalReference::debug_break(masm->isolate())));
148 
149  CEntryStub ceb(1);
150  __ CallStub(&ceb);
151 
152  // Restore the register values from the expression stack.
153  if ((object_regs | non_object_regs) != 0) {
154  __ ldm(ia_w, sp, object_regs | non_object_regs);
155  for (int i = 0; i < kNumJSCallerSaved; i++) {
156  int r = JSCallerSavedCode(i);
157  Register reg = { r };
158  if ((non_object_regs & (1 << r)) != 0) {
159  __ SmiUntag(reg);
160  }
161  if (FLAG_debug_code &&
162  (((object_regs |non_object_regs) & (1 << r)) == 0)) {
163  __ mov(reg, Operand(kDebugZapValue));
164  }
165  }
166  }
167 
168  // Leave the internal frame.
169  }
170 
171  // Now that the break point has been handled, resume normal execution by
172  // jumping to the target address intended by the caller and that was
173  // overwritten by the address of DebugBreakXXX.
174  ExternalReference after_break_target =
175  ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate());
176  __ mov(ip, Operand(after_break_target));
177  __ ldr(ip, MemOperand(ip));
178  __ Jump(ip);
179 }
180 
181 
182 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
183  // Calling convention for IC load (from ic-arm.cc).
184  // ----------- S t a t e -------------
185  // -- r2 : name
186  // -- lr : return address
187  // -- r0 : receiver
188  // -- [sp] : receiver
189  // -----------------------------------
190  // Registers r0 and r2 contain objects that need to be pushed on the
191  // expression stack of the fake JS frame.
192  Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit(), 0);
193 }
194 
195 
196 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
197  // Calling convention for IC store (from ic-arm.cc).
198  // ----------- S t a t e -------------
199  // -- r0 : value
200  // -- r1 : receiver
201  // -- r2 : name
202  // -- lr : return address
203  // -----------------------------------
204  // Registers r0, r1, and r2 contain objects that need to be pushed on the
205  // expression stack of the fake JS frame.
206  Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
207 }
208 
209 
210 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
211  // ---------- S t a t e --------------
212  // -- lr : return address
213  // -- r0 : key
214  // -- r1 : receiver
215  Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit(), 0);
216 }
217 
218 
219 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
220  // ---------- S t a t e --------------
221  // -- r0 : value
222  // -- r1 : key
223  // -- r2 : receiver
224  // -- lr : return address
225  Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
226 }
227 
228 
229 void Debug::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
230  // Register state for CompareNil IC
231  // ----------- S t a t e -------------
232  // -- r0 : value
233  // -----------------------------------
234  Generate_DebugBreakCallHelper(masm, r0.bit(), 0);
235 }
236 
237 
238 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
239  // Calling convention for IC call (from ic-arm.cc)
240  // ----------- S t a t e -------------
241  // -- r2 : name
242  // -----------------------------------
243  Generate_DebugBreakCallHelper(masm, r2.bit(), 0);
244 }
245 
246 
247 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
248  // In places other than IC call sites it is expected that r0 is TOS which
249  // is an object - this is not generally the case so this should be used with
250  // care.
251  Generate_DebugBreakCallHelper(masm, r0.bit(), 0);
252 }
253 
254 
255 void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
256  // Register state for CallFunctionStub (from code-stubs-arm.cc).
257  // ----------- S t a t e -------------
258  // -- r1 : function
259  // -----------------------------------
260  Generate_DebugBreakCallHelper(masm, r1.bit(), 0);
261 }
262 
263 
264 void Debug::GenerateCallFunctionStubRecordDebugBreak(MacroAssembler* masm) {
265  // Register state for CallFunctionStub (from code-stubs-arm.cc).
266  // ----------- S t a t e -------------
267  // -- r1 : function
268  // -- r2 : feedback array
269  // -- r3 : slot in feedback array
270  // -----------------------------------
271  Generate_DebugBreakCallHelper(masm, r1.bit() | r2.bit() | r3.bit(), 0);
272 }
273 
274 
275 void Debug::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
276  // Calling convention for CallConstructStub (from code-stubs-arm.cc)
277  // ----------- S t a t e -------------
278  // -- r0 : number of arguments (not smi)
279  // -- r1 : constructor function
280  // -----------------------------------
281  Generate_DebugBreakCallHelper(masm, r1.bit(), r0.bit());
282 }
283 
284 
285 void Debug::GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm) {
286  // Calling convention for CallConstructStub (from code-stubs-arm.cc)
287  // ----------- S t a t e -------------
288  // -- r0 : number of arguments (not smi)
289  // -- r1 : constructor function
290  // -- r2 : feedback array
291  // -- r3 : feedback slot (smi)
292  // -----------------------------------
293  Generate_DebugBreakCallHelper(masm, r1.bit() | r2.bit() | r3.bit(), r0.bit());
294 }
295 
296 
297 void Debug::GenerateSlot(MacroAssembler* masm) {
298  // Generate enough nop's to make space for a call instruction. Avoid emitting
299  // the constant pool in the debug break slot code.
300  Assembler::BlockConstPoolScope block_const_pool(masm);
301  Label check_codesize;
302  __ bind(&check_codesize);
303  __ RecordDebugBreakSlot();
304  for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
306  }
307  ASSERT_EQ(Assembler::kDebugBreakSlotInstructions,
308  masm->InstructionsGeneratedSince(&check_codesize));
309 }
310 
311 
312 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
313  // In the places where a debug break slot is inserted no registers can contain
314  // object pointers.
315  Generate_DebugBreakCallHelper(masm, 0, 0);
316 }
317 
318 
319 void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
320  masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnArm);
321 }
322 
323 
324 void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
325  masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnArm);
326 }
327 
328 const bool Debug::kFrameDropperSupported = false;
329 
330 #undef __
331 
332 
333 
334 #endif // ENABLE_DEBUGGER_SUPPORT
335 
336 } } // namespace v8::internal
337 
338 #endif // V8_TARGET_ARCH_ARM
static const int kDebugBreakSlotInstructions
const Register r3
uint32_t RegList
Definition: frames.h:41
#define ASSERT(condition)
Definition: checks.h:329
const RegList kJSCallerSaved
Definition: frames-arm.h:47
friend class BlockConstPoolScope
const Register r2
int JSCallerSavedCode(int n)
Definition: frames.cc:1610
const Register sp
const Register ip
#define __
const Register pc
const int kNumJSCallerSaved
Definition: frames-arm.h:53
const Register r0
const Register r1
#define ASSERT_EQ(v1, v2)
Definition: checks.h:330
static const int kJSReturnSequenceInstructions
const uint32_t kDebugZapValue
Definition: v8globals.h:87