958cbfe48ad37ca044920717468f836aec3a397b
[WebKit-https.git] / Source / WebCore / inspector / PageScriptDebugServer.cpp
1 /*
2  * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
3  * Copyright (c) 2011 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  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "PageScriptDebugServer.h"
29
30 #include "Document.h"
31 #include "EventLoop.h"
32 #include "FrameView.h"
33 #include "JSDOMWindowCustom.h"
34 #include "MainFrame.h"
35 #include "Page.h"
36 #include "PageGroup.h"
37 #include "PluginViewBase.h"
38 #include "ScriptController.h"
39 #include "Timer.h"
40 #include <runtime/JSLock.h>
41 #include <wtf/MainThread.h>
42 #include <wtf/StdLibExtras.h>
43
44 #if PLATFORM(IOS)
45 #include "JSDOMWindowBase.h"
46 #include "WebCoreThreadInternal.h"
47 #endif
48
49 using namespace JSC;
50 using namespace Inspector;
51
52 namespace WebCore {
53
54 PageScriptDebugServer::PageScriptDebugServer(Page& page)
55     : ScriptDebugServer(false)
56     , m_page(page)
57 {
58 }
59
60 void PageScriptDebugServer::addListener(ScriptDebugListener* listener)
61 {
62     if (!listener)
63         return;
64
65     bool wasEmpty = m_listeners.isEmpty();
66     m_listeners.add(listener);
67
68     if (wasEmpty) {
69         m_page.setDebugger(this);
70         recompileAllJSFunctions();
71     }
72 }
73
74 void PageScriptDebugServer::removeListener(ScriptDebugListener* listener, bool isBeingDestroyed)
75 {
76     if (!listener)
77         return;
78
79     m_listeners.remove(listener);
80
81     if (m_listeners.isEmpty()) {
82         m_page.setDebugger(nullptr);
83         if (!isBeingDestroyed)
84             recompileAllJSFunctions();
85     }
86 }
87
88 void PageScriptDebugServer::recompileAllJSFunctions()
89 {
90     JSLockHolder lock(JSDOMWindow::commonVM());
91     Debugger::recompileAllJSFunctions(&JSDOMWindow::commonVM());
92 }
93
94 void PageScriptDebugServer::didPause(JSGlobalObject*)
95 {
96     setJavaScriptPaused(m_page.group(), true);
97 }
98
99 void PageScriptDebugServer::didContinue(JSGlobalObject*)
100 {
101     setJavaScriptPaused(m_page.group(), false);
102 }
103
104 void PageScriptDebugServer::runEventLoopWhilePaused()
105 {
106 #if PLATFORM(IOS)
107     // On iOS, running an EventLoop causes us to run a nested WebRunLoop.
108     // Since the WebThread is autoreleased at the end of run loop iterations
109     // we need to gracefully handle releasing and reacquiring the lock.
110     if (WebThreadIsEnabled()) {
111         ASSERT(WebThreadIsLockedOrDisabled());
112         JSC::JSLock::DropAllLocks dropAllLocks(WebCore::JSDOMWindowBase::commonVM());
113         WebRunLoopEnableNested();
114
115         runEventLoopWhilePausedInternal();
116
117         WebRunLoopDisableNested();
118         ASSERT(WebThreadIsLockedOrDisabled());
119         return;
120     }
121 #endif
122
123     runEventLoopWhilePausedInternal();
124 }
125
126 void PageScriptDebugServer::runEventLoopWhilePausedInternal()
127 {
128     TimerBase::fireTimersInNestedEventLoop();
129
130     EventLoop loop;
131     while (!m_doneProcessingDebuggerEvents && !loop.ended())
132         loop.cycle();
133 }
134
135 bool PageScriptDebugServer::isContentScript(ExecState* exec) const
136 {
137     return &currentWorld(exec) != &mainThreadNormalWorld();
138 }
139
140 void PageScriptDebugServer::reportException(ExecState* exec, JSValue exception) const
141 {
142     WebCore::reportException(exec, exception);
143 }
144
145 void PageScriptDebugServer::setJavaScriptPaused(const PageGroup& pageGroup, bool paused)
146 {
147     setMainThreadCallbacksPaused(paused);
148
149     const HashSet<Page*>& pages = pageGroup.pages();
150
151     HashSet<Page*>::const_iterator end = pages.end();
152     for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it)
153         setJavaScriptPaused(*it, paused);
154 }
155
156 void PageScriptDebugServer::setJavaScriptPaused(Page* page, bool paused)
157 {
158     ASSERT_ARG(page, page);
159
160     page->setDefersLoading(paused);
161
162     for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext())
163         setJavaScriptPaused(frame, paused);
164 }
165
166 void PageScriptDebugServer::setJavaScriptPaused(Frame* frame, bool paused)
167 {
168     ASSERT_ARG(frame, frame);
169
170     if (!frame->script().canExecuteScripts(NotAboutToExecuteScript))
171         return;
172
173     frame->script().setPaused(paused);
174
175     Document* document = frame->document();
176     if (paused) {
177         document->suspendScriptedAnimationControllerCallbacks();
178         document->suspendActiveDOMObjects(ActiveDOMObject::JavaScriptDebuggerPaused);
179     } else {
180         document->resumeActiveDOMObjects(ActiveDOMObject::JavaScriptDebuggerPaused);
181         document->resumeScriptedAnimationControllerCallbacks();
182     }
183
184     setJavaScriptPaused(frame->view(), paused);
185 }
186
187 void PageScriptDebugServer::setJavaScriptPaused(FrameView* view, bool paused)
188 {
189     if (!view)
190         return;
191
192     for (auto& child : view->children()) {
193         if (!is<PluginViewBase>(*child))
194             continue;
195
196         downcast<PluginViewBase>(*child).setJavaScriptPaused(paused);
197     }
198 }
199
200 } // namespace WebCore