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 <memory> | 7 #include <memory> |
8 | 8 |
9 #include "src/api.h" | 9 #include "src/api.h" |
10 #include "src/arguments.h" | 10 #include "src/arguments.h" |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
48 break_points_active_(true), | 48 break_points_active_(true), |
49 in_debug_event_listener_(false), | 49 in_debug_event_listener_(false), |
50 break_on_exception_(false), | 50 break_on_exception_(false), |
51 break_on_uncaught_exception_(false), | 51 break_on_uncaught_exception_(false), |
52 debug_info_list_(NULL), | 52 debug_info_list_(NULL), |
53 feature_tracker_(isolate), | 53 feature_tracker_(isolate), |
54 isolate_(isolate) { | 54 isolate_(isolate) { |
55 ThreadInit(); | 55 ThreadInit(); |
56 } | 56 } |
57 | 57 |
58 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, | 58 BreakLocation BreakLocation::FromFrame(StandardFrame* frame) { |
59 JavaScriptFrame* frame) { | 59 // TODO(clemensh): Handle Wasm frames. |
60 FrameSummary summary = FrameSummary::GetFirst(frame); | 60 DCHECK(!frame->is_wasm()); |
61 | |
62 auto summary = FrameSummary::GetFirst(frame).AsJavaScript(); | |
61 int offset = summary.code_offset(); | 63 int offset = summary.code_offset(); |
62 Handle<AbstractCode> abstract_code = summary.AsJavaScript().abstract_code(); | 64 Handle<AbstractCode> abstract_code = summary.abstract_code(); |
63 if (abstract_code->IsCode()) offset = offset - 1; | 65 if (abstract_code->IsCode()) offset = offset - 1; |
66 Handle<DebugInfo> debug_info(summary.function()->shared()->GetDebugInfo()); | |
64 auto it = BreakIterator::GetIterator(debug_info, abstract_code); | 67 auto it = BreakIterator::GetIterator(debug_info, abstract_code); |
65 it->SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset)); | 68 it->SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset)); |
66 return it->GetBreakLocation(); | 69 return it->GetBreakLocation(); |
67 } | 70 } |
68 | 71 |
69 void BreakLocation::AllAtCurrentStatement(Handle<DebugInfo> debug_info, | 72 void BreakLocation::AllAtCurrentStatement(Handle<DebugInfo> debug_info, |
70 JavaScriptFrame* frame, | 73 JavaScriptFrame* frame, |
71 List<BreakLocation>* result_out) { | 74 List<BreakLocation>* result_out) { |
72 auto summary = FrameSummary::GetFirst(frame).AsJavaScript(); | 75 auto summary = FrameSummary::GetFirst(frame).AsJavaScript(); |
73 int offset = summary.code_offset(); | 76 int offset = summary.code_offset(); |
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
501 // Just continue if breaks are disabled or debugger cannot be loaded. | 504 // Just continue if breaks are disabled or debugger cannot be loaded. |
502 if (break_disabled()) return; | 505 if (break_disabled()) return; |
503 | 506 |
504 // Enter the debugger. | 507 // Enter the debugger. |
505 DebugScope debug_scope(this); | 508 DebugScope debug_scope(this); |
506 if (debug_scope.failed()) return; | 509 if (debug_scope.failed()) return; |
507 | 510 |
508 // Postpone interrupt during breakpoint processing. | 511 // Postpone interrupt during breakpoint processing. |
509 PostponeInterruptsScope postpone(isolate_); | 512 PostponeInterruptsScope postpone(isolate_); |
510 | 513 |
511 // Get the debug info (create it if it does not exist). | 514 // Return if we fail to retrieve debug info for javascript frames. |
512 Handle<JSFunction> function(frame->function()); | 515 if (frame->is_java_script()) { |
513 Handle<SharedFunctionInfo> shared(function->shared()); | 516 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); |
Yang
2017/01/12 12:50:21
Currently frame has the type JavaScriptFrame*. I a
Clemens Hammacher
2017/01/12 14:11:38
That's right. This will change in one of the follo
Yang
2017/01/12 14:18:19
right... but currently we do the check for is_java
| |
514 if (!EnsureDebugInfo(shared, function)) { | 517 |
515 // Return if we failed to retrieve the debug info. | 518 // Get the debug info (create it if it does not exist). |
516 return; | 519 Handle<JSFunction> function(js_frame->function()); |
520 Handle<SharedFunctionInfo> shared(function->shared()); | |
521 if (!EnsureDebugInfo(shared, function)) return; | |
517 } | 522 } |
518 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); | |
519 | 523 |
520 // Find the break location where execution has stopped. | 524 BreakLocation location = BreakLocation::FromFrame(frame); |
521 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); | |
522 | 525 |
523 // Find actual break points, if any, and trigger debug break event. | 526 // Find actual break points, if any, and trigger debug break event. |
524 Handle<Object> break_points_hit = CheckBreakPoints(debug_info, &location); | 527 MaybeHandle<FixedArray> break_points_hit; |
525 if (!break_points_hit->IsUndefined(isolate_)) { | 528 if (!break_points_active()) { |
529 // Don't try to find hit breakpoints. | |
530 } else if (frame->is_wasm_interpreter_entry()) { | |
531 // TODO(clemensh): Find hit breakpoints for wasm. | |
532 UNIMPLEMENTED(); | |
533 } else { | |
534 // Get the debug info, which must exist if we reach here. | |
535 Handle<DebugInfo> debug_info( | |
536 JavaScriptFrame::cast(frame)->function()->shared()->GetDebugInfo(), | |
537 isolate_); | |
538 | |
539 break_points_hit = CheckBreakPoints(debug_info, &location); | |
540 } | |
541 | |
542 if (!break_points_hit.is_null()) { | |
526 // Clear all current stepping setup. | 543 // Clear all current stepping setup. |
527 ClearStepping(); | 544 ClearStepping(); |
528 // Notify the debug event listeners. | 545 // Notify the debug event listeners. |
529 OnDebugBreak(break_points_hit, false); | 546 Handle<JSArray> jsarr = isolate_->factory()->NewJSArrayWithElements( |
547 break_points_hit.ToHandleChecked()); | |
548 OnDebugBreak(jsarr, false); | |
530 return; | 549 return; |
531 } | 550 } |
532 | 551 |
533 // No break point. Check for stepping. | 552 // No break point. Check for stepping. |
534 StepAction step_action = last_step_action(); | 553 StepAction step_action = last_step_action(); |
535 Address current_fp = frame->UnpaddedFP(); | 554 Address current_fp = frame->UnpaddedFP(); |
536 Address target_fp = thread_local_.target_fp_; | 555 Address target_fp = thread_local_.target_fp_; |
537 Address last_fp = thread_local_.last_fp_; | 556 Address last_fp = thread_local_.last_fp_; |
538 | 557 |
539 bool step_break = false; | 558 bool step_break = false; |
(...skipping 30 matching lines...) Expand all Loading... | |
570 // Notify the debug event listeners. | 589 // Notify the debug event listeners. |
571 OnDebugBreak(isolate_->factory()->undefined_value(), false); | 590 OnDebugBreak(isolate_->factory()->undefined_value(), false); |
572 } else { | 591 } else { |
573 // Re-prepare to continue. | 592 // Re-prepare to continue. |
574 PrepareStep(step_action); | 593 PrepareStep(step_action); |
575 } | 594 } |
576 } | 595 } |
577 | 596 |
578 | 597 |
579 // Find break point objects for this location, if any, and evaluate them. | 598 // Find break point objects for this location, if any, and evaluate them. |
580 // Return an array of break point objects that evaluated true. | 599 // Return an array of break point objects that evaluated true, or an empty |
581 Handle<Object> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info, | 600 // handle if none evaluated true. |
582 BreakLocation* location, | 601 MaybeHandle<FixedArray> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info, |
583 bool* has_break_points) { | 602 BreakLocation* location, |
584 Factory* factory = isolate_->factory(); | 603 bool* has_break_points) { |
585 bool has_break_points_to_check = | 604 bool has_break_points_to_check = |
586 break_points_active_ && location->HasBreakPoint(debug_info); | 605 break_points_active_ && location->HasBreakPoint(debug_info); |
587 if (has_break_points) *has_break_points = has_break_points_to_check; | 606 if (has_break_points) *has_break_points = has_break_points_to_check; |
588 if (!has_break_points_to_check) return factory->undefined_value(); | 607 if (!has_break_points_to_check) return {}; |
589 | 608 |
590 Handle<Object> break_point_objects = | 609 Handle<Object> break_point_objects = |
591 debug_info->GetBreakPointObjects(location->position()); | 610 debug_info->GetBreakPointObjects(location->position()); |
592 // Count the number of break points hit. If there are multiple break points | 611 return Debug::GetHitBreakPointObjects(break_point_objects); |
593 // they are in a FixedArray. | |
594 Handle<FixedArray> break_points_hit; | |
595 int break_points_hit_count = 0; | |
596 DCHECK(!break_point_objects->IsUndefined(isolate_)); | |
597 if (break_point_objects->IsFixedArray()) { | |
598 Handle<FixedArray> array(FixedArray::cast(*break_point_objects)); | |
599 break_points_hit = factory->NewFixedArray(array->length()); | |
600 for (int i = 0; i < array->length(); i++) { | |
601 Handle<Object> break_point_object(array->get(i), isolate_); | |
602 if (CheckBreakPoint(break_point_object)) { | |
603 break_points_hit->set(break_points_hit_count++, *break_point_object); | |
604 } | |
605 } | |
606 } else { | |
607 break_points_hit = factory->NewFixedArray(1); | |
608 if (CheckBreakPoint(break_point_objects)) { | |
609 break_points_hit->set(break_points_hit_count++, *break_point_objects); | |
610 } | |
611 } | |
612 if (break_points_hit_count == 0) return factory->undefined_value(); | |
613 Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit); | |
614 result->set_length(Smi::FromInt(break_points_hit_count)); | |
615 return result; | |
616 } | 612 } |
617 | 613 |
618 | 614 |
619 bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) { | 615 bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) { |
620 // A break location is considered muted if break locations on the current | 616 // A break location is considered muted if break locations on the current |
621 // statement have at least one break point, and all of these break points | 617 // statement have at least one break point, and all of these break points |
622 // evaluate to false. Aside from not triggering a debug break event at the | 618 // evaluate to false. Aside from not triggering a debug break event at the |
623 // break location, we also do not trigger one for debugger statements, nor | 619 // break location, we also do not trigger one for debugger statements, nor |
624 // an exception event on exception at this location. | 620 // an exception event on exception at this location. |
625 Object* fun = frame->function(); | 621 Object* fun = frame->function(); |
626 if (!fun->IsJSFunction()) return false; | 622 if (!fun->IsJSFunction()) return false; |
627 JSFunction* function = JSFunction::cast(fun); | 623 JSFunction* function = JSFunction::cast(fun); |
628 if (!function->shared()->HasDebugInfo()) return false; | 624 if (!function->shared()->HasDebugInfo()) return false; |
629 HandleScope scope(isolate_); | 625 HandleScope scope(isolate_); |
630 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo()); | 626 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo()); |
631 // Enter the debugger. | 627 // Enter the debugger. |
632 DebugScope debug_scope(this); | 628 DebugScope debug_scope(this); |
633 if (debug_scope.failed()) return false; | 629 if (debug_scope.failed()) return false; |
634 List<BreakLocation> break_locations; | 630 List<BreakLocation> break_locations; |
635 BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations); | 631 BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations); |
636 bool has_break_points_at_all = false; | 632 bool has_break_points_at_all = false; |
637 for (int i = 0; i < break_locations.length(); i++) { | 633 for (int i = 0; i < break_locations.length(); i++) { |
638 bool has_break_points; | 634 bool has_break_points; |
639 Handle<Object> check_result = | 635 MaybeHandle<FixedArray> check_result = |
640 CheckBreakPoints(debug_info, &break_locations[i], &has_break_points); | 636 CheckBreakPoints(debug_info, &break_locations[i], &has_break_points); |
641 has_break_points_at_all |= has_break_points; | 637 has_break_points_at_all |= has_break_points; |
642 if (has_break_points && !check_result->IsUndefined(isolate_)) return false; | 638 if (has_break_points && !check_result.is_null()) return false; |
643 } | 639 } |
644 return has_break_points_at_all; | 640 return has_break_points_at_all; |
645 } | 641 } |
646 | 642 |
647 | 643 |
648 MaybeHandle<Object> Debug::CallFunction(const char* name, int argc, | 644 MaybeHandle<Object> Debug::CallFunction(const char* name, int argc, |
649 Handle<Object> args[]) { | 645 Handle<Object> args[]) { |
650 PostponeInterruptsScope no_interrupts(isolate_); | 646 PostponeInterruptsScope no_interrupts(isolate_); |
651 AssertDebugContext(); | 647 AssertDebugContext(); |
652 Handle<JSReceiver> holder = | 648 Handle<JSReceiver> holder = |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
893 | 889 |
894 | 890 |
895 bool Debug::IsBreakOnException(ExceptionBreakType type) { | 891 bool Debug::IsBreakOnException(ExceptionBreakType type) { |
896 if (type == BreakUncaughtException) { | 892 if (type == BreakUncaughtException) { |
897 return break_on_uncaught_exception_; | 893 return break_on_uncaught_exception_; |
898 } else { | 894 } else { |
899 return break_on_exception_; | 895 return break_on_exception_; |
900 } | 896 } |
901 } | 897 } |
902 | 898 |
899 MaybeHandle<FixedArray> Debug::GetHitBreakPointObjects( | |
900 Handle<Object> break_point_objects) { | |
901 DCHECK(!break_point_objects->IsUndefined(isolate_)); | |
902 if (!break_point_objects->IsFixedArray()) { | |
903 if (!CheckBreakPoint(break_point_objects)) return {}; | |
904 Handle<FixedArray> break_points_hit = isolate_->factory()->NewFixedArray(1); | |
905 break_points_hit->set(0, *break_point_objects); | |
906 return break_points_hit; | |
907 } | |
908 | |
909 Handle<FixedArray> array(FixedArray::cast(*break_point_objects)); | |
910 int num_objects = array->length(); | |
911 Handle<FixedArray> break_points_hit = | |
912 isolate_->factory()->NewFixedArray(num_objects); | |
913 int break_points_hit_count = 0; | |
914 for (int i = 0; i < num_objects; ++i) { | |
915 Handle<Object> break_point_object(array->get(i), isolate_); | |
916 if (CheckBreakPoint(break_point_object)) { | |
917 break_points_hit->set(break_points_hit_count++, *break_point_object); | |
918 } | |
919 } | |
920 if (break_points_hit_count == 0) return {}; | |
921 break_points_hit->Shrink(break_points_hit_count); | |
922 return break_points_hit; | |
923 } | |
903 | 924 |
904 void Debug::PrepareStepIn(Handle<JSFunction> function) { | 925 void Debug::PrepareStepIn(Handle<JSFunction> function) { |
905 CHECK(last_step_action() >= StepIn); | 926 CHECK(last_step_action() >= StepIn); |
906 if (!is_active()) return; | 927 if (!is_active()) return; |
907 if (in_debug_scope()) return; | 928 if (in_debug_scope()) return; |
908 FloodWithOneShot(function); | 929 FloodWithOneShot(function); |
909 } | 930 } |
910 | 931 |
911 void Debug::PrepareStepInSuspendedGenerator() { | 932 void Debug::PrepareStepInSuspendedGenerator() { |
912 CHECK(has_suspended_generator()); | 933 CHECK(has_suspended_generator()); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
981 // Step out: Find the calling JavaScript frame and flood it with | 1002 // Step out: Find the calling JavaScript frame and flood it with |
982 // breakpoints. | 1003 // breakpoints. |
983 frames_it.Advance(); | 1004 frames_it.Advance(); |
984 // Fill the function to return to with one-shot break points. | 1005 // Fill the function to return to with one-shot break points. |
985 JSFunction* function = frames_it.frame()->function(); | 1006 JSFunction* function = frames_it.frame()->function(); |
986 FloodWithOneShot(Handle<JSFunction>(function)); | 1007 FloodWithOneShot(Handle<JSFunction>(function)); |
987 return; | 1008 return; |
988 } | 1009 } |
989 | 1010 |
990 // Get the debug info (create it if it does not exist). | 1011 // Get the debug info (create it if it does not exist). |
991 auto summary = FrameSummary::GetFirst(frame).AsJavaScript(); | 1012 auto summary = FrameSummary::GetFirst(frame).AsJavaScript(); |
Yang
2017/01/12 12:50:21
These few lines could be dropped if we already hav
Clemens Hammacher
2017/01/12 14:11:38
Same problem.
| |
992 Handle<JSFunction> function(summary.function()); | 1013 Handle<JSFunction> function(summary.function()); |
993 Handle<SharedFunctionInfo> shared(function->shared()); | 1014 Handle<SharedFunctionInfo> shared(function->shared()); |
994 if (!EnsureDebugInfo(shared, function)) { | 1015 if (!EnsureDebugInfo(shared, function)) { |
995 // Return if ensuring debug info failed. | 1016 // Return if ensuring debug info failed. |
996 return; | 1017 return; |
997 } | 1018 } |
998 | 1019 |
999 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 1020 BreakLocation location = BreakLocation::FromFrame(frame); |
1000 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); | |
1001 | 1021 |
1002 // Any step at a return is a step-out. | 1022 // Any step at a return is a step-out. |
1003 if (location.IsReturn()) step_action = StepOut; | 1023 if (location.IsReturn()) step_action = StepOut; |
1004 // A step-next at a tail call is a step-out. | 1024 // A step-next at a tail call is a step-out. |
1005 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; | 1025 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; |
1006 | 1026 |
1007 thread_local_.last_statement_position_ = | 1027 thread_local_.last_statement_position_ = |
1008 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); | 1028 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); |
1009 thread_local_.last_fp_ = frame->UnpaddedFP(); | 1029 thread_local_.last_fp_ = frame->UnpaddedFP(); |
1010 // No longer perform the current async step. | 1030 // No longer perform the current async step. |
(...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1556 after_break_target_ = NULL; | 1576 after_break_target_ = NULL; |
1557 if (!LiveEdit::SetAfterBreakTarget(this)) { | 1577 if (!LiveEdit::SetAfterBreakTarget(this)) { |
1558 // Continue just after the slot. | 1578 // Continue just after the slot. |
1559 after_break_target_ = frame->pc(); | 1579 after_break_target_ = frame->pc(); |
1560 } | 1580 } |
1561 } | 1581 } |
1562 | 1582 |
1563 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { | 1583 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { |
1564 HandleScope scope(isolate_); | 1584 HandleScope scope(isolate_); |
1565 | 1585 |
1566 // Get the executing function in which the debug break occurred. | |
1567 Handle<SharedFunctionInfo> shared(frame->function()->shared()); | |
1568 | |
1569 // With no debug info there are no break points, so we can't be at a return. | 1586 // With no debug info there are no break points, so we can't be at a return. |
1570 if (!shared->HasDebugInfo()) return false; | 1587 if (!frame->function()->shared()->HasDebugInfo()) return false; |
1571 | 1588 |
1572 DCHECK(!frame->is_optimized()); | 1589 DCHECK(!frame->is_optimized()); |
1573 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 1590 BreakLocation location = BreakLocation::FromFrame(frame); |
1574 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); | |
1575 return location.IsReturn() || location.IsTailCall(); | 1591 return location.IsReturn() || location.IsTailCall(); |
1576 } | 1592 } |
1577 | 1593 |
1578 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, | 1594 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, |
1579 LiveEditFrameDropMode mode) { | 1595 LiveEditFrameDropMode mode) { |
1580 if (mode != LIVE_EDIT_CURRENTLY_SET_MODE) { | 1596 if (mode != LIVE_EDIT_CURRENTLY_SET_MODE) { |
1581 thread_local_.frame_drop_mode_ = mode; | 1597 thread_local_.frame_drop_mode_ = mode; |
1582 } | 1598 } |
1583 thread_local_.break_frame_id_ = new_break_frame_id; | 1599 thread_local_.break_frame_id_ = new_break_frame_id; |
1584 } | 1600 } |
(...skipping 965 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2550 logger_->DebugEvent("Put", message.text()); | 2566 logger_->DebugEvent("Put", message.text()); |
2551 } | 2567 } |
2552 | 2568 |
2553 void LockingCommandMessageQueue::Clear() { | 2569 void LockingCommandMessageQueue::Clear() { |
2554 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 2570 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
2555 queue_.Clear(); | 2571 queue_.Clear(); |
2556 } | 2572 } |
2557 | 2573 |
2558 } // namespace internal | 2574 } // namespace internal |
2559 } // namespace v8 | 2575 } // namespace v8 |
OLD | NEW |