Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/debugger.h" | 5 #include "vm/debugger.h" |
| 6 | 6 |
| 7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
| 8 | 8 |
| 9 #include "platform/address_sanitizer.h" | 9 #include "platform/address_sanitizer.h" |
| 10 | 10 |
| 11 #include "vm/code_patcher.h" | 11 #include "vm/code_patcher.h" |
| 12 #include "vm/compiler.h" | 12 #include "vm/compiler.h" |
| 13 #include "vm/dart_entry.h" | 13 #include "vm/dart_entry.h" |
| 14 #include "vm/deopt_instructions.h" | 14 #include "vm/deopt_instructions.h" |
| 15 #include "vm/flags.h" | 15 #include "vm/flags.h" |
| 16 #include "vm/globals.h" | 16 #include "vm/globals.h" |
| 17 #include "vm/json_stream.h" | 17 #include "vm/json_stream.h" |
| 18 #include "vm/longjump.h" | 18 #include "vm/longjump.h" |
| 19 #include "vm/message_handler.h" | 19 #include "vm/message_handler.h" |
| 20 #include "vm/object.h" | 20 #include "vm/object.h" |
| 21 #include "vm/object_store.h" | 21 #include "vm/object_store.h" |
| 22 #include "vm/os.h" | 22 #include "vm/os.h" |
| 23 #include "vm/parser.h" | |
| 23 #include "vm/port.h" | 24 #include "vm/port.h" |
| 24 #include "vm/runtime_entry.h" | 25 #include "vm/runtime_entry.h" |
| 25 #include "vm/service.h" | 26 #include "vm/service.h" |
| 26 #include "vm/service_event.h" | 27 #include "vm/service_event.h" |
| 27 #include "vm/service_isolate.h" | 28 #include "vm/service_isolate.h" |
| 28 #include "vm/stack_frame.h" | 29 #include "vm/stack_frame.h" |
| 29 #include "vm/stack_trace.h" | 30 #include "vm/stack_trace.h" |
| 30 #include "vm/stub_code.h" | 31 #include "vm/stub_code.h" |
| 31 #include "vm/symbols.h" | 32 #include "vm/symbols.h" |
| 32 #include "vm/thread_interrupter.h" | 33 #include "vm/thread_interrupter.h" |
| (...skipping 2614 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2647 } | 2648 } |
| 2648 } | 2649 } |
| 2649 } | 2650 } |
| 2650 | 2651 |
| 2651 | 2652 |
| 2652 static bool IsTokenPosWithinFunction(const Function& func, TokenPosition pos) { | 2653 static bool IsTokenPosWithinFunction(const Function& func, TokenPosition pos) { |
| 2653 return (func.token_pos() <= pos && pos <= func.end_token_pos()); | 2654 return (func.token_pos() <= pos && pos <= func.end_token_pos()); |
| 2654 } | 2655 } |
| 2655 | 2656 |
| 2656 | 2657 |
| 2657 RawFunction* Debugger::FindBestFit(const Script& script, | 2658 // Returns true if a best fit is found. A best fit can either be a function |
| 2658 TokenPosition token_pos) { | 2659 // or a field. If it is a function, then the best fit function is returned |
| 2660 // in |best_fit|. If a best fit is a field, it means that a latent | |
| 2661 // breakpoint can be set in the range |token_pos| to |last_token_pos|. | |
| 2662 bool Debugger::FindBestFit(const Script& script, | |
| 2663 TokenPosition token_pos, | |
| 2664 TokenPosition last_token_pos, | |
| 2665 Function* best_fit) { | |
| 2659 Zone* zone = Thread::Current()->zone(); | 2666 Zone* zone = Thread::Current()->zone(); |
| 2660 Class& cls = Class::Handle(zone); | 2667 Class& cls = Class::Handle(zone); |
| 2661 Array& functions = Array::Handle(zone); | |
| 2662 const GrowableObjectArray& closures = GrowableObjectArray::Handle( | 2668 const GrowableObjectArray& closures = GrowableObjectArray::Handle( |
| 2663 zone, isolate_->object_store()->closure_functions()); | 2669 zone, isolate_->object_store()->closure_functions()); |
| 2664 Function& function = Function::Handle(zone); | 2670 Function& function = Function::Handle(zone); |
| 2665 Function& best_fit = Function::Handle(zone); | 2671 Field& field = Field::Handle(zone); |
| 2666 Error& error = Error::Handle(zone); | 2672 Error& error = Error::Handle(zone); |
| 2667 | 2673 |
| 2668 const intptr_t num_closures = closures.Length(); | 2674 const intptr_t num_closures = closures.Length(); |
| 2669 for (intptr_t i = 0; i < num_closures; i++) { | 2675 for (intptr_t i = 0; i < num_closures; i++) { |
| 2670 function ^= closures.At(i); | 2676 function ^= closures.At(i); |
| 2671 if (function.script() != script.raw()) { | 2677 if (function.script() != script.raw()) { |
| 2672 continue; | 2678 continue; |
| 2673 } | 2679 } |
| 2674 if (IsTokenPosWithinFunction(function, token_pos)) { | 2680 if (IsTokenPosWithinFunction(function, token_pos)) { |
| 2675 // Select the inner most closure. | 2681 // Select the inner most closure. |
| 2676 SelectBestFit(&best_fit, &function); | 2682 SelectBestFit(best_fit, &function); |
| 2677 } | 2683 } |
| 2678 } | 2684 } |
| 2679 if (!best_fit.IsNull()) { | 2685 if (!best_fit->IsNull()) { |
| 2680 // The inner most closure found will be the best fit. Going | 2686 // The inner most closure found will be the best fit. Going |
| 2681 // over class functions below will not help in any further | 2687 // over class functions below will not help in any further |
| 2682 // narrowing. | 2688 // narrowing. |
| 2683 return best_fit.raw(); | 2689 return true; |
| 2684 } | 2690 } |
| 2685 | 2691 |
| 2686 const ClassTable& class_table = *isolate_->class_table(); | 2692 const ClassTable& class_table = *isolate_->class_table(); |
| 2687 const intptr_t num_classes = class_table.NumCids(); | 2693 const intptr_t num_classes = class_table.NumCids(); |
| 2688 for (intptr_t i = 1; i < num_classes; i++) { | 2694 for (intptr_t i = 1; i < num_classes; i++) { |
| 2689 if (class_table.HasValidClassAt(i)) { | 2695 if (!class_table.HasValidClassAt(i)) { |
| 2690 cls = class_table.At(i); | 2696 continue; |
| 2691 if (cls.script() != script.raw()) { | 2697 } |
| 2692 continue; | 2698 cls = class_table.At(i); |
| 2699 if (cls.script() != script.raw()) { | |
| 2700 continue; | |
| 2701 } | |
| 2702 // Parse class definition if not done yet. | |
| 2703 error = cls.EnsureIsFinalized(Thread::Current()); | |
| 2704 if (!error.IsNull()) { | |
| 2705 // Ignore functions in this class. | |
| 2706 // TODO(hausner): Should we propagate this error? How? | |
| 2707 // EnsureIsFinalized only returns an error object if there | |
| 2708 // is no longjump base on the stack. | |
| 2709 continue; | |
| 2710 } | |
| 2711 const Array& functions = Array::Handle(zone, cls.functions()); | |
|
siva
2017/05/26 17:18:40
Since this is in a loop it is better to hoist this
sivachandra
2017/05/26 20:27:35
Done.
| |
| 2712 if (!functions.IsNull()) { | |
| 2713 const intptr_t num_functions = functions.Length(); | |
| 2714 for (intptr_t pos = 0; pos < num_functions; pos++) { | |
| 2715 function ^= functions.At(pos); | |
| 2716 ASSERT(!function.IsNull()); | |
| 2717 if (IsTokenPosWithinFunction(function, token_pos)) { | |
| 2718 // Closures and inner functions within a class method are not | |
| 2719 // present in the functions of a class. Hence, we can return | |
| 2720 // right away as looking through other functions of a class | |
| 2721 // will not narrow down to any inner function/closure. | |
| 2722 *best_fit = function.raw(); | |
| 2723 return true; | |
| 2724 } | |
| 2693 } | 2725 } |
| 2694 // Parse class definition if not done yet. | 2726 } |
| 2695 error = cls.EnsureIsFinalized(Thread::Current()); | 2727 // If none of the functions in the class contain token_pos, then we |
| 2696 if (!error.IsNull()) { | 2728 // check if it falls within a function literal initializer of field. |
|
siva
2017/05/26 17:18:40
// check if it falls within a function literal ini
sivachandra
2017/05/26 20:27:34
Improved as you suggested, and also added a little
| |
| 2697 // Ignore functions in this class. | 2729 const Array& fields = Array::Handle(zone, cls.fields()); |
|
siva
2017/05/26 17:18:40
Ditto comment about hoisting this handle creation
sivachandra
2017/05/26 20:27:34
Done.
| |
| 2698 // TODO(hausner): Should we propagate this error? How? | 2730 if (!fields.IsNull()) { |
| 2699 // EnsureIsFinalized only returns an error object if there | 2731 const intptr_t num_fields = fields.Length(); |
| 2700 // is no longjump base on the stack. | 2732 for (intptr_t pos = 0; pos < num_fields; pos++) { |
| 2701 continue; | 2733 TokenPosition start; |
| 2702 } | 2734 TokenPosition end; |
| 2703 functions = cls.functions(); | 2735 field ^= fields.At(pos); |
| 2704 if (!functions.IsNull()) { | 2736 ASSERT(!field.IsNull()); |
| 2705 const intptr_t num_functions = functions.Length(); | 2737 if (Parser::FieldHasFunctionLiteralInitializer(field, &start, &end)) { |
| 2706 for (intptr_t pos = 0; pos < num_functions; pos++) { | 2738 if ((start <= token_pos && token_pos <= end) || |
| 2707 function ^= functions.At(pos); | 2739 (token_pos <= start && start <= last_token_pos)) { |
| 2708 ASSERT(!function.IsNull()); | 2740 return true; |
| 2709 if (IsTokenPosWithinFunction(function, token_pos)) { | |
| 2710 // Closures and inner functions within a class method are not | |
| 2711 // present in the functions of a class. Hence, we can return | |
| 2712 // right away as looking through other functions of a class | |
| 2713 // will not narrow down to any inner function/closure. | |
| 2714 return function.raw(); | |
| 2715 } | 2741 } |
| 2716 } | 2742 } |
| 2717 } | 2743 } |
| 2718 } | 2744 } |
| 2719 } | 2745 } |
| 2720 return Function::null(); | 2746 return false; |
| 2721 } | 2747 } |
| 2722 | 2748 |
| 2723 | 2749 |
| 2724 BreakpointLocation* Debugger::SetBreakpoint(const Script& script, | 2750 BreakpointLocation* Debugger::SetBreakpoint(const Script& script, |
| 2725 TokenPosition token_pos, | 2751 TokenPosition token_pos, |
| 2726 TokenPosition last_token_pos, | 2752 TokenPosition last_token_pos, |
| 2727 intptr_t requested_line, | 2753 intptr_t requested_line, |
| 2728 intptr_t requested_column) { | 2754 intptr_t requested_column) { |
| 2729 Function& func = Function::Handle(); | 2755 Function& func = Function::Handle(); |
| 2730 func = FindBestFit(script, token_pos); | 2756 if (!FindBestFit(script, token_pos, last_token_pos, &func)) { |
| 2731 if (func.IsNull()) { | |
| 2732 return NULL; | 2757 return NULL; |
| 2733 } | 2758 } |
| 2734 // There may be more than one function object for a given function | 2759 if (!func.IsNull()) { |
| 2735 // in source code. There may be implicit closure functions, and | 2760 // There may be more than one function object for a given function |
| 2736 // there may be copies of mixin functions. Collect all compiled | 2761 // in source code. There may be implicit closure functions, and |
| 2737 // functions whose source code range matches exactly the best fit | 2762 // there may be copies of mixin functions. Collect all compiled |
| 2738 // function we found. | 2763 // functions whose source code range matches exactly the best fit |
| 2739 GrowableObjectArray& functions = | 2764 // function we found. |
| 2740 GrowableObjectArray::Handle(GrowableObjectArray::New()); | 2765 GrowableObjectArray& functions = |
| 2741 FindCompiledFunctions(script, func.token_pos(), func.end_token_pos(), | 2766 GrowableObjectArray::Handle(GrowableObjectArray::New()); |
| 2742 &functions); | 2767 FindCompiledFunctions(script, func.token_pos(), func.end_token_pos(), |
| 2768 &functions); | |
| 2743 | 2769 |
| 2744 if (functions.Length() > 0) { | 2770 if (functions.Length() > 0) { |
| 2745 // One or more function object containing this breakpoint location | 2771 // One or more function object containing this breakpoint location |
| 2746 // have already been compiled. We can resolve the breakpoint now. | 2772 // have already been compiled. We can resolve the breakpoint now. |
| 2747 DeoptimizeWorld(); | 2773 DeoptimizeWorld(); |
| 2748 func ^= functions.At(0); | 2774 func ^= functions.At(0); |
| 2749 TokenPosition breakpoint_pos = | 2775 TokenPosition breakpoint_pos = ResolveBreakpointPos( |
| 2750 ResolveBreakpointPos(func, token_pos, last_token_pos, requested_column); | 2776 func, token_pos, last_token_pos, requested_column); |
| 2751 if (breakpoint_pos.IsReal()) { | 2777 if (breakpoint_pos.IsReal()) { |
| 2752 BreakpointLocation* bpt = | 2778 BreakpointLocation* bpt = |
| 2753 GetBreakpointLocation(script, breakpoint_pos, requested_column); | 2779 GetBreakpointLocation(script, breakpoint_pos, requested_column); |
| 2754 if (bpt != NULL) { | 2780 if (bpt != NULL) { |
| 2755 // A source breakpoint for this location already exists. | 2781 // A source breakpoint for this location already exists. |
| 2782 return bpt; | |
| 2783 } | |
| 2784 bpt = new BreakpointLocation(script, token_pos, last_token_pos, | |
| 2785 requested_line, requested_column); | |
| 2786 bpt->SetResolved(func, breakpoint_pos); | |
| 2787 RegisterBreakpointLocation(bpt); | |
| 2788 | |
| 2789 // Create code breakpoints for all compiled functions we found. | |
| 2790 const intptr_t num_functions = functions.Length(); | |
| 2791 for (intptr_t i = 0; i < num_functions; i++) { | |
| 2792 func ^= functions.At(i); | |
| 2793 ASSERT(func.HasCode()); | |
| 2794 MakeCodeBreakpointAt(func, bpt); | |
| 2795 } | |
| 2796 if (FLAG_verbose_debug) { | |
| 2797 intptr_t line_number; | |
| 2798 intptr_t column_number; | |
| 2799 script.GetTokenLocation(breakpoint_pos, &line_number, &column_number); | |
| 2800 OS::Print( | |
| 2801 "Resolved BP for " | |
| 2802 "function '%s' at line %" Pd " col %" Pd "\n", | |
| 2803 func.ToFullyQualifiedCString(), line_number, column_number); | |
| 2804 } | |
| 2756 return bpt; | 2805 return bpt; |
| 2757 } | 2806 } |
| 2758 bpt = new BreakpointLocation(script, token_pos, last_token_pos, | |
| 2759 requested_line, requested_column); | |
| 2760 bpt->SetResolved(func, breakpoint_pos); | |
| 2761 RegisterBreakpointLocation(bpt); | |
| 2762 | |
| 2763 // Create code breakpoints for all compiled functions we found. | |
| 2764 const intptr_t num_functions = functions.Length(); | |
| 2765 for (intptr_t i = 0; i < num_functions; i++) { | |
| 2766 func ^= functions.At(i); | |
| 2767 ASSERT(func.HasCode()); | |
| 2768 MakeCodeBreakpointAt(func, bpt); | |
| 2769 } | |
| 2770 if (FLAG_verbose_debug) { | |
| 2771 intptr_t line_number; | |
| 2772 intptr_t column_number; | |
| 2773 script.GetTokenLocation(breakpoint_pos, &line_number, &column_number); | |
| 2774 OS::Print( | |
| 2775 "Resolved BP for " | |
| 2776 "function '%s' at line %" Pd " col %" Pd "\n", | |
| 2777 func.ToFullyQualifiedCString(), line_number, column_number); | |
| 2778 } | |
| 2779 return bpt; | |
| 2780 } | 2807 } |
| 2781 } | 2808 } |
| 2782 // There is no compiled function at this token position. | 2809 // There is either an uncompiled function, or an uncompiled function literal |
| 2783 // Register an unresolved breakpoint. | 2810 // initializer of a field at |token_pos|. Hence, Register an unresolved |
| 2784 if (FLAG_verbose_debug && !func.IsNull()) { | 2811 // breakpoint. |
| 2812 if (FLAG_verbose_debug) { | |
| 2785 intptr_t line_number; | 2813 intptr_t line_number; |
| 2786 intptr_t column_number; | 2814 intptr_t column_number; |
| 2787 script.GetTokenLocation(token_pos, &line_number, &column_number); | 2815 script.GetTokenLocation(token_pos, &line_number, &column_number); |
| 2788 OS::Print( | 2816 if (func.IsNull()) { |
| 2789 "Registering pending breakpoint for " | 2817 OS::Print( |
| 2790 "uncompiled function '%s' at line %" Pd " col %" Pd "\n", | 2818 "Registering pending breakpoint for " |
| 2791 func.ToFullyQualifiedCString(), line_number, column_number); | 2819 "an uncompiled function literal at line %" Pd " col %" Pd "\n", |
| 2820 line_number, column_number); | |
| 2821 } else { | |
| 2822 OS::Print( | |
| 2823 "Registering pending breakpoint for " | |
| 2824 "uncompiled function '%s' at line %" Pd " col %" Pd "\n", | |
| 2825 func.ToFullyQualifiedCString(), line_number, column_number); | |
| 2826 } | |
| 2792 } | 2827 } |
| 2793 BreakpointLocation* bpt = | 2828 BreakpointLocation* bpt = |
| 2794 GetBreakpointLocation(script, token_pos, requested_column); | 2829 GetBreakpointLocation(script, token_pos, requested_column); |
| 2795 if (bpt == NULL) { | 2830 if (bpt == NULL) { |
| 2796 bpt = new BreakpointLocation(script, token_pos, last_token_pos, | 2831 bpt = new BreakpointLocation(script, token_pos, last_token_pos, |
| 2797 requested_line, requested_column); | 2832 requested_line, requested_column); |
| 2798 RegisterBreakpointLocation(bpt); | 2833 RegisterBreakpointLocation(bpt); |
| 2799 } | 2834 } |
| 2800 return bpt; | 2835 return bpt; |
| 2801 } | 2836 } |
| (...skipping 1639 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4441 | 4476 |
| 4442 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 4477 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 4443 ASSERT(bpt->next() == NULL); | 4478 ASSERT(bpt->next() == NULL); |
| 4444 bpt->set_next(code_breakpoints_); | 4479 bpt->set_next(code_breakpoints_); |
| 4445 code_breakpoints_ = bpt; | 4480 code_breakpoints_ = bpt; |
| 4446 } | 4481 } |
| 4447 | 4482 |
| 4448 #endif // !PRODUCT | 4483 #endif // !PRODUCT |
| 4449 | 4484 |
| 4450 } // namespace dart | 4485 } // namespace dart |
| OLD | NEW |