Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Unified Diff: Source/bindings/dart/DartScriptDebugServer.cpp

Issue 300393002: Merge DevTools Refactor CL to Blink36 (Closed) Base URL: svn://svn.chromium.org/blink/branches/dart/1985
Patch Set: PTAL Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/bindings/dart/DartScriptDebugServer.h ('k') | Source/bindings/dart/DartUtilities.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..90293bff31ecd204c0e71706d361e65d0e2553f0
--- /dev/null
+++ b/Source/bindings/dart/DartScriptDebugServer.cpp
@@ -0,0 +1,1153 @@
+/*
+ * 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/common/StackTrace.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/V8Binding.h"
+#include "bindings/v8/V8ScriptState.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 should be able to get rid of the V8Scope now that
+ // DartScriptState and ScriptState have been refactored.
+ V8Scope v8Scope(DartDOMData::current(), v8::Debug::GetDebugContext());
+
+ LocalFrame* frame = DartUtilities::domWindowForCurrentIsolate()->frame();
+ DartController* controller = DartController::retrieve(frame);
+ Vector<DartScriptState*> 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);
+}
+
+}
« no previous file with comments | « Source/bindings/dart/DartScriptDebugServer.h ('k') | Source/bindings/dart/DartUtilities.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698