Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(208)

Side by Side Diff: src/ia32/debug-ia32.cc

Issue 1234833003: Debugger: use debug break slots to break at function exit. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: fix for arm Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/ia32/assembler-ia32-inl.h ('k') | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #if V8_TARGET_ARCH_IA32 7 #if V8_TARGET_ARCH_IA32
8 8
9 #include "src/codegen.h" 9 #include "src/codegen.h"
10 #include "src/debug.h" 10 #include "src/debug.h"
11 11
12 12
13 namespace v8 { 13 namespace v8 {
14 namespace internal { 14 namespace internal {
15 15
16 #define __ ACCESS_MASM(masm)
16 17
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 // Call instruction takes up 5 bytes and int3 takes up one byte.
21 static const int kCallCodeSize = 5;
22 int code_size = kCallCodeSize + guard_bytes;
23 18
24 // Create a code patcher. 19 void EmitDebugBreakSlot(MacroAssembler* masm) {
25 CodePatcher patcher(pc, code_size);
26
27 // Add a label for checking the size of the code used for returning.
28 #ifdef DEBUG
29 Label check_codesize; 20 Label check_codesize;
30 patcher.masm()->bind(&check_codesize); 21 __ bind(&check_codesize);
31 #endif 22 __ Nop(Assembler::kDebugBreakSlotLength);
32 23 DCHECK_EQ(Assembler::kDebugBreakSlotLength,
33 // Patch the code. 24 masm->SizeOfCodeGeneratedSince(&check_codesize));
34 patcher.masm()->call(target, RelocInfo::NONE32);
35
36 // Check that the size of the code generated is as expected.
37 DCHECK_EQ(kCallCodeSize,
38 patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
39
40 // Add the requested number of int3 instructions after the call.
41 DCHECK_GE(guard_bytes, 0);
42 for (int i = 0; i < guard_bytes; i++) {
43 patcher.masm()->int3();
44 }
45
46 CpuFeatures::FlushICache(pc, code_size);
47 } 25 }
48 26
49 27
50 // Patch the JS frame exit code with a debug break call. See 28 void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode,
51 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-ia32.cc 29 int call_argc) {
52 // for the precise return instructions sequence. 30 // Generate enough nop's to make space for a call instruction.
53 void BreakLocation::SetDebugBreakAtReturn() { 31 masm->RecordDebugBreakSlot(mode, call_argc);
54 DCHECK(Assembler::kJSReturnSequenceLength >= 32 EmitDebugBreakSlot(masm);
55 Assembler::kCallInstructionLength);
56 PatchCodeWithCall(
57 pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
58 Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
59 } 33 }
60 34
61 35
62 void BreakLocation::SetDebugBreakAtSlot() { 36 void DebugCodegen::ClearDebugBreakSlot(Address pc) {
63 DCHECK(IsDebugBreakSlot()); 37 CodePatcher patcher(pc, Assembler::kDebugBreakSlotLength);
64 Isolate* isolate = debug_info_->GetIsolate(); 38 EmitDebugBreakSlot(patcher.masm());
65 PatchCodeWithCall(
66 pc(), isolate->builtins()->Slot_DebugBreak()->entry(),
67 Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
68 } 39 }
69 40
70 41
71 #define __ ACCESS_MASM(masm) 42 void DebugCodegen::PatchDebugBreakSlot(Address pc, Handle<Code> code) {
43 DCHECK_EQ(Code::BUILTIN, code->kind());
44 static const int kSize = Assembler::kDebugBreakSlotLength;
45 CodePatcher patcher(pc, kSize);
72 46
73 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, 47 // Add a label for checking the size of the code used for returning.
74 RegList object_regs) { 48 Label check_codesize;
49 patcher.masm()->bind(&check_codesize);
50 patcher.masm()->call(code->entry(), RelocInfo::NONE32);
51 // Check that the size of the code generated is as expected.
52 DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
53 }
54
55
56 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
57 DebugBreakCallHelperMode mode) {
58 __ RecordComment("Debug break");
59
75 // Enter an internal frame. 60 // Enter an internal frame.
76 { 61 {
77 FrameScope scope(masm, StackFrame::INTERNAL); 62 FrameScope scope(masm, StackFrame::INTERNAL);
78 63
79 // Load padding words on stack. 64 // Load padding words on stack.
80 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { 65 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
81 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue))); 66 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue)));
82 } 67 }
83 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); 68 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
84 69
85 // Store the registers containing live values on the expression stack to 70 if (mode == SAVE_RESULT_REGISTER) __ push(eax);
86 // make sure that these are correctly updated during GC. Non object values
87 // are stored as a smi causing it to be untouched by GC.
88 DCHECK((object_regs & ~kJSCallerSaved) == 0);
89 for (int i = 0; i < kNumJSCallerSaved; i++) {
90 int r = JSCallerSavedCode(i);
91 Register reg = { r };
92 if ((object_regs & (1 << r)) != 0) {
93 __ push(reg);
94 }
95 }
96 71
97 #ifdef DEBUG
98 __ RecordComment("// Calling from debug break to runtime - come in - over");
99 #endif
100 __ Move(eax, Immediate(0)); // No arguments. 72 __ Move(eax, Immediate(0)); // No arguments.
101 __ mov(ebx, Immediate(ExternalReference::debug_break(masm->isolate()))); 73 __ mov(ebx, Immediate(ExternalReference::debug_break(masm->isolate())));
102 74
103 CEntryStub ceb(masm->isolate(), 1); 75 CEntryStub ceb(masm->isolate(), 1);
104 __ CallStub(&ceb); 76 __ CallStub(&ceb);
105 77
106 // Automatically find register that could be used after register restore. 78 if (FLAG_debug_code) {
107 // We need one register for padding skip instructions. 79 for (int i = 0; i < kNumJSCallerSaved; ++i) {
108 Register unused_reg = { -1 }; 80 Register reg = {JSCallerSavedCode(i)};
109
110 // Restore the register values containing object pointers from the
111 // expression stack.
112 for (int i = kNumJSCallerSaved; --i >= 0;) {
113 int r = JSCallerSavedCode(i);
114 Register reg = { r };
115 if (FLAG_debug_code) {
116 __ Move(reg, Immediate(kDebugZapValue)); 81 __ Move(reg, Immediate(kDebugZapValue));
117 } 82 }
118 bool taken = reg.code() == esi.code();
119 if ((object_regs & (1 << r)) != 0) {
120 __ pop(reg);
121 taken = true;
122 }
123 if (!taken) {
124 unused_reg = reg;
125 }
126 } 83 }
127 84
128 DCHECK(unused_reg.code() != -1); 85 if (mode == SAVE_RESULT_REGISTER) __ pop(eax);
129 86
130 // Read current padding counter and skip corresponding number of words. 87 __ pop(ebx);
131 __ pop(unused_reg);
132 // We divide stored value by 2 (untagging) and multiply it by word's size. 88 // We divide stored value by 2 (untagging) and multiply it by word's size.
133 STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0); 89 STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0);
134 __ lea(esp, Operand(esp, unused_reg, times_half_pointer_size, 0)); 90 __ lea(esp, Operand(esp, ebx, times_half_pointer_size, 0));
135 91
136 // Get rid of the internal frame. 92 // Get rid of the internal frame.
137 } 93 }
138 94
139 // This call did not replace a call , so there will be an unwanted 95 // This call did not replace a call , so there will be an unwanted
140 // return address left on the stack. Here we get rid of that. 96 // return address left on the stack. Here we get rid of that.
141 __ add(esp, Immediate(kPointerSize)); 97 __ add(esp, Immediate(kPointerSize));
142 98
143 // Now that the break point has been handled, resume normal execution by 99 // 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 100 // jumping to the target address intended by the caller and that was
145 // overwritten by the address of DebugBreakXXX. 101 // overwritten by the address of DebugBreakXXX.
146 ExternalReference after_break_target = 102 ExternalReference after_break_target =
147 ExternalReference::debug_after_break_target_address(masm->isolate()); 103 ExternalReference::debug_after_break_target_address(masm->isolate());
148 __ jmp(Operand::StaticVariable(after_break_target)); 104 __ jmp(Operand::StaticVariable(after_break_target));
149 } 105 }
150 106
151 107
152 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
153 // Register state just before return from JS function (from codegen-ia32.cc).
154 // ----------- S t a t e -------------
155 // -- eax: return value
156 // -----------------------------------
157 Generate_DebugBreakCallHelper(masm, eax.bit());
158 }
159
160
161 void DebugCodegen::GenerateSlot(MacroAssembler* masm,
162 DebugCodegen::SlotLocation location,
163 int call_argc) {
164 // Generate enough nop's to make space for a call instruction.
165 Label check_codesize;
166 __ bind(&check_codesize);
167 RecordRelocInfo(masm, location, call_argc);
168 __ Nop(Assembler::kDebugBreakSlotLength);
169 DCHECK_EQ(Assembler::kDebugBreakSlotLength,
170 masm->SizeOfCodeGeneratedSince(&check_codesize));
171 }
172
173
174 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
175 Generate_DebugBreakCallHelper(masm, 0);
176 }
177
178
179 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { 108 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
180 masm->ret(0); 109 masm->ret(0);
181 } 110 }
182 111
183 112
184 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { 113 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
185 ExternalReference restarter_frame_function_slot = 114 ExternalReference restarter_frame_function_slot =
186 ExternalReference::debug_restarter_frame_function_pointer_address( 115 ExternalReference::debug_restarter_frame_function_pointer_address(
187 masm->isolate()); 116 masm->isolate());
188 __ mov(Operand::StaticVariable(restarter_frame_function_slot), Immediate(0)); 117 __ mov(Operand::StaticVariable(restarter_frame_function_slot), Immediate(0));
(...skipping 18 matching lines...) Expand all
207 136
208 137
209 const bool LiveEdit::kFrameDropperSupported = true; 138 const bool LiveEdit::kFrameDropperSupported = true;
210 139
211 #undef __ 140 #undef __
212 141
213 } // namespace internal 142 } // namespace internal
214 } // namespace v8 143 } // namespace v8
215 144
216 #endif // V8_TARGET_ARCH_IA32 145 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/ia32/assembler-ia32-inl.h ('k') | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698