OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/debugger.h" | 5 #include "vm/debugger.h" |
6 | 6 |
7 #include "vm/code_index_table.h" | 7 #include "vm/code_index_table.h" |
| 8 #include "vm/code_generator.h" |
8 #include "vm/code_patcher.h" | 9 #include "vm/code_patcher.h" |
9 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
10 #include "vm/dart_entry.h" | 11 #include "vm/dart_entry.h" |
11 #include "vm/flags.h" | 12 #include "vm/flags.h" |
12 #include "vm/globals.h" | 13 #include "vm/globals.h" |
13 #include "vm/longjump.h" | 14 #include "vm/longjump.h" |
14 #include "vm/object.h" | 15 #include "vm/object.h" |
15 #include "vm/object_store.h" | 16 #include "vm/object_store.h" |
16 #include "vm/os.h" | 17 #include "vm/os.h" |
17 #include "vm/stack_frame.h" | 18 #include "vm/stack_frame.h" |
18 #include "vm/stub_code.h" | 19 #include "vm/stub_code.h" |
19 #include "vm/visitor.h" | 20 #include "vm/visitor.h" |
20 | 21 |
21 | 22 |
22 namespace dart { | 23 namespace dart { |
23 | 24 |
24 static const bool verbose = false; | 25 static const bool verbose = false; |
25 | 26 |
26 | 27 |
27 Breakpoint::Breakpoint(const Function& func, intptr_t pc_desc_index) | 28 Breakpoint::Breakpoint(const Function& func, intptr_t pc_desc_index) |
28 : function_(func.raw()), | 29 : function_(func.raw()), |
29 pc_desc_index_(pc_desc_index), | 30 pc_desc_index_(pc_desc_index), |
30 pc_(0), | 31 pc_(0), |
31 saved_bytes_(0), | |
32 line_number_(-1), | 32 line_number_(-1), |
| 33 is_patched_(false), |
33 next_(NULL) { | 34 next_(NULL) { |
34 Code& code = Code::Handle(func.code()); | 35 Code& code = Code::Handle(func.code()); |
35 ASSERT(!code.IsNull()); // Function must be compiled. | 36 ASSERT(!code.IsNull()); // Function must be compiled. |
36 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 37 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
37 ASSERT(pc_desc_index < desc.Length()); | 38 ASSERT(pc_desc_index < desc.Length()); |
38 this->token_index_ = desc.TokenIndex(pc_desc_index); | 39 this->token_index_ = desc.TokenIndex(pc_desc_index); |
39 ASSERT(this->token_index_ > 0); | 40 ASSERT(this->token_index_ > 0); |
40 this->pc_ = desc.PC(pc_desc_index); | 41 this->pc_ = desc.PC(pc_desc_index); |
41 ASSERT(this->pc_ != 0); | 42 ASSERT(this->pc_ != 0); |
| 43 this->breakpoint_kind_ = desc.DescriptorKind(pc_desc_index); |
42 } | 44 } |
43 | 45 |
44 | 46 |
45 RawScript* Breakpoint::SourceCode() { | 47 RawScript* Breakpoint::SourceCode() { |
46 const Function& func = Function::Handle(this->function_); | 48 const Function& func = Function::Handle(this->function_); |
47 const Class& cls = Class::Handle(func.owner()); | 49 const Class& cls = Class::Handle(func.owner()); |
48 return cls.script(); | 50 return cls.script(); |
49 } | 51 } |
50 | 52 |
51 | 53 |
(...skipping 13 matching lines...) Expand all Loading... |
65 } | 67 } |
66 return this->line_number_; | 68 return this->line_number_; |
67 } | 69 } |
68 | 70 |
69 | 71 |
70 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 72 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
71 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 73 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
72 } | 74 } |
73 | 75 |
74 | 76 |
75 ActivationFrame::ActivationFrame(uword pc, uword fp) | 77 ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp) |
76 : pc_(pc), fp_(fp), | 78 : pc_(pc), fp_(fp), sp_(sp), |
77 function_(Function::ZoneHandle()), | 79 function_(Function::ZoneHandle()), |
78 token_index_(-1), | 80 token_index_(-1), |
79 line_number_(-1), | 81 line_number_(-1), |
80 var_descriptors_(NULL), | 82 var_descriptors_(NULL), |
81 desc_indices_(8) { | 83 desc_indices_(8) { |
82 } | 84 } |
83 | 85 |
84 | 86 |
85 const Function& ActivationFrame::DartFunction() { | 87 const Function& ActivationFrame::DartFunction() { |
86 if (function_.IsNull()) { | 88 if (function_.IsNull()) { |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 OS::SNPrint(chars, len, kFormat, func_name, url.ToCString(), line); | 273 OS::SNPrint(chars, len, kFormat, func_name, url.ToCString(), line); |
272 return chars; | 274 return chars; |
273 } | 275 } |
274 | 276 |
275 | 277 |
276 void StackTrace::AddActivation(ActivationFrame* frame) { | 278 void StackTrace::AddActivation(ActivationFrame* frame) { |
277 this->trace_.Add(frame); | 279 this->trace_.Add(frame); |
278 } | 280 } |
279 | 281 |
280 | 282 |
| 283 void Breakpoint::PatchCode() { |
| 284 ASSERT(!is_patched_); |
| 285 switch (breakpoint_kind_) { |
| 286 case PcDescriptors::kIcCall: { |
| 287 int num_args, num_named_args; |
| 288 CodePatcher::GetInstanceCallAt(pc_, |
| 289 NULL, &num_args, &num_named_args, |
| 290 &saved_bytes_.target_address_); |
| 291 CodePatcher::PatchInstanceCallAt( |
| 292 pc_, StubCode::BreakpointDynamicEntryPoint()); |
| 293 break; |
| 294 } |
| 295 case PcDescriptors::kFuncCall: { |
| 296 Function& func = Function::Handle(); |
| 297 CodePatcher::GetStaticCallAt(pc_, &func, &saved_bytes_.target_address_); |
| 298 CodePatcher::PatchStaticCallAt(pc_, |
| 299 StubCode::BreakpointStaticEntryPoint()); |
| 300 break; |
| 301 } |
| 302 case PcDescriptors::kReturn: |
| 303 PatchFunctionReturn(); |
| 304 break; |
| 305 default: |
| 306 UNREACHABLE(); |
| 307 } |
| 308 is_patched_ = true; |
| 309 } |
| 310 |
| 311 |
| 312 void Breakpoint::RestoreCode() { |
| 313 ASSERT(is_patched_); |
| 314 switch (breakpoint_kind_) { |
| 315 case PcDescriptors::kIcCall: |
| 316 CodePatcher::PatchInstanceCallAt(pc_, saved_bytes_.target_address_); |
| 317 break; |
| 318 case PcDescriptors::kFuncCall: |
| 319 CodePatcher::PatchStaticCallAt(pc_, saved_bytes_.target_address_); |
| 320 break; |
| 321 case PcDescriptors::kReturn: |
| 322 RestoreFunctionReturn(); |
| 323 break; |
| 324 default: |
| 325 UNREACHABLE(); |
| 326 } |
| 327 is_patched_ = false; |
| 328 } |
| 329 |
| 330 void Breakpoint::SetActive(bool value) { |
| 331 if (value && !is_patched_) { |
| 332 PatchCode(); |
| 333 return; |
| 334 } |
| 335 if (!value && is_patched_) { |
| 336 RestoreCode(); |
| 337 } |
| 338 } |
| 339 |
| 340 |
| 341 bool Breakpoint::IsActive() { |
| 342 return is_patched_; |
| 343 } |
| 344 |
| 345 |
281 Debugger::Debugger() | 346 Debugger::Debugger() |
282 : isolate_(NULL), | 347 : isolate_(NULL), |
283 initialized_(false), | 348 initialized_(false), |
284 bp_handler_(NULL), | 349 bp_handler_(NULL), |
285 breakpoints_(NULL) { | 350 breakpoints_(NULL), |
| 351 resume_action_(kContinue) { |
286 } | 352 } |
287 | 353 |
288 | 354 |
289 Debugger::~Debugger() { | 355 Debugger::~Debugger() { |
290 ASSERT(breakpoints_ == NULL); | 356 ASSERT(breakpoints_ == NULL); |
291 } | 357 } |
292 | 358 |
293 | 359 |
294 void Debugger::Shutdown() { | 360 void Debugger::Shutdown() { |
295 while (breakpoints_ != NULL) { | 361 while (breakpoints_ != NULL) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 if (!cls.IsNull()) { | 404 if (!cls.IsNull()) { |
339 function = cls.LookupStaticFunction(function_name); | 405 function = cls.LookupStaticFunction(function_name); |
340 if (function.IsNull()) { | 406 if (function.IsNull()) { |
341 function = cls.LookupDynamicFunction(function_name); | 407 function = cls.LookupDynamicFunction(function_name); |
342 } | 408 } |
343 } | 409 } |
344 return function.raw(); | 410 return function.raw(); |
345 } | 411 } |
346 | 412 |
347 | 413 |
| 414 void Debugger::InstrumentForStepping(const Function &target_function) { |
| 415 if (!target_function.HasCode()) { |
| 416 Compiler::CompileFunction(target_function); |
| 417 // If there were any errors, ignore them silently and return without |
| 418 // adding breakpoints to target. |
| 419 if (!target_function.HasCode()) { |
| 420 return; |
| 421 } |
| 422 } |
| 423 Code& code = Code::Handle(target_function.code()); |
| 424 ASSERT(!code.IsNull()); |
| 425 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 426 for (int i = 0; i < desc.Length(); i++) { |
| 427 Breakpoint* bpt = GetBreakpoint(desc.PC(i)); |
| 428 if (bpt != NULL) { |
| 429 // There is already a breakpoint for this address. Leave it alone. |
| 430 continue; |
| 431 } |
| 432 PcDescriptors::Kind kind = desc.DescriptorKind(i); |
| 433 if ((kind == PcDescriptors::kIcCall) || |
| 434 (kind == PcDescriptors::kFuncCall) || |
| 435 (kind == PcDescriptors::kReturn)) { |
| 436 bpt = new Breakpoint(target_function, i); |
| 437 bpt->set_temporary(true); |
| 438 bpt->PatchCode(); |
| 439 RegisterBreakpoint(bpt); |
| 440 } |
| 441 } |
| 442 } |
| 443 |
| 444 |
348 // TODO(hausner): Distinguish between newly created breakpoints and | 445 // TODO(hausner): Distinguish between newly created breakpoints and |
349 // returning a breakpoint that already exists? | 446 // returning a breakpoint that already exists? |
350 Breakpoint* Debugger::SetBreakpoint(const Function& target_function, | 447 Breakpoint* Debugger::SetBreakpoint(const Function& target_function, |
351 intptr_t token_index, | 448 intptr_t token_index, |
352 Error* error) { | 449 Error* error) { |
353 if ((token_index < target_function.token_index()) || | 450 if ((token_index < target_function.token_index()) || |
354 (target_function.end_token_index() <= token_index)) { | 451 (target_function.end_token_index() <= token_index)) { |
355 // The given token position is not within the target function. | 452 // The given token position is not within the target function. |
356 return NULL; | 453 return NULL; |
357 } | 454 } |
358 if (!target_function.HasCode()) { | 455 if (!target_function.HasCode()) { |
359 *error = Compiler::CompileFunction(target_function); | 456 *error = Compiler::CompileFunction(target_function); |
360 if (!error->IsNull()) { | 457 if (!error->IsNull()) { |
361 return NULL; | 458 return NULL; |
362 } | 459 } |
363 } | 460 } |
364 Code& code = Code::Handle(target_function.code()); | 461 Code& code = Code::Handle(target_function.code()); |
365 ASSERT(!code.IsNull()); | 462 ASSERT(!code.IsNull()); |
366 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 463 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
367 for (int i = 0; i < desc.Length(); i++) { | 464 for (int i = 0; i < desc.Length(); i++) { |
368 if (desc.TokenIndex(i) < token_index) { | 465 if (desc.TokenIndex(i) < token_index) { |
369 continue; | 466 continue; |
370 } | 467 } |
| 468 Breakpoint* bpt = GetBreakpoint(desc.PC(i)); |
| 469 if (bpt != NULL) { |
| 470 // Found existing breakpoint. |
| 471 return bpt; |
| 472 } |
371 PcDescriptors::Kind kind = desc.DescriptorKind(i); | 473 PcDescriptors::Kind kind = desc.DescriptorKind(i); |
372 Breakpoint* bpt = NULL; | 474 if ((kind == PcDescriptors::kIcCall) || |
373 if (kind == PcDescriptors::kIcCall) { | 475 (kind == PcDescriptors::kFuncCall) || |
374 bpt = GetBreakpoint(desc.PC(i)); | 476 (kind == PcDescriptors::kReturn)) { |
375 if (bpt != NULL) { | |
376 // There is an existing breakpoint at this token position. | |
377 break; | |
378 } | |
379 bpt = new Breakpoint(target_function, i); | 477 bpt = new Breakpoint(target_function, i); |
380 String& func_name = String::Handle(); | 478 bpt->PatchCode(); |
381 int num_args, num_named_args; | |
382 CodePatcher::GetInstanceCallAt(desc.PC(i), | |
383 &func_name, &num_args, &num_named_args, &bpt->saved_bytes_); | |
384 CodePatcher::PatchInstanceCallAt( | |
385 desc.PC(i), StubCode::BreakpointDynamicEntryPoint()); | |
386 RegisterBreakpoint(bpt); | 479 RegisterBreakpoint(bpt); |
387 } else if (kind == PcDescriptors::kOther) { | |
388 if ((desc.TokenIndex(i) > 0) && CodePatcher::IsDartCall(desc.PC(i))) { | |
389 bpt = GetBreakpoint(desc.PC(i)); | |
390 if (bpt != NULL) { | |
391 // There is an existing breakpoint at this token position. | |
392 break; | |
393 } | |
394 bpt = new Breakpoint(target_function, i); | |
395 Function& func = Function::Handle(); | |
396 CodePatcher::GetStaticCallAt(desc.PC(i), &func, &bpt->saved_bytes_); | |
397 CodePatcher::PatchStaticCallAt( | |
398 desc.PC(i), StubCode::BreakpointStaticEntryPoint()); | |
399 RegisterBreakpoint(bpt); | |
400 } | |
401 } | |
402 if (bpt != NULL) { | |
403 if (verbose) { | 480 if (verbose) { |
404 OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n", | 481 OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n", |
405 String::Handle(bpt->SourceUrl()).ToCString(), | 482 String::Handle(bpt->SourceUrl()).ToCString(), |
406 bpt->LineNumber(), | 483 bpt->LineNumber(), |
407 bpt->pc()); | 484 bpt->pc()); |
408 } | 485 } |
409 return bpt; | 486 return bpt; |
410 } | 487 } |
411 } | 488 } |
412 return NULL; | 489 return NULL; |
413 } | 490 } |
414 | 491 |
415 | 492 |
416 void Debugger::UnsetBreakpoint(Breakpoint* bpt) { | 493 void Debugger::UnsetBreakpoint(Breakpoint* bpt) { |
417 const Function& func = Function::Handle(bpt->function()); | 494 bpt->SetActive(false); |
418 const Code& code = Code::Handle(func.code()); | |
419 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | |
420 intptr_t desc_index = bpt->pc_desc_index(); | |
421 ASSERT(desc_index < desc.Length()); | |
422 ASSERT(bpt->pc() == desc.PC(desc_index)); | |
423 PcDescriptors::Kind kind = desc.DescriptorKind(desc_index); | |
424 if (kind == PcDescriptors::kIcCall) { | |
425 CodePatcher::PatchInstanceCallAt(desc.PC(desc_index), bpt->saved_bytes_); | |
426 } else { | |
427 CodePatcher::PatchStaticCallAt(desc.PC(desc_index), bpt->saved_bytes_); | |
428 } | |
429 } | 495 } |
430 | 496 |
431 | 497 |
432 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function, | 498 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function, |
433 Error* error) { | 499 Error* error) { |
434 ASSERT(!target_function.IsNull()); | 500 ASSERT(!target_function.IsNull()); |
435 return SetBreakpoint(target_function, target_function.token_index(), error); | 501 return SetBreakpoint(target_function, target_function.token_index(), error); |
436 } | 502 } |
437 | 503 |
438 | 504 |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 | 669 |
604 | 670 |
605 void Debugger::BreakpointCallback() { | 671 void Debugger::BreakpointCallback() { |
606 ASSERT(initialized_); | 672 ASSERT(initialized_); |
607 DartFrameIterator iterator; | 673 DartFrameIterator iterator; |
608 DartFrame* frame = iterator.NextFrame(); | 674 DartFrame* frame = iterator.NextFrame(); |
609 ASSERT(frame != NULL); | 675 ASSERT(frame != NULL); |
610 Breakpoint* bpt = GetBreakpoint(frame->pc()); | 676 Breakpoint* bpt = GetBreakpoint(frame->pc()); |
611 ASSERT(bpt != NULL); | 677 ASSERT(bpt != NULL); |
612 if (verbose) { | 678 if (verbose) { |
613 OS::Print(">>> Breakpoint at %s:%d (Address %p)\n", | 679 OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n", |
| 680 bpt->is_temporary() ? "hit temp" : "hit user", |
614 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?", | 681 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?", |
615 bpt ? bpt->LineNumber() : 0, | 682 bpt ? bpt->LineNumber() : 0, |
616 frame->pc()); | 683 frame->pc()); |
617 } | 684 } |
618 StackTrace* stack_trace = new StackTrace(8); | 685 StackTrace* stack_trace = new StackTrace(8); |
619 while (frame != NULL) { | 686 while (frame != NULL) { |
620 ASSERT(frame->IsValid()); | 687 ASSERT(frame->IsValid()); |
621 ASSERT(frame->IsDartFrame()); | 688 ASSERT(frame->IsDartFrame()); |
622 ActivationFrame* activation = | 689 ActivationFrame* activation = |
623 new ActivationFrame(frame->pc(), frame->fp()); | 690 new ActivationFrame(frame->pc(), frame->fp(), frame->sp()); |
624 stack_trace->AddActivation(activation); | 691 stack_trace->AddActivation(activation); |
625 frame = iterator.NextFrame(); | 692 frame = iterator.NextFrame(); |
626 } | 693 } |
627 | 694 |
| 695 resume_action_ = kContinue; |
628 if (bp_handler_ != NULL) { | 696 if (bp_handler_ != NULL) { |
629 (*bp_handler_)(bpt, stack_trace); | 697 (*bp_handler_)(bpt, stack_trace); |
630 } | 698 } |
| 699 |
| 700 if (resume_action_ == kContinue) { |
| 701 RemoveTemporaryBreakpoints(); |
| 702 } else if (resume_action_ == kStepOver) { |
| 703 Function& func = Function::Handle(bpt->function()); |
| 704 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) { |
| 705 // If we are at the function return, do a StepOut action. |
| 706 if (stack_trace->Length() > 1) { |
| 707 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); |
| 708 func = caller->DartFunction().raw(); |
| 709 RemoveTemporaryBreakpoints(); |
| 710 } |
| 711 } |
| 712 InstrumentForStepping(func); |
| 713 } else if (resume_action_ == kStepInto) { |
| 714 RemoveTemporaryBreakpoints(); |
| 715 if (bpt->breakpoint_kind_ == PcDescriptors::kIcCall) { |
| 716 int num_args, num_named_args; |
| 717 uword target; |
| 718 CodePatcher::GetInstanceCallAt(bpt->pc_, NULL, |
| 719 &num_args, &num_named_args, &target); |
| 720 ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0); |
| 721 Instance& receiver = Instance::Handle( |
| 722 top_frame->GetInstanceCallReceiver(num_args)); |
| 723 Code& code = Code::Handle( |
| 724 ResolveCompileInstanceCallTarget(isolate_, receiver)); |
| 725 if (!code.IsNull()) { |
| 726 Function& callee = Function::Handle(code.function()); |
| 727 InstrumentForStepping(callee); |
| 728 } |
| 729 } else if (bpt->breakpoint_kind_ == PcDescriptors::kFuncCall) { |
| 730 Function& callee = Function::Handle(); |
| 731 uword target; |
| 732 CodePatcher::GetStaticCallAt(bpt->pc_, &callee, &target); |
| 733 InstrumentForStepping(callee); |
| 734 } else { |
| 735 ASSERT(bpt->breakpoint_kind_ == PcDescriptors::kReturn); |
| 736 // Treat like stepping out to caller. |
| 737 if (stack_trace->Length() > 1) { |
| 738 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); |
| 739 InstrumentForStepping(caller->DartFunction()); |
| 740 } |
| 741 } |
| 742 } else { |
| 743 ASSERT(resume_action_ == kStepOut); |
| 744 // Set temporary breakpoints in the caller. |
| 745 RemoveTemporaryBreakpoints(); |
| 746 if (stack_trace->Length() > 1) { |
| 747 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); |
| 748 InstrumentForStepping(caller->DartFunction()); |
| 749 } |
| 750 } |
631 } | 751 } |
632 | 752 |
633 | 753 |
634 void Debugger::Initialize(Isolate* isolate) { | 754 void Debugger::Initialize(Isolate* isolate) { |
635 if (initialized_) { | 755 if (initialized_) { |
636 return; | 756 return; |
637 } | 757 } |
638 isolate_ = isolate; | 758 isolate_ = isolate; |
639 initialized_ = true; | 759 initialized_ = true; |
640 SetBreakpointHandler(DefaultBreakpointHandler); | 760 SetBreakpointHandler(DefaultBreakpointHandler); |
(...skipping 27 matching lines...) Expand all Loading... |
668 delete bpt; | 788 delete bpt; |
669 return; | 789 return; |
670 } | 790 } |
671 prev_bpt = curr_bpt; | 791 prev_bpt = curr_bpt; |
672 curr_bpt = curr_bpt->next(); | 792 curr_bpt = curr_bpt->next(); |
673 } | 793 } |
674 // bpt is not a registered breakpoint, nothing to do. | 794 // bpt is not a registered breakpoint, nothing to do. |
675 } | 795 } |
676 | 796 |
677 | 797 |
| 798 void Debugger::RemoveTemporaryBreakpoints() { |
| 799 Breakpoint* prev_bpt = NULL; |
| 800 Breakpoint* curr_bpt = breakpoints_; |
| 801 while (curr_bpt != NULL) { |
| 802 if (curr_bpt->is_temporary()) { |
| 803 if (prev_bpt == NULL) { |
| 804 breakpoints_ = breakpoints_->next(); |
| 805 } else { |
| 806 prev_bpt->set_next(curr_bpt->next()); |
| 807 } |
| 808 Breakpoint* temp_bpt = curr_bpt; |
| 809 curr_bpt = curr_bpt->next(); |
| 810 UnsetBreakpoint(temp_bpt); |
| 811 delete temp_bpt; |
| 812 } else { |
| 813 prev_bpt = curr_bpt; |
| 814 curr_bpt = curr_bpt->next(); |
| 815 } |
| 816 } |
| 817 } |
| 818 |
| 819 |
678 Breakpoint* Debugger::GetBreakpointByFunction(const Function& func, | 820 Breakpoint* Debugger::GetBreakpointByFunction(const Function& func, |
679 intptr_t token_index) { | 821 intptr_t token_index) { |
680 Breakpoint* bpt = this->breakpoints_; | 822 Breakpoint* bpt = this->breakpoints_; |
681 while (bpt != NULL) { | 823 while (bpt != NULL) { |
682 if ((bpt->function() == func.raw()) && | 824 if ((bpt->function() == func.raw()) && |
683 (bpt->token_index() == token_index)) { | 825 (bpt->token_index() == token_index)) { |
684 return bpt; | 826 return bpt; |
685 } | 827 } |
686 bpt = bpt->next(); | 828 bpt = bpt->next(); |
687 } | 829 } |
688 return NULL; | 830 return NULL; |
689 } | 831 } |
690 | 832 |
691 | 833 |
692 void Debugger::RegisterBreakpoint(Breakpoint* bpt) { | 834 void Debugger::RegisterBreakpoint(Breakpoint* bpt) { |
693 ASSERT(bpt->next() == NULL); | 835 ASSERT(bpt->next() == NULL); |
694 bpt->set_next(this->breakpoints_); | 836 bpt->set_next(this->breakpoints_); |
695 this->breakpoints_ = bpt; | 837 this->breakpoints_ = bpt; |
696 } | 838 } |
697 | 839 |
698 | 840 |
699 } // namespace dart | 841 } // namespace dart |
OLD | NEW |