| 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/visitor.h" | 19 #include "vm/visitor.h" |
| 20 | 20 |
| 21 | 21 |
| 22 namespace dart { | 22 namespace dart { |
| 23 | 23 |
| 24 static const bool verbose = false; | 24 static const bool verbose = false; |
| 25 | 25 |
| 26 class RemoteObjectCache : public ZoneAllocated { |
| 27 public: |
| 28 explicit RemoteObjectCache(intptr_t initial_size); |
| 29 intptr_t AddObject(const Object& obj); |
| 30 RawObject* GetObj(intptr_t obj_id) const; |
| 31 bool IsValidId(intptr_t obj_id) const { |
| 32 return obj_id < objs_->Length(); |
| 33 } |
| 34 |
| 35 private: |
| 36 GrowableObjectArray* objs_; |
| 37 |
| 38 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); |
| 39 }; |
| 40 |
| 26 | 41 |
| 27 SourceBreakpoint::SourceBreakpoint(intptr_t id, | 42 SourceBreakpoint::SourceBreakpoint(intptr_t id, |
| 28 const Function& func, | 43 const Function& func, |
| 29 intptr_t token_index) | 44 intptr_t token_index) |
| 30 : id_(id), | 45 : id_(id), |
| 31 function_(func.raw()), | 46 function_(func.raw()), |
| 32 token_index_(token_index), | 47 token_index_(token_index), |
| 33 line_number_(-1), | 48 line_number_(-1), |
| 34 is_enabled_(false), | 49 is_enabled_(false), |
| 35 next_(NULL) { | 50 next_(NULL) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 104 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 90 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 105 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
| 91 } | 106 } |
| 92 | 107 |
| 93 | 108 |
| 94 ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp) | 109 ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp) |
| 95 : pc_(pc), fp_(fp), sp_(sp), | 110 : pc_(pc), fp_(fp), sp_(sp), |
| 96 function_(Function::ZoneHandle()), | 111 function_(Function::ZoneHandle()), |
| 97 token_index_(-1), | 112 token_index_(-1), |
| 98 line_number_(-1), | 113 line_number_(-1), |
| 99 var_descriptors_(NULL), | 114 var_descriptors_(LocalVarDescriptors::ZoneHandle()), |
| 100 desc_indices_(8) { | 115 desc_indices_(8) { |
| 101 } | 116 } |
| 102 | 117 |
| 103 | 118 |
| 104 const Function& ActivationFrame::DartFunction() { | 119 const Function& ActivationFrame::DartFunction() { |
| 105 if (function_.IsNull()) { | 120 if (function_.IsNull()) { |
| 106 Isolate* isolate = Isolate::Current(); | 121 Isolate* isolate = Isolate::Current(); |
| 107 ASSERT(isolate != NULL); | 122 ASSERT(isolate != NULL); |
| 108 const Code& code = Code::Handle(Code::LookupCode(pc_)); | 123 const Code& code = Code::Handle(Code::LookupCode(pc_)); |
| 109 function_ = code.function(); | 124 function_ = code.function(); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 if (line_number_ < 0) { | 191 if (line_number_ < 0) { |
| 177 const Script& script = Script::Handle(SourceScript()); | 192 const Script& script = Script::Handle(SourceScript()); |
| 178 intptr_t ignore_column; | 193 intptr_t ignore_column; |
| 179 script.GetTokenLocation(TokenIndex(), &line_number_, &ignore_column); | 194 script.GetTokenLocation(TokenIndex(), &line_number_, &ignore_column); |
| 180 } | 195 } |
| 181 return line_number_; | 196 return line_number_; |
| 182 } | 197 } |
| 183 | 198 |
| 184 | 199 |
| 185 void ActivationFrame::GetDescIndices() { | 200 void ActivationFrame::GetDescIndices() { |
| 186 if (var_descriptors_ == NULL) { | 201 if (var_descriptors_.IsNull()) { |
| 187 ASSERT(!DartFunction().HasOptimizedCode()); | 202 ASSERT(!DartFunction().HasOptimizedCode()); |
| 188 const Code& code = Code::Handle(DartFunction().unoptimized_code()); | 203 const Code& code = Code::Handle(DartFunction().unoptimized_code()); |
| 189 var_descriptors_ = | 204 var_descriptors_ = code.var_descriptors(); |
| 190 &LocalVarDescriptors::ZoneHandle(code.var_descriptors()); | |
| 191 // TODO(Hausner): Consider replacing this GrowableArray. | 205 // TODO(Hausner): Consider replacing this GrowableArray. |
| 192 GrowableArray<String*> var_names(8); | 206 GrowableArray<String*> var_names(8); |
| 193 intptr_t activation_token_pos = TokenIndex(); | 207 intptr_t activation_token_pos = TokenIndex(); |
| 194 intptr_t var_desc_len = var_descriptors_->Length(); | 208 intptr_t var_desc_len = var_descriptors_.Length(); |
| 195 for (int cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { | 209 for (int cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { |
| 196 ASSERT(var_names.length() == desc_indices_.length()); | 210 ASSERT(var_names.length() == desc_indices_.length()); |
| 197 intptr_t scope_id, begin_pos, end_pos; | 211 intptr_t scope_id, begin_pos, end_pos; |
| 198 var_descriptors_->GetScopeInfo(cur_idx, &scope_id, &begin_pos, &end_pos); | 212 var_descriptors_.GetScopeInfo(cur_idx, &scope_id, &begin_pos, &end_pos); |
| 199 if ((begin_pos <= activation_token_pos) && | 213 if ((begin_pos <= activation_token_pos) && |
| 200 (activation_token_pos <= end_pos)) { | 214 (activation_token_pos <= end_pos)) { |
| 201 // The current variable is textually in scope. Now check whether | 215 // The current variable is textually in scope. Now check whether |
| 202 // there is another local variable with the same name that shadows | 216 // there is another local variable with the same name that shadows |
| 203 // or is shadowed by this variable. | 217 // or is shadowed by this variable. |
| 204 String& var_name = String::Handle(var_descriptors_->GetName(cur_idx)); | 218 String& var_name = String::Handle(var_descriptors_.GetName(cur_idx)); |
| 205 intptr_t indices_len = desc_indices_.length(); | 219 intptr_t indices_len = desc_indices_.length(); |
| 206 bool name_match_found = false; | 220 bool name_match_found = false; |
| 207 for (int i = 0; i < indices_len; i++) { | 221 for (int i = 0; i < indices_len; i++) { |
| 208 if (var_name.Equals(*var_names[i])) { | 222 if (var_name.Equals(*var_names[i])) { |
| 209 // Found two local variables with the same name. Now determine | 223 // Found two local variables with the same name. Now determine |
| 210 // which one is shadowed. | 224 // which one is shadowed. |
| 211 name_match_found = true; | 225 name_match_found = true; |
| 212 intptr_t i_begin_pos, ignore; | 226 intptr_t i_begin_pos, ignore; |
| 213 var_descriptors_->GetScopeInfo( | 227 var_descriptors_.GetScopeInfo( |
| 214 desc_indices_[i], &ignore, &i_begin_pos, &ignore); | 228 desc_indices_[i], &ignore, &i_begin_pos, &ignore); |
| 215 if (i_begin_pos < begin_pos) { | 229 if (i_begin_pos < begin_pos) { |
| 216 // The variable we found earlier is in an outer scope | 230 // The variable we found earlier is in an outer scope |
| 217 // and is shadowed by the current variable. Replace the | 231 // and is shadowed by the current variable. Replace the |
| 218 // descriptor index of the previously found variable | 232 // descriptor index of the previously found variable |
| 219 // with the descriptor index of the current variable. | 233 // with the descriptor index of the current variable. |
| 220 desc_indices_[i] = cur_idx; | 234 desc_indices_[i] = cur_idx; |
| 221 } else { | 235 } else { |
| 222 // The variable we found earlier is in an inner scope | 236 // The variable we found earlier is in an inner scope |
| 223 // and shadows the current variable. Skip the current | 237 // and shadows the current variable. Skip the current |
| (...skipping 22 matching lines...) Expand all Loading... |
| 246 | 260 |
| 247 void ActivationFrame::VariableAt(intptr_t i, | 261 void ActivationFrame::VariableAt(intptr_t i, |
| 248 String* name, | 262 String* name, |
| 249 intptr_t* token_pos, | 263 intptr_t* token_pos, |
| 250 intptr_t* end_pos, | 264 intptr_t* end_pos, |
| 251 Instance* value) { | 265 Instance* value) { |
| 252 GetDescIndices(); | 266 GetDescIndices(); |
| 253 ASSERT(i < desc_indices_.length()); | 267 ASSERT(i < desc_indices_.length()); |
| 254 ASSERT(name != NULL); | 268 ASSERT(name != NULL); |
| 255 intptr_t desc_index = desc_indices_[i]; | 269 intptr_t desc_index = desc_indices_[i]; |
| 256 *name ^= var_descriptors_->GetName(desc_index); | 270 *name ^= var_descriptors_.GetName(desc_index); |
| 257 intptr_t scope_id; | 271 intptr_t scope_id; |
| 258 var_descriptors_->GetScopeInfo(desc_index, &scope_id, token_pos, end_pos); | 272 var_descriptors_.GetScopeInfo(desc_index, &scope_id, token_pos, end_pos); |
| 259 ASSERT(value != NULL); | 273 ASSERT(value != NULL); |
| 260 *value = GetLocalVarValue(var_descriptors_->GetSlotIndex(desc_index)); | 274 *value = GetLocalVarValue(var_descriptors_.GetSlotIndex(desc_index)); |
| 261 } | 275 } |
| 262 | 276 |
| 263 | 277 |
| 264 RawArray* ActivationFrame::GetLocalVariables() { | 278 RawArray* ActivationFrame::GetLocalVariables() { |
| 265 GetDescIndices(); | 279 GetDescIndices(); |
| 266 intptr_t num_variables = desc_indices_.length(); | 280 intptr_t num_variables = desc_indices_.length(); |
| 267 String& var_name = String::Handle(); | 281 String& var_name = String::Handle(); |
| 268 Instance& value = Instance::Handle(); | 282 Instance& value = Instance::Handle(); |
| 269 const Array& list = Array::Handle(Array::New(2 * num_variables)); | 283 const Array& list = Array::Handle(Array::New(2 * num_variables)); |
| 270 for (int i = 0; i < num_variables; i++) { | 284 for (int i = 0; i < num_variables; i++) { |
| 271 var_name = var_descriptors_->GetName(i); | 285 var_name = var_descriptors_.GetName(i); |
| 272 list.SetAt(2 * i, var_name); | 286 list.SetAt(2 * i, var_name); |
| 273 value = GetLocalVarValue(var_descriptors_->GetSlotIndex(i)); | 287 value = GetLocalVarValue(var_descriptors_.GetSlotIndex(i)); |
| 274 list.SetAt((2 * i) + 1, value); | 288 list.SetAt((2 * i) + 1, value); |
| 275 } | 289 } |
| 276 return list.raw(); | 290 return list.raw(); |
| 277 } | 291 } |
| 278 | 292 |
| 279 | 293 |
| 280 const char* ActivationFrame::ToCString() { | 294 const char* ActivationFrame::ToCString() { |
| 281 const char* kFormat = "Function: '%s' url: '%s' line: %d"; | 295 const char* kFormat = "Function: '%s' url: '%s' line: %d"; |
| 282 | 296 |
| 283 const Function& func = DartFunction(); | 297 const Function& func = DartFunction(); |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 | 433 |
| 420 | 434 |
| 421 void CodeBreakpoint::Disable() { | 435 void CodeBreakpoint::Disable() { |
| 422 if (is_enabled_) { | 436 if (is_enabled_) { |
| 423 RestoreCode(); | 437 RestoreCode(); |
| 424 } | 438 } |
| 425 ASSERT(!is_enabled_); | 439 ASSERT(!is_enabled_); |
| 426 } | 440 } |
| 427 | 441 |
| 428 | 442 |
| 443 RemoteObjectCache::RemoteObjectCache(intptr_t initial_size) { |
| 444 objs_ = &GrowableObjectArray::ZoneHandle( |
| 445 GrowableObjectArray::New(initial_size)); |
| 446 } |
| 447 |
| 448 |
| 449 intptr_t RemoteObjectCache::AddObject(const Object& obj) { |
| 450 intptr_t len = objs_->Length(); |
| 451 for (int i = 0; i < len; i++) { |
| 452 if (objs_->At(i) == obj.raw()) { |
| 453 return i; |
| 454 } |
| 455 } |
| 456 objs_->Add(obj); |
| 457 return len; |
| 458 } |
| 459 |
| 460 |
| 461 RawObject* RemoteObjectCache::GetObj(intptr_t obj_id) const { |
| 462 ASSERT(IsValidId(obj_id)); |
| 463 return objs_->At(obj_id); |
| 464 } |
| 465 |
| 466 |
| 429 Debugger::Debugger() | 467 Debugger::Debugger() |
| 430 : isolate_(NULL), | 468 : isolate_(NULL), |
| 431 initialized_(false), | 469 initialized_(false), |
| 432 bp_handler_(NULL), | 470 bp_handler_(NULL), |
| 433 event_handler_(NULL), | 471 event_handler_(NULL), |
| 434 next_id_(1), | 472 next_id_(1), |
| 435 stack_trace_(NULL), | 473 stack_trace_(NULL), |
| 474 obj_cache_(NULL), |
| 436 src_breakpoints_(NULL), | 475 src_breakpoints_(NULL), |
| 437 code_breakpoints_(NULL), | 476 code_breakpoints_(NULL), |
| 438 resume_action_(kContinue), | 477 resume_action_(kContinue), |
| 439 ignore_breakpoints_(false) { | 478 ignore_breakpoints_(false) { |
| 440 } | 479 } |
| 441 | 480 |
| 442 | 481 |
| 443 Debugger::~Debugger() { | 482 Debugger::~Debugger() { |
| 444 ASSERT(src_breakpoints_ == NULL); | 483 ASSERT(src_breakpoints_ == NULL); |
| 445 ASSERT(code_breakpoints_ == NULL); | 484 ASSERT(code_breakpoints_ == NULL); |
| 446 ASSERT(stack_trace_ == NULL); | 485 ASSERT(stack_trace_ == NULL); |
| 486 ASSERT(obj_cache_ == NULL); |
| 447 } | 487 } |
| 448 | 488 |
| 449 | 489 |
| 450 void Debugger::Shutdown() { | 490 void Debugger::Shutdown() { |
| 451 while (src_breakpoints_ != NULL) { | 491 while (src_breakpoints_ != NULL) { |
| 452 SourceBreakpoint* bpt = src_breakpoints_; | 492 SourceBreakpoint* bpt = src_breakpoints_; |
| 453 src_breakpoints_ = src_breakpoints_->next(); | 493 src_breakpoints_ = src_breakpoints_->next(); |
| 454 delete bpt; | 494 delete bpt; |
| 455 } | 495 } |
| 456 while (code_breakpoints_ != NULL) { | 496 while (code_breakpoints_ != NULL) { |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 715 if (verbose) { | 755 if (verbose) { |
| 716 OS::Print("No executable code at line %d in '%s'\n", | 756 OS::Print("No executable code at line %d in '%s'\n", |
| 717 line_number, script_url.ToCString()); | 757 line_number, script_url.ToCString()); |
| 718 } | 758 } |
| 719 return NULL; | 759 return NULL; |
| 720 } | 760 } |
| 721 return SetBreakpoint(func, token_index_at_line); | 761 return SetBreakpoint(func, token_index_at_line); |
| 722 } | 762 } |
| 723 | 763 |
| 724 | 764 |
| 765 intptr_t Debugger::CacheObject(const Object& obj) { |
| 766 ASSERT(obj_cache_ != NULL); |
| 767 return obj_cache_->AddObject(obj); |
| 768 } |
| 769 |
| 770 |
| 771 bool Debugger::IsValidObjectId(intptr_t obj_id) { |
| 772 ASSERT(obj_cache_ != NULL); |
| 773 return obj_cache_->IsValidId(obj_id); |
| 774 } |
| 775 |
| 776 |
| 777 RawObject* Debugger::GetCachedObject(intptr_t obj_id) { |
| 778 ASSERT(obj_cache_ != NULL); |
| 779 return obj_cache_->GetObj(obj_id); |
| 780 } |
| 781 |
| 725 // TODO(hausner): Merge some of this functionality with the code in | 782 // TODO(hausner): Merge some of this functionality with the code in |
| 726 // dart_api_impl.cc. | 783 // dart_api_impl.cc. |
| 727 RawObject* Debugger::GetInstanceField(const Class& cls, | 784 RawObject* Debugger::GetInstanceField(const Class& cls, |
| 728 const String& field_name, | 785 const String& field_name, |
| 729 const Instance& object) { | 786 const Instance& object) { |
| 730 const Function& getter_func = | 787 const Function& getter_func = |
| 731 Function::Handle(cls.LookupGetterFunction(field_name)); | 788 Function::Handle(cls.LookupGetterFunction(field_name)); |
| 732 ASSERT(!getter_func.IsNull()); | 789 ASSERT(!getter_func.IsNull()); |
| 733 | 790 |
| 734 Object& result = Object::Handle(); | 791 Object& result = Object::Handle(); |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 909 ActivationFrame* activation = | 966 ActivationFrame* activation = |
| 910 new ActivationFrame(frame->pc(), frame->fp(), frame->sp()); | 967 new ActivationFrame(frame->pc(), frame->fp(), frame->sp()); |
| 911 stack_trace->AddActivation(activation); | 968 stack_trace->AddActivation(activation); |
| 912 frame = iterator.NextFrame(); | 969 frame = iterator.NextFrame(); |
| 913 } | 970 } |
| 914 | 971 |
| 915 resume_action_ = kContinue; | 972 resume_action_ = kContinue; |
| 916 if (bp_handler_ != NULL) { | 973 if (bp_handler_ != NULL) { |
| 917 SourceBreakpoint* src_bpt = bpt->src_bpt(); | 974 SourceBreakpoint* src_bpt = bpt->src_bpt(); |
| 918 ASSERT(stack_trace_ == NULL); | 975 ASSERT(stack_trace_ == NULL); |
| 976 ASSERT(obj_cache_ == NULL); |
| 977 obj_cache_ = new RemoteObjectCache(64); |
| 919 stack_trace_ = stack_trace; | 978 stack_trace_ = stack_trace; |
| 920 (*bp_handler_)(src_bpt, stack_trace); | 979 (*bp_handler_)(src_bpt, stack_trace); |
| 921 stack_trace_ = NULL; | 980 stack_trace_ = NULL; |
| 981 obj_cache_ = NULL; // Remote object cache is zone allocated. |
| 922 } | 982 } |
| 923 | 983 |
| 924 if (resume_action_ == kContinue) { | 984 if (resume_action_ == kContinue) { |
| 925 RemoveInternalBreakpoints(); | 985 RemoveInternalBreakpoints(); |
| 926 } else if (resume_action_ == kStepOver) { | 986 } else if (resume_action_ == kStepOver) { |
| 927 Function& func = Function::Handle(bpt->function()); | 987 Function& func = Function::Handle(bpt->function()); |
| 928 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) { | 988 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) { |
| 929 // If we are at the function return, do a StepOut action. | 989 // If we are at the function return, do a StepOut action. |
| 930 if (stack_trace->Length() > 1) { | 990 if (stack_trace->Length() > 1) { |
| 931 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); | 991 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1136 } | 1196 } |
| 1137 | 1197 |
| 1138 | 1198 |
| 1139 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 1199 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 1140 ASSERT(bpt->next() == NULL); | 1200 ASSERT(bpt->next() == NULL); |
| 1141 bpt->set_next(code_breakpoints_); | 1201 bpt->set_next(code_breakpoints_); |
| 1142 code_breakpoints_ = bpt; | 1202 code_breakpoints_ = bpt; |
| 1143 } | 1203 } |
| 1144 | 1204 |
| 1145 } // namespace dart | 1205 } // namespace dart |
| OLD | NEW |