diff options
Diffstat (limited to 'WebCore/inspector/JavaScriptDebugServer.cpp')
-rw-r--r-- | WebCore/inspector/JavaScriptDebugServer.cpp | 641 |
1 files changed, 0 insertions, 641 deletions
diff --git a/WebCore/inspector/JavaScriptDebugServer.cpp b/WebCore/inspector/JavaScriptDebugServer.cpp deleted file mode 100644 index 03c3577..0000000 --- a/WebCore/inspector/JavaScriptDebugServer.cpp +++ /dev/null @@ -1,641 +0,0 @@ -/* - * Copyright (C) 2008, 2009 Apple 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 "JavaScriptDebugServer.h" - -#if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC) - -#include "DOMWindow.h" -#include "EventLoop.h" -#include "Frame.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "JSDOMWindowCustom.h" -#include "JavaScriptCallFrame.h" -#include "JavaScriptDebugListener.h" -#include "Page.h" -#include "PageGroup.h" -#include "PluginView.h" -#include "ScrollView.h" -#include "Widget.h" -#include "ScriptController.h" -#include <debugger/DebuggerCallFrame.h> -#include <runtime/JSLock.h> -#include <wtf/MainThread.h> -#include <wtf/StdLibExtras.h> -#include <wtf/UnusedParam.h> - -using namespace JSC; - -namespace WebCore { - -typedef JavaScriptDebugServer::ListenerSet ListenerSet; - -inline const UString& JavaScriptDebugServer::BreakpointInfo::condition() const -{ - return m_condition; -} - -void JavaScriptDebugServer::BreakpointInfo::setCondition(const UString& condition) -{ - m_condition = condition; -} - -JavaScriptDebugServer& JavaScriptDebugServer::shared() -{ - DEFINE_STATIC_LOCAL(JavaScriptDebugServer, server, ()); - return server; -} - -JavaScriptDebugServer::JavaScriptDebugServer() - : m_callingListeners(false) - , m_pauseOnExceptionsState(DontPauseOnExceptions) - , m_pauseOnNextStatement(false) - , m_paused(false) - , m_doneProcessingDebuggerEvents(true) - , m_pauseOnCallFrame(0) - , m_recompileTimer(this, &JavaScriptDebugServer::recompileAllJSFunctions) -{ -} - -JavaScriptDebugServer::~JavaScriptDebugServer() -{ - deleteAllValues(m_pageListenersMap); - deleteAllValues(m_breakpoints); -} - -void JavaScriptDebugServer::addListener(JavaScriptDebugListener* listener) -{ - ASSERT_ARG(listener, listener); - - m_listeners.add(listener); - - didAddListener(0); -} - -void JavaScriptDebugServer::removeListener(JavaScriptDebugListener* listener) -{ - ASSERT_ARG(listener, listener); - - m_listeners.remove(listener); - - didRemoveListener(0); - if (!hasListeners()) - didRemoveLastListener(); -} - -void JavaScriptDebugServer::addListener(JavaScriptDebugListener* 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 JavaScriptDebugServer::removeListener(JavaScriptDebugListener* 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); - if (!hasListeners()) - didRemoveLastListener(); -} - -void JavaScriptDebugServer::pageCreated(Page* page) -{ - ASSERT_ARG(page, page); - - if (!hasListenersInterestedInPage(page)) - return; - page->setDebugger(this); -} - -bool JavaScriptDebugServer::hasListenersInterestedInPage(Page* page) -{ - ASSERT_ARG(page, page); - - if (hasGlobalListeners()) - return true; - - return m_pageListenersMap.contains(page); -} - -void JavaScriptDebugServer::addBreakpoint(intptr_t sourceID, unsigned lineNumber, const UString& condition) -{ - LineToBreakpointInfoMap* sourceBreakpoints = m_breakpoints.get(sourceID); - if (!sourceBreakpoints) { - sourceBreakpoints = new LineToBreakpointInfoMap; - m_breakpoints.set(sourceID, sourceBreakpoints); - } - BreakpointInfo* info = sourceBreakpoints->get(lineNumber); - if (!info) - sourceBreakpoints->set(lineNumber, new BreakpointInfo(condition)); - else - updateBreakpointInfo(info, condition); -} - -JavaScriptDebugServer::BreakpointInfo* JavaScriptDebugServer::breakpointInfo(intptr_t sourceID, unsigned lineNumber) const -{ - LineToBreakpointInfoMap* sourceBreakpoints = m_breakpoints.get(sourceID); - if (!sourceBreakpoints) - return 0; - return sourceBreakpoints->get(lineNumber); -} - -void JavaScriptDebugServer::updateBreakpoint(intptr_t sourceID, unsigned lineNumber, const UString& condition) -{ - BreakpointInfo* info = breakpointInfo(sourceID, lineNumber); - if (!info) - return; - updateBreakpointInfo(info, condition); -} - -void JavaScriptDebugServer::updateBreakpointInfo(BreakpointInfo* info, const UString& condition) -{ - info->setCondition(condition); -} - -void JavaScriptDebugServer::removeBreakpoint(intptr_t sourceID, unsigned lineNumber) -{ - LineToBreakpointInfoMap* sourceBreakpoints = m_breakpoints.get(sourceID); - if (!sourceBreakpoints) - return; - - BreakpointInfo* info = sourceBreakpoints->get(lineNumber); - if (!info) - return; - - sourceBreakpoints->remove(lineNumber); - delete info; - - if (sourceBreakpoints->isEmpty()) { - m_breakpoints.remove(sourceID); - delete sourceBreakpoints; - } -} - -bool JavaScriptDebugServer::hasBreakpoint(intptr_t sourceID, unsigned lineNumber) const -{ - BreakpointInfo* info = breakpointInfo(sourceID, lineNumber); - if (!info) - return false; - - // An empty condition counts as no condition which is equivalent to "true". - if (info->condition().isEmpty()) - return true; - - JSValue exception; - JSValue result = m_currentCallFrame->evaluate(info->condition(), exception); - if (exception) { - // An erroneous condition counts as "false". - return false; - } - return result.toBoolean(m_currentCallFrame->scopeChain()->globalObject->globalExec()); -} - -void JavaScriptDebugServer::clearBreakpoints() -{ - BreakpointsMap::iterator end = m_breakpoints.end(); - for (BreakpointsMap::iterator it = m_breakpoints.begin(); it != end; ++it) { - deleteAllValues(*(it->second)); - it->second->clear(); - } - deleteAllValues(m_breakpoints); - m_breakpoints.clear(); -} - -void JavaScriptDebugServer::setPauseOnExceptionsState(PauseOnExceptionsState pause) -{ - m_pauseOnExceptionsState = pause; -} - -void JavaScriptDebugServer::pauseProgram() -{ - m_pauseOnNextStatement = true; -} - -void JavaScriptDebugServer::continueProgram() -{ - if (!m_paused) - return; - - m_pauseOnNextStatement = false; - m_doneProcessingDebuggerEvents = true; -} - -void JavaScriptDebugServer::stepIntoStatement() -{ - if (!m_paused) - return; - - m_pauseOnNextStatement = true; - m_doneProcessingDebuggerEvents = true; -} - -void JavaScriptDebugServer::stepOverStatement() -{ - if (!m_paused) - return; - - m_pauseOnCallFrame = m_currentCallFrame.get(); - m_doneProcessingDebuggerEvents = true; -} - -void JavaScriptDebugServer::stepOutOfFunction() -{ - if (!m_paused) - return; - - m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->caller() : 0; - m_doneProcessingDebuggerEvents = true; -} - -JavaScriptCallFrame* JavaScriptDebugServer::currentCallFrame() -{ - if (!m_paused) - return 0; - return m_currentCallFrame.get(); -} - -static void dispatchDidParseSource(const ListenerSet& listeners, ExecState* exec, const JSC::SourceCode& source) -{ - Vector<JavaScriptDebugListener*> copy; - copyToVector(listeners, copy); - for (size_t i = 0; i < copy.size(); ++i) - copy[i]->didParseSource(exec, source); -} - -static void dispatchFailedToParseSource(const ListenerSet& listeners, ExecState* exec, const SourceCode& source, int errorLine, const String& errorMessage) -{ - Vector<JavaScriptDebugListener*> copy; - copyToVector(listeners, copy); - for (size_t i = 0; i < copy.size(); ++i) - copy[i]->failedToParseSource(exec, source, 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; -} - -void JavaScriptDebugServer::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 JavaScriptDebugServer::sourceParsed(ExecState* exec, const SourceCode& source, int errorLine, const UString& errorMessage) -{ - if (m_callingListeners) - return; - - Page* page = toPage(exec->dynamicGlobalObject()); - if (!page) - return; - - m_callingListeners = true; - - bool isError = errorLine != -1; - - if (hasGlobalListeners()) { - if (isError) - dispatchFailedToParseSource(m_listeners, exec, source, errorLine, errorMessage); - else - dispatchDidParseSource(m_listeners, exec, source); - } - - if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) { - ASSERT(!pageListeners->isEmpty()); - if (isError) - dispatchFailedToParseSource(*pageListeners, exec, source, errorLine, errorMessage); - else - dispatchDidParseSource(*pageListeners, exec, source); - } - - m_callingListeners = false; -} - -static void dispatchFunctionToListeners(const ListenerSet& listeners, JavaScriptDebugServer::JavaScriptExecutionCallback callback) -{ - Vector<JavaScriptDebugListener*> copy; - copyToVector(listeners, copy); - for (size_t i = 0; i < copy.size(); ++i) - (copy[i]->*callback)(); -} - -void JavaScriptDebugServer::dispatchFunctionToListeners(JavaScriptExecutionCallback callback, Page* page) -{ - if (m_callingListeners) - return; - - m_callingListeners = true; - - ASSERT(hasListeners()); - - WebCore::dispatchFunctionToListeners(m_listeners, callback); - - if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) { - ASSERT(!pageListeners->isEmpty()); - WebCore::dispatchFunctionToListeners(*pageListeners, callback); - } - - m_callingListeners = false; -} - -void JavaScriptDebugServer::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 JavaScriptDebugServer::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 JavaScriptDebugServer::setJavaScriptPaused(Frame* frame, bool paused) -{ - ASSERT_ARG(frame, frame); - - if (!frame->script()->canExecuteScripts()) - return; - - frame->script()->setPaused(paused); - - Document* document = frame->document(); - if (paused) - document->suspendActiveDOMObjects(); - else - document->resumeActiveDOMObjects(); - - setJavaScriptPaused(frame->view(), paused); -} - -#if PLATFORM(MAC) - -void JavaScriptDebugServer::setJavaScriptPaused(FrameView*, bool) -{ -} - -#else - -void JavaScriptDebugServer::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); - } -} - -#endif - -void JavaScriptDebugServer::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; - - dispatchFunctionToListeners(&JavaScriptDebugListener::didPause, 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; - - dispatchFunctionToListeners(&JavaScriptDebugListener::didContinue, page); -} - -void JavaScriptDebugServer::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 JavaScriptDebugServer::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 JavaScriptDebugServer::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())); - - // 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 JavaScriptDebugServer::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 JavaScriptDebugServer::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 JavaScriptDebugServer::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 JavaScriptDebugServer::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 JavaScriptDebugServer::recompileAllJSFunctionsSoon() -{ - m_recompileTimer.startOneShot(0); -} - -void JavaScriptDebugServer::recompileAllJSFunctions(Timer<JavaScriptDebugServer>*) -{ - JSLock lock(SilenceAssertionsOnly); - Debugger::recompileAllJSFunctions(JSDOMWindow::commonJSGlobalData()); -} - -void JavaScriptDebugServer::didAddListener(Page* page) -{ - recompileAllJSFunctionsSoon(); - - if (page) - page->setDebugger(this); - else - Page::setDebuggerForAllPages(this); -} - -void JavaScriptDebugServer::didRemoveListener(Page* page) -{ - if (hasGlobalListeners() || (page && hasListenersInterestedInPage(page))) - return; - - recompileAllJSFunctionsSoon(); - - if (page) - page->setDebugger(0); - else - Page::setDebuggerForAllPages(0); -} - -void JavaScriptDebugServer::didRemoveLastListener() -{ - m_doneProcessingDebuggerEvents = true; -} - -} // namespace WebCore - -#endif // ENABLE(JAVASCRIPT_DEBUGGER) |