|  | // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "tonic/dart_debugger.h" | 
|  |  | 
|  | #include "dart/runtime/include/dart_api.h" | 
|  | #include "dart/runtime/include/dart_native_api.h" | 
|  | #include "dart/runtime/include/dart_tools_api.h" | 
|  |  | 
|  |  | 
|  | namespace tonic { | 
|  |  | 
|  | MonitorLocker::~MonitorLocker() { | 
|  | monitor_->Exit(); | 
|  | } | 
|  |  | 
|  | void DartDebuggerIsolate::MessageLoop() { | 
|  | MonitorLocker ml(&monitor_); | 
|  | // Request notification on isolate messages.  This allows us to | 
|  | // respond to vm service messages while at breakpoint. | 
|  | Dart_SetMessageNotifyCallback(DartDebugger::NotifyIsolate); | 
|  | while (true) { | 
|  | // Handle all available vm service messages, up to a resume | 
|  | // request. | 
|  | bool resume = false; | 
|  | while (!resume && Dart_HasServiceMessages()) { | 
|  | monitor_.Exit(); | 
|  | resume = Dart_HandleServiceMessages(); | 
|  | monitor_.Enter(); | 
|  | } | 
|  | if (resume) { | 
|  | break; | 
|  | } | 
|  | ml.Wait(); | 
|  | } | 
|  | Dart_SetMessageNotifyCallback(nullptr); | 
|  | } | 
|  |  | 
|  | void DartDebugger::BptResolvedHandler(Dart_IsolateId isolate_id, | 
|  | intptr_t bp_id, | 
|  | const Dart_CodeLocation& location) { | 
|  | // Nothing to do here. Service event is dispatched to let Observatory know | 
|  | // that a breakpoint was resolved. | 
|  | } | 
|  |  | 
|  | void DartDebugger::PausedEventHandler(Dart_IsolateId isolate_id, | 
|  | intptr_t bp_id, | 
|  | const Dart_CodeLocation& loc) { | 
|  | Dart_EnterScope(); | 
|  | intptr_t isolate_index = FindIsolateIndexById(isolate_id); | 
|  | CHECK(isolate_index != -1); | 
|  | (*isolates_)[isolate_index]->MessageLoop(); | 
|  | Dart_ExitScope(); | 
|  | } | 
|  |  | 
|  | void DartDebugger::ExceptionThrownHandler(Dart_IsolateId isolate_id, | 
|  | Dart_Handle exception, | 
|  | Dart_StackTrace stack_trace) { | 
|  | Dart_EnterScope(); | 
|  | intptr_t isolate_index = FindIsolateIndexById(isolate_id); | 
|  | CHECK(isolate_index != -1); | 
|  | (*isolates_)[isolate_index]->MessageLoop(); | 
|  | Dart_ExitScope(); | 
|  | } | 
|  |  | 
|  | void DartDebugger::IsolateEventHandler(Dart_IsolateId isolate_id, | 
|  | Dart_IsolateEvent kind) { | 
|  | Dart_EnterScope(); | 
|  | if (kind == Dart_IsolateEvent::kCreated) { | 
|  | AddIsolate(isolate_id); | 
|  | } else { | 
|  | intptr_t isolate_index = FindIsolateIndexById(isolate_id); | 
|  | CHECK(isolate_index != -1); | 
|  | if (kind == Dart_IsolateEvent::kInterrupted) { | 
|  | (*isolates_)[isolate_index]->MessageLoop(); | 
|  | } else { | 
|  | CHECK(kind == Dart_IsolateEvent::kShutdown); | 
|  | RemoveIsolate(isolate_id); | 
|  | } | 
|  | } | 
|  | Dart_ExitScope(); | 
|  | } | 
|  |  | 
|  | void DartDebugger::NotifyIsolate(Dart_Isolate isolate) { | 
|  | base::AutoLock al(*lock_); | 
|  | Dart_IsolateId isolate_id = Dart_GetIsolateId(isolate); | 
|  | intptr_t isolate_index = FindIsolateIndexByIdLocked(isolate_id); | 
|  | if (isolate_index >= 0) { | 
|  | (*isolates_)[isolate_index]->Notify(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void DartDebugger::InitDebugger() { | 
|  | Dart_SetIsolateEventHandler(IsolateEventHandler); | 
|  | Dart_SetPausedEventHandler(PausedEventHandler); | 
|  | Dart_SetBreakpointResolvedHandler(BptResolvedHandler); | 
|  | Dart_SetExceptionThrownHandler(ExceptionThrownHandler); | 
|  | lock_ = new base::Lock(); | 
|  | isolates_ = new std::vector<std::unique_ptr<DartDebuggerIsolate>>(); | 
|  | } | 
|  |  | 
|  | intptr_t DartDebugger::FindIsolateIndexById(Dart_IsolateId id) { | 
|  | base::AutoLock al(*lock_); | 
|  | return FindIsolateIndexByIdLocked(id); | 
|  | } | 
|  |  | 
|  | intptr_t DartDebugger::FindIsolateIndexByIdLocked( | 
|  | Dart_IsolateId id) { | 
|  | lock_->AssertAcquired(); | 
|  | for (size_t i = 0; i < isolates_->size(); i++) { | 
|  | if ((*isolates_)[i]->id() == id) { | 
|  | return i; | 
|  | } | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | void DartDebugger::AddIsolate(Dart_IsolateId id) { | 
|  | base::AutoLock al(*lock_); | 
|  | CHECK(FindIsolateIndexByIdLocked(id) == -1); | 
|  | std::unique_ptr<DartDebuggerIsolate> debugger_isolate = | 
|  | std::unique_ptr<DartDebuggerIsolate>(new DartDebuggerIsolate(id)); | 
|  | isolates_->push_back(std::move(debugger_isolate)); | 
|  | } | 
|  |  | 
|  | void DartDebugger::RemoveIsolate(Dart_IsolateId id) { | 
|  | base::AutoLock al(*lock_); | 
|  | for (size_t i = 0; i < isolates_->size(); i++) { | 
|  | if (id == (*isolates_)[i]->id()) { | 
|  | isolates_->erase(isolates_->begin() + i); | 
|  | return; | 
|  | } | 
|  | } | 
|  | NOTREACHED(); | 
|  | } | 
|  |  | 
|  | base::Lock* DartDebugger::lock_ = nullptr; | 
|  | std::vector<std::unique_ptr<DartDebuggerIsolate>>* DartDebugger::isolates_ = | 
|  | nullptr; | 
|  |  | 
|  | }  // namespace tonic |