Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / v8 / src / mips64 / debug-mips64.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
6
7 #include "src/v8.h"
8
9 #if V8_TARGET_ARCH_MIPS64
10
11 #include "src/codegen.h"
12 #include "src/debug.h"
13
14 namespace v8 {
15 namespace internal {
16
17 bool BreakLocationIterator::IsDebugBreakAtReturn() {
18   return Debug::IsDebugBreakAtReturn(rinfo());
19 }
20
21
22 void BreakLocationIterator::SetDebugBreakAtReturn() {
23   // Mips return sequence:
24   // mov sp, fp
25   // lw fp, sp(0)
26   // lw ra, sp(4)
27   // addiu sp, sp, 8
28   // addiu sp, sp, N
29   // jr ra
30   // nop (in branch delay slot)
31
32   // Make sure this constant matches the number if instructions we emit.
33   DCHECK(Assembler::kJSReturnSequenceInstructions == 7);
34   CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
35   // li and Call pseudo-instructions emit 6 + 2 instructions.
36   patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int64_t>(
37       debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry())),
38       ADDRESS_LOAD);
39   patcher.masm()->Call(v8::internal::t9);
40   // Place nop to match return sequence size.
41   patcher.masm()->nop();
42   // TODO(mips): Open issue about using breakpoint instruction instead of nops.
43   // patcher.masm()->bkpt(0);
44 }
45
46
47 // Restore the JS frame exit code.
48 void BreakLocationIterator::ClearDebugBreakAtReturn() {
49   rinfo()->PatchCode(original_rinfo()->pc(),
50                      Assembler::kJSReturnSequenceInstructions);
51 }
52
53
54 // A debug break in the exit code is identified by the JS frame exit code
55 // having been patched with li/call psuedo-instrunction (liu/ori/jalr).
56 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
57   DCHECK(RelocInfo::IsJSReturn(rinfo->rmode()));
58   return rinfo->IsPatchedReturnSequence();
59 }
60
61
62 bool BreakLocationIterator::IsDebugBreakAtSlot() {
63   DCHECK(IsDebugBreakSlot());
64   // Check whether the debug break slot instructions have been patched.
65   return rinfo()->IsPatchedDebugBreakSlotSequence();
66 }
67
68
69 void BreakLocationIterator::SetDebugBreakAtSlot() {
70   DCHECK(IsDebugBreakSlot());
71   // Patch the code changing the debug break slot code from:
72   //   nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
73   //   nop(DEBUG_BREAK_NOP)
74   //   nop(DEBUG_BREAK_NOP)
75   //   nop(DEBUG_BREAK_NOP)
76   //   nop(DEBUG_BREAK_NOP)
77   //   nop(DEBUG_BREAK_NOP)
78   // to a call to the debug break slot code.
79   //   li t9, address   (4-instruction sequence on mips64)
80   //   call t9          (jalr t9 / nop instruction pair)
81   CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
82   patcher.masm()->li(v8::internal::t9,
83       Operand(reinterpret_cast<int64_t>(
84           debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())),
85       ADDRESS_LOAD);
86   patcher.masm()->Call(v8::internal::t9);
87 }
88
89
90 void BreakLocationIterator::ClearDebugBreakAtSlot() {
91   DCHECK(IsDebugBreakSlot());
92   rinfo()->PatchCode(original_rinfo()->pc(),
93                      Assembler::kDebugBreakSlotInstructions);
94 }
95
96
97 #define __ ACCESS_MASM(masm)
98
99
100
101 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
102                                           RegList object_regs,
103                                           RegList non_object_regs) {
104   {
105     FrameScope scope(masm, StackFrame::INTERNAL);
106
107     // Load padding words on stack.
108     __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue)));
109     __ Dsubu(sp, sp,
110             Operand(kPointerSize * LiveEdit::kFramePaddingInitialSize));
111     for (int i = LiveEdit::kFramePaddingInitialSize - 1; i >= 0; i--) {
112       __ sd(at, MemOperand(sp, kPointerSize * i));
113     }
114     __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
115     __ push(at);
116
117
118     // TODO(plind): This needs to be revised to store pairs of smi's per
119     //    the other 64-bit arch's.
120
121     // Store the registers containing live values on the expression stack to
122     // make sure that these are correctly updated during GC. Non object values
123     // are stored as a smi causing it to be untouched by GC.
124     DCHECK((object_regs & ~kJSCallerSaved) == 0);
125     DCHECK((non_object_regs & ~kJSCallerSaved) == 0);
126     DCHECK((object_regs & non_object_regs) == 0);
127     for (int i = 0; i < kNumJSCallerSaved; i++) {
128       int r = JSCallerSavedCode(i);
129       Register reg = { r };
130       if ((object_regs & (1 << r)) != 0) {
131         __ push(reg);
132       }
133       if ((non_object_regs & (1 << r)) != 0) {
134         __ PushRegisterAsTwoSmis(reg);
135       }
136     }
137
138 #ifdef DEBUG
139     __ RecordComment("// Calling from debug break to runtime - come in - over");
140 #endif
141     __ PrepareCEntryArgs(0);  // No arguments.
142     __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate()));
143
144     CEntryStub ceb(masm->isolate(), 1);
145     __ CallStub(&ceb);
146
147     // Restore the register values from the expression stack.
148     for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
149       int r = JSCallerSavedCode(i);
150       Register reg = { r };
151       if ((non_object_regs & (1 << r)) != 0) {
152         __ PopRegisterAsTwoSmis(reg, at);
153       }
154       if ((object_regs & (1 << r)) != 0) {
155         __ pop(reg);
156       }
157       if (FLAG_debug_code &&
158           (((object_regs |non_object_regs) & (1 << r)) == 0)) {
159         __ li(reg, kDebugZapValue);
160       }
161     }
162
163     // Don't bother removing padding bytes pushed on the stack
164     // as the frame is going to be restored right away.
165
166     // Leave the internal frame.
167   }
168
169   // Now that the break point has been handled, resume normal execution by
170   // jumping to the target address intended by the caller and that was
171   // overwritten by the address of DebugBreakXXX.
172   ExternalReference after_break_target =
173       ExternalReference::debug_after_break_target_address(masm->isolate());
174   __ li(t9, Operand(after_break_target));
175   __ ld(t9, MemOperand(t9));
176   __ Jump(t9);
177 }
178
179
180 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
181   // Register state for CallICStub
182   // ----------- S t a t e -------------
183   //  -- a1 : function
184   //  -- a3 : slot in feedback array (smi)
185   // -----------------------------------
186   Generate_DebugBreakCallHelper(masm, a1.bit() | a3.bit(), 0);
187 }
188
189
190 void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
191   Register receiver = LoadDescriptor::ReceiverRegister();
192   Register name = LoadDescriptor::NameRegister();
193   Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0);
194 }
195
196
197 void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
198   Register receiver = StoreDescriptor::ReceiverRegister();
199   Register name = StoreDescriptor::NameRegister();
200   Register value = StoreDescriptor::ValueRegister();
201   Generate_DebugBreakCallHelper(
202       masm, receiver.bit() | name.bit() | value.bit(), 0);
203 }
204
205
206 void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
207   // Calling convention for keyed IC load (from ic-mips64.cc).
208   GenerateLoadICDebugBreak(masm);
209 }
210
211
212 void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
213   // Calling convention for IC keyed store call (from ic-mips64.cc).
214   Register receiver = StoreDescriptor::ReceiverRegister();
215   Register name = StoreDescriptor::NameRegister();
216   Register value = StoreDescriptor::ValueRegister();
217   Generate_DebugBreakCallHelper(
218       masm, receiver.bit() | name.bit() | value.bit(), 0);
219 }
220
221
222 void DebugCodegen::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
223   // Register state for CompareNil IC
224   // ----------- S t a t e -------------
225   //  -- a0    : value
226   // -----------------------------------
227   Generate_DebugBreakCallHelper(masm, a0.bit(), 0);
228 }
229
230
231 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
232   // In places other than IC call sites it is expected that v0 is TOS which
233   // is an object - this is not generally the case so this should be used with
234   // care.
235   Generate_DebugBreakCallHelper(masm, v0.bit(), 0);
236 }
237
238
239 void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
240   // Register state for CallFunctionStub (from code-stubs-mips.cc).
241   // ----------- S t a t e -------------
242   //  -- a1 : function
243   // -----------------------------------
244   Generate_DebugBreakCallHelper(masm, a1.bit(), 0);
245 }
246
247
248 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
249   // Calling convention for CallConstructStub (from code-stubs-mips.cc).
250   // ----------- S t a t e -------------
251   //  -- a0     : number of arguments (not smi)
252   //  -- a1     : constructor function
253   // -----------------------------------
254   Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit());
255 }
256
257
258
259 void DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
260     MacroAssembler* masm) {
261   // Calling convention for CallConstructStub (from code-stubs-mips.cc).
262   // ----------- S t a t e -------------
263   //  -- a0     : number of arguments (not smi)
264   //  -- a1     : constructor function
265   //  -- a2     : feedback array
266   //  -- a3     : feedback slot (smi)
267   // -----------------------------------
268   Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit() | a3.bit(), a0.bit());
269 }
270
271
272 void DebugCodegen::GenerateSlot(MacroAssembler* masm) {
273   // Generate enough nop's to make space for a call instruction. Avoid emitting
274   // the trampoline pool in the debug break slot code.
275   Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
276   Label check_codesize;
277   __ bind(&check_codesize);
278   __ RecordDebugBreakSlot();
279   for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
280     __ nop(MacroAssembler::DEBUG_BREAK_NOP);
281   }
282   DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
283             masm->InstructionsGeneratedSince(&check_codesize));
284 }
285
286
287 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
288   // In the places where a debug break slot is inserted no registers can contain
289   // object pointers.
290   Generate_DebugBreakCallHelper(masm, 0, 0);
291 }
292
293
294 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
295   __ Ret();
296 }
297
298
299 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
300   ExternalReference restarter_frame_function_slot =
301       ExternalReference::debug_restarter_frame_function_pointer_address(
302           masm->isolate());
303   __ li(at, Operand(restarter_frame_function_slot));
304   __ sw(zero_reg, MemOperand(at, 0));
305
306   // We do not know our frame height, but set sp based on fp.
307   __ Dsubu(sp, fp, Operand(kPointerSize));
308
309   __ Pop(ra, fp, a1);  // Return address, Frame, Function.
310
311   // Load context from the function.
312   __ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
313
314   // Get function code.
315   __ ld(at, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
316   __ ld(at, FieldMemOperand(at, SharedFunctionInfo::kCodeOffset));
317   __ Daddu(t9, at, Operand(Code::kHeaderSize - kHeapObjectTag));
318
319   // Re-run JSFunction, a1 is function, cp is context.
320   __ Jump(t9);
321 }
322
323
324 const bool LiveEdit::kFrameDropperSupported = true;
325
326 #undef __
327
328 } }  // namespace v8::internal
329
330 #endif  // V8_TARGET_ARCH_MIPS64