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

Side by Side Diff: src/debug/debug.cc

Issue 1539483002: [debugger] simplify stepping logic. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/debug/debug.h ('k') | src/debug/debug-scopes.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/debug/debug.h ('k') | src/debug/debug-scopes.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698