OLD | NEW |
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" |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 // code. By using blr, event hough control will not return after the branch, | 87 // code. By using blr, event hough control will not return after the branch, |
88 // this call site will be registered in the frame (lr being saved as the pc | 88 // this call site will be registered in the frame (lr being saved as the pc |
89 // of the next instruction to execute for this frame). The debugger can now | 89 // of the next instruction to execute for this frame). The debugger can now |
90 // iterate on the frames to find call to debug break slot code. | 90 // iterate on the frames to find call to debug break slot code. |
91 patcher.blr(ip0); | 91 patcher.blr(ip0); |
92 patcher.dc64(reinterpret_cast<int64_t>(entry)); | 92 patcher.dc64(reinterpret_cast<int64_t>(entry)); |
93 } | 93 } |
94 | 94 |
95 | 95 |
96 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, | 96 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, |
97 RegList object_regs, | 97 RegList object_regs) { |
98 RegList non_object_regs, | 98 Register scratch = x10; |
99 Register scratch) { | |
100 { | 99 { |
101 FrameScope scope(masm, StackFrame::INTERNAL); | 100 FrameScope scope(masm, StackFrame::INTERNAL); |
102 | 101 |
103 // Load padding words on stack. | 102 // Load padding words on stack. |
104 __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingValue)); | 103 __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingValue)); |
105 __ PushMultipleTimes(scratch, LiveEdit::kFramePaddingInitialSize); | 104 __ PushMultipleTimes(scratch, LiveEdit::kFramePaddingInitialSize); |
106 __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); | 105 __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); |
107 __ Push(scratch); | 106 __ Push(scratch); |
108 | 107 |
109 // Any live values (object_regs and non_object_regs) in caller-saved | 108 // Any live values (object_regs and non_object_regs) in caller-saved |
110 // registers (or lr) need to be stored on the stack so that their values are | 109 // registers (or lr) need to be stored on the stack so that their values are |
111 // safely preserved for a call into C code. | 110 // safely preserved for a call into C code. |
112 // | 111 // |
113 // Also: | 112 // Also: |
114 // * object_regs may be modified during the C code by the garbage | 113 // * object_regs may be modified during the C code by the garbage |
115 // collector. Every object register must be a valid tagged pointer or | 114 // collector. Every object register must be a valid tagged pointer or |
116 // SMI. | 115 // SMI. |
117 // | 116 // |
118 // * non_object_regs will be converted to SMIs so that the garbage | 117 // * non_object_regs will be converted to SMIs so that the garbage |
119 // collector doesn't try to interpret them as pointers. | 118 // collector doesn't try to interpret them as pointers. |
120 // | 119 // |
121 // TODO(jbramley): Why can't this handle callee-saved registers? | 120 // TODO(jbramley): Why can't this handle callee-saved registers? |
122 DCHECK((~kCallerSaved.list() & object_regs) == 0); | 121 DCHECK((~kCallerSaved.list() & object_regs) == 0); |
123 DCHECK((~kCallerSaved.list() & non_object_regs) == 0); | |
124 DCHECK((object_regs & non_object_regs) == 0); | |
125 DCHECK((scratch.Bit() & object_regs) == 0); | 122 DCHECK((scratch.Bit() & object_regs) == 0); |
126 DCHECK((scratch.Bit() & non_object_regs) == 0); | 123 DCHECK((masm->TmpList()->list() & object_regs) == 0); |
127 DCHECK((masm->TmpList()->list() & (object_regs | non_object_regs)) == 0); | |
128 STATIC_ASSERT(kSmiValueSize == 32); | 124 STATIC_ASSERT(kSmiValueSize == 32); |
129 | 125 |
130 CPURegList non_object_list = | |
131 CPURegList(CPURegister::kRegister, kXRegSizeInBits, non_object_regs); | |
132 while (!non_object_list.IsEmpty()) { | |
133 // Store each non-object register as two SMIs. | |
134 Register reg = Register(non_object_list.PopLowestIndex()); | |
135 __ Lsr(scratch, reg, 32); | |
136 __ SmiTagAndPush(scratch, reg); | |
137 | |
138 // Stack: | |
139 // jssp[12]: reg[63:32] | |
140 // jssp[8]: 0x00000000 (SMI tag & padding) | |
141 // jssp[4]: reg[31:0] | |
142 // jssp[0]: 0x00000000 (SMI tag & padding) | |
143 STATIC_ASSERT(kSmiTag == 0); | |
144 STATIC_ASSERT(static_cast<unsigned>(kSmiShift) == kWRegSizeInBits); | |
145 } | |
146 | |
147 if (object_regs != 0) { | 126 if (object_regs != 0) { |
148 __ PushXRegList(object_regs); | 127 __ PushXRegList(object_regs); |
149 } | 128 } |
150 | 129 |
151 #ifdef DEBUG | 130 #ifdef DEBUG |
152 __ RecordComment("// Calling from debug break to runtime - come in - over"); | 131 __ RecordComment("// Calling from debug break to runtime - come in - over"); |
153 #endif | 132 #endif |
154 __ Mov(x0, 0); // No arguments. | 133 __ Mov(x0, 0); // No arguments. |
155 __ Mov(x1, ExternalReference::debug_break(masm->isolate())); | 134 __ Mov(x1, ExternalReference::debug_break(masm->isolate())); |
156 | 135 |
157 CEntryStub stub(masm->isolate(), 1); | 136 CEntryStub stub(masm->isolate(), 1); |
158 __ CallStub(&stub); | 137 __ CallStub(&stub); |
159 | 138 |
160 // Restore the register values from the expression stack. | 139 // Restore the register values from the expression stack. |
161 if (object_regs != 0) { | 140 if (object_regs != 0) { |
162 __ PopXRegList(object_regs); | 141 __ PopXRegList(object_regs); |
163 } | 142 } |
164 | 143 |
165 non_object_list = | |
166 CPURegList(CPURegister::kRegister, kXRegSizeInBits, non_object_regs); | |
167 while (!non_object_list.IsEmpty()) { | |
168 // Load each non-object register from two SMIs. | |
169 // Stack: | |
170 // jssp[12]: reg[63:32] | |
171 // jssp[8]: 0x00000000 (SMI tag & padding) | |
172 // jssp[4]: reg[31:0] | |
173 // jssp[0]: 0x00000000 (SMI tag & padding) | |
174 Register reg = Register(non_object_list.PopHighestIndex()); | |
175 __ Pop(scratch, reg); | |
176 __ Bfxil(reg, scratch, 32, 32); | |
177 } | |
178 | |
179 // Don't bother removing padding bytes pushed on the stack | 144 // Don't bother removing padding bytes pushed on the stack |
180 // as the frame is going to be restored right away. | 145 // as the frame is going to be restored right away. |
181 | 146 |
182 // Leave the internal frame. | 147 // Leave the internal frame. |
183 } | 148 } |
184 | 149 |
185 // Now that the break point has been handled, resume normal execution by | 150 // Now that the break point has been handled, resume normal execution by |
186 // jumping to the target address intended by the caller and that was | 151 // jumping to the target address intended by the caller and that was |
187 // overwritten by the address of DebugBreakXXX. | 152 // overwritten by the address of DebugBreakXXX. |
188 ExternalReference after_break_target = | 153 ExternalReference after_break_target = |
189 ExternalReference::debug_after_break_target_address(masm->isolate()); | 154 ExternalReference::debug_after_break_target_address(masm->isolate()); |
190 __ Mov(scratch, after_break_target); | 155 __ Mov(scratch, after_break_target); |
191 __ Ldr(scratch, MemOperand(scratch)); | 156 __ Ldr(scratch, MemOperand(scratch)); |
192 __ Br(scratch); | 157 __ Br(scratch); |
193 } | 158 } |
194 | 159 |
195 | 160 |
196 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) { | |
197 // Register state for CallICStub | |
198 // ----------- S t a t e ------------- | |
199 // -- x1 : function | |
200 // -- x3 : slot in feedback array | |
201 // ----------------------------------- | |
202 Generate_DebugBreakCallHelper(masm, x1.Bit() | x3.Bit(), 0, x10); | |
203 } | |
204 | |
205 | |
206 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) { | 161 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) { |
207 // In places other than IC call sites it is expected that r0 is TOS which | 162 // In places other than IC call sites it is expected that r0 is TOS which |
208 // is an object - this is not generally the case so this should be used with | 163 // is an object - this is not generally the case so this should be used with |
209 // care. | 164 // care. |
210 Generate_DebugBreakCallHelper(masm, x0.Bit(), 0, x10); | 165 Generate_DebugBreakCallHelper(masm, x0.Bit()); |
211 } | 166 } |
212 | 167 |
213 | 168 |
214 void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) { | |
215 // Register state for CallFunctionStub (from code-stubs-arm64.cc). | |
216 // ----------- S t a t e ------------- | |
217 // -- x1 : function | |
218 // ----------------------------------- | |
219 Generate_DebugBreakCallHelper(masm, x1.Bit(), 0, x10); | |
220 } | |
221 | |
222 | |
223 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) { | |
224 // Calling convention for CallConstructStub (from code-stubs-arm64.cc). | |
225 // ----------- S t a t e ------------- | |
226 // -- x0 : number of arguments (not smi) | |
227 // -- x1 : constructor function | |
228 // ----------------------------------- | |
229 Generate_DebugBreakCallHelper(masm, x1.Bit(), x0.Bit(), x10); | |
230 } | |
231 | |
232 | |
233 void DebugCodegen::GenerateCallConstructStubRecordDebugBreak( | |
234 MacroAssembler* masm) { | |
235 // Calling convention for CallConstructStub (from code-stubs-arm64.cc). | |
236 // ----------- S t a t e ------------- | |
237 // -- x0 : number of arguments (not smi) | |
238 // -- x1 : constructor function | |
239 // -- x2 : feedback array | |
240 // -- x3 : feedback slot (smi) | |
241 // ----------------------------------- | |
242 Generate_DebugBreakCallHelper( | |
243 masm, x1.Bit() | x2.Bit() | x3.Bit(), x0.Bit(), x10); | |
244 } | |
245 | |
246 | |
247 void DebugCodegen::GenerateSlot(MacroAssembler* masm) { | 169 void DebugCodegen::GenerateSlot(MacroAssembler* masm) { |
248 // Generate enough nop's to make space for a call instruction. Avoid emitting | 170 // Generate enough nop's to make space for a call instruction. Avoid emitting |
249 // the constant pool in the debug break slot code. | 171 // the constant pool in the debug break slot code. |
250 InstructionAccurateScope scope(masm, Assembler::kDebugBreakSlotInstructions); | 172 InstructionAccurateScope scope(masm, Assembler::kDebugBreakSlotInstructions); |
251 | 173 |
252 __ RecordDebugBreakSlot(); | |
253 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) { | 174 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) { |
254 __ nop(Assembler::DEBUG_BREAK_NOP); | 175 __ nop(Assembler::DEBUG_BREAK_NOP); |
255 } | 176 } |
256 } | 177 } |
257 | 178 |
258 | 179 |
259 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) { | 180 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) { |
260 // In the places where a debug break slot is inserted no registers can contain | 181 // In the places where a debug break slot is inserted no registers can contain |
261 // object pointers. | 182 // object pointers. |
262 Generate_DebugBreakCallHelper(masm, 0, 0, x10); | 183 Generate_DebugBreakCallHelper(masm, 0); |
263 } | 184 } |
264 | 185 |
265 | 186 |
266 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { | 187 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { |
267 __ Ret(); | 188 __ Ret(); |
268 } | 189 } |
269 | 190 |
270 | 191 |
271 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { | 192 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { |
272 ExternalReference restarter_frame_function_slot = | 193 ExternalReference restarter_frame_function_slot = |
(...skipping 23 matching lines...) Expand all Loading... |
296 __ Br(scratch); | 217 __ Br(scratch); |
297 } | 218 } |
298 | 219 |
299 | 220 |
300 const bool LiveEdit::kFrameDropperSupported = true; | 221 const bool LiveEdit::kFrameDropperSupported = true; |
301 | 222 |
302 } // namespace internal | 223 } // namespace internal |
303 } // namespace v8 | 224 } // namespace v8 |
304 | 225 |
305 #endif // V8_TARGET_ARCH_ARM64 | 226 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |