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