diff options
Diffstat (limited to 'WebCore/bindings/js/ScriptDebugServer.cpp')
-rw-r--r-- | WebCore/bindings/js/ScriptDebugServer.cpp | 618 |
1 files changed, 0 insertions, 618 deletions
diff --git a/WebCore/bindings/js/ScriptDebugServer.cpp b/WebCore/bindings/js/ScriptDebugServer.cpp deleted file mode 100644 index 10df223..0000000 --- a/WebCore/bindings/js/ScriptDebugServer.cpp +++ /dev/null @@ -1,618 +0,0 @@ -/* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2010 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: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "ScriptDebugServer.h" - -#if ENABLE(JAVASCRIPT_DEBUGGER) - -#include "DOMWindow.h" -#include "EventLoop.h" -#include "Frame.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "JSDOMWindowCustom.h" -#include "JavaScriptCallFrame.h" -#include "Page.h" -#include "PageGroup.h" -#include "PluginView.h" -#include "ScriptBreakpoint.h" -#include "ScriptController.h" -#include "ScriptDebugListener.h" -#include "ScrollView.h" -#include "Widget.h" -#include <debugger/DebuggerCallFrame.h> -#include <parser/SourceCode.h> -#include <runtime/JSLock.h> -#include <wtf/text/StringConcatenate.h> -#include <wtf/MainThread.h> -#include <wtf/StdLibExtras.h> -#include <wtf/UnusedParam.h> - -using namespace JSC; - -namespace WebCore { - -ScriptDebugServer& ScriptDebugServer::shared() -{ - DEFINE_STATIC_LOCAL(ScriptDebugServer, server, ()); - return server; -} - -ScriptDebugServer::ScriptDebugServer() - : m_callingListeners(false) - , m_pauseOnExceptionsState(DontPauseOnExceptions) - , m_pauseOnNextStatement(false) - , m_paused(false) - , m_pausedPage(0) - , m_doneProcessingDebuggerEvents(true) - , m_breakpointsActivated(true) - , m_pauseOnCallFrame(0) - , m_recompileTimer(this, &ScriptDebugServer::recompileAllJSFunctions) -{ -} - -ScriptDebugServer::~ScriptDebugServer() -{ - deleteAllValues(m_pageListenersMap); -} - -void ScriptDebugServer::addListener(ScriptDebugListener* listener, Page* page) -{ - ASSERT_ARG(listener, listener); - ASSERT_ARG(page, page); - - pair<PageListenersMap::iterator, bool> result = m_pageListenersMap.add(page, 0); - if (result.second) - result.first->second = new ListenerSet; - - ListenerSet* listeners = result.first->second; - listeners->add(listener); - - didAddListener(page); -} - -void ScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page) -{ - ASSERT_ARG(listener, listener); - ASSERT_ARG(page, page); - - PageListenersMap::iterator it = m_pageListenersMap.find(page); - if (it == m_pageListenersMap.end()) - return; - - ListenerSet* listeners = it->second; - listeners->remove(listener); - if (listeners->isEmpty()) { - m_pageListenersMap.remove(it); - delete listeners; - } - - didRemoveListener(page); -} - -void ScriptDebugServer::pageCreated(Page* page) -{ - ASSERT_ARG(page, page); - - if (!hasListenersInterestedInPage(page)) - return; - page->setDebugger(this); -} - -bool ScriptDebugServer::isDebuggerAlwaysEnabled() -{ - return false; -} - -bool ScriptDebugServer::hasListenersInterestedInPage(Page* page) -{ - ASSERT_ARG(page, page); - - return m_pageListenersMap.contains(page); -} - -String ScriptDebugServer::setBreakpoint(const String& sourceID, unsigned lineNumber, const String& condition, bool enabled, unsigned* actualLineNumber) -{ - intptr_t sourceIDValue = sourceID.toIntPtr(); - if (!sourceIDValue) - return ""; - BreakpointsMap::iterator it = m_breakpoints.find(sourceIDValue); - if (it == m_breakpoints.end()) - it = m_breakpoints.set(sourceIDValue, SourceBreakpoints()).first; - if (it->second.contains(lineNumber)) - return ""; - it->second.set(lineNumber, ScriptBreakpoint(enabled, condition)); - *actualLineNumber = lineNumber; - return makeString(sourceID, ":", String::number(lineNumber)); -} - -void ScriptDebugServer::removeBreakpoint(const String& breakpointId) -{ - Vector<String> tokens; - breakpointId.split(":", tokens); - if (tokens.size() != 2) - return; - bool success; - intptr_t sourceIDValue = tokens[0].toIntPtr(&success); - if (!success) - return; - unsigned lineNumber = tokens[1].toUInt(&success); - if (!success) - return; - BreakpointsMap::iterator it = m_breakpoints.find(sourceIDValue); - if (it != m_breakpoints.end()) - it->second.remove(lineNumber); -} - -bool ScriptDebugServer::hasBreakpoint(intptr_t sourceID, unsigned lineNumber) const -{ - if (!m_breakpointsActivated) - return false; - - BreakpointsMap::const_iterator it = m_breakpoints.find(sourceID); - if (it == m_breakpoints.end()) - return false; - SourceBreakpoints::const_iterator breakIt = it->second.find(lineNumber); - if (breakIt == it->second.end() || !breakIt->second.enabled) - return false; - - // An empty condition counts as no condition which is equivalent to "true". - if (breakIt->second.condition.isEmpty()) - return true; - - JSValue exception; - JSValue result = m_currentCallFrame->evaluate(stringToUString(breakIt->second.condition), exception); - if (exception) { - // An erroneous condition counts as "false". - return false; - } - return result.toBoolean(m_currentCallFrame->scopeChain()->globalObject->globalExec()); -} - -void ScriptDebugServer::clearBreakpoints() -{ - m_breakpoints.clear(); -} - -void ScriptDebugServer::setBreakpointsActivated(bool activated) -{ - m_breakpointsActivated = activated; -} - -void ScriptDebugServer::setPauseOnExceptionsState(PauseOnExceptionsState pause) -{ - m_pauseOnExceptionsState = pause; -} - -void ScriptDebugServer::setPauseOnNextStatement(bool pause) -{ - m_pauseOnNextStatement = pause; -} - -void ScriptDebugServer::breakProgram() -{ - // FIXME(WK43332): implement this. -} - -void ScriptDebugServer::continueProgram() -{ - if (!m_paused) - return; - - m_pauseOnNextStatement = false; - m_doneProcessingDebuggerEvents = true; -} - -void ScriptDebugServer::stepIntoStatement() -{ - if (!m_paused) - return; - - m_pauseOnNextStatement = true; - m_doneProcessingDebuggerEvents = true; -} - -void ScriptDebugServer::stepOverStatement() -{ - if (!m_paused) - return; - - m_pauseOnCallFrame = m_currentCallFrame.get(); - m_doneProcessingDebuggerEvents = true; -} - -void ScriptDebugServer::stepOutOfFunction() -{ - if (!m_paused) - return; - - m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->caller() : 0; - m_doneProcessingDebuggerEvents = true; -} - -bool ScriptDebugServer::editScriptSource(const String&, const String&, String&) -{ - // FIXME(40300): implement this. - return false; -} - -JavaScriptCallFrame* ScriptDebugServer::currentCallFrame() -{ - if (!m_paused) - return 0; - return m_currentCallFrame.get(); -} - -void ScriptDebugServer::dispatchDidPause(ScriptDebugListener* listener) -{ - ASSERT(m_paused); - ScriptState* state = m_currentCallFrame->scopeChain()->globalObject->globalExec(); - listener->didPause(state); -} - -void ScriptDebugServer::dispatchDidContinue(ScriptDebugListener* listener) -{ - listener->didContinue(); -} - -void ScriptDebugServer::dispatchDidParseSource(const ListenerSet& listeners, const JSC::SourceCode& source, ScriptWorldType worldType) -{ - String sourceID = ustringToString(JSC::UString::number(source.provider()->asID())); - String url = ustringToString(source.provider()->url()); - String data = ustringToString(JSC::UString(source.data(), source.length())); - int firstLine = source.firstLine(); - - Vector<ScriptDebugListener*> copy; - copyToVector(listeners, copy); - for (size_t i = 0; i < copy.size(); ++i) - copy[i]->didParseSource(sourceID, url, data, firstLine, worldType); -} - -void ScriptDebugServer::dispatchFailedToParseSource(const ListenerSet& listeners, const SourceCode& source, int errorLine, const String& errorMessage) -{ - String url = ustringToString(source.provider()->url()); - String data = ustringToString(JSC::UString(source.data(), source.length())); - int firstLine = source.firstLine(); - - Vector<ScriptDebugListener*> copy; - copyToVector(listeners, copy); - for (size_t i = 0; i < copy.size(); ++i) - copy[i]->failedToParseSource(url, data, firstLine, errorLine, errorMessage); -} - -static Page* toPage(JSGlobalObject* globalObject) -{ - ASSERT_ARG(globalObject, globalObject); - - JSDOMWindow* window = asJSDOMWindow(globalObject); - Frame* frame = window->impl()->frame(); - return frame ? frame->page() : 0; -} - -static ScriptWorldType currentWorldType(ExecState* exec) -{ - if (currentWorld(exec) == mainThreadNormalWorld()) - return MAIN_WORLD; - return EXTENSIONS_WORLD; -} - -void ScriptDebugServer::detach(JSGlobalObject* globalObject) -{ - // If we're detaching from the currently executing global object, manually tear down our - // stack, since we won't get further debugger callbacks to do so. Also, resume execution, - // since there's no point in staying paused once a window closes. - if (m_currentCallFrame && m_currentCallFrame->dynamicGlobalObject() == globalObject) { - m_currentCallFrame = 0; - m_pauseOnCallFrame = 0; - continueProgram(); - } - Debugger::detach(globalObject); -} - -void ScriptDebugServer::sourceParsed(ExecState* exec, const SourceCode& source, int errorLine, const UString& errorMessage) -{ - if (m_callingListeners) - return; - - Page* page = toPage(exec->lexicalGlobalObject()); - if (!page) - return; - - ScriptWorldType worldType = currentWorldType(exec); - - m_callingListeners = true; - - bool isError = errorLine != -1; - - if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) { - ASSERT(!pageListeners->isEmpty()); - if (isError) - dispatchFailedToParseSource(*pageListeners, source, errorLine, ustringToString(errorMessage)); - else - dispatchDidParseSource(*pageListeners, source, worldType); - } - - m_callingListeners = false; -} - -void ScriptDebugServer::dispatchFunctionToListeners(const ListenerSet& listeners, JavaScriptExecutionCallback callback) -{ - Vector<ScriptDebugListener*> copy; - copyToVector(listeners, copy); - for (size_t i = 0; i < copy.size(); ++i) - (this->*callback)(copy[i]); -} - -void ScriptDebugServer::dispatchFunctionToListeners(JavaScriptExecutionCallback callback, Page* page) -{ - if (m_callingListeners) - return; - - m_callingListeners = true; - - if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) { - ASSERT(!pageListeners->isEmpty()); - dispatchFunctionToListeners(*pageListeners, callback); - } - - m_callingListeners = false; -} - -void ScriptDebugServer::setJavaScriptPaused(const PageGroup& pageGroup, bool paused) -{ - setMainThreadCallbacksPaused(paused); - - const HashSet<Page*>& pages = pageGroup.pages(); - - HashSet<Page*>::const_iterator end = pages.end(); - for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) - setJavaScriptPaused(*it, paused); -} - -void ScriptDebugServer::setJavaScriptPaused(Page* page, bool paused) -{ - ASSERT_ARG(page, page); - - page->setDefersLoading(paused); - - for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) - setJavaScriptPaused(frame, paused); -} - -void ScriptDebugServer::setJavaScriptPaused(Frame* frame, bool paused) -{ - ASSERT_ARG(frame, frame); - - if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript)) - return; - - frame->script()->setPaused(paused); - - Document* document = frame->document(); - if (paused) - document->suspendActiveDOMObjects(ActiveDOMObject::JavaScriptDebuggerPaused); - else - document->resumeActiveDOMObjects(); - - setJavaScriptPaused(frame->view(), paused); -} - -void ScriptDebugServer::setJavaScriptPaused(FrameView* view, bool paused) -{ - if (!view) - return; - - const HashSet<RefPtr<Widget> >* children = view->children(); - ASSERT(children); - - HashSet<RefPtr<Widget> >::const_iterator end = children->end(); - for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) { - Widget* widget = (*it).get(); - if (!widget->isPluginView()) - continue; - static_cast<PluginView*>(widget)->setJavaScriptPaused(paused); - } -} - -void ScriptDebugServer::pauseIfNeeded(Page* page) -{ - if (m_paused) - return; - - if (!page || !hasListenersInterestedInPage(page)) - return; - - bool pauseNow = m_pauseOnNextStatement; - pauseNow |= (m_pauseOnCallFrame == m_currentCallFrame); - pauseNow |= (m_currentCallFrame->line() > 0 && hasBreakpoint(m_currentCallFrame->sourceID(), m_currentCallFrame->line())); - if (!pauseNow) - return; - - m_pauseOnCallFrame = 0; - m_pauseOnNextStatement = false; - m_paused = true; - m_pausedPage = page; - - dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidPause, page); - - setJavaScriptPaused(page->group(), true); - - TimerBase::fireTimersInNestedEventLoop(); - - EventLoop loop; - m_doneProcessingDebuggerEvents = false; - while (!m_doneProcessingDebuggerEvents && !loop.ended()) - loop.cycle(); - - setJavaScriptPaused(page->group(), false); - - m_paused = false; - m_pausedPage = 0; - - dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidContinue, page); -} - -void ScriptDebugServer::callEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) -{ - if (m_paused) - return; - - m_currentCallFrame = JavaScriptCallFrame::create(debuggerCallFrame, m_currentCallFrame, sourceID, lineNumber); - pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject())); -} - -void ScriptDebugServer::atStatement(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) -{ - if (m_paused) - return; - - ASSERT(m_currentCallFrame); - if (!m_currentCallFrame) - return; - - m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber); - pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject())); -} - -void ScriptDebugServer::returnEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) -{ - if (m_paused) - return; - - ASSERT(m_currentCallFrame); - if (!m_currentCallFrame) - return; - - m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber); - pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject())); - - // detach may have been called during pauseIfNeeded - if (!m_currentCallFrame) - return; - - // Treat stepping over a return statement like stepping out. - if (m_currentCallFrame == m_pauseOnCallFrame) - m_pauseOnCallFrame = m_currentCallFrame->caller(); - m_currentCallFrame = m_currentCallFrame->caller(); -} - -void ScriptDebugServer::exception(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber, bool hasHandler) -{ - if (m_paused) - return; - - ASSERT(m_currentCallFrame); - if (!m_currentCallFrame) - return; - - if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasHandler)) - m_pauseOnNextStatement = true; - - m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber); - pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject())); -} - -void ScriptDebugServer::willExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) -{ - if (m_paused) - return; - - m_currentCallFrame = JavaScriptCallFrame::create(debuggerCallFrame, m_currentCallFrame, sourceID, lineNumber); - pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject())); -} - -void ScriptDebugServer::didExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) -{ - if (m_paused) - return; - - ASSERT(m_currentCallFrame); - if (!m_currentCallFrame) - return; - - m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber); - pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject())); - - // Treat stepping over the end of a program like stepping out. - if (m_currentCallFrame == m_pauseOnCallFrame) - m_pauseOnCallFrame = m_currentCallFrame->caller(); - m_currentCallFrame = m_currentCallFrame->caller(); -} - -void ScriptDebugServer::didReachBreakpoint(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) -{ - if (m_paused) - return; - - ASSERT(m_currentCallFrame); - if (!m_currentCallFrame) - return; - - m_pauseOnNextStatement = true; - m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber); - pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject())); -} - -void ScriptDebugServer::recompileAllJSFunctionsSoon() -{ - m_recompileTimer.startOneShot(0); -} - -void ScriptDebugServer::recompileAllJSFunctions(Timer<ScriptDebugServer>*) -{ - JSLock lock(SilenceAssertionsOnly); - // If JavaScript stack is not empty postpone recompilation. - if (JSDOMWindow::commonJSGlobalData()->dynamicGlobalObject) - recompileAllJSFunctionsSoon(); - else - Debugger::recompileAllJSFunctions(JSDOMWindow::commonJSGlobalData()); -} - -void ScriptDebugServer::didAddListener(Page* page) -{ - recompileAllJSFunctionsSoon(); - page->setDebugger(this); -} - -void ScriptDebugServer::didRemoveListener(Page* page) -{ - if (hasListenersInterestedInPage(page)) - return; - - if (m_pausedPage == page) - m_doneProcessingDebuggerEvents = true; - - recompileAllJSFunctionsSoon(); - page->setDebugger(0); -} - -} // namespace WebCore - -#endif // ENABLE(JAVASCRIPT_DEBUGGER) |