| 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 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |