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 |
| (...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 472 const String& func_name = String::Handle(func.name()); | 472 const String& func_name = String::Handle(func.name()); |
| 473 Class& func_class = Class::Handle(func.Owner()); | 473 Class& func_class = Class::Handle(func.Owner()); |
| 474 String& class_name = String::Handle(func_class.Name()); | 474 String& class_name = String::Handle(func_class.Name()); |
| 475 | 475 |
| 476 return OS::SCreate(Thread::Current()->zone(), "%s%s%s", | 476 return OS::SCreate(Thread::Current()->zone(), "%s%s%s", |
| 477 func_class.IsTopLevel() ? "" : class_name.ToCString(), | 477 func_class.IsTopLevel() ? "" : class_name.ToCString(), |
| 478 func_class.IsTopLevel() ? "" : ".", func_name.ToCString()); | 478 func_class.IsTopLevel() ? "" : ".", func_name.ToCString()); |
| 479 } | 479 } |
| 480 | 480 |
| 481 | 481 |
| 482 // Returns true if function contains the token position in the given script. | 482 // Returns true if the function |func| overlaps the token range |
| 483 static bool FunctionContains(const Function& func, | 483 // [|token_pos|, |end_token_pos|] in |script|. |
| 484 static bool FunctionOverlaps(const Function& func, | |
| 484 const Script& script, | 485 const Script& script, |
| 485 TokenPosition token_pos) { | 486 TokenPosition token_pos, |
| 486 if ((func.token_pos() <= token_pos) && (token_pos <= func.end_token_pos())) { | 487 TokenPosition end_token_pos) { |
| 488 TokenPosition func_start = func.token_pos(); | |
| 489 if (((func_start <= token_pos) && (token_pos <= func.end_token_pos())) || | |
| 490 ((token_pos <= func_start) && (func_start <= end_token_pos))) { | |
| 487 // Check script equality second because it allocates | 491 // Check script equality second because it allocates |
| 488 // handles as a side effect. | 492 // handles as a side effect. |
| 489 return func.script() == script.raw(); | 493 return func.script() == script.raw(); |
| 490 } | 494 } |
| 491 return false; | 495 return false; |
| 492 } | 496 } |
| 493 | 497 |
| 494 | 498 |
| 499 static bool IsImplicitFunction(const Function& func) { | |
| 500 switch (func.kind()) { | |
| 501 case RawFunction::kImplicitGetter: | |
| 502 case RawFunction::kImplicitSetter: | |
| 503 case RawFunction::kImplicitStaticFinalGetter: | |
| 504 return true; | |
| 505 default: | |
| 506 return false; | |
| 507 } | |
| 508 } | |
| 509 | |
| 510 | |
| 495 bool Debugger::HasBreakpoint(const Function& func, Zone* zone) { | 511 bool Debugger::HasBreakpoint(const Function& func, Zone* zone) { |
| 496 if (!func.HasCode()) { | 512 if (!func.HasCode()) { |
| 497 // If the function is not compiled yet, just check whether there | 513 // If the function is not compiled yet, just check whether there |
| 498 // is a user-defined breakpoint that falls into the token | 514 // is a user-defined breakpoint that falls into the token |
| 499 // range of the function. This may be a false positive: the breakpoint | 515 // range of the function. This may be a false positive: the breakpoint |
| 500 // might be inside a local closure. | 516 // might be inside a local closure. |
| 501 Script& script = Script::Handle(zone); | 517 Script& script = Script::Handle(zone); |
| 502 BreakpointLocation* sbpt = breakpoint_locations_; | 518 BreakpointLocation* sbpt = breakpoint_locations_; |
| 503 while (sbpt != NULL) { | 519 while (sbpt != NULL) { |
| 504 script = sbpt->script(); | 520 script = sbpt->script(); |
| 505 if (FunctionContains(func, script, sbpt->token_pos())) { | 521 if (FunctionOverlaps(func, script, sbpt->token_pos(), |
| 522 sbpt->end_token_pos())) { | |
| 506 return true; | 523 return true; |
| 507 } | 524 } |
| 508 sbpt = sbpt->next_; | 525 sbpt = sbpt->next_; |
| 509 } | 526 } |
| 510 return false; | 527 return false; |
| 511 } | 528 } |
| 512 CodeBreakpoint* cbpt = code_breakpoints_; | 529 CodeBreakpoint* cbpt = code_breakpoints_; |
| 513 while (cbpt != NULL) { | 530 while (cbpt != NULL) { |
| 514 if (func.raw() == cbpt->function()) { | 531 if (func.raw() == cbpt->function()) { |
| 515 return true; | 532 return true; |
| (...skipping 2127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2643 *best_fit = func->raw(); | 2660 *best_fit = func->raw(); |
| 2644 } else { | 2661 } else { |
| 2645 if ((func->token_pos() > best_fit->token_pos()) && | 2662 if ((func->token_pos() > best_fit->token_pos()) && |
| 2646 ((func->end_token_pos() <= best_fit->end_token_pos()))) { | 2663 ((func->end_token_pos() <= best_fit->end_token_pos()))) { |
| 2647 *best_fit = func->raw(); | 2664 *best_fit = func->raw(); |
| 2648 } | 2665 } |
| 2649 } | 2666 } |
| 2650 } | 2667 } |
| 2651 | 2668 |
| 2652 | 2669 |
| 2653 static bool IsTokenPosWithinFunction(const Function& func, TokenPosition pos) { | |
| 2654 return (func.token_pos() <= pos && pos <= func.end_token_pos()); | |
| 2655 } | |
| 2656 | |
| 2657 | |
| 2658 // Returns true if a best fit is found. A best fit can either be a function | 2670 // Returns true if a best fit is found. A best fit can either be a function |
| 2659 // or a field. If it is a function, then the best fit function is returned | 2671 // 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 | 2672 // 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|. | 2673 // breakpoint can be set in the range |token_pos| to |last_token_pos|. |
| 2662 bool Debugger::FindBestFit(const Script& script, | 2674 bool Debugger::FindBestFit(const Script& script, |
| 2663 TokenPosition token_pos, | 2675 TokenPosition token_pos, |
| 2664 TokenPosition last_token_pos, | 2676 TokenPosition last_token_pos, |
| 2665 Function* best_fit) { | 2677 Function* best_fit) { |
| 2666 Zone* zone = Thread::Current()->zone(); | 2678 Zone* zone = Thread::Current()->zone(); |
| 2667 Class& cls = Class::Handle(zone); | 2679 Class& cls = Class::Handle(zone); |
| 2668 const GrowableObjectArray& closures = GrowableObjectArray::Handle( | 2680 const GrowableObjectArray& closures = GrowableObjectArray::Handle( |
| 2669 zone, isolate_->object_store()->closure_functions()); | 2681 zone, isolate_->object_store()->closure_functions()); |
| 2670 Array& functions = Array::Handle(zone); | 2682 Array& functions = Array::Handle(zone); |
| 2671 Function& function = Function::Handle(zone); | 2683 Function& function = Function::Handle(zone); |
| 2672 Array& fields = Array::Handle(zone); | 2684 Array& fields = Array::Handle(zone); |
| 2673 Field& field = Field::Handle(zone); | 2685 Field& field = Field::Handle(zone); |
| 2674 Error& error = Error::Handle(zone); | 2686 Error& error = Error::Handle(zone); |
| 2675 | 2687 |
| 2676 const intptr_t num_closures = closures.Length(); | 2688 const intptr_t num_closures = closures.Length(); |
| 2677 for (intptr_t i = 0; i < num_closures; i++) { | 2689 for (intptr_t i = 0; i < num_closures; i++) { |
| 2678 function ^= closures.At(i); | 2690 function ^= closures.At(i); |
| 2679 if (function.script() != script.raw()) { | 2691 if (FunctionOverlaps(function, script, token_pos, last_token_pos)) { |
| 2680 continue; | |
| 2681 } | |
| 2682 if (IsTokenPosWithinFunction(function, token_pos)) { | |
| 2683 // Select the inner most closure. | 2692 // Select the inner most closure. |
| 2684 SelectBestFit(best_fit, &function); | 2693 SelectBestFit(best_fit, &function); |
| 2685 } | 2694 } |
| 2686 } | 2695 } |
| 2687 if (!best_fit->IsNull()) { | 2696 if (!best_fit->IsNull()) { |
| 2688 // The inner most closure found will be the best fit. Going | 2697 // The inner most closure found will be the best fit. Going |
| 2689 // over class functions below will not help in any further | 2698 // over class functions below will not help in any further |
| 2690 // narrowing. | 2699 // narrowing. |
| 2691 return true; | 2700 return true; |
| 2692 } | 2701 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 2709 // EnsureIsFinalized only returns an error object if there | 2718 // EnsureIsFinalized only returns an error object if there |
| 2710 // is no longjump base on the stack. | 2719 // is no longjump base on the stack. |
| 2711 continue; | 2720 continue; |
| 2712 } | 2721 } |
| 2713 functions = cls.functions(); | 2722 functions = cls.functions(); |
| 2714 if (!functions.IsNull()) { | 2723 if (!functions.IsNull()) { |
| 2715 const intptr_t num_functions = functions.Length(); | 2724 const intptr_t num_functions = functions.Length(); |
| 2716 for (intptr_t pos = 0; pos < num_functions; pos++) { | 2725 for (intptr_t pos = 0; pos < num_functions; pos++) { |
| 2717 function ^= functions.At(pos); | 2726 function ^= functions.At(pos); |
| 2718 ASSERT(!function.IsNull()); | 2727 ASSERT(!function.IsNull()); |
| 2719 if (IsTokenPosWithinFunction(function, token_pos)) { | 2728 if (IsImplicitFunction(function)) { |
|
siva
2017/05/31 19:20:54
Should this also include other function types that
sivachandra
2017/05/31 20:16:46
Likewise, I think there are implicit constructors
| |
| 2729 // Implicit functions do not have a user specifiable source | |
| 2730 // location. | |
| 2731 continue; | |
| 2732 } | |
| 2733 if (FunctionOverlaps(function, script, token_pos, last_token_pos)) { | |
| 2720 // Closures and inner functions within a class method are not | 2734 // Closures and inner functions within a class method are not |
| 2721 // present in the functions of a class. Hence, we can return | 2735 // present in the functions of a class. Hence, we can return |
| 2722 // right away as looking through other functions of a class | 2736 // right away as looking through other functions of a class |
| 2723 // will not narrow down to any inner function/closure. | 2737 // will not narrow down to any inner function/closure. |
| 2724 *best_fit = function.raw(); | 2738 *best_fit = function.raw(); |
| 2725 return true; | 2739 return true; |
| 2726 } | 2740 } |
| 2727 } | 2741 } |
| 2728 } | 2742 } |
| 2729 // If none of the functions in the class contain token_pos, then we | 2743 // If none of the functions in the class contain token_pos, then we |
| (...skipping 1307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4037 // we'll resolve the breakpoint when the inner function is compiled. | 4051 // we'll resolve the breakpoint when the inner function is compiled. |
| 4038 return; | 4052 return; |
| 4039 } | 4053 } |
| 4040 // Iterate over all source breakpoints to check whether breakpoints | 4054 // Iterate over all source breakpoints to check whether breakpoints |
| 4041 // need to be set in the newly compiled function. | 4055 // need to be set in the newly compiled function. |
| 4042 Zone* zone = Thread::Current()->zone(); | 4056 Zone* zone = Thread::Current()->zone(); |
| 4043 Script& script = Script::Handle(zone); | 4057 Script& script = Script::Handle(zone); |
| 4044 for (BreakpointLocation* loc = breakpoint_locations_; loc != NULL; | 4058 for (BreakpointLocation* loc = breakpoint_locations_; loc != NULL; |
| 4045 loc = loc->next()) { | 4059 loc = loc->next()) { |
| 4046 script = loc->script(); | 4060 script = loc->script(); |
| 4047 if (FunctionContains(func, script, loc->token_pos())) { | 4061 if (FunctionOverlaps(func, script, loc->token_pos(), |
| 4062 loc->end_token_pos())) { | |
| 4048 Function& inner_function = Function::Handle(zone); | 4063 Function& inner_function = Function::Handle(zone); |
| 4049 inner_function = FindInnermostClosure(func, loc->token_pos()); | 4064 inner_function = FindInnermostClosure(func, loc->token_pos()); |
| 4050 if (!inner_function.IsNull()) { | 4065 if (!inner_function.IsNull()) { |
| 4051 // The local function of a function we just compiled cannot | 4066 // The local function of a function we just compiled cannot |
| 4052 // be compiled already. | 4067 // be compiled already. |
| 4053 ASSERT(!inner_function.HasCode()); | 4068 ASSERT(!inner_function.HasCode()); |
| 4054 if (FLAG_verbose_debug) { | 4069 if (FLAG_verbose_debug) { |
| 4055 OS::Print("Pending BP remains unresolved in inner function '%s'\n", | 4070 OS::Print("Pending BP remains unresolved in inner function '%s'\n", |
| 4056 inner_function.ToFullyQualifiedCString()); | 4071 inner_function.ToFullyQualifiedCString()); |
| 4057 } | 4072 } |
| (...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4481 | 4496 |
| 4482 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 4497 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 4483 ASSERT(bpt->next() == NULL); | 4498 ASSERT(bpt->next() == NULL); |
| 4484 bpt->set_next(code_breakpoints_); | 4499 bpt->set_next(code_breakpoints_); |
| 4485 code_breakpoints_ = bpt; | 4500 code_breakpoints_ = bpt; |
| 4486 } | 4501 } |
| 4487 | 4502 |
| 4488 #endif // !PRODUCT | 4503 #endif // !PRODUCT |
| 4489 | 4504 |
| 4490 } // namespace dart | 4505 } // namespace dart |
| OLD | NEW |