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

Side by Side Diff: src/x64/debug-x64.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/x64/assembler-x64-inl.h ('k') | src/x64/full-codegen-x64.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_X64 7 #if V8_TARGET_ARCH_X64
8 8
9 #include "src/assembler.h" 9 #include "src/assembler.h"
10 #include "src/codegen.h" 10 #include "src/codegen.h"
11 #include "src/debug.h" 11 #include "src/debug.h"
12 12
13 13
14 namespace v8 { 14 namespace v8 {
15 namespace internal { 15 namespace internal {
16 16
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 int code_size = Assembler::kCallSequenceLength + guard_bytes;
21
22 // Create a code patcher.
23 CodePatcher patcher(pc, code_size);
24
25 // Add a label for checking the size of the code used for returning.
26 #ifdef DEBUG
27 Label check_codesize;
28 patcher.masm()->bind(&check_codesize);
29 #endif
30
31 // Patch the code.
32 patcher.masm()->movp(kScratchRegister, reinterpret_cast<void*>(target),
33 Assembler::RelocInfoNone());
34 patcher.masm()->call(kScratchRegister);
35
36 // Check that the size of the code generated is as expected.
37 DCHECK_EQ(Assembler::kCallSequenceLength,
38 patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
39
40 // Add the requested number of int3 instructions after the call.
41 for (int i = 0; i < guard_bytes; i++) {
42 patcher.masm()->int3();
43 }
44
45 CpuFeatures::FlushICache(pc, code_size);
46 }
47
48
49 // Patch the JS frame exit code with a debug break call. See
50 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc
51 // for the precise return instructions sequence.
52 void BreakLocation::SetDebugBreakAtReturn() {
53 DCHECK(Assembler::kJSReturnSequenceLength >= Assembler::kCallSequenceLength);
54 PatchCodeWithCall(
55 pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
56 Assembler::kJSReturnSequenceLength - Assembler::kCallSequenceLength);
57 }
58
59
60 void BreakLocation::SetDebugBreakAtSlot() {
61 DCHECK(IsDebugBreakSlot());
62 PatchCodeWithCall(
63 pc(), debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry(),
64 Assembler::kDebugBreakSlotLength - Assembler::kCallSequenceLength);
65 }
66
67
68 #define __ ACCESS_MASM(masm) 17 #define __ ACCESS_MASM(masm)
69 18
70 19
71 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, 20 void EmitDebugBreakSlot(MacroAssembler* masm) {
72 RegList object_regs) { 21 Label check_codesize;
22 __ bind(&check_codesize);
23 __ Nop(Assembler::kDebugBreakSlotLength);
24 DCHECK_EQ(Assembler::kDebugBreakSlotLength,
25 masm->SizeOfCodeGeneratedSince(&check_codesize));
26 }
27
28
29 void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode,
30 int call_argc) {
31 // Generate enough nop's to make space for a call instruction.
32 masm->RecordDebugBreakSlot(mode, call_argc);
33 EmitDebugBreakSlot(masm);
34 }
35
36
37 void DebugCodegen::ClearDebugBreakSlot(Address pc) {
38 CodePatcher patcher(pc, Assembler::kDebugBreakSlotLength);
39 EmitDebugBreakSlot(patcher.masm());
40 }
41
42
43 void DebugCodegen::PatchDebugBreakSlot(Address pc, Handle<Code> code) {
44 DCHECK_EQ(Code::BUILTIN, code->kind());
45 static const int kSize = Assembler::kDebugBreakSlotLength;
46 CodePatcher patcher(pc, kSize);
47 Label check_codesize;
48 patcher.masm()->bind(&check_codesize);
49 patcher.masm()->movp(kScratchRegister, reinterpret_cast<void*>(code->entry()),
50 Assembler::RelocInfoNone());
51 patcher.masm()->call(kScratchRegister);
52 // Check that the size of the code generated is as expected.
53 DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
54 }
55
56
57 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
58 DebugBreakCallHelperMode mode) {
59 __ RecordComment("Debug break");
60
73 // Enter an internal frame. 61 // Enter an internal frame.
74 { 62 {
75 FrameScope scope(masm, StackFrame::INTERNAL); 63 FrameScope scope(masm, StackFrame::INTERNAL);
76 64
77 // Load padding words on stack. 65 // Load padding words on stack.
78 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { 66 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
79 __ Push(Smi::FromInt(LiveEdit::kFramePaddingValue)); 67 __ Push(Smi::FromInt(LiveEdit::kFramePaddingValue));
80 } 68 }
81 __ Push(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); 69 __ Push(Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
82 70
83 // Store the registers containing live values on the expression stack to 71 if (mode == SAVE_RESULT_REGISTER) __ Push(rax);
84 // make sure that these are correctly updated during GC. Non object values
85 // are stored as as two smis causing it to be untouched by GC.
86 DCHECK((object_regs & ~kJSCallerSaved) == 0);
87 for (int i = 0; i < kNumJSCallerSaved; i++) {
88 int r = JSCallerSavedCode(i);
89 Register reg = { r };
90 DCHECK(!reg.is(kScratchRegister));
91 if ((object_regs & (1 << r)) != 0) {
92 __ Push(reg);
93 }
94 }
95 72
96 #ifdef DEBUG
97 __ RecordComment("// Calling from debug break to runtime - come in - over");
98 #endif
99 __ Set(rax, 0); // No arguments (argc == 0). 73 __ Set(rax, 0); // No arguments (argc == 0).
100 __ Move(rbx, ExternalReference::debug_break(masm->isolate())); 74 __ Move(rbx, ExternalReference::debug_break(masm->isolate()));
101 75
102 CEntryStub ceb(masm->isolate(), 1); 76 CEntryStub ceb(masm->isolate(), 1);
103 __ CallStub(&ceb); 77 __ CallStub(&ceb);
104 78
105 // Restore the register values from the expression stack. 79 if (FLAG_debug_code) {
106 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) { 80 for (int i = 0; i < kNumJSCallerSaved; ++i) {
107 int r = JSCallerSavedCode(i); 81 Register reg = {JSCallerSavedCode(i)};
108 Register reg = { r };
109 if (FLAG_debug_code) {
110 __ Set(reg, kDebugZapValue); 82 __ Set(reg, kDebugZapValue);
111 } 83 }
112 if ((object_regs & (1 << r)) != 0) {
113 __ Pop(reg);
114 }
115 } 84 }
116 85
86 if (mode == SAVE_RESULT_REGISTER) __ Pop(rax);
87
117 // Read current padding counter and skip corresponding number of words. 88 // Read current padding counter and skip corresponding number of words.
118 __ Pop(kScratchRegister); 89 __ Pop(kScratchRegister);
119 __ SmiToInteger32(kScratchRegister, kScratchRegister); 90 __ SmiToInteger32(kScratchRegister, kScratchRegister);
120 __ leap(rsp, Operand(rsp, kScratchRegister, times_pointer_size, 0)); 91 __ leap(rsp, Operand(rsp, kScratchRegister, times_pointer_size, 0));
121 92
122 // Get rid of the internal frame. 93 // Get rid of the internal frame.
123 } 94 }
124 95
125 // This call did not replace a call , so there will be an unwanted 96 // This call did not replace a call , so there will be an unwanted
126 // return address left on the stack. Here we get rid of that. 97 // return address left on the stack. Here we get rid of that.
127 __ addp(rsp, Immediate(kPCOnStackSize)); 98 __ addp(rsp, Immediate(kPCOnStackSize));
128 99
129 // Now that the break point has been handled, resume normal execution by 100 // Now that the break point has been handled, resume normal execution by
130 // jumping to the target address intended by the caller and that was 101 // jumping to the target address intended by the caller and that was
131 // overwritten by the address of DebugBreakXXX. 102 // overwritten by the address of DebugBreakXXX.
132 ExternalReference after_break_target = 103 ExternalReference after_break_target =
133 ExternalReference::debug_after_break_target_address(masm->isolate()); 104 ExternalReference::debug_after_break_target_address(masm->isolate());
134 __ Move(kScratchRegister, after_break_target); 105 __ Move(kScratchRegister, after_break_target);
135 __ Jump(Operand(kScratchRegister, 0)); 106 __ Jump(Operand(kScratchRegister, 0));
136 } 107 }
137 108
138 109
139 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
140 // Register state just before return from JS function (from codegen-x64.cc).
141 // ----------- S t a t e -------------
142 // -- rax: return value
143 // -----------------------------------
144 Generate_DebugBreakCallHelper(masm, rax.bit());
145 }
146
147
148 void DebugCodegen::GenerateSlot(MacroAssembler* masm,
149 DebugCodegen::SlotLocation location,
150 int call_argc) {
151 // Generate enough nop's to make space for a call instruction.
152 Label check_codesize;
153 __ bind(&check_codesize);
154 RecordRelocInfo(masm, location, call_argc);
155 __ Nop(Assembler::kDebugBreakSlotLength);
156 DCHECK_EQ(Assembler::kDebugBreakSlotLength,
157 masm->SizeOfCodeGeneratedSince(&check_codesize));
158 }
159
160
161 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
162 // In the places where a debug break slot is inserted no registers can contain
163 // object pointers.
164 Generate_DebugBreakCallHelper(masm, 0);
165 }
166
167
168 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { 110 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
169 masm->ret(0); 111 masm->ret(0);
170 } 112 }
171 113
172 114
173 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { 115 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
174 ExternalReference restarter_frame_function_slot = 116 ExternalReference restarter_frame_function_slot =
175 ExternalReference::debug_restarter_frame_function_pointer_address( 117 ExternalReference::debug_restarter_frame_function_pointer_address(
176 masm->isolate()); 118 masm->isolate());
177 __ Move(rax, restarter_frame_function_slot); 119 __ Move(rax, restarter_frame_function_slot);
(...skipping 18 matching lines...) Expand all
196 } 138 }
197 139
198 const bool LiveEdit::kFrameDropperSupported = true; 140 const bool LiveEdit::kFrameDropperSupported = true;
199 141
200 #undef __ 142 #undef __
201 143
202 } // namespace internal 144 } // namespace internal
203 } // namespace v8 145 } // namespace v8
204 146
205 #endif // V8_TARGET_ARCH_X64 147 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/assembler-x64-inl.h ('k') | src/x64/full-codegen-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698