| 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 "vm/code_generator.h" | 7 #include "vm/code_generator.h" |
| 8 #include "vm/code_patcher.h" | 8 #include "vm/code_patcher.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| 11 #include "vm/flags.h" | 11 #include "vm/flags.h" |
| 12 #include "vm/globals.h" | 12 #include "vm/globals.h" |
| 13 #include "vm/longjump.h" | 13 #include "vm/longjump.h" |
| 14 #include "vm/object.h" | 14 #include "vm/object.h" |
| 15 #include "vm/object_store.h" | 15 #include "vm/object_store.h" |
| 16 #include "vm/os.h" | 16 #include "vm/os.h" |
| 17 #include "vm/stack_frame.h" | 17 #include "vm/stack_frame.h" |
| 18 #include "vm/stub_code.h" | 18 #include "vm/stub_code.h" |
| 19 #include "vm/symbols.h" | 19 #include "vm/symbols.h" |
| 20 #include "vm/visitor.h" | 20 #include "vm/visitor.h" |
| 21 | 21 |
| 22 | 22 |
| 23 namespace dart { | 23 namespace dart { |
| 24 | 24 |
| 25 static const bool verbose = false; | 25 DEFINE_FLAG(bool, verbose_debug, false, "Verbose debugger messages"); |
| 26 | 26 |
| 27 class RemoteObjectCache : public ZoneAllocated { | 27 class RemoteObjectCache : public ZoneAllocated { |
| 28 public: | 28 public: |
| 29 explicit RemoteObjectCache(intptr_t initial_size); | 29 explicit RemoteObjectCache(intptr_t initial_size); |
| 30 intptr_t AddObject(const Object& obj); | 30 intptr_t AddObject(const Object& obj); |
| 31 RawObject* GetObj(intptr_t obj_id) const; | 31 RawObject* GetObj(intptr_t obj_id) const; |
| 32 bool IsValidId(intptr_t obj_id) const { | 32 bool IsValidId(intptr_t obj_id) const { |
| 33 return obj_id < objs_->Length(); | 33 return obj_id < objs_->Length(); |
| 34 } | 34 } |
| 35 | 35 |
| (...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 678 } | 678 } |
| 679 return function.raw(); | 679 return function.raw(); |
| 680 } | 680 } |
| 681 | 681 |
| 682 | 682 |
| 683 // Deoptimize function if necessary. Does not patch return addresses on the | 683 // Deoptimize function if necessary. Does not patch return addresses on the |
| 684 // stack. If there are activation frames of this function on the stack, | 684 // stack. If there are activation frames of this function on the stack, |
| 685 // the optimized code will be executed when the callee returns. | 685 // the optimized code will be executed when the callee returns. |
| 686 void Debugger::EnsureFunctionIsDeoptimized(const Function& func) { | 686 void Debugger::EnsureFunctionIsDeoptimized(const Function& func) { |
| 687 if (func.HasOptimizedCode()) { | 687 if (func.HasOptimizedCode()) { |
| 688 if (verbose) { | 688 if (FLAG_verbose_debug) { |
| 689 OS::Print("Deoptimizing function %s\n", | 689 OS::Print("Deoptimizing function %s\n", |
| 690 String::Handle(func.name()).ToCString()); | 690 String::Handle(func.name()).ToCString()); |
| 691 } | 691 } |
| 692 func.set_usage_counter(0); | 692 func.set_usage_counter(0); |
| 693 func.set_deoptimization_counter(func.deoptimization_counter() + 1); | 693 func.set_deoptimization_counter(func.deoptimization_counter() + 1); |
| 694 Compiler::CompileFunction(func); | 694 Compiler::CompileFunction(func); |
| 695 ASSERT(!func.HasOptimizedCode()); | 695 ASSERT(!func.HasOptimizedCode()); |
| 696 } | 696 } |
| 697 } | 697 } |
| 698 | 698 |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 863 best_fit_index = lowest_pc_index; | 863 best_fit_index = lowest_pc_index; |
| 864 } | 864 } |
| 865 if (best_fit_index >= 0) { | 865 if (best_fit_index >= 0) { |
| 866 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(best_fit_index)); | 866 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(best_fit_index)); |
| 867 // We should only ever have one code breakpoint at the same address. | 867 // We should only ever have one code breakpoint at the same address. |
| 868 if (bpt != NULL) { | 868 if (bpt != NULL) { |
| 869 return bpt; | 869 return bpt; |
| 870 } | 870 } |
| 871 | 871 |
| 872 bpt = new CodeBreakpoint(func, best_fit_index); | 872 bpt = new CodeBreakpoint(func, best_fit_index); |
| 873 if (verbose) { | 873 if (FLAG_verbose_debug) { |
| 874 OS::Print("Setting breakpoint in function '%s' (%s:%d) (PC %p)\n", | 874 OS::Print("Setting breakpoint in function '%s' (%s:%d) (PC %p)\n", |
| 875 String::Handle(func.name()).ToCString(), | 875 String::Handle(func.name()).ToCString(), |
| 876 String::Handle(bpt->SourceUrl()).ToCString(), | 876 String::Handle(bpt->SourceUrl()).ToCString(), |
| 877 bpt->LineNumber(), | 877 bpt->LineNumber(), |
| 878 bpt->pc()); | 878 bpt->pc()); |
| 879 } | 879 } |
| 880 RegisterCodeBreakpoint(bpt); | 880 RegisterCodeBreakpoint(bpt); |
| 881 return bpt; | 881 return bpt; |
| 882 } | 882 } |
| 883 return NULL; | 883 return NULL; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 914 } else { | 914 } else { |
| 915 bpt = GetSourceBreakpoint(target_function, first_token_pos); | 915 bpt = GetSourceBreakpoint(target_function, first_token_pos); |
| 916 if (bpt != NULL) { | 916 if (bpt != NULL) { |
| 917 // A source breakpoint for this uncompiled location already | 917 // A source breakpoint for this uncompiled location already |
| 918 // exists. | 918 // exists. |
| 919 return bpt; | 919 return bpt; |
| 920 } | 920 } |
| 921 } | 921 } |
| 922 bpt = new SourceBreakpoint(nextId(), target_function, first_token_pos); | 922 bpt = new SourceBreakpoint(nextId(), target_function, first_token_pos); |
| 923 RegisterSourceBreakpoint(bpt); | 923 RegisterSourceBreakpoint(bpt); |
| 924 if (verbose && !target_function.HasCode()) { | 924 if (FLAG_verbose_debug && !target_function.HasCode()) { |
| 925 OS::Print("Registering breakpoint for " | 925 OS::Print("Registering breakpoint for " |
| 926 "uncompiled function '%s' at line %d\n", | 926 "uncompiled function '%s' at line %d\n", |
| 927 target_function.ToFullyQualifiedCString(), | 927 target_function.ToFullyQualifiedCString(), |
| 928 bpt->LineNumber()); | 928 bpt->LineNumber()); |
| 929 } | 929 } |
| 930 | 930 |
| 931 if (cbpt != NULL) { | 931 if (cbpt != NULL) { |
| 932 ASSERT(cbpt->src_bpt() == NULL); | 932 ASSERT(cbpt->src_bpt() == NULL); |
| 933 cbpt->set_src_bpt(bpt); | 933 cbpt->set_src_bpt(bpt); |
| 934 SignalBpResolved(bpt); | 934 SignalBpResolved(bpt); |
| 935 } else { | 935 } else { |
| 936 if (verbose) { | 936 if (FLAG_verbose_debug) { |
| 937 OS::Print("Failed to set breakpoint at '%s' line %d\n", | 937 OS::Print("Failed to set breakpoint at '%s' line %d\n", |
| 938 String::Handle(bpt->SourceUrl()).ToCString(), | 938 String::Handle(bpt->SourceUrl()).ToCString(), |
| 939 bpt->LineNumber()); | 939 bpt->LineNumber()); |
| 940 } | 940 } |
| 941 } | 941 } |
| 942 bpt->Enable(); | 942 bpt->Enable(); |
| 943 return bpt; | 943 return bpt; |
| 944 } | 944 } |
| 945 | 945 |
| 946 | 946 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 977 const GrowableObjectArray& libs = | 977 const GrowableObjectArray& libs = |
| 978 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); | 978 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
| 979 for (int i = 0; i < libs.Length(); i++) { | 979 for (int i = 0; i < libs.Length(); i++) { |
| 980 lib ^= libs.At(i); | 980 lib ^= libs.At(i); |
| 981 script = lib.LookupScript(script_url); | 981 script = lib.LookupScript(script_url); |
| 982 if (!script.IsNull()) { | 982 if (!script.IsNull()) { |
| 983 break; | 983 break; |
| 984 } | 984 } |
| 985 } | 985 } |
| 986 if (script.IsNull()) { | 986 if (script.IsNull()) { |
| 987 if (verbose) { | 987 if (FLAG_verbose_debug) { |
| 988 OS::Print("Failed to find script with url '%s'\n", | 988 OS::Print("Failed to find script with url '%s'\n", |
| 989 script_url.ToCString()); | 989 script_url.ToCString()); |
| 990 } | 990 } |
| 991 return NULL; | 991 return NULL; |
| 992 } | 992 } |
| 993 intptr_t first_token_idx, last_token_idx; | 993 intptr_t first_token_idx, last_token_idx; |
| 994 script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx); | 994 script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx); |
| 995 if (first_token_idx < 0) { | 995 if (first_token_idx < 0) { |
| 996 // Script does not contain the given line number. | 996 // Script does not contain the given line number. |
| 997 if (verbose) { | 997 if (FLAG_verbose_debug) { |
| 998 OS::Print("Script '%s' does not contain line number %d\n", | 998 OS::Print("Script '%s' does not contain line number %d\n", |
| 999 script_url.ToCString(), line_number); | 999 script_url.ToCString(), line_number); |
| 1000 } | 1000 } |
| 1001 return NULL; | 1001 return NULL; |
| 1002 } | 1002 } |
| 1003 const Function& func = | 1003 const Function& func = |
| 1004 Function::Handle(lib.LookupFunctionInScript(script, first_token_idx)); | 1004 Function::Handle(lib.LookupFunctionInScript(script, first_token_idx)); |
| 1005 if (func.IsNull()) { | 1005 if (func.IsNull()) { |
| 1006 if (verbose) { | 1006 if (FLAG_verbose_debug) { |
| 1007 OS::Print("No executable code at line %d in '%s'\n", | 1007 OS::Print("No executable code at line %d in '%s'\n", |
| 1008 line_number, script_url.ToCString()); | 1008 line_number, script_url.ToCString()); |
| 1009 } | 1009 } |
| 1010 return NULL; | 1010 return NULL; |
| 1011 } | 1011 } |
| 1012 if (last_token_idx < 0) { | 1012 if (last_token_idx < 0) { |
| 1013 // The token at first_token_index is past the requested source line. | 1013 // The token at first_token_index is past the requested source line. |
| 1014 // Set the breakpoint at the closest position after that line. | 1014 // Set the breakpoint at the closest position after that line. |
| 1015 last_token_idx = func.end_token_pos(); | 1015 last_token_idx = func.end_token_pos(); |
| 1016 } | 1016 } |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1281 void Debugger::SignalBpReached() { | 1281 void Debugger::SignalBpReached() { |
| 1282 if (ignore_breakpoints_) { | 1282 if (ignore_breakpoints_) { |
| 1283 return; | 1283 return; |
| 1284 } | 1284 } |
| 1285 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 1285 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 1286 ASSERT(stack_trace->Length() > 0); | 1286 ASSERT(stack_trace->Length() > 0); |
| 1287 ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0); | 1287 ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0); |
| 1288 ASSERT(top_frame != NULL); | 1288 ASSERT(top_frame != NULL); |
| 1289 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); | 1289 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); |
| 1290 ASSERT(bpt != NULL); | 1290 ASSERT(bpt != NULL); |
| 1291 if (verbose) { | 1291 if (FLAG_verbose_debug) { |
| 1292 OS::Print(">>> hit %s breakpoint at %s:%d (Address %p)\n", | 1292 OS::Print(">>> hit %s breakpoint at %s:%d (Address %p)\n", |
| 1293 bpt->IsInternal() ? "internal" : "user", | 1293 bpt->IsInternal() ? "internal" : "user", |
| 1294 String::Handle(bpt->SourceUrl()).ToCString(), | 1294 String::Handle(bpt->SourceUrl()).ToCString(), |
| 1295 bpt->LineNumber(), | 1295 bpt->LineNumber(), |
| 1296 top_frame->pc()); | 1296 top_frame->pc()); |
| 1297 } | 1297 } |
| 1298 | 1298 |
| 1299 if (!bpt->IsInternal()) { | 1299 if (!bpt->IsInternal()) { |
| 1300 // This is a user-defined breakpoint so we call the breakpoint | 1300 // This is a user-defined breakpoint so we call the breakpoint |
| 1301 // callback even if it is on the same line as the previous breakpoint. | 1301 // callback even if it is on the same line as the previous breakpoint. |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1420 } | 1420 } |
| 1421 SourceBreakpoint* bpt = src_breakpoints_; | 1421 SourceBreakpoint* bpt = src_breakpoints_; |
| 1422 while (bpt != NULL) { | 1422 while (bpt != NULL) { |
| 1423 if (lookup_function.raw() == bpt->function()) { | 1423 if (lookup_function.raw() == bpt->function()) { |
| 1424 // Check if the breakpoint is inside a closure or local function | 1424 // Check if the breakpoint is inside a closure or local function |
| 1425 // within the newly compiled function. | 1425 // within the newly compiled function. |
| 1426 Class& owner = Class::Handle(lookup_function.Owner()); | 1426 Class& owner = Class::Handle(lookup_function.Owner()); |
| 1427 Function& closure = | 1427 Function& closure = |
| 1428 Function::Handle(owner.LookupClosureFunction(bpt->token_pos())); | 1428 Function::Handle(owner.LookupClosureFunction(bpt->token_pos())); |
| 1429 if (!closure.IsNull() && (closure.raw() != lookup_function.raw())) { | 1429 if (!closure.IsNull() && (closure.raw() != lookup_function.raw())) { |
| 1430 if (verbose) { | 1430 if (FLAG_verbose_debug) { |
| 1431 OS::Print("Resetting pending breakpoint to function %s\n", | 1431 OS::Print("Resetting pending breakpoint to function %s\n", |
| 1432 closure.ToFullyQualifiedCString()); | 1432 closure.ToFullyQualifiedCString()); |
| 1433 } | 1433 } |
| 1434 bpt->set_function(closure); | 1434 bpt->set_function(closure); |
| 1435 } else { | 1435 } else { |
| 1436 if (verbose) { | 1436 if (FLAG_verbose_debug) { |
| 1437 OS::Print("Enable pending breakpoint for function '%s'\n", | 1437 OS::Print("Enable pending breakpoint for function '%s'\n", |
| 1438 String::Handle(lookup_function.name()).ToCString()); | 1438 String::Handle(lookup_function.name()).ToCString()); |
| 1439 } | 1439 } |
| 1440 // Set breakpoint in newly compiled code of function func. | 1440 // Set breakpoint in newly compiled code of function func. |
| 1441 CodeBreakpoint* cbpt = | 1441 CodeBreakpoint* cbpt = |
| 1442 MakeCodeBreakpoint(func, bpt->token_pos(), func.end_token_pos()); | 1442 MakeCodeBreakpoint(func, bpt->token_pos(), func.end_token_pos()); |
| 1443 if (cbpt != NULL) { | 1443 if (cbpt != NULL) { |
| 1444 cbpt->set_src_bpt(bpt); | 1444 cbpt->set_src_bpt(bpt); |
| 1445 SignalBpResolved(bpt); | 1445 SignalBpResolved(bpt); |
| 1446 } | 1446 } |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1565 } | 1565 } |
| 1566 | 1566 |
| 1567 | 1567 |
| 1568 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 1568 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 1569 ASSERT(bpt->next() == NULL); | 1569 ASSERT(bpt->next() == NULL); |
| 1570 bpt->set_next(code_breakpoints_); | 1570 bpt->set_next(code_breakpoints_); |
| 1571 code_breakpoints_ = bpt; | 1571 code_breakpoints_ = bpt; |
| 1572 } | 1572 } |
| 1573 | 1573 |
| 1574 } // namespace dart | 1574 } // namespace dart |
| OLD | NEW |