V8 Project
debug-ia32.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_IA32
8 
9 #include "src/codegen.h"
10 #include "src/debug.h"
11 
12 
13 namespace v8 {
14 namespace internal {
15 
18 }
19 
20 
21 // Patch the JS frame exit code with a debug break call. See
22 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-ia32.cc
23 // 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.
42 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
43  DCHECK(RelocInfo::IsJSReturn(rinfo->rmode()));
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 
57  Isolate* isolate = debug_info_->GetIsolate();
59  isolate->builtins()->Slot_DebugBreak()->entry(),
61 }
62 
63 
67 }
68 
69 
70 #define __ ACCESS_MASM(masm)
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 a smi 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  if ((object_regs & (1 << r)) != 0) {
96  __ push(reg);
97  }
98  if ((non_object_regs & (1 << r)) != 0) {
99  if (FLAG_debug_code) {
100  __ test(reg, Immediate(0xc0000000));
101  __ Assert(zero, kUnableToEncodeValueAsSmi);
102  }
103  __ SmiTag(reg);
104  __ push(reg);
105  }
106  }
107 
108 #ifdef DEBUG
109  __ RecordComment("// Calling from debug break to runtime - come in - over");
110 #endif
111  __ Move(eax, Immediate(0)); // No arguments.
112  __ mov(ebx, Immediate(ExternalReference::debug_break(masm->isolate())));
113 
114  CEntryStub ceb(masm->isolate(), 1);
115  __ CallStub(&ceb);
116 
117  // Automatically find register that could be used after register restore.
118  // We need one register for padding skip instructions.
119  Register unused_reg = { -1 };
120 
121  // Restore the register values containing object pointers from the
122  // expression stack.
123  for (int i = kNumJSCallerSaved; --i >= 0;) {
124  int r = JSCallerSavedCode(i);
125  Register reg = { r };
126  if (FLAG_debug_code) {
127  __ Move(reg, Immediate(kDebugZapValue));
128  }
129  bool taken = reg.code() == esi.code();
130  if ((object_regs & (1 << r)) != 0) {
131  __ pop(reg);
132  taken = true;
133  }
134  if ((non_object_regs & (1 << r)) != 0) {
135  __ pop(reg);
136  __ SmiUntag(reg);
137  taken = true;
138  }
139  if (!taken) {
140  unused_reg = reg;
141  }
142  }
143 
144  DCHECK(unused_reg.code() != -1);
145 
146  // Read current padding counter and skip corresponding number of words.
147  __ pop(unused_reg);
148  // We divide stored value by 2 (untagging) and multiply it by word's size.
150  __ lea(esp, Operand(esp, unused_reg, times_half_pointer_size, 0));
151 
152  // Get rid of the internal frame.
153  }
154 
155  // If this call did not replace a call but patched other code then there will
156  // be an unwanted return address left on the stack. Here we get rid of that.
157  if (convert_call_to_jmp) {
158  __ add(esp, Immediate(kPointerSize));
159  }
160 
161  // Now that the break point has been handled, resume normal execution by
162  // jumping to the target address intended by the caller and that was
163  // overwritten by the address of DebugBreakXXX.
164  ExternalReference after_break_target =
165  ExternalReference::debug_after_break_target_address(masm->isolate());
166  __ jmp(Operand::StaticVariable(after_break_target));
167 }
168 
169 
170 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
171  // Register state for CallICStub
172  // ----------- S t a t e -------------
173  // -- edx : type feedback slot (smi)
174  // -- edi : function
175  // -----------------------------------
176  Generate_DebugBreakCallHelper(masm, edx.bit() | edi.bit(),
177  0, false);
178 }
179 
180 
181 void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
182  // Register state for IC load call (from ic-ia32.cc).
183  Register receiver = LoadDescriptor::ReceiverRegister();
184  Register name = LoadDescriptor::NameRegister();
185  Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0, false);
186 }
187 
188 
189 void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
190  // Register state for IC store call (from ic-ia32.cc).
191  Register receiver = StoreDescriptor::ReceiverRegister();
192  Register name = StoreDescriptor::NameRegister();
193  Register value = StoreDescriptor::ValueRegister();
194  Generate_DebugBreakCallHelper(
195  masm, receiver.bit() | name.bit() | value.bit(), 0, false);
196 }
197 
198 
199 void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
200  // Register state for keyed IC load call (from ic-ia32.cc).
202 }
203 
204 
205 void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
206  // Register state for keyed IC store call (from ic-ia32.cc).
207  Register receiver = StoreDescriptor::ReceiverRegister();
208  Register name = StoreDescriptor::NameRegister();
209  Register value = StoreDescriptor::ValueRegister();
210  Generate_DebugBreakCallHelper(
211  masm, receiver.bit() | name.bit() | value.bit(), 0, false);
212 }
213 
214 
215 void DebugCodegen::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
216  // Register state for CompareNil IC
217  // ----------- S t a t e -------------
218  // -- eax : value
219  // -----------------------------------
220  Generate_DebugBreakCallHelper(masm, eax.bit(), 0, false);
221 }
222 
223 
224 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
225  // Register state just before return from JS function (from codegen-ia32.cc).
226  // ----------- S t a t e -------------
227  // -- eax: return value
228  // -----------------------------------
229  Generate_DebugBreakCallHelper(masm, eax.bit(), 0, true);
230 }
231 
232 
233 void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
234  // Register state for CallFunctionStub (from code-stubs-ia32.cc).
235  // ----------- S t a t e -------------
236  // -- edi: function
237  // -----------------------------------
238  Generate_DebugBreakCallHelper(masm, edi.bit(), 0, false);
239 }
240 
241 
242 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
243  // Register state for CallConstructStub (from code-stubs-ia32.cc).
244  // eax is the actual number of arguments not encoded as a smi see comment
245  // above IC call.
246  // ----------- S t a t e -------------
247  // -- eax: number of arguments (not smi)
248  // -- edi: constructor function
249  // -----------------------------------
250  // The number of arguments in eax is not smi encoded.
251  Generate_DebugBreakCallHelper(masm, edi.bit(), eax.bit(), false);
252 }
253 
254 
256  MacroAssembler* masm) {
257  // Register state for CallConstructStub (from code-stubs-ia32.cc).
258  // eax is the actual number of arguments not encoded as a smi see comment
259  // above IC call.
260  // ----------- S t a t e -------------
261  // -- eax: number of arguments (not smi)
262  // -- ebx: feedback array
263  // -- edx: feedback slot (smi)
264  // -- edi: constructor function
265  // -----------------------------------
266  // The number of arguments in eax is not smi encoded.
267  Generate_DebugBreakCallHelper(masm, ebx.bit() | edx.bit() | edi.bit(),
268  eax.bit(), false);
269 }
270 
271 
272 void DebugCodegen::GenerateSlot(MacroAssembler* masm) {
273  // Generate enough nop's to make space for a call instruction.
274  Label check_codesize;
275  __ bind(&check_codesize);
276  __ RecordDebugBreakSlot();
279  masm->SizeOfCodeGeneratedSince(&check_codesize));
280 }
281 
282 
283 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
284  // In the places where a debug break slot is inserted no registers can contain
285  // object pointers.
286  Generate_DebugBreakCallHelper(masm, 0, 0, true);
287 }
288 
289 
290 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
291  masm->ret(0);
292 }
293 
294 
295 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
296  ExternalReference restarter_frame_function_slot =
297  ExternalReference::debug_restarter_frame_function_pointer_address(
298  masm->isolate());
299  __ mov(Operand::StaticVariable(restarter_frame_function_slot), Immediate(0));
300 
301  // We do not know our frame height, but set esp based on ebp.
302  __ lea(esp, Operand(ebp, -1 * kPointerSize));
303 
304  __ pop(edi); // Function.
305  __ pop(ebp);
306 
307  // Load context from the function.
309 
310  // Get function code.
314 
315  // Re-run JSFunction, edi is function, esi is context.
316  __ jmp(edx);
317 }
318 
319 
320 const bool LiveEdit::kFrameDropperSupported = true;
321 
322 #undef __
323 
324 } } // namespace v8::internal
325 
326 #endif // V8_TARGET_ARCH_IA32
static const int kCallInstructionLength
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)
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
const int kPointerSize
Definition: globals.h:129
const Register edx
const Register edi
const uint32_t kDebugZapValue
Definition: globals.h:274
const RegList kJSCallerSaved
Definition: frames-arm.h:24
const Register esp
const int kSmiTagSize
Definition: v8.h:5743
int JSCallerSavedCode(int n)
Definition: frames.cc:1601
Operand FieldOperand(Register object, int offset)
const Register esi
const Register eax
const Register ebx
uint32_t RegList
Definition: frames.h:18
const int kSmiShiftSize
Definition: v8.h:5805
const int kNumJSCallerSaved
Definition: frames-arm.h:30
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
const Register ebp
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20