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 "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
10 #include "vm/code_patcher.h" | 10 #include "vm/code_patcher.h" |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 context_level_(-1), | 256 context_level_(-1), |
257 deopt_frame_(Array::ZoneHandle(deopt_frame.raw())), | 257 deopt_frame_(Array::ZoneHandle(deopt_frame.raw())), |
258 deopt_frame_offset_(deopt_frame_offset), | 258 deopt_frame_offset_(deopt_frame_offset), |
259 vars_initialized_(false), | 259 vars_initialized_(false), |
260 var_descriptors_(LocalVarDescriptors::ZoneHandle()), | 260 var_descriptors_(LocalVarDescriptors::ZoneHandle()), |
261 desc_indices_(8), | 261 desc_indices_(8), |
262 pc_desc_(PcDescriptors::ZoneHandle()) { | 262 pc_desc_(PcDescriptors::ZoneHandle()) { |
263 } | 263 } |
264 | 264 |
265 | 265 |
266 void DebuggerEvent::UpdateTimestamp() { | 266 bool Debugger::NeedsIsolateEvents() { |
267 timestamp_ = OS::GetCurrentTimeMillis(); | 267 return ((isolate_ != Dart::vm_isolate()) && |
| 268 !ServiceIsolate::IsServiceIsolateDescendant(isolate_) && |
| 269 ((event_handler_ != NULL) || Service::isolate_stream.enabled())); |
268 } | 270 } |
269 | 271 |
270 | 272 |
271 bool Debugger::HasAnyEventHandler() { | 273 bool Debugger::NeedsDebugEvents() { |
272 return ((event_handler_ != NULL) || | 274 ASSERT(isolate_ != Dart::vm_isolate() && |
273 Service::isolate_stream.enabled() || | 275 !ServiceIsolate::IsServiceIsolateDescendant(isolate_)); |
| 276 return (FLAG_warn_on_pause_with_no_debugger || |
| 277 (event_handler_ != NULL) || |
274 Service::debug_stream.enabled()); | 278 Service::debug_stream.enabled()); |
275 } | 279 } |
276 | 280 |
277 | 281 |
278 bool Debugger::HasDebugEventHandler() { | 282 void Debugger::InvokeEventHandler(ServiceEvent* event) { |
279 return ((event_handler_ != NULL) || | 283 ASSERT(!event->IsPause()); // For pause events, call Pause instead. |
280 Service::debug_stream.enabled()); | 284 Service::HandleEvent(event); |
281 } | |
282 | 285 |
283 | 286 // Call the embedder's event handler, if it exists. |
284 static bool ServiceNeedsDebuggerEvent(DebuggerEvent::EventType type) { | 287 if (event_handler_ != NULL) { |
285 switch (type) { | 288 TransitionVMToNative transition(Thread::Current()); |
286 case DebuggerEvent::kBreakpointResolved: | 289 (*event_handler_)(event); |
287 // kBreakpointResolved events are handled differently in the vm | |
288 // service, so suppress them here. | |
289 return false; | |
290 | |
291 case DebuggerEvent::kBreakpointReached: | |
292 case DebuggerEvent::kExceptionThrown: | |
293 case DebuggerEvent::kIsolateInterrupted: | |
294 return (Service::debug_stream.enabled() || | |
295 FLAG_warn_on_pause_with_no_debugger); | |
296 | |
297 case DebuggerEvent::kIsolateCreated: | |
298 case DebuggerEvent::kIsolateShutdown: | |
299 return Service::isolate_stream.enabled(); | |
300 | |
301 default: | |
302 UNREACHABLE(); | |
303 return false; | |
304 } | 290 } |
305 } | 291 } |
306 | 292 |
307 | 293 |
308 void Debugger::InvokeEventHandler(DebuggerEvent* event) { | 294 RawError* Debugger::PauseInterrupted() { |
309 // Give the event to the Service first, as the debugger event handler | 295 if (ignore_breakpoints_ || IsPaused()) { |
310 // may go into a message loop and the Service will not. | 296 // We don't let the isolate get interrupted if we are already |
311 // | 297 // paused or ignoring breakpoints. |
312 // kBreakpointResolved events are handled differently in the vm | 298 return Error::null(); |
313 // service, so suppress them here. | |
314 if (ServiceNeedsDebuggerEvent(event->type())) { | |
315 ServiceEvent service_event(event); | |
316 Service::HandleEvent(&service_event); | |
317 } | 299 } |
318 | 300 ServiceEvent event(isolate_, ServiceEvent::kPauseInterrupted); |
319 { | 301 DebuggerStackTrace* trace = CollectStackTrace(); |
320 TransitionVMToNative transition(Thread::Current()); | 302 if (trace->Length() > 0) { |
321 if ((FLAG_steal_breakpoints || (event_handler_ == NULL)) && | 303 event.set_top_frame(trace->FrameAt(0)); |
322 event->IsPauseEvent()) { | |
323 // We allow the embedder's default breakpoint handler to be overridden. | |
324 isolate_->PauseEventHandler(); | |
325 } else if (event_handler_ != NULL) { | |
326 (*event_handler_)(event); | |
327 } | |
328 } | 304 } |
329 | 305 ASSERT(stack_trace_ == NULL); |
330 if (ServiceNeedsDebuggerEvent(event->type()) && event->IsPauseEvent()) { | 306 stack_trace_ = trace; |
331 // If we were paused, notify the service that we have resumed. | 307 resume_action_ = kContinue; |
332 const Error& error = | 308 Pause(&event); |
333 Error::Handle(Thread::Current()->sticky_error()); | 309 HandleSteppingRequest(trace); |
334 ASSERT(error.IsNull() || | 310 stack_trace_ = NULL; |
335 error.IsUnwindError() || | |
336 error.IsUnhandledException()); | |
337 | |
338 // Only send a resume event when the isolate is not unwinding. | |
339 if (!error.IsUnwindError()) { | |
340 ServiceEvent service_event(event->isolate(), ServiceEvent::kResume); | |
341 service_event.set_top_frame(event->top_frame()); | |
342 Service::HandleEvent(&service_event); | |
343 } | |
344 } | |
345 } | |
346 | |
347 | |
348 void Debugger::SignalIsolateEvent(DebuggerEvent::EventType type) { | |
349 if (HasAnyEventHandler()) { | |
350 DebuggerEvent event(isolate_, type); | |
351 ASSERT(event.isolate_id() != ILLEGAL_ISOLATE_ID); | |
352 if (type == DebuggerEvent::kIsolateInterrupted) { | |
353 DebuggerStackTrace* trace = CollectStackTrace(); | |
354 if (trace->Length() > 0) { | |
355 event.set_top_frame(trace->FrameAt(0)); | |
356 } | |
357 ASSERT(stack_trace_ == NULL); | |
358 stack_trace_ = trace; | |
359 resume_action_ = kContinue; | |
360 Pause(&event); | |
361 HandleSteppingRequest(trace); | |
362 stack_trace_ = NULL; | |
363 } else { | |
364 InvokeEventHandler(&event); | |
365 } | |
366 } | |
367 } | |
368 | |
369 | |
370 RawError* Debugger::SignalIsolateInterrupted() { | |
371 if (HasDebugEventHandler()) { | |
372 SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted); | |
373 } | |
374 | 311 |
375 // If any error occurred while in the debug message loop, return it here. | 312 // If any error occurred while in the debug message loop, return it here. |
376 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 313 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
377 ASSERT(error.IsNull() || error.IsUnwindError()); | 314 ASSERT(error.IsNull() || error.IsUnwindError()); |
378 Thread::Current()->clear_sticky_error(); | 315 Thread::Current()->clear_sticky_error(); |
379 return error.raw(); | 316 return error.raw(); |
380 } | 317 } |
381 | 318 |
382 | 319 |
383 // The vm service handles breakpoint notifications in a different way | 320 void Debugger::SendBreakpointEvent(ServiceEvent::EventKind kind, |
384 // than the regular debugger breakpoint notifications. | 321 Breakpoint* bpt) { |
385 static void SendServiceBreakpointEvent(ServiceEvent::EventKind kind, | 322 if (NeedsDebugEvents()) { |
386 Breakpoint* bpt) { | 323 // TODO(turnidge): Currently we send single-shot breakpoint events |
387 if (Service::debug_stream.enabled()) { | 324 // to the vm service. Do we want to change this? |
388 ServiceEvent service_event(Isolate::Current(), kind); | 325 ServiceEvent event(isolate_, kind); |
389 service_event.set_breakpoint(bpt); | 326 event.set_breakpoint(bpt); |
390 Service::HandleEvent(&service_event); | 327 InvokeEventHandler(&event); |
391 } | 328 } |
392 } | 329 } |
393 | 330 |
394 | 331 |
395 void BreakpointLocation::AddBreakpoint(Breakpoint* bpt, Debugger* dbg) { | 332 void BreakpointLocation::AddBreakpoint(Breakpoint* bpt, Debugger* dbg) { |
396 bpt->set_next(breakpoints()); | 333 bpt->set_next(breakpoints()); |
397 set_breakpoints(bpt); | 334 set_breakpoints(bpt); |
398 | 335 |
399 dbg->SyncBreakpointLocation(this); | 336 dbg->SyncBreakpointLocation(this); |
400 | 337 dbg->SendBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); |
401 if (IsResolved()) { | |
402 dbg->SignalBpResolved(bpt); | |
403 } | |
404 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); | |
405 } | 338 } |
406 | 339 |
407 | 340 |
408 Breakpoint* BreakpointLocation::AddRepeated(Debugger* dbg) { | 341 Breakpoint* BreakpointLocation::AddRepeated(Debugger* dbg) { |
409 Breakpoint* bpt = breakpoints(); | 342 Breakpoint* bpt = breakpoints(); |
410 while (bpt != NULL) { | 343 while (bpt != NULL) { |
411 if (bpt->IsRepeated()) break; | 344 if (bpt->IsRepeated()) break; |
412 bpt = bpt->next(); | 345 bpt = bpt->next(); |
413 } | 346 } |
414 if (bpt == NULL) { | 347 if (bpt == NULL) { |
(...skipping 848 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1263 RawObject* RemoteObjectCache::GetObj(intptr_t obj_id) const { | 1196 RawObject* RemoteObjectCache::GetObj(intptr_t obj_id) const { |
1264 ASSERT(IsValidId(obj_id)); | 1197 ASSERT(IsValidId(obj_id)); |
1265 return objs_->At(obj_id); | 1198 return objs_->At(obj_id); |
1266 } | 1199 } |
1267 | 1200 |
1268 | 1201 |
1269 Debugger::Debugger() | 1202 Debugger::Debugger() |
1270 : isolate_(NULL), | 1203 : isolate_(NULL), |
1271 isolate_id_(ILLEGAL_ISOLATE_ID), | 1204 isolate_id_(ILLEGAL_ISOLATE_ID), |
1272 initialized_(false), | 1205 initialized_(false), |
1273 creation_message_sent_(false), | |
1274 next_id_(1), | 1206 next_id_(1), |
1275 latent_locations_(NULL), | 1207 latent_locations_(NULL), |
1276 breakpoint_locations_(NULL), | 1208 breakpoint_locations_(NULL), |
1277 code_breakpoints_(NULL), | 1209 code_breakpoints_(NULL), |
1278 resume_action_(kContinue), | 1210 resume_action_(kContinue), |
1279 ignore_breakpoints_(false), | 1211 ignore_breakpoints_(false), |
1280 pause_event_(NULL), | 1212 pause_event_(NULL), |
1281 obj_cache_(NULL), | 1213 obj_cache_(NULL), |
1282 stack_trace_(NULL), | 1214 stack_trace_(NULL), |
1283 stepping_fp_(0), | 1215 stepping_fp_(0), |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1315 BreakpointLocation* bpt = latent_locations_; | 1247 BreakpointLocation* bpt = latent_locations_; |
1316 latent_locations_ = latent_locations_->next(); | 1248 latent_locations_ = latent_locations_->next(); |
1317 delete bpt; | 1249 delete bpt; |
1318 } | 1250 } |
1319 while (code_breakpoints_ != NULL) { | 1251 while (code_breakpoints_ != NULL) { |
1320 CodeBreakpoint* bpt = code_breakpoints_; | 1252 CodeBreakpoint* bpt = code_breakpoints_; |
1321 code_breakpoints_ = code_breakpoints_->next(); | 1253 code_breakpoints_ = code_breakpoints_->next(); |
1322 bpt->Disable(); | 1254 bpt->Disable(); |
1323 delete bpt; | 1255 delete bpt; |
1324 } | 1256 } |
1325 // Signal isolate shutdown event, but only if we previously sent the creation | 1257 if (NeedsIsolateEvents()) { |
1326 // event. | 1258 ServiceEvent event(isolate_, ServiceEvent::kIsolateExit); |
1327 if (creation_message_sent_) { | 1259 InvokeEventHandler(&event); |
1328 SignalIsolateEvent(DebuggerEvent::kIsolateShutdown); | |
1329 } | 1260 } |
1330 } | 1261 } |
1331 | 1262 |
1332 | 1263 |
1333 static RawFunction* ResolveLibraryFunction( | 1264 static RawFunction* ResolveLibraryFunction( |
1334 const Library& library, | 1265 const Library& library, |
1335 const String& fname) { | 1266 const String& fname) { |
1336 ASSERT(!library.IsNull()); | 1267 ASSERT(!library.IsNull()); |
1337 const Object& object = Object::Handle(library.ResolveName(fname)); | 1268 const Object& object = Object::Handle(library.ResolveName(fname)); |
1338 if (!object.IsNull() && object.IsFunction()) { | 1269 if (!object.IsNull() && object.IsFunction()) { |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1444 for (intptr_t pos = 0; pos < num_closures; pos++) { | 1375 for (intptr_t pos = 0; pos < num_closures; pos++) { |
1445 function ^= closures.At(pos); | 1376 function ^= closures.At(pos); |
1446 ASSERT(!function.IsNull()); | 1377 ASSERT(!function.IsNull()); |
1447 if (function.HasOptimizedCode()) { | 1378 if (function.HasOptimizedCode()) { |
1448 function.SwitchToUnoptimizedCode(); | 1379 function.SwitchToUnoptimizedCode(); |
1449 } | 1380 } |
1450 } | 1381 } |
1451 } | 1382 } |
1452 | 1383 |
1453 | 1384 |
1454 void Debugger::SignalBpResolved(Breakpoint* bpt) { | |
1455 if (HasDebugEventHandler() && !bpt->IsSingleShot()) { | |
1456 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved); | |
1457 event.set_breakpoint(bpt); | |
1458 InvokeEventHandler(&event); | |
1459 } | |
1460 } | |
1461 | |
1462 | |
1463 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, | 1385 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, |
1464 uword pc, | 1386 uword pc, |
1465 StackFrame* frame, | 1387 StackFrame* frame, |
1466 const Code& code, | 1388 const Code& code, |
1467 const Array& deopt_frame, | 1389 const Array& deopt_frame, |
1468 intptr_t deopt_frame_offset) { | 1390 intptr_t deopt_frame_offset) { |
1469 ASSERT(code.ContainsInstructionAt(pc)); | 1391 ASSERT(code.ContainsInstructionAt(pc)); |
1470 ActivationFrame* activation = | 1392 ActivationFrame* activation = |
1471 new ActivationFrame(pc, frame->fp(), frame->sp(), code, | 1393 new ActivationFrame(pc, frame->fp(), frame->sp(), code, |
1472 deopt_frame, deopt_frame_offset); | 1394 deopt_frame, deopt_frame_offset); |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1660 // Note that this check is not precise, since we can't check | 1582 // Note that this check is not precise, since we can't check |
1661 // uninstantiated types, i.e. types containing type parameters. | 1583 // uninstantiated types, i.e. types containing type parameters. |
1662 // Thus, we may report an exception as unhandled when in fact | 1584 // Thus, we may report an exception as unhandled when in fact |
1663 // it will be caught once we unwind the stack. | 1585 // it will be caught once we unwind the stack. |
1664 return true; | 1586 return true; |
1665 } | 1587 } |
1666 return false; | 1588 return false; |
1667 } | 1589 } |
1668 | 1590 |
1669 | 1591 |
1670 void Debugger::SignalExceptionThrown(const Instance& exc) { | 1592 void Debugger::PauseException(const Instance& exc) { |
1671 // We ignore this exception event when the VM is executing code invoked | 1593 // We ignore this exception event when the VM is executing code invoked |
1672 // by the debugger to evaluate variables values, when we see a nested | 1594 // by the debugger to evaluate variables values, when we see a nested |
1673 // breakpoint or exception event, or if the debugger is not | 1595 // breakpoint or exception event, or if the debugger is not |
1674 // interested in exception events. | 1596 // interested in exception events. |
1675 if (ignore_breakpoints_ || | 1597 if (ignore_breakpoints_ || |
1676 IsPaused() || | 1598 IsPaused() || |
1677 (exc_pause_info_ == kNoPauseOnExceptions)) { | 1599 (exc_pause_info_ == kNoPauseOnExceptions)) { |
1678 return; | 1600 return; |
1679 } | 1601 } |
1680 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 1602 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
1681 if (!ShouldPauseOnException(stack_trace, exc)) { | 1603 if (!ShouldPauseOnException(stack_trace, exc)) { |
1682 return; | 1604 return; |
1683 } | 1605 } |
1684 DebuggerEvent event(isolate_, DebuggerEvent::kExceptionThrown); | 1606 ServiceEvent event(isolate_, ServiceEvent::kPauseException); |
1685 event.set_exception(&exc); | 1607 event.set_exception(&exc); |
1686 if (stack_trace->Length() > 0) { | 1608 if (stack_trace->Length() > 0) { |
1687 event.set_top_frame(stack_trace->FrameAt(0)); | 1609 event.set_top_frame(stack_trace->FrameAt(0)); |
1688 } | 1610 } |
1689 ASSERT(stack_trace_ == NULL); | 1611 ASSERT(stack_trace_ == NULL); |
1690 stack_trace_ = stack_trace; | 1612 stack_trace_ = stack_trace; |
1691 Pause(&event); | 1613 Pause(&event); |
1692 stack_trace_ = NULL; | 1614 stack_trace_ = NULL; |
1693 } | 1615 } |
1694 | 1616 |
(...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2229 } | 2151 } |
2230 loc = loc->next(); | 2152 loc = loc->next(); |
2231 } | 2153 } |
2232 | 2154 |
2233 return NULL; | 2155 return NULL; |
2234 } | 2156 } |
2235 | 2157 |
2236 | 2158 |
2237 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 2159 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, |
2238 intptr_t line_number) { | 2160 intptr_t line_number) { |
| 2161 // Prevent future tests from calling this function in the wrong |
| 2162 // execution state. If you hit this assert, consider using |
| 2163 // Dart_SetBreakpoint instead. |
| 2164 ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM); |
| 2165 |
2239 BreakpointLocation* loc = | 2166 BreakpointLocation* loc = |
2240 BreakpointLocationAtLineCol(script_url, line_number, -1 /* no column */); | 2167 BreakpointLocationAtLineCol(script_url, line_number, -1 /* no column */); |
2241 if (loc != NULL) { | 2168 if (loc != NULL) { |
2242 return loc->AddRepeated(this); | 2169 return loc->AddRepeated(this); |
2243 } | 2170 } |
2244 return NULL; | 2171 return NULL; |
2245 } | 2172 } |
2246 | 2173 |
2247 | 2174 |
2248 Breakpoint* Debugger::SetBreakpointAtLineCol(const String& script_url, | 2175 Breakpoint* Debugger::SetBreakpointAtLineCol(const String& script_url, |
2249 intptr_t line_number, | 2176 intptr_t line_number, |
2250 intptr_t column_number) { | 2177 intptr_t column_number) { |
| 2178 // Prevent future tests from calling this function in the wrong |
| 2179 // execution state. If you hit this assert, consider using |
| 2180 // Dart_SetBreakpoint instead. |
| 2181 ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM); |
| 2182 |
2251 BreakpointLocation* loc = BreakpointLocationAtLineCol(script_url, | 2183 BreakpointLocation* loc = BreakpointLocationAtLineCol(script_url, |
2252 line_number, | 2184 line_number, |
2253 column_number); | 2185 column_number); |
2254 if (loc != NULL) { | 2186 if (loc != NULL) { |
2255 return loc->AddRepeated(this); | 2187 return loc->AddRepeated(this); |
2256 } | 2188 } |
2257 return NULL; | 2189 return NULL; |
2258 } | 2190 } |
2259 | 2191 |
2260 | 2192 |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2551 } | 2483 } |
2552 } | 2484 } |
2553 | 2485 |
2554 | 2486 |
2555 // static | 2487 // static |
2556 void Debugger::SetEventHandler(EventHandler* handler) { | 2488 void Debugger::SetEventHandler(EventHandler* handler) { |
2557 event_handler_ = handler; | 2489 event_handler_ = handler; |
2558 } | 2490 } |
2559 | 2491 |
2560 | 2492 |
2561 void Debugger::Pause(DebuggerEvent* event) { | 2493 void Debugger::Pause(ServiceEvent* event) { |
2562 ASSERT(!IsPaused()); // No recursive pausing. | 2494 ASSERT(event->IsPause()); // Should call InvokeEventHandler instead. |
| 2495 ASSERT(!ignore_breakpoints_); // We shouldn't get here when ignoring bpts. |
| 2496 ASSERT(!IsPaused()); // No recursive pausing. |
2563 ASSERT(obj_cache_ == NULL); | 2497 ASSERT(obj_cache_ == NULL); |
2564 | 2498 |
2565 pause_event_ = event; | 2499 pause_event_ = event; |
2566 pause_event_->UpdateTimestamp(); | 2500 pause_event_->UpdateTimestamp(); |
2567 obj_cache_ = new RemoteObjectCache(64); | 2501 obj_cache_ = new RemoteObjectCache(64); |
2568 | 2502 |
2569 // We are about to invoke the debuggers event handler. Disable interrupts | 2503 // We are about to invoke the debugger's event handler. Disable |
2570 // for this thread while waiting for debug commands over the service protocol. | 2504 // interrupts for this thread while waiting for debug commands over |
| 2505 // the service protocol. |
2571 { | 2506 { |
2572 Thread* thread = Thread::Current(); | 2507 Thread* thread = Thread::Current(); |
2573 DisableThreadInterruptsScope dtis(thread); | 2508 DisableThreadInterruptsScope dtis(thread); |
2574 TimelineDurationScope tds(thread, | 2509 TimelineDurationScope tds(thread, |
2575 Timeline::GetDebuggerStream(), | 2510 Timeline::GetDebuggerStream(), |
2576 "Debugger Pause"); | 2511 "Debugger Pause"); |
2577 InvokeEventHandler(event); | 2512 |
| 2513 // Send the pause event. |
| 2514 Service::HandleEvent(event); |
| 2515 |
| 2516 { |
| 2517 TransitionVMToNative transition(Thread::Current()); |
| 2518 if (FLAG_steal_breakpoints || (event_handler_ == NULL)) { |
| 2519 // We allow the embedder's default breakpoint handler to be overridden. |
| 2520 isolate_->PauseEventHandler(); |
| 2521 } else if (event_handler_ != NULL) { |
| 2522 (*event_handler_)(event); |
| 2523 } |
| 2524 } |
| 2525 |
| 2526 // Notify the service that we have resumed. |
| 2527 const Error& error = |
| 2528 Error::Handle(Thread::Current()->sticky_error()); |
| 2529 ASSERT(error.IsNull() || |
| 2530 error.IsUnwindError() || |
| 2531 error.IsUnhandledException()); |
| 2532 |
| 2533 // Only send a resume event when the isolate is not unwinding. |
| 2534 if (!error.IsUnwindError()) { |
| 2535 ServiceEvent resume_event(event->isolate(), ServiceEvent::kResume); |
| 2536 resume_event.set_top_frame(event->top_frame()); |
| 2537 Service::HandleEvent(&resume_event); |
| 2538 } |
2578 } | 2539 } |
2579 | 2540 |
2580 pause_event_ = NULL; | 2541 pause_event_ = NULL; |
2581 obj_cache_ = NULL; // Zone allocated | 2542 obj_cache_ = NULL; // Zone allocated |
2582 } | 2543 } |
2583 | 2544 |
2584 | 2545 |
2585 void Debugger::EnterSingleStepMode() { | 2546 void Debugger::EnterSingleStepMode() { |
2586 stepping_fp_ = 0; | 2547 stepping_fp_ = 0; |
2587 DeoptimizeWorld(); | 2548 DeoptimizeWorld(); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2650 resume_action_ = kContinue; | 2611 resume_action_ = kContinue; |
2651 stepping_fp_ = 0; | 2612 stepping_fp_ = 0; |
2652 isolate_->set_single_step(false); | 2613 isolate_->set_single_step(false); |
2653 ASSERT(!IsPaused()); | 2614 ASSERT(!IsPaused()); |
2654 ASSERT(obj_cache_ == NULL); | 2615 ASSERT(obj_cache_ == NULL); |
2655 if ((bpt != NULL) && bpt->IsSingleShot()) { | 2616 if ((bpt != NULL) && bpt->IsSingleShot()) { |
2656 RemoveBreakpoint(bpt->id()); | 2617 RemoveBreakpoint(bpt->id()); |
2657 bpt = NULL; | 2618 bpt = NULL; |
2658 } | 2619 } |
2659 | 2620 |
2660 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); | 2621 ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint); |
2661 event.set_top_frame(top_frame); | 2622 event.set_top_frame(top_frame); |
2662 event.set_breakpoint(bpt); | 2623 event.set_breakpoint(bpt); |
2663 event.set_at_async_jump(IsAtAsyncJump(top_frame)); | 2624 event.set_at_async_jump(IsAtAsyncJump(top_frame)); |
2664 Pause(&event); | 2625 Pause(&event); |
2665 } | 2626 } |
2666 | 2627 |
2667 | 2628 |
2668 bool Debugger::IsAtAsyncJump(ActivationFrame* top_frame) { | 2629 bool Debugger::IsAtAsyncJump(ActivationFrame* top_frame) { |
2669 Zone* zone = Thread::Current()->zone(); | 2630 Zone* zone = Thread::Current()->zone(); |
2670 Object& closure_or_null = | 2631 Object& closure_or_null = |
2671 Object::Handle(zone, top_frame->GetAsyncOperation()); | 2632 Object::Handle(zone, top_frame->GetAsyncOperation()); |
2672 if (!closure_or_null.IsNull()) { | 2633 if (!closure_or_null.IsNull()) { |
2673 ASSERT(closure_or_null.IsInstance()); | 2634 ASSERT(closure_or_null.IsInstance()); |
2674 ASSERT(Instance::Cast(closure_or_null).IsClosure()); | 2635 ASSERT(Instance::Cast(closure_or_null).IsClosure()); |
2675 const Script& script = Script::Handle(zone, top_frame->SourceScript()); | 2636 const Script& script = Script::Handle(zone, top_frame->SourceScript()); |
2676 const TokenStream& tokens = TokenStream::Handle(zone, script.tokens()); | 2637 const TokenStream& tokens = TokenStream::Handle(zone, script.tokens()); |
2677 TokenStream::Iterator iter(zone, tokens, top_frame->TokenPos()); | 2638 TokenStream::Iterator iter(zone, tokens, top_frame->TokenPos()); |
2678 if ((iter.CurrentTokenKind() == Token::kIDENT) && | 2639 if ((iter.CurrentTokenKind() == Token::kIDENT) && |
2679 ((iter.CurrentLiteral() == Symbols::Await().raw()) || | 2640 ((iter.CurrentLiteral() == Symbols::Await().raw()) || |
2680 (iter.CurrentLiteral() == Symbols::YieldKw().raw()))) { | 2641 (iter.CurrentLiteral() == Symbols::YieldKw().raw()))) { |
2681 return true; | 2642 return true; |
2682 } | 2643 } |
2683 } | 2644 } |
2684 return false; | 2645 return false; |
2685 } | 2646 } |
2686 | 2647 |
2687 RawError* Debugger::DebuggerStepCallback() { | 2648 RawError* Debugger::PauseStepping() { |
2688 ASSERT(isolate_->single_step()); | 2649 ASSERT(isolate_->single_step()); |
2689 // Don't pause recursively. | 2650 // Don't pause recursively. |
2690 if (IsPaused()) { | 2651 if (IsPaused()) { |
2691 return Error::null(); | 2652 return Error::null(); |
2692 } | 2653 } |
2693 if (skip_next_step_) { | 2654 if (skip_next_step_) { |
2694 skip_next_step_ = false; | 2655 skip_next_step_ = false; |
2695 return Error::null(); | 2656 return Error::null(); |
2696 } | 2657 } |
2697 | 2658 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2734 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", | 2695 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", |
2735 String::Handle(frame->SourceUrl()).ToCString(), | 2696 String::Handle(frame->SourceUrl()).ToCString(), |
2736 frame->LineNumber(), | 2697 frame->LineNumber(), |
2737 String::Handle(frame->QualifiedFunctionName()).ToCString(), | 2698 String::Handle(frame->QualifiedFunctionName()).ToCString(), |
2738 frame->TokenPos().ToCString()); | 2699 frame->TokenPos().ToCString()); |
2739 } | 2700 } |
2740 | 2701 |
2741 ASSERT(stack_trace_ == NULL); | 2702 ASSERT(stack_trace_ == NULL); |
2742 stack_trace_ = CollectStackTrace(); | 2703 stack_trace_ = CollectStackTrace(); |
2743 // If this step callback is part of stepping over an await statement, | 2704 // If this step callback is part of stepping over an await statement, |
2744 // we saved the synthetic async breakpoint in SignalBpReached. We report | 2705 // we saved the synthetic async breakpoint in PauseBreakpoint. We report |
2745 // that we are paused at that breakpoint and then delete it after continuing. | 2706 // that we are paused at that breakpoint and then delete it after continuing. |
2746 SignalPausedEvent(frame, synthetic_async_breakpoint_); | 2707 SignalPausedEvent(frame, synthetic_async_breakpoint_); |
2747 if (synthetic_async_breakpoint_ != NULL) { | 2708 if (synthetic_async_breakpoint_ != NULL) { |
2748 RemoveBreakpoint(synthetic_async_breakpoint_->id()); | 2709 RemoveBreakpoint(synthetic_async_breakpoint_->id()); |
2749 synthetic_async_breakpoint_ = NULL; | 2710 synthetic_async_breakpoint_ = NULL; |
2750 } | 2711 } |
2751 HandleSteppingRequest(stack_trace_); | 2712 HandleSteppingRequest(stack_trace_); |
2752 stack_trace_ = NULL; | 2713 stack_trace_ = NULL; |
2753 | 2714 |
2754 // If any error occurred while in the debug message loop, return it here. | 2715 // If any error occurred while in the debug message loop, return it here. |
2755 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 2716 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
2756 Thread::Current()->clear_sticky_error(); | 2717 Thread::Current()->clear_sticky_error(); |
2757 return error.raw(); | 2718 return error.raw(); |
2758 } | 2719 } |
2759 | 2720 |
2760 | 2721 |
2761 RawError* Debugger::SignalBpReached() { | 2722 RawError* Debugger::PauseBreakpoint() { |
2762 // We ignore this breakpoint when the VM is executing code invoked | 2723 // We ignore this breakpoint when the VM is executing code invoked |
2763 // by the debugger to evaluate variables values, or when we see a nested | 2724 // by the debugger to evaluate variables values, or when we see a nested |
2764 // breakpoint or exception event. | 2725 // breakpoint or exception event. |
2765 if (ignore_breakpoints_ || IsPaused()) { | 2726 if (ignore_breakpoints_ || IsPaused()) { |
2766 return Error::null(); | 2727 return Error::null(); |
2767 } | 2728 } |
2768 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 2729 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
2769 ASSERT(stack_trace->Length() > 0); | 2730 ASSERT(stack_trace->Length() > 0); |
2770 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 2731 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
2771 ASSERT(top_frame != NULL); | 2732 ASSERT(top_frame != NULL); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2871 RemoveInternalBreakpoints(); | 2832 RemoveInternalBreakpoints(); |
2872 } | 2833 } |
2873 | 2834 |
2874 // If any error occurred while in the debug message loop, return it here. | 2835 // If any error occurred while in the debug message loop, return it here. |
2875 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 2836 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
2876 Thread::Current()->clear_sticky_error(); | 2837 Thread::Current()->clear_sticky_error(); |
2877 return error.raw(); | 2838 return error.raw(); |
2878 } | 2839 } |
2879 | 2840 |
2880 | 2841 |
2881 void Debugger::BreakHere(const String& msg) { | 2842 void Debugger::PauseDeveloper(const String& msg) { |
2882 // We ignore this breakpoint when the VM is executing code invoked | 2843 // We ignore this breakpoint when the VM is executing code invoked |
2883 // by the debugger to evaluate variables values, or when we see a nested | 2844 // by the debugger to evaluate variables values, or when we see a nested |
2884 // breakpoint or exception event. | 2845 // breakpoint or exception event. |
2885 if (ignore_breakpoints_ || IsPaused()) { | 2846 if (ignore_breakpoints_ || IsPaused()) { |
2886 return; | 2847 return; |
2887 } | 2848 } |
2888 | 2849 |
2889 if (!HasDebugEventHandler()) { | 2850 if (!NeedsDebugEvents()) { |
2890 OS::Print("Hit debugger!"); | 2851 OS::Print("Hit debugger!"); |
2891 } | 2852 } |
2892 | 2853 |
2893 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 2854 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
2894 ASSERT(stack_trace->Length() > 0); | 2855 ASSERT(stack_trace->Length() > 0); |
2895 ASSERT(stack_trace_ == NULL); | 2856 ASSERT(stack_trace_ == NULL); |
2896 stack_trace_ = stack_trace; | 2857 stack_trace_ = stack_trace; |
2897 | 2858 |
2898 // TODO(johnmccutchan): Send |msg| to Observatory. | 2859 // TODO(johnmccutchan): Send |msg| to Observatory. |
2899 | 2860 |
2900 // We are in the native call to Debugger_breakHere or Debugger_breakHereIf, | 2861 // We are in the native call to Developer_debugger. the developer |
2901 // the developer gets a better experience by not seeing this call. To | 2862 // gets a better experience by not seeing this call. To accomplish |
2902 // accomplish this, we continue execution until the call exits (step out). | 2863 // this, we continue execution until the call exits (step out). |
2903 SetStepOut(); | 2864 SetStepOut(); |
2904 HandleSteppingRequest(stack_trace_); | 2865 HandleSteppingRequest(stack_trace_); |
2905 | 2866 |
2906 stack_trace_ = NULL; | 2867 stack_trace_ = NULL; |
2907 } | 2868 } |
2908 | 2869 |
2909 | 2870 |
2910 void Debugger::Initialize(Isolate* isolate) { | 2871 void Debugger::Initialize(Isolate* isolate) { |
2911 if (initialized_) { | 2872 if (initialized_) { |
2912 return; | 2873 return; |
2913 } | 2874 } |
2914 isolate_ = isolate; | 2875 isolate_ = isolate; |
2915 | 2876 |
2916 // Use the isolate's control port as the isolate_id for debugging. | 2877 // Use the isolate's control port as the isolate_id for debugging. |
2917 // This port will be used as a unique ID to represent the isolate in the | 2878 // This port will be used as a unique ID to represent the isolate in |
2918 // debugger wire protocol messages. | 2879 // the debugger embedder api. |
2919 isolate_id_ = isolate_->main_port(); | 2880 isolate_id_ = isolate_->main_port(); |
2920 initialized_ = true; | 2881 initialized_ = true; |
2921 } | 2882 } |
2922 | 2883 |
2923 | 2884 |
2924 void Debugger::NotifyIsolateCreated() { | 2885 void Debugger::NotifyIsolateCreated() { |
2925 // Signal isolate creation event. | 2886 if (NeedsIsolateEvents()) { |
2926 if ((isolate_ != Dart::vm_isolate()) && | 2887 ServiceEvent event(isolate_, ServiceEvent::kIsolateStart); |
2927 !ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { | 2888 InvokeEventHandler(&event); |
2928 SignalIsolateEvent(DebuggerEvent::kIsolateCreated); | |
2929 creation_message_sent_ = true; | |
2930 } | 2889 } |
2931 } | 2890 } |
2932 | 2891 |
2933 | 2892 |
2934 // Return innermost closure contained in 'function' that contains | 2893 // Return innermost closure contained in 'function' that contains |
2935 // the given token position. | 2894 // the given token position. |
2936 RawFunction* Debugger::FindInnermostClosure(const Function& function, | 2895 RawFunction* Debugger::FindInnermostClosure(const Function& function, |
2937 TokenPosition token_pos) { | 2896 TokenPosition token_pos) { |
2938 Zone* zone = Thread::Current()->zone(); | 2897 Zone* zone = Thread::Current()->zone(); |
2939 const Script& outer_origin = Script::Handle(zone, function.script()); | 2898 const Script& outer_origin = Script::Handle(zone, function.script()); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3021 "requested col %" Pd ")\n", | 2980 "requested col %" Pd ")\n", |
3022 bpt->id(), | 2981 bpt->id(), |
3023 loc->token_pos().ToCString(), | 2982 loc->token_pos().ToCString(), |
3024 loc->LineNumber(), | 2983 loc->LineNumber(), |
3025 loc->ColumnNumber(), | 2984 loc->ColumnNumber(), |
3026 func.ToFullyQualifiedCString(), | 2985 func.ToFullyQualifiedCString(), |
3027 requested_pos.ToCString(), | 2986 requested_pos.ToCString(), |
3028 requested_end_pos.ToCString(), | 2987 requested_end_pos.ToCString(), |
3029 loc->requested_column_number()); | 2988 loc->requested_column_number()); |
3030 } | 2989 } |
3031 SignalBpResolved(bpt); | 2990 SendBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt); |
3032 SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt); | |
3033 bpt = bpt->next(); | 2991 bpt = bpt->next(); |
3034 } | 2992 } |
3035 } | 2993 } |
3036 ASSERT(loc->IsResolved()); | 2994 ASSERT(loc->IsResolved()); |
3037 if (FLAG_verbose_debug) { | 2995 if (FLAG_verbose_debug) { |
3038 Breakpoint* bpt = loc->breakpoints(); | 2996 Breakpoint* bpt = loc->breakpoints(); |
3039 while (bpt != NULL) { | 2997 while (bpt != NULL) { |
3040 OS::Print("Setting breakpoint %" Pd " at line %" Pd " col %" Pd "" | 2998 OS::Print("Setting breakpoint %" Pd " at line %" Pd " col %" Pd "" |
3041 " for %s '%s'\n", | 2999 " for %s '%s'\n", |
3042 bpt->id(), | 3000 bpt->id(), |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3211 Breakpoint* prev_bpt = NULL; | 3169 Breakpoint* prev_bpt = NULL; |
3212 Breakpoint* curr_bpt = curr_loc->breakpoints(); | 3170 Breakpoint* curr_bpt = curr_loc->breakpoints(); |
3213 while (curr_bpt != NULL) { | 3171 while (curr_bpt != NULL) { |
3214 if (curr_bpt->id() == bp_id) { | 3172 if (curr_bpt->id() == bp_id) { |
3215 if (prev_bpt == NULL) { | 3173 if (prev_bpt == NULL) { |
3216 curr_loc->set_breakpoints(curr_bpt->next()); | 3174 curr_loc->set_breakpoints(curr_bpt->next()); |
3217 } else { | 3175 } else { |
3218 prev_bpt->set_next(curr_bpt->next()); | 3176 prev_bpt->set_next(curr_bpt->next()); |
3219 } | 3177 } |
3220 | 3178 |
3221 SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt); | 3179 SendBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt); |
3222 | 3180 |
3223 // Remove references from the current debugger pause event. | 3181 // Remove references from the current debugger pause event. |
3224 if (pause_event_ != NULL && | 3182 if (pause_event_ != NULL && pause_event_->breakpoint() == curr_bpt) { |
3225 pause_event_->type() == DebuggerEvent::kBreakpointReached && | |
3226 pause_event_->breakpoint() == curr_bpt) { | |
3227 pause_event_->set_breakpoint(NULL); | 3183 pause_event_->set_breakpoint(NULL); |
3228 } | 3184 } |
3229 break; | 3185 break; |
3230 } | 3186 } |
3231 | 3187 |
3232 prev_bpt = curr_bpt; | 3188 prev_bpt = curr_bpt; |
3233 curr_bpt = curr_bpt->next(); | 3189 curr_bpt = curr_bpt->next(); |
3234 } | 3190 } |
3235 | 3191 |
3236 if (curr_loc->breakpoints() == NULL) { | 3192 if (curr_loc->breakpoints() == NULL) { |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3360 | 3316 |
3361 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 3317 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
3362 ASSERT(bpt->next() == NULL); | 3318 ASSERT(bpt->next() == NULL); |
3363 bpt->set_next(code_breakpoints_); | 3319 bpt->set_next(code_breakpoints_); |
3364 code_breakpoints_ = bpt; | 3320 code_breakpoints_ = bpt; |
3365 } | 3321 } |
3366 | 3322 |
3367 #endif // !PRODUCT | 3323 #endif // !PRODUCT |
3368 | 3324 |
3369 } // namespace dart | 3325 } // namespace dart |
OLD | NEW |