Update To 11.40.268.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 "src/v8.h"
6
7 #if V8_TARGET_ARCH_ARM
8
9 #include "src/codegen.h"
10 #include "src/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   //   bkpt 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   DCHECK(RelocInfo::IsJSReturn(rinfo->rmode()));
51   return rinfo->IsPatchedReturnSequence();
52 }
53
54
55 bool BreakLocationIterator::IsDebugBreakAtSlot() {
56   DCHECK(IsDebugBreakSlot());
57   // Check whether the debug break slot instructions have been patched.
58   return rinfo()->IsPatchedDebugBreakSlotSequence();
59 }
60
61
62 void BreakLocationIterator::SetDebugBreakAtSlot() {
63   DCHECK(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   DCHECK(IsDebugBreakSlot());
82   rinfo()->PatchCode(original_rinfo()->pc(),
83                      Assembler::kDebugBreakSlotInstructions);
84 }
85
86
87 #define __ ACCESS_MASM(masm)
88
89
90 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
91                                           RegList object_regs,
92                                           RegList non_object_regs) {
93   {
94     FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
95
96     // Load padding words on stack.
97     __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue)));
98     for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
99       __ push(ip);
100     }
101     __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
102     __ push(ip);
103
104     // Store the registers containing live values on the expression stack to
105     // make sure that these are correctly updated during GC. Non object values
106     // are stored as a smi causing it to be untouched by GC.
107     DCHECK((object_regs & ~kJSCallerSaved) == 0);
108     DCHECK((non_object_regs & ~kJSCallerSaved) == 0);
109     DCHECK((object_regs & non_object_regs) == 0);
110     if ((object_regs | non_object_regs) != 0) {
111       for (int i = 0; i < kNumJSCallerSaved; i++) {
112         int r = JSCallerSavedCode(i);
113         Register reg = { r };
114         if ((non_object_regs & (1 << r)) != 0) {
115           if (FLAG_debug_code) {
116             __ tst(reg, Operand(0xc0000000));
117             __ Assert(eq, kUnableToEncodeValueAsSmi);
118           }
119           __ SmiTag(reg);
120         }
121       }
122       __ stm(db_w, sp, object_regs | non_object_regs);
123     }
124
125 #ifdef DEBUG
126     __ RecordComment("// Calling from debug break to runtime - come in - over");
127 #endif
128     __ mov(r0, Operand::Zero());  // no arguments
129     __ mov(r1, Operand(ExternalReference::debug_break(masm->isolate())));
130
131     CEntryStub ceb(masm->isolate(), 1);
132     __ CallStub(&ceb);
133
134     // Restore the register values from the expression stack.
135     if ((object_regs | non_object_regs) != 0) {
136       __ ldm(ia_w, sp, object_regs | non_object_regs);
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           __ SmiUntag(reg);
142         }
143         if (FLAG_debug_code &&
144             (((object_regs |non_object_regs) & (1 << r)) == 0)) {
145           __ mov(reg, Operand(kDebugZapValue));
146         }
147       }
148     }
149
150     // Don't bother removing padding bytes pushed on the stack
151     // as the frame is going to be restored right away.
152
153     // Leave the internal frame.
154   }
155
156   // Now that the break point has been handled, resume normal execution by
157   // jumping to the target address intended by the caller and that was
158   // overwritten by the address of DebugBreakXXX.
159   ExternalReference after_break_target =
160       ExternalReference::debug_after_break_target_address(masm->isolate());
161   __ mov(ip, Operand(after_break_target));
162   __ ldr(ip, MemOperand(ip));
163   __ Jump(ip);
164 }
165
166
167 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
168   // Register state for CallICStub
169   // ----------- S t a t e -------------
170   //  -- r1 : function
171   //  -- r3 : slot in feedback array (smi)
172   // -----------------------------------
173   Generate_DebugBreakCallHelper(masm, r1.bit() | r3.bit(), 0);
174 }
175
176
177 void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
178   // Calling convention for IC load (from ic-arm.cc).
179   Register receiver = LoadDescriptor::ReceiverRegister();
180   Register name = LoadDescriptor::NameRegister();
181   RegList regs = receiver.bit() | name.bit();
182   if (FLAG_vector_ics) {
183     regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
184   }
185   Generate_DebugBreakCallHelper(masm, regs, 0);
186 }
187
188
189 void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
190   // Calling convention for IC store (from ic-arm.cc).
191   Register receiver = StoreDescriptor::ReceiverRegister();
192   Register name = StoreDescriptor::NameRegister();
193   Register value = StoreDescriptor::ValueRegister();
194   Generate_DebugBreakCallHelper(
195       masm, receiver.bit() | name.bit() | value.bit(), 0);
196 }
197
198
199 void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
200   // Calling convention for keyed IC load (from ic-arm.cc).
201   GenerateLoadICDebugBreak(masm);
202 }
203
204
205 void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
206   // Calling convention for IC keyed store call (from ic-arm.cc).
207   Register receiver = StoreDescriptor::ReceiverRegister();
208   Register name = StoreDescriptor::NameRegister();
209   Register value = StoreDescriptor::ValueRegister();
210   Generate_DebugBreakCallHelper(
211       masm, receiver.bit() | name.bit() | value.bit(), 0);
212 }
213
214
215 void DebugCodegen::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 DebugCodegen::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 DebugCodegen::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 DebugCodegen::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 DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
252     MacroAssembler* masm) {
253   // Calling convention for CallConstructStub (from code-stubs-arm.cc)
254   // ----------- S t a t e -------------
255   //  -- r0     : number of arguments (not smi)
256   //  -- r1     : constructor function
257   //  -- r2     : feedback array
258   //  -- r3     : feedback slot (smi)
259   // -----------------------------------
260   Generate_DebugBreakCallHelper(masm, r1.bit() | r2.bit() | r3.bit(), r0.bit());
261 }
262
263
264 void DebugCodegen::GenerateSlot(MacroAssembler* masm) {
265   // Generate enough nop's to make space for a call instruction. Avoid emitting
266   // the constant pool in the debug break slot code.
267   Assembler::BlockConstPoolScope block_const_pool(masm);
268   Label check_codesize;
269   __ bind(&check_codesize);
270   __ RecordDebugBreakSlot();
271   for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
272     __ nop(MacroAssembler::DEBUG_BREAK_NOP);
273   }
274   DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
275             masm->InstructionsGeneratedSince(&check_codesize));
276 }
277
278
279 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
280   // In the places where a debug break slot is inserted no registers can contain
281   // object pointers.
282   Generate_DebugBreakCallHelper(masm, 0, 0);
283 }
284
285
286 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
287   __ Ret();
288 }
289
290
291 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
292   ExternalReference restarter_frame_function_slot =
293       ExternalReference::debug_restarter_frame_function_pointer_address(
294           masm->isolate());
295   __ mov(ip, Operand(restarter_frame_function_slot));
296   __ mov(r1, Operand::Zero());
297   __ str(r1, MemOperand(ip, 0));
298
299   // Load the function pointer off of our current stack frame.
300   __ ldr(r1, MemOperand(fp,
301          StandardFrameConstants::kConstantPoolOffset - kPointerSize));
302
303   // Pop return address, frame and constant pool pointer (if
304   // FLAG_enable_ool_constant_pool).
305   __ LeaveFrame(StackFrame::INTERNAL);
306
307   { ConstantPoolUnavailableScope constant_pool_unavailable(masm);
308     // Load context from the function.
309     __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
310
311     // Get function code.
312     __ ldr(ip, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
313     __ ldr(ip, FieldMemOperand(ip, SharedFunctionInfo::kCodeOffset));
314     __ add(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
315
316     // Re-run JSFunction, r1 is function, cp is context.
317     __ Jump(ip);
318   }
319 }
320
321
322 const bool LiveEdit::kFrameDropperSupported = true;
323
324 #undef __
325
326 } }  // namespace v8::internal
327
328 #endif  // V8_TARGET_ARCH_ARM