diff options
Diffstat (limited to 'Source/WebCore/dom/ScriptExecutionContext.cpp')
-rw-r--r-- | Source/WebCore/dom/ScriptExecutionContext.cpp | 476 |
1 files changed, 273 insertions, 203 deletions
diff --git a/Source/WebCore/dom/ScriptExecutionContext.cpp b/Source/WebCore/dom/ScriptExecutionContext.cpp index ca6041f9a..328818f4a 100644 --- a/Source/WebCore/dom/ScriptExecutionContext.cpp +++ b/Source/WebCore/dom/ScriptExecutionContext.cpp @@ -11,10 +11,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -29,52 +29,39 @@ #include "ScriptExecutionContext.h" #include "CachedScript.h" +#include "CommonVM.h" #include "DOMTimer.h" +#include "DatabaseContext.h" +#include "Document.h" #include "ErrorEvent.h" +#include "JSDOMWindow.h" #include "MessagePort.h" +#include "NoEventDispatchAssertion.h" #include "PublicURLManager.h" -#include "ScriptCallStack.h" +#include "ResourceRequest.h" +#include "ScriptState.h" #include "Settings.h" #include "WorkerGlobalScope.h" #include "WorkerThread.h" +#include <heap/StrongInlines.h> +#include <inspector/ScriptCallStack.h> +#include <runtime/Exception.h> #include <wtf/MainThread.h> #include <wtf/Ref.h> -// FIXME: This is a layering violation. -#include "JSDOMWindow.h" - -#if PLATFORM(IOS) -#include "Document.h" -#endif - -#if ENABLE(SQL_DATABASE) -#include "DatabaseContext.h" -#endif +using namespace Inspector; namespace WebCore { -class ProcessMessagesSoonTask : public ScriptExecutionContext::Task { -public: - static PassOwnPtr<ProcessMessagesSoonTask> create() - { - return adoptPtr(new ProcessMessagesSoonTask); - } - - virtual void performTask(ScriptExecutionContext* context) override - { - context->dispatchMessagePortEvents(); - } -}; - -class ScriptExecutionContext::PendingException { - WTF_MAKE_NONCOPYABLE(PendingException); +struct ScriptExecutionContext::PendingException { + WTF_MAKE_FAST_ALLOCATED; public: - PendingException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack) + PendingException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, RefPtr<ScriptCallStack>&& callStack) : m_errorMessage(errorMessage) , m_lineNumber(lineNumber) , m_columnNumber(columnNumber) , m_sourceURL(sourceURL) - , m_callStack(callStack) + , m_callStack(WTFMove(callStack)) { } String m_errorMessage; @@ -84,240 +71,312 @@ public: RefPtr<ScriptCallStack> m_callStack; }; -void ScriptExecutionContext::AddConsoleMessageTask::performTask(ScriptExecutionContext* context) +ScriptExecutionContext::ScriptExecutionContext() { - context->addConsoleMessage(m_source, m_level, m_message); } -ScriptExecutionContext::ScriptExecutionContext() - : m_iteratingActiveDOMObjects(false) - , m_inDestructor(false) - , m_circularSequentialID(0) - , m_inDispatchErrorEvent(false) - , m_activeDOMObjectsAreSuspended(false) - , m_reasonForSuspendingActiveDOMObjects(static_cast<ActiveDOMObject::ReasonForSuspension>(-1)) - , m_activeDOMObjectsAreStopped(false) +#if ASSERT_DISABLED + +inline void ScriptExecutionContext::checkConsistency() const { } -ScriptExecutionContext::~ScriptExecutionContext() +#else + +void ScriptExecutionContext::checkConsistency() const { - m_inDestructor = true; - for (HashSet<ContextDestructionObserver*>::iterator iter = m_destructionObservers.begin(); iter != m_destructionObservers.end(); iter = m_destructionObservers.begin()) { - ContextDestructionObserver* observer = *iter; - m_destructionObservers.remove(observer); - ASSERT(observer->scriptExecutionContext() == this); - observer->contextDestroyed(); - } + for (auto* messagePort : m_messagePorts) + ASSERT(messagePort->scriptExecutionContext() == this); + + for (auto* destructionObserver : m_destructionObservers) + ASSERT(destructionObserver->scriptExecutionContext() == this); - HashSet<MessagePort*>::iterator messagePortsEnd = m_messagePorts.end(); - for (HashSet<MessagePort*>::iterator iter = m_messagePorts.begin(); iter != messagePortsEnd; ++iter) { - ASSERT((*iter)->scriptExecutionContext() == this); - (*iter)->contextDestroyed(); + for (auto* activeDOMObject : m_activeDOMObjects) { + ASSERT(activeDOMObject->scriptExecutionContext() == this); + activeDOMObject->assertSuspendIfNeededWasCalled(); } -#if ENABLE(BLOB) - if (m_publicURLManager) - m_publicURLManager->contextDestroyed(); +} + +#endif + +ScriptExecutionContext::~ScriptExecutionContext() +{ + checkConsistency(); + +#if !ASSERT_DISABLED + m_inScriptExecutionContextDestructor = true; +#endif + + while (auto* destructionObserver = m_destructionObservers.takeAny()) + destructionObserver->contextDestroyed(); + + for (auto* messagePort : m_messagePorts) + messagePort->contextDestroyed(); + +#if !ASSERT_DISABLED + m_inScriptExecutionContextDestructor = false; #endif } void ScriptExecutionContext::processMessagePortMessagesSoon() { - postTask(ProcessMessagesSoonTask::create()); + if (m_willProcessMessagePortMessagesSoon) + return; + + m_willProcessMessagePortMessagesSoon = true; + postTask([] (ScriptExecutionContext& context) { + context.dispatchMessagePortEvents(); + }); } void ScriptExecutionContext::dispatchMessagePortEvents() { - Ref<ScriptExecutionContext> protect(*this); - - // Make a frozen copy. - Vector<MessagePort*> ports; - copyToVector(m_messagePorts, ports); - - unsigned portCount = ports.size(); - for (unsigned i = 0; i < portCount; ++i) { - MessagePort* port = ports[i]; - // The port may be destroyed, and another one created at the same address, but this is safe, as the worst that can happen - // as a result is that dispatchMessages() will be called needlessly. - if (m_messagePorts.contains(port) && port->started()) - port->dispatchMessages(); + checkConsistency(); + + Ref<ScriptExecutionContext> protectedThis(*this); + ASSERT(m_willProcessMessagePortMessagesSoon); + m_willProcessMessagePortMessagesSoon = false; + + // Make a frozen copy of the ports so we can iterate while new ones might be added or destroyed. + Vector<MessagePort*> possibleMessagePorts; + copyToVector(m_messagePorts, possibleMessagePorts); + for (auto* messagePort : possibleMessagePorts) { + // The port may be destroyed, and another one created at the same address, + // but this is harmless. The worst that can happen as a result is that + // dispatchMessages() will be called needlessly. + if (m_messagePorts.contains(messagePort) && messagePort->started()) + messagePort->dispatchMessages(); } } -void ScriptExecutionContext::createdMessagePort(MessagePort* port) +void ScriptExecutionContext::createdMessagePort(MessagePort& messagePort) { - ASSERT(port); - ASSERT((isDocument() && isMainThread()) - || (isWorkerGlobalScope() && currentThread() == static_cast<WorkerGlobalScope*>(this)->thread()->threadID())); + ASSERT((is<Document>(*this) && isMainThread()) + || (is<WorkerGlobalScope>(*this) && currentThread() == downcast<WorkerGlobalScope>(*this).thread().threadID())); - m_messagePorts.add(port); + m_messagePorts.add(&messagePort); } -void ScriptExecutionContext::destroyedMessagePort(MessagePort* port) +void ScriptExecutionContext::destroyedMessagePort(MessagePort& messagePort) { - ASSERT(port); - ASSERT((isDocument() && isMainThread()) - || (isWorkerGlobalScope() && currentThread() == static_cast<WorkerGlobalScope*>(this)->thread()->threadID())); + ASSERT((is<Document>(*this) && isMainThread()) + || (is<WorkerGlobalScope>(*this) && currentThread() == downcast<WorkerGlobalScope>(*this).thread().threadID())); - m_messagePorts.remove(port); + m_messagePorts.remove(&messagePort); } -bool ScriptExecutionContext::canSuspendActiveDOMObjects() +void ScriptExecutionContext::didLoadResourceSynchronously() { - // No protection against m_activeDOMObjects changing during iteration: canSuspend() shouldn't execute arbitrary JS. - m_iteratingActiveDOMObjects = true; - ActiveDOMObjectsSet::iterator activeObjectsEnd = m_activeDOMObjects.end(); - for (ActiveDOMObjectsSet::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { - ASSERT((*iter)->scriptExecutionContext() == this); - ASSERT((*iter)->suspendIfNeededCalled()); - if (!(*iter)->canSuspend()) { - m_iteratingActiveDOMObjects = false; - return false; +} + +bool ScriptExecutionContext::canSuspendActiveDOMObjectsForDocumentSuspension(Vector<ActiveDOMObject*>* unsuspendableObjects) +{ + checkConsistency(); + + bool canSuspend = true; + + m_activeDOMObjectAdditionForbidden = true; +#if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS) + m_activeDOMObjectRemovalForbidden = true; +#endif + + // We assume that m_activeDOMObjects will not change during iteration: canSuspend + // functions should not add new active DOM objects, nor execute arbitrary JavaScript. + // An ASSERT_WITH_SECURITY_IMPLICATION or RELEASE_ASSERT will fire if this happens, but it's important to code + // canSuspend functions so it will not happen! + NoEventDispatchAssertion assertNoEventDispatch; + for (auto* activeDOMObject : m_activeDOMObjects) { + if (!activeDOMObject->canSuspendForDocumentSuspension()) { + canSuspend = false; + if (unsuspendableObjects) + unsuspendableObjects->append(activeDOMObject); + else + break; } } - m_iteratingActiveDOMObjects = false; - return true; + + m_activeDOMObjectAdditionForbidden = false; +#if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS) + m_activeDOMObjectRemovalForbidden = false; +#endif + + return canSuspend; } void ScriptExecutionContext::suspendActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why) { -#if PLATFORM(IOS) + checkConsistency(); + if (m_activeDOMObjectsAreSuspended) { - ASSERT(m_reasonForSuspendingActiveDOMObjects == ActiveDOMObject::DocumentWillBePaused); + // A page may subsequently suspend DOM objects, say as part of entering the page cache, after the embedding + // client requested the page be suspended. We ignore such requests so long as the embedding client requested + // the suspension first. See <rdar://problem/13754896> for more details. + ASSERT(m_reasonForSuspendingActiveDOMObjects == ActiveDOMObject::PageWillBeSuspended); return; } -#endif - // No protection against m_activeDOMObjects changing during iteration: suspend() shouldn't execute arbitrary JS. - m_iteratingActiveDOMObjects = true; - ActiveDOMObjectsSet::iterator activeObjectsEnd = m_activeDOMObjects.end(); - for (ActiveDOMObjectsSet::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { - ASSERT((*iter)->scriptExecutionContext() == this); - ASSERT((*iter)->suspendIfNeededCalled()); - (*iter)->suspend(why); - } - m_iteratingActiveDOMObjects = false; m_activeDOMObjectsAreSuspended = true; + + m_activeDOMObjectAdditionForbidden = true; +#if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS) + m_activeDOMObjectRemovalForbidden = true; +#endif + + // We assume that m_activeDOMObjects will not change during iteration: suspend + // functions should not add new active DOM objects, nor execute arbitrary JavaScript. + // An ASSERT_WITH_SECURITY_IMPLICATION or RELEASE_ASSERT will fire if this happens, but it's important to code + // suspend functions so it will not happen! + NoEventDispatchAssertion assertNoEventDispatch; + for (auto* activeDOMObject : m_activeDOMObjects) + activeDOMObject->suspend(why); + + m_activeDOMObjectAdditionForbidden = false; +#if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS) + m_activeDOMObjectRemovalForbidden = false; +#endif + m_reasonForSuspendingActiveDOMObjects = why; } void ScriptExecutionContext::resumeActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why) { + checkConsistency(); + if (m_reasonForSuspendingActiveDOMObjects != why) return; - m_activeDOMObjectsAreSuspended = false; - // No protection against m_activeDOMObjects changing during iteration: resume() shouldn't execute arbitrary JS. - m_iteratingActiveDOMObjects = true; - ActiveDOMObjectsSet::iterator activeObjectsEnd = m_activeDOMObjects.end(); - for (ActiveDOMObjectsSet::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { - ASSERT((*iter)->scriptExecutionContext() == this); - ASSERT((*iter)->suspendIfNeededCalled()); - (*iter)->resume(); - } - m_iteratingActiveDOMObjects = false; + + m_activeDOMObjectAdditionForbidden = true; +#if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS) + m_activeDOMObjectRemovalForbidden = true; +#endif + + // We assume that m_activeDOMObjects will not change during iteration: resume + // functions should not add new active DOM objects, nor execute arbitrary JavaScript. + // An ASSERT_WITH_SECURITY_IMPLICATION or RELEASE_ASSERT will fire if this happens, but it's important to code + // resume functions so it will not happen! + NoEventDispatchAssertion assertNoEventDispatch; + for (auto* activeDOMObject : m_activeDOMObjects) + activeDOMObject->resume(); + + m_activeDOMObjectAdditionForbidden = false; +#if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS) + m_activeDOMObjectRemovalForbidden = false; +#endif } void ScriptExecutionContext::stopActiveDOMObjects() { + checkConsistency(); + if (m_activeDOMObjectsAreStopped) return; m_activeDOMObjectsAreStopped = true; - // No protection against m_activeDOMObjects changing during iteration: stop() shouldn't execute arbitrary JS. - m_iteratingActiveDOMObjects = true; - ActiveDOMObjectsSet::iterator activeObjectsEnd = m_activeDOMObjects.end(); - for (ActiveDOMObjectsSet::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { - ASSERT((*iter)->scriptExecutionContext() == this); - ASSERT((*iter)->suspendIfNeededCalled()); - (*iter)->stop(); + + // Make a frozen copy of the objects so we can iterate while new ones might be destroyed. + Vector<ActiveDOMObject*> possibleActiveDOMObjects; + copyToVector(m_activeDOMObjects, possibleActiveDOMObjects); + + m_activeDOMObjectAdditionForbidden = true; + + // We assume that new objects will not be added to m_activeDOMObjects during iteration: + // stop functions should not add new active DOM objects, nor execute arbitrary JavaScript. + // An ASSERT_WITH_SECURITY_IMPLICATION or RELEASE_ASSERT will fire if this happens, but it's important to code stop functions + // so it will not happen! + NoEventDispatchAssertion assertNoEventDispatch; + for (auto* activeDOMObject : possibleActiveDOMObjects) { + // Check if this object was deleted already. If so, just skip it. + // Calling contains on a possibly-already-deleted object is OK because we guarantee + // no new object can be added, so even if a new object ends up allocated with the + // same address, that will be *after* this function exits. + if (!m_activeDOMObjects.contains(activeDOMObject)) + continue; + activeDOMObject->stop(); } - m_iteratingActiveDOMObjects = false; - // Also close MessagePorts. If they were ActiveDOMObjects (they could be) then they could be stopped instead. - closeMessagePorts(); + m_activeDOMObjectAdditionForbidden = false; + + // FIXME: Make message ports be active DOM objects and let them implement stop instead + // of having this separate mechanism just for them. + for (auto* messagePort : m_messagePorts) + messagePort->close(); } -void ScriptExecutionContext::suspendActiveDOMObjectIfNeeded(ActiveDOMObject* object) +void ScriptExecutionContext::suspendActiveDOMObjectIfNeeded(ActiveDOMObject& activeDOMObject) { - ASSERT(m_activeDOMObjects.contains(object)); - // Ensure all ActiveDOMObjects are suspended also newly created ones. + ASSERT(m_activeDOMObjects.contains(&activeDOMObject)); if (m_activeDOMObjectsAreSuspended) - object->suspend(m_reasonForSuspendingActiveDOMObjects); + activeDOMObject.suspend(m_reasonForSuspendingActiveDOMObjects); if (m_activeDOMObjectsAreStopped) - object->stop(); + activeDOMObject.stop(); } -void ScriptExecutionContext::didCreateActiveDOMObject(ActiveDOMObject* object) +void ScriptExecutionContext::didCreateActiveDOMObject(ActiveDOMObject& activeDOMObject) { - ASSERT(object); - ASSERT(!m_inDestructor); - if (m_iteratingActiveDOMObjects) - CRASH(); - m_activeDOMObjects.add(object); + // The m_activeDOMObjectAdditionForbidden check is a RELEASE_ASSERT because of the + // consequences of having an ActiveDOMObject that is not correctly reflected in the set. + // If we do have one of those, it can possibly be a security vulnerability. So we'd + // rather have a crash than continue running with the set possibly compromised. + ASSERT(!m_inScriptExecutionContextDestructor); + RELEASE_ASSERT(!m_activeDOMObjectAdditionForbidden); + m_activeDOMObjects.add(&activeDOMObject); } -void ScriptExecutionContext::willDestroyActiveDOMObject(ActiveDOMObject* object) +void ScriptExecutionContext::willDestroyActiveDOMObject(ActiveDOMObject& activeDOMObject) { - ASSERT(object); - if (m_iteratingActiveDOMObjects) - CRASH(); - m_activeDOMObjects.remove(object); + ASSERT_WITH_SECURITY_IMPLICATION(!m_activeDOMObjectRemovalForbidden); + m_activeDOMObjects.remove(&activeDOMObject); } -void ScriptExecutionContext::didCreateDestructionObserver(ContextDestructionObserver* observer) +void ScriptExecutionContext::didCreateDestructionObserver(ContextDestructionObserver& observer) { - ASSERT(observer); - ASSERT(!m_inDestructor); - m_destructionObservers.add(observer); + ASSERT(!m_inScriptExecutionContextDestructor); + m_destructionObservers.add(&observer); } -void ScriptExecutionContext::willDestroyDestructionObserver(ContextDestructionObserver* observer) +void ScriptExecutionContext::willDestroyDestructionObserver(ContextDestructionObserver& observer) { - ASSERT(observer); - m_destructionObservers.remove(observer); + m_destructionObservers.remove(&observer); } -void ScriptExecutionContext::closeMessagePorts() { - HashSet<MessagePort*>::iterator messagePortsEnd = m_messagePorts.end(); - for (HashSet<MessagePort*>::iterator iter = m_messagePorts.begin(); iter != messagePortsEnd; ++iter) { - ASSERT((*iter)->scriptExecutionContext() == this); - (*iter)->close(); - } -} - -bool ScriptExecutionContext::sanitizeScriptError(String& errorMessage, int& lineNumber, int& columnNumber, String& sourceURL, CachedScript* cachedScript) +bool ScriptExecutionContext::sanitizeScriptError(String& errorMessage, int& lineNumber, int& columnNumber, String& sourceURL, JSC::Strong<JSC::Unknown>& error, CachedScript* cachedScript) { - URL targetURL = completeURL(sourceURL); - if (securityOrigin()->canRequest(targetURL) || (cachedScript && cachedScript->passesAccessControlCheck(securityOrigin()))) + ASSERT(securityOrigin()); + if (cachedScript) { + ASSERT(cachedScript->origin()); + ASSERT(securityOrigin()->toString() == cachedScript->origin()->toString()); + if (cachedScript->isCORSSameOrigin()) + return false; + } else if (securityOrigin()->canRequest(completeURL(sourceURL))) return false; - errorMessage = "Script error."; - sourceURL = String(); + + errorMessage = ASCIILiteral { "Script error." }; + sourceURL = { }; lineNumber = 0; columnNumber = 0; + error = { }; return true; } -void ScriptExecutionContext::reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack, CachedScript* cachedScript) +void ScriptExecutionContext::reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception* exception, RefPtr<ScriptCallStack>&& callStack, CachedScript* cachedScript) { if (m_inDispatchErrorEvent) { if (!m_pendingExceptions) - m_pendingExceptions = adoptPtr(new Vector<OwnPtr<PendingException>>()); - m_pendingExceptions->append(adoptPtr(new PendingException(errorMessage, lineNumber, columnNumber, sourceURL, callStack))); + m_pendingExceptions = std::make_unique<Vector<std::unique_ptr<PendingException>>>(); + m_pendingExceptions->append(std::make_unique<PendingException>(errorMessage, lineNumber, columnNumber, sourceURL, WTFMove(callStack))); return; } // First report the original exception and only then all the nested ones. - if (!dispatchErrorEvent(errorMessage, lineNumber, columnNumber, sourceURL, cachedScript)) - logExceptionToConsole(errorMessage, sourceURL, lineNumber, columnNumber, callStack); + if (!dispatchErrorEvent(errorMessage, lineNumber, columnNumber, sourceURL, exception, cachedScript)) + logExceptionToConsole(errorMessage, sourceURL, lineNumber, columnNumber, callStack.copyRef()); if (!m_pendingExceptions) return; - for (size_t i = 0; i < m_pendingExceptions->size(); i++) { - PendingException* e = m_pendingExceptions->at(i).get(); - logExceptionToConsole(e->m_errorMessage, e->m_sourceURL, e->m_lineNumber, e->m_columnNumber, e->m_callStack); - } - m_pendingExceptions.clear(); + auto pendingExceptions = WTFMove(m_pendingExceptions); + for (auto& exception : *pendingExceptions) + logExceptionToConsole(exception->m_errorMessage, exception->m_sourceURL, exception->m_lineNumber, exception->m_columnNumber, WTFMove(exception->m_callStack)); } void ScriptExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, JSC::ExecState* state, unsigned long requestIdentifier) @@ -325,16 +384,15 @@ void ScriptExecutionContext::addConsoleMessage(MessageSource source, MessageLeve addMessage(source, level, message, sourceURL, lineNumber, columnNumber, 0, state, requestIdentifier); } -bool ScriptExecutionContext::dispatchErrorEvent(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, CachedScript* cachedScript) +bool ScriptExecutionContext::dispatchErrorEvent(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, JSC::Exception* exception, CachedScript* cachedScript) { EventTarget* target = errorEventTarget(); if (!target) return false; #if PLATFORM(IOS) - if (target == target->toDOMWindow() && isDocument()) { - Settings* settings = static_cast<Document*>(this)->settings(); - if (settings && !settings->shouldDispatchJavaScriptWindowOnErrorEvents()) + if (target->toDOMWindow() && is<Document>(*this)) { + if (!downcast<Document>(*this).settings().shouldDispatchJavaScriptWindowOnErrorEvents()) return false; } #endif @@ -343,11 +401,12 @@ bool ScriptExecutionContext::dispatchErrorEvent(const String& errorMessage, int int line = lineNumber; int column = columnNumber; String sourceName = sourceURL; - sanitizeScriptError(message, line, column, sourceName, cachedScript); + JSC::Strong<JSC::Unknown> error = exception && exception->value() ? JSC::Strong<JSC::Unknown>(vm(), exception->value()) : JSC::Strong<JSC::Unknown>(); + sanitizeScriptError(message, line, column, sourceName, error, cachedScript); ASSERT(!m_inDispatchErrorEvent); m_inDispatchErrorEvent = true; - RefPtr<ErrorEvent> errorEvent = ErrorEvent::create(message, sourceName, line, column); + Ref<ErrorEvent> errorEvent = ErrorEvent::create(message, sourceName, line, column, error); target->dispatchEvent(errorEvent); m_inDispatchErrorEvent = false; return errorEvent->defaultPrevented(); @@ -361,70 +420,81 @@ int ScriptExecutionContext::circularSequentialID() return m_circularSequentialID; } -#if ENABLE(BLOB) PublicURLManager& ScriptExecutionContext::publicURLManager() { if (!m_publicURLManager) - m_publicURLManager = PublicURLManager::create(); + m_publicURLManager = PublicURLManager::create(this); return *m_publicURLManager; } -#endif -void ScriptExecutionContext::adjustMinimumTimerInterval(double oldMinimumTimerInterval) +void ScriptExecutionContext::adjustMinimumTimerInterval(std::chrono::milliseconds oldMinimumTimerInterval) { if (minimumTimerInterval() != oldMinimumTimerInterval) { - for (TimeoutMap::iterator iter = m_timeouts.begin(); iter != m_timeouts.end(); ++iter) { - DOMTimer* timer = iter->value; - timer->adjustMinimumTimerInterval(oldMinimumTimerInterval); - } + for (auto& timer : m_timeouts.values()) + timer->updateTimerIntervalIfNecessary(); } } -double ScriptExecutionContext::minimumTimerInterval() const +std::chrono::milliseconds ScriptExecutionContext::minimumTimerInterval() const { // The default implementation returns the DOMTimer's default // minimum timer interval. FIXME: to make it work with dedicated // workers, we will have to override it in the appropriate // subclass, and provide a way to enumerate a Document's dedicated // workers so we can update them all. - return Settings::defaultMinDOMTimerInterval(); + return DOMTimer::defaultMinimumInterval(); } void ScriptExecutionContext::didChangeTimerAlignmentInterval() { - for (TimeoutMap::iterator iter = m_timeouts.begin(); iter != m_timeouts.end(); ++iter) { - DOMTimer* timer = iter->value; + for (auto& timer : m_timeouts.values()) timer->didChangeAlignmentInterval(); - } } -double ScriptExecutionContext::timerAlignmentInterval() const +std::chrono::milliseconds ScriptExecutionContext::timerAlignmentInterval(bool) const { - return Settings::defaultDOMTimerAlignmentInterval(); + return DOMTimer::defaultAlignmentInterval(); } -ScriptExecutionContext::Task::~Task() +JSC::VM& ScriptExecutionContext::vm() { + if (is<Document>(*this)) + return commonVM(); + + return downcast<WorkerGlobalScope>(*this).script()->vm(); } -JSC::VM* ScriptExecutionContext::vm() +void ScriptExecutionContext::setDatabaseContext(DatabaseContext* databaseContext) { - if (isDocument()) - return JSDOMWindow::commonVM(); + m_databaseContext = databaseContext; +} + +bool ScriptExecutionContext::hasPendingActivity() const +{ + checkConsistency(); - if (isWorkerGlobalScope()) - return static_cast<WorkerGlobalScope*>(this)->script()->vm(); + for (auto* activeDOMObject : m_activeDOMObjects) { + if (activeDOMObject->hasPendingActivity()) + return true; + } + + for (auto* messagePort : m_messagePorts) { + if (messagePort->hasPendingActivity()) + return true; + } - ASSERT_NOT_REACHED(); - return 0; + return false; } -#if ENABLE(SQL_DATABASE) -void ScriptExecutionContext::setDatabaseContext(DatabaseContext* databaseContext) +JSC::ExecState* ScriptExecutionContext::execState() { - ASSERT(!m_databaseContext); - m_databaseContext = databaseContext; + if (is<Document>(*this)) { + Document& document = downcast<Document>(*this); + return execStateFromPage(mainThreadNormalWorld(), document.page()); + } + + WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(this); + return execStateFromWorkerGlobalScope(workerGlobalScope); } -#endif } // namespace WebCore |