Chromium Code Reviews| Index: Source/bindings/dart/DartScriptDebugServer.cpp | 
| diff --git a/Source/bindings/dart/DartScriptDebugServer.cpp b/Source/bindings/dart/DartScriptDebugServer.cpp | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..4f0dfa398d6a0c88a5ab3ba75d63b4d3618f71ce | 
| --- /dev/null | 
| +++ b/Source/bindings/dart/DartScriptDebugServer.cpp | 
| @@ -0,0 +1,1152 @@ | 
| +/* | 
| + * Copyright (C) 2014 Google Inc. All rights reserved. | 
| + * | 
| + * Redistribution and use in source and binary forms, with or without | 
| + * modification, are permitted provided that the following conditions are | 
| + * met: | 
| + * | 
| + * * Redistributions of source code must retain the above copyright | 
| + * notice, this list of conditions and the following disclaimer. | 
| + * * Redistributions in binary form must reproduce the above | 
| + * copyright notice, this list of conditions and the following disclaimer | 
| + * in the documentation and/or other materials provided with the | 
| + * distribution. | 
| + * * Neither the name of Google Inc. nor the names of its | 
| + * contributors may be used to endorse or promote products derived from | 
| + * this software without specific prior written permission. | 
| + * | 
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
| + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
| + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
| + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
| + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
| + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
| + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
| + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
| + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
| + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
| + */ | 
| +#include "config.h" | 
| +#include "bindings/dart/DartScriptDebugServer.h" | 
| + | 
| +#include "bindings/dart/DartController.h" | 
| +#include "bindings/dart/DartHandleProxy.h" | 
| +#include "bindings/dart/DartUtilities.h" | 
| +#include "bindings/dart/V8Converter.h" | 
| +#include "bindings/v8/PageScriptDebugServer.h" | 
| +#include "bindings/v8/ScriptController.h" | 
| +#include "bindings/v8/ScriptState.h" | 
| +#include "bindings/v8/V8Binding.h" | 
| +#include "bindings/v8/V8WindowShell.h" | 
| +#include "core/dom/Document.h" | 
| +#include "core/frame/DOMWindow.h" | 
| +#include "core/inspector/InspectorController.h" | 
| +#include "core/inspector/InspectorDebuggerAgent.h" | 
| +#include "core/inspector/InspectorInstrumentation.h" | 
| +#include "core/inspector/InstrumentingAgents.h" | 
| +#include "core/inspector/JSONParser.h" | 
| +#include "core/inspector/ScriptDebugListener.h" | 
| +#include "core/page/Page.h" | 
| +#include "platform/JSONValues.h" | 
| +#include "platform/Logging.h" | 
| +#include "wtf/HashMap.h" | 
| +#include "wtf/Vector.h" | 
| + | 
| +namespace WebCore { | 
| + | 
| +static Dart_ExceptionPauseInfo calculatePauseInfo(ScriptDebugServer::PauseOnExceptionsState pauseOnExceptionState) | 
| +{ | 
| + switch (pauseOnExceptionState) { | 
| + case ScriptDebugServer::DontPauseOnExceptions: | 
| + return kNoPauseOnExceptions; | 
| + case ScriptDebugServer::PauseOnAllExceptions: | 
| + return kPauseOnAllExceptions; | 
| + case ScriptDebugServer::PauseOnUncaughtExceptions: | 
| + return kPauseOnUnhandledExceptions; | 
| + } | 
| + return kNoPauseOnExceptions; | 
| +} | 
| + | 
| +DartBreakpoint::DartBreakpoint(intptr_t breakpointId, Dart_Isolate isolate) | 
| + : m_breakpointId(breakpointId) | 
| + , m_isolate(isolate) | 
| +{ | 
| +} | 
| + | 
| +DartBreakpointInfo::DartBreakpointInfo(const String& scriptUrl, const ScriptBreakpoint& scriptBreakpoint) | 
| + : m_scriptUrl(scriptUrl) | 
| + , m_scriptBreakpoint(scriptBreakpoint) | 
| +{ | 
| +} | 
| + | 
| +DartPageDebug::DartPageDebug(Page* page, size_t pageId) | 
| + : m_page(page) | 
| + , m_listener(0) | 
| + , m_pageId(pageId) | 
| + , m_nextBreakpointId(1) | 
| + , m_nextScriptId(1) | 
| +{ | 
| +} | 
| + | 
| +DartPageDebug::~DartPageDebug() | 
| +{ | 
| + for (BreakpointMap::iterator it = m_breakpoints.begin(); it != m_breakpoints.end(); ++it) | 
| + delete it->value; | 
| +} | 
| + | 
| +void DartPageDebug::registerIsolate(Dart_Isolate isolate) | 
| +{ | 
| + m_isolateMap.add(isolate); | 
| +} | 
| + | 
| +intptr_t DartPageDebug::setBreakpointHelper(DartBreakpointInfo* breakpointInfo, const String& breakpointIdString, Dart_Isolate isolate, Dart_Handle& exception) | 
| +{ | 
| + Dart_Handle scriptURL = DartUtilities::convertSourceString(breakpointInfo->m_scriptUrl); | 
| + // FIXME: use scriptBreakpoint.columnNumber and ScriptBreakpoint.condition as well. | 
| + Dart_Handle ret = Dart_SetBreakpoint(scriptURL, breakpointInfo->m_scriptBreakpoint.lineNumber + 1); | 
| + if (Dart_IsError(ret)) { | 
| + exception = ret; | 
| + return 0; | 
| + } | 
| + ASSERT(Dart_IsInteger(ret)); | 
| + intptr_t breakpointId = DartUtilities::dartToInt(ret, exception); | 
| + ASSERT(!exception); | 
| + if (exception) { | 
| + return 0; | 
| + } | 
| + m_breakpointIdMap.set(breakpointId, breakpointIdString); | 
| + breakpointInfo->m_breakpoints.append(DartBreakpoint(breakpointId, isolate)); | 
| + return breakpointId; | 
| +} | 
| + | 
| +String DartPageDebug::setBreakpoint(const String& sourceID, const ScriptBreakpoint& scriptBreakpoint, int* actualLineNumber, int* actualColumnNumber, bool interstatementLocation) | 
| +{ | 
| + String breakpointIdString = String::format("{\"dartBreakpoint\":%ld,\"page\":%ld}", m_nextBreakpointId, m_pageId); | 
| + | 
| + m_nextBreakpointId++; | 
| + if (!m_idToScriptUrlMap.contains(sourceID)) { | 
| + return "Unable to set breakpoint. Unknown sourceID"; | 
| + } | 
| + Vector<Dart_Isolate> isolates; | 
| + m_isolateMap.copyValues(isolates); | 
| + for (Vector<Dart_Isolate>::iterator it = isolates.begin(); it != isolates.end(); ++it) { | 
| + Dart_Isolate isolate = *it; | 
| + DartIsolateScope scope(isolate); | 
| + DartApiScope apiScope; | 
| + Dart_Handle exception = 0; | 
| + | 
| + DartBreakpointInfo* breakpointInfo; | 
| + BreakpointMap::iterator breakpointIt = m_breakpoints.find(breakpointIdString); | 
| + if (breakpointIt != m_breakpoints.end()) { | 
| + breakpointInfo = breakpointIt->value; | 
| + } else { | 
| + breakpointInfo = new DartBreakpointInfo(m_idToScriptUrlMap.get(sourceID), scriptBreakpoint); | 
| + m_breakpoints.set(breakpointIdString, breakpointInfo); | 
| + } | 
| + | 
| + intptr_t breakpointId = setBreakpointHelper(breakpointInfo, breakpointIdString, isolate, exception); | 
| + if (exception) { | 
| + continue; | 
| + } | 
| + Dart_Handle breakpointLine = Dart_GetBreakpointLine(breakpointId); | 
| + *actualColumnNumber = 0; | 
| + if (!Dart_IsError(breakpointLine)) { | 
| + ASSERT(Dart_IsInteger(breakpointLine)); | 
| + *actualLineNumber = DartUtilities::dartToInt(breakpointLine, exception) - 1; | 
| + ASSERT(!exception); | 
| + } else { | 
| + *actualLineNumber = 1; | 
| + } | 
| + } | 
| + return breakpointIdString; | 
| +} | 
| + | 
| + | 
| +void DartPageDebug::removeBreakpointHelper(DartBreakpointInfo* breakpointInfo) | 
| +{ | 
| + Vector<DartBreakpoint>& breakpoints = breakpointInfo->m_breakpoints; | 
| + for (Vector<DartBreakpoint>::iterator it = breakpoints.begin(); it != breakpoints.end(); ++it) { | 
| + DartBreakpoint& breakpoint = *it; | 
| + DartIsolateScope scope(breakpoint.m_isolate); | 
| + DartApiScope apiScope; | 
| + // perhaps this isn't needed if the isolate will be removed soon anyway. | 
| + Dart_RemoveBreakpoint(breakpoint.m_breakpointId); | 
| + } | 
| + delete breakpointInfo; | 
| +} | 
| + | 
| +void DartPageDebug::removeBreakpoint(const String& breakpointId) | 
| +{ | 
| + if (m_breakpoints.contains(breakpointId)) { | 
| + removeBreakpointHelper(m_breakpoints.get(breakpointId)); | 
| + m_breakpoints.remove(breakpointId); | 
| + } | 
| +} | 
| + | 
| +void DartPageDebug::clearBreakpointsForIsolate(Dart_Isolate isolate) | 
| +{ | 
| + // Warning: this code is O(num_isolates * num_breakpoints) | 
| + for (BreakpointMap::iterator i = m_breakpoints.begin(); i != m_breakpoints.end(); ++i) { | 
| + Vector<DartBreakpoint>& breakpoints = i->value->m_breakpoints; | 
| + for (size_t j = 0; j < breakpoints.size(); j++) { | 
| + DartBreakpoint& breakpoint = breakpoints[j]; | 
| + if (breakpoint.m_isolate == isolate) { | 
| + // No need to actually call Dart_RemoveBreakpoint as the | 
| + // isolate is about to be shut down. | 
| + breakpoints.remove(j); | 
| + break; | 
| + } | 
| + } | 
| + } | 
| +} | 
| + | 
| +void DartPageDebug::dispatchDidParseSource(intptr_t libraryId, Dart_Handle scriptURL, Dart_Isolate isolate) | 
| +{ | 
| + ASSERT(Dart_IsString(scriptURL)); | 
| + ScriptDebugListener::Script script; | 
| + script.url = DartUtilities::toString(scriptURL); | 
| + String sourceID = getScriptId(script.url); | 
| + script.source = DartUtilities::toString(Dart_ScriptGetSource(libraryId, scriptURL)); | 
| + // FIXME: track script.sourceMappingURL for dart-dart source map support. | 
| + | 
| + Dart_Handle info = Dart_ScriptGetTokenInfo(libraryId, scriptURL); | 
| + ASSERT(Dart_IsList(info)); | 
| + intptr_t infoLength = 0; | 
| + Dart_Handle ALLOW_UNUSED result = Dart_ListLength(info, &infoLength); | 
| + ASSERT(!Dart_IsError(result)); | 
| + Dart_Handle elem; | 
| + int lastLineNumber = 0; | 
| + int lastColumnNumber = 0; | 
| + intptr_t lastLineStart = 0; | 
| + for (intptr_t i = infoLength - 3; i >= 0; i--) { | 
| + elem = Dart_ListGetAt(info, i); | 
| + if (Dart_IsNull(elem)) { | 
| + lastLineStart = i; | 
| + break; | 
| + } | 
| + } | 
| + Dart_Handle exception = 0; | 
| + lastLineNumber = DartUtilities::toInteger(Dart_ListGetAt(info, lastLineStart + 1), exception); | 
| + ASSERT(!exception); | 
| + lastColumnNumber = DartUtilities::toInteger(Dart_ListGetAt(info, infoLength - 1), exception); | 
| + ASSERT(!exception); | 
| + | 
| + script.startLine = 0; | 
| + script.startColumn = 0; | 
| + script.endLine = lastLineNumber + 1; | 
| + script.endColumn = !lastLineNumber ? lastColumnNumber : 0; | 
| + script.isContentScript = false; | 
| + script.language = String("dart"); | 
| + script.libraryId = libraryId; | 
| + m_listener->didParseSource(sourceID, script); | 
| +} | 
| + | 
| +String DartPageDebug::getScriptId(const String& url) | 
| +{ | 
| + HashMap<String, String>::iterator it = m_scriptUrlToIdMap.find(url); | 
| + if (it == m_scriptUrlToIdMap.end()) { | 
| + String id = String::format("{\"dartScript\":%ld,\"page\":%ld}", m_nextScriptId, m_pageId); | 
| + m_nextScriptId++; | 
| + m_scriptUrlToIdMap.set(url, id); | 
| + m_idToScriptUrlMap.set(id, url); | 
| + return id; | 
| + } | 
| + return it->value; | 
| +} | 
| + | 
| +void DartPageDebug::clearBreakpoints() | 
| +{ | 
| + for (BreakpointMap::iterator i = m_breakpoints.begin(); i != m_breakpoints.end(); ++i) | 
| + removeBreakpointHelper(i->value); | 
| + m_breakpoints.clear(); | 
| + m_breakpointIdMap.clear(); | 
| +} | 
| + | 
| +void DartPageDebug::registerIsolateScripts(Dart_Isolate isolate) | 
| +{ | 
| + Dart_Handle libraries = Dart_GetLibraryIds(); | 
| + ASSERT(Dart_IsList(libraries)); | 
| + | 
| + intptr_t librariesLength = 0; | 
| + Dart_Handle ALLOW_UNUSED result = Dart_ListLength(libraries, &librariesLength); | 
| + ASSERT(!Dart_IsError(result)); | 
| + for (intptr_t i = 0; i < librariesLength; ++i) { | 
| + Dart_Handle libraryIdHandle = Dart_ListGetAt(libraries, i); | 
| + ASSERT(!Dart_IsError(libraryIdHandle)); | 
| + Dart_Handle exception = 0; | 
| + int64_t int64LibraryId = DartUtilities::toInteger(libraryIdHandle, exception); | 
| + ASSERT(!exception); | 
| + intptr_t libraryId = static_cast<intptr_t>(int64LibraryId); | 
| + ASSERT(libraryId == int64LibraryId); | 
| + | 
| + Dart_Handle libraryURL = Dart_GetLibraryURL(libraryId); | 
| + ASSERT(Dart_IsString(libraryURL)); | 
| + | 
| + // FIXMEDART: we may be doing this more than once per library. | 
| + Dart_SetLibraryDebuggable(libraryId, true); | 
| + | 
| + Dart_Handle scripts = Dart_GetScriptURLs(libraryURL); | 
| + ASSERT(Dart_IsList(scripts)); | 
| + | 
| + intptr_t scriptsLength = 0; | 
| + result = Dart_ListLength(scripts, &scriptsLength); | 
| + ASSERT(!Dart_IsError(result)); | 
| + for (intptr_t j = 0; j < scriptsLength; ++j) { | 
| + Dart_Handle scriptURL = Dart_ListGetAt(scripts, j); | 
| + dispatchDidParseSource(libraryId, scriptURL, isolate); | 
| + } | 
| + } | 
| +} | 
| + | 
| +Vector<Dart_Isolate> DartPageDebug::isolates() | 
| +{ | 
| + Vector<Dart_Isolate> result; | 
| + m_isolateMap.copyValues(result); | 
| + return result; | 
| +} | 
| + | 
| +void DartPageDebug::addListener(ScriptDebugListener* listener) | 
| +{ | 
| + ASSERT(!m_listener); | 
| + m_listener = listener; | 
| + | 
| + Vector<Dart_Isolate> iter = isolates(); | 
| + for (Vector<Dart_Isolate>::iterator i = iter.begin(); i != iter.end(); ++i) { | 
| + Dart_Isolate isolate = *i; | 
| + DartIsolateScope scope(isolate); | 
| + DartApiScope apiScope; | 
| + isolateLoaded(); | 
| + } | 
| +} | 
| + | 
| +void DartPageDebug::removeListener() | 
| +{ | 
| + m_listener = 0; | 
| + Vector<Dart_Isolate> iter = isolates(); | 
| + for (Vector<Dart_Isolate>::iterator i = iter.begin(); i != iter.end(); ++i) { | 
| + Dart_Isolate isolate = *i; | 
| + DartIsolateScope scope(isolate); | 
| + DartApiScope apiScope; | 
| + Dart_SetPausedEventHandler(0); | 
| + Dart_SetExceptionThrownHandler(0); | 
| + Dart_SetIsolateEventHandler(0); | 
| + Dart_SetExceptionPauseInfo(kNoPauseOnExceptions); | 
| + } | 
| + // FIXME: Remove all breakpoints set by the agent. JavaScript does not | 
| + // remove the breakpoints either. | 
| +} | 
| + | 
| +void DartPageDebug::unregisterIsolate(Dart_Isolate isolate) | 
| +{ | 
| + clearBreakpointsForIsolate(isolate); | 
| + m_isolateMap.removeByValue(isolate); | 
| +} | 
| + | 
| +void DartPageDebug::isolateLoaded() | 
| +{ | 
| + if (!m_listener) | 
| + return; | 
| + | 
| + Dart_Isolate isolate = Dart_CurrentIsolate(); | 
| + Dart_SetPausedEventHandler(DartScriptDebugServer::pausedEventHandler); | 
| + Dart_SetExceptionThrownHandler(DartScriptDebugServer::exceptionHandler); | 
| + Dart_SetIsolateEventHandler(DartScriptDebugServer::isolateEventHandler); | 
| + | 
| + Dart_ExceptionPauseInfo pauseInfo = calculatePauseInfo( | 
| + DartScriptDebugServer::shared().pauseOnExceptionState()); | 
| + Dart_SetExceptionPauseInfo(pauseInfo); | 
| + | 
| + ASSERT(isolate); | 
| + // FIXME: we can get rid of the V8Scope once DartScriptState and | 
| 
 
rmacnak
2014/06/03 17:32:34
Can we remove this now?
 
Jacob
2014/06/03 20:23:13
sadly we can't yet. I updated the comment. with so
 
 | 
| + // ScriptState are refactored. | 
| + V8Scope v8Scope(DartDOMData::current(), v8::Debug::GetDebugContext()); | 
| + | 
| + LocalFrame* frame = DartUtilities::domWindowForCurrentIsolate()->frame(); | 
| + DartController* controller = DartController::retrieve(frame); | 
| + Vector<ScriptState*> scriptStates; | 
| + controller->collectScriptStatesForIsolate(isolate, DartUtilities::currentV8Context(), scriptStates); | 
| + for (size_t i = 0; i< scriptStates.size(); i++) | 
| + InspectorInstrumentation::didCreateIsolatedContext(frame, scriptStates[i], 0); | 
| + | 
| + registerIsolateScripts(isolate); | 
| + | 
| + for (BreakpointMap::iterator it = m_breakpoints.begin(); it != m_breakpoints.end(); ++it) { | 
| + Dart_Handle ALLOW_UNUSED exception = 0; | 
| + setBreakpointHelper(it->value, it->key, isolate, exception); | 
| + } | 
| +} | 
| + | 
| +String DartPageDebug::lookupBreakpointId(intptr_t dartBreakpointId) | 
| +{ | 
| + if (dartBreakpointId > 0) { | 
| + BreakpointIdMap::iterator it = m_breakpointIdMap.find(dartBreakpointId); | 
| + if (it != m_breakpointIdMap.end()) | 
| + return it->value; | 
| + } | 
| + return ""; | 
| +} | 
| + | 
| +DartScriptDebugServer::DartScriptDebugServer() | 
| + : m_pauseOnExceptionState(DontPauseOnExceptions) | 
| + , m_breakpointsActivated(true) | 
| + , m_runningNestedMessageLoop(false) | 
| + , m_executionState(0) | 
| + , m_pausedPage(0) | 
| + , m_clientMessageLoop(0) | 
| + , m_nextPageId(1) | 
| +{ | 
| +} | 
| + | 
| +DartScriptDebugServer::~DartScriptDebugServer() | 
| +{ | 
| + for (DebugDataMap::iterator it = m_pageIdToDebugDataMap.begin(); it != m_pageIdToDebugDataMap.end(); ++it) | 
| + delete it->value; | 
| +} | 
| + | 
| +DartPageDebug* DartScriptDebugServer::lookupPageDebugForId(const String& id) | 
| +{ | 
| + RefPtr<JSONValue> json = parseJSON(id); | 
| + ASSERT(json && json->type() == JSONValue::TypeObject); | 
| + if (json && json->type() == JSONValue::TypeObject) { | 
| + size_t pageId; | 
| + bool success = json->asObject()->getNumber("page", &pageId); | 
| + ASSERT(success); | 
| + if (success) | 
| + return m_pageIdToDebugDataMap.get(pageId); | 
| + } | 
| + return 0; | 
| +} | 
| + | 
| +DartPageDebug* DartScriptDebugServer::lookupPageDebug(Page* page) | 
| +{ | 
| + ASSERT(page); | 
| + PageToIdMap::iterator it = m_pageToIdMap.find(page); | 
| + if (it != m_pageToIdMap.end()) | 
| + return m_pageIdToDebugDataMap.get(it->value); | 
| + | 
| + size_t pageId = m_nextPageId++; | 
| + m_pageToIdMap.set(page, pageId); | 
| + DartPageDebug* pageDebug = new DartPageDebug(page, pageId); | 
| + m_pageIdToDebugDataMap.set(pageId, pageDebug); | 
| + return pageDebug; | 
| +} | 
| + | 
| +String DartScriptDebugServer::getScriptId(const String& url, Dart_Isolate isolate) | 
| +{ | 
| + // FIXME: this is a ugly. It would be better to get the domData for the | 
| + // specified isolate. | 
| + ASSERT(isolate == Dart_CurrentIsolate()); | 
| + DartPageDebug* pageDebug = lookupPageDebug(DartUtilities::domWindowForCurrentIsolate()->document()->page()); | 
| + ASSERT(pageDebug); | 
| + if (!pageDebug) | 
| + return ""; | 
| + return pageDebug->getScriptId(url); | 
| +} | 
| + | 
| +void DartScriptDebugServer::registerIsolate(Dart_Isolate isolate, Page* page) | 
| +{ | 
| + DartIsolateScope scope(isolate); | 
| + DartApiScope apiScope; | 
| + | 
| + DartPageDebug* pageDebug = lookupPageDebug(page); | 
| + pageDebug->registerIsolate(isolate); | 
| +} | 
| + | 
| +// FIXMEDART: we aren't really handling adding and removing breakpoints | 
| +// as new isolates add/remove themselves. | 
| +String DartScriptDebugServer::setBreakpoint(const String& sourceID, const ScriptBreakpoint& scriptBreakpoint, int* actualLineNumber, int* actualColumnNumber, bool interstatementLocation) | 
| +{ | 
| + DartPageDebug* pageDebug = lookupPageDebugForId(sourceID); | 
| + ASSERT(pageDebug); | 
| + if (!pageDebug) | 
| + return ""; | 
| + return pageDebug->setBreakpoint(sourceID, scriptBreakpoint, actualLineNumber, actualColumnNumber, interstatementLocation); | 
| +} | 
| + | 
| +void DartScriptDebugServer::removeBreakpoint(const String& breakpointId) | 
| +{ | 
| + DartPageDebug* pageDebug = lookupPageDebugForId(breakpointId); | 
| + if (pageDebug) { | 
| + pageDebug->removeBreakpoint(breakpointId); | 
| + } | 
| +} | 
| + | 
| +void DartScriptDebugServer::clearBreakpoints() | 
| +{ | 
| + Vector<DartPageDebug*> list = pages(); | 
| + for (Vector<DartPageDebug*>::iterator it = list.begin(); it != list.end(); ++it) | 
| + (*it)->clearBreakpoints(); | 
| +} | 
| + | 
| +void DartScriptDebugServer::setBreakpointsActivated(bool activated) | 
| +{ | 
| + m_breakpointsActivated = activated; | 
| +} | 
| + | 
| +ScriptDebugServer::PauseOnExceptionsState DartScriptDebugServer::pauseOnExceptionsState() | 
| +{ | 
| + return m_pauseOnExceptionState; | 
| +} | 
| + | 
| +void DartScriptDebugServer::setPauseOnExceptionsState(PauseOnExceptionsState pauseOnExceptionState) | 
| +{ | 
| + if (m_pauseOnExceptionState == pauseOnExceptionState) | 
| + return; | 
| + m_pauseOnExceptionState = pauseOnExceptionState; | 
| + | 
| + Dart_ExceptionPauseInfo pauseInfo = calculatePauseInfo(pauseOnExceptionState); | 
| + | 
| + Vector<Dart_Isolate> iter = isolates(); | 
| + for (Vector<Dart_Isolate>::iterator it = iter.begin(); it != iter.end(); ++it) { | 
| + DartIsolateScope scope(*it); | 
| + DartApiScope apiScope; | 
| + Dart_SetExceptionPauseInfo(pauseInfo); | 
| + } | 
| +} | 
| + | 
| +void DartScriptDebugServer::setPauseOnNextStatement(bool pause) | 
| +{ | 
| + if (isPaused()) | 
| + return; | 
| + if (pause) { | 
| + debugBreak(); | 
| + } else { | 
| + cancelDebugBreak(); | 
| + } | 
| +} | 
| + | 
| +bool DartScriptDebugServer::canBreakProgram() | 
| +{ | 
| + if (!m_breakpointsActivated) | 
| + return false; | 
| + | 
| + // FIXME: what is the dart equivalent of | 
| + // v8::HandleScope scope(m_isolate); | 
| + // return !m_isolate->GetCurrentContext().IsEmpty(); | 
| + // ? | 
| + return true; | 
| +} | 
| + | 
| +void DartScriptDebugServer::breakProgram() | 
| +{ | 
| + if (!canBreakProgram()) | 
| + return; | 
| + | 
| + // FIXME: determine if this method needs to be implemented for Dart. | 
| +} | 
| + | 
| +void DartScriptDebugServer::continueProgram() | 
| +{ | 
| + if (isPaused()) | 
| + quitMessageLoopOnPause(); | 
| + m_executionState = 0; | 
| +} | 
| + | 
| +void DartScriptDebugServer::stepIntoStatement() | 
| +{ | 
| + ASSERT(isPaused()); | 
| + Dart_SetStepInto(); | 
| + continueProgram(); | 
| +} | 
| + | 
| +void DartScriptDebugServer::stepOverStatement(const ActivationFrame& frame) | 
| +{ | 
| + ASSERT(isPaused()); | 
| + Dart_SetStepOver(); | 
| + continueProgram(); | 
| +} | 
| + | 
| +void DartScriptDebugServer::stepOutOfFunction(const ActivationFrame& frame) | 
| +{ | 
| + ASSERT(isPaused()); | 
| + Dart_SetStepOut(); | 
| + continueProgram(); | 
| +} | 
| + | 
| +bool DartScriptDebugServer::setScriptSource(const String& sourceID, const String& newContent, bool preview, String* error, RefPtr<TypeBuilder::Debugger::SetScriptSourceError>& errorData, StackTrace* newCallFrames, RefPtr<JSONObject>& result) | 
| +{ | 
| + *error = "Dart does not support live editing source code yet."; | 
| + return false; | 
| +} | 
| + | 
| +bool DartScriptDebugServer::executeSkipPauseRequest(ScriptDebugListener::SkipPauseRequest request, Dart_StackTrace stackTrace) | 
| +{ | 
| + switch (request) { | 
| + case ScriptDebugListener::NoSkip: | 
| + return false; | 
| + case ScriptDebugListener::Continue: | 
| + return true; | 
| + case ScriptDebugListener::StepInto: | 
| + case ScriptDebugListener::StepOut: | 
| + break; | 
| + } | 
| + ASSERT(0); | 
| + // FIXMEDART: actually do something jacobr JACOBR | 
| + return true; | 
| +} | 
| + | 
| +StackTrace DartScriptDebugServer::currentCallFrames() | 
| +{ | 
| + return StackTrace(m_executionState); | 
| +} | 
| + | 
| +StackTrace DartScriptDebugServer::currentCallFramesForAsyncStack() | 
| +{ | 
| + // FIXMEDART: implement propertly. These are the regular not Async call frames. | 
| + return StackTrace(m_executionState); | 
| +} | 
| + | 
| +bool DartScriptDebugServer::isPaused() | 
| +{ | 
| + return !!m_executionState; | 
| +} | 
| + | 
| +void DartScriptDebugServer::clearCompiledScripts() | 
| +{ | 
| + // FIXMEDART: is this meaningful for Dart? | 
| + // Currently tracking what scripts have been compiled is handled by a | 
| + // different class. | 
| +} | 
| + | 
| +void DartScriptDebugServer::setPreprocessorSource(const String& preprocessorSource) | 
| +{ | 
| + // FIXMEDART: support calling a preprocessor on all Dart scripts. | 
| +} | 
| + | 
| +DartScriptDebugServer& DartScriptDebugServer::shared() | 
| +{ | 
| + DEFINE_STATIC_LOCAL(DartScriptDebugServer, server, ()); | 
| + return server; | 
| +} | 
| + | 
| +void DartScriptDebugServer::addListener(ScriptDebugListener* listener, Page* page) | 
| +{ | 
| + ScriptController& scriptController = page->mainFrame()->script(); | 
| + if (!scriptController.canExecuteScripts(NotAboutToExecuteScript)) | 
| + return; | 
| + | 
| + DartPageDebug* pageDebug = lookupPageDebug(page); | 
| + pageDebug->addListener(listener); | 
| +} | 
| + | 
| +Vector<DartPageDebug*> DartScriptDebugServer::pages() | 
| +{ | 
| + Vector<DartPageDebug*> result; | 
| + copyValuesToVector(m_pageIdToDebugDataMap, result); | 
| + return result; | 
| +} | 
| + | 
| +Vector<Dart_Isolate> DartScriptDebugServer::isolates() | 
| +{ | 
| + Vector<Dart_Isolate> result; | 
| + Vector<DartPageDebug*> allPages = pages(); | 
| + for (Vector<DartPageDebug*>::iterator it = allPages.begin(); it != allPages.end(); ++it) { | 
| + Vector<Dart_Isolate> forPage = (*it)->isolates(); | 
| + result.appendRange(forPage.begin(), forPage.end()); | 
| + } | 
| + return result; | 
| +} | 
| + | 
| +bool DartScriptDebugServer::resolveCodeLocation(const Dart_CodeLocation& location, int* line, int* column) | 
| +{ | 
| + // FIXME: cache the results of calling Dart_ScriptGetTokenInfo to improve | 
| + // performance. | 
| + Dart_Handle info = Dart_ScriptGetTokenInfo(location.library_id, location.script_url); | 
| + ASSERT(Dart_IsList(info)); | 
| + intptr_t infoLength = 0; | 
| + Dart_Handle ALLOW_UNUSED result = Dart_ListLength(info, &infoLength); | 
| + ASSERT(!Dart_IsError(result)); | 
| + Dart_Handle elem; | 
| + bool lineStart = true; | 
| + int currentLineNumber = 0; | 
| + for (intptr_t i = 0; i < infoLength; i++) { | 
| + elem = Dart_ListGetAt(info, i); | 
| + if (Dart_IsNull(elem)) { | 
| + lineStart = true; | 
| + } else { | 
| + ASSERT(Dart_IsInteger(elem)); | 
| + Dart_Handle exception = 0; | 
| + int64_t value = DartUtilities::toInteger(elem, exception); | 
| + ASSERT(!exception); | 
| + if (lineStart) { | 
| + // Line number. | 
| + currentLineNumber = value; | 
| + lineStart = false; | 
| + } else { | 
| + // Token offset. | 
| + if (value == location.token_pos) { | 
| + *line = currentLineNumber; | 
| + ASSERT(i + 1 < infoLength); | 
| + *column = DartUtilities::toInteger(Dart_ListGetAt(info, i + 1), exception); | 
| + ASSERT(!exception); | 
| + return true; | 
| + } | 
| + i++; // skip columnNumber. | 
| + } | 
| + } | 
| + } | 
| + return false; | 
| +} | 
| + | 
| +void DartScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page) | 
| +{ | 
| + if (!m_pageToIdMap.contains(page)) | 
| + return; | 
| + | 
| + if (m_pausedPage == page) | 
| + continueProgram(); | 
| + | 
| + DartPageDebug* pageDebug = lookupPageDebug(page); | 
| + if (pageDebug) | 
| + pageDebug->removeListener(); | 
| +} | 
| + | 
| +void DartScriptDebugServer::setClientMessageLoop(PageScriptDebugServer::ClientMessageLoop* clientMessageLoop) | 
| +{ | 
| + m_clientMessageLoop = clientMessageLoop; | 
| +} | 
| + | 
| +void DartScriptDebugServer::runMessageLoopOnPause(Dart_Isolate isolate) | 
| +{ | 
| + LocalFrame* frame = DartUtilities::domWindowForCurrentIsolate()->frame(); | 
| + m_pausedPage = frame->page(); | 
| + | 
| + // Wait for continue or step command. | 
| + ASSERT(m_clientMessageLoop); | 
| + if (m_clientMessageLoop) | 
| + m_clientMessageLoop->run(m_pausedPage); | 
| + | 
| + DartPageDebug* pageDebug = lookupPageDebug(m_pausedPage); | 
| + // The listener may have been removed in the nested loop. | 
| + if (pageDebug && pageDebug->listener()) | 
| + pageDebug->listener()->didContinue(); | 
| + | 
| + m_pausedPage = 0; | 
| +} | 
| + | 
| +void DartScriptDebugServer::quitMessageLoopOnPause() | 
| +{ | 
| + m_clientMessageLoop->quitNow(); | 
| +} | 
| + | 
| +bool DartScriptDebugServer::canPreprocess(LocalFrame* frame) | 
| +{ | 
| + // FIXMEDART: support preprocessing Dart source code. | 
| + return false; | 
| +} | 
| + | 
| +// Source to Source processing iff debugger enabled and it has loaded a preprocessor. | 
| +PassOwnPtr<ScriptSourceCode> DartScriptDebugServer::preprocess(LocalFrame* frame, const ScriptSourceCode& sourceCode) | 
| +{ | 
| + // FIXMEDART: support preprocessing Dart source code. | 
| + return PassOwnPtr<ScriptSourceCode>(); | 
| +} | 
| + | 
| +String DartScriptDebugServer::preprocessEventListener(LocalFrame* frame, const String& source, const String& url, const String& functionName) | 
| +{ | 
| + // We don't support inline event listeners in Dart so this code should | 
| + // never be executed. | 
| + ASSERT_NOT_REACHED(); | 
| + return source; | 
| +} | 
| + | 
| +void DartScriptDebugServer::debugBreak() | 
| +{ | 
| + Vector<Dart_Isolate> iter = isolates(); | 
| + for (Vector<Dart_Isolate>::iterator it = iter.begin(); it != iter.end(); ++it) { | 
| + Dart_Isolate isolate = *it; | 
| + if (!m_interruptCalled.contains(isolate)) { | 
| + m_interruptCalled.add(isolate); | 
| + Dart_InterruptIsolate(isolate); | 
| + } | 
| + m_interruptCancelled.remove(isolate); | 
| + } | 
| +} | 
| + | 
| +void DartScriptDebugServer::cancelDebugBreak() | 
| +{ | 
| + // FIXME: it would be nice if the DartVM provided an API to directly cancel | 
| + // a debug break call like V8 does. | 
| + for (HashSet<Dart_Isolate>::iterator it = m_interruptCalled.begin(); it != m_interruptCalled.end(); ++it) { | 
| + m_interruptCancelled.add(*it); | 
| + } | 
| +} | 
| + | 
| +Page* DartScriptDebugServer::inferPage(Dart_Isolate isolate) | 
| +{ | 
| + for (DebugDataMap::iterator it = m_pageIdToDebugDataMap.begin(); it != m_pageIdToDebugDataMap.end(); ++it) { | 
| + DartPageDebug* pageDebug = it->value; | 
| + if (pageDebug->containsIsolate(isolate)) { | 
| + return pageDebug->page(); | 
| + } | 
| + } | 
| + return 0; | 
| +} | 
| + | 
| +void DartScriptDebugServer::unregisterIsolate(Dart_Isolate isolate, Page* page) | 
| +{ | 
| + m_interruptCalled.remove(isolate); | 
| + m_interruptCancelled.remove(isolate); | 
| + if (!page) { | 
| + // FIXME: We should instead fix the underlying issue where the | 
| + // reference to the page is lost before we call unregisterIsolate in | 
| + // some cases. | 
| + page = inferPage(isolate); | 
| + ASSERT(page); | 
| + } | 
| + DartPageDebug* pageDebug = lookupPageDebug(page); | 
| + ASSERT(pageDebug); | 
| + if (pageDebug) | 
| + pageDebug->unregisterIsolate(isolate); | 
| +} | 
| + | 
| +void DartScriptDebugServer::isolateLoaded() | 
| +{ | 
| + Page* page = DartUtilities::domWindowForCurrentIsolate()->document()->page(); | 
| + if (!page || !instrumentationForPage(page)->inspectorDebuggerAgent()) | 
| + return; | 
| + | 
| + DartPageDebug* pageDebug = lookupPageDebug(page); | 
| + if (!pageDebug) | 
| + return; | 
| + | 
| + pageDebug->isolateLoaded(); | 
| +} | 
| + | 
| +void DartScriptDebugServer::handleDartDebugEvent(Dart_IsolateId isolateId, intptr_t breakpointId, Dart_Handle exception, const Dart_CodeLocation& location) | 
| +{ | 
| + Dart_Isolate isolate = Dart_GetIsolate(isolateId); | 
| + ASSERT(isolate); | 
| + Dart_Handle result = 0; | 
| + Dart_StackTrace stackTrace = 0; | 
| + result = Dart_GetStackTrace(&stackTrace); | 
| + ASSERT(!Dart_IsError(result)); | 
| + result = 0; | 
| + DartPageDebug* pageDebug = lookupPageDebugForCurrentIsolate(); | 
| + if (!pageDebug) | 
| + return; | 
| + ScriptDebugListener* listener = pageDebug->listener(); | 
| + if (listener) { | 
| + DartIsolateScope scope(isolate); | 
| + DartApiScope apiScope; | 
| + ScriptCallFrame topFrame = DartUtilities::getTopFrame(stackTrace, result); | 
| + if (!result) { | 
| + if (exception) { | 
| + if (executeSkipPauseRequest(listener->shouldSkipExceptionPause(topFrame), stackTrace)) | 
| + return; | 
| + } else { | 
| + ScriptDebugListener::SkipPauseRequest skipRequest; | 
| + if (breakpointId != ILLEGAL_BREAKPOINT_ID) | 
| + skipRequest = listener->shouldSkipBreakpointPause(topFrame); | 
| + else | 
| + skipRequest = listener->shouldSkipStepPause(topFrame); | 
| + if (executeSkipPauseRequest(skipRequest, stackTrace)) | 
| + return; | 
| + } | 
| + } | 
| + handleProgramBreak(isolate, stackTrace, breakpointId, exception, location); | 
| + } | 
| +} | 
| + | 
| +DartPageDebug* DartScriptDebugServer::lookupPageDebugForCurrentIsolate() | 
| +{ | 
| + Page* page = DartUtilities::domWindowForCurrentIsolate()->document()->page(); | 
| + return lookupPageDebug(page); | 
| +} | 
| + | 
| +void DartScriptDebugServer::handleProgramBreak(Dart_Isolate isolate, Dart_StackTrace stackTrace, intptr_t dartBreakpointId, Dart_Handle exception, const Dart_CodeLocation& location) | 
| +{ | 
| + ASSERT(isolate == Dart_CurrentIsolate()); | 
| + // Don't allow nested breaks. | 
| + if (isPaused()) | 
| + return; | 
| + | 
| + DartPageDebug* pageDebug = lookupPageDebugForCurrentIsolate(); | 
| + if (!pageDebug) | 
| + return; | 
| + ScriptDebugListener* listener = pageDebug->listener(); | 
| + | 
| + if (!listener) | 
| + return; | 
| + | 
| + Vector<String> breakpointIds; | 
| + breakpointIds.append(pageDebug->lookupBreakpointId(dartBreakpointId)); | 
| + m_executionState = stackTrace; | 
| + // FIXME: remove call to DartHandleProxy once ScriptValue is refactored. | 
| + listener->didPause(DartUtilities::currentScriptState(), currentCallFrames(), exception ? ScriptValue(DartHandleProxy::create(exception), DartUtilities::currentV8Context()->GetIsolate()) : ScriptValue(), breakpointIds); | 
| + | 
| + m_runningNestedMessageLoop = true; | 
| + runMessageLoopOnPause(isolate); | 
| + m_runningNestedMessageLoop = false; | 
| +} | 
| + | 
| +void DartScriptDebugServer::pausedEventHandler(Dart_IsolateId isolateId, intptr_t breakpointId, const Dart_CodeLocation& location) | 
| +{ | 
| + DartScriptDebugServer::shared().handleDartDebugEvent(isolateId, breakpointId, 0, location); | 
| +} | 
| + | 
| +void DartScriptDebugServer::exceptionHandler(Dart_IsolateId isolateId, Dart_Handle exception, Dart_StackTrace trace) | 
| +{ | 
| + DartScriptDebugServer::shared().handleException(isolateId, exception, trace); | 
| +} | 
| + | 
| +void DartScriptDebugServer::isolateEventHandler(Dart_IsolateId isolateId, Dart_IsolateEvent kind) | 
| +{ | 
| + if (kind == kInterrupted) { | 
| + DartScriptDebugServer::shared().handleInterrupted(isolateId); | 
| + } | 
| +} | 
| + | 
| +void DartScriptDebugServer::handleInterrupted(Dart_IsolateId isolateId) | 
| +{ | 
| + Dart_Isolate isolate = Dart_GetIsolate(isolateId); | 
| + | 
| + if (isolate) { | 
| + ASSERT(isolate == Dart_CurrentIsolate()); | 
| + if (!m_interruptCalled.contains(isolate)) { | 
| + return; | 
| + } | 
| + | 
| + m_interruptCalled.remove(isolate); | 
| + if (m_interruptCancelled.contains(isolate)) { | 
| + m_interruptCancelled.remove(isolate); | 
| + return; | 
| + } | 
| + | 
| + // FIXME: this is a bit of a hack. V8 was also set to pause on the next | 
| + // code execution. If it attempts to pause while in the middle of | 
| + // internal V8 debugger logic it will crash so before we do anything we | 
| + // need to cancel the pending pause sent to V8. | 
| + // Perhaps it would be slightly less hacky to send a message to | 
| + // ScriptDebugServer instructing it to cancel pausing V8. | 
| + v8::Debug::CancelDebugBreak(DartUtilities::currentV8Context()->GetIsolate()); | 
| + | 
| + // The user really wants to be paused at the start of the first line of | 
| + // the Dart method not at the method invocation itself. Otherwise, | 
| + // stepping to the next call steps out of the executing Dart code | 
| + // which is not what the user expects. | 
| + Dart_SetStepInto(); | 
| + continueProgram(); | 
| + } | 
| +} | 
| + | 
| +void DartScriptDebugServer::handleException(Dart_IsolateId isolateId, Dart_Handle exception, Dart_StackTrace trace) | 
| +{ | 
| + Dart_Isolate isolate = Dart_GetIsolate(isolateId); | 
| + ASSERT(isolate); | 
| + Dart_CodeLocation location; | 
| + Dart_Handle ALLOW_UNUSED result; | 
| + Dart_ActivationFrame frame; | 
| + result = Dart_GetActivationFrame(trace, 0, &frame); | 
| + ASSERT(!Dart_IsError(result)); | 
| + result = Dart_ActivationFrameGetLocation(frame, 0, 0, &location); | 
| + ASSERT(!Dart_IsError(result)); | 
| + handleProgramBreak(isolate, trace, ILLEGAL_BREAKPOINT_ID, exception, location); | 
| +} | 
| + | 
| +void DartScriptDebugServer::runScript(ScriptState* scriptState, const String& scriptId, ScriptValue* result, bool* wasThrown, String* exceptionMessage) | 
| +{ | 
| +} | 
| + | 
| +UnifiedScriptDebugServer::UnifiedScriptDebugServer(DartScriptDebugServer* dartScriptDebugServer, PageScriptDebugServer* scriptDebugServer) | 
| +{ | 
| + m_v8 = scriptDebugServer; | 
| + m_dart = dartScriptDebugServer; | 
| +} | 
| + | 
| +UnifiedScriptDebugServer& UnifiedScriptDebugServer::shared() | 
| +{ | 
| + DEFINE_STATIC_LOCAL(UnifiedScriptDebugServer, server, (&DartScriptDebugServer::shared(), &PageScriptDebugServer::shared())); | 
| + return server; | 
| +} | 
| + | 
| +String UnifiedScriptDebugServer::setBreakpoint(const String& sourceID, const ScriptBreakpoint& scriptBreakpoint, int* actualLineNumber, int* actualColumnNumber, bool interstatementLocation) | 
| +{ | 
| + if (isDartSourceID(sourceID)) | 
| + return m_dart->setBreakpoint(sourceID, scriptBreakpoint, actualLineNumber, actualColumnNumber, interstatementLocation); | 
| + return m_v8->setBreakpoint(sourceID, scriptBreakpoint, actualLineNumber, actualColumnNumber, interstatementLocation); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::removeBreakpoint(const String& breakpointId) | 
| +{ | 
| + if (isDartBreakpointId(breakpointId)) | 
| + m_dart->removeBreakpoint(breakpointId); | 
| + else | 
| + m_v8->removeBreakpoint(breakpointId); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::clearBreakpoints() | 
| +{ | 
| + m_v8->clearBreakpoints(); | 
| + m_dart->clearBreakpoints(); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::setBreakpointsActivated(bool activated) | 
| +{ | 
| + m_v8->setBreakpointsActivated(activated); | 
| + m_dart->setBreakpointsActivated(activated); | 
| +} | 
| + | 
| +ScriptDebugServer::PauseOnExceptionsState UnifiedScriptDebugServer::pauseOnExceptionsState() | 
| +{ | 
| + // Assume Dart and V8 always have a consistent value for | 
| + // pauseOnExceptionsState. | 
| + return m_v8->pauseOnExceptionsState(); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::setPauseOnExceptionsState(ScriptDebugServer::PauseOnExceptionsState pauseOnExceptionsState) | 
| +{ | 
| + m_dart->setPauseOnExceptionsState(pauseOnExceptionsState); | 
| + m_v8->setPauseOnExceptionsState(pauseOnExceptionsState); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::setPauseOnNextStatement(bool pause) | 
| +{ | 
| + if (isPaused()) { | 
| + return; | 
| + } | 
| + m_v8->setPauseOnNextStatement(pause); | 
| + m_dart->setPauseOnNextStatement(pause); | 
| +} | 
| + | 
| +bool UnifiedScriptDebugServer::canBreakProgram() | 
| +{ | 
| + return m_v8->canBreakProgram() || m_dart->canBreakProgram(); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::breakProgram() | 
| +{ | 
| + if (m_v8->canBreakProgram()) | 
| + m_v8->breakProgram(); | 
| + if (m_dart->canBreakProgram()) | 
| + m_dart->breakProgram(); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::continueProgram() | 
| +{ | 
| + m_v8->continueProgram(); | 
| + m_dart->continueProgram(); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::stepIntoStatement() | 
| +{ | 
| + if (m_v8->isPaused()) | 
| + m_v8->stepIntoStatement(); | 
| + else | 
| + m_dart->stepIntoStatement(); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::stepOverStatement(const ActivationFrame& frame) | 
| +{ | 
| + if (m_v8->isPaused()) | 
| + m_v8->stepOverStatement(frame); | 
| + else | 
| + m_dart->stepOverStatement(frame); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::stepOutOfFunction(const ActivationFrame& frame) | 
| +{ | 
| + if (m_v8->isPaused()) | 
| + m_v8->stepOutOfFunction(frame); | 
| + else | 
| + m_dart->stepOutOfFunction(frame); | 
| +} | 
| + | 
| +bool UnifiedScriptDebugServer::isDartSourceID(const String& sourceID) | 
| +{ | 
| + // FIXMEDART: find a cleaner solution. | 
| + return sourceID.startsWith(String("{\"dartScript")); | 
| +} | 
| + | 
| +bool UnifiedScriptDebugServer::isDartBreakpointId(const String& breakpointId) | 
| +{ | 
| + // FIXMEDART: find a cleaner solution. | 
| + return breakpointId.startsWith(String("{\"dartBreakpoint")); | 
| +} | 
| + | 
| +bool UnifiedScriptDebugServer::setScriptSource(const String& sourceID, const String& newContent, bool preview, String* error, RefPtr<TypeBuilder::Debugger::SetScriptSourceError>& errorBuilder, StackTrace* newCallFrames, RefPtr<JSONObject>& result) | 
| +{ | 
| + if (isDartSourceID(sourceID)) | 
| + return m_dart->setScriptSource(sourceID, newContent, preview, error, errorBuilder, newCallFrames, result); | 
| + return m_v8->setScriptSource(sourceID, newContent, preview, error, errorBuilder, newCallFrames, result); | 
| +} | 
| + | 
| +StackTrace UnifiedScriptDebugServer::currentCallFrames() | 
| +{ | 
| + // FIXMEDART: we need to figure out how to interleave stack traces where possible. | 
| + StackTrace v8StackTrace = m_v8->currentCallFrames(); | 
| + if (!v8StackTrace.isNull()) | 
| + return v8StackTrace; | 
| + return m_dart->currentCallFrames(); | 
| +} | 
| + | 
| +StackTrace UnifiedScriptDebugServer::currentCallFramesForAsyncStack() | 
| +{ | 
| + // FIXMEDART: we need to figure out how to interleave stack traces where possible. | 
| + StackTrace v8StackTrace = m_v8->currentCallFramesForAsyncStack(); | 
| + if (!v8StackTrace.isNull()) | 
| + return v8StackTrace; | 
| + return m_dart->currentCallFramesForAsyncStack(); | 
| +} | 
| + | 
| + | 
| +bool UnifiedScriptDebugServer::isPaused() | 
| +{ | 
| + return m_v8->isPaused() || m_dart->isPaused(); | 
| +} | 
| + | 
| +bool UnifiedScriptDebugServer::runningNestedMessageLoop() | 
| +{ | 
| + return m_dart->runningNestedMessageLoop() || m_v8->runningNestedMessageLoop(); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::clearCompiledScripts() | 
| +{ | 
| + m_v8->clearCompiledScripts(); | 
| + m_dart->clearCompiledScripts(); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::setPreprocessorSource(const String& script) | 
| +{ | 
| + m_v8->setPreprocessorSource(script); | 
| + m_dart->setPreprocessorSource(script); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::preprocessBeforeCompile(const v8::Debug::EventDetails& eventDetails) | 
| +{ | 
| + m_v8->preprocessBeforeCompile(eventDetails); | 
| + // FIXMEDART: tweak the signature and call for dart. | 
| +} | 
| + | 
| +PassOwnPtr<ScriptSourceCode> UnifiedScriptDebugServer::preprocess(LocalFrame* frame, const ScriptSourceCode& scriptSourceCode) | 
| +{ | 
| + // FIXME: how do we know whether to preprocess with Dart or V8? | 
| + return m_v8->preprocess(frame, scriptSourceCode); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::addListener(ScriptDebugListener* listener, Page* page) | 
| +{ | 
| + m_v8->addListener(listener, page); | 
| + m_dart->addListener(listener, page); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page) | 
| +{ | 
| + m_v8->removeListener(listener, page); | 
| + m_dart->removeListener(listener, page); | 
| +} | 
| + | 
| +String UnifiedScriptDebugServer::preprocessEventListener(LocalFrame* frame, const String& source, const String& url, const String& functionName) | 
| +{ | 
| + // FIXME: how do we know whether to preprocess with Dart or V8? | 
| + return m_v8->preprocessEventListener(frame, source, url, functionName); | 
| +} | 
| + | 
| +void UnifiedScriptDebugServer::runScript(ScriptState* scriptState, const String& scriptId, ScriptValue* result, bool* wasThrown, String* exceptionMessage) | 
| +{ | 
| + // FIXME: support runScript for Dart as well. | 
| + m_v8->runScript(scriptState, scriptId, result, wasThrown, exceptionMessage); | 
| +} | 
| + | 
| +} |