v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
debug-x64.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #if V8_TARGET_ARCH_X64
31 
32 #include "assembler.h"
33 #include "codegen.h"
34 #include "debug.h"
35 
36 
37 namespace v8 {
38 namespace internal {
39 
40 #ifdef ENABLE_DEBUGGER_SUPPORT
41 
42 bool BreakLocationIterator::IsDebugBreakAtReturn() {
43  return Debug::IsDebugBreakAtReturn(rinfo());
44 }
45 
46 
47 // Patch the JS frame exit code with a debug break call. See
48 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc
49 // for the precise return instructions sequence.
50 void BreakLocationIterator::SetDebugBreakAtReturn() {
52  rinfo()->PatchCodeWithCall(
53  debug_info_->GetIsolate()->debug()->debug_break_return()->entry(),
55 }
56 
57 
58 // Restore the JS frame exit code.
59 void BreakLocationIterator::ClearDebugBreakAtReturn() {
60  rinfo()->PatchCode(original_rinfo()->pc(),
62 }
63 
64 
65 // A debug break in the frame exit code is identified by the JS frame exit code
66 // having been patched with a call instruction.
67 bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) {
68  ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
69  return rinfo->IsPatchedReturnSequence();
70 }
71 
72 
73 bool BreakLocationIterator::IsDebugBreakAtSlot() {
74  ASSERT(IsDebugBreakSlot());
75  // Check whether the debug break slot instructions have been patched.
76  return !Assembler::IsNop(rinfo()->pc());
77 }
78 
79 
80 void BreakLocationIterator::SetDebugBreakAtSlot() {
81  ASSERT(IsDebugBreakSlot());
82  rinfo()->PatchCodeWithCall(
83  debug_info_->GetIsolate()->debug()->debug_break_slot()->entry(),
85 }
86 
87 
88 void BreakLocationIterator::ClearDebugBreakAtSlot() {
89  ASSERT(IsDebugBreakSlot());
90  rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
91 }
92 
93 const bool Debug::FramePaddingLayout::kIsSupported = true;
94 
95 
96 #define __ ACCESS_MASM(masm)
97 
98 
99 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
100  RegList object_regs,
101  RegList non_object_regs,
102  bool convert_call_to_jmp) {
103  // Enter an internal frame.
104  {
105  FrameScope scope(masm, StackFrame::INTERNAL);
106 
107  // Load padding words on stack.
108  for (int i = 0; i < Debug::FramePaddingLayout::kInitialSize; i++) {
109  __ Push(Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue));
110  }
111  __ Push(Smi::FromInt(Debug::FramePaddingLayout::kInitialSize));
112 
113  // Store the registers containing live values on the expression stack to
114  // make sure that these are correctly updated during GC. Non object values
115  // are stored as as two smis causing it to be untouched by GC.
116  ASSERT((object_regs & ~kJSCallerSaved) == 0);
117  ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
118  ASSERT((object_regs & non_object_regs) == 0);
119  for (int i = 0; i < kNumJSCallerSaved; i++) {
120  int r = JSCallerSavedCode(i);
121  Register reg = { r };
122  ASSERT(!reg.is(kScratchRegister));
123  if ((object_regs & (1 << r)) != 0) {
124  __ Push(reg);
125  }
126  if ((non_object_regs & (1 << r)) != 0) {
127  __ PushInt64AsTwoSmis(reg);
128  }
129  }
130 
131 #ifdef DEBUG
132  __ RecordComment("// Calling from debug break to runtime - come in - over");
133 #endif
134  __ Set(rax, 0); // No arguments (argc == 0).
135  __ Move(rbx, ExternalReference::debug_break(masm->isolate()));
136 
137  CEntryStub ceb(1);
138  __ CallStub(&ceb);
139 
140  // Restore the register values from the expression stack.
141  for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
142  int r = JSCallerSavedCode(i);
143  Register reg = { r };
144  if (FLAG_debug_code) {
145  __ Set(reg, kDebugZapValue);
146  }
147  if ((object_regs & (1 << r)) != 0) {
148  __ Pop(reg);
149  }
150  // Reconstruct the 64-bit value from two smis.
151  if ((non_object_regs & (1 << r)) != 0) {
152  __ PopInt64AsTwoSmis(reg);
153  }
154  }
155 
156  // Read current padding counter and skip corresponding number of words.
157  __ Pop(kScratchRegister);
158  __ SmiToInteger32(kScratchRegister, kScratchRegister);
159  __ leap(rsp, Operand(rsp, kScratchRegister, times_pointer_size, 0));
160 
161  // Get rid of the internal frame.
162  }
163 
164  // If this call did not replace a call but patched other code then there will
165  // be an unwanted return address left on the stack. Here we get rid of that.
166  if (convert_call_to_jmp) {
167  __ addp(rsp, Immediate(kPCOnStackSize));
168  }
169 
170  // Now that the break point has been handled, resume normal execution by
171  // jumping to the target address intended by the caller and that was
172  // overwritten by the address of DebugBreakXXX.
173  ExternalReference after_break_target =
174  ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate());
175  __ Move(kScratchRegister, after_break_target);
176  __ Jump(Operand(kScratchRegister, 0));
177 }
178 
179 
180 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
181  // Register state for IC load call (from ic-x64.cc).
182  // ----------- S t a t e -------------
183  // -- rax : receiver
184  // -- rcx : name
185  // -----------------------------------
186  Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit(), 0, false);
187 }
188 
189 
190 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
191  // Register state for IC store call (from ic-x64.cc).
192  // ----------- S t a t e -------------
193  // -- rax : value
194  // -- rcx : name
195  // -- rdx : receiver
196  // -----------------------------------
197  Generate_DebugBreakCallHelper(
198  masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
199 }
200 
201 
202 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
203  // Register state for keyed IC load call (from ic-x64.cc).
204  // ----------- S t a t e -------------
205  // -- rax : key
206  // -- rdx : receiver
207  // -----------------------------------
208  Generate_DebugBreakCallHelper(masm, rax.bit() | rdx.bit(), 0, false);
209 }
210 
211 
212 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
213  // Register state for keyed IC load call (from ic-x64.cc).
214  // ----------- S t a t e -------------
215  // -- rax : value
216  // -- rcx : key
217  // -- rdx : receiver
218  // -----------------------------------
219  Generate_DebugBreakCallHelper(
220  masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
221 }
222 
223 
224 void Debug::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
225  // Register state for CompareNil IC
226  // ----------- S t a t e -------------
227  // -- rax : value
228  // -----------------------------------
229  Generate_DebugBreakCallHelper(masm, rax.bit(), 0, false);
230 }
231 
232 
233 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
234  // Register state for IC call call (from ic-x64.cc)
235  // ----------- S t a t e -------------
236  // -- rcx: function name
237  // -----------------------------------
238  Generate_DebugBreakCallHelper(masm, rcx.bit(), 0, false);
239 }
240 
241 
242 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
243  // Register state just before return from JS function (from codegen-x64.cc).
244  // ----------- S t a t e -------------
245  // -- rax: return value
246  // -----------------------------------
247  Generate_DebugBreakCallHelper(masm, rax.bit(), 0, true);
248 }
249 
250 
251 void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
252  // Register state for CallFunctionStub (from code-stubs-x64.cc).
253  // ----------- S t a t e -------------
254  // -- rdi : function
255  // -----------------------------------
256  Generate_DebugBreakCallHelper(masm, rdi.bit(), 0, false);
257 }
258 
259 
260 void Debug::GenerateCallFunctionStubRecordDebugBreak(MacroAssembler* masm) {
261  // Register state for CallFunctionStub (from code-stubs-x64.cc).
262  // ----------- S t a t e -------------
263  // -- rdi : function
264  // -- rbx: feedback array
265  // -- rdx: slot in feedback array
266  // -----------------------------------
267  Generate_DebugBreakCallHelper(masm, rbx.bit() | rdx.bit() | rdi.bit(),
268  0, false);
269 }
270 
271 
272 void Debug::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
273  // Register state for CallConstructStub (from code-stubs-x64.cc).
274  // rax is the actual number of arguments not encoded as a smi, see comment
275  // above IC call.
276  // ----------- S t a t e -------------
277  // -- rax: number of arguments
278  // -----------------------------------
279  // The number of arguments in rax is not smi encoded.
280  Generate_DebugBreakCallHelper(masm, rdi.bit(), rax.bit(), false);
281 }
282 
283 
284 void Debug::GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm) {
285  // Register state for CallConstructStub (from code-stubs-x64.cc).
286  // rax is the actual number of arguments not encoded as a smi, see comment
287  // above IC call.
288  // ----------- S t a t e -------------
289  // -- rax: number of arguments
290  // -- rbx: feedback array
291  // -- rdx: feedback slot (smi)
292  // -----------------------------------
293  // The number of arguments in rax is not smi encoded.
294  Generate_DebugBreakCallHelper(masm, rbx.bit() | rdx.bit() | rdi.bit(),
295  rax.bit(), false);
296 }
297 
298 
299 void Debug::GenerateSlot(MacroAssembler* masm) {
300  // Generate enough nop's to make space for a call instruction.
301  Label check_codesize;
302  __ bind(&check_codesize);
303  __ RecordDebugBreakSlot();
306  masm->SizeOfCodeGeneratedSince(&check_codesize));
307 }
308 
309 
310 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
311  // In the places where a debug break slot is inserted no registers can contain
312  // object pointers.
313  Generate_DebugBreakCallHelper(masm, 0, 0, true);
314 }
315 
316 
317 void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
318  masm->ret(0);
319 }
320 
321 
322 void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
323  ExternalReference restarter_frame_function_slot =
324  ExternalReference(Debug_Address::RestarterFrameFunctionPointer(),
325  masm->isolate());
326  __ Move(rax, restarter_frame_function_slot);
327  __ movp(Operand(rax, 0), Immediate(0));
328 
329  // We do not know our frame height, but set rsp based on rbp.
330  __ leap(rsp, Operand(rbp, -1 * kPointerSize));
331 
332  __ Pop(rdi); // Function.
333  __ popq(rbp);
334 
335  // Load context from the function.
337 
338  // Get function code.
342 
343  // Re-run JSFunction, rdi is function, rsi is context.
344  __ jmp(rdx);
345 }
346 
347 const bool Debug::kFrameDropperSupported = true;
348 
349 #undef __
350 
351 #endif // ENABLE_DEBUGGER_SUPPORT
352 
353 } } // namespace v8::internal
354 
355 #endif // V8_TARGET_ARCH_X64
const Register rdx
static const int kCodeOffset
Definition: objects.h:7103
static Smi * FromInt(int value)
Definition: objects-inl.h:1209
const Register rbp
const Register rsi
uint32_t RegList
Definition: frames.h:41
#define ASSERT(condition)
Definition: checks.h:329
const RegList kJSCallerSaved
Definition: frames-arm.h:47
static const int kContextOffset
Definition: objects.h:7523
int JSCallerSavedCode(int n)
Definition: frames.cc:1610
const int kPointerSize
Definition: globals.h:268
static const int kJSReturnSequenceLength
Operand FieldOperand(Register object, int offset)
const Register rbx
const Register rsp
#define __
const Register pc
const int kNumJSCallerSaved
Definition: frames-arm.h:53
const Register rax
const Register rdi
static const int kDebugBreakSlotLength
static bool IsNop(Instr instr, int type=NON_MARKING_NOP)
static const int kCallSequenceLength
const Register kScratchRegister
static const int kHeaderSize
Definition: objects.h:5604
const Register rcx
#define ASSERT_EQ(v1, v2)
Definition: checks.h:330
const uint32_t kDebugZapValue
Definition: v8globals.h:87
const int kPCOnStackSize
Definition: globals.h:270
static const int kSharedFunctionInfoOffset
Definition: objects.h:7521