WebCore/bindings/js/ScriptDebugServer.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
       
     3  * Copyright (C) 2010 Google Inc. All rights reserved.
       
     4  *
       
     5  * Redistribution and use in source and binary forms, with or without
       
     6  * modification, are permitted provided that the following conditions
       
     7  * are met:
       
     8  *
       
     9  * 1.  Redistributions of source code must retain the above copyright
       
    10  *     notice, this list of conditions and the following disclaimer.
       
    11  * 2.  Redistributions in binary form must reproduce the above copyright
       
    12  *     notice, this list of conditions and the following disclaimer in the
       
    13  *     documentation and/or other materials provided with the distribution.
       
    14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    15  *     its contributors may be used to endorse or promote products derived
       
    16  *     from this software without specific prior written permission.
       
    17  *
       
    18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    28  */
       
    29 
       
    30 #include "config.h"
       
    31 #include "ScriptDebugServer.h"
       
    32 
       
    33 #if ENABLE(JAVASCRIPT_DEBUGGER)
       
    34 
       
    35 #include "DOMWindow.h"
       
    36 #include "EventLoop.h"
       
    37 #include "Frame.h"
       
    38 #include "FrameTree.h"
       
    39 #include "FrameView.h"
       
    40 #include "JSDOMWindowCustom.h"
       
    41 #include "JavaScriptCallFrame.h"
       
    42 #include "Page.h"
       
    43 #include "PageGroup.h"
       
    44 #include "PluginView.h"
       
    45 #include "ScriptBreakpoint.h"
       
    46 #include "ScriptController.h"
       
    47 #include "ScriptDebugListener.h"
       
    48 #include "ScrollView.h"
       
    49 #include "Widget.h"
       
    50 #include <debugger/DebuggerCallFrame.h>
       
    51 #include <parser/SourceCode.h>
       
    52 #include <runtime/JSLock.h>
       
    53 #include <wtf/MainThread.h>
       
    54 #include <wtf/StdLibExtras.h>
       
    55 #include <wtf/UnusedParam.h>
       
    56 
       
    57 using namespace JSC;
       
    58 
       
    59 namespace WebCore {
       
    60 
       
    61 ScriptDebugServer& ScriptDebugServer::shared()
       
    62 {
       
    63     DEFINE_STATIC_LOCAL(ScriptDebugServer, server, ());
       
    64     return server;
       
    65 }
       
    66 
       
    67 ScriptDebugServer::ScriptDebugServer()
       
    68     : m_callingListeners(false)
       
    69     , m_pauseOnExceptionsState(DontPauseOnExceptions)
       
    70     , m_pauseOnNextStatement(false)
       
    71     , m_paused(false)
       
    72     , m_pausedPage(0)
       
    73     , m_doneProcessingDebuggerEvents(true)
       
    74     , m_breakpointsActivated(true)
       
    75     , m_pauseOnCallFrame(0)
       
    76     , m_recompileTimer(this, &ScriptDebugServer::recompileAllJSFunctions)
       
    77 {
       
    78 }
       
    79 
       
    80 ScriptDebugServer::~ScriptDebugServer()
       
    81 {
       
    82     deleteAllValues(m_pageListenersMap);
       
    83 }
       
    84 
       
    85 void ScriptDebugServer::addListener(ScriptDebugListener* listener, Page* page)
       
    86 {
       
    87     ASSERT_ARG(listener, listener);
       
    88     ASSERT_ARG(page, page);
       
    89 
       
    90     pair<PageListenersMap::iterator, bool> result = m_pageListenersMap.add(page, 0);
       
    91     if (result.second)
       
    92         result.first->second = new ListenerSet;
       
    93 
       
    94     ListenerSet* listeners = result.first->second;
       
    95     listeners->add(listener);
       
    96 
       
    97     didAddListener(page);
       
    98 }
       
    99 
       
   100 void ScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page)
       
   101 {
       
   102     ASSERT_ARG(listener, listener);
       
   103     ASSERT_ARG(page, page);
       
   104 
       
   105     PageListenersMap::iterator it = m_pageListenersMap.find(page);
       
   106     if (it == m_pageListenersMap.end())
       
   107         return;
       
   108 
       
   109     ListenerSet* listeners = it->second;
       
   110     listeners->remove(listener);
       
   111     if (listeners->isEmpty()) {
       
   112         m_pageListenersMap.remove(it);
       
   113         delete listeners;
       
   114     }
       
   115 
       
   116     didRemoveListener(page);
       
   117 }
       
   118 
       
   119 void ScriptDebugServer::pageCreated(Page* page)
       
   120 {
       
   121     ASSERT_ARG(page, page);
       
   122 
       
   123     if (!hasListenersInterestedInPage(page))
       
   124         return;
       
   125     page->setDebugger(this);
       
   126 }
       
   127 
       
   128 bool ScriptDebugServer::isDebuggerAlwaysEnabled()
       
   129 {
       
   130     return false;
       
   131 }
       
   132 
       
   133 bool ScriptDebugServer::hasListenersInterestedInPage(Page* page)
       
   134 {
       
   135     ASSERT_ARG(page, page);
       
   136 
       
   137     return m_pageListenersMap.contains(page);
       
   138 }
       
   139 
       
   140 bool ScriptDebugServer::setBreakpoint(const String& sourceID, ScriptBreakpoint breakpoint, unsigned lineNumber, unsigned* actualLineNumber)
       
   141 {
       
   142     intptr_t sourceIDValue = sourceID.toIntPtr();
       
   143     if (!sourceIDValue)
       
   144         return false;
       
   145     BreakpointsMap::iterator it = m_breakpoints.find(sourceIDValue);
       
   146     if (it == m_breakpoints.end())
       
   147         it = m_breakpoints.set(sourceIDValue, SourceBreakpoints()).first;
       
   148     it->second.set(lineNumber, breakpoint);
       
   149     *actualLineNumber = lineNumber;
       
   150     return true;
       
   151 }
       
   152 
       
   153 void ScriptDebugServer::removeBreakpoint(const String& sourceID, unsigned lineNumber)
       
   154 {
       
   155     intptr_t sourceIDValue = sourceID.toIntPtr();
       
   156     if (!sourceIDValue)
       
   157         return;
       
   158     BreakpointsMap::iterator it = m_breakpoints.find(sourceIDValue);
       
   159     if (it != m_breakpoints.end())
       
   160         it->second.remove(lineNumber);
       
   161 }
       
   162 
       
   163 bool ScriptDebugServer::hasBreakpoint(intptr_t sourceID, unsigned lineNumber) const
       
   164 {
       
   165     if (!m_breakpointsActivated)
       
   166         return false;
       
   167 
       
   168     BreakpointsMap::const_iterator it = m_breakpoints.find(sourceID);
       
   169     if (it == m_breakpoints.end())
       
   170         return false;
       
   171     SourceBreakpoints::const_iterator breakIt = it->second.find(lineNumber);
       
   172     if (breakIt == it->second.end() || !breakIt->second.enabled)
       
   173         return false;
       
   174 
       
   175     // An empty condition counts as no condition which is equivalent to "true".
       
   176     if (breakIt->second.condition.isEmpty())
       
   177         return true;
       
   178 
       
   179     JSValue exception;
       
   180     JSValue result = m_currentCallFrame->evaluate(stringToUString(breakIt->second.condition), exception);
       
   181     if (exception) {
       
   182         // An erroneous condition counts as "false".
       
   183         return false;
       
   184     }
       
   185     return result.toBoolean(m_currentCallFrame->scopeChain()->globalObject->globalExec());
       
   186 }
       
   187 
       
   188 void ScriptDebugServer::clearBreakpoints()
       
   189 {
       
   190     m_breakpoints.clear();
       
   191 }
       
   192 
       
   193 void ScriptDebugServer::setBreakpointsActivated(bool activated)
       
   194 {
       
   195     m_breakpointsActivated = activated;
       
   196 }
       
   197 
       
   198 void ScriptDebugServer::setPauseOnExceptionsState(PauseOnExceptionsState pause)
       
   199 {
       
   200     m_pauseOnExceptionsState = pause;
       
   201 }
       
   202 
       
   203 void ScriptDebugServer::pause()
       
   204 {
       
   205     m_pauseOnNextStatement = true;
       
   206 }
       
   207 
       
   208 void ScriptDebugServer::continueProgram()
       
   209 {
       
   210     if (!m_paused)
       
   211         return;
       
   212 
       
   213     m_pauseOnNextStatement = false;
       
   214     m_doneProcessingDebuggerEvents = true;
       
   215 }
       
   216 
       
   217 void ScriptDebugServer::stepIntoStatement()
       
   218 {
       
   219     if (!m_paused)
       
   220         return;
       
   221 
       
   222     m_pauseOnNextStatement = true;
       
   223     m_doneProcessingDebuggerEvents = true;
       
   224 }
       
   225 
       
   226 void ScriptDebugServer::stepOverStatement()
       
   227 {
       
   228     if (!m_paused)
       
   229         return;
       
   230 
       
   231     m_pauseOnCallFrame = m_currentCallFrame.get();
       
   232     m_doneProcessingDebuggerEvents = true;
       
   233 }
       
   234 
       
   235 void ScriptDebugServer::stepOutOfFunction()
       
   236 {
       
   237     if (!m_paused)
       
   238         return;
       
   239 
       
   240     m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->caller() : 0;
       
   241     m_doneProcessingDebuggerEvents = true;
       
   242 }
       
   243 
       
   244 bool ScriptDebugServer::editScriptSource(const String&, const String&, String&)
       
   245 {
       
   246     // FIXME(40300): implement this.
       
   247     return false;
       
   248 }
       
   249 
       
   250 JavaScriptCallFrame* ScriptDebugServer::currentCallFrame()
       
   251 {
       
   252     if (!m_paused)
       
   253         return 0;
       
   254     return m_currentCallFrame.get();
       
   255 }
       
   256 
       
   257 void ScriptDebugServer::dispatchDidPause(ScriptDebugListener* listener)
       
   258 {
       
   259     ASSERT(m_paused);
       
   260     ScriptState* state = m_currentCallFrame->scopeChain()->globalObject->globalExec();
       
   261     listener->didPause(state);
       
   262 }
       
   263 
       
   264 void ScriptDebugServer::dispatchDidContinue(ScriptDebugListener* listener)
       
   265 {
       
   266     listener->didContinue();
       
   267 }
       
   268 
       
   269 void ScriptDebugServer::dispatchDidParseSource(const ListenerSet& listeners, const JSC::SourceCode& source, ScriptWorldType worldType)
       
   270 {
       
   271     String sourceID = ustringToString(JSC::UString::from(source.provider()->asID()));
       
   272     String url = ustringToString(source.provider()->url());
       
   273     String data = ustringToString(JSC::UString(source.data(), source.length()));
       
   274     int firstLine = source.firstLine();
       
   275 
       
   276     Vector<ScriptDebugListener*> copy;
       
   277     copyToVector(listeners, copy);
       
   278     for (size_t i = 0; i < copy.size(); ++i)
       
   279         copy[i]->didParseSource(sourceID, url, data, firstLine, worldType);
       
   280 }
       
   281 
       
   282 void ScriptDebugServer::dispatchFailedToParseSource(const ListenerSet& listeners, const SourceCode& source, int errorLine, const String& errorMessage)
       
   283 {
       
   284     String url = ustringToString(source.provider()->url());
       
   285     String data = ustringToString(JSC::UString(source.data(), source.length()));
       
   286     int firstLine = source.firstLine();
       
   287 
       
   288     Vector<ScriptDebugListener*> copy;
       
   289     copyToVector(listeners, copy);
       
   290     for (size_t i = 0; i < copy.size(); ++i)
       
   291         copy[i]->failedToParseSource(url, data, firstLine, errorLine, errorMessage);
       
   292 }
       
   293 
       
   294 static Page* toPage(JSGlobalObject* globalObject)
       
   295 {
       
   296     ASSERT_ARG(globalObject, globalObject);
       
   297 
       
   298     JSDOMWindow* window = asJSDOMWindow(globalObject);
       
   299     Frame* frame = window->impl()->frame();
       
   300     return frame ? frame->page() : 0;
       
   301 }
       
   302 
       
   303 static ScriptWorldType currentWorldType(ExecState* exec)
       
   304 {
       
   305     if (currentWorld(exec) == mainThreadNormalWorld())
       
   306         return MAIN_WORLD;
       
   307     return EXTENSIONS_WORLD;
       
   308 }
       
   309 
       
   310 void ScriptDebugServer::detach(JSGlobalObject* globalObject)
       
   311 {
       
   312     // If we're detaching from the currently executing global object, manually tear down our
       
   313     // stack, since we won't get further debugger callbacks to do so. Also, resume execution,
       
   314     // since there's no point in staying paused once a window closes.
       
   315     if (m_currentCallFrame && m_currentCallFrame->dynamicGlobalObject() == globalObject) {
       
   316         m_currentCallFrame = 0;
       
   317         m_pauseOnCallFrame = 0;
       
   318         continueProgram();
       
   319     }
       
   320     Debugger::detach(globalObject);
       
   321 }
       
   322 
       
   323 void ScriptDebugServer::sourceParsed(ExecState* exec, const SourceCode& source, int errorLine, const UString& errorMessage)
       
   324 {
       
   325     if (m_callingListeners)
       
   326         return;
       
   327 
       
   328     Page* page = toPage(exec->lexicalGlobalObject());
       
   329     if (!page)
       
   330         return;
       
   331 
       
   332     ScriptWorldType worldType = currentWorldType(exec);
       
   333 
       
   334     m_callingListeners = true;
       
   335 
       
   336     bool isError = errorLine != -1;
       
   337 
       
   338     if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) {
       
   339         ASSERT(!pageListeners->isEmpty());
       
   340         if (isError)
       
   341             dispatchFailedToParseSource(*pageListeners, source, errorLine, ustringToString(errorMessage));
       
   342         else
       
   343             dispatchDidParseSource(*pageListeners, source, worldType);
       
   344     }
       
   345 
       
   346     m_callingListeners = false;
       
   347 }
       
   348 
       
   349 void ScriptDebugServer::dispatchFunctionToListeners(const ListenerSet& listeners, JavaScriptExecutionCallback callback)
       
   350 {
       
   351     Vector<ScriptDebugListener*> copy;
       
   352     copyToVector(listeners, copy);
       
   353     for (size_t i = 0; i < copy.size(); ++i)
       
   354         (this->*callback)(copy[i]);
       
   355 }
       
   356 
       
   357 void ScriptDebugServer::dispatchFunctionToListeners(JavaScriptExecutionCallback callback, Page* page)
       
   358 {
       
   359     if (m_callingListeners)
       
   360         return;
       
   361 
       
   362     m_callingListeners = true;
       
   363 
       
   364     if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) {
       
   365         ASSERT(!pageListeners->isEmpty());
       
   366         dispatchFunctionToListeners(*pageListeners, callback);
       
   367     }
       
   368 
       
   369     m_callingListeners = false;
       
   370 }
       
   371 
       
   372 void ScriptDebugServer::setJavaScriptPaused(const PageGroup& pageGroup, bool paused)
       
   373 {
       
   374     setMainThreadCallbacksPaused(paused);
       
   375 
       
   376     const HashSet<Page*>& pages = pageGroup.pages();
       
   377 
       
   378     HashSet<Page*>::const_iterator end = pages.end();
       
   379     for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it)
       
   380         setJavaScriptPaused(*it, paused);
       
   381 }
       
   382 
       
   383 void ScriptDebugServer::setJavaScriptPaused(Page* page, bool paused)
       
   384 {
       
   385     ASSERT_ARG(page, page);
       
   386 
       
   387     page->setDefersLoading(paused);
       
   388 
       
   389     for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
       
   390         setJavaScriptPaused(frame, paused);
       
   391 }
       
   392 
       
   393 void ScriptDebugServer::setJavaScriptPaused(Frame* frame, bool paused)
       
   394 {
       
   395     ASSERT_ARG(frame, frame);
       
   396 
       
   397     if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript))
       
   398         return;
       
   399 
       
   400     frame->script()->setPaused(paused);
       
   401 
       
   402     Document* document = frame->document();
       
   403     if (paused)
       
   404         document->suspendActiveDOMObjects();
       
   405     else
       
   406         document->resumeActiveDOMObjects();
       
   407 
       
   408     setJavaScriptPaused(frame->view(), paused);
       
   409 }
       
   410 
       
   411 void ScriptDebugServer::setJavaScriptPaused(FrameView* view, bool paused)
       
   412 {
       
   413     if (!view)
       
   414         return;
       
   415 
       
   416     const HashSet<RefPtr<Widget> >* children = view->children();
       
   417     ASSERT(children);
       
   418 
       
   419     HashSet<RefPtr<Widget> >::const_iterator end = children->end();
       
   420     for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) {
       
   421         Widget* widget = (*it).get();
       
   422         if (!widget->isPluginView())
       
   423             continue;
       
   424         static_cast<PluginView*>(widget)->setJavaScriptPaused(paused);
       
   425     }
       
   426 }
       
   427 
       
   428 void ScriptDebugServer::pauseIfNeeded(Page* page)
       
   429 {
       
   430     if (m_paused)
       
   431         return;
       
   432 
       
   433     if (!page || !hasListenersInterestedInPage(page))
       
   434         return;
       
   435 
       
   436     bool pauseNow = m_pauseOnNextStatement;
       
   437     pauseNow |= (m_pauseOnCallFrame == m_currentCallFrame);
       
   438     pauseNow |= (m_currentCallFrame->line() > 0 && hasBreakpoint(m_currentCallFrame->sourceID(), m_currentCallFrame->line()));
       
   439     if (!pauseNow)
       
   440         return;
       
   441 
       
   442     m_pauseOnCallFrame = 0;
       
   443     m_pauseOnNextStatement = false;
       
   444     m_paused = true;
       
   445     m_pausedPage = page;
       
   446 
       
   447     dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidPause, page);
       
   448 
       
   449     setJavaScriptPaused(page->group(), true);
       
   450 
       
   451     TimerBase::fireTimersInNestedEventLoop();
       
   452 
       
   453     EventLoop loop;
       
   454     m_doneProcessingDebuggerEvents = false;
       
   455     while (!m_doneProcessingDebuggerEvents && !loop.ended())
       
   456         loop.cycle();
       
   457 
       
   458     setJavaScriptPaused(page->group(), false);
       
   459 
       
   460     m_paused = false;
       
   461     m_pausedPage = 0;
       
   462 
       
   463     dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidContinue, page);
       
   464 }
       
   465 
       
   466 void ScriptDebugServer::callEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber)
       
   467 {
       
   468     if (m_paused)
       
   469         return;
       
   470 
       
   471     m_currentCallFrame = JavaScriptCallFrame::create(debuggerCallFrame, m_currentCallFrame, sourceID, lineNumber);
       
   472     pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
       
   473 }
       
   474 
       
   475 void ScriptDebugServer::atStatement(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber)
       
   476 {
       
   477     if (m_paused)
       
   478         return;
       
   479 
       
   480     ASSERT(m_currentCallFrame);
       
   481     if (!m_currentCallFrame)
       
   482         return;
       
   483 
       
   484     m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
       
   485     pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
       
   486 }
       
   487 
       
   488 void ScriptDebugServer::returnEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber)
       
   489 {
       
   490     if (m_paused)
       
   491         return;
       
   492 
       
   493     ASSERT(m_currentCallFrame);
       
   494     if (!m_currentCallFrame)
       
   495         return;
       
   496 
       
   497     m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
       
   498     pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
       
   499 
       
   500     // Treat stepping over a return statement like stepping out.
       
   501     if (m_currentCallFrame == m_pauseOnCallFrame)
       
   502         m_pauseOnCallFrame = m_currentCallFrame->caller();
       
   503     m_currentCallFrame = m_currentCallFrame->caller();
       
   504 }
       
   505 
       
   506 void ScriptDebugServer::exception(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber, bool hasHandler)
       
   507 {
       
   508     if (m_paused)
       
   509         return;
       
   510 
       
   511     ASSERT(m_currentCallFrame);
       
   512     if (!m_currentCallFrame)
       
   513         return;
       
   514 
       
   515     if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasHandler))
       
   516         m_pauseOnNextStatement = true;
       
   517 
       
   518     m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
       
   519     pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
       
   520 }
       
   521 
       
   522 void ScriptDebugServer::willExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber)
       
   523 {
       
   524     if (m_paused)
       
   525         return;
       
   526 
       
   527     m_currentCallFrame = JavaScriptCallFrame::create(debuggerCallFrame, m_currentCallFrame, sourceID, lineNumber);
       
   528     pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
       
   529 }
       
   530 
       
   531 void ScriptDebugServer::didExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber)
       
   532 {
       
   533     if (m_paused)
       
   534         return;
       
   535 
       
   536     ASSERT(m_currentCallFrame);
       
   537     if (!m_currentCallFrame)
       
   538         return;
       
   539 
       
   540     m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
       
   541     pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
       
   542 
       
   543     // Treat stepping over the end of a program like stepping out.
       
   544     if (m_currentCallFrame == m_pauseOnCallFrame)
       
   545         m_pauseOnCallFrame = m_currentCallFrame->caller();
       
   546     m_currentCallFrame = m_currentCallFrame->caller();
       
   547 }
       
   548 
       
   549 void ScriptDebugServer::didReachBreakpoint(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber)
       
   550 {
       
   551     if (m_paused)
       
   552         return;
       
   553 
       
   554     ASSERT(m_currentCallFrame);
       
   555     if (!m_currentCallFrame)
       
   556         return;
       
   557 
       
   558     m_pauseOnNextStatement = true;
       
   559     m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
       
   560     pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
       
   561 }
       
   562 
       
   563 void ScriptDebugServer::recompileAllJSFunctionsSoon()
       
   564 {
       
   565     m_recompileTimer.startOneShot(0);
       
   566 }
       
   567 
       
   568 void ScriptDebugServer::recompileAllJSFunctions(Timer<ScriptDebugServer>*)
       
   569 {
       
   570     JSLock lock(SilenceAssertionsOnly);
       
   571     // If JavaScript stack is not empty postpone recompilation.
       
   572     if (JSDOMWindow::commonJSGlobalData()->dynamicGlobalObject)
       
   573         recompileAllJSFunctionsSoon();
       
   574     else
       
   575         Debugger::recompileAllJSFunctions(JSDOMWindow::commonJSGlobalData());
       
   576 }
       
   577 
       
   578 void ScriptDebugServer::didAddListener(Page* page)
       
   579 {
       
   580     recompileAllJSFunctionsSoon();
       
   581     page->setDebugger(this);
       
   582 }
       
   583 
       
   584 void ScriptDebugServer::didRemoveListener(Page* page)
       
   585 {
       
   586     if (hasListenersInterestedInPage(page))
       
   587         return;
       
   588 
       
   589     if (m_pausedPage == page)
       
   590         m_doneProcessingDebuggerEvents = true;
       
   591 
       
   592     recompileAllJSFunctionsSoon();
       
   593     page->setDebugger(0);
       
   594 }
       
   595 
       
   596 } // namespace WebCore
       
   597 
       
   598 #endif // ENABLE(JAVASCRIPT_DEBUGGER)