/* * Copyright (C) 2013-2014 Apple Inc. All rights reserved. * Copyright (c) 2011 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. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR * 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 "PageScriptDebugServer.h" #include "CommonVM.h" #include "Document.h" #include "EventLoop.h" #include "FrameView.h" #include "InspectorController.h" #include "InspectorFrontendClient.h" #include "JSDOMExceptionHandling.h" #include "JSDOMWindowCustom.h" #include "MainFrame.h" #include "Page.h" #include "PageGroup.h" #include "PluginViewBase.h" #include "ScriptController.h" #include "Timer.h" #include #include #include #if PLATFORM(IOS) #include "WebCoreThreadInternal.h" #endif using namespace JSC; using namespace Inspector; namespace WebCore { PageScriptDebugServer::PageScriptDebugServer(Page& page) : ScriptDebugServer(WebCore::commonVM()) , m_page(page) { } void PageScriptDebugServer::attachDebugger() { m_page.setDebugger(this); } void PageScriptDebugServer::detachDebugger(bool isBeingDestroyed) { m_page.setDebugger(nullptr); if (!isBeingDestroyed) recompileAllJSFunctions(); } void PageScriptDebugServer::recompileAllJSFunctions() { JSLockHolder lock(vm()); Debugger::recompileAllJSFunctions(); } void PageScriptDebugServer::didPause(JSGlobalObject*) { setJavaScriptPaused(m_page.group(), true); } void PageScriptDebugServer::didContinue(JSGlobalObject*) { setJavaScriptPaused(m_page.group(), false); } void PageScriptDebugServer::runEventLoopWhilePaused() { #if PLATFORM(IOS) // On iOS, running an EventLoop causes us to run a nested WebRunLoop. // Since the WebThread is autoreleased at the end of run loop iterations // we need to gracefully handle releasing and reacquiring the lock. if (WebThreadIsEnabled()) { ASSERT(WebThreadIsLockedOrDisabled()); JSC::JSLock::DropAllLocks dropAllLocks(vm()); WebRunLoopEnableNested(); runEventLoopWhilePausedInternal(); WebRunLoopDisableNested(); ASSERT(WebThreadIsLockedOrDisabled()); return; } #endif runEventLoopWhilePausedInternal(); } void PageScriptDebugServer::runEventLoopWhilePausedInternal() { TimerBase::fireTimersInNestedEventLoop(); m_page.incrementNestedRunLoopCount(); EventLoop loop; while (!m_doneProcessingDebuggerEvents && !loop.ended()) loop.cycle(); m_page.decrementNestedRunLoopCount(); } bool PageScriptDebugServer::isContentScript(ExecState* exec) const { return ¤tWorld(exec) != &mainThreadNormalWorld(); } void PageScriptDebugServer::reportException(ExecState* exec, JSC::Exception* exception) const { WebCore::reportException(exec, exception); } void PageScriptDebugServer::setJavaScriptPaused(const PageGroup& pageGroup, bool paused) { setMainThreadCallbacksPaused(paused); for (auto& page : pageGroup.pages()) { page->setDefersLoading(paused); for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) setJavaScriptPaused(*frame, paused); if (auto* frontendClient = page->inspectorController().inspectorFrontendClient()) { if (paused) frontendClient->pagePaused(); else frontendClient->pageUnpaused(); } } } void PageScriptDebugServer::setJavaScriptPaused(Frame& frame, bool paused) { if (!frame.script().canExecuteScripts(NotAboutToExecuteScript)) return; frame.script().setPaused(paused); ASSERT(frame.document()); auto& document = *frame.document(); if (paused) { document.suspendScriptedAnimationControllerCallbacks(); document.suspendActiveDOMObjects(ActiveDOMObject::JavaScriptDebuggerPaused); } else { document.resumeActiveDOMObjects(ActiveDOMObject::JavaScriptDebuggerPaused); document.resumeScriptedAnimationControllerCallbacks(); } if (auto* view = frame.view()) { for (auto& child : view->children()) { if (!is(child.get())) continue; downcast(child.get()).setJavaScriptPaused(paused); } } } } // namespace WebCore