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 "CommonVM.h" |
31 | #include "Document.h" |
32 | #include "EventLoop.h" |
33 | #include "Frame.h" |
34 | #include "FrameView.h" |
35 | #include "InspectorController.h" |
36 | #include "InspectorFrontendClient.h" |
37 | #include "JSDOMExceptionHandling.h" |
38 | #include "JSDOMWindowCustom.h" |
39 | #include "Page.h" |
40 | #include "PageGroup.h" |
41 | #include "PluginViewBase.h" |
42 | #include "ScriptController.h" |
43 | #include "Timer.h" |
44 | #include <JavaScriptCore/JSLock.h> |
45 | #include <wtf/MainThread.h> |
46 | #include <wtf/StdLibExtras.h> |
47 | |
48 | #if PLATFORM(IOS_FAMILY) |
49 | #include "WebCoreThreadInternal.h" |
50 | #endif |
51 | |
52 | |
53 | namespace WebCore { |
54 | using namespace JSC; |
55 | using namespace Inspector; |
56 | |
57 | PageScriptDebugServer::PageScriptDebugServer(Page& page) |
58 | : ScriptDebugServer(WebCore::commonVM()) |
59 | , m_page(page) |
60 | { |
61 | } |
62 | |
63 | void PageScriptDebugServer::attachDebugger() |
64 | { |
65 | m_page.setDebugger(this); |
66 | } |
67 | |
68 | void PageScriptDebugServer::detachDebugger(bool isBeingDestroyed) |
69 | { |
70 | m_page.setDebugger(nullptr); |
71 | if (!isBeingDestroyed) |
72 | recompileAllJSFunctions(); |
73 | } |
74 | |
75 | void PageScriptDebugServer::recompileAllJSFunctions() |
76 | { |
77 | JSLockHolder lock(vm()); |
78 | Debugger::recompileAllJSFunctions(); |
79 | } |
80 | |
81 | void PageScriptDebugServer::didPause(JSGlobalObject*) |
82 | { |
83 | setJavaScriptPaused(m_page.group(), true); |
84 | } |
85 | |
86 | void PageScriptDebugServer::didContinue(JSGlobalObject*) |
87 | { |
88 | setJavaScriptPaused(m_page.group(), false); |
89 | } |
90 | |
91 | void PageScriptDebugServer::runEventLoopWhilePaused() |
92 | { |
93 | #if PLATFORM(IOS_FAMILY) |
94 | // On iOS, running an EventLoop causes us to run a nested WebRunLoop. |
95 | // Since the WebThread is autoreleased at the end of run loop iterations |
96 | // we need to gracefully handle releasing and reacquiring the lock. |
97 | if (WebThreadIsEnabled()) { |
98 | ASSERT(WebThreadIsLockedOrDisabled()); |
99 | JSC::JSLock::DropAllLocks dropAllLocks(vm()); |
100 | WebRunLoopEnableNested(); |
101 | |
102 | runEventLoopWhilePausedInternal(); |
103 | |
104 | WebRunLoopDisableNested(); |
105 | ASSERT(WebThreadIsLockedOrDisabled()); |
106 | return; |
107 | } |
108 | #endif |
109 | |
110 | runEventLoopWhilePausedInternal(); |
111 | } |
112 | |
113 | void PageScriptDebugServer::runEventLoopWhilePausedInternal() |
114 | { |
115 | TimerBase::fireTimersInNestedEventLoop(); |
116 | |
117 | m_page.incrementNestedRunLoopCount(); |
118 | |
119 | EventLoop loop; |
120 | while (!m_doneProcessingDebuggerEvents && !loop.ended()) |
121 | loop.cycle(); |
122 | |
123 | m_page.decrementNestedRunLoopCount(); |
124 | } |
125 | |
126 | bool PageScriptDebugServer::isContentScript(ExecState* state) const |
127 | { |
128 | return ¤tWorld(*state) != &mainThreadNormalWorld(); |
129 | } |
130 | |
131 | void PageScriptDebugServer::reportException(ExecState* state, JSC::Exception* exception) const |
132 | { |
133 | WebCore::reportException(state, exception); |
134 | } |
135 | |
136 | void PageScriptDebugServer::setJavaScriptPaused(const PageGroup& pageGroup, bool paused) |
137 | { |
138 | setMainThreadCallbacksPaused(paused); |
139 | |
140 | for (auto& page : pageGroup.pages()) { |
141 | for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) |
142 | setJavaScriptPaused(*frame, paused); |
143 | |
144 | if (auto* frontendClient = page->inspectorController().inspectorFrontendClient()) { |
145 | if (paused) |
146 | frontendClient->pagePaused(); |
147 | else |
148 | frontendClient->pageUnpaused(); |
149 | } |
150 | } |
151 | } |
152 | |
153 | void PageScriptDebugServer::setJavaScriptPaused(Frame& frame, bool paused) |
154 | { |
155 | if (!frame.script().canExecuteScripts(NotAboutToExecuteScript)) |
156 | return; |
157 | |
158 | frame.script().setPaused(paused); |
159 | |
160 | ASSERT(frame.document()); |
161 | auto& document = *frame.document(); |
162 | if (paused) { |
163 | document.suspendScriptedAnimationControllerCallbacks(); |
164 | document.suspendActiveDOMObjects(ReasonForSuspension::JavaScriptDebuggerPaused); |
165 | } else { |
166 | document.resumeActiveDOMObjects(ReasonForSuspension::JavaScriptDebuggerPaused); |
167 | document.resumeScriptedAnimationControllerCallbacks(); |
168 | } |
169 | |
170 | if (auto* view = frame.view()) { |
171 | for (auto& child : view->children()) { |
172 | if (!is<PluginViewBase>(child)) |
173 | continue; |
174 | downcast<PluginViewBase>(child.get()).setJavaScriptPaused(paused); |
175 | } |
176 | } |
177 | } |
178 | |
179 | } // namespace WebCore |
180 | |