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