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

Side by Side Diff: runtime/vm/debugger.cc

Issue 2912763005: Hit breakpoints in single line closures. (Closed)
Patch Set: Enable a test with dartk which now passes Created 3 years, 6 months 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 | « runtime/observatory/tests/service/service.status ('k') | runtime/vm/debugger_test.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 (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
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 case RawFunction::kMethodExtractor:
505 case RawFunction::kNoSuchMethodDispatcher:
506 case RawFunction::kInvokeFieldDispatcher:
507 case RawFunction::kIrregexpFunction:
508 return true;
509 default:
510 if (func.token_pos() == func.end_token_pos()) {
511 // |func| could be an implicit constructor for example.
512 return true;
513 }
514 }
515 return false;
516 }
517
518
495 bool Debugger::HasBreakpoint(const Function& func, Zone* zone) { 519 bool Debugger::HasBreakpoint(const Function& func, Zone* zone) {
496 if (!func.HasCode()) { 520 if (!func.HasCode()) {
497 // If the function is not compiled yet, just check whether there 521 // If the function is not compiled yet, just check whether there
498 // is a user-defined breakpoint that falls into the token 522 // is a user-defined breakpoint that falls into the token
499 // range of the function. This may be a false positive: the breakpoint 523 // range of the function. This may be a false positive: the breakpoint
500 // might be inside a local closure. 524 // might be inside a local closure.
501 Script& script = Script::Handle(zone); 525 Script& script = Script::Handle(zone);
502 BreakpointLocation* sbpt = breakpoint_locations_; 526 BreakpointLocation* sbpt = breakpoint_locations_;
503 while (sbpt != NULL) { 527 while (sbpt != NULL) {
504 script = sbpt->script(); 528 script = sbpt->script();
505 if (FunctionContains(func, script, sbpt->token_pos())) { 529 if (FunctionOverlaps(func, script, sbpt->token_pos(),
530 sbpt->end_token_pos())) {
506 return true; 531 return true;
507 } 532 }
508 sbpt = sbpt->next_; 533 sbpt = sbpt->next_;
509 } 534 }
510 return false; 535 return false;
511 } 536 }
512 CodeBreakpoint* cbpt = code_breakpoints_; 537 CodeBreakpoint* cbpt = code_breakpoints_;
513 while (cbpt != NULL) { 538 while (cbpt != NULL) {
514 if (func.raw() == cbpt->function()) { 539 if (func.raw() == cbpt->function()) {
515 return true; 540 return true;
(...skipping 2127 matching lines...) Expand 10 before | Expand all | Expand 10 after
2643 *best_fit = func->raw(); 2668 *best_fit = func->raw();
2644 } else { 2669 } else {
2645 if ((func->token_pos() > best_fit->token_pos()) && 2670 if ((func->token_pos() > best_fit->token_pos()) &&
2646 ((func->end_token_pos() <= best_fit->end_token_pos()))) { 2671 ((func->end_token_pos() <= best_fit->end_token_pos()))) {
2647 *best_fit = func->raw(); 2672 *best_fit = func->raw();
2648 } 2673 }
2649 } 2674 }
2650 } 2675 }
2651 2676
2652 2677
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 2678 // 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 2679 // 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 2680 // 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|. 2681 // breakpoint can be set in the range |token_pos| to |last_token_pos|.
2662 bool Debugger::FindBestFit(const Script& script, 2682 bool Debugger::FindBestFit(const Script& script,
2663 TokenPosition token_pos, 2683 TokenPosition token_pos,
2664 TokenPosition last_token_pos, 2684 TokenPosition last_token_pos,
2665 Function* best_fit) { 2685 Function* best_fit) {
2666 Zone* zone = Thread::Current()->zone(); 2686 Zone* zone = Thread::Current()->zone();
2667 Class& cls = Class::Handle(zone); 2687 Class& cls = Class::Handle(zone);
2668 const GrowableObjectArray& closures = GrowableObjectArray::Handle( 2688 const GrowableObjectArray& closures = GrowableObjectArray::Handle(
2669 zone, isolate_->object_store()->closure_functions()); 2689 zone, isolate_->object_store()->closure_functions());
2670 Array& functions = Array::Handle(zone); 2690 Array& functions = Array::Handle(zone);
2671 Function& function = Function::Handle(zone); 2691 Function& function = Function::Handle(zone);
2672 Array& fields = Array::Handle(zone); 2692 Array& fields = Array::Handle(zone);
2673 Field& field = Field::Handle(zone); 2693 Field& field = Field::Handle(zone);
2674 Error& error = Error::Handle(zone); 2694 Error& error = Error::Handle(zone);
2675 2695
2676 const intptr_t num_closures = closures.Length(); 2696 const intptr_t num_closures = closures.Length();
2677 for (intptr_t i = 0; i < num_closures; i++) { 2697 for (intptr_t i = 0; i < num_closures; i++) {
2678 function ^= closures.At(i); 2698 function ^= closures.At(i);
2679 if (function.script() != script.raw()) { 2699 if (FunctionOverlaps(function, script, token_pos, last_token_pos)) {
2680 continue;
2681 }
2682 if (IsTokenPosWithinFunction(function, token_pos)) {
2683 // Select the inner most closure. 2700 // Select the inner most closure.
2684 SelectBestFit(best_fit, &function); 2701 SelectBestFit(best_fit, &function);
2685 } 2702 }
2686 } 2703 }
2687 if (!best_fit->IsNull()) { 2704 if (!best_fit->IsNull()) {
2688 // The inner most closure found will be the best fit. Going 2705 // The inner most closure found will be the best fit. Going
2689 // over class functions below will not help in any further 2706 // over class functions below will not help in any further
2690 // narrowing. 2707 // narrowing.
2691 return true; 2708 return true;
2692 } 2709 }
(...skipping 16 matching lines...) Expand all
2709 // EnsureIsFinalized only returns an error object if there 2726 // EnsureIsFinalized only returns an error object if there
2710 // is no longjump base on the stack. 2727 // is no longjump base on the stack.
2711 continue; 2728 continue;
2712 } 2729 }
2713 functions = cls.functions(); 2730 functions = cls.functions();
2714 if (!functions.IsNull()) { 2731 if (!functions.IsNull()) {
2715 const intptr_t num_functions = functions.Length(); 2732 const intptr_t num_functions = functions.Length();
2716 for (intptr_t pos = 0; pos < num_functions; pos++) { 2733 for (intptr_t pos = 0; pos < num_functions; pos++) {
2717 function ^= functions.At(pos); 2734 function ^= functions.At(pos);
2718 ASSERT(!function.IsNull()); 2735 ASSERT(!function.IsNull());
2719 if (IsTokenPosWithinFunction(function, token_pos)) { 2736 if (IsImplicitFunction(function)) {
2737 // Implicit functions do not have a user specifiable source
2738 // location.
2739 continue;
2740 }
2741 if (FunctionOverlaps(function, script, token_pos, last_token_pos)) {
2720 // Closures and inner functions within a class method are not 2742 // Closures and inner functions within a class method are not
2721 // present in the functions of a class. Hence, we can return 2743 // present in the functions of a class. Hence, we can return
2722 // right away as looking through other functions of a class 2744 // right away as looking through other functions of a class
2723 // will not narrow down to any inner function/closure. 2745 // will not narrow down to any inner function/closure.
2724 *best_fit = function.raw(); 2746 *best_fit = function.raw();
2725 return true; 2747 return true;
2726 } 2748 }
2727 } 2749 }
2728 } 2750 }
2729 // If none of the functions in the class contain token_pos, then we 2751 // 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
4037 // we'll resolve the breakpoint when the inner function is compiled. 4059 // we'll resolve the breakpoint when the inner function is compiled.
4038 return; 4060 return;
4039 } 4061 }
4040 // Iterate over all source breakpoints to check whether breakpoints 4062 // Iterate over all source breakpoints to check whether breakpoints
4041 // need to be set in the newly compiled function. 4063 // need to be set in the newly compiled function.
4042 Zone* zone = Thread::Current()->zone(); 4064 Zone* zone = Thread::Current()->zone();
4043 Script& script = Script::Handle(zone); 4065 Script& script = Script::Handle(zone);
4044 for (BreakpointLocation* loc = breakpoint_locations_; loc != NULL; 4066 for (BreakpointLocation* loc = breakpoint_locations_; loc != NULL;
4045 loc = loc->next()) { 4067 loc = loc->next()) {
4046 script = loc->script(); 4068 script = loc->script();
4047 if (FunctionContains(func, script, loc->token_pos())) { 4069 if (FunctionOverlaps(func, script, loc->token_pos(),
4070 loc->end_token_pos())) {
4048 Function& inner_function = Function::Handle(zone); 4071 Function& inner_function = Function::Handle(zone);
4049 inner_function = FindInnermostClosure(func, loc->token_pos()); 4072 inner_function = FindInnermostClosure(func, loc->token_pos());
4050 if (!inner_function.IsNull()) { 4073 if (!inner_function.IsNull()) {
4051 // The local function of a function we just compiled cannot 4074 // The local function of a function we just compiled cannot
4052 // be compiled already. 4075 // be compiled already.
4053 ASSERT(!inner_function.HasCode()); 4076 ASSERT(!inner_function.HasCode());
4054 if (FLAG_verbose_debug) { 4077 if (FLAG_verbose_debug) {
4055 OS::Print("Pending BP remains unresolved in inner function '%s'\n", 4078 OS::Print("Pending BP remains unresolved in inner function '%s'\n",
4056 inner_function.ToFullyQualifiedCString()); 4079 inner_function.ToFullyQualifiedCString());
4057 } 4080 }
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after
4481 4504
4482 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { 4505 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) {
4483 ASSERT(bpt->next() == NULL); 4506 ASSERT(bpt->next() == NULL);
4484 bpt->set_next(code_breakpoints_); 4507 bpt->set_next(code_breakpoints_);
4485 code_breakpoints_ = bpt; 4508 code_breakpoints_ = bpt;
4486 } 4509 }
4487 4510
4488 #endif // !PRODUCT 4511 #endif // !PRODUCT
4489 4512
4490 } // namespace dart 4513 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/observatory/tests/service/service.status ('k') | runtime/vm/debugger_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698