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