V8 Project
debug-x64.cc
Go to the documentation of this file.
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 
19 }
20 
21 
22 // Patch the JS frame exit code with a debug break call. See
23 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc
24 // for the precise return instructions sequence.
28  debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
30 }
31 
32 
33 // Restore the JS frame exit code.
37 }
38 
39 
40 // A debug break in the frame exit code is identified by the JS frame exit code
41 // having been patched with a call instruction.
44  return rinfo->IsPatchedReturnSequence();
45 }
46 
47 
50  // Check whether the debug break slot instructions have been patched.
51  return rinfo()->IsPatchedDebugBreakSlotSequence();
52 }
53 
54 
58  debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry(),
60 }
61 
62 
66 }
67 
68 
69 #define __ ACCESS_MASM(masm)
70 
71 
72 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
73  RegList object_regs,
74  RegList non_object_regs,
75  bool convert_call_to_jmp) {
76  // Enter an internal frame.
77  {
78  FrameScope scope(masm, StackFrame::INTERNAL);
79 
80  // Load padding words on stack.
81  for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
83  }
85 
86  // Store the registers containing live values on the expression stack to
87  // make sure that these are correctly updated during GC. Non object values
88  // are stored as as two smis causing it to be untouched by GC.
89  DCHECK((object_regs & ~kJSCallerSaved) == 0);
90  DCHECK((non_object_regs & ~kJSCallerSaved) == 0);
91  DCHECK((object_regs & non_object_regs) == 0);
92  for (int i = 0; i < kNumJSCallerSaved; i++) {
93  int r = JSCallerSavedCode(i);
94  Register reg = { r };
95  DCHECK(!reg.is(kScratchRegister));
96  if ((object_regs & (1 << r)) != 0) {
97  __ Push(reg);
98  }
99  if ((non_object_regs & (1 << r)) != 0) {
100  __ PushRegisterAsTwoSmis(reg);
101  }
102  }
103 
104 #ifdef DEBUG
105  __ RecordComment("// Calling from debug break to runtime - come in - over");
106 #endif
107  __ Set(rax, 0); // No arguments (argc == 0).
108  __ Move(rbx, ExternalReference::debug_break(masm->isolate()));
109 
110  CEntryStub ceb(masm->isolate(), 1);
111  __ CallStub(&ceb);
112 
113  // Restore the register values from the expression stack.
114  for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
115  int r = JSCallerSavedCode(i);
116  Register reg = { r };
117  if (FLAG_debug_code) {
118  __ Set(reg, kDebugZapValue);
119  }
120  if ((object_regs & (1 << r)) != 0) {
121  __ Pop(reg);
122  }
123  // Reconstruct the 64-bit value from two smis.
124  if ((non_object_regs & (1 << r)) != 0) {
125  __ PopRegisterAsTwoSmis(reg);
126  }
127  }
128 
129  // Read current padding counter and skip corresponding number of words.
130  __ Pop(kScratchRegister);
131  __ SmiToInteger32(kScratchRegister, kScratchRegister);
132  __ leap(rsp, Operand(rsp, kScratchRegister, times_pointer_size, 0));
133 
134  // Get rid of the internal frame.
135  }
136 
137  // If this call did not replace a call but patched other code then there will
138  // be an unwanted return address left on the stack. Here we get rid of that.
139  if (convert_call_to_jmp) {
140  __ addp(rsp, Immediate(kPCOnStackSize));
141  }
142 
143  // Now that the break point has been handled, resume normal execution by
144  // jumping to the target address intended by the caller and that was
145  // overwritten by the address of DebugBreakXXX.
146  ExternalReference after_break_target =
147  ExternalReference::debug_after_break_target_address(masm->isolate());
148  __ Move(kScratchRegister, after_break_target);
149  __ Jump(Operand(kScratchRegister, 0));
150 }
151 
152 
153 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
154  // Register state for CallICStub
155  // ----------- S t a t e -------------
156  // -- rdx : type feedback slot (smi)
157  // -- rdi : function
158  // -----------------------------------
159  Generate_DebugBreakCallHelper(masm, rdx.bit() | rdi.bit(), 0, false);
160 }
161 
162 
163 void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
164  // Register state for IC load call (from ic-x64.cc).
165  Register receiver = LoadDescriptor::ReceiverRegister();
166  Register name = LoadDescriptor::NameRegister();
167  Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0, false);
168 }
169 
170 
171 void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
172  // Register state for IC store call (from ic-x64.cc).
173  Register receiver = StoreDescriptor::ReceiverRegister();
174  Register name = StoreDescriptor::NameRegister();
175  Register value = StoreDescriptor::ValueRegister();
176  Generate_DebugBreakCallHelper(
177  masm, receiver.bit() | name.bit() | value.bit(), 0, false);
178 }
179 
180 
181 void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
182  // Register state for keyed IC load call (from ic-x64.cc).
184 }
185 
186 
187 void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
188  // Register state for keyed IC store call (from ic-x64.cc).
189  Register receiver = StoreDescriptor::ReceiverRegister();
190  Register name = StoreDescriptor::NameRegister();
191  Register value = StoreDescriptor::ValueRegister();
192  Generate_DebugBreakCallHelper(
193  masm, receiver.bit() | name.bit() | value.bit(), 0, false);
194 }
195 
196 
197 void DebugCodegen::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
198  // Register state for CompareNil IC
199  // ----------- S t a t e -------------
200  // -- rax : value
201  // -----------------------------------
202  Generate_DebugBreakCallHelper(masm, rax.bit(), 0, false);
203 }
204 
205 
206 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
207  // Register state just before return from JS function (from codegen-x64.cc).
208  // ----------- S t a t e -------------
209  // -- rax: return value
210  // -----------------------------------
211  Generate_DebugBreakCallHelper(masm, rax.bit(), 0, true);
212 }
213 
214 
215 void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
216  // Register state for CallFunctionStub (from code-stubs-x64.cc).
217  // ----------- S t a t e -------------
218  // -- rdi : function
219  // -----------------------------------
220  Generate_DebugBreakCallHelper(masm, rdi.bit(), 0, false);
221 }
222 
223 
224 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
225  // Register state for CallConstructStub (from code-stubs-x64.cc).
226  // rax is the actual number of arguments not encoded as a smi, see comment
227  // above IC call.
228  // ----------- S t a t e -------------
229  // -- rax: number of arguments
230  // -----------------------------------
231  // The number of arguments in rax is not smi encoded.
232  Generate_DebugBreakCallHelper(masm, rdi.bit(), rax.bit(), false);
233 }
234 
235 
237  MacroAssembler* masm) {
238  // Register state for CallConstructStub (from code-stubs-x64.cc).
239  // rax is the actual number of arguments not encoded as a smi, see comment
240  // above IC call.
241  // ----------- S t a t e -------------
242  // -- rax: number of arguments
243  // -- rbx: feedback array
244  // -- rdx: feedback slot (smi)
245  // -----------------------------------
246  // The number of arguments in rax is not smi encoded.
247  Generate_DebugBreakCallHelper(masm, rbx.bit() | rdx.bit() | rdi.bit(),
248  rax.bit(), false);
249 }
250 
251 
252 void DebugCodegen::GenerateSlot(MacroAssembler* masm) {
253  // Generate enough nop's to make space for a call instruction.
254  Label check_codesize;
255  __ bind(&check_codesize);
256  __ RecordDebugBreakSlot();
259  masm->SizeOfCodeGeneratedSince(&check_codesize));
260 }
261 
262 
263 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
264  // In the places where a debug break slot is inserted no registers can contain
265  // object pointers.
266  Generate_DebugBreakCallHelper(masm, 0, 0, true);
267 }
268 
269 
270 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
271  masm->ret(0);
272 }
273 
274 
275 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
276  ExternalReference restarter_frame_function_slot =
277  ExternalReference::debug_restarter_frame_function_pointer_address(
278  masm->isolate());
279  __ Move(rax, restarter_frame_function_slot);
280  __ movp(Operand(rax, 0), Immediate(0));
281 
282  // We do not know our frame height, but set rsp based on rbp.
283  __ leap(rsp, Operand(rbp, -1 * kPointerSize));
284 
285  __ Pop(rdi); // Function.
286  __ popq(rbp);
287 
288  // Load context from the function.
290 
291  // Get function code.
295 
296  // Re-run JSFunction, rdi is function, rsi is context.
297  __ jmp(rdx);
298 }
299 
300 const bool LiveEdit::kFrameDropperSupported = true;
301 
302 #undef __
303 
304 } } // namespace v8::internal
305 
306 #endif // V8_TARGET_ARCH_X64
static const int kCallSequenceLength
static const int kJSReturnSequenceLength
static const int kDebugBreakSlotLength
Handle< DebugInfo > debug_info_
Definition: debug.h:123
static const int kHeaderSize
Definition: objects.h:5373
static void GenerateSlot(MacroAssembler *masm)
static void GenerateStoreICDebugBreak(MacroAssembler *masm)
static void GenerateLoadICDebugBreak(MacroAssembler *masm)
static void GeneratePlainReturnLiveEdit(MacroAssembler *masm)
static void GenerateCallConstructStubDebugBreak(MacroAssembler *masm)
static void GenerateCallConstructStubRecordDebugBreak(MacroAssembler *masm)
static void GenerateCallFunctionStubDebugBreak(MacroAssembler *masm)
static void GenerateCompareNilICDebugBreak(MacroAssembler *masm)
static void GenerateKeyedStoreICDebugBreak(MacroAssembler *masm)
static void GenerateCallICStubDebugBreak(MacroAssembler *masm)
static void GenerateFrameDropperLiveEdit(MacroAssembler *masm)
static void GenerateKeyedLoadICDebugBreak(MacroAssembler *masm)
static void GenerateReturnDebugBreak(MacroAssembler *masm)
static void GenerateSlotDebugBreak(MacroAssembler *masm)
static bool IsDebugBreakAtReturn(RelocInfo *rinfo)
static const int kSharedFunctionInfoOffset
Definition: objects.h:7379
static const int kContextOffset
Definition: objects.h:7381
static const int kFramePaddingValue
Definition: liveedit.h:184
static const bool kFrameDropperSupported
Definition: liveedit.h:147
static const int kFramePaddingInitialSize
Definition: liveedit.h:181
static const Register ReceiverRegister()
static const Register NameRegister()
static bool IsJSReturn(Mode mode)
Definition: assembler.h:412
void PatchCode(byte *instructions, int instruction_count)
Mode rmode() const
Definition: assembler.h:459
void PatchCodeWithCall(Address target, int guard_bytes)
static const int kCodeOffset
Definition: objects.h:6893
static Smi * FromInt(int value)
Definition: objects-inl.h:1321
static const Register ReceiverRegister()
static const Register NameRegister()
static const Register ValueRegister()
#define __
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
static int Push(SpecialRPOStackFrame *stack, int depth, BasicBlock *child, int unvisited)
Definition: scheduler.cc:773
const int kPointerSize
Definition: globals.h:129
const uint32_t kDebugZapValue
Definition: globals.h:274
const RegList kJSCallerSaved
Definition: frames-arm.h:24
const int kPCOnStackSize
Definition: globals.h:135
const Register kScratchRegister
int JSCallerSavedCode(int n)
Definition: frames.cc:1601
Operand FieldOperand(Register object, int offset)
const Register rsi
const Register rbp
const Register rdi
const Register rbx
uint32_t RegList
Definition: frames.h:18
const Register rdx
const Register rax
const int kNumJSCallerSaved
Definition: frames-arm.h:30
const Register rsp
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20