deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / x64 / debug-x64.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_X64
8
9 #include "src/assembler.h"
10 #include "src/codegen.h"
11 #include "src/debug.h"
12
13
14 namespace v8 {
15 namespace internal {
16
17 // Patch the code at the current PC with a call to the target address.
18 // Additional guard int3 instructions can be added if required.
19 void PatchCodeWithCall(Address pc, Address target, int guard_bytes) {
20   int code_size = Assembler::kCallSequenceLength + guard_bytes;
21
22   // Create a code patcher.
23   CodePatcher patcher(pc, code_size);
24
25 // Add a label for checking the size of the code used for returning.
26 #ifdef DEBUG
27   Label check_codesize;
28   patcher.masm()->bind(&check_codesize);
29 #endif
30
31   // Patch the code.
32   patcher.masm()->movp(kScratchRegister, reinterpret_cast<void*>(target),
33                        Assembler::RelocInfoNone());
34   patcher.masm()->call(kScratchRegister);
35
36   // Check that the size of the code generated is as expected.
37   DCHECK_EQ(Assembler::kCallSequenceLength,
38             patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
39
40   // Add the requested number of int3 instructions after the call.
41   for (int i = 0; i < guard_bytes; i++) {
42     patcher.masm()->int3();
43   }
44
45   CpuFeatures::FlushICache(pc, code_size);
46 }
47
48
49 // Patch the JS frame exit code with a debug break call. See
50 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc
51 // for the precise return instructions sequence.
52 void BreakLocation::SetDebugBreakAtReturn() {
53   DCHECK(Assembler::kJSReturnSequenceLength >= Assembler::kCallSequenceLength);
54   PatchCodeWithCall(
55       pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
56       Assembler::kJSReturnSequenceLength - Assembler::kCallSequenceLength);
57 }
58
59
60 void BreakLocation::SetDebugBreakAtSlot() {
61   DCHECK(IsDebugBreakSlot());
62   PatchCodeWithCall(
63       pc(), debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry(),
64       Assembler::kDebugBreakSlotLength - Assembler::kCallSequenceLength);
65 }
66
67
68 #define __ ACCESS_MASM(masm)
69
70
71 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
72                                           RegList object_regs,
73                                           RegList non_object_regs,
74                                           bool convert_call_to_jmp) {
75   // Enter an internal frame.
76   {
77     FrameScope scope(masm, StackFrame::INTERNAL);
78
79     // Load padding words on stack.
80     for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
81       __ Push(Smi::FromInt(LiveEdit::kFramePaddingValue));
82     }
83     __ Push(Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
84
85     // Store the registers containing live values on the expression stack to
86     // make sure that these are correctly updated during GC. Non object values
87     // are stored as as two smis causing it to be untouched by GC.
88     DCHECK((object_regs & ~kJSCallerSaved) == 0);
89     DCHECK((non_object_regs & ~kJSCallerSaved) == 0);
90     DCHECK((object_regs & non_object_regs) == 0);
91     for (int i = 0; i < kNumJSCallerSaved; i++) {
92       int r = JSCallerSavedCode(i);
93       Register reg = { r };
94       DCHECK(!reg.is(kScratchRegister));
95       if ((object_regs & (1 << r)) != 0) {
96         __ Push(reg);
97       }
98       if ((non_object_regs & (1 << r)) != 0) {
99         __ PushRegisterAsTwoSmis(reg);
100       }
101     }
102
103 #ifdef DEBUG
104     __ RecordComment("// Calling from debug break to runtime - come in - over");
105 #endif
106     __ Set(rax, 0);  // No arguments (argc == 0).
107     __ Move(rbx, ExternalReference::debug_break(masm->isolate()));
108
109     CEntryStub ceb(masm->isolate(), 1);
110     __ CallStub(&ceb);
111
112     // Restore the register values from the expression stack.
113     for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
114       int r = JSCallerSavedCode(i);
115       Register reg = { r };
116       if (FLAG_debug_code) {
117         __ Set(reg, kDebugZapValue);
118       }
119       if ((object_regs & (1 << r)) != 0) {
120         __ Pop(reg);
121       }
122       // Reconstruct the 64-bit value from two smis.
123       if ((non_object_regs & (1 << r)) != 0) {
124         __ PopRegisterAsTwoSmis(reg);
125       }
126     }
127
128     // Read current padding counter and skip corresponding number of words.
129     __ Pop(kScratchRegister);
130     __ SmiToInteger32(kScratchRegister, kScratchRegister);
131     __ leap(rsp, Operand(rsp, kScratchRegister, times_pointer_size, 0));
132
133     // Get rid of the internal frame.
134   }
135
136   // If this call did not replace a call but patched other code then there will
137   // be an unwanted return address left on the stack. Here we get rid of that.
138   if (convert_call_to_jmp) {
139     __ addp(rsp, Immediate(kPCOnStackSize));
140   }
141
142   // Now that the break point has been handled, resume normal execution by
143   // jumping to the target address intended by the caller and that was
144   // overwritten by the address of DebugBreakXXX.
145   ExternalReference after_break_target =
146       ExternalReference::debug_after_break_target_address(masm->isolate());
147   __ Move(kScratchRegister, after_break_target);
148   __ Jump(Operand(kScratchRegister, 0));
149 }
150
151
152 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
153   // Register state for CallICStub
154   // ----------- S t a t e -------------
155   //  -- rdx    : type feedback slot (smi)
156   //  -- rdi    : function
157   // -----------------------------------
158   Generate_DebugBreakCallHelper(masm, rdx.bit() | rdi.bit(), 0, false);
159 }
160
161
162 void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
163   // Register state for IC load call (from ic-x64.cc).
164   Register receiver = LoadDescriptor::ReceiverRegister();
165   Register name = LoadDescriptor::NameRegister();
166   RegList regs = receiver.bit() | name.bit();
167   if (FLAG_vector_ics) {
168     regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
169   }
170   Generate_DebugBreakCallHelper(masm, regs, 0, false);
171 }
172
173
174 void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
175   // Register state for IC store call (from ic-x64.cc).
176   Register receiver = StoreDescriptor::ReceiverRegister();
177   Register name = StoreDescriptor::NameRegister();
178   Register value = StoreDescriptor::ValueRegister();
179   Generate_DebugBreakCallHelper(
180       masm, receiver.bit() | name.bit() | value.bit(), 0, false);
181 }
182
183
184 void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
185   // Register state for keyed IC load call (from ic-x64.cc).
186   GenerateLoadICDebugBreak(masm);
187 }
188
189
190 void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
191   // Register state for keyed IC store call (from ic-x64.cc).
192   Register receiver = StoreDescriptor::ReceiverRegister();
193   Register name = StoreDescriptor::NameRegister();
194   Register value = StoreDescriptor::ValueRegister();
195   Generate_DebugBreakCallHelper(
196       masm, receiver.bit() | name.bit() | value.bit(), 0, false);
197 }
198
199
200 void DebugCodegen::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
201   // Register state for CompareNil IC
202   // ----------- S t a t e -------------
203   //  -- rax    : value
204   // -----------------------------------
205   Generate_DebugBreakCallHelper(masm, rax.bit(), 0, false);
206 }
207
208
209 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
210   // Register state just before return from JS function (from codegen-x64.cc).
211   // ----------- S t a t e -------------
212   //  -- rax: return value
213   // -----------------------------------
214   Generate_DebugBreakCallHelper(masm, rax.bit(), 0, true);
215 }
216
217
218 void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
219   // Register state for CallFunctionStub (from code-stubs-x64.cc).
220   // ----------- S t a t e -------------
221   //  -- rdi : function
222   // -----------------------------------
223   Generate_DebugBreakCallHelper(masm, rdi.bit(), 0, false);
224 }
225
226
227 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
228   // Register state for CallConstructStub (from code-stubs-x64.cc).
229   // rax is the actual number of arguments not encoded as a smi, see comment
230   // above IC call.
231   // ----------- S t a t e -------------
232   //  -- rax: number of arguments
233   // -----------------------------------
234   // The number of arguments in rax is not smi encoded.
235   Generate_DebugBreakCallHelper(masm, rdi.bit(), rax.bit(), false);
236 }
237
238
239 void DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
240     MacroAssembler* masm) {
241   // Register state for CallConstructStub (from code-stubs-x64.cc).
242   // rax is the actual number of arguments not encoded as a smi, see comment
243   // above IC call.
244   // ----------- S t a t e -------------
245   //  -- rax: number of arguments
246   //  -- rbx: feedback array
247   //  -- rdx: feedback slot (smi)
248   // -----------------------------------
249   // The number of arguments in rax is not smi encoded.
250   Generate_DebugBreakCallHelper(masm, rbx.bit() | rdx.bit() | rdi.bit(),
251                                 rax.bit(), false);
252 }
253
254
255 void DebugCodegen::GenerateSlot(MacroAssembler* masm) {
256   // Generate enough nop's to make space for a call instruction.
257   Label check_codesize;
258   __ bind(&check_codesize);
259   __ RecordDebugBreakSlot();
260   __ Nop(Assembler::kDebugBreakSlotLength);
261   DCHECK_EQ(Assembler::kDebugBreakSlotLength,
262             masm->SizeOfCodeGeneratedSince(&check_codesize));
263 }
264
265
266 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
267   // In the places where a debug break slot is inserted no registers can contain
268   // object pointers.
269   Generate_DebugBreakCallHelper(masm, 0, 0, true);
270 }
271
272
273 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
274   masm->ret(0);
275 }
276
277
278 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
279   ExternalReference restarter_frame_function_slot =
280       ExternalReference::debug_restarter_frame_function_pointer_address(
281           masm->isolate());
282   __ Move(rax, restarter_frame_function_slot);
283   __ movp(Operand(rax, 0), Immediate(0));
284
285   // We do not know our frame height, but set rsp based on rbp.
286   __ leap(rsp, Operand(rbp, -1 * kPointerSize));
287
288   __ Pop(rdi);  // Function.
289   __ popq(rbp);
290
291   // Load context from the function.
292   __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
293
294   // Get function code.
295   __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
296   __ movp(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
297   __ leap(rdx, FieldOperand(rdx, Code::kHeaderSize));
298
299   // Re-run JSFunction, rdi is function, rsi is context.
300   __ jmp(rdx);
301 }
302
303 const bool LiveEdit::kFrameDropperSupported = true;
304
305 #undef __
306
307 } }  // namespace v8::internal
308
309 #endif  // V8_TARGET_ARCH_X64