| 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 18 matching lines...) Expand all Loading... |
| 29 #include "vm/service_isolate.h" | 29 #include "vm/service_isolate.h" |
| 30 #include "vm/stack_frame.h" | 30 #include "vm/stack_frame.h" |
| 31 #include "vm/stack_trace.h" | 31 #include "vm/stack_trace.h" |
| 32 #include "vm/stub_code.h" | 32 #include "vm/stub_code.h" |
| 33 #include "vm/symbols.h" | 33 #include "vm/symbols.h" |
| 34 #include "vm/thread_interrupter.h" | 34 #include "vm/thread_interrupter.h" |
| 35 #include "vm/timeline.h" | 35 #include "vm/timeline.h" |
| 36 #include "vm/token_position.h" | 36 #include "vm/token_position.h" |
| 37 #include "vm/visitor.h" | 37 #include "vm/visitor.h" |
| 38 | 38 |
| 39 | |
| 40 namespace dart { | 39 namespace dart { |
| 41 | 40 |
| 42 DEFINE_FLAG(bool, | 41 DEFINE_FLAG(bool, |
| 43 show_invisible_frames, | 42 show_invisible_frames, |
| 44 false, | 43 false, |
| 45 "Show invisible frames in debugger stack traces"); | 44 "Show invisible frames in debugger stack traces"); |
| 46 DEFINE_FLAG(bool, | 45 DEFINE_FLAG(bool, |
| 47 trace_debugger_stacktrace, | 46 trace_debugger_stacktrace, |
| 48 false, | 47 false, |
| 49 "Trace debugger stacktrace collection"); | 48 "Trace debugger stacktrace collection"); |
| 50 DEFINE_FLAG(bool, trace_rewind, false, "Trace frame rewind"); | 49 DEFINE_FLAG(bool, trace_rewind, false, "Trace frame rewind"); |
| 51 DEFINE_FLAG(bool, verbose_debug, false, "Verbose debugger messages"); | 50 DEFINE_FLAG(bool, verbose_debug, false, "Verbose debugger messages"); |
| 52 DEFINE_FLAG(bool, | 51 DEFINE_FLAG(bool, |
| 53 steal_breakpoints, | 52 steal_breakpoints, |
| 54 false, | 53 false, |
| 55 "Intercept breakpoints and other pause events before they " | 54 "Intercept breakpoints and other pause events before they " |
| 56 "are sent to the embedder and use a generic VM breakpoint " | 55 "are sent to the embedder and use a generic VM breakpoint " |
| 57 "handler instead. This handler dispatches breakpoints to " | 56 "handler instead. This handler dispatches breakpoints to " |
| 58 "the VM service."); | 57 "the VM service."); |
| 59 | 58 |
| 60 DECLARE_FLAG(bool, warn_on_pause_with_no_debugger); | 59 DECLARE_FLAG(bool, warn_on_pause_with_no_debugger); |
| 61 | 60 |
| 62 | |
| 63 #ifndef PRODUCT | 61 #ifndef PRODUCT |
| 64 | 62 |
| 65 Debugger::EventHandler* Debugger::event_handler_ = NULL; | 63 Debugger::EventHandler* Debugger::event_handler_ = NULL; |
| 66 | 64 |
| 67 | |
| 68 class RemoteObjectCache : public ZoneAllocated { | 65 class RemoteObjectCache : public ZoneAllocated { |
| 69 public: | 66 public: |
| 70 explicit RemoteObjectCache(intptr_t initial_size); | 67 explicit RemoteObjectCache(intptr_t initial_size); |
| 71 intptr_t AddObject(const Object& obj); | 68 intptr_t AddObject(const Object& obj); |
| 72 RawObject* GetObj(intptr_t obj_id) const; | 69 RawObject* GetObj(intptr_t obj_id) const; |
| 73 bool IsValidId(intptr_t obj_id) const { return obj_id < objs_->Length(); } | 70 bool IsValidId(intptr_t obj_id) const { return obj_id < objs_->Length(); } |
| 74 | 71 |
| 75 private: | 72 private: |
| 76 GrowableObjectArray* objs_; | 73 GrowableObjectArray* objs_; |
| 77 | 74 |
| 78 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); | 75 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); |
| 79 }; | 76 }; |
| 80 | 77 |
| 81 | |
| 82 // Create an unresolved breakpoint in given token range and script. | 78 // Create an unresolved breakpoint in given token range and script. |
| 83 BreakpointLocation::BreakpointLocation(const Script& script, | 79 BreakpointLocation::BreakpointLocation(const Script& script, |
| 84 TokenPosition token_pos, | 80 TokenPosition token_pos, |
| 85 TokenPosition end_token_pos, | 81 TokenPosition end_token_pos, |
| 86 intptr_t requested_line_number, | 82 intptr_t requested_line_number, |
| 87 intptr_t requested_column_number) | 83 intptr_t requested_column_number) |
| 88 : script_(script.raw()), | 84 : script_(script.raw()), |
| 89 url_(script.url()), | 85 url_(script.url()), |
| 90 token_pos_(token_pos), | 86 token_pos_(token_pos), |
| 91 end_token_pos_(end_token_pos), | 87 end_token_pos_(end_token_pos), |
| (...skipping 21 matching lines...) Expand all Loading... |
| 113 next_(NULL), | 109 next_(NULL), |
| 114 conditions_(NULL), | 110 conditions_(NULL), |
| 115 requested_line_number_(requested_line_number), | 111 requested_line_number_(requested_line_number), |
| 116 requested_column_number_(requested_column_number), | 112 requested_column_number_(requested_column_number), |
| 117 function_(Function::null()), | 113 function_(Function::null()), |
| 118 line_number_(-1), | 114 line_number_(-1), |
| 119 column_number_(-1) { | 115 column_number_(-1) { |
| 120 ASSERT(requested_line_number_ >= 0); | 116 ASSERT(requested_line_number_ >= 0); |
| 121 } | 117 } |
| 122 | 118 |
| 123 | |
| 124 BreakpointLocation::~BreakpointLocation() { | 119 BreakpointLocation::~BreakpointLocation() { |
| 125 Breakpoint* bpt = breakpoints(); | 120 Breakpoint* bpt = breakpoints(); |
| 126 while (bpt != NULL) { | 121 while (bpt != NULL) { |
| 127 Breakpoint* temp = bpt; | 122 Breakpoint* temp = bpt; |
| 128 bpt = bpt->next(); | 123 bpt = bpt->next(); |
| 129 delete temp; | 124 delete temp; |
| 130 } | 125 } |
| 131 } | 126 } |
| 132 | 127 |
| 133 | |
| 134 bool BreakpointLocation::AnyEnabled() const { | 128 bool BreakpointLocation::AnyEnabled() const { |
| 135 return breakpoints() != NULL; | 129 return breakpoints() != NULL; |
| 136 } | 130 } |
| 137 | 131 |
| 138 | |
| 139 void BreakpointLocation::SetResolved(const Function& func, | 132 void BreakpointLocation::SetResolved(const Function& func, |
| 140 TokenPosition token_pos) { | 133 TokenPosition token_pos) { |
| 141 ASSERT(!IsLatent()); | 134 ASSERT(!IsLatent()); |
| 142 ASSERT(func.script() == script_); | 135 ASSERT(func.script() == script_); |
| 143 ASSERT((func.token_pos() <= token_pos) && | 136 ASSERT((func.token_pos() <= token_pos) && |
| 144 (token_pos <= func.end_token_pos())); | 137 (token_pos <= func.end_token_pos())); |
| 145 ASSERT(func.is_debuggable()); | 138 ASSERT(func.is_debuggable()); |
| 146 function_ = func.raw(); | 139 function_ = func.raw(); |
| 147 token_pos_ = token_pos; | 140 token_pos_ = token_pos; |
| 148 end_token_pos_ = token_pos; | 141 end_token_pos_ = token_pos; |
| 149 is_resolved_ = true; | 142 is_resolved_ = true; |
| 150 } | 143 } |
| 151 | 144 |
| 152 | |
| 153 // TODO(hausner): Get rid of library parameter. A source breakpoint location | 145 // TODO(hausner): Get rid of library parameter. A source breakpoint location |
| 154 // does not imply a library, since the same source code can be included | 146 // does not imply a library, since the same source code can be included |
| 155 // in more than one library, e.g. the text location of mixin functions. | 147 // in more than one library, e.g. the text location of mixin functions. |
| 156 void BreakpointLocation::GetCodeLocation(Library* lib, | 148 void BreakpointLocation::GetCodeLocation(Library* lib, |
| 157 Script* script, | 149 Script* script, |
| 158 TokenPosition* pos) const { | 150 TokenPosition* pos) const { |
| 159 if (IsLatent()) { | 151 if (IsLatent()) { |
| 160 *lib = Library::null(); | 152 *lib = Library::null(); |
| 161 *script = Script::null(); | 153 *script = Script::null(); |
| 162 *pos = TokenPosition::kNoSource; | 154 *pos = TokenPosition::kNoSource; |
| 163 } else { | 155 } else { |
| 164 *script = this->script(); | 156 *script = this->script(); |
| 165 *pos = token_pos_; | 157 *pos = token_pos_; |
| 166 if (IsResolved()) { | 158 if (IsResolved()) { |
| 167 const Function& func = Function::Handle(function_); | 159 const Function& func = Function::Handle(function_); |
| 168 ASSERT(!func.IsNull()); | 160 ASSERT(!func.IsNull()); |
| 169 const Class& cls = Class::Handle(func.origin()); | 161 const Class& cls = Class::Handle(func.origin()); |
| 170 *lib = cls.library(); | 162 *lib = cls.library(); |
| 171 } else { | 163 } else { |
| 172 *lib = Library::null(); | 164 *lib = Library::null(); |
| 173 } | 165 } |
| 174 } | 166 } |
| 175 } | 167 } |
| 176 | 168 |
| 177 | |
| 178 intptr_t BreakpointLocation::LineNumber() { | 169 intptr_t BreakpointLocation::LineNumber() { |
| 179 ASSERT(IsResolved()); | 170 ASSERT(IsResolved()); |
| 180 // Compute line number lazily since it causes scanning of the script. | 171 // Compute line number lazily since it causes scanning of the script. |
| 181 if (line_number_ < 0) { | 172 if (line_number_ < 0) { |
| 182 const Script& script = Script::Handle(this->script()); | 173 const Script& script = Script::Handle(this->script()); |
| 183 script.GetTokenLocation(token_pos_, &line_number_, NULL); | 174 script.GetTokenLocation(token_pos_, &line_number_, NULL); |
| 184 } | 175 } |
| 185 return line_number_; | 176 return line_number_; |
| 186 } | 177 } |
| 187 | 178 |
| 188 | |
| 189 intptr_t BreakpointLocation::ColumnNumber() { | 179 intptr_t BreakpointLocation::ColumnNumber() { |
| 190 ASSERT(IsResolved()); | 180 ASSERT(IsResolved()); |
| 191 // Compute column number lazily since it causes scanning of the script. | 181 // Compute column number lazily since it causes scanning of the script. |
| 192 if (column_number_ < 0) { | 182 if (column_number_ < 0) { |
| 193 const Script& script = Script::Handle(this->script()); | 183 const Script& script = Script::Handle(this->script()); |
| 194 script.GetTokenLocation(token_pos_, &line_number_, &column_number_); | 184 script.GetTokenLocation(token_pos_, &line_number_, &column_number_); |
| 195 } | 185 } |
| 196 return column_number_; | 186 return column_number_; |
| 197 } | 187 } |
| 198 | 188 |
| 199 | |
| 200 void Breakpoint::set_bpt_location(BreakpointLocation* new_bpt_location) { | 189 void Breakpoint::set_bpt_location(BreakpointLocation* new_bpt_location) { |
| 201 // Only latent breakpoints can be moved. | 190 // Only latent breakpoints can be moved. |
| 202 ASSERT((new_bpt_location == NULL) || bpt_location_->IsLatent()); | 191 ASSERT((new_bpt_location == NULL) || bpt_location_->IsLatent()); |
| 203 bpt_location_ = new_bpt_location; | 192 bpt_location_ = new_bpt_location; |
| 204 } | 193 } |
| 205 | 194 |
| 206 | |
| 207 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 195 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 208 visitor->VisitPointer(reinterpret_cast<RawObject**>(&closure_)); | 196 visitor->VisitPointer(reinterpret_cast<RawObject**>(&closure_)); |
| 209 } | 197 } |
| 210 | 198 |
| 211 | |
| 212 void BreakpointLocation::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 199 void BreakpointLocation::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 213 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); | 200 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); |
| 214 visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_)); | 201 visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_)); |
| 215 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 202 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
| 216 | 203 |
| 217 Breakpoint* bpt = conditions_; | 204 Breakpoint* bpt = conditions_; |
| 218 while (bpt != NULL) { | 205 while (bpt != NULL) { |
| 219 bpt->VisitObjectPointers(visitor); | 206 bpt->VisitObjectPointers(visitor); |
| 220 bpt = bpt->next(); | 207 bpt = bpt->next(); |
| 221 } | 208 } |
| 222 } | 209 } |
| 223 | 210 |
| 224 | |
| 225 void Breakpoint::PrintJSON(JSONStream* stream) { | 211 void Breakpoint::PrintJSON(JSONStream* stream) { |
| 226 JSONObject jsobj(stream); | 212 JSONObject jsobj(stream); |
| 227 jsobj.AddProperty("type", "Breakpoint"); | 213 jsobj.AddProperty("type", "Breakpoint"); |
| 228 | 214 |
| 229 jsobj.AddFixedServiceId("breakpoints/%" Pd "", id()); | 215 jsobj.AddFixedServiceId("breakpoints/%" Pd "", id()); |
| 230 jsobj.AddProperty("breakpointNumber", id()); | 216 jsobj.AddProperty("breakpointNumber", id()); |
| 231 if (is_synthetic_async()) { | 217 if (is_synthetic_async()) { |
| 232 jsobj.AddProperty("isSyntheticAsyncContinuation", is_synthetic_async()); | 218 jsobj.AddProperty("isSyntheticAsyncContinuation", is_synthetic_async()); |
| 233 } | 219 } |
| 234 jsobj.AddProperty("resolved", bpt_location_->IsResolved()); | 220 jsobj.AddProperty("resolved", bpt_location_->IsResolved()); |
| 235 if (bpt_location_->IsResolved()) { | 221 if (bpt_location_->IsResolved()) { |
| 236 jsobj.AddLocation(bpt_location_); | 222 jsobj.AddLocation(bpt_location_); |
| 237 } else { | 223 } else { |
| 238 jsobj.AddUnresolvedLocation(bpt_location_); | 224 jsobj.AddUnresolvedLocation(bpt_location_); |
| 239 } | 225 } |
| 240 } | 226 } |
| 241 | 227 |
| 242 | |
| 243 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 228 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 244 visitor->VisitPointer(reinterpret_cast<RawObject**>(&code_)); | 229 visitor->VisitPointer(reinterpret_cast<RawObject**>(&code_)); |
| 245 #if !defined(TARGET_ARCH_DBC) | 230 #if !defined(TARGET_ARCH_DBC) |
| 246 visitor->VisitPointer(reinterpret_cast<RawObject**>(&saved_value_)); | 231 visitor->VisitPointer(reinterpret_cast<RawObject**>(&saved_value_)); |
| 247 #endif | 232 #endif |
| 248 } | 233 } |
| 249 | 234 |
| 250 | |
| 251 ActivationFrame::ActivationFrame(uword pc, | 235 ActivationFrame::ActivationFrame(uword pc, |
| 252 uword fp, | 236 uword fp, |
| 253 uword sp, | 237 uword sp, |
| 254 const Code& code, | 238 const Code& code, |
| 255 const Array& deopt_frame, | 239 const Array& deopt_frame, |
| 256 intptr_t deopt_frame_offset, | 240 intptr_t deopt_frame_offset, |
| 257 ActivationFrame::Kind kind) | 241 ActivationFrame::Kind kind) |
| 258 : pc_(pc), | 242 : pc_(pc), |
| 259 fp_(fp), | 243 fp_(fp), |
| 260 sp_(sp), | 244 sp_(sp), |
| 261 ctx_(Context::ZoneHandle()), | 245 ctx_(Context::ZoneHandle()), |
| 262 code_(Code::ZoneHandle(code.raw())), | 246 code_(Code::ZoneHandle(code.raw())), |
| 263 function_(Function::ZoneHandle(code.function())), | 247 function_(Function::ZoneHandle(code.function())), |
| 264 live_frame_((kind == kRegular) || (kind == kAsyncActivation)), | 248 live_frame_((kind == kRegular) || (kind == kAsyncActivation)), |
| 265 token_pos_initialized_(false), | 249 token_pos_initialized_(false), |
| 266 token_pos_(TokenPosition::kNoSource), | 250 token_pos_(TokenPosition::kNoSource), |
| 267 try_index_(-1), | 251 try_index_(-1), |
| 268 deopt_id_(Thread::kNoDeoptId), | 252 deopt_id_(Thread::kNoDeoptId), |
| 269 line_number_(-1), | 253 line_number_(-1), |
| 270 column_number_(-1), | 254 column_number_(-1), |
| 271 context_level_(-1), | 255 context_level_(-1), |
| 272 deopt_frame_(Array::ZoneHandle(deopt_frame.raw())), | 256 deopt_frame_(Array::ZoneHandle(deopt_frame.raw())), |
| 273 deopt_frame_offset_(deopt_frame_offset), | 257 deopt_frame_offset_(deopt_frame_offset), |
| 274 kind_(kind), | 258 kind_(kind), |
| 275 vars_initialized_(false), | 259 vars_initialized_(false), |
| 276 var_descriptors_(LocalVarDescriptors::ZoneHandle()), | 260 var_descriptors_(LocalVarDescriptors::ZoneHandle()), |
| 277 desc_indices_(8), | 261 desc_indices_(8), |
| 278 pc_desc_(PcDescriptors::ZoneHandle()) {} | 262 pc_desc_(PcDescriptors::ZoneHandle()) {} |
| 279 | 263 |
| 280 | |
| 281 ActivationFrame::ActivationFrame(Kind kind) | 264 ActivationFrame::ActivationFrame(Kind kind) |
| 282 : pc_(0), | 265 : pc_(0), |
| 283 fp_(0), | 266 fp_(0), |
| 284 sp_(0), | 267 sp_(0), |
| 285 ctx_(Context::ZoneHandle()), | 268 ctx_(Context::ZoneHandle()), |
| 286 code_(Code::ZoneHandle()), | 269 code_(Code::ZoneHandle()), |
| 287 function_(Function::ZoneHandle()), | 270 function_(Function::ZoneHandle()), |
| 288 live_frame_(kind == kRegular), | 271 live_frame_(kind == kRegular), |
| 289 token_pos_initialized_(false), | 272 token_pos_initialized_(false), |
| 290 token_pos_(TokenPosition::kNoSource), | 273 token_pos_(TokenPosition::kNoSource), |
| 291 try_index_(-1), | 274 try_index_(-1), |
| 292 line_number_(-1), | 275 line_number_(-1), |
| 293 column_number_(-1), | 276 column_number_(-1), |
| 294 context_level_(-1), | 277 context_level_(-1), |
| 295 deopt_frame_(Array::ZoneHandle()), | 278 deopt_frame_(Array::ZoneHandle()), |
| 296 deopt_frame_offset_(0), | 279 deopt_frame_offset_(0), |
| 297 kind_(kind), | 280 kind_(kind), |
| 298 vars_initialized_(false), | 281 vars_initialized_(false), |
| 299 var_descriptors_(LocalVarDescriptors::ZoneHandle()), | 282 var_descriptors_(LocalVarDescriptors::ZoneHandle()), |
| 300 desc_indices_(8), | 283 desc_indices_(8), |
| 301 pc_desc_(PcDescriptors::ZoneHandle()) {} | 284 pc_desc_(PcDescriptors::ZoneHandle()) {} |
| 302 | 285 |
| 303 | |
| 304 ActivationFrame::ActivationFrame(const Closure& async_activation) | 286 ActivationFrame::ActivationFrame(const Closure& async_activation) |
| 305 : pc_(0), | 287 : pc_(0), |
| 306 fp_(0), | 288 fp_(0), |
| 307 sp_(0), | 289 sp_(0), |
| 308 ctx_(Context::ZoneHandle()), | 290 ctx_(Context::ZoneHandle()), |
| 309 code_(Code::ZoneHandle()), | 291 code_(Code::ZoneHandle()), |
| 310 function_(Function::ZoneHandle()), | 292 function_(Function::ZoneHandle()), |
| 311 live_frame_(false), | 293 live_frame_(false), |
| 312 token_pos_initialized_(false), | 294 token_pos_initialized_(false), |
| 313 token_pos_(TokenPosition::kNoSource), | 295 token_pos_(TokenPosition::kNoSource), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 324 pc_desc_(PcDescriptors::ZoneHandle()) { | 306 pc_desc_(PcDescriptors::ZoneHandle()) { |
| 325 // Extract the function and the code from the asynchronous activation. | 307 // Extract the function and the code from the asynchronous activation. |
| 326 function_ = async_activation.function(); | 308 function_ = async_activation.function(); |
| 327 function_.EnsureHasCompiledUnoptimizedCode(); | 309 function_.EnsureHasCompiledUnoptimizedCode(); |
| 328 code_ = function_.unoptimized_code(); | 310 code_ = function_.unoptimized_code(); |
| 329 ctx_ = async_activation.context(); | 311 ctx_ = async_activation.context(); |
| 330 ASSERT(fp_ == 0); | 312 ASSERT(fp_ == 0); |
| 331 ASSERT(!ctx_.IsNull()); | 313 ASSERT(!ctx_.IsNull()); |
| 332 } | 314 } |
| 333 | 315 |
| 334 | |
| 335 bool Debugger::NeedsIsolateEvents() { | 316 bool Debugger::NeedsIsolateEvents() { |
| 336 return ((isolate_ != Dart::vm_isolate()) && | 317 return ((isolate_ != Dart::vm_isolate()) && |
| 337 !ServiceIsolate::IsServiceIsolateDescendant(isolate_) && | 318 !ServiceIsolate::IsServiceIsolateDescendant(isolate_) && |
| 338 ((event_handler_ != NULL) || Service::isolate_stream.enabled())); | 319 ((event_handler_ != NULL) || Service::isolate_stream.enabled())); |
| 339 } | 320 } |
| 340 | 321 |
| 341 | |
| 342 bool Debugger::NeedsDebugEvents() { | 322 bool Debugger::NeedsDebugEvents() { |
| 343 ASSERT(isolate_ != Dart::vm_isolate() && | 323 ASSERT(isolate_ != Dart::vm_isolate() && |
| 344 !ServiceIsolate::IsServiceIsolateDescendant(isolate_)); | 324 !ServiceIsolate::IsServiceIsolateDescendant(isolate_)); |
| 345 return (FLAG_warn_on_pause_with_no_debugger || (event_handler_ != NULL) || | 325 return (FLAG_warn_on_pause_with_no_debugger || (event_handler_ != NULL) || |
| 346 Service::debug_stream.enabled()); | 326 Service::debug_stream.enabled()); |
| 347 } | 327 } |
| 348 | 328 |
| 349 | |
| 350 void Debugger::InvokeEventHandler(ServiceEvent* event) { | 329 void Debugger::InvokeEventHandler(ServiceEvent* event) { |
| 351 ASSERT(!event->IsPause()); // For pause events, call Pause instead. | 330 ASSERT(!event->IsPause()); // For pause events, call Pause instead. |
| 352 Service::HandleEvent(event); | 331 Service::HandleEvent(event); |
| 353 | 332 |
| 354 // Call the embedder's event handler, if it exists. | 333 // Call the embedder's event handler, if it exists. |
| 355 if (event_handler_ != NULL) { | 334 if (event_handler_ != NULL) { |
| 356 TransitionVMToNative transition(Thread::Current()); | 335 TransitionVMToNative transition(Thread::Current()); |
| 357 (*event_handler_)(event); | 336 (*event_handler_)(event); |
| 358 } | 337 } |
| 359 } | 338 } |
| 360 | 339 |
| 361 | |
| 362 RawError* Debugger::PauseInterrupted() { | 340 RawError* Debugger::PauseInterrupted() { |
| 363 return PauseRequest(ServiceEvent::kPauseInterrupted); | 341 return PauseRequest(ServiceEvent::kPauseInterrupted); |
| 364 } | 342 } |
| 365 | 343 |
| 366 | |
| 367 RawError* Debugger::PausePostRequest() { | 344 RawError* Debugger::PausePostRequest() { |
| 368 return PauseRequest(ServiceEvent::kPausePostRequest); | 345 return PauseRequest(ServiceEvent::kPausePostRequest); |
| 369 } | 346 } |
| 370 | 347 |
| 371 | |
| 372 RawError* Debugger::PauseRequest(ServiceEvent::EventKind kind) { | 348 RawError* Debugger::PauseRequest(ServiceEvent::EventKind kind) { |
| 373 if (ignore_breakpoints_ || IsPaused()) { | 349 if (ignore_breakpoints_ || IsPaused()) { |
| 374 // We don't let the isolate get interrupted if we are already | 350 // We don't let the isolate get interrupted if we are already |
| 375 // paused or ignoring breakpoints. | 351 // paused or ignoring breakpoints. |
| 376 return Error::null(); | 352 return Error::null(); |
| 377 } | 353 } |
| 378 ServiceEvent event(isolate_, kind); | 354 ServiceEvent event(isolate_, kind); |
| 379 DebuggerStackTrace* trace = CollectStackTrace(); | 355 DebuggerStackTrace* trace = CollectStackTrace(); |
| 380 if (trace->Length() > 0) { | 356 if (trace->Length() > 0) { |
| 381 event.set_top_frame(trace->FrameAt(0)); | 357 event.set_top_frame(trace->FrameAt(0)); |
| 382 } | 358 } |
| 383 CacheStackTraces(trace, CollectAsyncCausalStackTrace(), | 359 CacheStackTraces(trace, CollectAsyncCausalStackTrace(), |
| 384 CollectAwaiterReturnStackTrace()); | 360 CollectAwaiterReturnStackTrace()); |
| 385 resume_action_ = kContinue; | 361 resume_action_ = kContinue; |
| 386 Pause(&event); | 362 Pause(&event); |
| 387 HandleSteppingRequest(trace); | 363 HandleSteppingRequest(trace); |
| 388 ClearCachedStackTraces(); | 364 ClearCachedStackTraces(); |
| 389 | 365 |
| 390 // If any error occurred while in the debug message loop, return it here. | 366 // If any error occurred while in the debug message loop, return it here. |
| 391 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 367 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
| 392 ASSERT(error.IsNull() || error.IsUnwindError()); | 368 ASSERT(error.IsNull() || error.IsUnwindError()); |
| 393 Thread::Current()->clear_sticky_error(); | 369 Thread::Current()->clear_sticky_error(); |
| 394 return error.raw(); | 370 return error.raw(); |
| 395 } | 371 } |
| 396 | 372 |
| 397 | |
| 398 void Debugger::SendBreakpointEvent(ServiceEvent::EventKind kind, | 373 void Debugger::SendBreakpointEvent(ServiceEvent::EventKind kind, |
| 399 Breakpoint* bpt) { | 374 Breakpoint* bpt) { |
| 400 if (NeedsDebugEvents()) { | 375 if (NeedsDebugEvents()) { |
| 401 // TODO(turnidge): Currently we send single-shot breakpoint events | 376 // TODO(turnidge): Currently we send single-shot breakpoint events |
| 402 // to the vm service. Do we want to change this? | 377 // to the vm service. Do we want to change this? |
| 403 ServiceEvent event(isolate_, kind); | 378 ServiceEvent event(isolate_, kind); |
| 404 event.set_breakpoint(bpt); | 379 event.set_breakpoint(bpt); |
| 405 InvokeEventHandler(&event); | 380 InvokeEventHandler(&event); |
| 406 } | 381 } |
| 407 } | 382 } |
| 408 | 383 |
| 409 | |
| 410 void BreakpointLocation::AddBreakpoint(Breakpoint* bpt, Debugger* dbg) { | 384 void BreakpointLocation::AddBreakpoint(Breakpoint* bpt, Debugger* dbg) { |
| 411 bpt->set_next(breakpoints()); | 385 bpt->set_next(breakpoints()); |
| 412 set_breakpoints(bpt); | 386 set_breakpoints(bpt); |
| 413 | 387 |
| 414 dbg->SyncBreakpointLocation(this); | 388 dbg->SyncBreakpointLocation(this); |
| 415 dbg->SendBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); | 389 dbg->SendBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); |
| 416 } | 390 } |
| 417 | 391 |
| 418 | |
| 419 Breakpoint* BreakpointLocation::AddRepeated(Debugger* dbg) { | 392 Breakpoint* BreakpointLocation::AddRepeated(Debugger* dbg) { |
| 420 Breakpoint* bpt = breakpoints(); | 393 Breakpoint* bpt = breakpoints(); |
| 421 while (bpt != NULL) { | 394 while (bpt != NULL) { |
| 422 if (bpt->IsRepeated()) break; | 395 if (bpt->IsRepeated()) break; |
| 423 bpt = bpt->next(); | 396 bpt = bpt->next(); |
| 424 } | 397 } |
| 425 if (bpt == NULL) { | 398 if (bpt == NULL) { |
| 426 bpt = new Breakpoint(dbg->nextId(), this); | 399 bpt = new Breakpoint(dbg->nextId(), this); |
| 427 bpt->SetIsRepeated(); | 400 bpt->SetIsRepeated(); |
| 428 AddBreakpoint(bpt, dbg); | 401 AddBreakpoint(bpt, dbg); |
| 429 } | 402 } |
| 430 return bpt; | 403 return bpt; |
| 431 } | 404 } |
| 432 | 405 |
| 433 | |
| 434 Breakpoint* BreakpointLocation::AddSingleShot(Debugger* dbg) { | 406 Breakpoint* BreakpointLocation::AddSingleShot(Debugger* dbg) { |
| 435 Breakpoint* bpt = breakpoints(); | 407 Breakpoint* bpt = breakpoints(); |
| 436 while (bpt != NULL) { | 408 while (bpt != NULL) { |
| 437 if (bpt->IsSingleShot()) break; | 409 if (bpt->IsSingleShot()) break; |
| 438 bpt = bpt->next(); | 410 bpt = bpt->next(); |
| 439 } | 411 } |
| 440 if (bpt == NULL) { | 412 if (bpt == NULL) { |
| 441 bpt = new Breakpoint(dbg->nextId(), this); | 413 bpt = new Breakpoint(dbg->nextId(), this); |
| 442 bpt->SetIsSingleShot(); | 414 bpt->SetIsSingleShot(); |
| 443 AddBreakpoint(bpt, dbg); | 415 AddBreakpoint(bpt, dbg); |
| 444 } | 416 } |
| 445 return bpt; | 417 return bpt; |
| 446 } | 418 } |
| 447 | 419 |
| 448 | |
| 449 Breakpoint* BreakpointLocation::AddPerClosure(Debugger* dbg, | 420 Breakpoint* BreakpointLocation::AddPerClosure(Debugger* dbg, |
| 450 const Instance& closure, | 421 const Instance& closure, |
| 451 bool for_over_await) { | 422 bool for_over_await) { |
| 452 Breakpoint* bpt = NULL; | 423 Breakpoint* bpt = NULL; |
| 453 // Do not reuse existing breakpoints for stepping over await clauses. | 424 // Do not reuse existing breakpoints for stepping over await clauses. |
| 454 // A second async step-over command will set a new breakpoint before | 425 // A second async step-over command will set a new breakpoint before |
| 455 // the existing one gets deleted when first async step-over resumes. | 426 // the existing one gets deleted when first async step-over resumes. |
| 456 if (!for_over_await) { | 427 if (!for_over_await) { |
| 457 bpt = breakpoints(); | 428 bpt = breakpoints(); |
| 458 while (bpt != NULL) { | 429 while (bpt != NULL) { |
| 459 if (bpt->IsPerClosure() && (bpt->closure() == closure.raw())) break; | 430 if (bpt->IsPerClosure() && (bpt->closure() == closure.raw())) break; |
| 460 bpt = bpt->next(); | 431 bpt = bpt->next(); |
| 461 } | 432 } |
| 462 } | 433 } |
| 463 if (bpt == NULL) { | 434 if (bpt == NULL) { |
| 464 bpt = new Breakpoint(dbg->nextId(), this); | 435 bpt = new Breakpoint(dbg->nextId(), this); |
| 465 bpt->SetIsPerClosure(closure); | 436 bpt->SetIsPerClosure(closure); |
| 466 bpt->set_is_synthetic_async(for_over_await); | 437 bpt->set_is_synthetic_async(for_over_await); |
| 467 AddBreakpoint(bpt, dbg); | 438 AddBreakpoint(bpt, dbg); |
| 468 } | 439 } |
| 469 return bpt; | 440 return bpt; |
| 470 } | 441 } |
| 471 | 442 |
| 472 | |
| 473 const char* Debugger::QualifiedFunctionName(const Function& func) { | 443 const char* Debugger::QualifiedFunctionName(const Function& func) { |
| 474 const String& func_name = String::Handle(func.name()); | 444 const String& func_name = String::Handle(func.name()); |
| 475 Class& func_class = Class::Handle(func.Owner()); | 445 Class& func_class = Class::Handle(func.Owner()); |
| 476 String& class_name = String::Handle(func_class.Name()); | 446 String& class_name = String::Handle(func_class.Name()); |
| 477 | 447 |
| 478 return OS::SCreate(Thread::Current()->zone(), "%s%s%s", | 448 return OS::SCreate(Thread::Current()->zone(), "%s%s%s", |
| 479 func_class.IsTopLevel() ? "" : class_name.ToCString(), | 449 func_class.IsTopLevel() ? "" : class_name.ToCString(), |
| 480 func_class.IsTopLevel() ? "" : ".", func_name.ToCString()); | 450 func_class.IsTopLevel() ? "" : ".", func_name.ToCString()); |
| 481 } | 451 } |
| 482 | 452 |
| 483 | |
| 484 // Returns true if the function |func| overlaps the token range | 453 // Returns true if the function |func| overlaps the token range |
| 485 // [|token_pos|, |end_token_pos|] in |script|. | 454 // [|token_pos|, |end_token_pos|] in |script|. |
| 486 static bool FunctionOverlaps(const Function& func, | 455 static bool FunctionOverlaps(const Function& func, |
| 487 const Script& script, | 456 const Script& script, |
| 488 TokenPosition token_pos, | 457 TokenPosition token_pos, |
| 489 TokenPosition end_token_pos) { | 458 TokenPosition end_token_pos) { |
| 490 TokenPosition func_start = func.token_pos(); | 459 TokenPosition func_start = func.token_pos(); |
| 491 if (((func_start <= token_pos) && (token_pos <= func.end_token_pos())) || | 460 if (((func_start <= token_pos) && (token_pos <= func.end_token_pos())) || |
| 492 ((token_pos <= func_start) && (func_start <= end_token_pos))) { | 461 ((token_pos <= func_start) && (func_start <= end_token_pos))) { |
| 493 // Check script equality second because it allocates | 462 // Check script equality second because it allocates |
| 494 // handles as a side effect. | 463 // handles as a side effect. |
| 495 return func.script() == script.raw(); | 464 return func.script() == script.raw(); |
| 496 } | 465 } |
| 497 return false; | 466 return false; |
| 498 } | 467 } |
| 499 | 468 |
| 500 | |
| 501 static bool IsImplicitFunction(const Function& func) { | 469 static bool IsImplicitFunction(const Function& func) { |
| 502 switch (func.kind()) { | 470 switch (func.kind()) { |
| 503 case RawFunction::kImplicitGetter: | 471 case RawFunction::kImplicitGetter: |
| 504 case RawFunction::kImplicitSetter: | 472 case RawFunction::kImplicitSetter: |
| 505 case RawFunction::kImplicitStaticFinalGetter: | 473 case RawFunction::kImplicitStaticFinalGetter: |
| 506 case RawFunction::kMethodExtractor: | 474 case RawFunction::kMethodExtractor: |
| 507 case RawFunction::kNoSuchMethodDispatcher: | 475 case RawFunction::kNoSuchMethodDispatcher: |
| 508 case RawFunction::kInvokeFieldDispatcher: | 476 case RawFunction::kInvokeFieldDispatcher: |
| 509 case RawFunction::kIrregexpFunction: | 477 case RawFunction::kIrregexpFunction: |
| 510 return true; | 478 return true; |
| 511 default: | 479 default: |
| 512 if (func.token_pos() == func.end_token_pos()) { | 480 if (func.token_pos() == func.end_token_pos()) { |
| 513 // |func| could be an implicit constructor for example. | 481 // |func| could be an implicit constructor for example. |
| 514 return true; | 482 return true; |
| 515 } | 483 } |
| 516 } | 484 } |
| 517 return false; | 485 return false; |
| 518 } | 486 } |
| 519 | 487 |
| 520 | |
| 521 bool Debugger::HasBreakpoint(const Function& func, Zone* zone) { | 488 bool Debugger::HasBreakpoint(const Function& func, Zone* zone) { |
| 522 if (!func.HasCode()) { | 489 if (!func.HasCode()) { |
| 523 // If the function is not compiled yet, just check whether there | 490 // If the function is not compiled yet, just check whether there |
| 524 // is a user-defined breakpoint that falls into the token | 491 // is a user-defined breakpoint that falls into the token |
| 525 // range of the function. This may be a false positive: the breakpoint | 492 // range of the function. This may be a false positive: the breakpoint |
| 526 // might be inside a local closure. | 493 // might be inside a local closure. |
| 527 Script& script = Script::Handle(zone); | 494 Script& script = Script::Handle(zone); |
| 528 BreakpointLocation* sbpt = breakpoint_locations_; | 495 BreakpointLocation* sbpt = breakpoint_locations_; |
| 529 while (sbpt != NULL) { | 496 while (sbpt != NULL) { |
| 530 script = sbpt->script(); | 497 script = sbpt->script(); |
| 531 if (FunctionOverlaps(func, script, sbpt->token_pos(), | 498 if (FunctionOverlaps(func, script, sbpt->token_pos(), |
| 532 sbpt->end_token_pos())) { | 499 sbpt->end_token_pos())) { |
| 533 return true; | 500 return true; |
| 534 } | 501 } |
| 535 sbpt = sbpt->next_; | 502 sbpt = sbpt->next_; |
| 536 } | 503 } |
| 537 return false; | 504 return false; |
| 538 } | 505 } |
| 539 CodeBreakpoint* cbpt = code_breakpoints_; | 506 CodeBreakpoint* cbpt = code_breakpoints_; |
| 540 while (cbpt != NULL) { | 507 while (cbpt != NULL) { |
| 541 if (func.raw() == cbpt->function()) { | 508 if (func.raw() == cbpt->function()) { |
| 542 return true; | 509 return true; |
| 543 } | 510 } |
| 544 cbpt = cbpt->next_; | 511 cbpt = cbpt->next_; |
| 545 } | 512 } |
| 546 return false; | 513 return false; |
| 547 } | 514 } |
| 548 | 515 |
| 549 | |
| 550 bool Debugger::HasBreakpoint(const Code& code) { | 516 bool Debugger::HasBreakpoint(const Code& code) { |
| 551 CodeBreakpoint* cbpt = code_breakpoints_; | 517 CodeBreakpoint* cbpt = code_breakpoints_; |
| 552 while (cbpt != NULL) { | 518 while (cbpt != NULL) { |
| 553 if (code.raw() == cbpt->code_) { | 519 if (code.raw() == cbpt->code_) { |
| 554 return true; | 520 return true; |
| 555 } | 521 } |
| 556 cbpt = cbpt->next_; | 522 cbpt = cbpt->next_; |
| 557 } | 523 } |
| 558 return false; | 524 return false; |
| 559 } | 525 } |
| 560 | 526 |
| 561 | |
| 562 void Debugger::PrintBreakpointsToJSONArray(JSONArray* jsarr) const { | 527 void Debugger::PrintBreakpointsToJSONArray(JSONArray* jsarr) const { |
| 563 PrintBreakpointsListToJSONArray(breakpoint_locations_, jsarr); | 528 PrintBreakpointsListToJSONArray(breakpoint_locations_, jsarr); |
| 564 PrintBreakpointsListToJSONArray(latent_locations_, jsarr); | 529 PrintBreakpointsListToJSONArray(latent_locations_, jsarr); |
| 565 } | 530 } |
| 566 | 531 |
| 567 | |
| 568 void Debugger::PrintBreakpointsListToJSONArray(BreakpointLocation* sbpt, | 532 void Debugger::PrintBreakpointsListToJSONArray(BreakpointLocation* sbpt, |
| 569 JSONArray* jsarr) const { | 533 JSONArray* jsarr) const { |
| 570 while (sbpt != NULL) { | 534 while (sbpt != NULL) { |
| 571 Breakpoint* bpt = sbpt->breakpoints(); | 535 Breakpoint* bpt = sbpt->breakpoints(); |
| 572 while (bpt != NULL) { | 536 while (bpt != NULL) { |
| 573 jsarr->AddValue(bpt); | 537 jsarr->AddValue(bpt); |
| 574 bpt = bpt->next(); | 538 bpt = bpt->next(); |
| 575 } | 539 } |
| 576 sbpt = sbpt->next_; | 540 sbpt = sbpt->next_; |
| 577 } | 541 } |
| 578 } | 542 } |
| 579 | 543 |
| 580 | |
| 581 void Debugger::PrintSettingsToJSONObject(JSONObject* jsobj) const { | 544 void Debugger::PrintSettingsToJSONObject(JSONObject* jsobj) const { |
| 582 // This won't cut it when we support filtering by class, etc. | 545 // This won't cut it when we support filtering by class, etc. |
| 583 switch (GetExceptionPauseInfo()) { | 546 switch (GetExceptionPauseInfo()) { |
| 584 case kNoPauseOnExceptions: | 547 case kNoPauseOnExceptions: |
| 585 jsobj->AddProperty("_exceptions", "none"); | 548 jsobj->AddProperty("_exceptions", "none"); |
| 586 break; | 549 break; |
| 587 case kPauseOnAllExceptions: | 550 case kPauseOnAllExceptions: |
| 588 jsobj->AddProperty("_exceptions", "all"); | 551 jsobj->AddProperty("_exceptions", "all"); |
| 589 break; | 552 break; |
| 590 case kPauseOnUnhandledExceptions: | 553 case kPauseOnUnhandledExceptions: |
| 591 jsobj->AddProperty("_exceptions", "unhandled"); | 554 jsobj->AddProperty("_exceptions", "unhandled"); |
| 592 break; | 555 break; |
| 593 default: | 556 default: |
| 594 UNREACHABLE(); | 557 UNREACHABLE(); |
| 595 } | 558 } |
| 596 } | 559 } |
| 597 | 560 |
| 598 | |
| 599 RawString* ActivationFrame::QualifiedFunctionName() { | 561 RawString* ActivationFrame::QualifiedFunctionName() { |
| 600 return String::New(Debugger::QualifiedFunctionName(function())); | 562 return String::New(Debugger::QualifiedFunctionName(function())); |
| 601 } | 563 } |
| 602 | 564 |
| 603 | |
| 604 RawString* ActivationFrame::SourceUrl() { | 565 RawString* ActivationFrame::SourceUrl() { |
| 605 const Script& script = Script::Handle(SourceScript()); | 566 const Script& script = Script::Handle(SourceScript()); |
| 606 return script.url(); | 567 return script.url(); |
| 607 } | 568 } |
| 608 | 569 |
| 609 | |
| 610 RawScript* ActivationFrame::SourceScript() { | 570 RawScript* ActivationFrame::SourceScript() { |
| 611 return function().script(); | 571 return function().script(); |
| 612 } | 572 } |
| 613 | 573 |
| 614 | |
| 615 RawLibrary* ActivationFrame::Library() { | 574 RawLibrary* ActivationFrame::Library() { |
| 616 const Class& cls = Class::Handle(function().origin()); | 575 const Class& cls = Class::Handle(function().origin()); |
| 617 return cls.library(); | 576 return cls.library(); |
| 618 } | 577 } |
| 619 | 578 |
| 620 | |
| 621 void ActivationFrame::GetPcDescriptors() { | 579 void ActivationFrame::GetPcDescriptors() { |
| 622 if (pc_desc_.IsNull()) { | 580 if (pc_desc_.IsNull()) { |
| 623 pc_desc_ = code().pc_descriptors(); | 581 pc_desc_ = code().pc_descriptors(); |
| 624 ASSERT(!pc_desc_.IsNull()); | 582 ASSERT(!pc_desc_.IsNull()); |
| 625 } | 583 } |
| 626 } | 584 } |
| 627 | 585 |
| 628 | |
| 629 // Compute token_pos_ and try_index_ and token_pos_initialized_. | 586 // Compute token_pos_ and try_index_ and token_pos_initialized_. |
| 630 TokenPosition ActivationFrame::TokenPos() { | 587 TokenPosition ActivationFrame::TokenPos() { |
| 631 if (!token_pos_initialized_) { | 588 if (!token_pos_initialized_) { |
| 632 token_pos_initialized_ = true; | 589 token_pos_initialized_ = true; |
| 633 token_pos_ = TokenPosition::kNoSource; | 590 token_pos_ = TokenPosition::kNoSource; |
| 634 GetPcDescriptors(); | 591 GetPcDescriptors(); |
| 635 PcDescriptors::Iterator iter(pc_desc_, RawPcDescriptors::kAnyKind); | 592 PcDescriptors::Iterator iter(pc_desc_, RawPcDescriptors::kAnyKind); |
| 636 uword pc_offset = pc_ - code().PayloadStart(); | 593 uword pc_offset = pc_ - code().PayloadStart(); |
| 637 while (iter.MoveNext()) { | 594 while (iter.MoveNext()) { |
| 638 if (iter.PcOffset() == pc_offset) { | 595 if (iter.PcOffset() == pc_offset) { |
| 639 try_index_ = iter.TryIndex(); | 596 try_index_ = iter.TryIndex(); |
| 640 token_pos_ = iter.TokenPos(); | 597 token_pos_ = iter.TokenPos(); |
| 641 deopt_id_ = iter.DeoptId(); | 598 deopt_id_ = iter.DeoptId(); |
| 642 break; | 599 break; |
| 643 } | 600 } |
| 644 } | 601 } |
| 645 } | 602 } |
| 646 return token_pos_; | 603 return token_pos_; |
| 647 } | 604 } |
| 648 | 605 |
| 649 | |
| 650 intptr_t ActivationFrame::TryIndex() { | 606 intptr_t ActivationFrame::TryIndex() { |
| 651 if (!token_pos_initialized_) { | 607 if (!token_pos_initialized_) { |
| 652 TokenPos(); // Side effect: computes token_pos_initialized_, try_index_. | 608 TokenPos(); // Side effect: computes token_pos_initialized_, try_index_. |
| 653 } | 609 } |
| 654 return try_index_; | 610 return try_index_; |
| 655 } | 611 } |
| 656 | 612 |
| 657 | |
| 658 intptr_t ActivationFrame::DeoptId() { | 613 intptr_t ActivationFrame::DeoptId() { |
| 659 if (!token_pos_initialized_) { | 614 if (!token_pos_initialized_) { |
| 660 TokenPos(); // Side effect: computes token_pos_initialized_, try_index_. | 615 TokenPos(); // Side effect: computes token_pos_initialized_, try_index_. |
| 661 } | 616 } |
| 662 return deopt_id_; | 617 return deopt_id_; |
| 663 } | 618 } |
| 664 | 619 |
| 665 | |
| 666 intptr_t ActivationFrame::LineNumber() { | 620 intptr_t ActivationFrame::LineNumber() { |
| 667 // Compute line number lazily since it causes scanning of the script. | 621 // Compute line number lazily since it causes scanning of the script. |
| 668 if ((line_number_ < 0) && TokenPos().IsSourcePosition()) { | 622 if ((line_number_ < 0) && TokenPos().IsSourcePosition()) { |
| 669 const TokenPosition token_pos = TokenPos().SourcePosition(); | 623 const TokenPosition token_pos = TokenPos().SourcePosition(); |
| 670 const Script& script = Script::Handle(SourceScript()); | 624 const Script& script = Script::Handle(SourceScript()); |
| 671 script.GetTokenLocation(token_pos, &line_number_, NULL); | 625 script.GetTokenLocation(token_pos, &line_number_, NULL); |
| 672 } | 626 } |
| 673 return line_number_; | 627 return line_number_; |
| 674 } | 628 } |
| 675 | 629 |
| 676 | |
| 677 intptr_t ActivationFrame::ColumnNumber() { | 630 intptr_t ActivationFrame::ColumnNumber() { |
| 678 // Compute column number lazily since it causes scanning of the script. | 631 // Compute column number lazily since it causes scanning of the script. |
| 679 if ((column_number_ < 0) && TokenPos().IsSourcePosition()) { | 632 if ((column_number_ < 0) && TokenPos().IsSourcePosition()) { |
| 680 const TokenPosition token_pos = TokenPos().SourcePosition(); | 633 const TokenPosition token_pos = TokenPos().SourcePosition(); |
| 681 const Script& script = Script::Handle(SourceScript()); | 634 const Script& script = Script::Handle(SourceScript()); |
| 682 if (script.HasSource()) { | 635 if (script.HasSource()) { |
| 683 script.GetTokenLocation(token_pos, &line_number_, &column_number_); | 636 script.GetTokenLocation(token_pos, &line_number_, &column_number_); |
| 684 } else { | 637 } else { |
| 685 column_number_ = -1; | 638 column_number_ = -1; |
| 686 } | 639 } |
| 687 } | 640 } |
| 688 return column_number_; | 641 return column_number_; |
| 689 } | 642 } |
| 690 | 643 |
| 691 | |
| 692 void ActivationFrame::GetVarDescriptors() { | 644 void ActivationFrame::GetVarDescriptors() { |
| 693 if (var_descriptors_.IsNull()) { | 645 if (var_descriptors_.IsNull()) { |
| 694 Code& unoptimized_code = Code::Handle(function().unoptimized_code()); | 646 Code& unoptimized_code = Code::Handle(function().unoptimized_code()); |
| 695 if (unoptimized_code.IsNull()) { | 647 if (unoptimized_code.IsNull()) { |
| 696 Thread* thread = Thread::Current(); | 648 Thread* thread = Thread::Current(); |
| 697 Zone* zone = thread->zone(); | 649 Zone* zone = thread->zone(); |
| 698 const Error& error = Error::Handle( | 650 const Error& error = Error::Handle( |
| 699 zone, Compiler::EnsureUnoptimizedCode(thread, function())); | 651 zone, Compiler::EnsureUnoptimizedCode(thread, function())); |
| 700 if (!error.IsNull()) { | 652 if (!error.IsNull()) { |
| 701 Exceptions::PropagateError(error); | 653 Exceptions::PropagateError(error); |
| 702 } | 654 } |
| 703 unoptimized_code ^= function().unoptimized_code(); | 655 unoptimized_code ^= function().unoptimized_code(); |
| 704 } | 656 } |
| 705 ASSERT(!unoptimized_code.IsNull()); | 657 ASSERT(!unoptimized_code.IsNull()); |
| 706 var_descriptors_ = unoptimized_code.GetLocalVarDescriptors(); | 658 var_descriptors_ = unoptimized_code.GetLocalVarDescriptors(); |
| 707 ASSERT(!var_descriptors_.IsNull()); | 659 ASSERT(!var_descriptors_.IsNull()); |
| 708 } | 660 } |
| 709 } | 661 } |
| 710 | 662 |
| 711 | |
| 712 bool ActivationFrame::IsDebuggable() const { | 663 bool ActivationFrame::IsDebuggable() const { |
| 713 return Debugger::IsDebuggable(function()); | 664 return Debugger::IsDebuggable(function()); |
| 714 } | 665 } |
| 715 | 666 |
| 716 | |
| 717 void ActivationFrame::PrintDescriptorsError(const char* message) { | 667 void ActivationFrame::PrintDescriptorsError(const char* message) { |
| 718 OS::PrintErr("Bad descriptors: %s\n", message); | 668 OS::PrintErr("Bad descriptors: %s\n", message); |
| 719 OS::PrintErr("function %s\n", function().ToQualifiedCString()); | 669 OS::PrintErr("function %s\n", function().ToQualifiedCString()); |
| 720 OS::PrintErr("pc_ %" Px "\n", pc_); | 670 OS::PrintErr("pc_ %" Px "\n", pc_); |
| 721 OS::PrintErr("deopt_id_ %" Px "\n", deopt_id_); | 671 OS::PrintErr("deopt_id_ %" Px "\n", deopt_id_); |
| 722 OS::PrintErr("context_level_ %" Px "\n", context_level_); | 672 OS::PrintErr("context_level_ %" Px "\n", context_level_); |
| 723 DisassembleToStdout formatter; | 673 DisassembleToStdout formatter; |
| 724 code().Disassemble(&formatter); | 674 code().Disassemble(&formatter); |
| 725 PcDescriptors::Handle(code().pc_descriptors()).Print(); | 675 PcDescriptors::Handle(code().pc_descriptors()).Print(); |
| 726 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames, | 676 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames, |
| 727 Thread::Current(), | 677 Thread::Current(), |
| 728 StackFrameIterator::kNoCrossThreadIteration); | 678 StackFrameIterator::kNoCrossThreadIteration); |
| 729 StackFrame* frame = frames.NextFrame(); | 679 StackFrame* frame = frames.NextFrame(); |
| 730 while (frame != NULL) { | 680 while (frame != NULL) { |
| 731 OS::PrintErr("%s\n", frame->ToCString()); | 681 OS::PrintErr("%s\n", frame->ToCString()); |
| 732 frame = frames.NextFrame(); | 682 frame = frames.NextFrame(); |
| 733 } | 683 } |
| 734 OS::Abort(); | 684 OS::Abort(); |
| 735 } | 685 } |
| 736 | 686 |
| 737 | |
| 738 // Calculate the context level at the current token index of the frame. | 687 // Calculate the context level at the current token index of the frame. |
| 739 intptr_t ActivationFrame::ContextLevel() { | 688 intptr_t ActivationFrame::ContextLevel() { |
| 740 const Context& ctx = GetSavedCurrentContext(); | 689 const Context& ctx = GetSavedCurrentContext(); |
| 741 if (context_level_ < 0 && !ctx.IsNull()) { | 690 if (context_level_ < 0 && !ctx.IsNull()) { |
| 742 ASSERT(!code_.is_optimized()); | 691 ASSERT(!code_.is_optimized()); |
| 743 | 692 |
| 744 GetVarDescriptors(); | 693 GetVarDescriptors(); |
| 745 intptr_t deopt_id = DeoptId(); | 694 intptr_t deopt_id = DeoptId(); |
| 746 if (deopt_id == Thread::kNoDeoptId) { | 695 if (deopt_id == Thread::kNoDeoptId) { |
| 747 PrintDescriptorsError("Missing deopt id"); | 696 PrintDescriptorsError("Missing deopt id"); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 761 } | 710 } |
| 762 } | 711 } |
| 763 if (!found) { | 712 if (!found) { |
| 764 PrintDescriptorsError("Missing context level"); | 713 PrintDescriptorsError("Missing context level"); |
| 765 } | 714 } |
| 766 ASSERT(context_level_ >= 0); | 715 ASSERT(context_level_ >= 0); |
| 767 } | 716 } |
| 768 return context_level_; | 717 return context_level_; |
| 769 } | 718 } |
| 770 | 719 |
| 771 | |
| 772 RawObject* ActivationFrame::GetAsyncContextVariable(const String& name) { | 720 RawObject* ActivationFrame::GetAsyncContextVariable(const String& name) { |
| 773 if (!function_.IsAsyncClosure() && !function_.IsAsyncGenClosure()) { | 721 if (!function_.IsAsyncClosure() && !function_.IsAsyncGenClosure()) { |
| 774 return Object::null(); | 722 return Object::null(); |
| 775 } | 723 } |
| 776 GetVarDescriptors(); | 724 GetVarDescriptors(); |
| 777 intptr_t var_desc_len = var_descriptors_.Length(); | 725 intptr_t var_desc_len = var_descriptors_.Length(); |
| 778 for (intptr_t i = 0; i < var_desc_len; i++) { | 726 for (intptr_t i = 0; i < var_desc_len; i++) { |
| 779 RawLocalVarDescriptors::VarInfo var_info; | 727 RawLocalVarDescriptors::VarInfo var_info; |
| 780 var_descriptors_.GetInfo(i, &var_info); | 728 var_descriptors_.GetInfo(i, &var_info); |
| 781 if (var_descriptors_.GetName(i) == name.raw()) { | 729 if (var_descriptors_.GetName(i) == name.raw()) { |
| 782 const int8_t kind = var_info.kind(); | 730 const int8_t kind = var_info.kind(); |
| 783 if (!live_frame_) { | 731 if (!live_frame_) { |
| 784 ASSERT(kind == RawLocalVarDescriptors::kContextVar); | 732 ASSERT(kind == RawLocalVarDescriptors::kContextVar); |
| 785 } | 733 } |
| 786 if (kind == RawLocalVarDescriptors::kStackVar) { | 734 if (kind == RawLocalVarDescriptors::kStackVar) { |
| 787 return GetStackVar(var_info.index()); | 735 return GetStackVar(var_info.index()); |
| 788 } else { | 736 } else { |
| 789 ASSERT(kind == RawLocalVarDescriptors::kContextVar); | 737 ASSERT(kind == RawLocalVarDescriptors::kContextVar); |
| 790 if (!live_frame_) { | 738 if (!live_frame_) { |
| 791 ASSERT(!ctx_.IsNull()); | 739 ASSERT(!ctx_.IsNull()); |
| 792 return ctx_.At(var_info.index()); | 740 return ctx_.At(var_info.index()); |
| 793 } | 741 } |
| 794 return GetContextVar(var_info.scope_id, var_info.index()); | 742 return GetContextVar(var_info.scope_id, var_info.index()); |
| 795 } | 743 } |
| 796 } | 744 } |
| 797 } | 745 } |
| 798 return Object::null(); | 746 return Object::null(); |
| 799 } | 747 } |
| 800 | 748 |
| 801 | |
| 802 RawObject* ActivationFrame::GetAsyncCompleter() { | 749 RawObject* ActivationFrame::GetAsyncCompleter() { |
| 803 return GetAsyncContextVariable(Symbols::AsyncCompleter()); | 750 return GetAsyncContextVariable(Symbols::AsyncCompleter()); |
| 804 } | 751 } |
| 805 | 752 |
| 806 | |
| 807 RawObject* ActivationFrame::GetAsyncCompleterAwaiter(const Object& completer) { | 753 RawObject* ActivationFrame::GetAsyncCompleterAwaiter(const Object& completer) { |
| 808 const Class& sync_completer_cls = Class::Handle(completer.clazz()); | 754 const Class& sync_completer_cls = Class::Handle(completer.clazz()); |
| 809 ASSERT(!sync_completer_cls.IsNull()); | 755 ASSERT(!sync_completer_cls.IsNull()); |
| 810 const Class& completer_cls = Class::Handle(sync_completer_cls.SuperClass()); | 756 const Class& completer_cls = Class::Handle(sync_completer_cls.SuperClass()); |
| 811 const Field& future_field = | 757 const Field& future_field = |
| 812 Field::Handle(completer_cls.LookupInstanceFieldAllowPrivate( | 758 Field::Handle(completer_cls.LookupInstanceFieldAllowPrivate( |
| 813 Symbols::CompleterFuture())); | 759 Symbols::CompleterFuture())); |
| 814 ASSERT(!future_field.IsNull()); | 760 ASSERT(!future_field.IsNull()); |
| 815 Instance& future = Instance::Handle(); | 761 Instance& future = Instance::Handle(); |
| 816 future ^= Instance::Cast(completer).GetField(future_field); | 762 future ^= Instance::Cast(completer).GetField(future_field); |
| 817 if (future.IsNull()) { | 763 if (future.IsNull()) { |
| 818 // The completer object may not be fully initialized yet. | 764 // The completer object may not be fully initialized yet. |
| 819 return Object::null(); | 765 return Object::null(); |
| 820 } | 766 } |
| 821 const Class& future_cls = Class::Handle(future.clazz()); | 767 const Class& future_cls = Class::Handle(future.clazz()); |
| 822 ASSERT(!future_cls.IsNull()); | 768 ASSERT(!future_cls.IsNull()); |
| 823 const Field& awaiter_field = Field::Handle( | 769 const Field& awaiter_field = Field::Handle( |
| 824 future_cls.LookupInstanceFieldAllowPrivate(Symbols::_Awaiter())); | 770 future_cls.LookupInstanceFieldAllowPrivate(Symbols::_Awaiter())); |
| 825 ASSERT(!awaiter_field.IsNull()); | 771 ASSERT(!awaiter_field.IsNull()); |
| 826 return future.GetField(awaiter_field); | 772 return future.GetField(awaiter_field); |
| 827 } | 773 } |
| 828 | 774 |
| 829 | |
| 830 RawObject* ActivationFrame::GetAsyncStreamControllerStream() { | 775 RawObject* ActivationFrame::GetAsyncStreamControllerStream() { |
| 831 return GetAsyncContextVariable(Symbols::ControllerStream()); | 776 return GetAsyncContextVariable(Symbols::ControllerStream()); |
| 832 } | 777 } |
| 833 | 778 |
| 834 | |
| 835 RawObject* ActivationFrame::GetAsyncStreamControllerStreamAwaiter( | 779 RawObject* ActivationFrame::GetAsyncStreamControllerStreamAwaiter( |
| 836 const Object& stream) { | 780 const Object& stream) { |
| 837 const Class& stream_cls = Class::Handle(stream.clazz()); | 781 const Class& stream_cls = Class::Handle(stream.clazz()); |
| 838 ASSERT(!stream_cls.IsNull()); | 782 ASSERT(!stream_cls.IsNull()); |
| 839 const Class& stream_impl_cls = Class::Handle(stream_cls.SuperClass()); | 783 const Class& stream_impl_cls = Class::Handle(stream_cls.SuperClass()); |
| 840 const Field& awaiter_field = Field::Handle( | 784 const Field& awaiter_field = Field::Handle( |
| 841 stream_impl_cls.LookupInstanceFieldAllowPrivate(Symbols::_Awaiter())); | 785 stream_impl_cls.LookupInstanceFieldAllowPrivate(Symbols::_Awaiter())); |
| 842 ASSERT(!awaiter_field.IsNull()); | 786 ASSERT(!awaiter_field.IsNull()); |
| 843 return Instance::Cast(stream).GetField(awaiter_field); | 787 return Instance::Cast(stream).GetField(awaiter_field); |
| 844 } | 788 } |
| 845 | 789 |
| 846 | |
| 847 RawObject* ActivationFrame::GetAsyncAwaiter() { | 790 RawObject* ActivationFrame::GetAsyncAwaiter() { |
| 848 const Object& async_stream_controller_stream = | 791 const Object& async_stream_controller_stream = |
| 849 Object::Handle(GetAsyncStreamControllerStream()); | 792 Object::Handle(GetAsyncStreamControllerStream()); |
| 850 if (!async_stream_controller_stream.IsNull()) { | 793 if (!async_stream_controller_stream.IsNull()) { |
| 851 return GetAsyncStreamControllerStreamAwaiter( | 794 return GetAsyncStreamControllerStreamAwaiter( |
| 852 async_stream_controller_stream); | 795 async_stream_controller_stream); |
| 853 } | 796 } |
| 854 const Object& completer = Object::Handle(GetAsyncCompleter()); | 797 const Object& completer = Object::Handle(GetAsyncCompleter()); |
| 855 if (!completer.IsNull()) { | 798 if (!completer.IsNull()) { |
| 856 return GetAsyncCompleterAwaiter(completer); | 799 return GetAsyncCompleterAwaiter(completer); |
| 857 } | 800 } |
| 858 return Object::null(); | 801 return Object::null(); |
| 859 } | 802 } |
| 860 | 803 |
| 861 | |
| 862 RawObject* ActivationFrame::GetCausalStack() { | 804 RawObject* ActivationFrame::GetCausalStack() { |
| 863 return GetAsyncContextVariable(Symbols::AsyncStackTraceVar()); | 805 return GetAsyncContextVariable(Symbols::AsyncStackTraceVar()); |
| 864 } | 806 } |
| 865 | 807 |
| 866 | |
| 867 bool ActivationFrame::HandlesException(const Instance& exc_obj) { | 808 bool ActivationFrame::HandlesException(const Instance& exc_obj) { |
| 868 if ((kind_ == kAsyncSuspensionMarker) || (kind_ == kAsyncCausal)) { | 809 if ((kind_ == kAsyncSuspensionMarker) || (kind_ == kAsyncCausal)) { |
| 869 // These frames are historical. | 810 // These frames are historical. |
| 870 return false; | 811 return false; |
| 871 } | 812 } |
| 872 intptr_t try_index = TryIndex(); | 813 intptr_t try_index = TryIndex(); |
| 873 if (try_index < 0) { | 814 if (try_index < 0) { |
| 874 return false; | 815 return false; |
| 875 } | 816 } |
| 876 ExceptionHandlers& handlers = ExceptionHandlers::Handle(); | 817 ExceptionHandlers& handlers = ExceptionHandlers::Handle(); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 904 Object::null_type_arguments(), NULL)) { | 845 Object::null_type_arguments(), NULL)) { |
| 905 return true; | 846 return true; |
| 906 } | 847 } |
| 907 } | 848 } |
| 908 } | 849 } |
| 909 try_index = handlers.OuterTryIndex(try_index); | 850 try_index = handlers.OuterTryIndex(try_index); |
| 910 } | 851 } |
| 911 return false; | 852 return false; |
| 912 } | 853 } |
| 913 | 854 |
| 914 | |
| 915 void ActivationFrame::ExtractTokenPositionFromAsyncClosure() { | 855 void ActivationFrame::ExtractTokenPositionFromAsyncClosure() { |
| 916 // Attempt to determine the token position from the async closure. | 856 // Attempt to determine the token position from the async closure. |
| 917 ASSERT(function_.IsAsyncGenClosure() || function_.IsAsyncClosure()); | 857 ASSERT(function_.IsAsyncGenClosure() || function_.IsAsyncClosure()); |
| 918 // This should only be called on frames that aren't active on the stack. | 858 // This should only be called on frames that aren't active on the stack. |
| 919 ASSERT(fp() == 0); | 859 ASSERT(fp() == 0); |
| 920 const Array& await_to_token_map = | 860 const Array& await_to_token_map = |
| 921 Array::Handle(code_.await_token_positions()); | 861 Array::Handle(code_.await_token_positions()); |
| 922 if (await_to_token_map.IsNull()) { | 862 if (await_to_token_map.IsNull()) { |
| 923 // No mapping. | 863 // No mapping. |
| 924 return; | 864 return; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 958 // TODO(johnmccutchan): Is this heuristic precise enough? | 898 // TODO(johnmccutchan): Is this heuristic precise enough? |
| 959 if (iter.TryIndex() != CatchClauseNode::kInvalidTryIndex) { | 899 if (iter.TryIndex() != CatchClauseNode::kInvalidTryIndex) { |
| 960 if ((try_index_ == -1) || (iter.TryIndex() < try_index_)) { | 900 if ((try_index_ == -1) || (iter.TryIndex() < try_index_)) { |
| 961 try_index_ = iter.TryIndex(); | 901 try_index_ = iter.TryIndex(); |
| 962 } | 902 } |
| 963 } | 903 } |
| 964 } | 904 } |
| 965 } | 905 } |
| 966 } | 906 } |
| 967 | 907 |
| 968 | |
| 969 bool ActivationFrame::IsAsyncMachinery() const { | 908 bool ActivationFrame::IsAsyncMachinery() const { |
| 970 Isolate* isolate = Isolate::Current(); | 909 Isolate* isolate = Isolate::Current(); |
| 971 if (function_.raw() == isolate->object_store()->complete_on_async_return()) { | 910 if (function_.raw() == isolate->object_store()->complete_on_async_return()) { |
| 972 // We are completing an async function's completer. | 911 // We are completing an async function's completer. |
| 973 return true; | 912 return true; |
| 974 } | 913 } |
| 975 if (function_.Owner() == | 914 if (function_.Owner() == |
| 976 isolate->object_store()->async_star_stream_controller()) { | 915 isolate->object_store()->async_star_stream_controller()) { |
| 977 // We are inside the async* stream controller code. | 916 // We are inside the async* stream controller code. |
| 978 return true; | 917 return true; |
| 979 } | 918 } |
| 980 return false; | 919 return false; |
| 981 } | 920 } |
| 982 | 921 |
| 983 | |
| 984 // Get the saved current context of this activation. | 922 // Get the saved current context of this activation. |
| 985 const Context& ActivationFrame::GetSavedCurrentContext() { | 923 const Context& ActivationFrame::GetSavedCurrentContext() { |
| 986 if (!ctx_.IsNull()) return ctx_; | 924 if (!ctx_.IsNull()) return ctx_; |
| 987 GetVarDescriptors(); | 925 GetVarDescriptors(); |
| 988 intptr_t var_desc_len = var_descriptors_.Length(); | 926 intptr_t var_desc_len = var_descriptors_.Length(); |
| 989 Object& obj = Object::Handle(); | 927 Object& obj = Object::Handle(); |
| 990 for (intptr_t i = 0; i < var_desc_len; i++) { | 928 for (intptr_t i = 0; i < var_desc_len; i++) { |
| 991 RawLocalVarDescriptors::VarInfo var_info; | 929 RawLocalVarDescriptors::VarInfo var_info; |
| 992 var_descriptors_.GetInfo(i, &var_info); | 930 var_descriptors_.GetInfo(i, &var_info); |
| 993 const int8_t kind = var_info.kind(); | 931 const int8_t kind = var_info.kind(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1006 ctx_ ^= Context::Cast(obj).raw(); | 944 ctx_ ^= Context::Cast(obj).raw(); |
| 1007 } else { | 945 } else { |
| 1008 ASSERT(obj.IsNull()); | 946 ASSERT(obj.IsNull()); |
| 1009 } | 947 } |
| 1010 return ctx_; | 948 return ctx_; |
| 1011 } | 949 } |
| 1012 } | 950 } |
| 1013 return ctx_; | 951 return ctx_; |
| 1014 } | 952 } |
| 1015 | 953 |
| 1016 | |
| 1017 RawObject* ActivationFrame::GetAsyncOperation() { | 954 RawObject* ActivationFrame::GetAsyncOperation() { |
| 1018 GetVarDescriptors(); | 955 GetVarDescriptors(); |
| 1019 intptr_t var_desc_len = var_descriptors_.Length(); | 956 intptr_t var_desc_len = var_descriptors_.Length(); |
| 1020 for (intptr_t i = 0; i < var_desc_len; i++) { | 957 for (intptr_t i = 0; i < var_desc_len; i++) { |
| 1021 RawLocalVarDescriptors::VarInfo var_info; | 958 RawLocalVarDescriptors::VarInfo var_info; |
| 1022 var_descriptors_.GetInfo(i, &var_info); | 959 var_descriptors_.GetInfo(i, &var_info); |
| 1023 if (var_descriptors_.GetName(i) == Symbols::AsyncOperation().raw()) { | 960 if (var_descriptors_.GetName(i) == Symbols::AsyncOperation().raw()) { |
| 1024 const int8_t kind = var_info.kind(); | 961 const int8_t kind = var_info.kind(); |
| 1025 if (kind == RawLocalVarDescriptors::kStackVar) { | 962 if (kind == RawLocalVarDescriptors::kStackVar) { |
| 1026 return GetStackVar(var_info.index()); | 963 return GetStackVar(var_info.index()); |
| 1027 } else { | 964 } else { |
| 1028 ASSERT(kind == RawLocalVarDescriptors::kContextVar); | 965 ASSERT(kind == RawLocalVarDescriptors::kContextVar); |
| 1029 return GetContextVar(var_info.scope_id, var_info.index()); | 966 return GetContextVar(var_info.scope_id, var_info.index()); |
| 1030 } | 967 } |
| 1031 } | 968 } |
| 1032 } | 969 } |
| 1033 return Object::null(); | 970 return Object::null(); |
| 1034 } | 971 } |
| 1035 | 972 |
| 1036 | |
| 1037 ActivationFrame* DebuggerStackTrace::GetHandlerFrame( | 973 ActivationFrame* DebuggerStackTrace::GetHandlerFrame( |
| 1038 const Instance& exc_obj) const { | 974 const Instance& exc_obj) const { |
| 1039 for (intptr_t frame_index = 0; frame_index < Length(); frame_index++) { | 975 for (intptr_t frame_index = 0; frame_index < Length(); frame_index++) { |
| 1040 ActivationFrame* frame = FrameAt(frame_index); | 976 ActivationFrame* frame = FrameAt(frame_index); |
| 1041 if (frame->HandlesException(exc_obj)) { | 977 if (frame->HandlesException(exc_obj)) { |
| 1042 return frame; | 978 return frame; |
| 1043 } | 979 } |
| 1044 } | 980 } |
| 1045 return NULL; | 981 return NULL; |
| 1046 } | 982 } |
| 1047 | 983 |
| 1048 | |
| 1049 void ActivationFrame::GetDescIndices() { | 984 void ActivationFrame::GetDescIndices() { |
| 1050 if (vars_initialized_) { | 985 if (vars_initialized_) { |
| 1051 return; | 986 return; |
| 1052 } | 987 } |
| 1053 GetVarDescriptors(); | 988 GetVarDescriptors(); |
| 1054 | 989 |
| 1055 TokenPosition activation_token_pos = TokenPos(); | 990 TokenPosition activation_token_pos = TokenPos(); |
| 1056 if (!activation_token_pos.IsDebugPause() || !live_frame_) { | 991 if (!activation_token_pos.IsDebugPause() || !live_frame_) { |
| 1057 // We don't have a token position for this frame, so can't determine | 992 // We don't have a token position for this frame, so can't determine |
| 1058 // which variables are visible. | 993 // which variables are visible. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1114 // No duplicate name found. Add the current descriptor index to the | 1049 // No duplicate name found. Add the current descriptor index to the |
| 1115 // list of visible variables. | 1050 // list of visible variables. |
| 1116 desc_indices_.Add(cur_idx); | 1051 desc_indices_.Add(cur_idx); |
| 1117 var_names.Add(&var_name); | 1052 var_names.Add(&var_name); |
| 1118 } | 1053 } |
| 1119 } | 1054 } |
| 1120 } | 1055 } |
| 1121 vars_initialized_ = true; | 1056 vars_initialized_ = true; |
| 1122 } | 1057 } |
| 1123 | 1058 |
| 1124 | |
| 1125 intptr_t ActivationFrame::NumLocalVariables() { | 1059 intptr_t ActivationFrame::NumLocalVariables() { |
| 1126 GetDescIndices(); | 1060 GetDescIndices(); |
| 1127 return desc_indices_.length(); | 1061 return desc_indices_.length(); |
| 1128 } | 1062 } |
| 1129 | 1063 |
| 1130 | |
| 1131 DART_FORCE_INLINE static RawObject* GetVariableValue(uword addr) { | 1064 DART_FORCE_INLINE static RawObject* GetVariableValue(uword addr) { |
| 1132 return *reinterpret_cast<RawObject**>(addr); | 1065 return *reinterpret_cast<RawObject**>(addr); |
| 1133 } | 1066 } |
| 1134 | 1067 |
| 1135 | |
| 1136 RawObject* ActivationFrame::GetParameter(intptr_t index) { | 1068 RawObject* ActivationFrame::GetParameter(intptr_t index) { |
| 1137 intptr_t num_parameters = function().num_fixed_parameters(); | 1069 intptr_t num_parameters = function().num_fixed_parameters(); |
| 1138 ASSERT(0 <= index && index < num_parameters); | 1070 ASSERT(0 <= index && index < num_parameters); |
| 1139 | 1071 |
| 1140 if (function().NumOptionalParameters() > 0) { | 1072 if (function().NumOptionalParameters() > 0) { |
| 1141 // If the function has optional parameters, the first positional parameter | 1073 // If the function has optional parameters, the first positional parameter |
| 1142 // can be in a number of places in the caller's frame depending on how many | 1074 // can be in a number of places in the caller's frame depending on how many |
| 1143 // were actually supplied at the call site, but they are copied to a fixed | 1075 // were actually supplied at the call site, but they are copied to a fixed |
| 1144 // place in the callee's frame. | 1076 // place in the callee's frame. |
| 1145 return GetVariableValue( | 1077 return GetVariableValue( |
| 1146 LocalVarAddress(fp(), (kFirstLocalSlotFromFp - index))); | 1078 LocalVarAddress(fp(), (kFirstLocalSlotFromFp - index))); |
| 1147 } else { | 1079 } else { |
| 1148 intptr_t reverse_index = num_parameters - index; | 1080 intptr_t reverse_index = num_parameters - index; |
| 1149 return GetVariableValue(ParamAddress(fp(), reverse_index)); | 1081 return GetVariableValue(ParamAddress(fp(), reverse_index)); |
| 1150 } | 1082 } |
| 1151 } | 1083 } |
| 1152 | 1084 |
| 1153 | |
| 1154 RawObject* ActivationFrame::GetClosure() { | 1085 RawObject* ActivationFrame::GetClosure() { |
| 1155 ASSERT(function().IsClosureFunction()); | 1086 ASSERT(function().IsClosureFunction()); |
| 1156 return GetParameter(0); | 1087 return GetParameter(0); |
| 1157 } | 1088 } |
| 1158 | 1089 |
| 1159 | |
| 1160 RawObject* ActivationFrame::GetStackVar(intptr_t slot_index) { | 1090 RawObject* ActivationFrame::GetStackVar(intptr_t slot_index) { |
| 1161 if (deopt_frame_.IsNull()) { | 1091 if (deopt_frame_.IsNull()) { |
| 1162 return GetVariableValue(LocalVarAddress(fp(), slot_index)); | 1092 return GetVariableValue(LocalVarAddress(fp(), slot_index)); |
| 1163 } else { | 1093 } else { |
| 1164 return deopt_frame_.At(LocalVarIndex(deopt_frame_offset_, slot_index)); | 1094 return deopt_frame_.At(LocalVarIndex(deopt_frame_offset_, slot_index)); |
| 1165 } | 1095 } |
| 1166 } | 1096 } |
| 1167 | 1097 |
| 1168 | |
| 1169 bool ActivationFrame::IsRewindable() const { | 1098 bool ActivationFrame::IsRewindable() const { |
| 1170 if (deopt_frame_.IsNull()) { | 1099 if (deopt_frame_.IsNull()) { |
| 1171 return true; | 1100 return true; |
| 1172 } | 1101 } |
| 1173 // TODO(turnidge): This is conservative. It looks at all values in | 1102 // TODO(turnidge): This is conservative. It looks at all values in |
| 1174 // the deopt_frame_ even though some of them may correspond to other | 1103 // the deopt_frame_ even though some of them may correspond to other |
| 1175 // inlined frames. | 1104 // inlined frames. |
| 1176 Object& obj = Object::Handle(); | 1105 Object& obj = Object::Handle(); |
| 1177 for (int i = 0; i < deopt_frame_.Length(); i++) { | 1106 for (int i = 0; i < deopt_frame_.Length(); i++) { |
| 1178 obj = deopt_frame_.At(i); | 1107 obj = deopt_frame_.At(i); |
| 1179 if (obj.raw() == Symbols::OptimizedOut().raw()) { | 1108 if (obj.raw() == Symbols::OptimizedOut().raw()) { |
| 1180 return false; | 1109 return false; |
| 1181 } | 1110 } |
| 1182 } | 1111 } |
| 1183 return true; | 1112 return true; |
| 1184 } | 1113 } |
| 1185 | 1114 |
| 1186 | |
| 1187 void ActivationFrame::PrintContextMismatchError(intptr_t ctx_slot, | 1115 void ActivationFrame::PrintContextMismatchError(intptr_t ctx_slot, |
| 1188 intptr_t frame_ctx_level, | 1116 intptr_t frame_ctx_level, |
| 1189 intptr_t var_ctx_level) { | 1117 intptr_t var_ctx_level) { |
| 1190 OS::PrintErr( | 1118 OS::PrintErr( |
| 1191 "-------------------------\n" | 1119 "-------------------------\n" |
| 1192 "Encountered context mismatch\n" | 1120 "Encountered context mismatch\n" |
| 1193 "\tctx_slot: %" Pd | 1121 "\tctx_slot: %" Pd |
| 1194 "\n" | 1122 "\n" |
| 1195 "\tframe_ctx_level: %" Pd | 1123 "\tframe_ctx_level: %" Pd |
| 1196 "\n" | 1124 "\n" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1225 Thread::Current(), | 1153 Thread::Current(), |
| 1226 StackFrameIterator::kNoCrossThreadIteration); | 1154 StackFrameIterator::kNoCrossThreadIteration); |
| 1227 StackFrame* frame = iterator.NextFrame(); | 1155 StackFrame* frame = iterator.NextFrame(); |
| 1228 intptr_t num = 0; | 1156 intptr_t num = 0; |
| 1229 while ((frame != NULL)) { | 1157 while ((frame != NULL)) { |
| 1230 OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString()); | 1158 OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString()); |
| 1231 frame = iterator.NextFrame(); | 1159 frame = iterator.NextFrame(); |
| 1232 } | 1160 } |
| 1233 } | 1161 } |
| 1234 | 1162 |
| 1235 | |
| 1236 void ActivationFrame::VariableAt(intptr_t i, | 1163 void ActivationFrame::VariableAt(intptr_t i, |
| 1237 String* name, | 1164 String* name, |
| 1238 TokenPosition* declaration_token_pos, | 1165 TokenPosition* declaration_token_pos, |
| 1239 TokenPosition* visible_start_token_pos, | 1166 TokenPosition* visible_start_token_pos, |
| 1240 TokenPosition* visible_end_token_pos, | 1167 TokenPosition* visible_end_token_pos, |
| 1241 Object* value) { | 1168 Object* value) { |
| 1242 GetDescIndices(); | 1169 GetDescIndices(); |
| 1243 ASSERT(i < desc_indices_.length()); | 1170 ASSERT(i < desc_indices_.length()); |
| 1244 intptr_t desc_index = desc_indices_[i]; | 1171 intptr_t desc_index = desc_indices_[i]; |
| 1245 ASSERT(name != NULL); | 1172 ASSERT(name != NULL); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1257 ASSERT(value != NULL); | 1184 ASSERT(value != NULL); |
| 1258 const int8_t kind = var_info.kind(); | 1185 const int8_t kind = var_info.kind(); |
| 1259 if (kind == RawLocalVarDescriptors::kStackVar) { | 1186 if (kind == RawLocalVarDescriptors::kStackVar) { |
| 1260 *value = GetStackVar(var_info.index()); | 1187 *value = GetStackVar(var_info.index()); |
| 1261 } else { | 1188 } else { |
| 1262 ASSERT(kind == RawLocalVarDescriptors::kContextVar); | 1189 ASSERT(kind == RawLocalVarDescriptors::kContextVar); |
| 1263 *value = GetContextVar(var_info.scope_id, var_info.index()); | 1190 *value = GetContextVar(var_info.scope_id, var_info.index()); |
| 1264 } | 1191 } |
| 1265 } | 1192 } |
| 1266 | 1193 |
| 1267 | |
| 1268 RawObject* ActivationFrame::GetContextVar(intptr_t var_ctx_level, | 1194 RawObject* ActivationFrame::GetContextVar(intptr_t var_ctx_level, |
| 1269 intptr_t ctx_slot) { | 1195 intptr_t ctx_slot) { |
| 1270 const Context& ctx = GetSavedCurrentContext(); | 1196 const Context& ctx = GetSavedCurrentContext(); |
| 1271 ASSERT(!ctx.IsNull()); | 1197 ASSERT(!ctx.IsNull()); |
| 1272 | 1198 |
| 1273 // The context level at the PC/token index of this activation frame. | 1199 // The context level at the PC/token index of this activation frame. |
| 1274 intptr_t frame_ctx_level = ContextLevel(); | 1200 intptr_t frame_ctx_level = ContextLevel(); |
| 1275 | 1201 |
| 1276 intptr_t level_diff = frame_ctx_level - var_ctx_level; | 1202 intptr_t level_diff = frame_ctx_level - var_ctx_level; |
| 1277 if (level_diff == 0) { | 1203 if (level_diff == 0) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1290 if (var_ctx.IsNull() || (ctx_slot < 0) || | 1216 if (var_ctx.IsNull() || (ctx_slot < 0) || |
| 1291 (ctx_slot >= var_ctx.num_variables())) { | 1217 (ctx_slot >= var_ctx.num_variables())) { |
| 1292 PrintContextMismatchError(ctx_slot, frame_ctx_level, var_ctx_level); | 1218 PrintContextMismatchError(ctx_slot, frame_ctx_level, var_ctx_level); |
| 1293 } | 1219 } |
| 1294 ASSERT(!var_ctx.IsNull()); | 1220 ASSERT(!var_ctx.IsNull()); |
| 1295 ASSERT((ctx_slot >= 0) && (ctx_slot < var_ctx.num_variables())); | 1221 ASSERT((ctx_slot >= 0) && (ctx_slot < var_ctx.num_variables())); |
| 1296 return var_ctx.At(ctx_slot); | 1222 return var_ctx.At(ctx_slot); |
| 1297 } | 1223 } |
| 1298 } | 1224 } |
| 1299 | 1225 |
| 1300 | |
| 1301 RawArray* ActivationFrame::GetLocalVariables() { | 1226 RawArray* ActivationFrame::GetLocalVariables() { |
| 1302 GetDescIndices(); | 1227 GetDescIndices(); |
| 1303 intptr_t num_variables = desc_indices_.length(); | 1228 intptr_t num_variables = desc_indices_.length(); |
| 1304 String& var_name = String::Handle(); | 1229 String& var_name = String::Handle(); |
| 1305 Object& value = Instance::Handle(); | 1230 Object& value = Instance::Handle(); |
| 1306 const Array& list = Array::Handle(Array::New(2 * num_variables)); | 1231 const Array& list = Array::Handle(Array::New(2 * num_variables)); |
| 1307 for (intptr_t i = 0; i < num_variables; i++) { | 1232 for (intptr_t i = 0; i < num_variables; i++) { |
| 1308 TokenPosition ignore; | 1233 TokenPosition ignore; |
| 1309 VariableAt(i, &var_name, &ignore, &ignore, &ignore, &value); | 1234 VariableAt(i, &var_name, &ignore, &ignore, &ignore, &value); |
| 1310 list.SetAt(2 * i, var_name); | 1235 list.SetAt(2 * i, var_name); |
| 1311 list.SetAt((2 * i) + 1, value); | 1236 list.SetAt((2 * i) + 1, value); |
| 1312 } | 1237 } |
| 1313 return list.raw(); | 1238 return list.raw(); |
| 1314 } | 1239 } |
| 1315 | 1240 |
| 1316 | |
| 1317 RawObject* ActivationFrame::GetReceiver() { | 1241 RawObject* ActivationFrame::GetReceiver() { |
| 1318 GetDescIndices(); | 1242 GetDescIndices(); |
| 1319 intptr_t num_variables = desc_indices_.length(); | 1243 intptr_t num_variables = desc_indices_.length(); |
| 1320 String& var_name = String::Handle(); | 1244 String& var_name = String::Handle(); |
| 1321 Instance& value = Instance::Handle(); | 1245 Instance& value = Instance::Handle(); |
| 1322 for (intptr_t i = 0; i < num_variables; i++) { | 1246 for (intptr_t i = 0; i < num_variables; i++) { |
| 1323 TokenPosition ignore; | 1247 TokenPosition ignore; |
| 1324 VariableAt(i, &var_name, &ignore, &ignore, &ignore, &value); | 1248 VariableAt(i, &var_name, &ignore, &ignore, &ignore, &value); |
| 1325 if (var_name.Equals(Symbols::This())) { | 1249 if (var_name.Equals(Symbols::This())) { |
| 1326 return value.raw(); | 1250 return value.raw(); |
| 1327 } | 1251 } |
| 1328 } | 1252 } |
| 1329 return Symbols::OptimizedOut().raw(); | 1253 return Symbols::OptimizedOut().raw(); |
| 1330 } | 1254 } |
| 1331 | 1255 |
| 1332 | |
| 1333 static bool IsSyntheticVariableName(const String& var_name) { | 1256 static bool IsSyntheticVariableName(const String& var_name) { |
| 1334 return (var_name.Length() >= 1) && (var_name.CharAt(0) == ':'); | 1257 return (var_name.Length() >= 1) && (var_name.CharAt(0) == ':'); |
| 1335 } | 1258 } |
| 1336 | 1259 |
| 1337 | |
| 1338 static bool IsPrivateVariableName(const String& var_name) { | 1260 static bool IsPrivateVariableName(const String& var_name) { |
| 1339 return (var_name.Length() >= 1) && (var_name.CharAt(0) == '_'); | 1261 return (var_name.Length() >= 1) && (var_name.CharAt(0) == '_'); |
| 1340 } | 1262 } |
| 1341 | 1263 |
| 1342 | |
| 1343 RawObject* ActivationFrame::Evaluate(const String& expr, | 1264 RawObject* ActivationFrame::Evaluate(const String& expr, |
| 1344 const GrowableObjectArray& param_names, | 1265 const GrowableObjectArray& param_names, |
| 1345 const GrowableObjectArray& param_values) { | 1266 const GrowableObjectArray& param_values) { |
| 1346 GetDescIndices(); | 1267 GetDescIndices(); |
| 1347 String& name = String::Handle(); | 1268 String& name = String::Handle(); |
| 1348 String& existing_name = String::Handle(); | 1269 String& existing_name = String::Handle(); |
| 1349 Object& value = Instance::Handle(); | 1270 Object& value = Instance::Handle(); |
| 1350 intptr_t num_variables = desc_indices_.length(); | 1271 intptr_t num_variables = desc_indices_.length(); |
| 1351 for (intptr_t i = 0; i < num_variables; i++) { | 1272 for (intptr_t i = 0; i < num_variables; i++) { |
| 1352 TokenPosition ignore; | 1273 TokenPosition ignore; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1387 } | 1308 } |
| 1388 const Instance& inst = Instance::Cast(receiver); | 1309 const Instance& inst = Instance::Cast(receiver); |
| 1389 return inst.Evaluate(method_cls, expr, | 1310 return inst.Evaluate(method_cls, expr, |
| 1390 Array::Handle(Array::MakeFixedLength(param_names)), | 1311 Array::Handle(Array::MakeFixedLength(param_names)), |
| 1391 Array::Handle(Array::MakeFixedLength(param_values))); | 1312 Array::Handle(Array::MakeFixedLength(param_values))); |
| 1392 } | 1313 } |
| 1393 UNREACHABLE(); | 1314 UNREACHABLE(); |
| 1394 return Object::null(); | 1315 return Object::null(); |
| 1395 } | 1316 } |
| 1396 | 1317 |
| 1397 | |
| 1398 const char* ActivationFrame::ToCString() { | 1318 const char* ActivationFrame::ToCString() { |
| 1399 const String& url = String::Handle(SourceUrl()); | 1319 const String& url = String::Handle(SourceUrl()); |
| 1400 intptr_t line = LineNumber(); | 1320 intptr_t line = LineNumber(); |
| 1401 const char* func_name = Debugger::QualifiedFunctionName(function()); | 1321 const char* func_name = Debugger::QualifiedFunctionName(function()); |
| 1402 return Thread::Current()->zone()->PrintToString( | 1322 return Thread::Current()->zone()->PrintToString( |
| 1403 "[ Frame pc(0x%" Px ") fp(0x%" Px ") sp(0x%" Px | 1323 "[ Frame pc(0x%" Px ") fp(0x%" Px ") sp(0x%" Px |
| 1404 ")\n" | 1324 ")\n" |
| 1405 "\tfunction = %s\n" | 1325 "\tfunction = %s\n" |
| 1406 "\turl = %s\n" | 1326 "\turl = %s\n" |
| 1407 "\tline = %" Pd | 1327 "\tline = %" Pd |
| 1408 "\n" | 1328 "\n" |
| 1409 "\tcontext = %s\n" | 1329 "\tcontext = %s\n" |
| 1410 "\tcontext level = %" Pd " ]\n", | 1330 "\tcontext level = %" Pd " ]\n", |
| 1411 pc(), fp(), sp(), func_name, url.ToCString(), line, ctx_.ToCString(), | 1331 pc(), fp(), sp(), func_name, url.ToCString(), line, ctx_.ToCString(), |
| 1412 ContextLevel()); | 1332 ContextLevel()); |
| 1413 } | 1333 } |
| 1414 | 1334 |
| 1415 | |
| 1416 void ActivationFrame::PrintToJSONObject(JSONObject* jsobj, bool full) { | 1335 void ActivationFrame::PrintToJSONObject(JSONObject* jsobj, bool full) { |
| 1417 if (kind_ == kRegular) { | 1336 if (kind_ == kRegular) { |
| 1418 PrintToJSONObjectRegular(jsobj, full); | 1337 PrintToJSONObjectRegular(jsobj, full); |
| 1419 } else if (kind_ == kAsyncCausal) { | 1338 } else if (kind_ == kAsyncCausal) { |
| 1420 PrintToJSONObjectAsyncCausal(jsobj, full); | 1339 PrintToJSONObjectAsyncCausal(jsobj, full); |
| 1421 } else if (kind_ == kAsyncSuspensionMarker) { | 1340 } else if (kind_ == kAsyncSuspensionMarker) { |
| 1422 PrintToJSONObjectAsyncSuspensionMarker(jsobj, full); | 1341 PrintToJSONObjectAsyncSuspensionMarker(jsobj, full); |
| 1423 } else if (kind_ == kAsyncActivation) { | 1342 } else if (kind_ == kAsyncActivation) { |
| 1424 PrintToJSONObjectAsyncActivation(jsobj, full); | 1343 PrintToJSONObjectAsyncActivation(jsobj, full); |
| 1425 } else { | 1344 } else { |
| 1426 UNIMPLEMENTED(); | 1345 UNIMPLEMENTED(); |
| 1427 } | 1346 } |
| 1428 } | 1347 } |
| 1429 | 1348 |
| 1430 | |
| 1431 void ActivationFrame::PrintToJSONObjectRegular(JSONObject* jsobj, bool full) { | 1349 void ActivationFrame::PrintToJSONObjectRegular(JSONObject* jsobj, bool full) { |
| 1432 const Script& script = Script::Handle(SourceScript()); | 1350 const Script& script = Script::Handle(SourceScript()); |
| 1433 jsobj->AddProperty("type", "Frame"); | 1351 jsobj->AddProperty("type", "Frame"); |
| 1434 jsobj->AddProperty("kind", KindToCString(kind_)); | 1352 jsobj->AddProperty("kind", KindToCString(kind_)); |
| 1435 const TokenPosition pos = TokenPos().SourcePosition(); | 1353 const TokenPosition pos = TokenPos().SourcePosition(); |
| 1436 jsobj->AddLocation(script, pos); | 1354 jsobj->AddLocation(script, pos); |
| 1437 jsobj->AddProperty("function", function(), !full); | 1355 jsobj->AddProperty("function", function(), !full); |
| 1438 jsobj->AddProperty("code", code()); | 1356 jsobj->AddProperty("code", code()); |
| 1439 if (full) { | 1357 if (full) { |
| 1440 // TODO(cutch): The old "full" script usage no longer fits | 1358 // TODO(cutch): The old "full" script usage no longer fits |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1467 jsvar.AddProperty("declarationTokenPos", declaration_token_pos); | 1385 jsvar.AddProperty("declarationTokenPos", declaration_token_pos); |
| 1468 // When the variable becomes visible to the scope. | 1386 // When the variable becomes visible to the scope. |
| 1469 jsvar.AddProperty("scopeStartTokenPos", visible_start_token_pos); | 1387 jsvar.AddProperty("scopeStartTokenPos", visible_start_token_pos); |
| 1470 // When the variable stops being visible to the scope. | 1388 // When the variable stops being visible to the scope. |
| 1471 jsvar.AddProperty("scopeEndTokenPos", visible_end_token_pos); | 1389 jsvar.AddProperty("scopeEndTokenPos", visible_end_token_pos); |
| 1472 } | 1390 } |
| 1473 } | 1391 } |
| 1474 } | 1392 } |
| 1475 } | 1393 } |
| 1476 | 1394 |
| 1477 | |
| 1478 void ActivationFrame::PrintToJSONObjectAsyncCausal(JSONObject* jsobj, | 1395 void ActivationFrame::PrintToJSONObjectAsyncCausal(JSONObject* jsobj, |
| 1479 bool full) { | 1396 bool full) { |
| 1480 jsobj->AddProperty("type", "Frame"); | 1397 jsobj->AddProperty("type", "Frame"); |
| 1481 jsobj->AddProperty("kind", KindToCString(kind_)); | 1398 jsobj->AddProperty("kind", KindToCString(kind_)); |
| 1482 const Script& script = Script::Handle(SourceScript()); | 1399 const Script& script = Script::Handle(SourceScript()); |
| 1483 const TokenPosition pos = TokenPos().SourcePosition(); | 1400 const TokenPosition pos = TokenPos().SourcePosition(); |
| 1484 jsobj->AddLocation(script, pos); | 1401 jsobj->AddLocation(script, pos); |
| 1485 jsobj->AddProperty("function", function(), !full); | 1402 jsobj->AddProperty("function", function(), !full); |
| 1486 jsobj->AddProperty("code", code()); | 1403 jsobj->AddProperty("code", code()); |
| 1487 if (full) { | 1404 if (full) { |
| 1488 // TODO(cutch): The old "full" script usage no longer fits | 1405 // TODO(cutch): The old "full" script usage no longer fits |
| 1489 // in the world where we pass the script as part of the | 1406 // in the world where we pass the script as part of the |
| 1490 // location. | 1407 // location. |
| 1491 jsobj->AddProperty("script", script, !full); | 1408 jsobj->AddProperty("script", script, !full); |
| 1492 } | 1409 } |
| 1493 } | 1410 } |
| 1494 | 1411 |
| 1495 | |
| 1496 void ActivationFrame::PrintToJSONObjectAsyncSuspensionMarker(JSONObject* jsobj, | 1412 void ActivationFrame::PrintToJSONObjectAsyncSuspensionMarker(JSONObject* jsobj, |
| 1497 bool full) { | 1413 bool full) { |
| 1498 jsobj->AddProperty("type", "Frame"); | 1414 jsobj->AddProperty("type", "Frame"); |
| 1499 jsobj->AddProperty("kind", KindToCString(kind_)); | 1415 jsobj->AddProperty("kind", KindToCString(kind_)); |
| 1500 jsobj->AddProperty("marker", "AsynchronousSuspension"); | 1416 jsobj->AddProperty("marker", "AsynchronousSuspension"); |
| 1501 } | 1417 } |
| 1502 | 1418 |
| 1503 | |
| 1504 void ActivationFrame::PrintToJSONObjectAsyncActivation(JSONObject* jsobj, | 1419 void ActivationFrame::PrintToJSONObjectAsyncActivation(JSONObject* jsobj, |
| 1505 bool full) { | 1420 bool full) { |
| 1506 jsobj->AddProperty("type", "Frame"); | 1421 jsobj->AddProperty("type", "Frame"); |
| 1507 jsobj->AddProperty("kind", KindToCString(kind_)); | 1422 jsobj->AddProperty("kind", KindToCString(kind_)); |
| 1508 const Script& script = Script::Handle(SourceScript()); | 1423 const Script& script = Script::Handle(SourceScript()); |
| 1509 const TokenPosition pos = TokenPos().SourcePosition(); | 1424 const TokenPosition pos = TokenPos().SourcePosition(); |
| 1510 jsobj->AddLocation(script, pos); | 1425 jsobj->AddLocation(script, pos); |
| 1511 jsobj->AddProperty("function", function(), !full); | 1426 jsobj->AddProperty("function", function(), !full); |
| 1512 jsobj->AddProperty("code", code()); | 1427 jsobj->AddProperty("code", code()); |
| 1513 if (full) { | 1428 if (full) { |
| 1514 // TODO(cutch): The old "full" script usage no longer fits | 1429 // TODO(cutch): The old "full" script usage no longer fits |
| 1515 // in the world where we pass the script as part of the | 1430 // in the world where we pass the script as part of the |
| 1516 // location. | 1431 // location. |
| 1517 jsobj->AddProperty("script", script, !full); | 1432 jsobj->AddProperty("script", script, !full); |
| 1518 } | 1433 } |
| 1519 } | 1434 } |
| 1520 | 1435 |
| 1521 | |
| 1522 static bool IsFunctionVisible(const Function& function) { | 1436 static bool IsFunctionVisible(const Function& function) { |
| 1523 return FLAG_show_invisible_frames || function.is_visible(); | 1437 return FLAG_show_invisible_frames || function.is_visible(); |
| 1524 } | 1438 } |
| 1525 | 1439 |
| 1526 | |
| 1527 void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { | 1440 void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { |
| 1528 if (IsFunctionVisible(frame->function())) { | 1441 if (IsFunctionVisible(frame->function())) { |
| 1529 trace_.Add(frame); | 1442 trace_.Add(frame); |
| 1530 } | 1443 } |
| 1531 } | 1444 } |
| 1532 | 1445 |
| 1533 | |
| 1534 void DebuggerStackTrace::AddMarker(ActivationFrame::Kind marker) { | 1446 void DebuggerStackTrace::AddMarker(ActivationFrame::Kind marker) { |
| 1535 ASSERT(marker == ActivationFrame::kAsyncSuspensionMarker); | 1447 ASSERT(marker == ActivationFrame::kAsyncSuspensionMarker); |
| 1536 trace_.Add(new ActivationFrame(marker)); | 1448 trace_.Add(new ActivationFrame(marker)); |
| 1537 } | 1449 } |
| 1538 | 1450 |
| 1539 | |
| 1540 void DebuggerStackTrace::AddAsyncCausalFrame(uword pc, const Code& code) { | 1451 void DebuggerStackTrace::AddAsyncCausalFrame(uword pc, const Code& code) { |
| 1541 trace_.Add(new ActivationFrame(pc, 0, 0, code, Array::Handle(), 0, | 1452 trace_.Add(new ActivationFrame(pc, 0, 0, code, Array::Handle(), 0, |
| 1542 ActivationFrame::kAsyncCausal)); | 1453 ActivationFrame::kAsyncCausal)); |
| 1543 } | 1454 } |
| 1544 | 1455 |
| 1545 | |
| 1546 const uint8_t kSafepointKind = RawPcDescriptors::kIcCall | | 1456 const uint8_t kSafepointKind = RawPcDescriptors::kIcCall | |
| 1547 RawPcDescriptors::kUnoptStaticCall | | 1457 RawPcDescriptors::kUnoptStaticCall | |
| 1548 RawPcDescriptors::kRuntimeCall; | 1458 RawPcDescriptors::kRuntimeCall; |
| 1549 | 1459 |
| 1550 | |
| 1551 CodeBreakpoint::CodeBreakpoint(const Code& code, | 1460 CodeBreakpoint::CodeBreakpoint(const Code& code, |
| 1552 TokenPosition token_pos, | 1461 TokenPosition token_pos, |
| 1553 uword pc, | 1462 uword pc, |
| 1554 RawPcDescriptors::Kind kind) | 1463 RawPcDescriptors::Kind kind) |
| 1555 : code_(code.raw()), | 1464 : code_(code.raw()), |
| 1556 token_pos_(token_pos), | 1465 token_pos_(token_pos), |
| 1557 pc_(pc), | 1466 pc_(pc), |
| 1558 line_number_(-1), | 1467 line_number_(-1), |
| 1559 is_enabled_(false), | 1468 is_enabled_(false), |
| 1560 bpt_location_(NULL), | 1469 bpt_location_(NULL), |
| 1561 next_(NULL), | 1470 next_(NULL), |
| 1562 breakpoint_kind_(kind), | 1471 breakpoint_kind_(kind), |
| 1563 #if !defined(TARGET_ARCH_DBC) | 1472 #if !defined(TARGET_ARCH_DBC) |
| 1564 saved_value_(Code::null()) | 1473 saved_value_(Code::null()) |
| 1565 #else | 1474 #else |
| 1566 saved_value_(Bytecode::kTrap), | 1475 saved_value_(Bytecode::kTrap), |
| 1567 saved_value_fastsmi_(Bytecode::kTrap) | 1476 saved_value_fastsmi_(Bytecode::kTrap) |
| 1568 #endif | 1477 #endif |
| 1569 { | 1478 { |
| 1570 ASSERT(!code.IsNull()); | 1479 ASSERT(!code.IsNull()); |
| 1571 ASSERT(token_pos_.IsReal()); | 1480 ASSERT(token_pos_.IsReal()); |
| 1572 ASSERT(pc_ != 0); | 1481 ASSERT(pc_ != 0); |
| 1573 ASSERT((breakpoint_kind_ & kSafepointKind) != 0); | 1482 ASSERT((breakpoint_kind_ & kSafepointKind) != 0); |
| 1574 } | 1483 } |
| 1575 | 1484 |
| 1576 | |
| 1577 CodeBreakpoint::~CodeBreakpoint() { | 1485 CodeBreakpoint::~CodeBreakpoint() { |
| 1578 // Make sure we don't leave patched code behind. | 1486 // Make sure we don't leave patched code behind. |
| 1579 ASSERT(!IsEnabled()); | 1487 ASSERT(!IsEnabled()); |
| 1580 // Poison the data so we catch use after free errors. | 1488 // Poison the data so we catch use after free errors. |
| 1581 #ifdef DEBUG | 1489 #ifdef DEBUG |
| 1582 code_ = Code::null(); | 1490 code_ = Code::null(); |
| 1583 pc_ = 0ul; | 1491 pc_ = 0ul; |
| 1584 bpt_location_ = NULL; | 1492 bpt_location_ = NULL; |
| 1585 next_ = NULL; | 1493 next_ = NULL; |
| 1586 breakpoint_kind_ = RawPcDescriptors::kOther; | 1494 breakpoint_kind_ = RawPcDescriptors::kOther; |
| 1587 #endif | 1495 #endif |
| 1588 } | 1496 } |
| 1589 | 1497 |
| 1590 | |
| 1591 RawFunction* CodeBreakpoint::function() const { | 1498 RawFunction* CodeBreakpoint::function() const { |
| 1592 return Code::Handle(code_).function(); | 1499 return Code::Handle(code_).function(); |
| 1593 } | 1500 } |
| 1594 | 1501 |
| 1595 | |
| 1596 RawScript* CodeBreakpoint::SourceCode() { | 1502 RawScript* CodeBreakpoint::SourceCode() { |
| 1597 const Function& func = Function::Handle(this->function()); | 1503 const Function& func = Function::Handle(this->function()); |
| 1598 return func.script(); | 1504 return func.script(); |
| 1599 } | 1505 } |
| 1600 | 1506 |
| 1601 | |
| 1602 RawString* CodeBreakpoint::SourceUrl() { | 1507 RawString* CodeBreakpoint::SourceUrl() { |
| 1603 const Script& script = Script::Handle(SourceCode()); | 1508 const Script& script = Script::Handle(SourceCode()); |
| 1604 return script.url(); | 1509 return script.url(); |
| 1605 } | 1510 } |
| 1606 | 1511 |
| 1607 | |
| 1608 intptr_t CodeBreakpoint::LineNumber() { | 1512 intptr_t CodeBreakpoint::LineNumber() { |
| 1609 // Compute line number lazily since it causes scanning of the script. | 1513 // Compute line number lazily since it causes scanning of the script. |
| 1610 if (line_number_ < 0) { | 1514 if (line_number_ < 0) { |
| 1611 const Script& script = Script::Handle(SourceCode()); | 1515 const Script& script = Script::Handle(SourceCode()); |
| 1612 script.GetTokenLocation(token_pos_, &line_number_, NULL); | 1516 script.GetTokenLocation(token_pos_, &line_number_, NULL); |
| 1613 } | 1517 } |
| 1614 return line_number_; | 1518 return line_number_; |
| 1615 } | 1519 } |
| 1616 | 1520 |
| 1617 | |
| 1618 void CodeBreakpoint::Enable() { | 1521 void CodeBreakpoint::Enable() { |
| 1619 if (!is_enabled_) { | 1522 if (!is_enabled_) { |
| 1620 PatchCode(); | 1523 PatchCode(); |
| 1621 } | 1524 } |
| 1622 ASSERT(is_enabled_); | 1525 ASSERT(is_enabled_); |
| 1623 } | 1526 } |
| 1624 | 1527 |
| 1625 | |
| 1626 void CodeBreakpoint::Disable() { | 1528 void CodeBreakpoint::Disable() { |
| 1627 if (is_enabled_) { | 1529 if (is_enabled_) { |
| 1628 RestoreCode(); | 1530 RestoreCode(); |
| 1629 } | 1531 } |
| 1630 ASSERT(!is_enabled_); | 1532 ASSERT(!is_enabled_); |
| 1631 } | 1533 } |
| 1632 | 1534 |
| 1633 | |
| 1634 RemoteObjectCache::RemoteObjectCache(intptr_t initial_size) { | 1535 RemoteObjectCache::RemoteObjectCache(intptr_t initial_size) { |
| 1635 objs_ = | 1536 objs_ = |
| 1636 &GrowableObjectArray::ZoneHandle(GrowableObjectArray::New(initial_size)); | 1537 &GrowableObjectArray::ZoneHandle(GrowableObjectArray::New(initial_size)); |
| 1637 } | 1538 } |
| 1638 | 1539 |
| 1639 | |
| 1640 intptr_t RemoteObjectCache::AddObject(const Object& obj) { | 1540 intptr_t RemoteObjectCache::AddObject(const Object& obj) { |
| 1641 intptr_t len = objs_->Length(); | 1541 intptr_t len = objs_->Length(); |
| 1642 for (intptr_t i = 0; i < len; i++) { | 1542 for (intptr_t i = 0; i < len; i++) { |
| 1643 if (objs_->At(i) == obj.raw()) { | 1543 if (objs_->At(i) == obj.raw()) { |
| 1644 return i; | 1544 return i; |
| 1645 } | 1545 } |
| 1646 } | 1546 } |
| 1647 objs_->Add(obj); | 1547 objs_->Add(obj); |
| 1648 return len; | 1548 return len; |
| 1649 } | 1549 } |
| 1650 | 1550 |
| 1651 | |
| 1652 RawObject* RemoteObjectCache::GetObj(intptr_t obj_id) const { | 1551 RawObject* RemoteObjectCache::GetObj(intptr_t obj_id) const { |
| 1653 ASSERT(IsValidId(obj_id)); | 1552 ASSERT(IsValidId(obj_id)); |
| 1654 return objs_->At(obj_id); | 1553 return objs_->At(obj_id); |
| 1655 } | 1554 } |
| 1656 | 1555 |
| 1657 | |
| 1658 Debugger::Debugger() | 1556 Debugger::Debugger() |
| 1659 : isolate_(NULL), | 1557 : isolate_(NULL), |
| 1660 isolate_id_(ILLEGAL_ISOLATE_ID), | 1558 isolate_id_(ILLEGAL_ISOLATE_ID), |
| 1661 initialized_(false), | 1559 initialized_(false), |
| 1662 next_id_(1), | 1560 next_id_(1), |
| 1663 latent_locations_(NULL), | 1561 latent_locations_(NULL), |
| 1664 breakpoint_locations_(NULL), | 1562 breakpoint_locations_(NULL), |
| 1665 code_breakpoints_(NULL), | 1563 code_breakpoints_(NULL), |
| 1666 resume_action_(kContinue), | 1564 resume_action_(kContinue), |
| 1667 resume_frame_index_(-1), | 1565 resume_frame_index_(-1), |
| 1668 post_deopt_frame_index_(-1), | 1566 post_deopt_frame_index_(-1), |
| 1669 ignore_breakpoints_(false), | 1567 ignore_breakpoints_(false), |
| 1670 pause_event_(NULL), | 1568 pause_event_(NULL), |
| 1671 obj_cache_(NULL), | 1569 obj_cache_(NULL), |
| 1672 stack_trace_(NULL), | 1570 stack_trace_(NULL), |
| 1673 async_causal_stack_trace_(NULL), | 1571 async_causal_stack_trace_(NULL), |
| 1674 awaiter_stack_trace_(NULL), | 1572 awaiter_stack_trace_(NULL), |
| 1675 stepping_fp_(0), | 1573 stepping_fp_(0), |
| 1676 async_stepping_fp_(0), | 1574 async_stepping_fp_(0), |
| 1677 top_frame_awaiter_(Object::null()), | 1575 top_frame_awaiter_(Object::null()), |
| 1678 skip_next_step_(false), | 1576 skip_next_step_(false), |
| 1679 needs_breakpoint_cleanup_(false), | 1577 needs_breakpoint_cleanup_(false), |
| 1680 synthetic_async_breakpoint_(NULL), | 1578 synthetic_async_breakpoint_(NULL), |
| 1681 exc_pause_info_(kNoPauseOnExceptions) {} | 1579 exc_pause_info_(kNoPauseOnExceptions) {} |
| 1682 | 1580 |
| 1683 | |
| 1684 Debugger::~Debugger() { | 1581 Debugger::~Debugger() { |
| 1685 isolate_id_ = ILLEGAL_ISOLATE_ID; | 1582 isolate_id_ = ILLEGAL_ISOLATE_ID; |
| 1686 ASSERT(!IsPaused()); | 1583 ASSERT(!IsPaused()); |
| 1687 ASSERT(latent_locations_ == NULL); | 1584 ASSERT(latent_locations_ == NULL); |
| 1688 ASSERT(breakpoint_locations_ == NULL); | 1585 ASSERT(breakpoint_locations_ == NULL); |
| 1689 ASSERT(code_breakpoints_ == NULL); | 1586 ASSERT(code_breakpoints_ == NULL); |
| 1690 ASSERT(stack_trace_ == NULL); | 1587 ASSERT(stack_trace_ == NULL); |
| 1691 ASSERT(async_causal_stack_trace_ == NULL); | 1588 ASSERT(async_causal_stack_trace_ == NULL); |
| 1692 ASSERT(obj_cache_ == NULL); | 1589 ASSERT(obj_cache_ == NULL); |
| 1693 ASSERT(synthetic_async_breakpoint_ == NULL); | 1590 ASSERT(synthetic_async_breakpoint_ == NULL); |
| 1694 } | 1591 } |
| 1695 | 1592 |
| 1696 | |
| 1697 void Debugger::Shutdown() { | 1593 void Debugger::Shutdown() { |
| 1698 // TODO(johnmccutchan): Do not create a debugger for isolates that don't need | 1594 // TODO(johnmccutchan): Do not create a debugger for isolates that don't need |
| 1699 // them. Then, assert here that isolate_ is not one of those isolates. | 1595 // them. Then, assert here that isolate_ is not one of those isolates. |
| 1700 if ((isolate_ == Dart::vm_isolate()) || | 1596 if ((isolate_ == Dart::vm_isolate()) || |
| 1701 ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { | 1597 ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { |
| 1702 return; | 1598 return; |
| 1703 } | 1599 } |
| 1704 while (breakpoint_locations_ != NULL) { | 1600 while (breakpoint_locations_ != NULL) { |
| 1705 BreakpointLocation* bpt = breakpoint_locations_; | 1601 BreakpointLocation* bpt = breakpoint_locations_; |
| 1706 breakpoint_locations_ = breakpoint_locations_->next(); | 1602 breakpoint_locations_ = breakpoint_locations_->next(); |
| 1707 delete bpt; | 1603 delete bpt; |
| 1708 } | 1604 } |
| 1709 while (latent_locations_ != NULL) { | 1605 while (latent_locations_ != NULL) { |
| 1710 BreakpointLocation* bpt = latent_locations_; | 1606 BreakpointLocation* bpt = latent_locations_; |
| 1711 latent_locations_ = latent_locations_->next(); | 1607 latent_locations_ = latent_locations_->next(); |
| 1712 delete bpt; | 1608 delete bpt; |
| 1713 } | 1609 } |
| 1714 while (code_breakpoints_ != NULL) { | 1610 while (code_breakpoints_ != NULL) { |
| 1715 CodeBreakpoint* bpt = code_breakpoints_; | 1611 CodeBreakpoint* bpt = code_breakpoints_; |
| 1716 code_breakpoints_ = code_breakpoints_->next(); | 1612 code_breakpoints_ = code_breakpoints_->next(); |
| 1717 bpt->Disable(); | 1613 bpt->Disable(); |
| 1718 delete bpt; | 1614 delete bpt; |
| 1719 } | 1615 } |
| 1720 if (NeedsIsolateEvents()) { | 1616 if (NeedsIsolateEvents()) { |
| 1721 ServiceEvent event(isolate_, ServiceEvent::kIsolateExit); | 1617 ServiceEvent event(isolate_, ServiceEvent::kIsolateExit); |
| 1722 InvokeEventHandler(&event); | 1618 InvokeEventHandler(&event); |
| 1723 } | 1619 } |
| 1724 } | 1620 } |
| 1725 | 1621 |
| 1726 | |
| 1727 void Debugger::OnIsolateRunnable() {} | 1622 void Debugger::OnIsolateRunnable() {} |
| 1728 | 1623 |
| 1729 | |
| 1730 static RawFunction* ResolveLibraryFunction(const Library& library, | 1624 static RawFunction* ResolveLibraryFunction(const Library& library, |
| 1731 const String& fname) { | 1625 const String& fname) { |
| 1732 ASSERT(!library.IsNull()); | 1626 ASSERT(!library.IsNull()); |
| 1733 const Object& object = Object::Handle(library.ResolveName(fname)); | 1627 const Object& object = Object::Handle(library.ResolveName(fname)); |
| 1734 if (!object.IsNull() && object.IsFunction()) { | 1628 if (!object.IsNull() && object.IsFunction()) { |
| 1735 return Function::Cast(object).raw(); | 1629 return Function::Cast(object).raw(); |
| 1736 } | 1630 } |
| 1737 return Function::null(); | 1631 return Function::null(); |
| 1738 } | 1632 } |
| 1739 | 1633 |
| 1740 | |
| 1741 bool Debugger::SetupStepOverAsyncSuspension(const char** error) { | 1634 bool Debugger::SetupStepOverAsyncSuspension(const char** error) { |
| 1742 ActivationFrame* top_frame = TopDartFrame(); | 1635 ActivationFrame* top_frame = TopDartFrame(); |
| 1743 if (!IsAtAsyncJump(top_frame)) { | 1636 if (!IsAtAsyncJump(top_frame)) { |
| 1744 // Not at an async operation. | 1637 // Not at an async operation. |
| 1745 if (error) { | 1638 if (error) { |
| 1746 *error = "Isolate must be paused at an async suspension point"; | 1639 *error = "Isolate must be paused at an async suspension point"; |
| 1747 } | 1640 } |
| 1748 return false; | 1641 return false; |
| 1749 } | 1642 } |
| 1750 Object& closure = Object::Handle(top_frame->GetAsyncOperation()); | 1643 Object& closure = Object::Handle(top_frame->GetAsyncOperation()); |
| 1751 ASSERT(!closure.IsNull()); | 1644 ASSERT(!closure.IsNull()); |
| 1752 ASSERT(closure.IsInstance()); | 1645 ASSERT(closure.IsInstance()); |
| 1753 ASSERT(Instance::Cast(closure).IsClosure()); | 1646 ASSERT(Instance::Cast(closure).IsClosure()); |
| 1754 Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true); | 1647 Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true); |
| 1755 if (bpt == NULL) { | 1648 if (bpt == NULL) { |
| 1756 // Unable to set the breakpoint. | 1649 // Unable to set the breakpoint. |
| 1757 if (error) { | 1650 if (error) { |
| 1758 *error = "Unable to set breakpoint at async suspension point"; | 1651 *error = "Unable to set breakpoint at async suspension point"; |
| 1759 } | 1652 } |
| 1760 return false; | 1653 return false; |
| 1761 } | 1654 } |
| 1762 return true; | 1655 return true; |
| 1763 } | 1656 } |
| 1764 | 1657 |
| 1765 | |
| 1766 bool Debugger::SetResumeAction(ResumeAction action, | 1658 bool Debugger::SetResumeAction(ResumeAction action, |
| 1767 intptr_t frame_index, | 1659 intptr_t frame_index, |
| 1768 const char** error) { | 1660 const char** error) { |
| 1769 if (error) { | 1661 if (error) { |
| 1770 *error = NULL; | 1662 *error = NULL; |
| 1771 } | 1663 } |
| 1772 resume_frame_index_ = -1; | 1664 resume_frame_index_ = -1; |
| 1773 switch (action) { | 1665 switch (action) { |
| 1774 case kStepInto: | 1666 case kStepInto: |
| 1775 case kStepOver: | 1667 case kStepOver: |
| 1776 case kStepOut: | 1668 case kStepOut: |
| 1777 case kContinue: | 1669 case kContinue: |
| 1778 resume_action_ = action; | 1670 resume_action_ = action; |
| 1779 return true; | 1671 return true; |
| 1780 case kStepRewind: | 1672 case kStepRewind: |
| 1781 if (!CanRewindFrame(frame_index, error)) { | 1673 if (!CanRewindFrame(frame_index, error)) { |
| 1782 return false; | 1674 return false; |
| 1783 } | 1675 } |
| 1784 resume_action_ = kStepRewind; | 1676 resume_action_ = kStepRewind; |
| 1785 resume_frame_index_ = frame_index; | 1677 resume_frame_index_ = frame_index; |
| 1786 return true; | 1678 return true; |
| 1787 case kStepOverAsyncSuspension: | 1679 case kStepOverAsyncSuspension: |
| 1788 return SetupStepOverAsyncSuspension(error); | 1680 return SetupStepOverAsyncSuspension(error); |
| 1789 default: | 1681 default: |
| 1790 UNREACHABLE(); | 1682 UNREACHABLE(); |
| 1791 return false; | 1683 return false; |
| 1792 } | 1684 } |
| 1793 } | 1685 } |
| 1794 | 1686 |
| 1795 | |
| 1796 RawFunction* Debugger::ResolveFunction(const Library& library, | 1687 RawFunction* Debugger::ResolveFunction(const Library& library, |
| 1797 const String& class_name, | 1688 const String& class_name, |
| 1798 const String& function_name) { | 1689 const String& function_name) { |
| 1799 ASSERT(!library.IsNull()); | 1690 ASSERT(!library.IsNull()); |
| 1800 ASSERT(!class_name.IsNull()); | 1691 ASSERT(!class_name.IsNull()); |
| 1801 ASSERT(!function_name.IsNull()); | 1692 ASSERT(!function_name.IsNull()); |
| 1802 if (class_name.Length() == 0) { | 1693 if (class_name.Length() == 0) { |
| 1803 return ResolveLibraryFunction(library, function_name); | 1694 return ResolveLibraryFunction(library, function_name); |
| 1804 } | 1695 } |
| 1805 const Class& cls = Class::Handle(library.LookupClass(class_name)); | 1696 const Class& cls = Class::Handle(library.LookupClass(class_name)); |
| 1806 Function& function = Function::Handle(); | 1697 Function& function = Function::Handle(); |
| 1807 if (!cls.IsNull()) { | 1698 if (!cls.IsNull()) { |
| 1808 function = cls.LookupStaticFunction(function_name); | 1699 function = cls.LookupStaticFunction(function_name); |
| 1809 if (function.IsNull()) { | 1700 if (function.IsNull()) { |
| 1810 function = cls.LookupDynamicFunction(function_name); | 1701 function = cls.LookupDynamicFunction(function_name); |
| 1811 } | 1702 } |
| 1812 } | 1703 } |
| 1813 return function.raw(); | 1704 return function.raw(); |
| 1814 } | 1705 } |
| 1815 | 1706 |
| 1816 | |
| 1817 // Deoptimize all functions in the isolate. | 1707 // Deoptimize all functions in the isolate. |
| 1818 // TODO(hausner): Actually we only need to deoptimize those functions | 1708 // TODO(hausner): Actually we only need to deoptimize those functions |
| 1819 // that inline the function that contains the newly created breakpoint. | 1709 // that inline the function that contains the newly created breakpoint. |
| 1820 // We currently don't have this info so we deoptimize all functions. | 1710 // We currently don't have this info so we deoptimize all functions. |
| 1821 void Debugger::DeoptimizeWorld() { | 1711 void Debugger::DeoptimizeWorld() { |
| 1822 BackgroundCompiler::Stop(isolate_); | 1712 BackgroundCompiler::Stop(isolate_); |
| 1823 DeoptimizeFunctionsOnStack(); | 1713 DeoptimizeFunctionsOnStack(); |
| 1824 // Iterate over all classes, deoptimize functions. | 1714 // Iterate over all classes, deoptimize functions. |
| 1825 // TODO(hausner): Could possibly be combined with RemoveOptimizedCode() | 1715 // TODO(hausner): Could possibly be combined with RemoveOptimizedCode() |
| 1826 const ClassTable& class_table = *isolate_->class_table(); | 1716 const ClassTable& class_table = *isolate_->class_table(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1860 const intptr_t num_closures = closures.Length(); | 1750 const intptr_t num_closures = closures.Length(); |
| 1861 for (intptr_t pos = 0; pos < num_closures; pos++) { | 1751 for (intptr_t pos = 0; pos < num_closures; pos++) { |
| 1862 function ^= closures.At(pos); | 1752 function ^= closures.At(pos); |
| 1863 ASSERT(!function.IsNull()); | 1753 ASSERT(!function.IsNull()); |
| 1864 if (function.HasOptimizedCode()) { | 1754 if (function.HasOptimizedCode()) { |
| 1865 function.SwitchToUnoptimizedCode(); | 1755 function.SwitchToUnoptimizedCode(); |
| 1866 } | 1756 } |
| 1867 } | 1757 } |
| 1868 } | 1758 } |
| 1869 | 1759 |
| 1870 | |
| 1871 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, | 1760 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, |
| 1872 uword pc, | 1761 uword pc, |
| 1873 StackFrame* frame, | 1762 StackFrame* frame, |
| 1874 const Code& code, | 1763 const Code& code, |
| 1875 const Array& deopt_frame, | 1764 const Array& deopt_frame, |
| 1876 intptr_t deopt_frame_offset, | 1765 intptr_t deopt_frame_offset, |
| 1877 ActivationFrame::Kind kind) { | 1766 ActivationFrame::Kind kind) { |
| 1878 ASSERT(code.ContainsInstructionAt(pc)); | 1767 ASSERT(code.ContainsInstructionAt(pc)); |
| 1879 ActivationFrame* activation = | 1768 ActivationFrame* activation = |
| 1880 new ActivationFrame(pc, frame->fp(), frame->sp(), code, deopt_frame, | 1769 new ActivationFrame(pc, frame->fp(), frame->sp(), code, deopt_frame, |
| 1881 deopt_frame_offset, kind); | 1770 deopt_frame_offset, kind); |
| 1882 if (FLAG_trace_debugger_stacktrace) { | 1771 if (FLAG_trace_debugger_stacktrace) { |
| 1883 const Context& ctx = activation->GetSavedCurrentContext(); | 1772 const Context& ctx = activation->GetSavedCurrentContext(); |
| 1884 OS::PrintErr("\tUsing saved context: %s\n", ctx.ToCString()); | 1773 OS::PrintErr("\tUsing saved context: %s\n", ctx.ToCString()); |
| 1885 } | 1774 } |
| 1886 if (FLAG_trace_debugger_stacktrace) { | 1775 if (FLAG_trace_debugger_stacktrace) { |
| 1887 OS::PrintErr("\tLine number: %" Pd "\n", activation->LineNumber()); | 1776 OS::PrintErr("\tLine number: %" Pd "\n", activation->LineNumber()); |
| 1888 } | 1777 } |
| 1889 return activation; | 1778 return activation; |
| 1890 } | 1779 } |
| 1891 | 1780 |
| 1892 | |
| 1893 RawArray* Debugger::DeoptimizeToArray(Thread* thread, | 1781 RawArray* Debugger::DeoptimizeToArray(Thread* thread, |
| 1894 StackFrame* frame, | 1782 StackFrame* frame, |
| 1895 const Code& code) { | 1783 const Code& code) { |
| 1896 ASSERT(code.is_optimized()); | 1784 ASSERT(code.is_optimized()); |
| 1897 Isolate* isolate = thread->isolate(); | 1785 Isolate* isolate = thread->isolate(); |
| 1898 // Create the DeoptContext for this deoptimization. | 1786 // Create the DeoptContext for this deoptimization. |
| 1899 DeoptContext* deopt_context = | 1787 DeoptContext* deopt_context = |
| 1900 new DeoptContext(frame, code, DeoptContext::kDestIsAllocated, NULL, NULL, | 1788 new DeoptContext(frame, code, DeoptContext::kDestIsAllocated, NULL, NULL, |
| 1901 true, false /* deoptimizing_code */); | 1789 true, false /* deoptimizing_code */); |
| 1902 isolate->set_deopt_context(deopt_context); | 1790 isolate->set_deopt_context(deopt_context); |
| 1903 | 1791 |
| 1904 deopt_context->FillDestFrame(); | 1792 deopt_context->FillDestFrame(); |
| 1905 deopt_context->MaterializeDeferredObjects(); | 1793 deopt_context->MaterializeDeferredObjects(); |
| 1906 const Array& dest_frame = | 1794 const Array& dest_frame = |
| 1907 Array::Handle(thread->zone(), deopt_context->DestFrameAsArray()); | 1795 Array::Handle(thread->zone(), deopt_context->DestFrameAsArray()); |
| 1908 | 1796 |
| 1909 isolate->set_deopt_context(NULL); | 1797 isolate->set_deopt_context(NULL); |
| 1910 delete deopt_context; | 1798 delete deopt_context; |
| 1911 | 1799 |
| 1912 return dest_frame.raw(); | 1800 return dest_frame.raw(); |
| 1913 } | 1801 } |
| 1914 | 1802 |
| 1915 | |
| 1916 DebuggerStackTrace* Debugger::CollectStackTrace() { | 1803 DebuggerStackTrace* Debugger::CollectStackTrace() { |
| 1917 Thread* thread = Thread::Current(); | 1804 Thread* thread = Thread::Current(); |
| 1918 Zone* zone = thread->zone(); | 1805 Zone* zone = thread->zone(); |
| 1919 Isolate* isolate = thread->isolate(); | 1806 Isolate* isolate = thread->isolate(); |
| 1920 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); | 1807 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
| 1921 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames, | 1808 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames, |
| 1922 Thread::Current(), | 1809 Thread::Current(), |
| 1923 StackFrameIterator::kNoCrossThreadIteration); | 1810 StackFrameIterator::kNoCrossThreadIteration); |
| 1924 Code& code = Code::Handle(zone); | 1811 Code& code = Code::Handle(zone); |
| 1925 Code& inlined_code = Code::Handle(zone); | 1812 Code& inlined_code = Code::Handle(zone); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1965 stack_trace->AddActivation(CollectDartFrame(isolate, it.pc(), frame, | 1852 stack_trace->AddActivation(CollectDartFrame(isolate, it.pc(), frame, |
| 1966 *inlined_code, *deopt_frame, | 1853 *inlined_code, *deopt_frame, |
| 1967 deopt_frame_offset)); | 1854 deopt_frame_offset)); |
| 1968 } | 1855 } |
| 1969 } else { | 1856 } else { |
| 1970 stack_trace->AddActivation(CollectDartFrame( | 1857 stack_trace->AddActivation(CollectDartFrame( |
| 1971 isolate, frame->pc(), frame, *code, Object::null_array(), 0)); | 1858 isolate, frame->pc(), frame, *code, Object::null_array(), 0)); |
| 1972 } | 1859 } |
| 1973 } | 1860 } |
| 1974 | 1861 |
| 1975 | |
| 1976 DebuggerStackTrace* Debugger::CollectAsyncCausalStackTrace() { | 1862 DebuggerStackTrace* Debugger::CollectAsyncCausalStackTrace() { |
| 1977 if (!FLAG_causal_async_stacks) { | 1863 if (!FLAG_causal_async_stacks) { |
| 1978 return NULL; | 1864 return NULL; |
| 1979 } | 1865 } |
| 1980 Thread* thread = Thread::Current(); | 1866 Thread* thread = Thread::Current(); |
| 1981 Zone* zone = thread->zone(); | 1867 Zone* zone = thread->zone(); |
| 1982 Isolate* isolate = thread->isolate(); | 1868 Isolate* isolate = thread->isolate(); |
| 1983 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); | 1869 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
| 1984 | 1870 |
| 1985 Code& code = Code::Handle(zone); | 1871 Code& code = Code::Handle(zone); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2051 } | 1937 } |
| 2052 } | 1938 } |
| 2053 } | 1939 } |
| 2054 // Follow the link. | 1940 // Follow the link. |
| 2055 async_stack_trace = async_stack_trace.async_link(); | 1941 async_stack_trace = async_stack_trace.async_link(); |
| 2056 } | 1942 } |
| 2057 | 1943 |
| 2058 return stack_trace; | 1944 return stack_trace; |
| 2059 } | 1945 } |
| 2060 | 1946 |
| 2061 | |
| 2062 DebuggerStackTrace* Debugger::CollectAwaiterReturnStackTrace() { | 1947 DebuggerStackTrace* Debugger::CollectAwaiterReturnStackTrace() { |
| 2063 if (!FLAG_async_debugger) { | 1948 if (!FLAG_async_debugger) { |
| 2064 return NULL; | 1949 return NULL; |
| 2065 } | 1950 } |
| 2066 // Causal async stacks are not supported in the AOT runtime. | 1951 // Causal async stacks are not supported in the AOT runtime. |
| 2067 ASSERT(!FLAG_precompiled_runtime); | 1952 ASSERT(!FLAG_precompiled_runtime); |
| 2068 | 1953 |
| 2069 Thread* thread = Thread::Current(); | 1954 Thread* thread = Thread::Current(); |
| 2070 Zone* zone = thread->zone(); | 1955 Zone* zone = thread->zone(); |
| 2071 Isolate* isolate = thread->isolate(); | 1956 Isolate* isolate = thread->isolate(); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2198 } | 2083 } |
| 2199 } | 2084 } |
| 2200 } | 2085 } |
| 2201 // Follow the link. | 2086 // Follow the link. |
| 2202 async_stack_trace = async_stack_trace.async_link(); | 2087 async_stack_trace = async_stack_trace.async_link(); |
| 2203 } | 2088 } |
| 2204 | 2089 |
| 2205 return stack_trace; | 2090 return stack_trace; |
| 2206 } | 2091 } |
| 2207 | 2092 |
| 2208 | |
| 2209 ActivationFrame* Debugger::TopDartFrame() const { | 2093 ActivationFrame* Debugger::TopDartFrame() const { |
| 2210 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames, | 2094 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames, |
| 2211 Thread::Current(), | 2095 Thread::Current(), |
| 2212 StackFrameIterator::kNoCrossThreadIteration); | 2096 StackFrameIterator::kNoCrossThreadIteration); |
| 2213 StackFrame* frame = iterator.NextFrame(); | 2097 StackFrame* frame = iterator.NextFrame(); |
| 2214 while ((frame != NULL) && !frame->IsDartFrame()) { | 2098 while ((frame != NULL) && !frame->IsDartFrame()) { |
| 2215 frame = iterator.NextFrame(); | 2099 frame = iterator.NextFrame(); |
| 2216 } | 2100 } |
| 2217 Code& code = Code::Handle(frame->LookupDartCode()); | 2101 Code& code = Code::Handle(frame->LookupDartCode()); |
| 2218 ActivationFrame* activation = new ActivationFrame( | 2102 ActivationFrame* activation = new ActivationFrame( |
| 2219 frame->pc(), frame->fp(), frame->sp(), code, Object::null_array(), 0); | 2103 frame->pc(), frame->fp(), frame->sp(), code, Object::null_array(), 0); |
| 2220 return activation; | 2104 return activation; |
| 2221 } | 2105 } |
| 2222 | 2106 |
| 2223 | |
| 2224 DebuggerStackTrace* Debugger::StackTrace() { | 2107 DebuggerStackTrace* Debugger::StackTrace() { |
| 2225 return (stack_trace_ != NULL) ? stack_trace_ : CollectStackTrace(); | 2108 return (stack_trace_ != NULL) ? stack_trace_ : CollectStackTrace(); |
| 2226 } | 2109 } |
| 2227 | 2110 |
| 2228 | |
| 2229 DebuggerStackTrace* Debugger::CurrentStackTrace() { | 2111 DebuggerStackTrace* Debugger::CurrentStackTrace() { |
| 2230 return CollectStackTrace(); | 2112 return CollectStackTrace(); |
| 2231 } | 2113 } |
| 2232 | 2114 |
| 2233 | |
| 2234 DebuggerStackTrace* Debugger::AsyncCausalStackTrace() { | 2115 DebuggerStackTrace* Debugger::AsyncCausalStackTrace() { |
| 2235 return (async_causal_stack_trace_ != NULL) ? async_causal_stack_trace_ | 2116 return (async_causal_stack_trace_ != NULL) ? async_causal_stack_trace_ |
| 2236 : CollectAsyncCausalStackTrace(); | 2117 : CollectAsyncCausalStackTrace(); |
| 2237 } | 2118 } |
| 2238 | 2119 |
| 2239 | |
| 2240 DebuggerStackTrace* Debugger::CurrentAsyncCausalStackTrace() { | 2120 DebuggerStackTrace* Debugger::CurrentAsyncCausalStackTrace() { |
| 2241 return CollectAsyncCausalStackTrace(); | 2121 return CollectAsyncCausalStackTrace(); |
| 2242 } | 2122 } |
| 2243 | 2123 |
| 2244 | |
| 2245 DebuggerStackTrace* Debugger::AwaiterStackTrace() { | 2124 DebuggerStackTrace* Debugger::AwaiterStackTrace() { |
| 2246 return (awaiter_stack_trace_ != NULL) ? awaiter_stack_trace_ | 2125 return (awaiter_stack_trace_ != NULL) ? awaiter_stack_trace_ |
| 2247 : CollectAwaiterReturnStackTrace(); | 2126 : CollectAwaiterReturnStackTrace(); |
| 2248 } | 2127 } |
| 2249 | 2128 |
| 2250 | |
| 2251 DebuggerStackTrace* Debugger::CurrentAwaiterStackTrace() { | 2129 DebuggerStackTrace* Debugger::CurrentAwaiterStackTrace() { |
| 2252 return CollectAwaiterReturnStackTrace(); | 2130 return CollectAwaiterReturnStackTrace(); |
| 2253 } | 2131 } |
| 2254 | 2132 |
| 2255 | |
| 2256 DebuggerStackTrace* Debugger::StackTraceFrom(const class StackTrace& ex_trace) { | 2133 DebuggerStackTrace* Debugger::StackTraceFrom(const class StackTrace& ex_trace) { |
| 2257 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); | 2134 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
| 2258 Function& function = Function::Handle(); | 2135 Function& function = Function::Handle(); |
| 2259 Code& code = Code::Handle(); | 2136 Code& code = Code::Handle(); |
| 2260 | 2137 |
| 2261 const uword fp = 0; | 2138 const uword fp = 0; |
| 2262 const uword sp = 0; | 2139 const uword sp = 0; |
| 2263 const Array& deopt_frame = Array::Handle(); | 2140 const Array& deopt_frame = Array::Handle(); |
| 2264 const intptr_t deopt_frame_offset = -1; | 2141 const intptr_t deopt_frame_offset = -1; |
| 2265 | 2142 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2298 ActivationFrame* activation = new ActivationFrame( | 2175 ActivationFrame* activation = new ActivationFrame( |
| 2299 pc, fp, sp, code, deopt_frame, deopt_frame_offset); | 2176 pc, fp, sp, code, deopt_frame, deopt_frame_offset); |
| 2300 stack_trace->AddActivation(activation); | 2177 stack_trace->AddActivation(activation); |
| 2301 } | 2178 } |
| 2302 } | 2179 } |
| 2303 } | 2180 } |
| 2304 } | 2181 } |
| 2305 return stack_trace; | 2182 return stack_trace; |
| 2306 } | 2183 } |
| 2307 | 2184 |
| 2308 | |
| 2309 void Debugger::SetExceptionPauseInfo(Dart_ExceptionPauseInfo pause_info) { | 2185 void Debugger::SetExceptionPauseInfo(Dart_ExceptionPauseInfo pause_info) { |
| 2310 ASSERT((pause_info == kNoPauseOnExceptions) || | 2186 ASSERT((pause_info == kNoPauseOnExceptions) || |
| 2311 (pause_info == kPauseOnUnhandledExceptions) || | 2187 (pause_info == kPauseOnUnhandledExceptions) || |
| 2312 (pause_info == kPauseOnAllExceptions)); | 2188 (pause_info == kPauseOnAllExceptions)); |
| 2313 exc_pause_info_ = pause_info; | 2189 exc_pause_info_ = pause_info; |
| 2314 } | 2190 } |
| 2315 | 2191 |
| 2316 | |
| 2317 Dart_ExceptionPauseInfo Debugger::GetExceptionPauseInfo() const { | 2192 Dart_ExceptionPauseInfo Debugger::GetExceptionPauseInfo() const { |
| 2318 return exc_pause_info_; | 2193 return exc_pause_info_; |
| 2319 } | 2194 } |
| 2320 | 2195 |
| 2321 | |
| 2322 bool Debugger::ShouldPauseOnException(DebuggerStackTrace* stack_trace, | 2196 bool Debugger::ShouldPauseOnException(DebuggerStackTrace* stack_trace, |
| 2323 const Instance& exception) { | 2197 const Instance& exception) { |
| 2324 if (exc_pause_info_ == kNoPauseOnExceptions) { | 2198 if (exc_pause_info_ == kNoPauseOnExceptions) { |
| 2325 return false; | 2199 return false; |
| 2326 } | 2200 } |
| 2327 if (exc_pause_info_ == kPauseOnAllExceptions) { | 2201 if (exc_pause_info_ == kPauseOnAllExceptions) { |
| 2328 return true; | 2202 return true; |
| 2329 } | 2203 } |
| 2330 ASSERT(exc_pause_info_ == kPauseOnUnhandledExceptions); | 2204 ASSERT(exc_pause_info_ == kPauseOnUnhandledExceptions); |
| 2331 ActivationFrame* handler_frame = stack_trace->GetHandlerFrame(exception); | 2205 ActivationFrame* handler_frame = stack_trace->GetHandlerFrame(exception); |
| 2332 if (handler_frame == NULL) { | 2206 if (handler_frame == NULL) { |
| 2333 // Did not find an exception handler that catches this exception. | 2207 // Did not find an exception handler that catches this exception. |
| 2334 // Note that this check is not precise, since we can't check | 2208 // Note that this check is not precise, since we can't check |
| 2335 // uninstantiated types, i.e. types containing type parameters. | 2209 // uninstantiated types, i.e. types containing type parameters. |
| 2336 // Thus, we may report an exception as unhandled when in fact | 2210 // Thus, we may report an exception as unhandled when in fact |
| 2337 // it will be caught once we unwind the stack. | 2211 // it will be caught once we unwind the stack. |
| 2338 return true; | 2212 return true; |
| 2339 } | 2213 } |
| 2340 return false; | 2214 return false; |
| 2341 } | 2215 } |
| 2342 | 2216 |
| 2343 | |
| 2344 void Debugger::PauseException(const Instance& exc) { | 2217 void Debugger::PauseException(const Instance& exc) { |
| 2345 if (FLAG_stress_async_stacks) { | 2218 if (FLAG_stress_async_stacks) { |
| 2346 CollectAwaiterReturnStackTrace(); | 2219 CollectAwaiterReturnStackTrace(); |
| 2347 } | 2220 } |
| 2348 // We ignore this exception event when the VM is executing code invoked | 2221 // We ignore this exception event when the VM is executing code invoked |
| 2349 // by the debugger to evaluate variables values, when we see a nested | 2222 // by the debugger to evaluate variables values, when we see a nested |
| 2350 // breakpoint or exception event, or if the debugger is not | 2223 // breakpoint or exception event, or if the debugger is not |
| 2351 // interested in exception events. | 2224 // interested in exception events. |
| 2352 if (ignore_breakpoints_ || IsPaused() || | 2225 if (ignore_breakpoints_ || IsPaused() || |
| 2353 (exc_pause_info_ == kNoPauseOnExceptions)) { | 2226 (exc_pause_info_ == kNoPauseOnExceptions)) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2369 if (stack_trace->Length() > 0) { | 2242 if (stack_trace->Length() > 0) { |
| 2370 event.set_top_frame(stack_trace->FrameAt(0)); | 2243 event.set_top_frame(stack_trace->FrameAt(0)); |
| 2371 } | 2244 } |
| 2372 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace(), | 2245 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace(), |
| 2373 CollectAwaiterReturnStackTrace()); | 2246 CollectAwaiterReturnStackTrace()); |
| 2374 Pause(&event); | 2247 Pause(&event); |
| 2375 HandleSteppingRequest(stack_trace_); // we may get a rewind request | 2248 HandleSteppingRequest(stack_trace_); // we may get a rewind request |
| 2376 ClearCachedStackTraces(); | 2249 ClearCachedStackTraces(); |
| 2377 } | 2250 } |
| 2378 | 2251 |
| 2379 | |
| 2380 static TokenPosition LastTokenOnLine(Zone* zone, | 2252 static TokenPosition LastTokenOnLine(Zone* zone, |
| 2381 const TokenStream& tokens, | 2253 const TokenStream& tokens, |
| 2382 TokenPosition pos) { | 2254 TokenPosition pos) { |
| 2383 TokenStream::Iterator iter(zone, tokens, pos, | 2255 TokenStream::Iterator iter(zone, tokens, pos, |
| 2384 TokenStream::Iterator::kAllTokens); | 2256 TokenStream::Iterator::kAllTokens); |
| 2385 ASSERT(iter.IsValid()); | 2257 ASSERT(iter.IsValid()); |
| 2386 TokenPosition last_pos = pos; | 2258 TokenPosition last_pos = pos; |
| 2387 while ((iter.CurrentTokenKind() != Token::kNEWLINE) && | 2259 while ((iter.CurrentTokenKind() != Token::kNEWLINE) && |
| 2388 (iter.CurrentTokenKind() != Token::kEOS)) { | 2260 (iter.CurrentTokenKind() != Token::kEOS)) { |
| 2389 last_pos = iter.CurrentPosition(); | 2261 last_pos = iter.CurrentPosition(); |
| 2390 iter.Advance(); | 2262 iter.Advance(); |
| 2391 } | 2263 } |
| 2392 return last_pos; | 2264 return last_pos; |
| 2393 } | 2265 } |
| 2394 | 2266 |
| 2395 | |
| 2396 // Returns the best fit token position for a breakpoint. | 2267 // Returns the best fit token position for a breakpoint. |
| 2397 // | 2268 // |
| 2398 // Takes a range of tokens [requested_token_pos, last_token_pos] and | 2269 // Takes a range of tokens [requested_token_pos, last_token_pos] and |
| 2399 // an optional column (requested_column). The range of tokens usually | 2270 // an optional column (requested_column). The range of tokens usually |
| 2400 // represents one line of the program text, but can represent a larger | 2271 // represents one line of the program text, but can represent a larger |
| 2401 // range on recursive calls. | 2272 // range on recursive calls. |
| 2402 // | 2273 // |
| 2403 // The best fit is found in two passes. | 2274 // The best fit is found in two passes. |
| 2404 // | 2275 // |
| 2405 // The first pass finds a candidate token which: | 2276 // The first pass finds a candidate token which: |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2568 // find a safe point in the remaining source code of the function. | 2439 // find a safe point in the remaining source code of the function. |
| 2569 // Since we have moved to the next line of the function, we no | 2440 // Since we have moved to the next line of the function, we no |
| 2570 // longer are requesting a specific column number. | 2441 // longer are requesting a specific column number. |
| 2571 if (last_token_pos < func.end_token_pos()) { | 2442 if (last_token_pos < func.end_token_pos()) { |
| 2572 return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos(), | 2443 return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos(), |
| 2573 -1 /* no column */); | 2444 -1 /* no column */); |
| 2574 } | 2445 } |
| 2575 return TokenPosition::kNoSource; | 2446 return TokenPosition::kNoSource; |
| 2576 } | 2447 } |
| 2577 | 2448 |
| 2578 | |
| 2579 void Debugger::MakeCodeBreakpointAt(const Function& func, | 2449 void Debugger::MakeCodeBreakpointAt(const Function& func, |
| 2580 BreakpointLocation* loc) { | 2450 BreakpointLocation* loc) { |
| 2581 ASSERT(loc->token_pos_.IsReal()); | 2451 ASSERT(loc->token_pos_.IsReal()); |
| 2582 ASSERT((loc != NULL) && loc->IsResolved()); | 2452 ASSERT((loc != NULL) && loc->IsResolved()); |
| 2583 ASSERT(!func.HasOptimizedCode()); | 2453 ASSERT(!func.HasOptimizedCode()); |
| 2584 Code& code = Code::Handle(func.unoptimized_code()); | 2454 Code& code = Code::Handle(func.unoptimized_code()); |
| 2585 ASSERT(!code.IsNull()); | 2455 ASSERT(!code.IsNull()); |
| 2586 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 2456 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 2587 uword lowest_pc_offset = kUwordMax; | 2457 uword lowest_pc_offset = kUwordMax; |
| 2588 RawPcDescriptors::Kind lowest_kind = RawPcDescriptors::kAnyKind; | 2458 RawPcDescriptors::Kind lowest_kind = RawPcDescriptors::kAnyKind; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2607 code_bpt = | 2477 code_bpt = |
| 2608 new CodeBreakpoint(code, loc->token_pos_, lowest_pc, lowest_kind); | 2478 new CodeBreakpoint(code, loc->token_pos_, lowest_pc, lowest_kind); |
| 2609 RegisterCodeBreakpoint(code_bpt); | 2479 RegisterCodeBreakpoint(code_bpt); |
| 2610 } | 2480 } |
| 2611 code_bpt->set_bpt_location(loc); | 2481 code_bpt->set_bpt_location(loc); |
| 2612 if (loc->AnyEnabled()) { | 2482 if (loc->AnyEnabled()) { |
| 2613 code_bpt->Enable(); | 2483 code_bpt->Enable(); |
| 2614 } | 2484 } |
| 2615 } | 2485 } |
| 2616 | 2486 |
| 2617 | |
| 2618 void Debugger::FindCompiledFunctions(const Script& script, | 2487 void Debugger::FindCompiledFunctions(const Script& script, |
| 2619 TokenPosition start_pos, | 2488 TokenPosition start_pos, |
| 2620 TokenPosition end_pos, | 2489 TokenPosition end_pos, |
| 2621 GrowableObjectArray* function_list) { | 2490 GrowableObjectArray* function_list) { |
| 2622 Zone* zone = Thread::Current()->zone(); | 2491 Zone* zone = Thread::Current()->zone(); |
| 2623 Class& cls = Class::Handle(zone); | 2492 Class& cls = Class::Handle(zone); |
| 2624 Array& functions = Array::Handle(zone); | 2493 Array& functions = Array::Handle(zone); |
| 2625 GrowableObjectArray& closures = GrowableObjectArray::Handle(zone); | 2494 GrowableObjectArray& closures = GrowableObjectArray::Handle(zone); |
| 2626 Function& function = Function::Handle(zone); | 2495 Function& function = Function::Handle(zone); |
| 2627 | 2496 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2680 function_list->Add(function); | 2549 function_list->Add(function); |
| 2681 } | 2550 } |
| 2682 } | 2551 } |
| 2683 } | 2552 } |
| 2684 } | 2553 } |
| 2685 } | 2554 } |
| 2686 } | 2555 } |
| 2687 } | 2556 } |
| 2688 } | 2557 } |
| 2689 | 2558 |
| 2690 | |
| 2691 static void SelectBestFit(Function* best_fit, Function* func) { | 2559 static void SelectBestFit(Function* best_fit, Function* func) { |
| 2692 if (best_fit->IsNull()) { | 2560 if (best_fit->IsNull()) { |
| 2693 *best_fit = func->raw(); | 2561 *best_fit = func->raw(); |
| 2694 } else { | 2562 } else { |
| 2695 if ((func->token_pos() > best_fit->token_pos()) && | 2563 if ((func->token_pos() > best_fit->token_pos()) && |
| 2696 ((func->end_token_pos() <= best_fit->end_token_pos()))) { | 2564 ((func->end_token_pos() <= best_fit->end_token_pos()))) { |
| 2697 *best_fit = func->raw(); | 2565 *best_fit = func->raw(); |
| 2698 } | 2566 } |
| 2699 } | 2567 } |
| 2700 } | 2568 } |
| 2701 | 2569 |
| 2702 | |
| 2703 // Returns true if a best fit is found. A best fit can either be a function | 2570 // Returns true if a best fit is found. A best fit can either be a function |
| 2704 // or a field. If it is a function, then the best fit function is returned | 2571 // or a field. If it is a function, then the best fit function is returned |
| 2705 // in |best_fit|. If a best fit is a field, it means that a latent | 2572 // in |best_fit|. If a best fit is a field, it means that a latent |
| 2706 // breakpoint can be set in the range |token_pos| to |last_token_pos|. | 2573 // breakpoint can be set in the range |token_pos| to |last_token_pos|. |
| 2707 bool Debugger::FindBestFit(const Script& script, | 2574 bool Debugger::FindBestFit(const Script& script, |
| 2708 TokenPosition token_pos, | 2575 TokenPosition token_pos, |
| 2709 TokenPosition last_token_pos, | 2576 TokenPosition last_token_pos, |
| 2710 Function* best_fit) { | 2577 Function* best_fit) { |
| 2711 Zone* zone = Thread::Current()->zone(); | 2578 Zone* zone = Thread::Current()->zone(); |
| 2712 Class& cls = Class::Handle(zone); | 2579 Class& cls = Class::Handle(zone); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2800 (token_pos <= start && start <= last_token_pos)) { | 2667 (token_pos <= start && start <= last_token_pos)) { |
| 2801 return true; | 2668 return true; |
| 2802 } | 2669 } |
| 2803 } | 2670 } |
| 2804 } | 2671 } |
| 2805 } | 2672 } |
| 2806 } | 2673 } |
| 2807 return false; | 2674 return false; |
| 2808 } | 2675 } |
| 2809 | 2676 |
| 2810 | |
| 2811 BreakpointLocation* Debugger::SetBreakpoint(const Script& script, | 2677 BreakpointLocation* Debugger::SetBreakpoint(const Script& script, |
| 2812 TokenPosition token_pos, | 2678 TokenPosition token_pos, |
| 2813 TokenPosition last_token_pos, | 2679 TokenPosition last_token_pos, |
| 2814 intptr_t requested_line, | 2680 intptr_t requested_line, |
| 2815 intptr_t requested_column) { | 2681 intptr_t requested_column) { |
| 2816 Function& func = Function::Handle(); | 2682 Function& func = Function::Handle(); |
| 2817 if (!FindBestFit(script, token_pos, last_token_pos, &func)) { | 2683 if (!FindBestFit(script, token_pos, last_token_pos, &func)) { |
| 2818 return NULL; | 2684 return NULL; |
| 2819 } | 2685 } |
| 2820 if (!func.IsNull()) { | 2686 if (!func.IsNull()) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2889 BreakpointLocation* bpt = | 2755 BreakpointLocation* bpt = |
| 2890 GetBreakpointLocation(script, token_pos, requested_column); | 2756 GetBreakpointLocation(script, token_pos, requested_column); |
| 2891 if (bpt == NULL) { | 2757 if (bpt == NULL) { |
| 2892 bpt = new BreakpointLocation(script, token_pos, last_token_pos, | 2758 bpt = new BreakpointLocation(script, token_pos, last_token_pos, |
| 2893 requested_line, requested_column); | 2759 requested_line, requested_column); |
| 2894 RegisterBreakpointLocation(bpt); | 2760 RegisterBreakpointLocation(bpt); |
| 2895 } | 2761 } |
| 2896 return bpt; | 2762 return bpt; |
| 2897 } | 2763 } |
| 2898 | 2764 |
| 2899 | |
| 2900 // Synchronize the enabled/disabled state of all code breakpoints | 2765 // Synchronize the enabled/disabled state of all code breakpoints |
| 2901 // associated with the breakpoint location loc. | 2766 // associated with the breakpoint location loc. |
| 2902 void Debugger::SyncBreakpointLocation(BreakpointLocation* loc) { | 2767 void Debugger::SyncBreakpointLocation(BreakpointLocation* loc) { |
| 2903 bool any_enabled = loc->AnyEnabled(); | 2768 bool any_enabled = loc->AnyEnabled(); |
| 2904 | 2769 |
| 2905 CodeBreakpoint* cbpt = code_breakpoints_; | 2770 CodeBreakpoint* cbpt = code_breakpoints_; |
| 2906 while (cbpt != NULL) { | 2771 while (cbpt != NULL) { |
| 2907 if (loc == cbpt->bpt_location()) { | 2772 if (loc == cbpt->bpt_location()) { |
| 2908 if (any_enabled) { | 2773 if (any_enabled) { |
| 2909 cbpt->Enable(); | 2774 cbpt->Enable(); |
| 2910 } else { | 2775 } else { |
| 2911 cbpt->Disable(); | 2776 cbpt->Disable(); |
| 2912 } | 2777 } |
| 2913 } | 2778 } |
| 2914 cbpt = cbpt->next(); | 2779 cbpt = cbpt->next(); |
| 2915 } | 2780 } |
| 2916 } | 2781 } |
| 2917 | 2782 |
| 2918 | |
| 2919 RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) { | 2783 RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) { |
| 2920 LongJumpScope jump; | 2784 LongJumpScope jump; |
| 2921 if (setjmp(*jump.Set()) == 0) { | 2785 if (setjmp(*jump.Set()) == 0) { |
| 2922 SetBreakpointAtEntry(target_function, true); | 2786 SetBreakpointAtEntry(target_function, true); |
| 2923 return Error::null(); | 2787 return Error::null(); |
| 2924 } else { | 2788 } else { |
| 2925 return Thread::Current()->sticky_error(); | 2789 return Thread::Current()->sticky_error(); |
| 2926 } | 2790 } |
| 2927 } | 2791 } |
| 2928 | 2792 |
| 2929 | |
| 2930 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function, | 2793 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function, |
| 2931 bool single_shot) { | 2794 bool single_shot) { |
| 2932 ASSERT(!target_function.IsNull()); | 2795 ASSERT(!target_function.IsNull()); |
| 2933 if (!target_function.is_debuggable()) { | 2796 if (!target_function.is_debuggable()) { |
| 2934 return NULL; | 2797 return NULL; |
| 2935 } | 2798 } |
| 2936 const Script& script = Script::Handle(target_function.script()); | 2799 const Script& script = Script::Handle(target_function.script()); |
| 2937 BreakpointLocation* bpt_location = SetBreakpoint( | 2800 BreakpointLocation* bpt_location = SetBreakpoint( |
| 2938 script, target_function.token_pos(), target_function.end_token_pos(), -1, | 2801 script, target_function.token_pos(), target_function.end_token_pos(), -1, |
| 2939 -1 /* no requested line/col */); | 2802 -1 /* no requested line/col */); |
| 2940 if (single_shot) { | 2803 if (single_shot) { |
| 2941 return bpt_location->AddSingleShot(this); | 2804 return bpt_location->AddSingleShot(this); |
| 2942 } else { | 2805 } else { |
| 2943 return bpt_location->AddRepeated(this); | 2806 return bpt_location->AddRepeated(this); |
| 2944 } | 2807 } |
| 2945 } | 2808 } |
| 2946 | 2809 |
| 2947 | |
| 2948 Breakpoint* Debugger::SetBreakpointAtActivation(const Instance& closure, | 2810 Breakpoint* Debugger::SetBreakpointAtActivation(const Instance& closure, |
| 2949 bool for_over_await) { | 2811 bool for_over_await) { |
| 2950 if (!closure.IsClosure()) { | 2812 if (!closure.IsClosure()) { |
| 2951 return NULL; | 2813 return NULL; |
| 2952 } | 2814 } |
| 2953 const Function& func = Function::Handle(Closure::Cast(closure).function()); | 2815 const Function& func = Function::Handle(Closure::Cast(closure).function()); |
| 2954 const Script& script = Script::Handle(func.script()); | 2816 const Script& script = Script::Handle(func.script()); |
| 2955 BreakpointLocation* bpt_location = SetBreakpoint( | 2817 BreakpointLocation* bpt_location = SetBreakpoint( |
| 2956 script, func.token_pos(), func.end_token_pos(), -1, -1 /* no line/col */); | 2818 script, func.token_pos(), func.end_token_pos(), -1, -1 /* no line/col */); |
| 2957 return bpt_location->AddPerClosure(this, closure, for_over_await); | 2819 return bpt_location->AddPerClosure(this, closure, for_over_await); |
| 2958 } | 2820 } |
| 2959 | 2821 |
| 2960 | |
| 2961 Breakpoint* Debugger::BreakpointAtActivation(const Instance& closure) { | 2822 Breakpoint* Debugger::BreakpointAtActivation(const Instance& closure) { |
| 2962 if (!closure.IsClosure()) { | 2823 if (!closure.IsClosure()) { |
| 2963 return NULL; | 2824 return NULL; |
| 2964 } | 2825 } |
| 2965 | 2826 |
| 2966 BreakpointLocation* loc = breakpoint_locations_; | 2827 BreakpointLocation* loc = breakpoint_locations_; |
| 2967 while (loc != NULL) { | 2828 while (loc != NULL) { |
| 2968 Breakpoint* bpt = loc->breakpoints(); | 2829 Breakpoint* bpt = loc->breakpoints(); |
| 2969 while (bpt != NULL) { | 2830 while (bpt != NULL) { |
| 2970 if (bpt->IsPerClosure()) { | 2831 if (bpt->IsPerClosure()) { |
| 2971 if (closure.raw() == bpt->closure()) { | 2832 if (closure.raw() == bpt->closure()) { |
| 2972 return bpt; | 2833 return bpt; |
| 2973 } | 2834 } |
| 2974 } | 2835 } |
| 2975 bpt = bpt->next(); | 2836 bpt = bpt->next(); |
| 2976 } | 2837 } |
| 2977 loc = loc->next(); | 2838 loc = loc->next(); |
| 2978 } | 2839 } |
| 2979 | 2840 |
| 2980 return NULL; | 2841 return NULL; |
| 2981 } | 2842 } |
| 2982 | 2843 |
| 2983 | |
| 2984 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 2844 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, |
| 2985 intptr_t line_number) { | 2845 intptr_t line_number) { |
| 2986 // Prevent future tests from calling this function in the wrong | 2846 // Prevent future tests from calling this function in the wrong |
| 2987 // execution state. If you hit this assert, consider using | 2847 // execution state. If you hit this assert, consider using |
| 2988 // Dart_SetBreakpoint instead. | 2848 // Dart_SetBreakpoint instead. |
| 2989 ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM); | 2849 ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM); |
| 2990 | 2850 |
| 2991 BreakpointLocation* loc = | 2851 BreakpointLocation* loc = |
| 2992 BreakpointLocationAtLineCol(script_url, line_number, -1 /* no column */); | 2852 BreakpointLocationAtLineCol(script_url, line_number, -1 /* no column */); |
| 2993 if (loc != NULL) { | 2853 if (loc != NULL) { |
| 2994 return loc->AddRepeated(this); | 2854 return loc->AddRepeated(this); |
| 2995 } | 2855 } |
| 2996 return NULL; | 2856 return NULL; |
| 2997 } | 2857 } |
| 2998 | 2858 |
| 2999 | |
| 3000 Breakpoint* Debugger::SetBreakpointAtLineCol(const String& script_url, | 2859 Breakpoint* Debugger::SetBreakpointAtLineCol(const String& script_url, |
| 3001 intptr_t line_number, | 2860 intptr_t line_number, |
| 3002 intptr_t column_number) { | 2861 intptr_t column_number) { |
| 3003 // Prevent future tests from calling this function in the wrong | 2862 // Prevent future tests from calling this function in the wrong |
| 3004 // execution state. If you hit this assert, consider using | 2863 // execution state. If you hit this assert, consider using |
| 3005 // Dart_SetBreakpoint instead. | 2864 // Dart_SetBreakpoint instead. |
| 3006 ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM); | 2865 ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM); |
| 3007 | 2866 |
| 3008 BreakpointLocation* loc = | 2867 BreakpointLocation* loc = |
| 3009 BreakpointLocationAtLineCol(script_url, line_number, column_number); | 2868 BreakpointLocationAtLineCol(script_url, line_number, column_number); |
| 3010 if (loc != NULL) { | 2869 if (loc != NULL) { |
| 3011 return loc->AddRepeated(this); | 2870 return loc->AddRepeated(this); |
| 3012 } | 2871 } |
| 3013 return NULL; | 2872 return NULL; |
| 3014 } | 2873 } |
| 3015 | 2874 |
| 3016 | |
| 3017 BreakpointLocation* Debugger::BreakpointLocationAtLineCol( | 2875 BreakpointLocation* Debugger::BreakpointLocationAtLineCol( |
| 3018 const String& script_url, | 2876 const String& script_url, |
| 3019 intptr_t line_number, | 2877 intptr_t line_number, |
| 3020 intptr_t column_number) { | 2878 intptr_t column_number) { |
| 3021 Zone* zone = Thread::Current()->zone(); | 2879 Zone* zone = Thread::Current()->zone(); |
| 3022 Library& lib = Library::Handle(zone); | 2880 Library& lib = Library::Handle(zone); |
| 3023 Script& script = Script::Handle(zone); | 2881 Script& script = Script::Handle(zone); |
| 3024 const GrowableObjectArray& libs = | 2882 const GrowableObjectArray& libs = |
| 3025 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); | 2883 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
| 3026 const GrowableObjectArray& scripts = | 2884 const GrowableObjectArray& scripts = |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3077 column_number); | 2935 column_number); |
| 3078 first_token_idx.Next(); | 2936 first_token_idx.Next(); |
| 3079 } | 2937 } |
| 3080 if ((bpt == NULL) && FLAG_verbose_debug) { | 2938 if ((bpt == NULL) && FLAG_verbose_debug) { |
| 3081 OS::Print("No executable code at line %" Pd " in '%s'\n", line_number, | 2939 OS::Print("No executable code at line %" Pd " in '%s'\n", line_number, |
| 3082 script_url.ToCString()); | 2940 script_url.ToCString()); |
| 3083 } | 2941 } |
| 3084 return bpt; | 2942 return bpt; |
| 3085 } | 2943 } |
| 3086 | 2944 |
| 3087 | |
| 3088 intptr_t Debugger::CacheObject(const Object& obj) { | 2945 intptr_t Debugger::CacheObject(const Object& obj) { |
| 3089 ASSERT(obj_cache_ != NULL); | 2946 ASSERT(obj_cache_ != NULL); |
| 3090 return obj_cache_->AddObject(obj); | 2947 return obj_cache_->AddObject(obj); |
| 3091 } | 2948 } |
| 3092 | 2949 |
| 3093 | |
| 3094 bool Debugger::IsValidObjectId(intptr_t obj_id) { | 2950 bool Debugger::IsValidObjectId(intptr_t obj_id) { |
| 3095 ASSERT(obj_cache_ != NULL); | 2951 ASSERT(obj_cache_ != NULL); |
| 3096 return obj_cache_->IsValidId(obj_id); | 2952 return obj_cache_->IsValidId(obj_id); |
| 3097 } | 2953 } |
| 3098 | 2954 |
| 3099 | |
| 3100 RawObject* Debugger::GetCachedObject(intptr_t obj_id) { | 2955 RawObject* Debugger::GetCachedObject(intptr_t obj_id) { |
| 3101 ASSERT(obj_cache_ != NULL); | 2956 ASSERT(obj_cache_ != NULL); |
| 3102 return obj_cache_->GetObj(obj_id); | 2957 return obj_cache_->GetObj(obj_id); |
| 3103 } | 2958 } |
| 3104 | 2959 |
| 3105 // TODO(hausner): Merge some of this functionality with the code in | 2960 // TODO(hausner): Merge some of this functionality with the code in |
| 3106 // dart_api_impl.cc. | 2961 // dart_api_impl.cc. |
| 3107 RawObject* Debugger::GetInstanceField(const Class& cls, | 2962 RawObject* Debugger::GetInstanceField(const Class& cls, |
| 3108 const String& field_name, | 2963 const String& field_name, |
| 3109 const Instance& object) { | 2964 const Instance& object) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3120 const Array& args = Array::Handle(Array::New(1)); | 2975 const Array& args = Array::Handle(Array::New(1)); |
| 3121 args.SetAt(0, object); | 2976 args.SetAt(0, object); |
| 3122 result = DartEntry::InvokeFunction(getter_func, args); | 2977 result = DartEntry::InvokeFunction(getter_func, args); |
| 3123 } else { | 2978 } else { |
| 3124 result = Thread::Current()->sticky_error(); | 2979 result = Thread::Current()->sticky_error(); |
| 3125 } | 2980 } |
| 3126 ignore_breakpoints_ = saved_ignore_flag; | 2981 ignore_breakpoints_ = saved_ignore_flag; |
| 3127 return result.raw(); | 2982 return result.raw(); |
| 3128 } | 2983 } |
| 3129 | 2984 |
| 3130 | |
| 3131 RawObject* Debugger::GetStaticField(const Class& cls, | 2985 RawObject* Debugger::GetStaticField(const Class& cls, |
| 3132 const String& field_name) { | 2986 const String& field_name) { |
| 3133 const Field& fld = | 2987 const Field& fld = |
| 3134 Field::Handle(cls.LookupStaticFieldAllowPrivate(field_name)); | 2988 Field::Handle(cls.LookupStaticFieldAllowPrivate(field_name)); |
| 3135 if (!fld.IsNull()) { | 2989 if (!fld.IsNull()) { |
| 3136 // Return the value in the field if it has been initialized already. | 2990 // Return the value in the field if it has been initialized already. |
| 3137 const Instance& value = Instance::Handle(fld.StaticValue()); | 2991 const Instance& value = Instance::Handle(fld.StaticValue()); |
| 3138 ASSERT(value.raw() != Object::transition_sentinel().raw()); | 2992 ASSERT(value.raw() != Object::transition_sentinel().raw()); |
| 3139 if (value.raw() != Object::sentinel().raw()) { | 2993 if (value.raw() != Object::sentinel().raw()) { |
| 3140 return value.raw(); | 2994 return value.raw(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3155 LongJumpScope jump; | 3009 LongJumpScope jump; |
| 3156 if (setjmp(*jump.Set()) == 0) { | 3010 if (setjmp(*jump.Set()) == 0) { |
| 3157 result = DartEntry::InvokeFunction(getter_func, Object::empty_array()); | 3011 result = DartEntry::InvokeFunction(getter_func, Object::empty_array()); |
| 3158 } else { | 3012 } else { |
| 3159 result = Thread::Current()->sticky_error(); | 3013 result = Thread::Current()->sticky_error(); |
| 3160 } | 3014 } |
| 3161 ignore_breakpoints_ = saved_ignore_flag; | 3015 ignore_breakpoints_ = saved_ignore_flag; |
| 3162 return result.raw(); | 3016 return result.raw(); |
| 3163 } | 3017 } |
| 3164 | 3018 |
| 3165 | |
| 3166 RawArray* Debugger::GetInstanceFields(const Instance& obj) { | 3019 RawArray* Debugger::GetInstanceFields(const Instance& obj) { |
| 3167 Class& cls = Class::Handle(obj.clazz()); | 3020 Class& cls = Class::Handle(obj.clazz()); |
| 3168 Array& fields = Array::Handle(); | 3021 Array& fields = Array::Handle(); |
| 3169 Field& field = Field::Handle(); | 3022 Field& field = Field::Handle(); |
| 3170 const GrowableObjectArray& field_list = | 3023 const GrowableObjectArray& field_list = |
| 3171 GrowableObjectArray::Handle(GrowableObjectArray::New(8)); | 3024 GrowableObjectArray::Handle(GrowableObjectArray::New(8)); |
| 3172 String& field_name = String::Handle(); | 3025 String& field_name = String::Handle(); |
| 3173 PassiveObject& field_value = PassiveObject::Handle(); | 3026 PassiveObject& field_value = PassiveObject::Handle(); |
| 3174 // Iterate over fields in class hierarchy to count all instance fields. | 3027 // Iterate over fields in class hierarchy to count all instance fields. |
| 3175 while (!cls.IsNull()) { | 3028 while (!cls.IsNull()) { |
| 3176 fields = cls.fields(); | 3029 fields = cls.fields(); |
| 3177 for (intptr_t i = 0; i < fields.Length(); i++) { | 3030 for (intptr_t i = 0; i < fields.Length(); i++) { |
| 3178 field ^= fields.At(i); | 3031 field ^= fields.At(i); |
| 3179 if (!field.is_static()) { | 3032 if (!field.is_static()) { |
| 3180 field_name = field.name(); | 3033 field_name = field.name(); |
| 3181 field_list.Add(field_name); | 3034 field_list.Add(field_name); |
| 3182 field_value = GetInstanceField(cls, field_name, obj); | 3035 field_value = GetInstanceField(cls, field_name, obj); |
| 3183 field_list.Add(field_value); | 3036 field_list.Add(field_value); |
| 3184 } | 3037 } |
| 3185 } | 3038 } |
| 3186 cls = cls.SuperClass(); | 3039 cls = cls.SuperClass(); |
| 3187 } | 3040 } |
| 3188 return Array::MakeFixedLength(field_list); | 3041 return Array::MakeFixedLength(field_list); |
| 3189 } | 3042 } |
| 3190 | 3043 |
| 3191 | |
| 3192 RawArray* Debugger::GetStaticFields(const Class& cls) { | 3044 RawArray* Debugger::GetStaticFields(const Class& cls) { |
| 3193 const GrowableObjectArray& field_list = | 3045 const GrowableObjectArray& field_list = |
| 3194 GrowableObjectArray::Handle(GrowableObjectArray::New(8)); | 3046 GrowableObjectArray::Handle(GrowableObjectArray::New(8)); |
| 3195 Array& fields = Array::Handle(cls.fields()); | 3047 Array& fields = Array::Handle(cls.fields()); |
| 3196 Field& field = Field::Handle(); | 3048 Field& field = Field::Handle(); |
| 3197 String& field_name = String::Handle(); | 3049 String& field_name = String::Handle(); |
| 3198 PassiveObject& field_value = PassiveObject::Handle(); | 3050 PassiveObject& field_value = PassiveObject::Handle(); |
| 3199 for (intptr_t i = 0; i < fields.Length(); i++) { | 3051 for (intptr_t i = 0; i < fields.Length(); i++) { |
| 3200 field ^= fields.At(i); | 3052 field ^= fields.At(i); |
| 3201 if (field.is_static()) { | 3053 if (field.is_static()) { |
| 3202 field_name = field.name(); | 3054 field_name = field.name(); |
| 3203 field_value = GetStaticField(cls, field_name); | 3055 field_value = GetStaticField(cls, field_name); |
| 3204 field_list.Add(field_name); | 3056 field_list.Add(field_name); |
| 3205 field_list.Add(field_value); | 3057 field_list.Add(field_value); |
| 3206 } | 3058 } |
| 3207 } | 3059 } |
| 3208 return Array::MakeFixedLength(field_list); | 3060 return Array::MakeFixedLength(field_list); |
| 3209 } | 3061 } |
| 3210 | 3062 |
| 3211 | |
| 3212 void Debugger::CollectLibraryFields(const GrowableObjectArray& field_list, | 3063 void Debugger::CollectLibraryFields(const GrowableObjectArray& field_list, |
| 3213 const Library& lib, | 3064 const Library& lib, |
| 3214 const String& prefix, | 3065 const String& prefix, |
| 3215 bool include_private_fields) { | 3066 bool include_private_fields) { |
| 3216 DictionaryIterator it(lib); | 3067 DictionaryIterator it(lib); |
| 3217 Zone* zone = Thread::Current()->zone(); | 3068 Zone* zone = Thread::Current()->zone(); |
| 3218 Object& entry = Object::Handle(zone); | 3069 Object& entry = Object::Handle(zone); |
| 3219 Field& field = Field::Handle(zone); | 3070 Field& field = Field::Handle(zone); |
| 3220 String& field_name = String::Handle(zone); | 3071 String& field_name = String::Handle(zone); |
| 3221 PassiveObject& field_value = PassiveObject::Handle(zone); | 3072 PassiveObject& field_value = PassiveObject::Handle(zone); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 3240 } | 3091 } |
| 3241 if (!prefix.IsNull()) { | 3092 if (!prefix.IsNull()) { |
| 3242 field_name = String::Concat(prefix, field_name); | 3093 field_name = String::Concat(prefix, field_name); |
| 3243 } | 3094 } |
| 3244 field_list.Add(field_name); | 3095 field_list.Add(field_name); |
| 3245 field_list.Add(field_value); | 3096 field_list.Add(field_value); |
| 3246 } | 3097 } |
| 3247 } | 3098 } |
| 3248 } | 3099 } |
| 3249 | 3100 |
| 3250 | |
| 3251 RawArray* Debugger::GetLibraryFields(const Library& lib) { | 3101 RawArray* Debugger::GetLibraryFields(const Library& lib) { |
| 3252 Zone* zone = Thread::Current()->zone(); | 3102 Zone* zone = Thread::Current()->zone(); |
| 3253 const GrowableObjectArray& field_list = | 3103 const GrowableObjectArray& field_list = |
| 3254 GrowableObjectArray::Handle(GrowableObjectArray::New(8)); | 3104 GrowableObjectArray::Handle(GrowableObjectArray::New(8)); |
| 3255 CollectLibraryFields(field_list, lib, String::Handle(zone), true); | 3105 CollectLibraryFields(field_list, lib, String::Handle(zone), true); |
| 3256 return Array::MakeFixedLength(field_list); | 3106 return Array::MakeFixedLength(field_list); |
| 3257 } | 3107 } |
| 3258 | 3108 |
| 3259 | |
| 3260 RawArray* Debugger::GetGlobalFields(const Library& lib) { | 3109 RawArray* Debugger::GetGlobalFields(const Library& lib) { |
| 3261 Zone* zone = Thread::Current()->zone(); | 3110 Zone* zone = Thread::Current()->zone(); |
| 3262 const GrowableObjectArray& field_list = | 3111 const GrowableObjectArray& field_list = |
| 3263 GrowableObjectArray::Handle(zone, GrowableObjectArray::New(8)); | 3112 GrowableObjectArray::Handle(zone, GrowableObjectArray::New(8)); |
| 3264 String& prefix_name = String::Handle(zone); | 3113 String& prefix_name = String::Handle(zone); |
| 3265 CollectLibraryFields(field_list, lib, prefix_name, true); | 3114 CollectLibraryFields(field_list, lib, prefix_name, true); |
| 3266 Library& imported = Library::Handle(zone); | 3115 Library& imported = Library::Handle(zone); |
| 3267 intptr_t num_imports = lib.num_imports(); | 3116 intptr_t num_imports = lib.num_imports(); |
| 3268 for (intptr_t i = 0; i < num_imports; i++) { | 3117 for (intptr_t i = 0; i < num_imports; i++) { |
| 3269 imported = lib.ImportLibraryAt(i); | 3118 imported = lib.ImportLibraryAt(i); |
| 3270 ASSERT(!imported.IsNull()); | 3119 ASSERT(!imported.IsNull()); |
| 3271 CollectLibraryFields(field_list, imported, prefix_name, false); | 3120 CollectLibraryFields(field_list, imported, prefix_name, false); |
| 3272 } | 3121 } |
| 3273 LibraryPrefix& prefix = LibraryPrefix::Handle(zone); | 3122 LibraryPrefix& prefix = LibraryPrefix::Handle(zone); |
| 3274 LibraryPrefixIterator it(lib); | 3123 LibraryPrefixIterator it(lib); |
| 3275 while (it.HasNext()) { | 3124 while (it.HasNext()) { |
| 3276 prefix = it.GetNext(); | 3125 prefix = it.GetNext(); |
| 3277 prefix_name = prefix.name(); | 3126 prefix_name = prefix.name(); |
| 3278 ASSERT(!prefix_name.IsNull()); | 3127 ASSERT(!prefix_name.IsNull()); |
| 3279 prefix_name = String::Concat(prefix_name, Symbols::Dot()); | 3128 prefix_name = String::Concat(prefix_name, Symbols::Dot()); |
| 3280 for (int32_t i = 0; i < prefix.num_imports(); i++) { | 3129 for (int32_t i = 0; i < prefix.num_imports(); i++) { |
| 3281 imported = prefix.GetLibrary(i); | 3130 imported = prefix.GetLibrary(i); |
| 3282 CollectLibraryFields(field_list, imported, prefix_name, false); | 3131 CollectLibraryFields(field_list, imported, prefix_name, false); |
| 3283 } | 3132 } |
| 3284 } | 3133 } |
| 3285 return Array::MakeFixedLength(field_list); | 3134 return Array::MakeFixedLength(field_list); |
| 3286 } | 3135 } |
| 3287 | 3136 |
| 3288 | |
| 3289 // static | 3137 // static |
| 3290 void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 3138 void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 3291 ASSERT(visitor != NULL); | 3139 ASSERT(visitor != NULL); |
| 3292 BreakpointLocation* bpt = breakpoint_locations_; | 3140 BreakpointLocation* bpt = breakpoint_locations_; |
| 3293 while (bpt != NULL) { | 3141 while (bpt != NULL) { |
| 3294 bpt->VisitObjectPointers(visitor); | 3142 bpt->VisitObjectPointers(visitor); |
| 3295 bpt = bpt->next(); | 3143 bpt = bpt->next(); |
| 3296 } | 3144 } |
| 3297 bpt = latent_locations_; | 3145 bpt = latent_locations_; |
| 3298 while (bpt != NULL) { | 3146 while (bpt != NULL) { |
| 3299 bpt->VisitObjectPointers(visitor); | 3147 bpt->VisitObjectPointers(visitor); |
| 3300 bpt = bpt->next(); | 3148 bpt = bpt->next(); |
| 3301 } | 3149 } |
| 3302 CodeBreakpoint* cbpt = code_breakpoints_; | 3150 CodeBreakpoint* cbpt = code_breakpoints_; |
| 3303 while (cbpt != NULL) { | 3151 while (cbpt != NULL) { |
| 3304 cbpt->VisitObjectPointers(visitor); | 3152 cbpt->VisitObjectPointers(visitor); |
| 3305 cbpt = cbpt->next(); | 3153 cbpt = cbpt->next(); |
| 3306 } | 3154 } |
| 3307 visitor->VisitPointer(reinterpret_cast<RawObject**>(&top_frame_awaiter_)); | 3155 visitor->VisitPointer(reinterpret_cast<RawObject**>(&top_frame_awaiter_)); |
| 3308 } | 3156 } |
| 3309 | 3157 |
| 3310 | |
| 3311 // static | 3158 // static |
| 3312 void Debugger::SetEventHandler(EventHandler* handler) { | 3159 void Debugger::SetEventHandler(EventHandler* handler) { |
| 3313 event_handler_ = handler; | 3160 event_handler_ = handler; |
| 3314 } | 3161 } |
| 3315 | 3162 |
| 3316 | |
| 3317 void Debugger::Pause(ServiceEvent* event) { | 3163 void Debugger::Pause(ServiceEvent* event) { |
| 3318 ASSERT(event->IsPause()); // Should call InvokeEventHandler instead. | 3164 ASSERT(event->IsPause()); // Should call InvokeEventHandler instead. |
| 3319 ASSERT(!ignore_breakpoints_); // We shouldn't get here when ignoring bpts. | 3165 ASSERT(!ignore_breakpoints_); // We shouldn't get here when ignoring bpts. |
| 3320 ASSERT(!IsPaused()); // No recursive pausing. | 3166 ASSERT(!IsPaused()); // No recursive pausing. |
| 3321 ASSERT(obj_cache_ == NULL); | 3167 ASSERT(obj_cache_ == NULL); |
| 3322 | 3168 |
| 3323 pause_event_ = event; | 3169 pause_event_ = event; |
| 3324 pause_event_->UpdateTimestamp(); | 3170 pause_event_->UpdateTimestamp(); |
| 3325 obj_cache_ = new RemoteObjectCache(64); | 3171 obj_cache_ = new RemoteObjectCache(64); |
| 3326 | 3172 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3359 } | 3205 } |
| 3360 } | 3206 } |
| 3361 | 3207 |
| 3362 if (needs_breakpoint_cleanup_) { | 3208 if (needs_breakpoint_cleanup_) { |
| 3363 RemoveUnlinkedCodeBreakpoints(); | 3209 RemoveUnlinkedCodeBreakpoints(); |
| 3364 } | 3210 } |
| 3365 pause_event_ = NULL; | 3211 pause_event_ = NULL; |
| 3366 obj_cache_ = NULL; // Zone allocated | 3212 obj_cache_ = NULL; // Zone allocated |
| 3367 } | 3213 } |
| 3368 | 3214 |
| 3369 | |
| 3370 void Debugger::EnterSingleStepMode() { | 3215 void Debugger::EnterSingleStepMode() { |
| 3371 ResetSteppingFramePointers(); | 3216 ResetSteppingFramePointers(); |
| 3372 DeoptimizeWorld(); | 3217 DeoptimizeWorld(); |
| 3373 isolate_->set_single_step(true); | 3218 isolate_->set_single_step(true); |
| 3374 } | 3219 } |
| 3375 | 3220 |
| 3376 | |
| 3377 void Debugger::ResetSteppingFramePointers() { | 3221 void Debugger::ResetSteppingFramePointers() { |
| 3378 stepping_fp_ = 0; | 3222 stepping_fp_ = 0; |
| 3379 async_stepping_fp_ = 0; | 3223 async_stepping_fp_ = 0; |
| 3380 } | 3224 } |
| 3381 | 3225 |
| 3382 | |
| 3383 bool Debugger::SteppedForSyntheticAsyncBreakpoint() const { | 3226 bool Debugger::SteppedForSyntheticAsyncBreakpoint() const { |
| 3384 return synthetic_async_breakpoint_ != NULL; | 3227 return synthetic_async_breakpoint_ != NULL; |
| 3385 } | 3228 } |
| 3386 | 3229 |
| 3387 | |
| 3388 void Debugger::CleanupSyntheticAsyncBreakpoint() { | 3230 void Debugger::CleanupSyntheticAsyncBreakpoint() { |
| 3389 if (synthetic_async_breakpoint_ != NULL) { | 3231 if (synthetic_async_breakpoint_ != NULL) { |
| 3390 RemoveBreakpoint(synthetic_async_breakpoint_->id()); | 3232 RemoveBreakpoint(synthetic_async_breakpoint_->id()); |
| 3391 synthetic_async_breakpoint_ = NULL; | 3233 synthetic_async_breakpoint_ = NULL; |
| 3392 } | 3234 } |
| 3393 } | 3235 } |
| 3394 | 3236 |
| 3395 | |
| 3396 void Debugger::RememberTopFrameAwaiter() { | 3237 void Debugger::RememberTopFrameAwaiter() { |
| 3397 if (!FLAG_async_debugger) { | 3238 if (!FLAG_async_debugger) { |
| 3398 return; | 3239 return; |
| 3399 } | 3240 } |
| 3400 if (stack_trace_->Length() > 0) { | 3241 if (stack_trace_->Length() > 0) { |
| 3401 top_frame_awaiter_ = stack_trace_->FrameAt(0)->GetAsyncAwaiter(); | 3242 top_frame_awaiter_ = stack_trace_->FrameAt(0)->GetAsyncAwaiter(); |
| 3402 } else { | 3243 } else { |
| 3403 top_frame_awaiter_ = Object::null(); | 3244 top_frame_awaiter_ = Object::null(); |
| 3404 } | 3245 } |
| 3405 } | 3246 } |
| 3406 | 3247 |
| 3407 | |
| 3408 void Debugger::SetAsyncSteppingFramePointer() { | 3248 void Debugger::SetAsyncSteppingFramePointer() { |
| 3409 if (!FLAG_async_debugger) { | 3249 if (!FLAG_async_debugger) { |
| 3410 return; | 3250 return; |
| 3411 } | 3251 } |
| 3412 if (stack_trace_->FrameAt(0)->function().IsAsyncClosure() || | 3252 if (stack_trace_->FrameAt(0)->function().IsAsyncClosure() || |
| 3413 stack_trace_->FrameAt(0)->function().IsAsyncGenClosure()) { | 3253 stack_trace_->FrameAt(0)->function().IsAsyncGenClosure()) { |
| 3414 async_stepping_fp_ = stack_trace_->FrameAt(0)->fp(); | 3254 async_stepping_fp_ = stack_trace_->FrameAt(0)->fp(); |
| 3415 } else { | 3255 } else { |
| 3416 async_stepping_fp_ = 0; | 3256 async_stepping_fp_ = 0; |
| 3417 } | 3257 } |
| 3418 } | 3258 } |
| 3419 | 3259 |
| 3420 | |
| 3421 void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, | 3260 void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, |
| 3422 bool skip_next_step) { | 3261 bool skip_next_step) { |
| 3423 ResetSteppingFramePointers(); | 3262 ResetSteppingFramePointers(); |
| 3424 RememberTopFrameAwaiter(); | 3263 RememberTopFrameAwaiter(); |
| 3425 if (resume_action_ == kStepInto) { | 3264 if (resume_action_ == kStepInto) { |
| 3426 // When single stepping, we need to deoptimize because we might be | 3265 // When single stepping, we need to deoptimize because we might be |
| 3427 // stepping into optimized code. This happens in particular if | 3266 // stepping into optimized code. This happens in particular if |
| 3428 // the isolate has been interrupted, but can happen in other cases | 3267 // the isolate has been interrupted, but can happen in other cases |
| 3429 // as well. We need to deoptimize the world in case we are about | 3268 // as well. We need to deoptimize the world in case we are about |
| 3430 // to call an optimized function. | 3269 // to call an optimized function. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3488 while ((frame != NULL)) { | 3327 while ((frame != NULL)) { |
| 3489 OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString()); | 3328 OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString()); |
| 3490 frame = iterator.NextFrame(); | 3329 frame = iterator.NextFrame(); |
| 3491 } | 3330 } |
| 3492 } | 3331 } |
| 3493 RewindToFrame(resume_frame_index_); | 3332 RewindToFrame(resume_frame_index_); |
| 3494 UNREACHABLE(); | 3333 UNREACHABLE(); |
| 3495 } | 3334 } |
| 3496 } | 3335 } |
| 3497 | 3336 |
| 3498 | |
| 3499 void Debugger::CacheStackTraces(DebuggerStackTrace* stack_trace, | 3337 void Debugger::CacheStackTraces(DebuggerStackTrace* stack_trace, |
| 3500 DebuggerStackTrace* async_causal_stack_trace, | 3338 DebuggerStackTrace* async_causal_stack_trace, |
| 3501 DebuggerStackTrace* awaiter_stack_trace) { | 3339 DebuggerStackTrace* awaiter_stack_trace) { |
| 3502 ASSERT(stack_trace_ == NULL); | 3340 ASSERT(stack_trace_ == NULL); |
| 3503 stack_trace_ = stack_trace; | 3341 stack_trace_ = stack_trace; |
| 3504 ASSERT(async_causal_stack_trace_ == NULL); | 3342 ASSERT(async_causal_stack_trace_ == NULL); |
| 3505 async_causal_stack_trace_ = async_causal_stack_trace; | 3343 async_causal_stack_trace_ = async_causal_stack_trace; |
| 3506 ASSERT(awaiter_stack_trace_ == NULL); | 3344 ASSERT(awaiter_stack_trace_ == NULL); |
| 3507 awaiter_stack_trace_ = awaiter_stack_trace; | 3345 awaiter_stack_trace_ = awaiter_stack_trace; |
| 3508 } | 3346 } |
| 3509 | 3347 |
| 3510 | |
| 3511 void Debugger::ClearCachedStackTraces() { | 3348 void Debugger::ClearCachedStackTraces() { |
| 3512 stack_trace_ = NULL; | 3349 stack_trace_ = NULL; |
| 3513 async_causal_stack_trace_ = NULL; | 3350 async_causal_stack_trace_ = NULL; |
| 3514 awaiter_stack_trace_ = NULL; | 3351 awaiter_stack_trace_ = NULL; |
| 3515 } | 3352 } |
| 3516 | 3353 |
| 3517 | |
| 3518 static intptr_t FindNextRewindFrameIndex(DebuggerStackTrace* stack, | 3354 static intptr_t FindNextRewindFrameIndex(DebuggerStackTrace* stack, |
| 3519 intptr_t frame_index) { | 3355 intptr_t frame_index) { |
| 3520 for (intptr_t i = frame_index + 1; i < stack->Length(); i++) { | 3356 for (intptr_t i = frame_index + 1; i < stack->Length(); i++) { |
| 3521 ActivationFrame* frame = stack->FrameAt(i); | 3357 ActivationFrame* frame = stack->FrameAt(i); |
| 3522 if (frame->IsRewindable()) { | 3358 if (frame->IsRewindable()) { |
| 3523 return i; | 3359 return i; |
| 3524 } | 3360 } |
| 3525 } | 3361 } |
| 3526 return -1; | 3362 return -1; |
| 3527 } | 3363 } |
| 3528 | 3364 |
| 3529 | |
| 3530 // Can the top frame be rewound? | 3365 // Can the top frame be rewound? |
| 3531 bool Debugger::CanRewindFrame(intptr_t frame_index, const char** error) const { | 3366 bool Debugger::CanRewindFrame(intptr_t frame_index, const char** error) const { |
| 3532 // check rewind pc is found | 3367 // check rewind pc is found |
| 3533 DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace(); | 3368 DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace(); |
| 3534 intptr_t num_frames = stack->Length(); | 3369 intptr_t num_frames = stack->Length(); |
| 3535 if (frame_index < 1 || frame_index >= num_frames) { | 3370 if (frame_index < 1 || frame_index >= num_frames) { |
| 3536 if (error) { | 3371 if (error) { |
| 3537 *error = Thread::Current()->zone()->PrintToString( | 3372 *error = Thread::Current()->zone()->PrintToString( |
| 3538 "Frame must be in bounds [1..%" Pd | 3373 "Frame must be in bounds [1..%" Pd |
| 3539 "]: " | 3374 "]: " |
| (...skipping 21 matching lines...) Expand all Loading... |
| 3561 "optimizations. " | 3396 "optimizations. " |
| 3562 "Run the vm with --no-prune-dead-locals to disallow these " | 3397 "Run the vm with --no-prune-dead-locals to disallow these " |
| 3563 "optimizations.", | 3398 "optimizations.", |
| 3564 frame_index); | 3399 frame_index); |
| 3565 } | 3400 } |
| 3566 return false; | 3401 return false; |
| 3567 } | 3402 } |
| 3568 return true; | 3403 return true; |
| 3569 } | 3404 } |
| 3570 | 3405 |
| 3571 | |
| 3572 // Given a return address pc, find the "rewind" pc, which is the pc | 3406 // Given a return address pc, find the "rewind" pc, which is the pc |
| 3573 // before the corresponding call. | 3407 // before the corresponding call. |
| 3574 static uword LookupRewindPc(const Code& code, uword pc) { | 3408 static uword LookupRewindPc(const Code& code, uword pc) { |
| 3575 ASSERT(!code.is_optimized()); | 3409 ASSERT(!code.is_optimized()); |
| 3576 ASSERT(code.ContainsInstructionAt(pc)); | 3410 ASSERT(code.ContainsInstructionAt(pc)); |
| 3577 | 3411 |
| 3578 uword pc_offset = pc - code.PayloadStart(); | 3412 uword pc_offset = pc - code.PayloadStart(); |
| 3579 const PcDescriptors& descriptors = | 3413 const PcDescriptors& descriptors = |
| 3580 PcDescriptors::Handle(code.pc_descriptors()); | 3414 PcDescriptors::Handle(code.pc_descriptors()); |
| 3581 PcDescriptors::Iterator iter( | 3415 PcDescriptors::Iterator iter( |
| 3582 descriptors, RawPcDescriptors::kRewind | RawPcDescriptors::kIcCall | | 3416 descriptors, RawPcDescriptors::kRewind | RawPcDescriptors::kIcCall | |
| 3583 RawPcDescriptors::kUnoptStaticCall); | 3417 RawPcDescriptors::kUnoptStaticCall); |
| 3584 intptr_t rewind_deopt_id = -1; | 3418 intptr_t rewind_deopt_id = -1; |
| 3585 uword rewind_pc = 0; | 3419 uword rewind_pc = 0; |
| 3586 while (iter.MoveNext()) { | 3420 while (iter.MoveNext()) { |
| 3587 if (iter.Kind() == RawPcDescriptors::kRewind) { | 3421 if (iter.Kind() == RawPcDescriptors::kRewind) { |
| 3588 // Remember the last rewind so we don't need to iterator twice. | 3422 // Remember the last rewind so we don't need to iterator twice. |
| 3589 rewind_pc = code.PayloadStart() + iter.PcOffset(); | 3423 rewind_pc = code.PayloadStart() + iter.PcOffset(); |
| 3590 rewind_deopt_id = iter.DeoptId(); | 3424 rewind_deopt_id = iter.DeoptId(); |
| 3591 } | 3425 } |
| 3592 if ((pc_offset == iter.PcOffset()) && (iter.DeoptId() == rewind_deopt_id)) { | 3426 if ((pc_offset == iter.PcOffset()) && (iter.DeoptId() == rewind_deopt_id)) { |
| 3593 return rewind_pc; | 3427 return rewind_pc; |
| 3594 } | 3428 } |
| 3595 } | 3429 } |
| 3596 return 0; | 3430 return 0; |
| 3597 } | 3431 } |
| 3598 | 3432 |
| 3599 | |
| 3600 void Debugger::RewindToFrame(intptr_t frame_index) { | 3433 void Debugger::RewindToFrame(intptr_t frame_index) { |
| 3601 Thread* thread = Thread::Current(); | 3434 Thread* thread = Thread::Current(); |
| 3602 Zone* zone = thread->zone(); | 3435 Zone* zone = thread->zone(); |
| 3603 Code& code = Code::Handle(zone); | 3436 Code& code = Code::Handle(zone); |
| 3604 Function& function = Function::Handle(zone); | 3437 Function& function = Function::Handle(zone); |
| 3605 | 3438 |
| 3606 // Find the requested frame. | 3439 // Find the requested frame. |
| 3607 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames, | 3440 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames, |
| 3608 Thread::Current(), | 3441 Thread::Current(), |
| 3609 StackFrameIterator::kNoCrossThreadIteration); | 3442 StackFrameIterator::kNoCrossThreadIteration); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 3634 RewindToUnoptimizedFrame(frame, code); | 3467 RewindToUnoptimizedFrame(frame, code); |
| 3635 UNREACHABLE(); | 3468 UNREACHABLE(); |
| 3636 } | 3469 } |
| 3637 current_frame++; | 3470 current_frame++; |
| 3638 } | 3471 } |
| 3639 } | 3472 } |
| 3640 } | 3473 } |
| 3641 UNIMPLEMENTED(); | 3474 UNIMPLEMENTED(); |
| 3642 } | 3475 } |
| 3643 | 3476 |
| 3644 | |
| 3645 void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) { | 3477 void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) { |
| 3646 // We will be jumping out of the debugger rather than exiting this | 3478 // We will be jumping out of the debugger rather than exiting this |
| 3647 // function, so prepare the debugger state. | 3479 // function, so prepare the debugger state. |
| 3648 ClearCachedStackTraces(); | 3480 ClearCachedStackTraces(); |
| 3649 resume_action_ = kContinue; | 3481 resume_action_ = kContinue; |
| 3650 resume_frame_index_ = -1; | 3482 resume_frame_index_ = -1; |
| 3651 EnterSingleStepMode(); | 3483 EnterSingleStepMode(); |
| 3652 | 3484 |
| 3653 uword rewind_pc = LookupRewindPc(code, frame->pc()); | 3485 uword rewind_pc = LookupRewindPc(code, frame->pc()); |
| 3654 if (FLAG_trace_rewind && rewind_pc == 0) { | 3486 if (FLAG_trace_rewind && rewind_pc == 0) { |
| 3655 OS::PrintErr("Unable to find rewind pc for pc(%" Px ")\n", frame->pc()); | 3487 OS::PrintErr("Unable to find rewind pc for pc(%" Px ")\n", frame->pc()); |
| 3656 } | 3488 } |
| 3657 ASSERT(rewind_pc != 0); | 3489 ASSERT(rewind_pc != 0); |
| 3658 if (FLAG_trace_rewind) { | 3490 if (FLAG_trace_rewind) { |
| 3659 OS::PrintErr( | 3491 OS::PrintErr( |
| 3660 "===============================\n" | 3492 "===============================\n" |
| 3661 "Rewinding to unoptimized frame:\n" | 3493 "Rewinding to unoptimized frame:\n" |
| 3662 " rewind_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px | 3494 " rewind_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px |
| 3663 ")\n" | 3495 ")\n" |
| 3664 "===============================\n", | 3496 "===============================\n", |
| 3665 rewind_pc, frame->sp(), frame->fp()); | 3497 rewind_pc, frame->sp(), frame->fp()); |
| 3666 } | 3498 } |
| 3667 Exceptions::JumpToFrame(Thread::Current(), rewind_pc, frame->sp(), | 3499 Exceptions::JumpToFrame(Thread::Current(), rewind_pc, frame->sp(), |
| 3668 frame->fp(), true /* clear lazy deopt at target */); | 3500 frame->fp(), true /* clear lazy deopt at target */); |
| 3669 UNREACHABLE(); | 3501 UNREACHABLE(); |
| 3670 } | 3502 } |
| 3671 | 3503 |
| 3672 | |
| 3673 void Debugger::RewindToOptimizedFrame(StackFrame* frame, | 3504 void Debugger::RewindToOptimizedFrame(StackFrame* frame, |
| 3674 const Code& optimized_code, | 3505 const Code& optimized_code, |
| 3675 intptr_t sub_index) { | 3506 intptr_t sub_index) { |
| 3676 post_deopt_frame_index_ = sub_index; | 3507 post_deopt_frame_index_ = sub_index; |
| 3677 | 3508 |
| 3678 // We will be jumping out of the debugger rather than exiting this | 3509 // We will be jumping out of the debugger rather than exiting this |
| 3679 // function, so prepare the debugger state. | 3510 // function, so prepare the debugger state. |
| 3680 ClearCachedStackTraces(); | 3511 ClearCachedStackTraces(); |
| 3681 resume_action_ = kContinue; | 3512 resume_action_ = kContinue; |
| 3682 resume_frame_index_ = -1; | 3513 resume_frame_index_ = -1; |
| 3683 EnterSingleStepMode(); | 3514 EnterSingleStepMode(); |
| 3684 | 3515 |
| 3685 if (FLAG_trace_rewind) { | 3516 if (FLAG_trace_rewind) { |
| 3686 OS::PrintErr( | 3517 OS::PrintErr( |
| 3687 "===============================\n" | 3518 "===============================\n" |
| 3688 "Deoptimizing frame for rewind:\n" | 3519 "Deoptimizing frame for rewind:\n" |
| 3689 " deopt_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px | 3520 " deopt_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px |
| 3690 ")\n" | 3521 ")\n" |
| 3691 "===============================\n", | 3522 "===============================\n", |
| 3692 frame->pc(), frame->sp(), frame->fp()); | 3523 frame->pc(), frame->sp(), frame->fp()); |
| 3693 } | 3524 } |
| 3694 Thread* thread = Thread::Current(); | 3525 Thread* thread = Thread::Current(); |
| 3695 thread->set_resume_pc(frame->pc()); | 3526 thread->set_resume_pc(frame->pc()); |
| 3696 uword deopt_stub_pc = StubCode::DeoptForRewind_entry()->EntryPoint(); | 3527 uword deopt_stub_pc = StubCode::DeoptForRewind_entry()->EntryPoint(); |
| 3697 Exceptions::JumpToFrame(thread, deopt_stub_pc, frame->sp(), frame->fp(), | 3528 Exceptions::JumpToFrame(thread, deopt_stub_pc, frame->sp(), frame->fp(), |
| 3698 true /* clear lazy deopt at target */); | 3529 true /* clear lazy deopt at target */); |
| 3699 UNREACHABLE(); | 3530 UNREACHABLE(); |
| 3700 } | 3531 } |
| 3701 | 3532 |
| 3702 | |
| 3703 void Debugger::RewindPostDeopt() { | 3533 void Debugger::RewindPostDeopt() { |
| 3704 intptr_t rewind_frame = post_deopt_frame_index_; | 3534 intptr_t rewind_frame = post_deopt_frame_index_; |
| 3705 post_deopt_frame_index_ = -1; | 3535 post_deopt_frame_index_ = -1; |
| 3706 if (FLAG_trace_rewind) { | 3536 if (FLAG_trace_rewind) { |
| 3707 OS::PrintErr("Post deopt, jumping to frame %" Pd "\n", rewind_frame); | 3537 OS::PrintErr("Post deopt, jumping to frame %" Pd "\n", rewind_frame); |
| 3708 OS::PrintErr( | 3538 OS::PrintErr( |
| 3709 "-------------------------\n" | 3539 "-------------------------\n" |
| 3710 "All frames...\n\n"); | 3540 "All frames...\n\n"); |
| 3711 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames, | 3541 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames, |
| 3712 Thread::Current(), | 3542 Thread::Current(), |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3735 ASSERT(!code.is_optimized()); | 3565 ASSERT(!code.is_optimized()); |
| 3736 if (current_frame == rewind_frame) { | 3566 if (current_frame == rewind_frame) { |
| 3737 RewindToUnoptimizedFrame(frame, code); | 3567 RewindToUnoptimizedFrame(frame, code); |
| 3738 UNREACHABLE(); | 3568 UNREACHABLE(); |
| 3739 } | 3569 } |
| 3740 current_frame++; | 3570 current_frame++; |
| 3741 } | 3571 } |
| 3742 } | 3572 } |
| 3743 } | 3573 } |
| 3744 | 3574 |
| 3745 | |
| 3746 // static | 3575 // static |
| 3747 bool Debugger::IsDebuggable(const Function& func) { | 3576 bool Debugger::IsDebuggable(const Function& func) { |
| 3748 if (!func.is_debuggable()) { | 3577 if (!func.is_debuggable()) { |
| 3749 return false; | 3578 return false; |
| 3750 } | 3579 } |
| 3751 const Class& cls = Class::Handle(func.Owner()); | 3580 const Class& cls = Class::Handle(func.Owner()); |
| 3752 const Library& lib = Library::Handle(cls.library()); | 3581 const Library& lib = Library::Handle(cls.library()); |
| 3753 return lib.IsDebuggable(); | 3582 return lib.IsDebuggable(); |
| 3754 } | 3583 } |
| 3755 | 3584 |
| 3756 | |
| 3757 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt) { | 3585 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt) { |
| 3758 resume_action_ = kContinue; | 3586 resume_action_ = kContinue; |
| 3759 ResetSteppingFramePointers(); | 3587 ResetSteppingFramePointers(); |
| 3760 isolate_->set_single_step(false); | 3588 isolate_->set_single_step(false); |
| 3761 ASSERT(!IsPaused()); | 3589 ASSERT(!IsPaused()); |
| 3762 ASSERT(obj_cache_ == NULL); | 3590 ASSERT(obj_cache_ == NULL); |
| 3763 if ((bpt != NULL) && bpt->IsSingleShot()) { | 3591 if ((bpt != NULL) && bpt->IsSingleShot()) { |
| 3764 RemoveBreakpoint(bpt->id()); | 3592 RemoveBreakpoint(bpt->id()); |
| 3765 bpt = NULL; | 3593 bpt = NULL; |
| 3766 } | 3594 } |
| 3767 | 3595 |
| 3768 ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint); | 3596 ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint); |
| 3769 event.set_top_frame(top_frame); | 3597 event.set_top_frame(top_frame); |
| 3770 event.set_breakpoint(bpt); | 3598 event.set_breakpoint(bpt); |
| 3771 event.set_at_async_jump(IsAtAsyncJump(top_frame)); | 3599 event.set_at_async_jump(IsAtAsyncJump(top_frame)); |
| 3772 Pause(&event); | 3600 Pause(&event); |
| 3773 } | 3601 } |
| 3774 | 3602 |
| 3775 | |
| 3776 bool Debugger::IsAtAsyncJump(ActivationFrame* top_frame) { | 3603 bool Debugger::IsAtAsyncJump(ActivationFrame* top_frame) { |
| 3777 Zone* zone = Thread::Current()->zone(); | 3604 Zone* zone = Thread::Current()->zone(); |
| 3778 Object& closure_or_null = | 3605 Object& closure_or_null = |
| 3779 Object::Handle(zone, top_frame->GetAsyncOperation()); | 3606 Object::Handle(zone, top_frame->GetAsyncOperation()); |
| 3780 if (!closure_or_null.IsNull()) { | 3607 if (!closure_or_null.IsNull()) { |
| 3781 ASSERT(closure_or_null.IsInstance()); | 3608 ASSERT(closure_or_null.IsInstance()); |
| 3782 ASSERT(Instance::Cast(closure_or_null).IsClosure()); | 3609 ASSERT(Instance::Cast(closure_or_null).IsClosure()); |
| 3783 const Script& script = Script::Handle(zone, top_frame->SourceScript()); | 3610 const Script& script = Script::Handle(zone, top_frame->SourceScript()); |
| 3784 if (script.kind() == RawScript::kKernelTag) { | 3611 if (script.kind() == RawScript::kKernelTag) { |
| 3785 // Are we at a yield point (previous await)? | 3612 // Are we at a yield point (previous await)? |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3870 ASSERT(!HasActiveBreakpoint(frame->pc())); | 3697 ASSERT(!HasActiveBreakpoint(frame->pc())); |
| 3871 | 3698 |
| 3872 if (FLAG_verbose_debug) { | 3699 if (FLAG_verbose_debug) { |
| 3873 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", | 3700 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", |
| 3874 String::Handle(frame->SourceUrl()).ToCString(), | 3701 String::Handle(frame->SourceUrl()).ToCString(), |
| 3875 frame->LineNumber(), | 3702 frame->LineNumber(), |
| 3876 String::Handle(frame->QualifiedFunctionName()).ToCString(), | 3703 String::Handle(frame->QualifiedFunctionName()).ToCString(), |
| 3877 frame->TokenPos().ToCString()); | 3704 frame->TokenPos().ToCString()); |
| 3878 } | 3705 } |
| 3879 | 3706 |
| 3880 | |
| 3881 CacheStackTraces(CollectStackTrace(), CollectAsyncCausalStackTrace(), | 3707 CacheStackTraces(CollectStackTrace(), CollectAsyncCausalStackTrace(), |
| 3882 CollectAwaiterReturnStackTrace()); | 3708 CollectAwaiterReturnStackTrace()); |
| 3883 if (SteppedForSyntheticAsyncBreakpoint()) { | 3709 if (SteppedForSyntheticAsyncBreakpoint()) { |
| 3884 CleanupSyntheticAsyncBreakpoint(); | 3710 CleanupSyntheticAsyncBreakpoint(); |
| 3885 } | 3711 } |
| 3886 SignalPausedEvent(frame, NULL); | 3712 SignalPausedEvent(frame, NULL); |
| 3887 HandleSteppingRequest(stack_trace_); | 3713 HandleSteppingRequest(stack_trace_); |
| 3888 ClearCachedStackTraces(); | 3714 ClearCachedStackTraces(); |
| 3889 | 3715 |
| 3890 // If any error occurred while in the debug message loop, return it here. | 3716 // If any error occurred while in the debug message loop, return it here. |
| 3891 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 3717 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
| 3892 Thread::Current()->clear_sticky_error(); | 3718 Thread::Current()->clear_sticky_error(); |
| 3893 return error.raw(); | 3719 return error.raw(); |
| 3894 } | 3720 } |
| 3895 | 3721 |
| 3896 | |
| 3897 RawError* Debugger::PauseBreakpoint() { | 3722 RawError* Debugger::PauseBreakpoint() { |
| 3898 // We ignore this breakpoint when the VM is executing code invoked | 3723 // We ignore this breakpoint when the VM is executing code invoked |
| 3899 // by the debugger to evaluate variables values, or when we see a nested | 3724 // by the debugger to evaluate variables values, or when we see a nested |
| 3900 // breakpoint or exception event. | 3725 // breakpoint or exception event. |
| 3901 if (ignore_breakpoints_ || IsPaused()) { | 3726 if (ignore_breakpoints_ || IsPaused()) { |
| 3902 return Error::null(); | 3727 return Error::null(); |
| 3903 } | 3728 } |
| 3904 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 3729 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 3905 ASSERT(stack_trace->Length() > 0); | 3730 ASSERT(stack_trace->Length() > 0); |
| 3906 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 3731 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3959 // point will be at the exact same pc. Skip it. | 3784 // point will be at the exact same pc. Skip it. |
| 3960 HandleSteppingRequest(stack_trace_, true /* skip next step */); | 3785 HandleSteppingRequest(stack_trace_, true /* skip next step */); |
| 3961 ClearCachedStackTraces(); | 3786 ClearCachedStackTraces(); |
| 3962 | 3787 |
| 3963 // If any error occurred while in the debug message loop, return it here. | 3788 // If any error occurred while in the debug message loop, return it here. |
| 3964 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 3789 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
| 3965 Thread::Current()->clear_sticky_error(); | 3790 Thread::Current()->clear_sticky_error(); |
| 3966 return error.raw(); | 3791 return error.raw(); |
| 3967 } | 3792 } |
| 3968 | 3793 |
| 3969 | |
| 3970 Breakpoint* Debugger::FindHitBreakpoint(BreakpointLocation* location, | 3794 Breakpoint* Debugger::FindHitBreakpoint(BreakpointLocation* location, |
| 3971 ActivationFrame* top_frame) { | 3795 ActivationFrame* top_frame) { |
| 3972 if (location == NULL) { | 3796 if (location == NULL) { |
| 3973 return NULL; | 3797 return NULL; |
| 3974 } | 3798 } |
| 3975 // There may be more than one applicable breakpoint at this location, but we | 3799 // There may be more than one applicable breakpoint at this location, but we |
| 3976 // will report only one as reached. If there is a single-shot breakpoint, we | 3800 // will report only one as reached. If there is a single-shot breakpoint, we |
| 3977 // favor it; then a closure-specific breakpoint ; then an general breakpoint. | 3801 // favor it; then a closure-specific breakpoint ; then an general breakpoint. |
| 3978 | 3802 |
| 3979 // First check for a single-shot breakpoint. | 3803 // First check for a single-shot breakpoint. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 4004 while (bpt != NULL) { | 3828 while (bpt != NULL) { |
| 4005 if (bpt->IsRepeated()) { | 3829 if (bpt->IsRepeated()) { |
| 4006 return bpt; | 3830 return bpt; |
| 4007 } | 3831 } |
| 4008 bpt = bpt->next(); | 3832 bpt = bpt->next(); |
| 4009 } | 3833 } |
| 4010 | 3834 |
| 4011 return NULL; | 3835 return NULL; |
| 4012 } | 3836 } |
| 4013 | 3837 |
| 4014 | |
| 4015 void Debugger::PauseDeveloper(const String& msg) { | 3838 void Debugger::PauseDeveloper(const String& msg) { |
| 4016 // We ignore this breakpoint when the VM is executing code invoked | 3839 // We ignore this breakpoint when the VM is executing code invoked |
| 4017 // by the debugger to evaluate variables values, or when we see a nested | 3840 // by the debugger to evaluate variables values, or when we see a nested |
| 4018 // breakpoint or exception event. | 3841 // breakpoint or exception event. |
| 4019 if (ignore_breakpoints_ || IsPaused()) { | 3842 if (ignore_breakpoints_ || IsPaused()) { |
| 4020 return; | 3843 return; |
| 4021 } | 3844 } |
| 4022 | 3845 |
| 4023 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 3846 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 4024 ASSERT(stack_trace->Length() > 0); | 3847 ASSERT(stack_trace->Length() > 0); |
| 4025 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace(), | 3848 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace(), |
| 4026 CollectAwaiterReturnStackTrace()); | 3849 CollectAwaiterReturnStackTrace()); |
| 4027 // TODO(johnmccutchan): Send |msg| to Observatory. | 3850 // TODO(johnmccutchan): Send |msg| to Observatory. |
| 4028 | 3851 |
| 4029 // We are in the native call to Developer_debugger. the developer | 3852 // We are in the native call to Developer_debugger. the developer |
| 4030 // gets a better experience by not seeing this call. To accomplish | 3853 // gets a better experience by not seeing this call. To accomplish |
| 4031 // this, we continue execution until the call exits (step out). | 3854 // this, we continue execution until the call exits (step out). |
| 4032 SetResumeAction(kStepOut); | 3855 SetResumeAction(kStepOut); |
| 4033 HandleSteppingRequest(stack_trace_); | 3856 HandleSteppingRequest(stack_trace_); |
| 4034 ClearCachedStackTraces(); | 3857 ClearCachedStackTraces(); |
| 4035 } | 3858 } |
| 4036 | 3859 |
| 4037 | |
| 4038 void Debugger::Initialize(Isolate* isolate) { | 3860 void Debugger::Initialize(Isolate* isolate) { |
| 4039 if (initialized_) { | 3861 if (initialized_) { |
| 4040 return; | 3862 return; |
| 4041 } | 3863 } |
| 4042 isolate_ = isolate; | 3864 isolate_ = isolate; |
| 4043 | 3865 |
| 4044 // Use the isolate's control port as the isolate_id for debugging. | 3866 // Use the isolate's control port as the isolate_id for debugging. |
| 4045 // This port will be used as a unique ID to represent the isolate in | 3867 // This port will be used as a unique ID to represent the isolate in |
| 4046 // the debugger embedder api. | 3868 // the debugger embedder api. |
| 4047 isolate_id_ = isolate_->main_port(); | 3869 isolate_id_ = isolate_->main_port(); |
| 4048 initialized_ = true; | 3870 initialized_ = true; |
| 4049 } | 3871 } |
| 4050 | 3872 |
| 4051 | |
| 4052 void Debugger::NotifyIsolateCreated() { | 3873 void Debugger::NotifyIsolateCreated() { |
| 4053 if (NeedsIsolateEvents()) { | 3874 if (NeedsIsolateEvents()) { |
| 4054 ServiceEvent event(isolate_, ServiceEvent::kIsolateStart); | 3875 ServiceEvent event(isolate_, ServiceEvent::kIsolateStart); |
| 4055 InvokeEventHandler(&event); | 3876 InvokeEventHandler(&event); |
| 4056 } | 3877 } |
| 4057 } | 3878 } |
| 4058 | 3879 |
| 4059 | |
| 4060 // Return innermost closure contained in 'function' that contains | 3880 // Return innermost closure contained in 'function' that contains |
| 4061 // the given token position. | 3881 // the given token position. |
| 4062 RawFunction* Debugger::FindInnermostClosure(const Function& function, | 3882 RawFunction* Debugger::FindInnermostClosure(const Function& function, |
| 4063 TokenPosition token_pos) { | 3883 TokenPosition token_pos) { |
| 4064 Zone* zone = Thread::Current()->zone(); | 3884 Zone* zone = Thread::Current()->zone(); |
| 4065 const Script& outer_origin = Script::Handle(zone, function.script()); | 3885 const Script& outer_origin = Script::Handle(zone, function.script()); |
| 4066 const GrowableObjectArray& closures = GrowableObjectArray::Handle( | 3886 const GrowableObjectArray& closures = GrowableObjectArray::Handle( |
| 4067 zone, Isolate::Current()->object_store()->closure_functions()); | 3887 zone, Isolate::Current()->object_store()->closure_functions()); |
| 4068 const intptr_t num_closures = closures.Length(); | 3888 const intptr_t num_closures = closures.Length(); |
| 4069 Function& closure = Function::Handle(zone); | 3889 Function& closure = Function::Handle(zone); |
| 4070 Function& best_fit = Function::Handle(zone); | 3890 Function& best_fit = Function::Handle(zone); |
| 4071 for (intptr_t i = 0; i < num_closures; i++) { | 3891 for (intptr_t i = 0; i < num_closures; i++) { |
| 4072 closure ^= closures.At(i); | 3892 closure ^= closures.At(i); |
| 4073 if ((function.token_pos() < closure.token_pos()) && | 3893 if ((function.token_pos() < closure.token_pos()) && |
| 4074 (closure.end_token_pos() < function.end_token_pos()) && | 3894 (closure.end_token_pos() < function.end_token_pos()) && |
| 4075 (closure.token_pos() <= token_pos) && | 3895 (closure.token_pos() <= token_pos) && |
| 4076 (token_pos <= closure.end_token_pos()) && | 3896 (token_pos <= closure.end_token_pos()) && |
| 4077 (closure.script() == outer_origin.raw())) { | 3897 (closure.script() == outer_origin.raw())) { |
| 4078 SelectBestFit(&best_fit, &closure); | 3898 SelectBestFit(&best_fit, &closure); |
| 4079 } | 3899 } |
| 4080 } | 3900 } |
| 4081 return best_fit.raw(); | 3901 return best_fit.raw(); |
| 4082 } | 3902 } |
| 4083 | 3903 |
| 4084 | |
| 4085 void Debugger::NotifyCompilation(const Function& func) { | 3904 void Debugger::NotifyCompilation(const Function& func) { |
| 4086 if (breakpoint_locations_ == NULL) { | 3905 if (breakpoint_locations_ == NULL) { |
| 4087 // Return with minimal overhead if there are no breakpoints. | 3906 // Return with minimal overhead if there are no breakpoints. |
| 4088 return; | 3907 return; |
| 4089 } | 3908 } |
| 4090 if (!func.is_debuggable()) { | 3909 if (!func.is_debuggable()) { |
| 4091 // Nothing to do if the function is not debuggable. If there is | 3910 // Nothing to do if the function is not debuggable. If there is |
| 4092 // a pending breakpoint in an inner function (that is debuggable), | 3911 // a pending breakpoint in an inner function (that is debuggable), |
| 4093 // we'll resolve the breakpoint when the inner function is compiled. | 3912 // we'll resolve the breakpoint when the inner function is compiled. |
| 4094 return; | 3913 return; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4167 func.IsClosureFunction() ? "closure" : "function", | 3986 func.IsClosureFunction() ? "closure" : "function", |
| 4168 String::Handle(func.name()).ToCString()); | 3987 String::Handle(func.name()).ToCString()); |
| 4169 bpt = bpt->next(); | 3988 bpt = bpt->next(); |
| 4170 } | 3989 } |
| 4171 } | 3990 } |
| 4172 MakeCodeBreakpointAt(func, loc); | 3991 MakeCodeBreakpointAt(func, loc); |
| 4173 } | 3992 } |
| 4174 } | 3993 } |
| 4175 } | 3994 } |
| 4176 | 3995 |
| 4177 | |
| 4178 void Debugger::NotifyDoneLoading() { | 3996 void Debugger::NotifyDoneLoading() { |
| 4179 if (latent_locations_ == NULL) { | 3997 if (latent_locations_ == NULL) { |
| 4180 // Common, fast path. | 3998 // Common, fast path. |
| 4181 return; | 3999 return; |
| 4182 } | 4000 } |
| 4183 Zone* zone = Thread::Current()->zone(); | 4001 Zone* zone = Thread::Current()->zone(); |
| 4184 Library& lib = Library::Handle(zone); | 4002 Library& lib = Library::Handle(zone); |
| 4185 Script& script = Script::Handle(zone); | 4003 Script& script = Script::Handle(zone); |
| 4186 String& url = String::Handle(zone); | 4004 String& url = String::Handle(zone); |
| 4187 BreakpointLocation* loc = latent_locations_; | 4005 BreakpointLocation* loc = latent_locations_; |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4283 "%" Pd " with url '%s'\n", | 4101 "%" Pd " with url '%s'\n", |
| 4284 bpt->id(), url.ToCString()); | 4102 bpt->id(), url.ToCString()); |
| 4285 bpt = bpt->next(); | 4103 bpt = bpt->next(); |
| 4286 } | 4104 } |
| 4287 } | 4105 } |
| 4288 loc = loc->next(); | 4106 loc = loc->next(); |
| 4289 } | 4107 } |
| 4290 } | 4108 } |
| 4291 } | 4109 } |
| 4292 | 4110 |
| 4293 | |
| 4294 // TODO(hausner): Could potentially make this faster by checking | 4111 // TODO(hausner): Could potentially make this faster by checking |
| 4295 // whether the call target at pc is a debugger stub. | 4112 // whether the call target at pc is a debugger stub. |
| 4296 bool Debugger::HasActiveBreakpoint(uword pc) { | 4113 bool Debugger::HasActiveBreakpoint(uword pc) { |
| 4297 CodeBreakpoint* bpt = GetCodeBreakpoint(pc); | 4114 CodeBreakpoint* bpt = GetCodeBreakpoint(pc); |
| 4298 return (bpt != NULL) && (bpt->IsEnabled()); | 4115 return (bpt != NULL) && (bpt->IsEnabled()); |
| 4299 } | 4116 } |
| 4300 | 4117 |
| 4301 | |
| 4302 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { | 4118 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { |
| 4303 CodeBreakpoint* bpt = code_breakpoints_; | 4119 CodeBreakpoint* bpt = code_breakpoints_; |
| 4304 while (bpt != NULL) { | 4120 while (bpt != NULL) { |
| 4305 if (bpt->pc() == breakpoint_address) { | 4121 if (bpt->pc() == breakpoint_address) { |
| 4306 return bpt; | 4122 return bpt; |
| 4307 } | 4123 } |
| 4308 bpt = bpt->next(); | 4124 bpt = bpt->next(); |
| 4309 } | 4125 } |
| 4310 return NULL; | 4126 return NULL; |
| 4311 } | 4127 } |
| 4312 | 4128 |
| 4313 | |
| 4314 RawCode* Debugger::GetPatchedStubAddress(uword breakpoint_address) { | 4129 RawCode* Debugger::GetPatchedStubAddress(uword breakpoint_address) { |
| 4315 CodeBreakpoint* bpt = GetCodeBreakpoint(breakpoint_address); | 4130 CodeBreakpoint* bpt = GetCodeBreakpoint(breakpoint_address); |
| 4316 if (bpt != NULL) { | 4131 if (bpt != NULL) { |
| 4317 return bpt->OrigStubAddress(); | 4132 return bpt->OrigStubAddress(); |
| 4318 } | 4133 } |
| 4319 UNREACHABLE(); | 4134 UNREACHABLE(); |
| 4320 return Code::null(); | 4135 return Code::null(); |
| 4321 } | 4136 } |
| 4322 | 4137 |
| 4323 | |
| 4324 // Remove and delete the source breakpoint bpt and its associated | 4138 // Remove and delete the source breakpoint bpt and its associated |
| 4325 // code breakpoints. | 4139 // code breakpoints. |
| 4326 void Debugger::RemoveBreakpoint(intptr_t bp_id) { | 4140 void Debugger::RemoveBreakpoint(intptr_t bp_id) { |
| 4327 if (RemoveBreakpointFromTheList(bp_id, &breakpoint_locations_)) { | 4141 if (RemoveBreakpointFromTheList(bp_id, &breakpoint_locations_)) { |
| 4328 return; | 4142 return; |
| 4329 } | 4143 } |
| 4330 RemoveBreakpointFromTheList(bp_id, &latent_locations_); | 4144 RemoveBreakpointFromTheList(bp_id, &latent_locations_); |
| 4331 } | 4145 } |
| 4332 | 4146 |
| 4333 | |
| 4334 // Remove and delete the source breakpoint bpt and its associated | 4147 // Remove and delete the source breakpoint bpt and its associated |
| 4335 // code breakpoints. Returns true, if breakpoint was found and removed, | 4148 // code breakpoints. Returns true, if breakpoint was found and removed, |
| 4336 // returns false, if breakpoint was not found. | 4149 // returns false, if breakpoint was not found. |
| 4337 bool Debugger::RemoveBreakpointFromTheList(intptr_t bp_id, | 4150 bool Debugger::RemoveBreakpointFromTheList(intptr_t bp_id, |
| 4338 BreakpointLocation** list) { | 4151 BreakpointLocation** list) { |
| 4339 BreakpointLocation* prev_loc = NULL; | 4152 BreakpointLocation* prev_loc = NULL; |
| 4340 BreakpointLocation* curr_loc = *list; | 4153 BreakpointLocation* curr_loc = *list; |
| 4341 while (curr_loc != NULL) { | 4154 while (curr_loc != NULL) { |
| 4342 Breakpoint* prev_bpt = NULL; | 4155 Breakpoint* prev_bpt = NULL; |
| 4343 Breakpoint* curr_bpt = curr_loc->breakpoints(); | 4156 Breakpoint* curr_bpt = curr_loc->breakpoints(); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4393 prev_bpt = curr_bpt; | 4206 prev_bpt = curr_bpt; |
| 4394 curr_bpt = curr_bpt->next(); | 4207 curr_bpt = curr_bpt->next(); |
| 4395 } | 4208 } |
| 4396 prev_loc = curr_loc; | 4209 prev_loc = curr_loc; |
| 4397 curr_loc = curr_loc->next(); | 4210 curr_loc = curr_loc->next(); |
| 4398 } | 4211 } |
| 4399 // breakpoint with bp_id does not exist, nothing to do. | 4212 // breakpoint with bp_id does not exist, nothing to do. |
| 4400 return false; | 4213 return false; |
| 4401 } | 4214 } |
| 4402 | 4215 |
| 4403 | |
| 4404 // Unlink code breakpoints from the given breakpoint location. | 4216 // Unlink code breakpoints from the given breakpoint location. |
| 4405 // They will later be deleted when control returns from the pause event | 4217 // They will later be deleted when control returns from the pause event |
| 4406 // callback. Also, disable the breakpoint so it no longer fires if it | 4218 // callback. Also, disable the breakpoint so it no longer fires if it |
| 4407 // should be hit before it gets deleted. | 4219 // should be hit before it gets deleted. |
| 4408 void Debugger::UnlinkCodeBreakpoints(BreakpointLocation* bpt_location) { | 4220 void Debugger::UnlinkCodeBreakpoints(BreakpointLocation* bpt_location) { |
| 4409 ASSERT(bpt_location != NULL); | 4221 ASSERT(bpt_location != NULL); |
| 4410 CodeBreakpoint* curr_bpt = code_breakpoints_; | 4222 CodeBreakpoint* curr_bpt = code_breakpoints_; |
| 4411 while (curr_bpt != NULL) { | 4223 while (curr_bpt != NULL) { |
| 4412 if (curr_bpt->bpt_location() == bpt_location) { | 4224 if (curr_bpt->bpt_location() == bpt_location) { |
| 4413 curr_bpt->Disable(); | 4225 curr_bpt->Disable(); |
| 4414 curr_bpt->set_bpt_location(NULL); | 4226 curr_bpt->set_bpt_location(NULL); |
| 4415 needs_breakpoint_cleanup_ = true; | 4227 needs_breakpoint_cleanup_ = true; |
| 4416 } | 4228 } |
| 4417 curr_bpt = curr_bpt->next(); | 4229 curr_bpt = curr_bpt->next(); |
| 4418 } | 4230 } |
| 4419 } | 4231 } |
| 4420 | 4232 |
| 4421 | |
| 4422 // Remove and delete unlinked code breakpoints, i.e. breakpoints that | 4233 // Remove and delete unlinked code breakpoints, i.e. breakpoints that |
| 4423 // are not associated with a breakpoint location. | 4234 // are not associated with a breakpoint location. |
| 4424 void Debugger::RemoveUnlinkedCodeBreakpoints() { | 4235 void Debugger::RemoveUnlinkedCodeBreakpoints() { |
| 4425 CodeBreakpoint* prev_bpt = NULL; | 4236 CodeBreakpoint* prev_bpt = NULL; |
| 4426 CodeBreakpoint* curr_bpt = code_breakpoints_; | 4237 CodeBreakpoint* curr_bpt = code_breakpoints_; |
| 4427 while (curr_bpt != NULL) { | 4238 while (curr_bpt != NULL) { |
| 4428 if (curr_bpt->bpt_location() == NULL) { | 4239 if (curr_bpt->bpt_location() == NULL) { |
| 4429 if (prev_bpt == NULL) { | 4240 if (prev_bpt == NULL) { |
| 4430 code_breakpoints_ = code_breakpoints_->next(); | 4241 code_breakpoints_ = code_breakpoints_->next(); |
| 4431 } else { | 4242 } else { |
| 4432 prev_bpt->set_next(curr_bpt->next()); | 4243 prev_bpt->set_next(curr_bpt->next()); |
| 4433 } | 4244 } |
| 4434 CodeBreakpoint* temp_bpt = curr_bpt; | 4245 CodeBreakpoint* temp_bpt = curr_bpt; |
| 4435 curr_bpt = curr_bpt->next(); | 4246 curr_bpt = curr_bpt->next(); |
| 4436 temp_bpt->Disable(); | 4247 temp_bpt->Disable(); |
| 4437 delete temp_bpt; | 4248 delete temp_bpt; |
| 4438 } else { | 4249 } else { |
| 4439 prev_bpt = curr_bpt; | 4250 prev_bpt = curr_bpt; |
| 4440 curr_bpt = curr_bpt->next(); | 4251 curr_bpt = curr_bpt->next(); |
| 4441 } | 4252 } |
| 4442 } | 4253 } |
| 4443 needs_breakpoint_cleanup_ = false; | 4254 needs_breakpoint_cleanup_ = false; |
| 4444 } | 4255 } |
| 4445 | 4256 |
| 4446 | |
| 4447 BreakpointLocation* Debugger::GetBreakpointLocation(const Script& script, | 4257 BreakpointLocation* Debugger::GetBreakpointLocation(const Script& script, |
| 4448 TokenPosition token_pos, | 4258 TokenPosition token_pos, |
| 4449 intptr_t requested_column) { | 4259 intptr_t requested_column) { |
| 4450 BreakpointLocation* bpt = breakpoint_locations_; | 4260 BreakpointLocation* bpt = breakpoint_locations_; |
| 4451 while (bpt != NULL) { | 4261 while (bpt != NULL) { |
| 4452 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos) && | 4262 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos) && |
| 4453 (bpt->requested_column_number_ == requested_column)) { | 4263 (bpt->requested_column_number_ == requested_column)) { |
| 4454 return bpt; | 4264 return bpt; |
| 4455 } | 4265 } |
| 4456 bpt = bpt->next(); | 4266 bpt = bpt->next(); |
| 4457 } | 4267 } |
| 4458 return NULL; | 4268 return NULL; |
| 4459 } | 4269 } |
| 4460 | 4270 |
| 4461 | |
| 4462 Breakpoint* Debugger::GetBreakpointById(intptr_t id) { | 4271 Breakpoint* Debugger::GetBreakpointById(intptr_t id) { |
| 4463 Breakpoint* bpt = GetBreakpointByIdInTheList(id, breakpoint_locations_); | 4272 Breakpoint* bpt = GetBreakpointByIdInTheList(id, breakpoint_locations_); |
| 4464 if (bpt != NULL) { | 4273 if (bpt != NULL) { |
| 4465 return bpt; | 4274 return bpt; |
| 4466 } | 4275 } |
| 4467 return GetBreakpointByIdInTheList(id, latent_locations_); | 4276 return GetBreakpointByIdInTheList(id, latent_locations_); |
| 4468 } | 4277 } |
| 4469 | 4278 |
| 4470 | |
| 4471 Breakpoint* Debugger::GetBreakpointByIdInTheList(intptr_t id, | 4279 Breakpoint* Debugger::GetBreakpointByIdInTheList(intptr_t id, |
| 4472 BreakpointLocation* list) { | 4280 BreakpointLocation* list) { |
| 4473 BreakpointLocation* loc = list; | 4281 BreakpointLocation* loc = list; |
| 4474 while (loc != NULL) { | 4282 while (loc != NULL) { |
| 4475 Breakpoint* bpt = loc->breakpoints(); | 4283 Breakpoint* bpt = loc->breakpoints(); |
| 4476 while (bpt != NULL) { | 4284 while (bpt != NULL) { |
| 4477 if (bpt->id() == id) { | 4285 if (bpt->id() == id) { |
| 4478 return bpt; | 4286 return bpt; |
| 4479 } | 4287 } |
| 4480 bpt = bpt->next(); | 4288 bpt = bpt->next(); |
| 4481 } | 4289 } |
| 4482 loc = loc->next(); | 4290 loc = loc->next(); |
| 4483 } | 4291 } |
| 4484 return NULL; | 4292 return NULL; |
| 4485 } | 4293 } |
| 4486 | 4294 |
| 4487 | |
| 4488 void Debugger::MaybeAsyncStepInto(const Closure& async_op) { | 4295 void Debugger::MaybeAsyncStepInto(const Closure& async_op) { |
| 4489 if (FLAG_async_debugger && IsSingleStepping()) { | 4296 if (FLAG_async_debugger && IsSingleStepping()) { |
| 4490 // We are single stepping, set a breakpoint on the closure activation | 4297 // We are single stepping, set a breakpoint on the closure activation |
| 4491 // and resume execution so we can hit the breakpoint. | 4298 // and resume execution so we can hit the breakpoint. |
| 4492 AsyncStepInto(async_op); | 4299 AsyncStepInto(async_op); |
| 4493 } | 4300 } |
| 4494 } | 4301 } |
| 4495 | 4302 |
| 4496 | |
| 4497 void Debugger::AsyncStepInto(const Closure& async_op) { | 4303 void Debugger::AsyncStepInto(const Closure& async_op) { |
| 4498 SetBreakpointAtActivation(async_op, true); | 4304 SetBreakpointAtActivation(async_op, true); |
| 4499 Continue(); | 4305 Continue(); |
| 4500 } | 4306 } |
| 4501 | 4307 |
| 4502 | |
| 4503 void Debugger::Continue() { | 4308 void Debugger::Continue() { |
| 4504 SetResumeAction(kContinue); | 4309 SetResumeAction(kContinue); |
| 4505 stepping_fp_ = 0; | 4310 stepping_fp_ = 0; |
| 4506 async_stepping_fp_ = 0; | 4311 async_stepping_fp_ = 0; |
| 4507 isolate_->set_single_step(false); | 4312 isolate_->set_single_step(false); |
| 4508 } | 4313 } |
| 4509 | 4314 |
| 4510 | |
| 4511 BreakpointLocation* Debugger::GetLatentBreakpoint(const String& url, | 4315 BreakpointLocation* Debugger::GetLatentBreakpoint(const String& url, |
| 4512 intptr_t line, | 4316 intptr_t line, |
| 4513 intptr_t column) { | 4317 intptr_t column) { |
| 4514 BreakpointLocation* bpt = latent_locations_; | 4318 BreakpointLocation* bpt = latent_locations_; |
| 4515 String& bpt_url = String::Handle(); | 4319 String& bpt_url = String::Handle(); |
| 4516 while (bpt != NULL) { | 4320 while (bpt != NULL) { |
| 4517 bpt_url = bpt->url(); | 4321 bpt_url = bpt->url(); |
| 4518 if (bpt_url.Equals(url) && (bpt->requested_line_number() == line) && | 4322 if (bpt_url.Equals(url) && (bpt->requested_line_number() == line) && |
| 4519 (bpt->requested_column_number() == column)) { | 4323 (bpt->requested_column_number() == column)) { |
| 4520 return bpt; | 4324 return bpt; |
| 4521 } | 4325 } |
| 4522 bpt = bpt->next(); | 4326 bpt = bpt->next(); |
| 4523 } | 4327 } |
| 4524 // No breakpoint for this location requested. Allocate new one. | 4328 // No breakpoint for this location requested. Allocate new one. |
| 4525 bpt = new BreakpointLocation(url, line, column); | 4329 bpt = new BreakpointLocation(url, line, column); |
| 4526 bpt->set_next(latent_locations_); | 4330 bpt->set_next(latent_locations_); |
| 4527 latent_locations_ = bpt; | 4331 latent_locations_ = bpt; |
| 4528 return bpt; | 4332 return bpt; |
| 4529 } | 4333 } |
| 4530 | 4334 |
| 4531 | |
| 4532 void Debugger::RegisterBreakpointLocation(BreakpointLocation* bpt) { | 4335 void Debugger::RegisterBreakpointLocation(BreakpointLocation* bpt) { |
| 4533 ASSERT(bpt->next() == NULL); | 4336 ASSERT(bpt->next() == NULL); |
| 4534 bpt->set_next(breakpoint_locations_); | 4337 bpt->set_next(breakpoint_locations_); |
| 4535 breakpoint_locations_ = bpt; | 4338 breakpoint_locations_ = bpt; |
| 4536 } | 4339 } |
| 4537 | 4340 |
| 4538 | |
| 4539 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 4341 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 4540 ASSERT(bpt->next() == NULL); | 4342 ASSERT(bpt->next() == NULL); |
| 4541 bpt->set_next(code_breakpoints_); | 4343 bpt->set_next(code_breakpoints_); |
| 4542 code_breakpoints_ = bpt; | 4344 code_breakpoints_ = bpt; |
| 4543 } | 4345 } |
| 4544 | 4346 |
| 4545 #endif // !PRODUCT | 4347 #endif // !PRODUCT |
| 4546 | 4348 |
| 4547 } // namespace dart | 4349 } // namespace dart |
| OLD | NEW |