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

Side by Side Diff: src/arm64/debug-arm64.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/arm64/assembler-arm64-inl.h ('k') | src/arm64/full-codegen-arm64.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 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 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_ARM64 7 #if V8_TARGET_ARCH_ARM64
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 namespace v8 { 12 namespace v8 {
13 namespace internal { 13 namespace internal {
14 14
15
16 #define __ ACCESS_MASM(masm) 15 #define __ ACCESS_MASM(masm)
17 16
18 17
19 void BreakLocation::SetDebugBreakAtReturn() { 18 void EmitDebugBreakSlot(Assembler* masm) {
20 // Patch the code emitted by FullCodeGenerator::EmitReturnSequence, changing 19 Label check_size;
21 // the return from JS function sequence from 20 __ bind(&check_size);
22 // mov sp, fp 21 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
23 // ldp fp, lr, [sp] #16 22 __ nop(Assembler::DEBUG_BREAK_NOP);
24 // lrd ip0, [pc, #(3 * kInstructionSize)] 23 }
25 // add sp, sp, ip0 24 DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
26 // ret 25 static_cast<int>(masm->InstructionsGeneratedSince(&check_size)));
27 // <number of paramters ...
28 // ... plus one (64 bits)>
29 // to a call to the debug break return code.
30 // ldr ip0, [pc, #(3 * kInstructionSize)]
31 // blr ip0
32 // hlt kHltBadCode @ code should not return, catch if it does.
33 // <debug break return code ...
34 // ... entry point address (64 bits)>
35
36 // The patching code must not overflow the space occupied by the return
37 // sequence.
38 STATIC_ASSERT(Assembler::kJSReturnSequenceInstructions >= 5);
39 PatchingAssembler patcher(reinterpret_cast<Instruction*>(pc()), 5);
40 byte* entry =
41 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry();
42
43 // The first instruction of a patched return sequence must be a load literal
44 // loading the address of the debug break return code.
45 patcher.ldr_pcrel(ip0, (3 * kInstructionSize) >> kLoadLiteralScaleLog2);
46 // TODO(all): check the following is correct.
47 // The debug break return code will push a frame and call statically compiled
48 // code. By using blr, even though control will not return after the branch,
49 // this call site will be registered in the frame (lr being saved as the pc
50 // of the next instruction to execute for this frame). The debugger can now
51 // iterate on the frames to find call to debug break return code.
52 patcher.blr(ip0);
53 patcher.hlt(kHltBadCode);
54 patcher.dc64(reinterpret_cast<int64_t>(entry));
55 } 26 }
56 27
57 28
58 void BreakLocation::SetDebugBreakAtSlot() { 29 void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode,
59 DCHECK(IsDebugBreakSlot()); 30 int call_argc) {
31 // Generate enough nop's to make space for a call instruction. Avoid emitting
32 // the constant pool in the debug break slot code.
33 InstructionAccurateScope scope(masm, Assembler::kDebugBreakSlotInstructions);
34 masm->RecordDebugBreakSlot(mode, call_argc);
35 EmitDebugBreakSlot(masm);
36 }
37
38
39 void DebugCodegen::ClearDebugBreakSlot(Address pc) {
40 PatchingAssembler patcher(reinterpret_cast<Instruction*>(pc),
41 Assembler::kDebugBreakSlotInstructions);
42 EmitDebugBreakSlot(&patcher);
43 }
44
45
46 void DebugCodegen::PatchDebugBreakSlot(Address pc, Handle<Code> code) {
47 DCHECK_EQ(Code::BUILTIN, code->kind());
48 PatchingAssembler patcher(reinterpret_cast<Instruction*>(pc),
49 Assembler::kDebugBreakSlotInstructions);
60 // Patch the code emitted by DebugCodegen::GenerateSlots, changing the debug 50 // Patch the code emitted by DebugCodegen::GenerateSlots, changing the debug
61 // break slot code from 51 // break slot code from
62 // mov x0, x0 @ nop DEBUG_BREAK_NOP 52 // mov x0, x0 @ nop DEBUG_BREAK_NOP
63 // mov x0, x0 @ nop DEBUG_BREAK_NOP 53 // mov x0, x0 @ nop DEBUG_BREAK_NOP
64 // mov x0, x0 @ nop DEBUG_BREAK_NOP 54 // mov x0, x0 @ nop DEBUG_BREAK_NOP
65 // mov x0, x0 @ nop DEBUG_BREAK_NOP 55 // mov x0, x0 @ nop DEBUG_BREAK_NOP
56 // mov x0, x0 @ nop DEBUG_BREAK_NOP
66 // to a call to the debug slot code. 57 // to a call to the debug slot code.
67 // ldr ip0, [pc, #(2 * kInstructionSize)] 58 // ldr ip0, [pc, #(2 * kInstructionSize)]
68 // blr ip0 59 // blr ip0
69 // <debug break slot code ... 60 // b skip
70 // ... entry point address (64 bits)> 61 // <debug break slot code entry point address (64 bits)>
62 // skip:
71 63
72 // TODO(all): consider adding a hlt instruction after the blr as we don't 64 Label skip_constant;
73 // expect control to return here. This implies increasing
74 // kDebugBreakSlotInstructions to 5 instructions.
75
76 // The patching code must not overflow the space occupied by the return
77 // sequence.
78 STATIC_ASSERT(Assembler::kDebugBreakSlotInstructions >= 4);
79 PatchingAssembler patcher(reinterpret_cast<Instruction*>(pc()), 4);
80 byte* entry =
81 debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry();
82
83 // The first instruction of a patched debug break slot must be a load literal 65 // The first instruction of a patched debug break slot must be a load literal
84 // loading the address of the debug break slot code. 66 // loading the address of the debug break slot code.
85 patcher.ldr_pcrel(ip0, (2 * kInstructionSize) >> kLoadLiteralScaleLog2); 67 patcher.ldr_pcrel(ip0, (2 * kInstructionSize) >> kLoadLiteralScaleLog2);
68 patcher.b(&skip_constant);
69 patcher.dc64(reinterpret_cast<int64_t>(code->entry()));
70 patcher.bind(&skip_constant);
86 // TODO(all): check the following is correct. 71 // TODO(all): check the following is correct.
87 // The debug break slot code will push a frame and call statically compiled 72 // The debug break slot code will push a frame and call statically compiled
88 // code. By using blr, event hough control will not return after the branch, 73 // code. By using blr, this call site will be registered in the frame.
89 // this call site will be registered in the frame (lr being saved as the pc 74 // The debugger can now iterate on the frames to find this call.
90 // of the next instruction to execute for this frame). The debugger can now
91 // iterate on the frames to find call to debug break slot code.
92 patcher.blr(ip0); 75 patcher.blr(ip0);
93 patcher.dc64(reinterpret_cast<int64_t>(entry));
94 } 76 }
95 77
96 78
97 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, 79 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
98 RegList object_regs) { 80 DebugBreakCallHelperMode mode) {
81 __ RecordComment("Debug break");
99 Register scratch = x10; 82 Register scratch = x10;
100 { 83 {
101 FrameScope scope(masm, StackFrame::INTERNAL); 84 FrameScope scope(masm, StackFrame::INTERNAL);
102 85
103 // Load padding words on stack. 86 // Load padding words on stack.
104 __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingValue)); 87 __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingValue));
105 __ PushMultipleTimes(scratch, LiveEdit::kFramePaddingInitialSize); 88 __ PushMultipleTimes(scratch, LiveEdit::kFramePaddingInitialSize);
106 __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); 89 __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
107 __ Push(scratch); 90 __ Push(scratch);
108 91
109 // Any live values (object_regs and non_object_regs) in caller-saved 92 if (mode == SAVE_RESULT_REGISTER) __ Push(x0);
110 // registers (or lr) need to be stored on the stack so that their values are
111 // safely preserved for a call into C code.
112 //
113 // Also:
114 // * object_regs may be modified during the C code by the garbage
115 // collector. Every object register must be a valid tagged pointer or
116 // SMI.
117 //
118 // * non_object_regs will be converted to SMIs so that the garbage
119 // collector doesn't try to interpret them as pointers.
120 //
121 // TODO(jbramley): Why can't this handle callee-saved registers?
122 DCHECK((~kCallerSaved.list() & object_regs) == 0);
123 DCHECK((scratch.Bit() & object_regs) == 0);
124 DCHECK((masm->TmpList()->list() & object_regs) == 0);
125 STATIC_ASSERT(kSmiValueSize == 32);
126 93
127 if (object_regs != 0) {
128 __ PushXRegList(object_regs);
129 }
130
131 #ifdef DEBUG
132 __ RecordComment("// Calling from debug break to runtime - come in - over");
133 #endif
134 __ Mov(x0, 0); // No arguments. 94 __ Mov(x0, 0); // No arguments.
135 __ Mov(x1, ExternalReference::debug_break(masm->isolate())); 95 __ Mov(x1, ExternalReference::debug_break(masm->isolate()));
136 96
137 CEntryStub stub(masm->isolate(), 1); 97 CEntryStub stub(masm->isolate(), 1);
138 __ CallStub(&stub); 98 __ CallStub(&stub);
139 99
100 if (FLAG_debug_code) {
101 for (int i = 0; i < kNumJSCallerSaved; i++) {
102 Register reg = Register::XRegFromCode(JSCallerSavedCode(i));
103 __ Mov(reg, Operand(kDebugZapValue));
104 }
105 }
106
140 // Restore the register values from the expression stack. 107 // Restore the register values from the expression stack.
141 if (object_regs != 0) { 108 if (mode == SAVE_RESULT_REGISTER) __ Pop(x0);
142 __ PopXRegList(object_regs);
143 }
144 109
145 // Don't bother removing padding bytes pushed on the stack 110 // Don't bother removing padding bytes pushed on the stack
146 // as the frame is going to be restored right away. 111 // as the frame is going to be restored right away.
147 112
148 // Leave the internal frame. 113 // Leave the internal frame.
149 } 114 }
150 115
151 // Now that the break point has been handled, resume normal execution by 116 // Now that the break point has been handled, resume normal execution by
152 // jumping to the target address intended by the caller and that was 117 // jumping to the target address intended by the caller and that was
153 // overwritten by the address of DebugBreakXXX. 118 // overwritten by the address of DebugBreakXXX.
154 ExternalReference after_break_target = 119 ExternalReference after_break_target =
155 ExternalReference::debug_after_break_target_address(masm->isolate()); 120 ExternalReference::debug_after_break_target_address(masm->isolate());
156 __ Mov(scratch, after_break_target); 121 __ Mov(scratch, after_break_target);
157 __ Ldr(scratch, MemOperand(scratch)); 122 __ Ldr(scratch, MemOperand(scratch));
158 __ Br(scratch); 123 __ Br(scratch);
159 } 124 }
160 125
161 126
162 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
163 // In places other than IC call sites it is expected that r0 is TOS which
164 // is an object - this is not generally the case so this should be used with
165 // care.
166 Generate_DebugBreakCallHelper(masm, x0.Bit());
167 }
168
169
170 void DebugCodegen::GenerateSlot(MacroAssembler* masm,
171 DebugCodegen::SlotLocation location,
172 int call_argc) {
173 // Generate enough nop's to make space for a call instruction. Avoid emitting
174 // the constant pool in the debug break slot code.
175 InstructionAccurateScope scope(masm, Assembler::kDebugBreakSlotInstructions);
176 RecordRelocInfo(masm, location, call_argc);
177 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
178 __ nop(Assembler::DEBUG_BREAK_NOP);
179 }
180 }
181
182
183 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
184 // In the places where a debug break slot is inserted no registers can contain
185 // object pointers.
186 Generate_DebugBreakCallHelper(masm, 0);
187 }
188
189
190 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { 127 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
191 __ Ret(); 128 __ Ret();
192 } 129 }
193 130
194 131
195 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { 132 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
196 ExternalReference restarter_frame_function_slot = 133 ExternalReference restarter_frame_function_slot =
197 ExternalReference::debug_restarter_frame_function_pointer_address( 134 ExternalReference::debug_restarter_frame_function_pointer_address(
198 masm->isolate()); 135 masm->isolate());
199 UseScratchRegisterScope temps(masm); 136 UseScratchRegisterScope temps(masm);
(...skipping 20 matching lines...) Expand all
220 __ Br(scratch); 157 __ Br(scratch);
221 } 158 }
222 159
223 160
224 const bool LiveEdit::kFrameDropperSupported = true; 161 const bool LiveEdit::kFrameDropperSupported = true;
225 162
226 } // namespace internal 163 } // namespace internal
227 } // namespace v8 164 } // namespace v8
228 165
229 #endif // V8_TARGET_ARCH_ARM64 166 #endif // V8_TARGET_ARCH_ARM64
OLDNEW
« no previous file with comments | « src/arm64/assembler-arm64-inl.h ('k') | src/arm64/full-codegen-arm64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698