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/debug/debug.h" | 5 #include "src/debug/debug.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 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 | 138 |
139 break; | 139 break; |
140 } | 140 } |
141 break_index_++; | 141 break_index_++; |
142 } | 142 } |
143 | 143 |
144 | 144 |
145 // Find the break point at the supplied address, or the closest one before | 145 // Find the break point at the supplied address, or the closest one before |
146 // the address. | 146 // the address. |
147 BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info, | 147 BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info, |
148 BreakLocatorType type, Address pc) { | 148 Address pc) { |
149 Iterator it(debug_info, type); | 149 Iterator it(debug_info, ALL_BREAK_LOCATIONS); |
150 it.SkipTo(BreakIndexFromAddress(debug_info, type, pc)); | 150 it.SkipTo(BreakIndexFromAddress(debug_info, pc)); |
151 return it.GetBreakLocation(); | 151 return it.GetBreakLocation(); |
152 } | 152 } |
153 | 153 |
154 | 154 |
155 // Find the break point at the supplied address, or the closest one before | 155 // Find the break point at the supplied address, or the closest one before |
156 // the address. | 156 // the address. |
157 void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info, | 157 void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info, |
158 BreakLocatorType type, Address pc, | 158 Address pc, |
159 List<BreakLocation>* result_out) { | 159 List<BreakLocation>* result_out) { |
160 int break_index = BreakIndexFromAddress(debug_info, type, pc); | 160 int break_index = BreakIndexFromAddress(debug_info, pc); |
161 Iterator it(debug_info, type); | 161 Iterator it(debug_info, ALL_BREAK_LOCATIONS); |
162 it.SkipTo(break_index); | 162 it.SkipTo(break_index); |
163 int statement_position = it.statement_position(); | 163 int statement_position = it.statement_position(); |
164 while (!it.Done() && it.statement_position() == statement_position) { | 164 while (!it.Done() && it.statement_position() == statement_position) { |
165 result_out->Add(it.GetBreakLocation()); | 165 result_out->Add(it.GetBreakLocation()); |
166 it.Next(); | 166 it.Next(); |
167 } | 167 } |
168 } | 168 } |
169 | 169 |
170 | 170 |
171 int BreakLocation::BreakIndexFromAddress(Handle<DebugInfo> debug_info, | 171 int BreakLocation::BreakIndexFromAddress(Handle<DebugInfo> debug_info, |
172 BreakLocatorType type, Address pc) { | 172 Address pc) { |
173 // Run through all break points to locate the one closest to the address. | 173 // Run through all break points to locate the one closest to the address. |
174 int closest_break = 0; | 174 int closest_break = 0; |
175 int distance = kMaxInt; | 175 int distance = kMaxInt; |
176 for (Iterator it(debug_info, type); !it.Done(); it.Next()) { | 176 for (Iterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); it.Next()) { |
177 // Check if this break point is closer that what was previously found. | 177 // Check if this break point is closer that what was previously found. |
178 if (it.pc() <= pc && pc - it.pc() < distance) { | 178 if (it.pc() <= pc && pc - it.pc() < distance) { |
179 closest_break = it.break_index(); | 179 closest_break = it.break_index(); |
180 distance = static_cast<int>(pc - it.pc()); | 180 distance = static_cast<int>(pc - it.pc()); |
181 // Check whether we can't get any closer. | 181 // Check whether we can't get any closer. |
182 if (distance == 0) break; | 182 if (distance == 0) break; |
183 } | 183 } |
184 } | 184 } |
185 return closest_break; | 185 return closest_break; |
186 } | 186 } |
187 | 187 |
188 | 188 |
189 BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info, | 189 BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info, |
190 BreakLocatorType type, int position, | 190 int position, |
191 BreakPositionAlignment alignment) { | 191 BreakPositionAlignment alignment) { |
192 // Run through all break points to locate the one closest to the source | 192 // Run through all break points to locate the one closest to the source |
193 // position. | 193 // position. |
194 int closest_break = 0; | 194 int closest_break = 0; |
195 int distance = kMaxInt; | 195 int distance = kMaxInt; |
196 | 196 |
197 for (Iterator it(debug_info, type); !it.Done(); it.Next()) { | 197 for (Iterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); it.Next()) { |
198 int next_position; | 198 int next_position; |
199 if (alignment == STATEMENT_ALIGNED) { | 199 if (alignment == STATEMENT_ALIGNED) { |
200 next_position = it.statement_position(); | 200 next_position = it.statement_position(); |
201 } else { | 201 } else { |
202 DCHECK(alignment == BREAK_POSITION_ALIGNED); | 202 DCHECK(alignment == BREAK_POSITION_ALIGNED); |
203 next_position = it.position(); | 203 next_position = it.position(); |
204 } | 204 } |
205 if (position <= next_position && next_position - position < distance) { | 205 if (position <= next_position && next_position - position < distance) { |
206 closest_break = it.break_index(); | 206 closest_break = it.break_index(); |
207 distance = next_position - position; | 207 distance = next_position - position; |
208 // Check whether we can't get any closer. | 208 // Check whether we can't get any closer. |
209 if (distance == 0) break; | 209 if (distance == 0) break; |
210 } | 210 } |
211 } | 211 } |
212 | 212 |
213 Iterator it(debug_info, type); | 213 Iterator it(debug_info, ALL_BREAK_LOCATIONS); |
214 it.SkipTo(closest_break); | 214 it.SkipTo(closest_break); |
215 return it.GetBreakLocation(); | 215 return it.GetBreakLocation(); |
216 } | 216 } |
217 | 217 |
218 | 218 |
219 void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) { | 219 void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) { |
220 // If there is not already a real break point here patch code with debug | 220 // If there is not already a real break point here patch code with debug |
221 // break. | 221 // break. |
222 if (!HasBreakPoint()) SetDebugBreak(); | 222 if (!HasBreakPoint()) SetDebugBreak(); |
223 DCHECK(IsDebugBreak() || IsDebuggerStatement()); | 223 DCHECK(IsDebugBreak() || IsDebuggerStatement()); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 } | 320 } |
321 | 321 |
322 | 322 |
323 // Threading support. | 323 // Threading support. |
324 void Debug::ThreadInit() { | 324 void Debug::ThreadInit() { |
325 thread_local_.break_count_ = 0; | 325 thread_local_.break_count_ = 0; |
326 thread_local_.break_id_ = 0; | 326 thread_local_.break_id_ = 0; |
327 thread_local_.break_frame_id_ = StackFrame::NO_ID; | 327 thread_local_.break_frame_id_ = StackFrame::NO_ID; |
328 thread_local_.last_step_action_ = StepNone; | 328 thread_local_.last_step_action_ = StepNone; |
329 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; | 329 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; |
330 thread_local_.step_count_ = 0; | |
331 thread_local_.last_fp_ = 0; | 330 thread_local_.last_fp_ = 0; |
332 thread_local_.step_out_fp_ = 0; | 331 thread_local_.target_fp_ = 0; |
333 thread_local_.step_in_enabled_ = false; | 332 thread_local_.step_in_enabled_ = false; |
334 // TODO(isolates): frames_are_dropped_? | 333 // TODO(isolates): frames_are_dropped_? |
335 base::NoBarrier_Store(&thread_local_.current_debug_scope_, | 334 base::NoBarrier_Store(&thread_local_.current_debug_scope_, |
336 static_cast<base::AtomicWord>(0)); | 335 static_cast<base::AtomicWord>(0)); |
337 } | 336 } |
338 | 337 |
339 | 338 |
340 char* Debug::ArchiveDebug(char* storage) { | 339 char* Debug::ArchiveDebug(char* storage) { |
341 char* to = storage; | 340 char* to = storage; |
342 MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); | 341 MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 // Return debugger is not loaded. | 411 // Return debugger is not loaded. |
413 if (!is_loaded()) return; | 412 if (!is_loaded()) return; |
414 | 413 |
415 // Clear debugger context global handle. | 414 // Clear debugger context global handle. |
416 GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location()); | 415 GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location()); |
417 debug_context_ = Handle<Context>(); | 416 debug_context_ = Handle<Context>(); |
418 } | 417 } |
419 | 418 |
420 | 419 |
421 void Debug::Break(Arguments args, JavaScriptFrame* frame) { | 420 void Debug::Break(Arguments args, JavaScriptFrame* frame) { |
422 Heap* heap = isolate_->heap(); | |
423 HandleScope scope(isolate_); | 421 HandleScope scope(isolate_); |
424 DCHECK(args.length() == 0); | 422 DCHECK(args.length() == 0); |
425 | 423 |
426 // Initialize LiveEdit. | 424 // Initialize LiveEdit. |
427 LiveEdit::InitializeThreadLocal(this); | 425 LiveEdit::InitializeThreadLocal(this); |
428 | 426 |
429 // Just continue if breaks are disabled or debugger cannot be loaded. | 427 // Just continue if breaks are disabled or debugger cannot be loaded. |
430 if (break_disabled()) return; | 428 if (break_disabled()) return; |
431 | 429 |
432 // Enter the debugger. | 430 // Enter the debugger. |
433 DebugScope debug_scope(this); | 431 DebugScope debug_scope(this); |
434 if (debug_scope.failed()) return; | 432 if (debug_scope.failed()) return; |
435 | 433 |
436 // Postpone interrupt during breakpoint processing. | 434 // Postpone interrupt during breakpoint processing. |
437 PostponeInterruptsScope postpone(isolate_); | 435 PostponeInterruptsScope postpone(isolate_); |
438 | 436 |
439 // Get the debug info (create it if it does not exist). | 437 // Get the debug info (create it if it does not exist). |
440 Handle<JSFunction> function(frame->function()); | 438 Handle<JSFunction> function(frame->function()); |
441 Handle<SharedFunctionInfo> shared(function->shared()); | 439 Handle<SharedFunctionInfo> shared(function->shared()); |
442 if (!EnsureDebugInfo(shared, function)) { | 440 if (!EnsureDebugInfo(shared, function)) { |
443 // Return if we failed to retrieve the debug info. | 441 // Return if we failed to retrieve the debug info. |
444 return; | 442 return; |
445 } | 443 } |
446 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 444 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
447 | 445 |
448 // Find the break point where execution has stopped. | 446 // Find the break location where execution has stopped. |
449 // PC points to the instruction after the current one, possibly a break | 447 // PC points to the instruction after the current one, possibly a break |
450 // location as well. So the "- 1" to exclude it from the search. | 448 // location as well. So the "- 1" to exclude it from the search. |
451 Address call_pc = frame->pc() - 1; | 449 Address call_pc = frame->pc() - 1; |
452 BreakLocation break_location = | 450 BreakLocation location = BreakLocation::FromAddress(debug_info, call_pc); |
453 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); | |
454 | 451 |
455 // Check whether step next reached a new statement. | 452 // Find actual break points, if any, and trigger debug break event. |
456 if (!StepNextContinue(&break_location, frame)) { | 453 if (break_points_active_ && location.HasBreakPoint()) { |
457 // Decrease steps left if performing multiple steps. | 454 Handle<Object> break_point_objects = location.BreakPointObjects(); |
458 if (thread_local_.step_count_ > 0) { | 455 Handle<Object> break_points_hit = CheckBreakPoints(break_point_objects); |
459 thread_local_.step_count_--; | 456 if (!break_points_hit->IsUndefined()) { |
| 457 // Clear all current stepping setup. |
| 458 ClearStepping(); |
| 459 // Notify the debug event listeners. |
| 460 OnDebugBreak(break_points_hit, false); |
| 461 return; |
460 } | 462 } |
461 } | 463 } |
462 | 464 |
463 // If there is one or more real break points check whether any of these are | 465 // No break point. Check for stepping. |
464 // triggered. | 466 StepAction step_action = last_step_action(); |
465 Handle<Object> break_points_hit(heap->undefined_value(), isolate_); | 467 Address current_fp = frame->UnpaddedFP(); |
466 if (break_points_active_ && break_location.HasBreakPoint()) { | 468 Address target_fp = thread_local_.target_fp_; |
467 Handle<Object> break_point_objects = break_location.BreakPointObjects(); | 469 Address last_fp = thread_local_.last_fp_; |
468 break_points_hit = CheckBreakPoints(break_point_objects); | 470 |
| 471 bool step_break = true; |
| 472 switch (step_action) { |
| 473 case StepNone: |
| 474 return; |
| 475 case StepOut: |
| 476 // Step out has not reached the target frame yet. |
| 477 if (current_fp < target_fp) return; |
| 478 break; |
| 479 case StepNext: |
| 480 // Step next should not break in a deeper frame. |
| 481 if (current_fp < target_fp) return; |
| 482 // Fall through. |
| 483 case StepIn: |
| 484 step_break = location.IsReturn() || (current_fp != last_fp) || |
| 485 (thread_local_.last_statement_position_ != |
| 486 location.code()->SourceStatementPosition(frame->pc())); |
| 487 break; |
| 488 case StepFrame: |
| 489 step_break = current_fp != last_fp; |
| 490 break; |
469 } | 491 } |
470 | 492 |
471 // If step out is active skip everything until the frame where we need to step | 493 // Clear all current stepping setup. |
472 // out to is reached, unless real breakpoint is hit. | 494 ClearStepping(); |
473 if (StepOutActive() && | |
474 frame->fp() != thread_local_.step_out_fp_ && | |
475 break_points_hit->IsUndefined() ) { | |
476 // Step count should always be 0 for StepOut. | |
477 DCHECK(thread_local_.step_count_ == 0); | |
478 } else if (!break_points_hit->IsUndefined() || | |
479 (thread_local_.last_step_action_ != StepNone && | |
480 thread_local_.step_count_ == 0)) { | |
481 // Notify debugger if a real break point is triggered or if performing | |
482 // single stepping with no more steps to perform. Otherwise do another step. | |
483 | 495 |
484 // Clear all current stepping setup. | 496 if (step_break) { |
485 ClearStepping(); | |
486 // Notify the debug event listeners. | 497 // Notify the debug event listeners. |
487 OnDebugBreak(break_points_hit, false); | 498 OnDebugBreak(isolate_->factory()->undefined_value(), false); |
488 } else if (thread_local_.last_step_action_ != StepNone) { | 499 } else { |
489 // Hold on to last step action as it is cleared by the call to | 500 // Re-prepare to continue. |
490 // ClearStepping. | 501 PrepareStep(step_action); |
491 StepAction step_action = thread_local_.last_step_action_; | |
492 int step_count = thread_local_.step_count_; | |
493 | |
494 // If StepNext goes deeper into code, just return. The functions we need | |
495 // to have flooded with one-shots are already flooded. | |
496 if (step_action == StepNext && frame->fp() < thread_local_.last_fp_) return; | |
497 | |
498 // Clear all current stepping setup. | |
499 ClearStepping(); | |
500 | |
501 // Set up for the remaining steps. | |
502 PrepareStep(step_action, step_count); | |
503 } | 502 } |
504 } | 503 } |
505 | 504 |
506 | 505 |
507 // Check the break point objects for whether one or more are actually | 506 // Check the break point objects for whether one or more are actually |
508 // triggered. This function returns a JSArray with the break point objects | 507 // triggered. This function returns a JSArray with the break point objects |
509 // which is triggered. | 508 // which is triggered. |
510 Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) { | 509 Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) { |
511 Factory* factory = isolate_->factory(); | 510 Factory* factory = isolate_->factory(); |
512 | 511 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
589 // Return if retrieving debug info failed. | 588 // Return if retrieving debug info failed. |
590 return true; | 589 return true; |
591 } | 590 } |
592 | 591 |
593 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 592 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
594 // Source positions starts with zero. | 593 // Source positions starts with zero. |
595 DCHECK(*source_position >= 0); | 594 DCHECK(*source_position >= 0); |
596 | 595 |
597 // Find the break point and change it. | 596 // Find the break point and change it. |
598 BreakLocation location = BreakLocation::FromPosition( | 597 BreakLocation location = BreakLocation::FromPosition( |
599 debug_info, ALL_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED); | 598 debug_info, *source_position, STATEMENT_ALIGNED); |
600 *source_position = location.statement_position(); | 599 *source_position = location.statement_position(); |
601 location.SetBreakPoint(break_point_object); | 600 location.SetBreakPoint(break_point_object); |
602 | 601 |
603 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); | 602 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); |
604 | 603 |
605 // At least one active break point now. | 604 // At least one active break point now. |
606 return debug_info->GetBreakPointCount() > 0; | 605 return debug_info->GetBreakPointCount() > 0; |
607 } | 606 } |
608 | 607 |
609 | 608 |
(...skipping 22 matching lines...) Expand all Loading... |
632 position = 0; | 631 position = 0; |
633 } else { | 632 } else { |
634 position = *source_position - shared->start_position(); | 633 position = *source_position - shared->start_position(); |
635 } | 634 } |
636 | 635 |
637 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 636 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
638 // Source positions starts with zero. | 637 // Source positions starts with zero. |
639 DCHECK(position >= 0); | 638 DCHECK(position >= 0); |
640 | 639 |
641 // Find the break point and change it. | 640 // Find the break point and change it. |
642 BreakLocation location = BreakLocation::FromPosition( | 641 BreakLocation location = |
643 debug_info, ALL_BREAK_LOCATIONS, position, alignment); | 642 BreakLocation::FromPosition(debug_info, position, alignment); |
644 location.SetBreakPoint(break_point_object); | 643 location.SetBreakPoint(break_point_object); |
645 | 644 |
646 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); | 645 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); |
647 | 646 |
648 position = (alignment == STATEMENT_ALIGNED) ? location.statement_position() | 647 position = (alignment == STATEMENT_ALIGNED) ? location.statement_position() |
649 : location.position(); | 648 : location.position(); |
650 | 649 |
651 *source_position = position + shared->start_position(); | 650 *source_position = position + shared->start_position(); |
652 | 651 |
653 // At least one active break point now. | 652 // At least one active break point now. |
(...skipping 12 matching lines...) Expand all Loading... |
666 if (!result->IsUndefined()) { | 665 if (!result->IsUndefined()) { |
667 // Get information in the break point. | 666 // Get information in the break point. |
668 Handle<BreakPointInfo> break_point_info = | 667 Handle<BreakPointInfo> break_point_info = |
669 Handle<BreakPointInfo>::cast(result); | 668 Handle<BreakPointInfo>::cast(result); |
670 Handle<DebugInfo> debug_info = node->debug_info(); | 669 Handle<DebugInfo> debug_info = node->debug_info(); |
671 | 670 |
672 // Find the break point and clear it. | 671 // Find the break point and clear it. |
673 Address pc = | 672 Address pc = |
674 debug_info->code()->entry() + break_point_info->code_position(); | 673 debug_info->code()->entry() + break_point_info->code_position(); |
675 | 674 |
676 BreakLocation location = | 675 BreakLocation location = BreakLocation::FromAddress(debug_info, pc); |
677 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, pc); | |
678 location.ClearBreakPoint(break_point_object); | 676 location.ClearBreakPoint(break_point_object); |
679 | 677 |
680 // If there are no more break points left remove the debug info for this | 678 // If there are no more break points left remove the debug info for this |
681 // function. | 679 // function. |
682 if (debug_info->GetBreakPointCount() == 0) { | 680 if (debug_info->GetBreakPointCount() == 0) { |
683 RemoveDebugInfoAndClearFromShared(debug_info); | 681 RemoveDebugInfoAndClearFromShared(debug_info); |
684 } | 682 } |
685 | 683 |
686 return; | 684 return; |
687 } | 685 } |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
755 | 753 |
756 FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) { | 754 FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) { |
757 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); | 755 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); |
758 frame->Summarize(&frames); | 756 frame->Summarize(&frames); |
759 return frames.first(); | 757 return frames.first(); |
760 } | 758 } |
761 | 759 |
762 | 760 |
763 void Debug::PrepareStepIn(Handle<JSFunction> function) { | 761 void Debug::PrepareStepIn(Handle<JSFunction> function) { |
764 if (!is_active()) return; | 762 if (!is_active()) return; |
765 if (!IsStepping()) return; | |
766 if (last_step_action() < StepIn) return; | 763 if (last_step_action() < StepIn) return; |
767 if (in_debug_scope()) return; | 764 if (in_debug_scope()) return; |
768 if (thread_local_.step_in_enabled_) { | 765 if (thread_local_.step_in_enabled_) { |
769 ClearStepOut(); | |
770 FloodWithOneShot(function); | 766 FloodWithOneShot(function); |
771 } | 767 } |
772 } | 768 } |
773 | 769 |
774 | 770 |
775 void Debug::PrepareStepOnThrow() { | 771 void Debug::PrepareStepOnThrow() { |
776 if (!is_active()) return; | 772 if (!is_active()) return; |
777 if (!IsStepping()) return; | |
778 if (last_step_action() == StepNone) return; | 773 if (last_step_action() == StepNone) return; |
779 if (in_debug_scope()) return; | 774 if (in_debug_scope()) return; |
780 | 775 |
781 ClearOneShot(); | 776 ClearOneShot(); |
782 | 777 |
783 // Iterate through the JavaScript stack looking for handlers. | 778 // Iterate through the JavaScript stack looking for handlers. |
784 JavaScriptFrameIterator it(isolate_); | 779 JavaScriptFrameIterator it(isolate_); |
785 while (!it.done()) { | 780 while (!it.done()) { |
786 JavaScriptFrame* frame = it.frame(); | 781 JavaScriptFrame* frame = it.frame(); |
787 int stack_slots = 0; // The computed stack slot count is not used. | 782 int stack_slots = 0; // The computed stack slot count is not used. |
788 if (frame->LookupExceptionHandlerInTable(&stack_slots, NULL) > 0) break; | 783 if (frame->LookupExceptionHandlerInTable(&stack_slots, NULL) > 0) break; |
789 it.Advance(); | 784 it.Advance(); |
790 } | 785 } |
791 | 786 |
792 // Find the closest Javascript frame we can flood with one-shots. | 787 // Find the closest Javascript frame we can flood with one-shots. |
793 while (!it.done() && | 788 while (!it.done() && |
794 !it.frame()->function()->shared()->IsSubjectToDebugging()) { | 789 !it.frame()->function()->shared()->IsSubjectToDebugging()) { |
795 it.Advance(); | 790 it.Advance(); |
796 } | 791 } |
797 | 792 |
798 if (it.done()) return; // No suitable Javascript catch handler. | 793 if (it.done()) return; // No suitable Javascript catch handler. |
799 | 794 |
800 FloodWithOneShot(Handle<JSFunction>(it.frame()->function())); | 795 FloodWithOneShot(Handle<JSFunction>(it.frame()->function())); |
801 } | 796 } |
802 | 797 |
803 | 798 |
804 void Debug::PrepareStep(StepAction step_action, int step_count) { | 799 void Debug::PrepareStep(StepAction step_action) { |
805 HandleScope scope(isolate_); | 800 HandleScope scope(isolate_); |
806 | 801 |
807 DCHECK(in_debug_scope()); | 802 DCHECK(in_debug_scope()); |
808 | 803 |
809 // Get the frame where the execution has stopped and skip the debug frame if | 804 // Get the frame where the execution has stopped and skip the debug frame if |
810 // any. The debug frame will only be present if execution was stopped due to | 805 // any. The debug frame will only be present if execution was stopped due to |
811 // hitting a break point. In other situations (e.g. unhandled exception) the | 806 // hitting a break point. In other situations (e.g. unhandled exception) the |
812 // debug frame is not present. | 807 // debug frame is not present. |
813 StackFrame::Id frame_id = break_frame_id(); | 808 StackFrame::Id frame_id = break_frame_id(); |
814 // If there is no JavaScript stack don't do anything. | 809 // If there is no JavaScript stack don't do anything. |
815 if (frame_id == StackFrame::NO_ID) return; | 810 if (frame_id == StackFrame::NO_ID) return; |
816 | 811 |
817 JavaScriptFrameIterator frames_it(isolate_, frame_id); | 812 JavaScriptFrameIterator frames_it(isolate_, frame_id); |
818 JavaScriptFrame* frame = frames_it.frame(); | 813 JavaScriptFrame* frame = frames_it.frame(); |
819 | 814 |
820 feature_tracker()->Track(DebugFeatureTracker::kStepping); | 815 feature_tracker()->Track(DebugFeatureTracker::kStepping); |
821 | 816 |
822 // Remember this step action and count. | 817 // Remember this step action and count. |
823 thread_local_.last_step_action_ = step_action; | 818 thread_local_.last_step_action_ = step_action; |
824 STATIC_ASSERT(StepFrame > StepIn); | 819 STATIC_ASSERT(StepFrame > StepIn); |
825 thread_local_.step_in_enabled_ = (step_action >= StepIn); | 820 thread_local_.step_in_enabled_ = (step_action >= StepIn); |
826 if (step_action == StepOut) { | |
827 // For step out target frame will be found on the stack so there is no need | |
828 // to set step counter for it. It's expected to always be 0 for StepOut. | |
829 thread_local_.step_count_ = 0; | |
830 } else { | |
831 thread_local_.step_count_ = step_count; | |
832 } | |
833 | 821 |
834 // If the function on the top frame is unresolved perform step out. This will | 822 // If the function on the top frame is unresolved perform step out. This will |
835 // be the case when calling unknown function and having the debugger stopped | 823 // be the case when calling unknown function and having the debugger stopped |
836 // in an unhandled exception. | 824 // in an unhandled exception. |
837 if (!frame->function()->IsJSFunction()) { | 825 if (!frame->function()->IsJSFunction()) { |
838 // Step out: Find the calling JavaScript frame and flood it with | 826 // Step out: Find the calling JavaScript frame and flood it with |
839 // breakpoints. | 827 // breakpoints. |
840 frames_it.Advance(); | 828 frames_it.Advance(); |
841 // Fill the function to return to with one-shot break points. | 829 // Fill the function to return to with one-shot break points. |
842 JSFunction* function = frames_it.frame()->function(); | 830 JSFunction* function = frames_it.frame()->function(); |
(...skipping 10 matching lines...) Expand all Loading... |
853 return; | 841 return; |
854 } | 842 } |
855 | 843 |
856 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 844 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
857 // Refresh frame summary if the code has been recompiled for debugging. | 845 // Refresh frame summary if the code has been recompiled for debugging. |
858 if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame); | 846 if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame); |
859 | 847 |
860 // PC points to the instruction after the current one, possibly a break | 848 // PC points to the instruction after the current one, possibly a break |
861 // location as well. So the "- 1" to exclude it from the search. | 849 // location as well. So the "- 1" to exclude it from the search. |
862 Address call_pc = summary.pc() - 1; | 850 Address call_pc = summary.pc() - 1; |
863 BreakLocation location = | 851 BreakLocation location = BreakLocation::FromAddress(debug_info, call_pc); |
864 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); | |
865 | 852 |
866 // If this is the last break code target step out is the only possibility. | 853 // At a return statement we will step out either way. |
867 if (location.IsReturn() || step_action == StepOut) { | 854 if (location.IsReturn()) step_action = StepOut; |
868 if (step_action == StepOut) { | |
869 // Skip step_count frames starting with the current one. | |
870 while (step_count-- > 0 && !frames_it.done()) { | |
871 frames_it.Advance(); | |
872 } | |
873 } else { | |
874 DCHECK(location.IsReturn()); | |
875 frames_it.Advance(); | |
876 } | |
877 // Skip native and extension functions on the stack. | |
878 while (!frames_it.done() && | |
879 !frames_it.frame()->function()->shared()->IsSubjectToDebugging()) { | |
880 if (step_action >= StepIn) { | |
881 // Builtin functions are not subject to stepping, but need to be | |
882 // deoptimized, because optimized code does not check for debug | |
883 // step in at call sites. | |
884 Deoptimizer::DeoptimizeFunction(frames_it.frame()->function()); | |
885 } | |
886 frames_it.Advance(); | |
887 } | |
888 // Step out: If there is a JavaScript caller frame, we need to | |
889 // flood it with breakpoints. | |
890 if (!frames_it.done()) { | |
891 // Fill the function to return to with one-shot break points. | |
892 JSFunction* function = frames_it.frame()->function(); | |
893 FloodWithOneShot(Handle<JSFunction>(function)); | |
894 // Set target frame pointer. | |
895 ActivateStepOut(frames_it.frame()); | |
896 } else { | |
897 // Stepping out to the embedder. Disable step-in to avoid stepping into | |
898 // the next (unrelated) call that the embedder makes. | |
899 thread_local_.step_in_enabled_ = false; | |
900 } | |
901 return; | |
902 } | |
903 | 855 |
904 // Fill the current function with one-shot break points even for step in on | |
905 // a call target as the function called might be a native function for | |
906 // which step in will not stop. It also prepares for stepping in | |
907 // getters/setters. | |
908 // If we are stepping into another frame, only fill calls and returns. | |
909 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS | |
910 : ALL_BREAK_LOCATIONS); | |
911 | |
912 // Remember source position and frame to handle step next. | |
913 thread_local_.last_statement_position_ = | 856 thread_local_.last_statement_position_ = |
914 debug_info->code()->SourceStatementPosition(summary.pc()); | 857 debug_info->code()->SourceStatementPosition(summary.pc()); |
915 thread_local_.last_fp_ = frame->UnpaddedFP(); | 858 thread_local_.last_fp_ = frame->UnpaddedFP(); |
| 859 |
| 860 switch (step_action) { |
| 861 case StepNone: |
| 862 UNREACHABLE(); |
| 863 break; |
| 864 case StepOut: |
| 865 // Advance to caller frame. |
| 866 frames_it.Advance(); |
| 867 // Skip native and extension functions on the stack. |
| 868 while (!frames_it.done() && |
| 869 !frames_it.frame()->function()->shared()->IsSubjectToDebugging()) { |
| 870 // Builtin functions are not subject to stepping, but need to be |
| 871 // deoptimized to include checks for step-in at call sites. |
| 872 Deoptimizer::DeoptimizeFunction(frames_it.frame()->function()); |
| 873 frames_it.Advance(); |
| 874 } |
| 875 if (frames_it.done()) { |
| 876 // Stepping out to the embedder. Disable step-in to avoid stepping into |
| 877 // the next (unrelated) call that the embedder makes. |
| 878 thread_local_.step_in_enabled_ = false; |
| 879 } else { |
| 880 // Fill the caller function to return to with one-shot break points. |
| 881 Handle<JSFunction> caller_function(frames_it.frame()->function()); |
| 882 FloodWithOneShot(caller_function); |
| 883 thread_local_.target_fp_ = frames_it.frame()->UnpaddedFP(); |
| 884 } |
| 885 // Clear last position info. For stepping out it does not matter. |
| 886 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; |
| 887 thread_local_.last_fp_ = 0; |
| 888 break; |
| 889 case StepNext: |
| 890 thread_local_.target_fp_ = frame->UnpaddedFP(); |
| 891 FloodWithOneShot(function); |
| 892 break; |
| 893 case StepIn: |
| 894 FloodWithOneShot(function); |
| 895 break; |
| 896 case StepFrame: |
| 897 // No point in setting one-shot breaks at places where we are not about |
| 898 // to leave the current frame. |
| 899 FloodWithOneShot(function, CALLS_AND_RETURNS); |
| 900 break; |
| 901 } |
916 } | 902 } |
917 | 903 |
918 | 904 |
919 // Check whether the current debug break should be reported to the debugger. It | |
920 // is used to have step next and step in only report break back to the debugger | |
921 // if on a different frame or in a different statement. In some situations | |
922 // there will be several break points in the same statement when the code is | |
923 // flooded with one-shot break points. This function helps to perform several | |
924 // steps before reporting break back to the debugger. | |
925 bool Debug::StepNextContinue(BreakLocation* break_location, | |
926 JavaScriptFrame* frame) { | |
927 // StepNext and StepOut shouldn't bring us deeper in code, so last frame | |
928 // shouldn't be a parent of current frame. | |
929 StepAction step_action = thread_local_.last_step_action_; | |
930 | |
931 if (step_action == StepNext || step_action == StepOut) { | |
932 if (frame->fp() < thread_local_.last_fp_) return true; | |
933 } | |
934 | |
935 // We stepped into a new frame if the frame pointer changed. | |
936 if (step_action == StepFrame) { | |
937 return frame->UnpaddedFP() == thread_local_.last_fp_; | |
938 } | |
939 | |
940 // If the step last action was step next or step in make sure that a new | |
941 // statement is hit. | |
942 if (step_action == StepNext || step_action == StepIn) { | |
943 // Never continue if returning from function. | |
944 if (break_location->IsReturn()) return false; | |
945 | |
946 // Continue if we are still on the same frame and in the same statement. | |
947 int current_statement_position = | |
948 break_location->code()->SourceStatementPosition(frame->pc()); | |
949 return thread_local_.last_fp_ == frame->UnpaddedFP() && | |
950 thread_local_.last_statement_position_ == current_statement_position; | |
951 } | |
952 | |
953 // No step next action - don't continue. | |
954 return false; | |
955 } | |
956 | |
957 | |
958 // Simple function for returning the source positions for active break points. | 905 // Simple function for returning the source positions for active break points. |
959 Handle<Object> Debug::GetSourceBreakLocations( | 906 Handle<Object> Debug::GetSourceBreakLocations( |
960 Handle<SharedFunctionInfo> shared, | 907 Handle<SharedFunctionInfo> shared, |
961 BreakPositionAlignment position_alignment) { | 908 BreakPositionAlignment position_alignment) { |
962 Isolate* isolate = shared->GetIsolate(); | 909 Isolate* isolate = shared->GetIsolate(); |
963 Heap* heap = isolate->heap(); | 910 Heap* heap = isolate->heap(); |
964 if (!shared->HasDebugInfo()) { | 911 if (!shared->HasDebugInfo()) { |
965 return Handle<Object>(heap->undefined_value(), isolate); | 912 return Handle<Object>(heap->undefined_value(), isolate); |
966 } | 913 } |
967 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 914 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
(...skipping 21 matching lines...) Expand all Loading... |
989 for (int j = 0; j < break_points; ++j) locations->set(count++, position); | 936 for (int j = 0; j < break_points; ++j) locations->set(count++, position); |
990 } | 937 } |
991 } | 938 } |
992 return locations; | 939 return locations; |
993 } | 940 } |
994 | 941 |
995 | 942 |
996 void Debug::ClearStepping() { | 943 void Debug::ClearStepping() { |
997 // Clear the various stepping setup. | 944 // Clear the various stepping setup. |
998 ClearOneShot(); | 945 ClearOneShot(); |
999 ClearStepOut(); | |
1000 | 946 |
1001 thread_local_.step_count_ = 0; | |
1002 thread_local_.last_step_action_ = StepNone; | 947 thread_local_.last_step_action_ = StepNone; |
1003 thread_local_.step_in_enabled_ = false; | 948 thread_local_.step_in_enabled_ = false; |
1004 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; | 949 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; |
1005 thread_local_.last_fp_ = 0; | 950 thread_local_.last_fp_ = 0; |
| 951 thread_local_.target_fp_ = 0; |
1006 } | 952 } |
1007 | 953 |
1008 | 954 |
1009 // Clears all the one-shot break points that are currently set. Normally this | 955 // Clears all the one-shot break points that are currently set. Normally this |
1010 // function is called each time a break point is hit as one shot break points | 956 // function is called each time a break point is hit as one shot break points |
1011 // are used to support stepping. | 957 // are used to support stepping. |
1012 void Debug::ClearOneShot() { | 958 void Debug::ClearOneShot() { |
1013 // The current implementation just runs through all the breakpoints. When the | 959 // The current implementation just runs through all the breakpoints. When the |
1014 // last break point for a function is removed that function is automatically | 960 // last break point for a function is removed that function is automatically |
1015 // removed from the list. | 961 // removed from the list. |
1016 for (DebugInfoListNode* node = debug_info_list_; node != NULL; | 962 for (DebugInfoListNode* node = debug_info_list_; node != NULL; |
1017 node = node->next()) { | 963 node = node->next()) { |
1018 for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS); | 964 for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS); |
1019 !it.Done(); it.Next()) { | 965 !it.Done(); it.Next()) { |
1020 it.GetBreakLocation().ClearOneShot(); | 966 it.GetBreakLocation().ClearOneShot(); |
1021 } | 967 } |
1022 } | 968 } |
1023 } | 969 } |
1024 | 970 |
1025 | 971 |
1026 void Debug::ActivateStepOut(StackFrame* frame) { | |
1027 thread_local_.step_out_fp_ = frame->UnpaddedFP(); | |
1028 } | |
1029 | |
1030 | |
1031 void Debug::EnableStepIn() { | 972 void Debug::EnableStepIn() { |
1032 STATIC_ASSERT(StepFrame > StepIn); | 973 STATIC_ASSERT(StepFrame > StepIn); |
1033 thread_local_.step_in_enabled_ = (last_step_action() >= StepIn); | 974 thread_local_.step_in_enabled_ = (last_step_action() >= StepIn); |
1034 } | 975 } |
1035 | 976 |
1036 | 977 |
1037 void Debug::ClearStepOut() { thread_local_.step_out_fp_ = 0; } | |
1038 | |
1039 | |
1040 bool MatchingCodeTargets(Code* target1, Code* target2) { | 978 bool MatchingCodeTargets(Code* target1, Code* target2) { |
1041 if (target1 == target2) return true; | 979 if (target1 == target2) return true; |
1042 if (target1->kind() != target2->kind()) return false; | 980 if (target1->kind() != target2->kind()) return false; |
1043 return target1->is_handler() || target1->is_inline_cache_stub(); | 981 return target1->is_handler() || target1->is_inline_cache_stub(); |
1044 } | 982 } |
1045 | 983 |
1046 | 984 |
1047 // Count the number of calls before the current frame PC to find the | 985 // Count the number of calls before the current frame PC to find the |
1048 // corresponding PC in the newly recompiled code. | 986 // corresponding PC in the newly recompiled code. |
1049 static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code, | 987 static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code, |
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1526 if (!EnsureDebugInfo(shared, fun)) return; | 1464 if (!EnsureDebugInfo(shared, fun)) return; |
1527 | 1465 |
1528 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 1466 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
1529 // Refresh frame summary if the code has been recompiled for debugging. | 1467 // Refresh frame summary if the code has been recompiled for debugging. |
1530 if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame); | 1468 if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame); |
1531 | 1469 |
1532 // Find range of break points starting from the break point where execution | 1470 // Find range of break points starting from the break point where execution |
1533 // has stopped. | 1471 // has stopped. |
1534 Address call_pc = summary.pc() - 1; | 1472 Address call_pc = summary.pc() - 1; |
1535 List<BreakLocation> locations; | 1473 List<BreakLocation> locations; |
1536 BreakLocation::FromAddressSameStatement(debug_info, ALL_BREAK_LOCATIONS, | 1474 BreakLocation::FromAddressSameStatement(debug_info, call_pc, &locations); |
1537 call_pc, &locations); | |
1538 | 1475 |
1539 for (BreakLocation location : locations) { | 1476 for (BreakLocation location : locations) { |
1540 if (location.pc() <= summary.pc()) { | 1477 if (location.pc() <= summary.pc()) { |
1541 // The break point is near our pc. Could be a step-in possibility, | 1478 // The break point is near our pc. Could be a step-in possibility, |
1542 // that is currently taken by active debugger call. | 1479 // that is currently taken by active debugger call. |
1543 if (break_frame_id() == StackFrame::NO_ID) { | 1480 if (break_frame_id() == StackFrame::NO_ID) { |
1544 continue; // We are not stepping. | 1481 continue; // We are not stepping. |
1545 } else { | 1482 } else { |
1546 JavaScriptFrameIterator frame_it(isolate_, break_frame_id()); | 1483 JavaScriptFrameIterator frame_it(isolate_, break_frame_id()); |
1547 // If our frame is a top frame and we are stepping, we can do step-in | 1484 // If our frame is a top frame and we are stepping, we can do step-in |
(...skipping 919 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2467 } | 2404 } |
2468 | 2405 |
2469 | 2406 |
2470 void LockingCommandMessageQueue::Clear() { | 2407 void LockingCommandMessageQueue::Clear() { |
2471 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 2408 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
2472 queue_.Clear(); | 2409 queue_.Clear(); |
2473 } | 2410 } |
2474 | 2411 |
2475 } // namespace internal | 2412 } // namespace internal |
2476 } // namespace v8 | 2413 } // namespace v8 |
OLD | NEW |