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

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: rebase, clean ups, x64 port. 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
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 DebugCodegen::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::PatchDebugBreakSlot(Address pc, Handle<Code> code) {
51 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-ia32.cc 29 DCHECK_EQ(Code::BUILTIN, code->kind());
52 // for the precise return instructions sequence. 30 static const int kSize = Assembler::kDebugBreakSlotLength;
53 void BreakLocation::SetDebugBreakAtReturn() { 31 CodePatcher patcher(pc, kSize);
54 DCHECK(Assembler::kJSReturnSequenceLength >= 32
55 Assembler::kCallInstructionLength); 33 // Add a label for checking the size of the code used for returning.
56 PatchCodeWithCall( 34 Label check_codesize;
57 pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(), 35 patcher.masm()->bind(&check_codesize);
58 Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength); 36 patcher.masm()->call(code->entry(), RelocInfo::NONE32);
37 // Check that the size of the code generated is as expected.
38 DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
59 } 39 }
60 40
61 41
62 void BreakLocation::SetDebugBreakAtSlot() { 42 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
63 DCHECK(IsDebugBreakSlot()); 43 DebugBreakCallHelperMode mode) {
64 Isolate* isolate = debug_info_->GetIsolate(); 44 __ RecordComment("Debug break");
65 PatchCodeWithCall(
66 pc(), isolate->builtins()->Slot_DebugBreak()->entry(),
67 Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
68 }
69 45
70
71 #define __ ACCESS_MASM(masm)
72
73 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
74 RegList object_regs) {
75 // Enter an internal frame. 46 // Enter an internal frame.
76 { 47 {
77 FrameScope scope(masm, StackFrame::INTERNAL); 48 FrameScope scope(masm, StackFrame::INTERNAL);
78 49
79 // Load padding words on stack. 50 // Load padding words on stack.
80 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { 51 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
81 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue))); 52 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue)));
82 } 53 }
83 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); 54 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
84 55
85 // Store the registers containing live values on the expression stack to 56 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 57
97 #ifdef DEBUG
98 __ RecordComment("// Calling from debug break to runtime - come in - over");
99 #endif
100 __ Move(eax, Immediate(0)); // No arguments. 58 __ Move(eax, Immediate(0)); // No arguments.
101 __ mov(ebx, Immediate(ExternalReference::debug_break(masm->isolate()))); 59 __ mov(ebx, Immediate(ExternalReference::debug_break(masm->isolate())));
102 60
103 CEntryStub ceb(masm->isolate(), 1); 61 CEntryStub ceb(masm->isolate(), 1);
104 __ CallStub(&ceb); 62 __ CallStub(&ceb);
105 63
106 // Automatically find register that could be used after register restore.
107 // We need one register for padding skip instructions.
108 Register unused_reg = { -1 };
109
110 // Restore the register values containing object pointers from the 64 // Restore the register values containing object pointers from the
111 // expression stack. 65 // expression stack.
112 for (int i = kNumJSCallerSaved; --i >= 0;) { 66 if (FLAG_debug_code) {
113 int r = JSCallerSavedCode(i); 67 for (int i = 0; i < kNumJSCallerSaved; ++i) {
114 Register reg = { r }; 68 Register reg = {JSCallerSavedCode(i)};
115 if (FLAG_debug_code) {
116 __ Move(reg, Immediate(kDebugZapValue)); 69 __ Move(reg, Immediate(kDebugZapValue));
117 } 70 }
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 } 71 }
127 72
128 DCHECK(unused_reg.code() != -1); 73 if (mode == SAVE_RESULT_REGISTER) __ pop(eax);
129 74
130 // Read current padding counter and skip corresponding number of words. 75 __ pop(ebx);
131 __ pop(unused_reg);
132 // We divide stored value by 2 (untagging) and multiply it by word's size. 76 // We divide stored value by 2 (untagging) and multiply it by word's size.
133 STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0); 77 STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0);
134 __ lea(esp, Operand(esp, unused_reg, times_half_pointer_size, 0)); 78 __ lea(esp, Operand(esp, ebx, times_half_pointer_size, 0));
135 79
136 // Get rid of the internal frame. 80 // Get rid of the internal frame.
137 } 81 }
138 82
139 // This call did not replace a call , so there will be an unwanted 83 // 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. 84 // return address left on the stack. Here we get rid of that.
141 __ add(esp, Immediate(kPointerSize)); 85 __ add(esp, Immediate(kPointerSize));
142 86
143 // Now that the break point has been handled, resume normal execution by 87 // 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 88 // jumping to the target address intended by the caller and that was
145 // overwritten by the address of DebugBreakXXX. 89 // overwritten by the address of DebugBreakXXX.
146 ExternalReference after_break_target = 90 ExternalReference after_break_target =
147 ExternalReference::debug_after_break_target_address(masm->isolate()); 91 ExternalReference::debug_after_break_target_address(masm->isolate());
148 __ jmp(Operand::StaticVariable(after_break_target)); 92 __ jmp(Operand::StaticVariable(after_break_target));
149 } 93 }
150 94
151 95
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) { 96 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
180 masm->ret(0); 97 masm->ret(0);
181 } 98 }
182 99
183 100
184 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { 101 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
185 ExternalReference restarter_frame_function_slot = 102 ExternalReference restarter_frame_function_slot =
186 ExternalReference::debug_restarter_frame_function_pointer_address( 103 ExternalReference::debug_restarter_frame_function_pointer_address(
187 masm->isolate()); 104 masm->isolate());
188 __ mov(Operand::StaticVariable(restarter_frame_function_slot), Immediate(0)); 105 __ mov(Operand::StaticVariable(restarter_frame_function_slot), Immediate(0));
(...skipping 18 matching lines...) Expand all
207 124
208 125
209 const bool LiveEdit::kFrameDropperSupported = true; 126 const bool LiveEdit::kFrameDropperSupported = true;
210 127
211 #undef __ 128 #undef __
212 129
213 } // namespace internal 130 } // namespace internal
214 } // namespace v8 131 } // namespace v8
215 132
216 #endif // V8_TARGET_ARCH_IA32 133 #endif // V8_TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698