v8  3.11.10(node0.8.26)
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 defined(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() {
53  rinfo()->PatchCodeWithCall(
54  Isolate::Current()->debug()->debug_break_return()->entry(),
56 }
57 
58 
59 // Restore the JS frame exit code.
60 void BreakLocationIterator::ClearDebugBreakAtReturn() {
61  rinfo()->PatchCode(original_rinfo()->pc(),
63 }
64 
65 
66 // A debug break in the frame exit code is identified by the JS frame exit code
67 // having been patched with a call instruction.
68 bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) {
69  ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
70  return rinfo->IsPatchedReturnSequence();
71 }
72 
73 
74 bool BreakLocationIterator::IsDebugBreakAtSlot() {
75  ASSERT(IsDebugBreakSlot());
76  // Check whether the debug break slot instructions have been patched.
77  return !Assembler::IsNop(rinfo()->pc());
78 }
79 
80 
81 void BreakLocationIterator::SetDebugBreakAtSlot() {
82  ASSERT(IsDebugBreakSlot());
83  rinfo()->PatchCodeWithCall(
84  Isolate::Current()->debug()->debug_break_slot()->entry(),
86 }
87 
88 
89 void BreakLocationIterator::ClearDebugBreakAtSlot() {
90  ASSERT(IsDebugBreakSlot());
91  rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
92 }
93 
94 const bool Debug::FramePaddingLayout::kIsSupported = true;
95 
96 
97 #define __ ACCESS_MASM(masm)
98 
99 
100 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
101  RegList object_regs,
102  RegList non_object_regs,
103  bool convert_call_to_jmp) {
104  // Enter an internal frame.
105  {
106  FrameScope scope(masm, StackFrame::INTERNAL);
107 
108  // Load padding words on stack.
109  for (int i = 0; i < Debug::FramePaddingLayout::kInitialSize; i++) {
110  __ Push(Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue));
111  }
112  __ Push(Smi::FromInt(Debug::FramePaddingLayout::kInitialSize));
113 
114  // Store the registers containing live values on the expression stack to
115  // make sure that these are correctly updated during GC. Non object values
116  // are stored as as two smis causing it to be untouched by GC.
117  ASSERT((object_regs & ~kJSCallerSaved) == 0);
118  ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
119  ASSERT((object_regs & non_object_regs) == 0);
120  for (int i = 0; i < kNumJSCallerSaved; i++) {
121  int r = JSCallerSavedCode(i);
122  Register reg = { r };
123  ASSERT(!reg.is(kScratchRegister));
124  if ((object_regs & (1 << r)) != 0) {
125  __ push(reg);
126  }
127  // Store the 64-bit value as two smis.
128  if ((non_object_regs & (1 << r)) != 0) {
129  __ movq(kScratchRegister, reg);
130  __ Integer32ToSmi(reg, reg);
131  __ push(reg);
132  __ sar(kScratchRegister, Immediate(32));
133  __ Integer32ToSmi(kScratchRegister, kScratchRegister);
134  __ push(kScratchRegister);
135  }
136  }
137 
138 #ifdef DEBUG
139  __ RecordComment("// Calling from debug break to runtime - come in - over");
140 #endif
141  __ Set(rax, 0); // No arguments (argc == 0).
142  __ movq(rbx, ExternalReference::debug_break(masm->isolate()));
143 
144  CEntryStub ceb(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 (FLAG_debug_code) {
152  __ Set(reg, kDebugZapValue);
153  }
154  if ((object_regs & (1 << r)) != 0) {
155  __ pop(reg);
156  }
157  // Reconstruct the 64-bit value from two smis.
158  if ((non_object_regs & (1 << r)) != 0) {
159  __ pop(kScratchRegister);
160  __ SmiToInteger32(kScratchRegister, kScratchRegister);
161  __ shl(kScratchRegister, Immediate(32));
162  __ pop(reg);
163  __ SmiToInteger32(reg, reg);
164  __ or_(reg, kScratchRegister);
165  }
166  }
167 
168  // Read current padding counter and skip corresponding number of words.
169  __ pop(kScratchRegister);
170  __ SmiToInteger32(kScratchRegister, kScratchRegister);
171  __ lea(rsp, Operand(rsp, kScratchRegister, times_pointer_size, 0));
172 
173  // Get rid of the internal frame.
174  }
175 
176  // If this call did not replace a call but patched other code then there will
177  // be an unwanted return address left on the stack. Here we get rid of that.
178  if (convert_call_to_jmp) {
179  __ addq(rsp, Immediate(kPointerSize));
180  }
181 
182  // Now that the break point has been handled, resume normal execution by
183  // jumping to the target address intended by the caller and that was
184  // overwritten by the address of DebugBreakXXX.
185  ExternalReference after_break_target =
186  ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate());
187  __ movq(kScratchRegister, after_break_target);
188  __ jmp(Operand(kScratchRegister, 0));
189 }
190 
191 
192 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
193  // Register state for IC load call (from ic-x64.cc).
194  // ----------- S t a t e -------------
195  // -- rax : receiver
196  // -- rcx : name
197  // -----------------------------------
198  Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit(), 0, false);
199 }
200 
201 
202 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
203  // Register state for IC store call (from ic-x64.cc).
204  // ----------- S t a t e -------------
205  // -- rax : value
206  // -- rcx : name
207  // -- rdx : receiver
208  // -----------------------------------
209  Generate_DebugBreakCallHelper(
210  masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
211 }
212 
213 
214 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
215  // Register state for keyed IC load call (from ic-x64.cc).
216  // ----------- S t a t e -------------
217  // -- rax : key
218  // -- rdx : receiver
219  // -----------------------------------
220  Generate_DebugBreakCallHelper(masm, rax.bit() | rdx.bit(), 0, false);
221 }
222 
223 
224 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
225  // Register state for keyed IC load call (from ic-x64.cc).
226  // ----------- S t a t e -------------
227  // -- rax : value
228  // -- rcx : key
229  // -- rdx : receiver
230  // -----------------------------------
231  Generate_DebugBreakCallHelper(
232  masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
233 }
234 
235 
236 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
237  // Register state for IC call call (from ic-x64.cc)
238  // ----------- S t a t e -------------
239  // -- rcx: function name
240  // -----------------------------------
241  Generate_DebugBreakCallHelper(masm, rcx.bit(), 0, false);
242 }
243 
244 
245 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
246  // Register state just before return from JS function (from codegen-x64.cc).
247  // ----------- S t a t e -------------
248  // -- rax: return value
249  // -----------------------------------
250  Generate_DebugBreakCallHelper(masm, rax.bit(), 0, true);
251 }
252 
253 
254 void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
255  // Register state for CallFunctionStub (from code-stubs-x64.cc).
256  // ----------- S t a t e -------------
257  // -- rdi : function
258  // -----------------------------------
259  Generate_DebugBreakCallHelper(masm, rdi.bit(), 0, false);
260 }
261 
262 
263 void Debug::GenerateCallFunctionStubRecordDebugBreak(MacroAssembler* masm) {
264  // Register state for CallFunctionStub (from code-stubs-x64.cc).
265  // ----------- S t a t e -------------
266  // -- rdi : function
267  // -- rbx: cache cell for call target
268  // -----------------------------------
269  Generate_DebugBreakCallHelper(masm, rbx.bit() | rdi.bit(), 0, false);
270 }
271 
272 
273 void Debug::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
274  // Register state for CallConstructStub (from code-stubs-x64.cc).
275  // rax is the actual number of arguments not encoded as a smi, see comment
276  // above IC call.
277  // ----------- S t a t e -------------
278  // -- rax: number of arguments
279  // -----------------------------------
280  // The number of arguments in rax is not smi encoded.
281  Generate_DebugBreakCallHelper(masm, rdi.bit(), rax.bit(), false);
282 }
283 
284 
285 void Debug::GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm) {
286  // Register state for CallConstructStub (from code-stubs-x64.cc).
287  // rax is the actual number of arguments not encoded as a smi, see comment
288  // above IC call.
289  // ----------- S t a t e -------------
290  // -- rax: number of arguments
291  // -- rbx: cache cell for call target
292  // -----------------------------------
293  // The number of arguments in rax is not smi encoded.
294  Generate_DebugBreakCallHelper(masm, rbx.bit() | rdi.bit(), rax.bit(), false);
295 }
296 
297 
298 void Debug::GenerateSlot(MacroAssembler* masm) {
299  // Generate enough nop's to make space for a call instruction.
300  Label check_codesize;
301  __ bind(&check_codesize);
302  __ RecordDebugBreakSlot();
305  masm->SizeOfCodeGeneratedSince(&check_codesize));
306 }
307 
308 
309 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
310  // In the places where a debug break slot is inserted no registers can contain
311  // object pointers.
312  Generate_DebugBreakCallHelper(masm, 0, 0, true);
313 }
314 
315 
316 void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
317  masm->ret(0);
318 }
319 
320 
321 void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
322  ExternalReference restarter_frame_function_slot =
323  ExternalReference(Debug_Address::RestarterFrameFunctionPointer(),
324  masm->isolate());
325  __ movq(rax, restarter_frame_function_slot);
326  __ movq(Operand(rax, 0), Immediate(0));
327 
328  // We do not know our frame height, but set rsp based on rbp.
329  __ lea(rsp, Operand(rbp, -1 * kPointerSize));
330 
331  __ pop(rdi); // Function.
332  __ pop(rbp);
333 
334  // Load context from the function.
336 
337  // Get function code.
341 
342  // Re-run JSFunction, rdi is function, rsi is context.
343  __ jmp(rdx);
344 }
345 
346 const bool Debug::kFrameDropperSupported = true;
347 
348 #undef __
349 
350 #endif // ENABLE_DEBUGGER_SUPPORT
351 
352 } } // namespace v8::internal
353 
354 #endif // V8_TARGET_ARCH_X64
const Register rdx
static const int kCodeOffset
Definition: objects.h:5606
static Smi * FromInt(int value)
Definition: objects-inl.h:973
const Register rbp
const Register rsi
uint32_t RegList
Definition: frames.h:38
static const int kCallInstructionLength
#define ASSERT(condition)
Definition: checks.h:270
const RegList kJSCallerSaved
Definition: frames-arm.h:47
static const int kContextOffset
Definition: objects.h:5986
int JSCallerSavedCode(int n)
Definition: frames.cc:1395
const int kPointerSize
Definition: globals.h:234
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)
const Register kScratchRegister
static const int kHeaderSize
Definition: objects.h:4513
const Register rcx
#define ASSERT_EQ(v1, v2)
Definition: checks.h:271
const uint32_t kDebugZapValue
Definition: v8globals.h:93
static const int kSharedFunctionInfoOffset
Definition: objects.h:5984