OLD | NEW |
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 #include "src/api.h" | 7 #include "src/api.h" |
8 #include "src/arguments.h" | 8 #include "src/arguments.h" |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) { | 53 static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) { |
54 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); | 54 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); |
55 // Isolate::context() may have been NULL when "script collected" event | 55 // Isolate::context() may have been NULL when "script collected" event |
56 // occured. | 56 // occured. |
57 if (context.is_null()) return v8::Local<v8::Context>(); | 57 if (context.is_null()) return v8::Local<v8::Context>(); |
58 Handle<Context> native_context(context->native_context()); | 58 Handle<Context> native_context(context->native_context()); |
59 return v8::Utils::ToLocal(native_context); | 59 return v8::Utils::ToLocal(native_context); |
60 } | 60 } |
61 | 61 |
62 | 62 |
63 BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info, | 63 BreakLocation::Iterator::Iterator(Handle<DebugInfo> debug_info, |
64 BreakLocatorType type) { | 64 BreakLocatorType type) |
65 debug_info_ = debug_info; | 65 : debug_info_(debug_info), |
66 type_ = type; | 66 type_(type), |
67 reloc_iterator_ = NULL; | 67 reloc_iterator_(debug_info->code(), |
68 reloc_iterator_original_ = NULL; | 68 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)), |
69 Reset(); // Initialize the rest of the member variables. | 69 reloc_iterator_original_( |
| 70 debug_info->original_code(), |
| 71 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)), |
| 72 break_index_(-1), |
| 73 position_(1), |
| 74 statement_position_(1) { |
| 75 Next(); |
70 } | 76 } |
71 | 77 |
72 | 78 |
73 BreakLocationIterator::~BreakLocationIterator() { | 79 void BreakLocation::Iterator::Next() { |
74 DCHECK(reloc_iterator_ != NULL); | |
75 DCHECK(reloc_iterator_original_ != NULL); | |
76 delete reloc_iterator_; | |
77 delete reloc_iterator_original_; | |
78 } | |
79 | |
80 | |
81 // Check whether a code stub with the specified major key is a possible break | |
82 // point location when looking for source break locations. | |
83 static bool IsSourceBreakStub(Code* code) { | |
84 CodeStub::Major major_key = CodeStub::GetMajorKey(code); | |
85 return major_key == CodeStub::CallFunction; | |
86 } | |
87 | |
88 | |
89 // Check whether a code stub with the specified major key is a possible break | |
90 // location. | |
91 static bool IsBreakStub(Code* code) { | |
92 CodeStub::Major major_key = CodeStub::GetMajorKey(code); | |
93 return major_key == CodeStub::CallFunction; | |
94 } | |
95 | |
96 | |
97 void BreakLocationIterator::Next() { | |
98 DisallowHeapAllocation no_gc; | 80 DisallowHeapAllocation no_gc; |
99 DCHECK(!RinfoDone()); | 81 DCHECK(!RinfoDone()); |
100 | 82 |
101 // Iterate through reloc info for code and original code stopping at each | 83 // Iterate through reloc info for code and original code stopping at each |
102 // breakable code target. | 84 // breakable code target. |
103 bool first = break_point_ == -1; | 85 bool first = break_index_ == -1; |
104 while (!RinfoDone()) { | 86 while (!RinfoDone()) { |
105 if (!first) RinfoNext(); | 87 if (!first) RinfoNext(); |
106 first = false; | 88 first = false; |
107 if (RinfoDone()) return; | 89 if (RinfoDone()) return; |
108 | 90 |
109 // Whenever a statement position or (plain) position is passed update the | 91 // Whenever a statement position or (plain) position is passed update the |
110 // current value of these. | 92 // current value of these. |
111 if (RelocInfo::IsPosition(rmode())) { | 93 if (RelocInfo::IsPosition(rmode())) { |
112 if (RelocInfo::IsStatementPosition(rmode())) { | 94 if (RelocInfo::IsStatementPosition(rmode())) { |
113 statement_position_ = static_cast<int>( | 95 statement_position_ = static_cast<int>( |
114 rinfo()->data() - debug_info_->shared()->start_position()); | 96 rinfo()->data() - debug_info_->shared()->start_position()); |
115 } | 97 } |
116 // Always update the position as we don't want that to be before the | 98 // Always update the position as we don't want that to be before the |
117 // statement position. | 99 // statement position. |
118 position_ = static_cast<int>( | 100 position_ = static_cast<int>(rinfo()->data() - |
119 rinfo()->data() - debug_info_->shared()->start_position()); | 101 debug_info_->shared()->start_position()); |
120 DCHECK(position_ >= 0); | 102 DCHECK(position_ >= 0); |
121 DCHECK(statement_position_ >= 0); | 103 DCHECK(statement_position_ >= 0); |
122 } | 104 } |
123 | 105 |
124 // Check for break at return. | 106 // Check for break at return. |
125 if (RelocInfo::IsJSReturn(rmode())) { | 107 if (RelocInfo::IsJSReturn(rmode())) { |
126 // Set the positions to the end of the function. | 108 // Set the positions to the end of the function. |
127 if (debug_info_->shared()->HasSourceCode()) { | 109 if (debug_info_->shared()->HasSourceCode()) { |
128 position_ = debug_info_->shared()->end_position() - | 110 position_ = debug_info_->shared()->end_position() - |
129 debug_info_->shared()->start_position() - 1; | 111 debug_info_->shared()->start_position() - 1; |
130 } else { | 112 } else { |
131 position_ = 0; | 113 position_ = 0; |
132 } | 114 } |
133 statement_position_ = position_; | 115 statement_position_ = position_; |
134 break_point_++; | 116 break_index_++; |
135 return; | 117 return; |
136 } | 118 } |
137 | 119 |
138 if (RelocInfo::IsCodeTarget(rmode())) { | 120 if (RelocInfo::IsCodeTarget(rmode())) { |
139 // Check for breakable code target. Look in the original code as setting | 121 // Check for breakable code target. Look in the original code as setting |
140 // break points can cause the code targets in the running (debugged) code | 122 // break points can cause the code targets in the running (debugged) code |
141 // to be of a different kind than in the original code. | 123 // to be of a different kind than in the original code. |
142 Address target = original_rinfo()->target_address(); | 124 Address target = original_rinfo()->target_address(); |
143 Code* code = Code::GetCodeFromTargetAddress(target); | 125 Code* code = Code::GetCodeFromTargetAddress(target); |
144 | 126 |
145 if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) { | 127 if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) { |
146 break_point_++; | 128 break_index_++; |
147 return; | 129 return; |
148 } | 130 } |
149 | 131 |
150 // Skip below if we only want locations for calls and returns. | 132 // Skip below if we only want locations for calls and returns. |
151 if (type_ == CALLS_AND_RETURNS) continue; | 133 if (type_ == CALLS_AND_RETURNS) continue; |
152 | 134 |
153 if ((code->is_inline_cache_stub() && !code->is_binary_op_stub() && | 135 if ((code->is_inline_cache_stub() && !code->is_binary_op_stub() && |
154 !code->is_compare_ic_stub() && !code->is_to_boolean_ic_stub())) { | 136 !code->is_compare_ic_stub() && !code->is_to_boolean_ic_stub())) { |
155 break_point_++; | 137 break_index_++; |
156 return; | 138 return; |
157 } | 139 } |
158 if (code->kind() == Code::STUB) { | 140 if (code->kind() == Code::STUB) { |
159 if (IsDebuggerStatement()) { | 141 if (RelocInfo::IsDebuggerStatement(rmode())) { |
160 break_point_++; | 142 break_index_++; |
161 return; | 143 return; |
162 } else if (type_ == ALL_BREAK_LOCATIONS) { | 144 } else if (CodeStub::GetMajorKey(code) == CodeStub::CallFunction) { |
163 if (IsBreakStub(code)) { | 145 break_index_++; |
164 break_point_++; | 146 return; |
165 return; | |
166 } | |
167 } else { | |
168 DCHECK(type_ == SOURCE_BREAK_LOCATIONS); | |
169 if (IsSourceBreakStub(code)) { | |
170 break_point_++; | |
171 return; | |
172 } | |
173 } | 147 } |
174 } | 148 } |
175 } | 149 } |
176 | 150 |
177 if (IsDebugBreakSlot() && type_ != CALLS_AND_RETURNS) { | 151 if (RelocInfo::IsDebugBreakSlot(rmode()) && type_ != CALLS_AND_RETURNS) { |
178 // There is always a possible break point at a debug break slot. | 152 // There is always a possible break point at a debug break slot. |
179 break_point_++; | 153 break_index_++; |
180 return; | 154 return; |
181 } | 155 } |
182 } | 156 } |
183 } | 157 } |
184 | 158 |
185 | 159 |
186 void BreakLocationIterator::Next(int count) { | 160 // Find the break point at the supplied address, or the closest one before |
187 while (count > 0) { | 161 // the address. |
188 Next(); | 162 BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info, |
189 count--; | 163 BreakLocatorType type, Address pc) { |
190 } | 164 Iterator it(debug_info, type); |
| 165 it.SkipTo(BreakIndexFromAddress(debug_info, type, pc)); |
| 166 return it.GetBreakLocation(); |
191 } | 167 } |
192 | 168 |
193 | 169 |
194 // Find the break point at the supplied address, or the closest one before | 170 // Find the break point at the supplied address, or the closest one before |
195 // the address. | 171 // the address. |
196 void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) { | 172 void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info, |
| 173 BreakLocatorType type, Address pc, |
| 174 List<BreakLocation>* result_out) { |
| 175 int break_index = BreakIndexFromAddress(debug_info, type, pc); |
| 176 Iterator it(debug_info, type); |
| 177 it.SkipTo(break_index); |
| 178 int statement_position = it.statement_position(); |
| 179 while (!it.Done() && it.statement_position() == statement_position) { |
| 180 result_out->Add(it.GetBreakLocation()); |
| 181 it.Next(); |
| 182 } |
| 183 } |
| 184 |
| 185 |
| 186 int BreakLocation::BreakIndexFromAddress(Handle<DebugInfo> debug_info, |
| 187 BreakLocatorType type, Address pc) { |
197 // Run through all break points to locate the one closest to the address. | 188 // Run through all break points to locate the one closest to the address. |
198 int closest_break_point = 0; | 189 int closest_break = 0; |
199 int distance = kMaxInt; | 190 int distance = kMaxInt; |
200 while (!Done()) { | 191 for (Iterator it(debug_info, type); !it.Done(); it.Next()) { |
201 // Check if this break point is closer that what was previously found. | 192 // Check if this break point is closer that what was previously found. |
202 if (this->pc() <= pc && pc - this->pc() < distance) { | 193 if (it.pc() <= pc && pc - it.pc() < distance) { |
203 closest_break_point = break_point(); | 194 closest_break = it.break_index(); |
204 distance = static_cast<int>(pc - this->pc()); | 195 distance = static_cast<int>(pc - it.pc()); |
205 // Check whether we can't get any closer. | 196 // Check whether we can't get any closer. |
206 if (distance == 0) break; | 197 if (distance == 0) break; |
207 } | 198 } |
208 Next(); | |
209 } | 199 } |
210 | 200 return closest_break; |
211 // Move to the break point found. | |
212 Reset(); | |
213 Next(closest_break_point); | |
214 } | 201 } |
215 | 202 |
216 | 203 |
217 // Find the break point closest to the supplied source position. | 204 BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info, |
218 void BreakLocationIterator::FindBreakLocationFromPosition(int position, | 205 BreakLocatorType type, int position, |
219 BreakPositionAlignment alignment) { | 206 BreakPositionAlignment alignment) { |
220 // Run through all break points to locate the one closest to the source | 207 // Run through all break points to locate the one closest to the source |
221 // position. | 208 // position. |
222 int closest_break_point = 0; | 209 int closest_break = 0; |
223 int distance = kMaxInt; | 210 int distance = kMaxInt; |
224 | 211 |
225 while (!Done()) { | 212 for (Iterator it(debug_info, type); !it.Done(); it.Next()) { |
226 int next_position; | 213 int next_position; |
227 switch (alignment) { | 214 if (alignment == STATEMENT_ALIGNED) { |
228 case STATEMENT_ALIGNED: | 215 next_position = it.statement_position(); |
229 next_position = this->statement_position(); | 216 } else { |
230 break; | 217 DCHECK(alignment == BREAK_POSITION_ALIGNED); |
231 case BREAK_POSITION_ALIGNED: | 218 next_position = it.position(); |
232 next_position = this->position(); | |
233 break; | |
234 default: | |
235 UNREACHABLE(); | |
236 next_position = this->statement_position(); | |
237 } | 219 } |
238 // Check if this break point is closer that what was previously found. | |
239 if (position <= next_position && next_position - position < distance) { | 220 if (position <= next_position && next_position - position < distance) { |
240 closest_break_point = break_point(); | 221 closest_break = it.break_index(); |
241 distance = next_position - position; | 222 distance = next_position - position; |
242 // Check whether we can't get any closer. | 223 // Check whether we can't get any closer. |
243 if (distance == 0) break; | 224 if (distance == 0) break; |
244 } | 225 } |
245 Next(); | |
246 } | 226 } |
247 | 227 |
248 // Move to the break point found. | 228 Iterator it(debug_info, type); |
249 Reset(); | 229 it.SkipTo(closest_break); |
250 Next(closest_break_point); | 230 return it.GetBreakLocation(); |
251 } | 231 } |
252 | 232 |
253 | 233 |
254 void BreakLocationIterator::Reset() { | 234 void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) { |
255 // Create relocation iterators for the two code objects. | |
256 if (reloc_iterator_ != NULL) delete reloc_iterator_; | |
257 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_; | |
258 reloc_iterator_ = new RelocIterator( | |
259 debug_info_->code(), | |
260 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)); | |
261 reloc_iterator_original_ = new RelocIterator( | |
262 debug_info_->original_code(), | |
263 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)); | |
264 | |
265 // Position at the first break point. | |
266 break_point_ = -1; | |
267 position_ = 1; | |
268 statement_position_ = 1; | |
269 Next(); | |
270 } | |
271 | |
272 | |
273 bool BreakLocationIterator::Done() const { | |
274 return RinfoDone(); | |
275 } | |
276 | |
277 | |
278 void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) { | |
279 // If there is not already a real break point here patch code with debug | 235 // If there is not already a real break point here patch code with debug |
280 // break. | 236 // break. |
281 if (!HasBreakPoint()) SetDebugBreak(); | 237 if (!HasBreakPoint()) SetDebugBreak(); |
282 DCHECK(IsDebugBreak() || IsDebuggerStatement()); | 238 DCHECK(IsDebugBreak() || IsDebuggerStatement()); |
283 // Set the break point information. | 239 // Set the break point information. |
284 DebugInfo::SetBreakPoint(debug_info_, code_position(), | 240 DebugInfo::SetBreakPoint(debug_info_, pc_offset_, position_, |
285 position(), statement_position(), | 241 statement_position_, break_point_object); |
286 break_point_object); | |
287 } | 242 } |
288 | 243 |
289 | 244 |
290 void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) { | 245 void BreakLocation::ClearBreakPoint(Handle<Object> break_point_object) { |
291 // Clear the break point information. | 246 // Clear the break point information. |
292 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object); | 247 DebugInfo::ClearBreakPoint(debug_info_, pc_offset_, break_point_object); |
293 // If there are no more break points here remove the debug break. | 248 // If there are no more break points here remove the debug break. |
294 if (!HasBreakPoint()) { | 249 if (!HasBreakPoint()) { |
295 ClearDebugBreak(); | 250 ClearDebugBreak(); |
296 DCHECK(!IsDebugBreak()); | 251 DCHECK(!IsDebugBreak()); |
297 } | 252 } |
298 } | 253 } |
299 | 254 |
300 | 255 |
301 void BreakLocationIterator::SetOneShot() { | 256 void BreakLocation::SetOneShot() { |
302 // Debugger statement always calls debugger. No need to modify it. | 257 // Debugger statement always calls debugger. No need to modify it. |
303 if (IsDebuggerStatement()) return; | 258 if (IsDebuggerStatement()) return; |
304 | 259 |
305 // If there is a real break point here no more to do. | 260 // If there is a real break point here no more to do. |
306 if (HasBreakPoint()) { | 261 if (HasBreakPoint()) { |
307 DCHECK(IsDebugBreak()); | 262 DCHECK(IsDebugBreak()); |
308 return; | 263 return; |
309 } | 264 } |
310 | 265 |
311 // Patch code with debug break. | 266 // Patch code with debug break. |
312 SetDebugBreak(); | 267 SetDebugBreak(); |
313 } | 268 } |
314 | 269 |
315 | 270 |
316 void BreakLocationIterator::ClearOneShot() { | 271 void BreakLocation::ClearOneShot() { |
317 // Debugger statement always calls debugger. No need to modify it. | 272 // Debugger statement always calls debugger. No need to modify it. |
318 if (IsDebuggerStatement()) return; | 273 if (IsDebuggerStatement()) return; |
319 | 274 |
320 // If there is a real break point here no more to do. | 275 // If there is a real break point here no more to do. |
321 if (HasBreakPoint()) { | 276 if (HasBreakPoint()) { |
322 DCHECK(IsDebugBreak()); | 277 DCHECK(IsDebugBreak()); |
323 return; | 278 return; |
324 } | 279 } |
325 | 280 |
326 // Patch code removing debug break. | 281 // Patch code removing debug break. |
327 ClearDebugBreak(); | 282 ClearDebugBreak(); |
328 DCHECK(!IsDebugBreak()); | 283 DCHECK(!IsDebugBreak()); |
329 } | 284 } |
330 | 285 |
331 | 286 |
332 void BreakLocationIterator::SetDebugBreak() { | 287 void BreakLocation::SetDebugBreak() { |
333 // Debugger statement always calls debugger. No need to modify it. | 288 // Debugger statement always calls debugger. No need to modify it. |
334 if (IsDebuggerStatement()) return; | 289 if (IsDebuggerStatement()) return; |
335 | 290 |
336 // If there is already a break point here just return. This might happen if | 291 // If there is already a break point here just return. This might happen if |
337 // the same code is flooded with break points twice. Flooding the same | 292 // the same code is flooded with break points twice. Flooding the same |
338 // function twice might happen when stepping in a function with an exception | 293 // function twice might happen when stepping in a function with an exception |
339 // handler as the handler and the function is the same. | 294 // handler as the handler and the function is the same. |
340 if (IsDebugBreak()) return; | 295 if (IsDebugBreak()) return; |
341 | 296 |
342 if (RelocInfo::IsJSReturn(rmode())) { | 297 if (IsExit()) { |
343 // Patch the frame exit code with a break point. | 298 // Patch the frame exit code with a break point. |
344 SetDebugBreakAtReturn(); | 299 SetDebugBreakAtReturn(); |
345 } else if (IsDebugBreakSlot()) { | 300 } else if (IsDebugBreakSlot()) { |
346 // Patch the code in the break slot. | 301 // Patch the code in the break slot. |
347 SetDebugBreakAtSlot(); | 302 SetDebugBreakAtSlot(); |
348 } else { | 303 } else { |
349 // Patch the IC call. | 304 // Patch the IC call. |
350 SetDebugBreakAtIC(); | 305 SetDebugBreakAtIC(); |
351 } | 306 } |
352 DCHECK(IsDebugBreak()); | 307 DCHECK(IsDebugBreak()); |
353 } | 308 } |
354 | 309 |
355 | 310 |
356 void BreakLocationIterator::ClearDebugBreak() { | 311 void BreakLocation::ClearDebugBreak() { |
357 // Debugger statement always calls debugger. No need to modify it. | 312 // Debugger statement always calls debugger. No need to modify it. |
358 if (IsDebuggerStatement()) return; | 313 if (IsDebuggerStatement()) return; |
359 | 314 |
360 if (RelocInfo::IsJSReturn(rmode())) { | 315 if (IsExit()) { |
361 // Restore the frame exit code. | 316 // Restore the frame exit code with a break point. |
362 ClearDebugBreakAtReturn(); | 317 RestoreFromOriginal(Assembler::kJSReturnSequenceLength); |
363 } else if (IsDebugBreakSlot()) { | 318 } else if (IsDebugBreakSlot()) { |
364 // Restore the code in the break slot. | 319 // Restore the code in the break slot. |
365 ClearDebugBreakAtSlot(); | 320 RestoreFromOriginal(Assembler::kDebugBreakSlotLength); |
366 } else { | 321 } else { |
367 // Patch the IC call. | 322 // Restore the IC call. |
368 ClearDebugBreakAtIC(); | 323 rinfo().set_target_address(original_rinfo().target_address()); |
369 } | 324 } |
370 DCHECK(!IsDebugBreak()); | 325 DCHECK(!IsDebugBreak()); |
371 } | 326 } |
372 | 327 |
373 | 328 |
374 bool BreakLocationIterator::IsStepInLocation(Isolate* isolate) { | 329 void BreakLocation::RestoreFromOriginal(int length_in_bytes) { |
375 if (RelocInfo::IsConstructCall(original_rmode())) { | 330 memcpy(pc(), original_pc(), length_in_bytes); |
376 return true; | 331 CpuFeatures::FlushICache(pc(), length_in_bytes); |
377 } else if (RelocInfo::IsCodeTarget(rmode())) { | 332 } |
| 333 |
| 334 |
| 335 bool BreakLocation::IsStepInLocation() const { |
| 336 if (IsConstructCall()) return true; |
| 337 if (RelocInfo::IsCodeTarget(rmode())) { |
378 HandleScope scope(debug_info_->GetIsolate()); | 338 HandleScope scope(debug_info_->GetIsolate()); |
379 Address target = original_rinfo()->target_address(); | 339 Handle<Code> target_code = CodeTarget(); |
380 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); | |
381 if (target_code->kind() == Code::STUB) { | |
382 return CodeStub::GetMajorKey(*target_code) == CodeStub::CallFunction; | |
383 } | |
384 return target_code->is_call_stub(); | 340 return target_code->is_call_stub(); |
385 } | 341 } |
386 return false; | 342 return false; |
387 } | 343 } |
388 | 344 |
389 | 345 |
390 // Check whether the break point is at a position which will exit the function. | 346 bool BreakLocation::IsDebugBreak() const { |
391 bool BreakLocationIterator::IsExit() const { | 347 if (IsExit()) { |
392 return (RelocInfo::IsJSReturn(rmode())); | 348 return rinfo().IsPatchedReturnSequence(); |
393 } | |
394 | |
395 | |
396 bool BreakLocationIterator::HasBreakPoint() { | |
397 return debug_info_->HasBreakPoint(code_position()); | |
398 } | |
399 | |
400 | |
401 // Check whether there is a debug break at the current position. | |
402 bool BreakLocationIterator::IsDebugBreak() { | |
403 if (RelocInfo::IsJSReturn(rmode())) { | |
404 return IsDebugBreakAtReturn(); | |
405 } else if (IsDebugBreakSlot()) { | 349 } else if (IsDebugBreakSlot()) { |
406 return IsDebugBreakAtSlot(); | 350 return rinfo().IsPatchedDebugBreakSlotSequence(); |
407 } else { | 351 } else { |
408 return Debug::IsDebugBreak(rinfo()->target_address()); | 352 return Debug::IsDebugBreak(rinfo().target_address()); |
409 } | 353 } |
410 } | 354 } |
411 | 355 |
412 | 356 |
413 // Find the builtin to use for invoking the debug break | 357 // Find the builtin to use for invoking the debug break |
414 static Handle<Code> DebugBreakForIC(Handle<Code> code, RelocInfo::Mode mode) { | 358 static Handle<Code> DebugBreakForIC(Handle<Code> code, RelocInfo::Mode mode) { |
415 Isolate* isolate = code->GetIsolate(); | 359 Isolate* isolate = code->GetIsolate(); |
416 | 360 |
417 // Find the builtin debug break function matching the calling convention | 361 // Find the builtin debug break function matching the calling convention |
418 // used by the call site. | 362 // used by the call site. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 if (code->kind() == Code::STUB) { | 394 if (code->kind() == Code::STUB) { |
451 DCHECK(CodeStub::GetMajorKey(*code) == CodeStub::CallFunction); | 395 DCHECK(CodeStub::GetMajorKey(*code) == CodeStub::CallFunction); |
452 return isolate->builtins()->CallFunctionStub_DebugBreak(); | 396 return isolate->builtins()->CallFunctionStub_DebugBreak(); |
453 } | 397 } |
454 | 398 |
455 UNREACHABLE(); | 399 UNREACHABLE(); |
456 return Handle<Code>::null(); | 400 return Handle<Code>::null(); |
457 } | 401 } |
458 | 402 |
459 | 403 |
460 void BreakLocationIterator::SetDebugBreakAtIC() { | 404 void BreakLocation::SetDebugBreakAtIC() { |
461 // Patch the original code with the current address as the current address | 405 // Patch the original code with the current address as the current address |
462 // might have changed by the inline caching since the code was copied. | 406 // might have changed by the inline caching since the code was copied. |
463 original_rinfo()->set_target_address(rinfo()->target_address()); | 407 original_rinfo().set_target_address(rinfo().target_address()); |
464 | 408 |
465 RelocInfo::Mode mode = rmode(); | 409 if (RelocInfo::IsCodeTarget(rmode_)) { |
466 if (RelocInfo::IsCodeTarget(mode)) { | 410 Handle<Code> target_code = CodeTarget(); |
467 Address target = rinfo()->target_address(); | |
468 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); | |
469 | 411 |
470 // Patch the code to invoke the builtin debug break function matching the | 412 // Patch the code to invoke the builtin debug break function matching the |
471 // calling convention used by the call site. | 413 // calling convention used by the call site. |
472 Handle<Code> dbgbrk_code = DebugBreakForIC(target_code, mode); | 414 Handle<Code> debug_break_code = DebugBreakForIC(target_code, rmode_); |
473 rinfo()->set_target_address(dbgbrk_code->entry()); | 415 rinfo().set_target_address(debug_break_code->entry()); |
474 } | 416 } |
475 } | 417 } |
476 | 418 |
477 | 419 |
478 void BreakLocationIterator::ClearDebugBreakAtIC() { | 420 Handle<Object> BreakLocation::BreakPointObjects() const { |
479 // Patch the code to the original invoke. | 421 return debug_info_->GetBreakPointObjects(pc_offset_); |
480 rinfo()->set_target_address(original_rinfo()->target_address()); | |
481 } | 422 } |
482 | 423 |
483 | 424 |
484 bool BreakLocationIterator::IsDebuggerStatement() { | 425 Handle<Code> BreakLocation::CodeTarget() const { |
485 return RelocInfo::DEBUG_BREAK == rmode(); | 426 DCHECK(IsCodeTarget()); |
| 427 Address target = rinfo().target_address(); |
| 428 return Handle<Code>(Code::GetCodeFromTargetAddress(target)); |
486 } | 429 } |
487 | 430 |
488 | 431 |
489 bool BreakLocationIterator::IsDebugBreakSlot() { | 432 Handle<Code> BreakLocation::OriginalCodeTarget() const { |
490 return RelocInfo::DEBUG_BREAK_SLOT == rmode(); | 433 DCHECK(IsCodeTarget()); |
| 434 Address target = original_rinfo().target_address(); |
| 435 return Handle<Code>(Code::GetCodeFromTargetAddress(target)); |
491 } | 436 } |
492 | 437 |
493 | 438 |
494 Object* BreakLocationIterator::BreakPointObjects() { | 439 bool BreakLocation::Iterator::RinfoDone() const { |
495 return debug_info_->GetBreakPointObjects(code_position()); | 440 DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); |
| 441 return reloc_iterator_.done(); |
496 } | 442 } |
497 | 443 |
498 | 444 |
499 // Clear out all the debug break code. This is ONLY supposed to be used when | 445 void BreakLocation::Iterator::RinfoNext() { |
500 // shutting down the debugger as it will leave the break point information in | 446 reloc_iterator_.next(); |
501 // DebugInfo even though the code is patched back to the non break point state. | 447 reloc_iterator_original_.next(); |
502 void BreakLocationIterator::ClearAllDebugBreak() { | |
503 while (!Done()) { | |
504 ClearDebugBreak(); | |
505 Next(); | |
506 } | |
507 } | |
508 | |
509 | |
510 bool BreakLocationIterator::RinfoDone() const { | |
511 DCHECK(reloc_iterator_->done() == reloc_iterator_original_->done()); | |
512 return reloc_iterator_->done(); | |
513 } | |
514 | |
515 | |
516 void BreakLocationIterator::RinfoNext() { | |
517 reloc_iterator_->next(); | |
518 reloc_iterator_original_->next(); | |
519 #ifdef DEBUG | 448 #ifdef DEBUG |
520 DCHECK(reloc_iterator_->done() == reloc_iterator_original_->done()); | 449 DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); |
521 if (!reloc_iterator_->done()) { | 450 DCHECK(reloc_iterator_.done() || rmode() == original_rmode()); |
522 DCHECK(rmode() == original_rmode()); | |
523 } | |
524 #endif | 451 #endif |
525 } | 452 } |
526 | 453 |
527 | 454 |
528 // Threading support. | 455 // Threading support. |
529 void Debug::ThreadInit() { | 456 void Debug::ThreadInit() { |
530 thread_local_.break_count_ = 0; | 457 thread_local_.break_count_ = 0; |
531 thread_local_.break_id_ = 0; | 458 thread_local_.break_id_ = 0; |
532 thread_local_.break_frame_id_ = StackFrame::NO_ID; | 459 thread_local_.break_frame_id_ = StackFrame::NO_ID; |
533 thread_local_.last_step_action_ = StepNone; | 460 thread_local_.last_step_action_ = StepNone; |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
847 | 774 |
848 // Postpone interrupt during breakpoint processing. | 775 // Postpone interrupt during breakpoint processing. |
849 PostponeInterruptsScope postpone(isolate_); | 776 PostponeInterruptsScope postpone(isolate_); |
850 | 777 |
851 // Get the debug info (create it if it does not exist). | 778 // Get the debug info (create it if it does not exist). |
852 Handle<SharedFunctionInfo> shared = | 779 Handle<SharedFunctionInfo> shared = |
853 Handle<SharedFunctionInfo>(frame->function()->shared()); | 780 Handle<SharedFunctionInfo>(frame->function()->shared()); |
854 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 781 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
855 | 782 |
856 // Find the break point where execution has stopped. | 783 // Find the break point where execution has stopped. |
857 BreakLocationIterator break_location_iterator(debug_info, | 784 // PC points to the instruction after the current one, possibly a break |
858 ALL_BREAK_LOCATIONS); | |
859 // pc points to the instruction after the current one, possibly a break | |
860 // location as well. So the "- 1" to exclude it from the search. | 785 // location as well. So the "- 1" to exclude it from the search. |
861 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); | 786 Address call_pc = frame->pc() - 1; |
| 787 BreakLocation break_location = |
| 788 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); |
862 | 789 |
863 // Check whether step next reached a new statement. | 790 // Check whether step next reached a new statement. |
864 if (!StepNextContinue(&break_location_iterator, frame)) { | 791 if (!StepNextContinue(&break_location, frame)) { |
865 // Decrease steps left if performing multiple steps. | 792 // Decrease steps left if performing multiple steps. |
866 if (thread_local_.step_count_ > 0) { | 793 if (thread_local_.step_count_ > 0) { |
867 thread_local_.step_count_--; | 794 thread_local_.step_count_--; |
868 } | 795 } |
869 } | 796 } |
870 | 797 |
871 // If there is one or more real break points check whether any of these are | 798 // If there is one or more real break points check whether any of these are |
872 // triggered. | 799 // triggered. |
873 Handle<Object> break_points_hit(heap->undefined_value(), isolate_); | 800 Handle<Object> break_points_hit(heap->undefined_value(), isolate_); |
874 if (break_location_iterator.HasBreakPoint()) { | 801 if (break_location.HasBreakPoint()) { |
875 Handle<Object> break_point_objects = | 802 Handle<Object> break_point_objects = break_location.BreakPointObjects(); |
876 Handle<Object>(break_location_iterator.BreakPointObjects(), isolate_); | |
877 break_points_hit = CheckBreakPoints(break_point_objects); | 803 break_points_hit = CheckBreakPoints(break_point_objects); |
878 } | 804 } |
879 | 805 |
880 // If step out is active skip everything until the frame where we need to step | 806 // If step out is active skip everything until the frame where we need to step |
881 // out to is reached, unless real breakpoint is hit. | 807 // out to is reached, unless real breakpoint is hit. |
882 if (StepOutActive() && | 808 if (StepOutActive() && |
883 frame->fp() != thread_local_.step_out_fp_ && | 809 frame->fp() != thread_local_.step_out_fp_ && |
884 break_points_hit->IsUndefined() ) { | 810 break_points_hit->IsUndefined() ) { |
885 // Step count should always be 0 for StepOut. | 811 // Step count should always be 0 for StepOut. |
886 DCHECK(thread_local_.step_count_ == 0); | 812 DCHECK(thread_local_.step_count_ == 0); |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1051 if (!EnsureDebugInfo(shared, function)) { | 977 if (!EnsureDebugInfo(shared, function)) { |
1052 // Return if retrieving debug info failed. | 978 // Return if retrieving debug info failed. |
1053 return true; | 979 return true; |
1054 } | 980 } |
1055 | 981 |
1056 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 982 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
1057 // Source positions starts with zero. | 983 // Source positions starts with zero. |
1058 DCHECK(*source_position >= 0); | 984 DCHECK(*source_position >= 0); |
1059 | 985 |
1060 // Find the break point and change it. | 986 // Find the break point and change it. |
1061 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS); | 987 BreakLocation location = BreakLocation::FromPosition( |
1062 it.FindBreakLocationFromPosition(*source_position, STATEMENT_ALIGNED); | 988 debug_info, SOURCE_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED); |
1063 it.SetBreakPoint(break_point_object); | 989 *source_position = location.statement_position(); |
1064 | 990 location.SetBreakPoint(break_point_object); |
1065 *source_position = it.statement_position(); | |
1066 | 991 |
1067 // At least one active break point now. | 992 // At least one active break point now. |
1068 return debug_info->GetBreakPointCount() > 0; | 993 return debug_info->GetBreakPointCount() > 0; |
1069 } | 994 } |
1070 | 995 |
1071 | 996 |
1072 bool Debug::SetBreakPointForScript(Handle<Script> script, | 997 bool Debug::SetBreakPointForScript(Handle<Script> script, |
1073 Handle<Object> break_point_object, | 998 Handle<Object> break_point_object, |
1074 int* source_position, | 999 int* source_position, |
1075 BreakPositionAlignment alignment) { | 1000 BreakPositionAlignment alignment) { |
1076 HandleScope scope(isolate_); | 1001 HandleScope scope(isolate_); |
1077 | 1002 |
1078 PrepareForBreakPoints(); | 1003 PrepareForBreakPoints(); |
1079 | 1004 |
1080 // Obtain shared function info for the function. | 1005 // Obtain shared function info for the function. |
1081 Object* result = FindSharedFunctionInfoInScript(script, *source_position); | 1006 Handle<Object> result = |
| 1007 FindSharedFunctionInfoInScript(script, *source_position); |
1082 if (result->IsUndefined()) return false; | 1008 if (result->IsUndefined()) return false; |
1083 | 1009 |
1084 // Make sure the function has set up the debug info. | 1010 // Make sure the function has set up the debug info. |
1085 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result)); | 1011 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result); |
1086 if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) { | 1012 if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) { |
1087 // Return if retrieving debug info failed. | 1013 // Return if retrieving debug info failed. |
1088 return false; | 1014 return false; |
1089 } | 1015 } |
1090 | 1016 |
1091 // Find position within function. The script position might be before the | 1017 // Find position within function. The script position might be before the |
1092 // source position of the first function. | 1018 // source position of the first function. |
1093 int position; | 1019 int position; |
1094 if (shared->start_position() > *source_position) { | 1020 if (shared->start_position() > *source_position) { |
1095 position = 0; | 1021 position = 0; |
1096 } else { | 1022 } else { |
1097 position = *source_position - shared->start_position(); | 1023 position = *source_position - shared->start_position(); |
1098 } | 1024 } |
1099 | 1025 |
1100 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 1026 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
1101 // Source positions starts with zero. | 1027 // Source positions starts with zero. |
1102 DCHECK(position >= 0); | 1028 DCHECK(position >= 0); |
1103 | 1029 |
1104 // Find the break point and change it. | 1030 // Find the break point and change it. |
1105 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS); | 1031 BreakLocation location = BreakLocation::FromPosition( |
1106 it.FindBreakLocationFromPosition(position, alignment); | 1032 debug_info, SOURCE_BREAK_LOCATIONS, position, alignment); |
1107 it.SetBreakPoint(break_point_object); | 1033 location.SetBreakPoint(break_point_object); |
1108 | 1034 |
1109 position = (alignment == STATEMENT_ALIGNED) ? it.statement_position() | 1035 position = (alignment == STATEMENT_ALIGNED) ? location.statement_position() |
1110 : it.position(); | 1036 : location.position(); |
1111 | 1037 |
1112 *source_position = position + shared->start_position(); | 1038 *source_position = position + shared->start_position(); |
1113 | 1039 |
1114 // At least one active break point now. | 1040 // At least one active break point now. |
1115 DCHECK(debug_info->GetBreakPointCount() > 0); | 1041 DCHECK(debug_info->GetBreakPointCount() > 0); |
1116 return true; | 1042 return true; |
1117 } | 1043 } |
1118 | 1044 |
1119 | 1045 |
1120 void Debug::ClearBreakPoint(Handle<Object> break_point_object) { | 1046 void Debug::ClearBreakPoint(Handle<Object> break_point_object) { |
1121 HandleScope scope(isolate_); | 1047 HandleScope scope(isolate_); |
1122 | 1048 |
1123 DebugInfoListNode* node = debug_info_list_; | 1049 DebugInfoListNode* node = debug_info_list_; |
1124 while (node != NULL) { | 1050 while (node != NULL) { |
1125 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(), | 1051 Handle<Object> result = |
1126 break_point_object); | 1052 DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object); |
1127 if (!result->IsUndefined()) { | 1053 if (!result->IsUndefined()) { |
1128 // Get information in the break point. | 1054 // Get information in the break point. |
1129 BreakPointInfo* break_point_info = BreakPointInfo::cast(result); | 1055 Handle<BreakPointInfo> break_point_info = |
| 1056 Handle<BreakPointInfo>::cast(result); |
1130 Handle<DebugInfo> debug_info = node->debug_info(); | 1057 Handle<DebugInfo> debug_info = node->debug_info(); |
1131 | 1058 |
1132 // Find the break point and clear it. | 1059 // Find the break point and clear it. |
1133 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS); | 1060 Address pc = debug_info->code()->entry() + |
1134 it.FindBreakLocationFromAddress(debug_info->code()->entry() + | 1061 break_point_info->code_position()->value(); |
1135 break_point_info->code_position()->value()); | 1062 |
1136 it.ClearBreakPoint(break_point_object); | 1063 BreakLocation location = |
| 1064 BreakLocation::FromAddress(debug_info, SOURCE_BREAK_LOCATIONS, pc); |
| 1065 location.ClearBreakPoint(break_point_object); |
1137 | 1066 |
1138 // If there are no more break points left remove the debug info for this | 1067 // If there are no more break points left remove the debug info for this |
1139 // function. | 1068 // function. |
1140 if (debug_info->GetBreakPointCount() == 0) { | 1069 if (debug_info->GetBreakPointCount() == 0) { |
1141 RemoveDebugInfoAndClearFromShared(debug_info); | 1070 RemoveDebugInfoAndClearFromShared(debug_info); |
1142 } | 1071 } |
1143 | 1072 |
1144 return; | 1073 return; |
1145 } | 1074 } |
1146 node = node->next(); | 1075 node = node->next(); |
1147 } | 1076 } |
1148 } | 1077 } |
1149 | 1078 |
1150 | 1079 |
| 1080 // Clear out all the debug break code. This is ONLY supposed to be used when |
| 1081 // shutting down the debugger as it will leave the break point information in |
| 1082 // DebugInfo even though the code is patched back to the non break point state. |
1151 void Debug::ClearAllBreakPoints() { | 1083 void Debug::ClearAllBreakPoints() { |
1152 DebugInfoListNode* node = debug_info_list_; | 1084 for (DebugInfoListNode* node = debug_info_list_; node != NULL; |
1153 while (node != NULL) { | 1085 node = node->next()) { |
1154 // Remove all debug break code. | 1086 for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS); |
1155 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); | 1087 !it.Done(); it.Next()) { |
1156 it.ClearAllDebugBreak(); | 1088 it.GetBreakLocation().ClearDebugBreak(); |
1157 node = node->next(); | 1089 } |
1158 } | 1090 } |
1159 | |
1160 // Remove all debug info. | 1091 // Remove all debug info. |
1161 while (debug_info_list_ != NULL) { | 1092 while (debug_info_list_ != NULL) { |
1162 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); | 1093 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); |
1163 } | 1094 } |
1164 } | 1095 } |
1165 | 1096 |
1166 | 1097 |
1167 void Debug::FloodWithOneShot(Handle<JSFunction> function, | 1098 void Debug::FloodWithOneShot(Handle<JSFunction> function, |
1168 BreakLocatorType type) { | 1099 BreakLocatorType type) { |
1169 // Do not ever break in native functions. | 1100 // Do not ever break in native functions. |
1170 if (function->IsFromNativeScript()) return; | 1101 if (function->IsFromNativeScript()) return; |
1171 | 1102 |
1172 PrepareForBreakPoints(); | 1103 PrepareForBreakPoints(); |
1173 | 1104 |
1174 // Make sure the function is compiled and has set up the debug info. | 1105 // Make sure the function is compiled and has set up the debug info. |
1175 Handle<SharedFunctionInfo> shared(function->shared()); | 1106 Handle<SharedFunctionInfo> shared(function->shared()); |
1176 if (!EnsureDebugInfo(shared, function)) { | 1107 if (!EnsureDebugInfo(shared, function)) { |
1177 // Return if we failed to retrieve the debug info. | 1108 // Return if we failed to retrieve the debug info. |
1178 return; | 1109 return; |
1179 } | 1110 } |
1180 | 1111 |
1181 // Flood the function with break points. | 1112 // Flood the function with break points. |
1182 BreakLocationIterator it(GetDebugInfo(shared), type); | 1113 for (BreakLocation::Iterator it(GetDebugInfo(shared), type); !it.Done(); |
1183 while (!it.Done()) { | 1114 it.Next()) { |
1184 it.SetOneShot(); | 1115 it.GetBreakLocation().SetOneShot(); |
1185 it.Next(); | |
1186 } | 1116 } |
1187 } | 1117 } |
1188 | 1118 |
1189 | 1119 |
1190 void Debug::FloodBoundFunctionWithOneShot(Handle<JSFunction> function) { | 1120 void Debug::FloodBoundFunctionWithOneShot(Handle<JSFunction> function) { |
1191 Handle<FixedArray> new_bindings(function->function_bindings()); | 1121 Handle<FixedArray> new_bindings(function->function_bindings()); |
1192 Handle<Object> bindee(new_bindings->get(JSFunction::kBoundFunctionIndex), | 1122 Handle<Object> bindee(new_bindings->get(JSFunction::kBoundFunctionIndex), |
1193 isolate_); | 1123 isolate_); |
1194 | 1124 |
1195 if (!bindee.is_null() && bindee->IsJSFunction() && | 1125 if (!bindee.is_null() && bindee->IsJSFunction() && |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1334 if (!EnsureDebugInfo(shared, function)) { | 1264 if (!EnsureDebugInfo(shared, function)) { |
1335 // Return if ensuring debug info failed. | 1265 // Return if ensuring debug info failed. |
1336 return; | 1266 return; |
1337 } | 1267 } |
1338 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 1268 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
1339 | 1269 |
1340 // Compute whether or not the target is a call target. | 1270 // Compute whether or not the target is a call target. |
1341 bool is_load_or_store = false; | 1271 bool is_load_or_store = false; |
1342 bool is_inline_cache_stub = false; | 1272 bool is_inline_cache_stub = false; |
1343 bool is_at_restarted_function = false; | 1273 bool is_at_restarted_function = false; |
1344 bool is_exit = false; | |
1345 bool is_construct_call = false; | |
1346 Handle<Code> call_function_stub; | 1274 Handle<Code> call_function_stub; |
1347 | 1275 |
1348 { | 1276 // PC points to the instruction after the current one, possibly a break |
1349 // Find the break location where execution has stopped. | 1277 // location as well. So the "- 1" to exclude it from the search. |
1350 DisallowHeapAllocation no_gc; | 1278 Address call_pc = frame->pc() - 1; |
1351 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS); | 1279 BreakLocation location = |
| 1280 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); |
1352 | 1281 |
1353 // pc points to the instruction after the current one, possibly a break | 1282 if (thread_local_.restarter_frame_function_pointer_ == NULL) { |
1354 // location as well. So the "- 1" to exclude it from the search. | 1283 if (location.IsCodeTarget()) { |
1355 it.FindBreakLocationFromAddress(frame->pc() - 1); | 1284 Handle<Code> target_code = location.CodeTarget(); |
| 1285 is_inline_cache_stub = target_code->is_inline_cache_stub(); |
| 1286 is_load_or_store = is_inline_cache_stub && !target_code->is_call_stub(); |
1356 | 1287 |
1357 is_exit = it.IsExit(); | 1288 // Check if target code is CallFunction stub. |
1358 is_construct_call = RelocInfo::IsConstructCall(it.rmode()); | 1289 Handle<Code> maybe_call_function_stub = target_code; |
1359 | 1290 // If there is a breakpoint at this line look at the original code to |
1360 if (thread_local_.restarter_frame_function_pointer_ == NULL) { | 1291 // check if it is a CallFunction stub. |
1361 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) { | 1292 if (location.IsDebugBreak()) { |
1362 bool is_call_target = false; | 1293 maybe_call_function_stub = location.OriginalCodeTarget(); |
1363 Address target = it.rinfo()->target_address(); | |
1364 Code* code = Code::GetCodeFromTargetAddress(target); | |
1365 | |
1366 is_call_target = code->is_call_stub(); | |
1367 is_inline_cache_stub = code->is_inline_cache_stub(); | |
1368 is_load_or_store = is_inline_cache_stub && !is_call_target; | |
1369 | |
1370 // Check if target code is CallFunction stub. | |
1371 Code* maybe_call_function_stub = code; | |
1372 // If there is a breakpoint at this line look at the original code to | |
1373 // check if it is a CallFunction stub. | |
1374 if (it.IsDebugBreak()) { | |
1375 Address original_target = it.original_rinfo()->target_address(); | |
1376 maybe_call_function_stub = | |
1377 Code::GetCodeFromTargetAddress(original_target); | |
1378 } | |
1379 if ((maybe_call_function_stub->kind() == Code::STUB && | |
1380 CodeStub::GetMajorKey(maybe_call_function_stub) == | |
1381 CodeStub::CallFunction) || | |
1382 maybe_call_function_stub->is_call_stub()) { | |
1383 // Save reference to the code as we may need it to find out arguments | |
1384 // count for 'step in' later. | |
1385 call_function_stub = Handle<Code>(maybe_call_function_stub); | |
1386 } | |
1387 } | 1294 } |
1388 } else { | 1295 if ((maybe_call_function_stub->kind() == Code::STUB && |
1389 is_at_restarted_function = true; | 1296 CodeStub::GetMajorKey(*maybe_call_function_stub) == |
| 1297 CodeStub::CallFunction) || |
| 1298 maybe_call_function_stub->is_call_stub()) { |
| 1299 // Save reference to the code as we may need it to find out arguments |
| 1300 // count for 'step in' later. |
| 1301 call_function_stub = maybe_call_function_stub; |
| 1302 } |
1390 } | 1303 } |
| 1304 } else { |
| 1305 is_at_restarted_function = true; |
1391 } | 1306 } |
1392 | 1307 |
1393 // If this is the last break code target step out is the only possibility. | 1308 // If this is the last break code target step out is the only possibility. |
1394 if (is_exit || step_action == StepOut) { | 1309 if (location.IsExit() || step_action == StepOut) { |
1395 if (step_action == StepOut) { | 1310 if (step_action == StepOut) { |
1396 // Skip step_count frames starting with the current one. | 1311 // Skip step_count frames starting with the current one. |
1397 while (step_count-- > 0 && !frames_it.done()) { | 1312 while (step_count-- > 0 && !frames_it.done()) { |
1398 frames_it.Advance(); | 1313 frames_it.Advance(); |
1399 } | 1314 } |
1400 } else { | 1315 } else { |
1401 DCHECK(is_exit); | 1316 DCHECK(location.IsExit()); |
1402 frames_it.Advance(); | 1317 frames_it.Advance(); |
1403 } | 1318 } |
1404 // Skip builtin functions on the stack. | 1319 // Skip builtin functions on the stack. |
1405 while (!frames_it.done() && | 1320 while (!frames_it.done() && |
1406 frames_it.frame()->function()->IsFromNativeScript()) { | 1321 frames_it.frame()->function()->IsFromNativeScript()) { |
1407 frames_it.Advance(); | 1322 frames_it.Advance(); |
1408 } | 1323 } |
1409 // Step out: If there is a JavaScript caller frame, we need to | 1324 // Step out: If there is a JavaScript caller frame, we need to |
1410 // flood it with breakpoints. | 1325 // flood it with breakpoints. |
1411 if (!frames_it.done()) { | 1326 if (!frames_it.done()) { |
1412 // Fill the function to return to with one-shot break points. | 1327 // Fill the function to return to with one-shot break points. |
1413 JSFunction* function = frames_it.frame()->function(); | 1328 JSFunction* function = frames_it.frame()->function(); |
1414 FloodWithOneShot(Handle<JSFunction>(function)); | 1329 FloodWithOneShot(Handle<JSFunction>(function)); |
1415 // Set target frame pointer. | 1330 // Set target frame pointer. |
1416 ActivateStepOut(frames_it.frame()); | 1331 ActivateStepOut(frames_it.frame()); |
1417 } | 1332 } |
1418 } else if (!(is_inline_cache_stub || is_construct_call || | 1333 } else if (!(is_inline_cache_stub || location.IsConstructCall() || |
1419 !call_function_stub.is_null() || is_at_restarted_function) || | 1334 !call_function_stub.is_null() || is_at_restarted_function) || |
1420 step_action == StepNext || step_action == StepMin) { | 1335 step_action == StepNext || step_action == StepMin) { |
1421 // Step next or step min. | 1336 // Step next or step min. |
1422 | 1337 |
1423 // Fill the current function with one-shot break points. | 1338 // Fill the current function with one-shot break points. |
1424 // If we are stepping into another frame, only fill calls and returns. | 1339 // If we are stepping into another frame, only fill calls and returns. |
1425 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS | 1340 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS |
1426 : ALL_BREAK_LOCATIONS); | 1341 : ALL_BREAK_LOCATIONS); |
1427 | 1342 |
1428 // Remember source position and frame to handle step next. | 1343 // Remember source position and frame to handle step next. |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1504 } | 1419 } |
1505 | 1420 |
1506 // Step in or Step in min | 1421 // Step in or Step in min |
1507 // Step in through construct call requires no changes to the running code. | 1422 // Step in through construct call requires no changes to the running code. |
1508 // Step in through getters/setters should already be prepared as well | 1423 // Step in through getters/setters should already be prepared as well |
1509 // because caller of this function (Debug::PrepareStep) is expected to | 1424 // because caller of this function (Debug::PrepareStep) is expected to |
1510 // flood the top frame's function with one shot breakpoints. | 1425 // flood the top frame's function with one shot breakpoints. |
1511 // Step in through CallFunction stub should also be prepared by caller of | 1426 // Step in through CallFunction stub should also be prepared by caller of |
1512 // this function (Debug::PrepareStep) which should flood target function | 1427 // this function (Debug::PrepareStep) which should flood target function |
1513 // with breakpoints. | 1428 // with breakpoints. |
1514 DCHECK(is_construct_call || is_inline_cache_stub || | 1429 DCHECK(location.IsConstructCall() || is_inline_cache_stub || |
1515 !call_function_stub.is_null() || is_at_restarted_function); | 1430 !call_function_stub.is_null() || is_at_restarted_function); |
1516 ActivateStepIn(frame); | 1431 ActivateStepIn(frame); |
1517 } | 1432 } |
1518 } | 1433 } |
1519 | 1434 |
1520 | 1435 |
1521 // Check whether the current debug break should be reported to the debugger. It | 1436 // Check whether the current debug break should be reported to the debugger. It |
1522 // is used to have step next and step in only report break back to the debugger | 1437 // is used to have step next and step in only report break back to the debugger |
1523 // if on a different frame or in a different statement. In some situations | 1438 // if on a different frame or in a different statement. In some situations |
1524 // there will be several break points in the same statement when the code is | 1439 // there will be several break points in the same statement when the code is |
1525 // flooded with one-shot break points. This function helps to perform several | 1440 // flooded with one-shot break points. This function helps to perform several |
1526 // steps before reporting break back to the debugger. | 1441 // steps before reporting break back to the debugger. |
1527 bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator, | 1442 bool Debug::StepNextContinue(BreakLocation* break_location, |
1528 JavaScriptFrame* frame) { | 1443 JavaScriptFrame* frame) { |
1529 // StepNext and StepOut shouldn't bring us deeper in code, so last frame | 1444 // StepNext and StepOut shouldn't bring us deeper in code, so last frame |
1530 // shouldn't be a parent of current frame. | 1445 // shouldn't be a parent of current frame. |
1531 StepAction step_action = thread_local_.last_step_action_; | 1446 StepAction step_action = thread_local_.last_step_action_; |
1532 | 1447 |
1533 if (step_action == StepNext || step_action == StepOut) { | 1448 if (step_action == StepNext || step_action == StepOut) { |
1534 if (frame->fp() < thread_local_.last_fp_) return true; | 1449 if (frame->fp() < thread_local_.last_fp_) return true; |
1535 } | 1450 } |
1536 | 1451 |
1537 // We stepped into a new frame if the frame pointer changed. | 1452 // We stepped into a new frame if the frame pointer changed. |
1538 if (step_action == StepFrame) { | 1453 if (step_action == StepFrame) { |
1539 return frame->UnpaddedFP() == thread_local_.last_fp_; | 1454 return frame->UnpaddedFP() == thread_local_.last_fp_; |
1540 } | 1455 } |
1541 | 1456 |
1542 // If the step last action was step next or step in make sure that a new | 1457 // If the step last action was step next or step in make sure that a new |
1543 // statement is hit. | 1458 // statement is hit. |
1544 if (step_action == StepNext || step_action == StepIn) { | 1459 if (step_action == StepNext || step_action == StepIn) { |
1545 // Never continue if returning from function. | 1460 // Never continue if returning from function. |
1546 if (break_location_iterator->IsExit()) return false; | 1461 if (break_location->IsExit()) return false; |
1547 | 1462 |
1548 // Continue if we are still on the same frame and in the same statement. | 1463 // Continue if we are still on the same frame and in the same statement. |
1549 int current_statement_position = | 1464 int current_statement_position = |
1550 break_location_iterator->code()->SourceStatementPosition(frame->pc()); | 1465 break_location->code()->SourceStatementPosition(frame->pc()); |
1551 return thread_local_.last_fp_ == frame->UnpaddedFP() && | 1466 return thread_local_.last_fp_ == frame->UnpaddedFP() && |
1552 thread_local_.last_statement_position_ == current_statement_position; | 1467 thread_local_.last_statement_position_ == current_statement_position; |
1553 } | 1468 } |
1554 | 1469 |
1555 // No step next action - don't continue. | 1470 // No step next action - don't continue. |
1556 return false; | 1471 return false; |
1557 } | 1472 } |
1558 | 1473 |
1559 | 1474 |
1560 // Check whether the code object at the specified address is a debug break code | 1475 // Check whether the code object at the specified address is a debug break code |
1561 // object. | 1476 // object. |
1562 bool Debug::IsDebugBreak(Address addr) { | 1477 bool Debug::IsDebugBreak(Address addr) { |
1563 Code* code = Code::GetCodeFromTargetAddress(addr); | 1478 Code* code = Code::GetCodeFromTargetAddress(addr); |
1564 return code->is_debug_stub() && code->extra_ic_state() == DEBUG_BREAK; | 1479 return code->is_debug_stub() && code->extra_ic_state() == DEBUG_BREAK; |
1565 } | 1480 } |
1566 | 1481 |
1567 | 1482 |
1568 | |
1569 | |
1570 | |
1571 // Simple function for returning the source positions for active break points. | 1483 // Simple function for returning the source positions for active break points. |
1572 Handle<Object> Debug::GetSourceBreakLocations( | 1484 Handle<Object> Debug::GetSourceBreakLocations( |
1573 Handle<SharedFunctionInfo> shared, | 1485 Handle<SharedFunctionInfo> shared, |
1574 BreakPositionAlignment position_alignment) { | 1486 BreakPositionAlignment position_alignment) { |
1575 Isolate* isolate = shared->GetIsolate(); | 1487 Isolate* isolate = shared->GetIsolate(); |
1576 Heap* heap = isolate->heap(); | 1488 Heap* heap = isolate->heap(); |
1577 if (!HasDebugInfo(shared)) { | 1489 if (!HasDebugInfo(shared)) { |
1578 return Handle<Object>(heap->undefined_value(), isolate); | 1490 return Handle<Object>(heap->undefined_value(), isolate); |
1579 } | 1491 } |
1580 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 1492 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1648 } | 1560 } |
1649 | 1561 |
1650 | 1562 |
1651 // Clears all the one-shot break points that are currently set. Normally this | 1563 // Clears all the one-shot break points that are currently set. Normally this |
1652 // function is called each time a break point is hit as one shot break points | 1564 // function is called each time a break point is hit as one shot break points |
1653 // are used to support stepping. | 1565 // are used to support stepping. |
1654 void Debug::ClearOneShot() { | 1566 void Debug::ClearOneShot() { |
1655 // The current implementation just runs through all the breakpoints. When the | 1567 // The current implementation just runs through all the breakpoints. When the |
1656 // last break point for a function is removed that function is automatically | 1568 // last break point for a function is removed that function is automatically |
1657 // removed from the list. | 1569 // removed from the list. |
1658 | 1570 for (DebugInfoListNode* node = debug_info_list_; node != NULL; |
1659 DebugInfoListNode* node = debug_info_list_; | 1571 node = node->next()) { |
1660 while (node != NULL) { | 1572 for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS); |
1661 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); | 1573 !it.Done(); it.Next()) { |
1662 while (!it.Done()) { | 1574 it.GetBreakLocation().ClearOneShot(); |
1663 it.ClearOneShot(); | |
1664 it.Next(); | |
1665 } | 1575 } |
1666 node = node->next(); | |
1667 } | 1576 } |
1668 } | 1577 } |
1669 | 1578 |
1670 | 1579 |
1671 void Debug::ActivateStepIn(StackFrame* frame) { | 1580 void Debug::ActivateStepIn(StackFrame* frame) { |
1672 DCHECK(!StepOutActive()); | 1581 DCHECK(!StepOutActive()); |
1673 thread_local_.step_into_fp_ = frame->UnpaddedFP(); | 1582 thread_local_.step_into_fp_ = frame->UnpaddedFP(); |
1674 } | 1583 } |
1675 | 1584 |
1676 | 1585 |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2073 RedirectActivationsToRecompiledCodeOnThread(isolate_, | 1982 RedirectActivationsToRecompiledCodeOnThread(isolate_, |
2074 isolate_->thread_local_top()); | 1983 isolate_->thread_local_top()); |
2075 | 1984 |
2076 ActiveFunctionsRedirector active_functions_redirector; | 1985 ActiveFunctionsRedirector active_functions_redirector; |
2077 isolate_->thread_manager()->IterateArchivedThreads( | 1986 isolate_->thread_manager()->IterateArchivedThreads( |
2078 &active_functions_redirector); | 1987 &active_functions_redirector); |
2079 } | 1988 } |
2080 } | 1989 } |
2081 | 1990 |
2082 | 1991 |
2083 Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script, | 1992 Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script, |
2084 int position) { | 1993 int position) { |
2085 // Iterate the heap looking for SharedFunctionInfo generated from the | 1994 // Iterate the heap looking for SharedFunctionInfo generated from the |
2086 // script. The inner most SharedFunctionInfo containing the source position | 1995 // script. The inner most SharedFunctionInfo containing the source position |
2087 // for the requested break point is found. | 1996 // for the requested break point is found. |
2088 // NOTE: This might require several heap iterations. If the SharedFunctionInfo | 1997 // NOTE: This might require several heap iterations. If the SharedFunctionInfo |
2089 // which is found is not compiled it is compiled and the heap is iterated | 1998 // which is found is not compiled it is compiled and the heap is iterated |
2090 // again as the compilation might create inner functions from the newly | 1999 // again as the compilation might create inner functions from the newly |
2091 // compiled function and the actual requested break point might be in one of | 2000 // compiled function and the actual requested break point might be in one of |
2092 // these functions. | 2001 // these functions. |
2093 // NOTE: The below fix-point iteration depends on all functions that cannot be | 2002 // NOTE: The below fix-point iteration depends on all functions that cannot be |
2094 // compiled lazily without a context to not be compiled at all. Compilation | 2003 // compiled lazily without a context to not be compiled at all. Compilation |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2157 target_start_position = start_position; | 2066 target_start_position = start_position; |
2158 target_function = function; | 2067 target_function = function; |
2159 target = shared; | 2068 target = shared; |
2160 } | 2069 } |
2161 } | 2070 } |
2162 } | 2071 } |
2163 } | 2072 } |
2164 } // End for loop. | 2073 } // End for loop. |
2165 } // End no-allocation scope. | 2074 } // End no-allocation scope. |
2166 | 2075 |
2167 if (target.is_null()) return heap->undefined_value(); | 2076 if (target.is_null()) return isolate_->factory()->undefined_value(); |
2168 | 2077 |
2169 // There will be at least one break point when we are done. | 2078 // There will be at least one break point when we are done. |
2170 has_break_points_ = true; | 2079 has_break_points_ = true; |
2171 | 2080 |
2172 // If the candidate found is compiled we are done. | 2081 // If the candidate found is compiled we are done. |
2173 done = target->is_compiled(); | 2082 done = target->is_compiled(); |
2174 if (!done) { | 2083 if (!done) { |
2175 // If the candidate is not compiled, compile it to reveal any inner | 2084 // If the candidate is not compiled, compile it to reveal any inner |
2176 // functions which might contain the requested source position. This | 2085 // functions which might contain the requested source position. This |
2177 // will compile all inner functions that cannot be compiled without a | 2086 // will compile all inner functions that cannot be compiled without a |
2178 // context, because Compiler::BuildFunctionInfo checks whether the | 2087 // context, because Compiler::BuildFunctionInfo checks whether the |
2179 // debugger is active. | 2088 // debugger is active. |
2180 MaybeHandle<Code> maybe_result = target_function.is_null() | 2089 MaybeHandle<Code> maybe_result = target_function.is_null() |
2181 ? Compiler::GetUnoptimizedCode(target) | 2090 ? Compiler::GetUnoptimizedCode(target) |
2182 : Compiler::GetUnoptimizedCode(target_function); | 2091 : Compiler::GetUnoptimizedCode(target_function); |
2183 if (maybe_result.is_null()) return isolate_->heap()->undefined_value(); | 2092 if (maybe_result.is_null()) return isolate_->factory()->undefined_value(); |
2184 } | 2093 } |
2185 } // End while loop. | 2094 } // End while loop. |
2186 | 2095 |
2187 return *target; | 2096 return target; |
2188 } | 2097 } |
2189 | 2098 |
2190 | 2099 |
2191 // Ensures the debug information is present for shared. | 2100 // Ensures the debug information is present for shared. |
2192 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared, | 2101 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared, |
2193 Handle<JSFunction> function) { | 2102 Handle<JSFunction> function) { |
2194 Isolate* isolate = shared->GetIsolate(); | 2103 Isolate* isolate = shared->GetIsolate(); |
2195 | 2104 |
2196 // Return if we already have the debug info for shared. | 2105 // Return if we already have the debug info for shared. |
2197 if (HasDebugInfo(shared)) { | 2106 if (HasDebugInfo(shared)) { |
(...skipping 1274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3472 logger_->DebugEvent("Put", message.text()); | 3381 logger_->DebugEvent("Put", message.text()); |
3473 } | 3382 } |
3474 | 3383 |
3475 | 3384 |
3476 void LockingCommandMessageQueue::Clear() { | 3385 void LockingCommandMessageQueue::Clear() { |
3477 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 3386 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
3478 queue_.Clear(); | 3387 queue_.Clear(); |
3479 } | 3388 } |
3480 | 3389 |
3481 } } // namespace v8::internal | 3390 } } // namespace v8::internal |
OLD | NEW |