Changeset 167579 in webkit


Ignore:
Timestamp:
Apr 20, 2014 9:39:11 PM (10 years ago)
Author:
Darin Adler
Message:

ScriptExecutionContext::stopActiveDOMObjects iterates a hash map that can change during iteration (for multiple reasons, including GC)
https://bugs.webkit.org/show_bug.cgi?id=52719

Reviewed by Alexey Proskuryakov.

At least two specific ways this can happen:

1) XMLHttpRequest::stop can trigger a JavaScript garbage collection.
2) NotificationCenter::stop can delete the last references to notifications;

those notifications are also active DOM objects.

Besides fixing the iteration in that function, did some other fixes for the
ScriptExecutionContext class, including some coding style changes. Many uses
of nullptr instead of 0, without listing each function separately below.

  • Modules/webdatabase/DatabaseContext.cpp:

(WebCore::DatabaseContext::contextDestroyed): Call through to the base class
version of contextDestroyed rather than repeating what it does (with a large
comment that doesn't acknowledge the base class alread does it).

  • Modules/webdatabase/DatabaseContext.h: Removed some unneeded includes.

Wrote out "private" explicitly for deriving from ActiveDOMObject. Made the
ActiveDOMObject function overrides private, and marked them override and final.

  • dom/ActiveDOMObject.h: Updated comments. Replaced suspendIfNeededCalled with

assertSuspendIfNeededWasCalled, which has an empty inline version in the header.
Renamed m_suspendIfNeededCalled to m_suspendIfNeededWasCalled.

  • dom/ActiveDOMObject.cpp:

(WebCore::ActiveDOMObject::ActiveDOMObject): Pass a reference instead of a pointer.
(WebCore::ActiveDOMObject::~ActiveDOMObject): Ditto.
(WebCore::ActiveDOMObject::suspendIfNeeded): Ditto.

  • dom/ContextDestructionObserver.cpp:

(WebCore::ContextDestructionObserver::observeContext): Pass a reference instead of a pointer.

  • dom/MessagePort.cpp:

(WebCore::MessagePort::MessagePort): Pass a reference instead of a pointer.
(WebCore::MessagePort::~MessagePort): Ditto.
(WebCore::MessagePort::disentangle): Ditto.

  • dom/ScriptExecutionContext.cpp:

(WebCore::ScriptExecutionContext::ScriptExecutionContext): Updated flags used
for assertions so they are conditional and updated their names.
(WebCore::takeAny): Added. Helper function that we can consider for HashSet in
the future; makes loop below easier to read.
(WebCore::checkConsistency): Added. Assertions that were done multiple places below,
and should not be written over and over again.
(WebCore::ScriptExecutionContext::~ScriptExecutionContext): Changed to use C++11
for loops and the takeAny function above.
(WebCore::ScriptExecutionContext::dispatchMessagePortEvents): Ditto.
(WebCore::ScriptExecutionContext::createdMessagePort): Changed to take a reference
for clarity and so it doesn't have to do an assert the pointer is non-null.
(WebCore::ScriptExecutionContext::destroyedMessagePort): Ditto.
(WebCore::ScriptExecutionContext::canSuspendActiveDOMObjects): Changed to use
C++11 for loop and reworded comment and redid assertions.
(WebCore::ScriptExecutionContext::suspendActiveDOMObjects): Ditto.
(WebCore::ScriptExecutionContext::resumeActiveDOMObjects): Ditto.
(WebCore::ScriptExecutionContext::stopActiveDOMObjects): Changed to support
removal of an active DOM object during the stop function. Included new comments
to clarify what the rules are.
(WebCore::ScriptExecutionContext::suspendActiveDOMObjectIfNeeded): Changed to take
a reference for clarity and so it doesn't have to assert a pointer is non-null.
(WebCore::ScriptExecutionContext::didCreateActiveDOMObject): Ditto. Also changed to
use RELEASE_ASSERT instead of CRASH.
(WebCore::ScriptExecutionContext::willDestroyActiveDOMObject): Ditto.
(WebCore::ScriptExecutionContext::didCreateDestructionObserver): Ditto.
(WebCore::ScriptExecutionContext::willDestroyDestructionObserver): Ditto.
(WebCore::ScriptExecutionContext::closeMessagePorts): Moved the body of this
function into its one call site, ScriptExecutionContext::stopActiveDOMObjects,
since it's simple enough when written as a C++11 for loop.
(WebCore::ScriptExecutionContext::hasPendingActivity): Added. This function was
already exported for workers, and implementing it outside this class required
exposing the private HashSet members; more sensible to implement it here and
simply make it public in WorkerGlobalScope.

  • dom/ScriptExecutionContext.h: Removed unnecessary includes and forward declarations.

Removed a long-ago-fixed FIXME. Changed various functions to take references instead of
pointers. Added a protected hasPendingActivity function, deleted the closeMessagePorts
function, deleted the ActiveDOMObjectsSet typedef, made the assertion flags be
!ASSERT_DISABLED only, and deleted the messagePorts and activeDOMObjects functions.

  • workers/WorkerGlobalScope.cpp:

(WebCore::WorkerGlobalScope::hasPendingActivity): Deleted. This is now implemented
in the base class.

  • workers/WorkerGlobalScope.h: Make hasPendingActivity function from the base class

public instead of declaring it in this class.

Location:
trunk/Source/WebCore
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r167578 r167579  
     12014-04-20  Darin Adler  <darin@apple.com>
     2
     3        ScriptExecutionContext::stopActiveDOMObjects iterates a hash map that can change during iteration (for multiple reasons, including GC)
     4        https://bugs.webkit.org/show_bug.cgi?id=52719
     5
     6        Reviewed by Alexey Proskuryakov.
     7
     8        At least two specific ways this can happen:
     9
     10        1) XMLHttpRequest::stop can trigger a JavaScript garbage collection.
     11        2) NotificationCenter::stop can delete the last references to notifications;
     12           those notifications are also active DOM objects.
     13
     14        Besides fixing the iteration in that function, did some other fixes for the
     15        ScriptExecutionContext class, including some coding style changes. Many uses
     16        of nullptr instead of 0, without listing each function separately below.
     17
     18        * Modules/webdatabase/DatabaseContext.cpp:
     19        (WebCore::DatabaseContext::contextDestroyed): Call through to the base class
     20        version of contextDestroyed rather than repeating what it does (with a large
     21        comment that doesn't acknowledge the base class alread does it).
     22        * Modules/webdatabase/DatabaseContext.h: Removed some unneeded includes.
     23        Wrote out "private" explicitly for deriving from ActiveDOMObject. Made the
     24        ActiveDOMObject function overrides private, and marked them override and final.
     25
     26        * dom/ActiveDOMObject.h: Updated comments. Replaced suspendIfNeededCalled with
     27        assertSuspendIfNeededWasCalled, which has an empty inline version in the header.
     28        Renamed m_suspendIfNeededCalled to m_suspendIfNeededWasCalled.
     29
     30        * dom/ActiveDOMObject.cpp:
     31        (WebCore::ActiveDOMObject::ActiveDOMObject): Pass a reference instead of a pointer.
     32        (WebCore::ActiveDOMObject::~ActiveDOMObject): Ditto.
     33        (WebCore::ActiveDOMObject::suspendIfNeeded): Ditto.
     34
     35        * dom/ContextDestructionObserver.cpp:
     36        (WebCore::ContextDestructionObserver::observeContext): Pass a reference instead of a pointer.
     37
     38        * dom/MessagePort.cpp:
     39        (WebCore::MessagePort::MessagePort): Pass a reference instead of a pointer.
     40        (WebCore::MessagePort::~MessagePort): Ditto.
     41        (WebCore::MessagePort::disentangle): Ditto.
     42
     43        * dom/ScriptExecutionContext.cpp:
     44        (WebCore::ScriptExecutionContext::ScriptExecutionContext): Updated flags used
     45        for assertions so they are conditional and updated their names.
     46        (WebCore::takeAny): Added. Helper function that we can consider for HashSet in
     47        the future; makes loop below easier to read.
     48        (WebCore::checkConsistency): Added. Assertions that were done multiple places below,
     49        and should not be written over and over again.
     50        (WebCore::ScriptExecutionContext::~ScriptExecutionContext): Changed to use C++11
     51        for loops and the takeAny function above.
     52        (WebCore::ScriptExecutionContext::dispatchMessagePortEvents): Ditto.
     53        (WebCore::ScriptExecutionContext::createdMessagePort): Changed to take a reference
     54        for clarity and so it doesn't have to do an assert the pointer is non-null.
     55        (WebCore::ScriptExecutionContext::destroyedMessagePort): Ditto.
     56        (WebCore::ScriptExecutionContext::canSuspendActiveDOMObjects): Changed to use
     57        C++11 for loop and reworded comment and redid assertions.
     58        (WebCore::ScriptExecutionContext::suspendActiveDOMObjects): Ditto.
     59        (WebCore::ScriptExecutionContext::resumeActiveDOMObjects): Ditto.
     60        (WebCore::ScriptExecutionContext::stopActiveDOMObjects): Changed to support
     61        removal of an active DOM object during the stop function. Included new comments
     62        to clarify what the rules are.
     63        (WebCore::ScriptExecutionContext::suspendActiveDOMObjectIfNeeded): Changed to take
     64        a reference for clarity and so it doesn't have to assert a pointer is non-null.
     65        (WebCore::ScriptExecutionContext::didCreateActiveDOMObject): Ditto. Also changed to
     66        use RELEASE_ASSERT instead of CRASH.
     67        (WebCore::ScriptExecutionContext::willDestroyActiveDOMObject): Ditto.
     68        (WebCore::ScriptExecutionContext::didCreateDestructionObserver): Ditto.
     69        (WebCore::ScriptExecutionContext::willDestroyDestructionObserver): Ditto.
     70        (WebCore::ScriptExecutionContext::closeMessagePorts): Moved the body of this
     71        function into its one call site, ScriptExecutionContext::stopActiveDOMObjects,
     72        since it's simple enough when written as a C++11 for loop.
     73        (WebCore::ScriptExecutionContext::hasPendingActivity): Added. This function was
     74        already exported for workers, and implementing it outside this class required
     75        exposing the private HashSet members; more sensible to implement it here and
     76        simply make it public in WorkerGlobalScope.
     77
     78        * dom/ScriptExecutionContext.h: Removed unnecessary includes and forward declarations.
     79        Removed a long-ago-fixed FIXME. Changed various functions to take references instead of
     80        pointers. Added a protected hasPendingActivity function, deleted the closeMessagePorts
     81        function, deleted the ActiveDOMObjectsSet typedef, made the assertion flags be
     82        !ASSERT_DISABLED only, and deleted the messagePorts and activeDOMObjects functions.
     83
     84        * workers/WorkerGlobalScope.cpp:
     85        (WebCore::WorkerGlobalScope::hasPendingActivity): Deleted. This is now implemented
     86        in the base class.
     87
     88        * workers/WorkerGlobalScope.h: Make hasPendingActivity function from the base class
     89        public instead of declaring it in this class.
     90
    1912014-04-20  Brent Fulgham  <bfulgham@apple.com>
    292
  • trunk/Source/WebCore/Modules/webdatabase/DatabaseContext.cpp

    r166661 r167579  
    105105#if PLATFORM(IOS)
    106106    , m_paused(false)
    107 #endif //PLATFORM(IOS)
     107#endif
    108108{
    109109    // ActiveDOMObject expects this to be called to set internal flags.
     
    129129}
    130130
    131 // This is called if the associated ScriptExecutionContext is destructing while
     131// This is called if the associated ScriptExecutionContext is destroyed while
    132132// we're still associated with it. That's our cue to disassociate and shutdown.
    133 // To do this, we stop the database and let everything shutdown naturally
    134 // because the database closing process may still make use of this context.
     133// To do this, we stop the database and let everything shut down naturally
     134// because the database closing process might still make use of this context.
    135135// It is not safe to just delete the context here.
    136136void DatabaseContext::contextDestroyed()
    137137{
    138138    stopDatabases();
    139 
    140     // Normally, willDestroyActiveDOMObject() is called in ~ActiveDOMObject().
    141     // However, we're here because the destructor hasn't been called, and the
    142     // ScriptExecutionContext we're associated with is about to be destructed.
    143     // So, go ahead an unregister self from the ActiveDOMObject list, and
    144     // set m_scriptExecutionContext to 0 so that ~ActiveDOMObject() doesn't
    145     // try to do so again.
    146     m_scriptExecutionContext->willDestroyActiveDOMObject(this);
    147     m_scriptExecutionContext = 0;
     139    ActiveDOMObject::contextDestroyed();
    148140}
    149141
     
    167159#if PLATFORM(IOS)
    168160        MutexLocker lock(m_databaseThreadMutex);
    169 #endif //PLATFORM(IOS)
     161#endif
    170162        // It's OK to ask for the m_databaseThread after we've requested
    171163        // termination because we're still using it to execute the closing
     
    178170        m_databaseThread = DatabaseThread::create();
    179171        if (!m_databaseThread->start())
    180             m_databaseThread = 0;
     172            m_databaseThread = nullptr;
     173
    181174#if PLATFORM(IOS)
    182175        if (m_databaseThread)
    183176            m_databaseThread->setPaused(m_paused);
    184 #endif //PLATFORM(IOS)
     177#endif
    185178    }
    186179
     
    199192#endif // PLATFORM(IOS)
    200193
    201 bool DatabaseContext::stopDatabases(DatabaseTaskSynchronizer* cleanupSync)
     194bool DatabaseContext::stopDatabases(DatabaseTaskSynchronizer* synchronizer)
    202195{
    203196    if (m_isRegistered) {
     
    217210
    218211    if (m_databaseThread && !m_hasRequestedTermination) {
    219         m_databaseThread->requestTermination(cleanupSync);
     212        m_databaseThread->requestTermination(synchronizer);
    220213        m_hasRequestedTermination = true;
    221214        return true;
  • trunk/Source/WebCore/Modules/webdatabase/DatabaseContext.h

    r165676 r167579  
    3232
    3333#include "ActiveDOMObject.h"
    34 #include "DatabaseDetails.h"
    35 #include <wtf/Assertions.h>
     34#include <wtf/RefPtr.h>
    3635#include <wtf/ThreadSafeRefCounted.h>
    3736
    3837#if PLATFORM(IOS)
    3938#include <wtf/Threading.h>
    40 #endif // PLATFORM(IOS)
     39#endif
    4140
    4241namespace WebCore {
    4342
    4443class Database;
     44class DatabaseDetails;
    4545class DatabaseBackendContext;
    4646class DatabaseTaskSynchronizer;
    4747class DatabaseThread;
    48 class ScriptExecutionContext;
    4948
    50 class DatabaseContext : public ThreadSafeRefCounted<DatabaseContext>, ActiveDOMObject {
     49class DatabaseContext : public ThreadSafeRefCounted<DatabaseContext>, private ActiveDOMObject {
    5150public:
    5251    virtual ~DatabaseContext();
    5352
    54     // For life-cycle management (inherited from ActiveDOMObject):
    55     virtual void contextDestroyed();
    56     virtual void stop();
    57 
    5853    PassRefPtr<DatabaseBackendContext> backend();
    5954    DatabaseThread* databaseThread();
     55
    6056#if PLATFORM(IOS)
    6157    void setPaused(bool);
    62 #endif // PLATFORM(IOS)
     58#endif
    6359
    6460    void setHasOpenDatabases() { m_hasOpenDatabases = true; }
    6561    bool hasOpenDatabases() { return m_hasOpenDatabases; }
    6662
    67     // When the database cleanup is done, cleanupSync will be signalled.
     63    // When the database cleanup is done, the sychronizer will be signalled.
    6864    bool stopDatabases(DatabaseTaskSynchronizer*);
    6965
     
    7470    explicit DatabaseContext(ScriptExecutionContext*);
    7571
    76     void stopDatabases() { stopDatabases(0); }
     72    void stopDatabases() { stopDatabases(nullptr); }
     73
     74    virtual void contextDestroyed() override final;
     75    virtual void stop() override final;
    7776
    7877    RefPtr<DatabaseThread> m_databaseThread;
     
    8786    Mutex m_databaseThreadMutex;
    8887    bool m_paused;
    89 #endif // PLATFORM(IOS)
     88#endif
    9089};
    9190
  • trunk/Source/WebCore/dom/ActiveDOMObject.cpp

    r165676 r167579  
    3838    , m_pendingActivityCount(0)
    3939#if !ASSERT_DISABLED
    40     , m_suspendIfNeededCalled(false)
     40    , m_suspendIfNeededWasCalled(false)
    4141#endif
    4242{
     
    4545
    4646    ASSERT(m_scriptExecutionContext->isContextThread());
    47     m_scriptExecutionContext->didCreateActiveDOMObject(this);
     47    m_scriptExecutionContext->didCreateActiveDOMObject(*this);
    4848}
    4949
     
    5353        return;
    5454
    55     ASSERT(m_suspendIfNeededCalled);
     55    ASSERT(m_suspendIfNeededWasCalled);
    5656
    5757    // ActiveDOMObject may be inherited by a sub-class whose life-cycle
     
    6363    if (m_scriptExecutionContext) {
    6464        ASSERT(m_scriptExecutionContext->isContextThread());
    65         m_scriptExecutionContext->willDestroyActiveDOMObject(this);
     65        m_scriptExecutionContext->willDestroyActiveDOMObject(*this);
    6666    }
    6767}
     
    7070{
    7171#if !ASSERT_DISABLED
    72     ASSERT(!m_suspendIfNeededCalled);
    73     m_suspendIfNeededCalled = true;
     72    ASSERT(!m_suspendIfNeededWasCalled);
     73    m_suspendIfNeededWasCalled = true;
    7474#endif
    7575    if (!m_scriptExecutionContext)
    7676        return;
    7777
    78     m_scriptExecutionContext->suspendActiveDOMObjectIfNeeded(this);
     78    m_scriptExecutionContext->suspendActiveDOMObjectIfNeeded(*this);
    7979}
     80
     81#if !ASSERT_DISABLED
     82
     83void ActiveDOMObject::assertSuspendIfNeededWasCalled() const
     84{
     85    ASSERT(m_suspendIfNeededWasCalled);
     86}
     87
     88#endif
    8089
    8190bool ActiveDOMObject::hasPendingActivity() const
  • trunk/Source/WebCore/dom/ActiveDOMObject.h

    r165676 r167579  
    3838    explicit ActiveDOMObject(ScriptExecutionContext*);
    3939
    40     // suspendIfNeeded() should be called exactly once after object construction to synchronize
    41     // the suspend state with that in ScriptExecutionContext.
     40    // The suspendIfNeeded must be called exactly once after object construction to update
     41    // the suspended state to match that of the ScriptExecutionContext.
    4242    void suspendIfNeeded();
    43 #if !ASSERT_DISABLED
    44     bool suspendIfNeededCalled() const { return m_suspendIfNeededCalled; }
    45 #endif
     43    void assertSuspendIfNeededWasCalled() const;
    4644
    4745    virtual bool hasPendingActivity() const;
    4846
    49     // canSuspend() is used by the caller if there is a choice between suspending and stopping.
    50     // For example, a page won't be suspended and placed in the back/forward cache if it has
    51     // the objects that can not be suspended.
    52     // However, 'suspend' can be called even if canSuspend() would return 'false'. That
    53     // happens in step-by-step JS debugging for example - in this case it would be incorrect
    54     // to stop the object. Exact semantics of suspend is up to the object then.
     47    // The canSuspend function is used by the caller if there is a choice between suspending
     48    // and stopping. For example, a page won't be suspended and placed in the back/forward
     49    // cache if it contains any objects that cannot be suspended.
     50
     51    // However, the suspend function will sometimes be called even if canSuspend returns false.
     52    // That happens in step-by-step JS debugging for example - in this case it would be incorrect
     53    // to stop the object. Exact semantics of suspend is up to the object in cases like that.
     54
    5555    enum ReasonForSuspension {
    5656        JavaScriptDebuggerPaused,
     
    6060        DocumentWillBePaused
    6161    };
     62
     63    // These three functions must not have a side effect of creating or destroying
     64    // any ActiveDOMObject. That means they must not result in calls to arbitrary JavaScript.
    6265    virtual bool canSuspend() const;
    6366    virtual void suspend(ReasonForSuspension);
    6467    virtual void resume();
     68
     69    // This function must not have a side effect of creating an ActiveDOMObject.
     70    // That means it must not result in calls to arbitrary JavaScript.
     71    // It can, however, have a side effect of deleting an ActiveDOMObject.
    6572    virtual void stop();
    6673
     
    6976        ASSERT(thisObject == this);
    7077        thisObject->ref();
    71         m_pendingActivityCount++;
     78        ++m_pendingActivityCount;
    7279    }
    7380
     
    8592    unsigned m_pendingActivityCount;
    8693#if !ASSERT_DISABLED
    87     bool m_suspendIfNeededCalled;
     94    bool m_suspendIfNeededWasCalled;
    8895#endif
    8996};
     97
     98#if ASSERT_DISABLED
     99
     100inline void ActiveDOMObject::assertSuspendIfNeededWasCalled() const
     101{
     102}
     103
     104#endif
    90105
    91106} // namespace WebCore
  • trunk/Source/WebCore/dom/ContextDestructionObserver.cpp

    r165676 r167579  
    3333
    3434ContextDestructionObserver::ContextDestructionObserver(ScriptExecutionContext* scriptExecutionContext)
    35     : m_scriptExecutionContext(0)
     35    : m_scriptExecutionContext(nullptr)
    3636{
    3737    observeContext(scriptExecutionContext);
     
    4040ContextDestructionObserver::~ContextDestructionObserver()
    4141{
    42     observeContext(0);
     42    observeContext(nullptr);
    4343}
    4444
     
    4747    if (m_scriptExecutionContext) {
    4848        ASSERT(m_scriptExecutionContext->isContextThread());
    49         m_scriptExecutionContext->willDestroyDestructionObserver(this);
     49        m_scriptExecutionContext->willDestroyDestructionObserver(*this);
    5050    }
    5151
     
    5454    if (m_scriptExecutionContext) {
    5555        ASSERT(m_scriptExecutionContext->isContextThread());
    56         m_scriptExecutionContext->didCreateDestructionObserver(this);
     56        m_scriptExecutionContext->didCreateDestructionObserver(*this);
    5757    }
    5858}
     
    6060void ContextDestructionObserver::contextDestroyed()
    6161{
    62     m_scriptExecutionContext = 0;
     62    m_scriptExecutionContext = nullptr;
    6363}
    6464
  • trunk/Source/WebCore/dom/MessagePort.cpp

    r165676 r167579  
    4141    , m_scriptExecutionContext(&scriptExecutionContext)
    4242{
    43     m_scriptExecutionContext->createdMessagePort(this);
     43    m_scriptExecutionContext->createdMessagePort(*this);
    4444
    4545    // Don't need to call processMessagePortMessagesSoon() here, because the port will not be opened until start() is invoked.
     
    5050    close();
    5151    if (m_scriptExecutionContext)
    52         m_scriptExecutionContext->destroyedMessagePort(this);
     52        m_scriptExecutionContext->destroyedMessagePort(*this);
    5353}
    5454
     
    9090    m_entangledChannel->disentangle();
    9191
    92     // We can't receive any messages or generate any events, so remove ourselves from the list of active ports.
    93     ASSERT(m_scriptExecutionContext);
    94     m_scriptExecutionContext->destroyedMessagePort(this);
    95     m_scriptExecutionContext = 0;
     92    // We can't receive any messages or generate any events after this, so remove ourselves from the list of active ports.
     93    ASSERT(m_scriptExecutionContext);
     94    m_scriptExecutionContext->destroyedMessagePort(*this);
     95    m_scriptExecutionContext = nullptr;
    9696
    9797    return std::move(m_entangledChannel);
  • trunk/Source/WebCore/dom/ScriptExecutionContext.cpp

    r165710 r167579  
    9393
    9494ScriptExecutionContext::ScriptExecutionContext()
    95     : m_iteratingActiveDOMObjects(false)
    96     , m_inDestructor(false)
    97     , m_circularSequentialID(0)
     95    : m_circularSequentialID(0)
    9896    , m_inDispatchErrorEvent(false)
    9997    , m_activeDOMObjectsAreSuspended(false)
    10098    , m_reasonForSuspendingActiveDOMObjects(static_cast<ActiveDOMObject::ReasonForSuspension>(-1))
    10199    , m_activeDOMObjectsAreStopped(false)
    102 {
    103 }
     100    , m_activeDOMObjectAdditionForbidden(false)
     101#if !ASSERT_DISABLED
     102    , m_inScriptExecutionContextDestructor(false)
     103    , m_activeDOMObjectRemovalForbidden(false)
     104#endif
     105{
     106}
     107
     108// FIXME: We should make this a member function of HashSet.
     109template<typename T> inline T takeAny(HashSet<T>& set)
     110{
     111    ASSERT(!set.isEmpty());
     112    auto iterator = set.begin();
     113    T result = std::move(*iterator);
     114    set.remove(iterator);
     115    return result;
     116}
     117
     118#if ASSERT_DISABLED
     119
     120inline void ScriptExecutionContext::checkConsistency() const
     121{
     122}
     123
     124#else
     125
     126void ScriptExecutionContext::checkConsistency() const
     127{
     128    for (auto* messagePort : m_messagePorts)
     129        ASSERT(messagePort->scriptExecutionContext() == this);
     130
     131    for (auto* destructionObserver : m_destructionObservers)
     132        ASSERT(destructionObserver->scriptExecutionContext() == this);
     133
     134    for (auto* activeDOMObject : m_activeDOMObjects) {
     135        ASSERT(activeDOMObject->scriptExecutionContext() == this);
     136        activeDOMObject->assertSuspendIfNeededWasCalled();
     137    }
     138}
     139
     140#endif
    104141
    105142ScriptExecutionContext::~ScriptExecutionContext()
    106143{
    107     m_inDestructor = true;
    108     for (HashSet<ContextDestructionObserver*>::iterator iter = m_destructionObservers.begin(); iter != m_destructionObservers.end(); iter = m_destructionObservers.begin()) {
    109         ContextDestructionObserver* observer = *iter;
    110         m_destructionObservers.remove(observer);
    111         ASSERT(observer->scriptExecutionContext() == this);
    112         observer->contextDestroyed();
    113     }
    114 
    115     HashSet<MessagePort*>::iterator messagePortsEnd = m_messagePorts.end();
    116     for (HashSet<MessagePort*>::iterator iter = m_messagePorts.begin(); iter != messagePortsEnd; ++iter) {
    117         ASSERT((*iter)->scriptExecutionContext() == this);
    118         (*iter)->contextDestroyed();
    119     }
     144    checkConsistency();
     145
     146#if !ASSERT_DISABLED
     147    m_inScriptExecutionContextDestructor = true;
     148#endif
     149
     150    while (!m_destructionObservers.isEmpty())
     151        takeAny(m_destructionObservers)->contextDestroyed();
     152
     153    for (auto* messagePort : m_messagePorts)
     154        messagePort->contextDestroyed();
     155
     156#if !ASSERT_DISABLED
     157    m_inScriptExecutionContextDestructor = false;
     158#endif
    120159}
    121160
     
    127166void ScriptExecutionContext::dispatchMessagePortEvents()
    128167{
     168    checkConsistency();
     169
    129170    Ref<ScriptExecutionContext> protect(*this);
    130171
    131     // Make a frozen copy.
    132     Vector<MessagePort*> ports;
    133     copyToVector(m_messagePorts, ports);
    134 
    135     unsigned portCount = ports.size();
    136     for (unsigned i = 0; i < portCount; ++i) {
    137         MessagePort* port = ports[i];
    138         // The port may be destroyed, and another one created at the same address, but this is safe, as the worst that can happen
    139         // as a result is that dispatchMessages() will be called needlessly.
    140         if (m_messagePorts.contains(port) && port->started())
    141             port->dispatchMessages();
    142     }
    143 }
    144 
    145 void ScriptExecutionContext::createdMessagePort(MessagePort* port)
    146 {
    147     ASSERT(port);
     172    // Make a frozen copy of the ports so we can iterate while new ones might be added or destroyed.
     173    Vector<MessagePort*> possibleMessagePorts;
     174    copyToVector(m_messagePorts, possibleMessagePorts);
     175    for (auto* messagePort : possibleMessagePorts) {
     176        // The port may be destroyed, and another one created at the same address,
     177        // but this is harmless. The worst that can happen as a result is that
     178        // dispatchMessages() will be called needlessly.
     179        if (m_messagePorts.contains(messagePort) && messagePort->started())
     180            messagePort->dispatchMessages();
     181    }
     182}
     183
     184void ScriptExecutionContext::createdMessagePort(MessagePort& messagePort)
     185{
    148186    ASSERT((isDocument() && isMainThread())
    149187        || (isWorkerGlobalScope() && currentThread() == toWorkerGlobalScope(this)->thread().threadID()));
    150188
    151     m_messagePorts.add(port);
    152 }
    153 
    154 void ScriptExecutionContext::destroyedMessagePort(MessagePort* port)
    155 {
    156     ASSERT(port);
     189    m_messagePorts.add(&messagePort);
     190}
     191
     192void ScriptExecutionContext::destroyedMessagePort(MessagePort& messagePort)
     193{
    157194    ASSERT((isDocument() && isMainThread())
    158195        || (isWorkerGlobalScope() && currentThread() == toWorkerGlobalScope(this)->thread().threadID()));
    159196
    160     m_messagePorts.remove(port);
     197    m_messagePorts.remove(&messagePort);
    161198}
    162199
    163200bool ScriptExecutionContext::canSuspendActiveDOMObjects()
    164201{
    165     // No protection against m_activeDOMObjects changing during iteration: canSuspend() shouldn't execute arbitrary JS.
    166     m_iteratingActiveDOMObjects = true;
    167     ActiveDOMObjectsSet::iterator activeObjectsEnd = m_activeDOMObjects.end();
    168     for (ActiveDOMObjectsSet::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
    169         ASSERT((*iter)->scriptExecutionContext() == this);
    170         ASSERT((*iter)->suspendIfNeededCalled());
    171         if (!(*iter)->canSuspend()) {
    172             m_iteratingActiveDOMObjects = false;
    173             return false;
     202    checkConsistency();
     203
     204    bool canSuspend = true;
     205
     206    m_activeDOMObjectAdditionForbidden = true;
     207#if !ASSERT_DISABLED
     208    m_activeDOMObjectRemovalForbidden = true;
     209#endif
     210
     211    // We assume that m_activeDOMObjects will not change during iteration: canSuspend
     212    // functions should not add new active DOM objects, nor execute arbitrary JavaScript.
     213    // An ASSERT or RELEASE_ASSERT will fire if this happens, but it's important to code
     214    // canSuspend functions so it will not happen!
     215    for (auto* activeDOMObject : m_activeDOMObjects) {
     216        if (!activeDOMObject->canSuspend()) {
     217            canSuspend = false;
     218            break;
    174219        }
    175220    }
    176     m_iteratingActiveDOMObjects = false;
    177     return true;
     221
     222    m_activeDOMObjectAdditionForbidden = false;
     223#if !ASSERT_DISABLED
     224    m_activeDOMObjectRemovalForbidden = false;
     225#endif
     226
     227    return canSuspend;
    178228}
    179229
    180230void ScriptExecutionContext::suspendActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why)
    181231{
     232    checkConsistency();
     233
    182234#if PLATFORM(IOS)
    183235    if (m_activeDOMObjectsAreSuspended) {
     
    187239#endif
    188240
    189     // No protection against m_activeDOMObjects changing during iteration: suspend() shouldn't execute arbitrary JS.
    190     m_iteratingActiveDOMObjects = true;
    191     ActiveDOMObjectsSet::iterator activeObjectsEnd = m_activeDOMObjects.end();
    192     for (ActiveDOMObjectsSet::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
    193         ASSERT((*iter)->scriptExecutionContext() == this);
    194         ASSERT((*iter)->suspendIfNeededCalled());
    195         (*iter)->suspend(why);
    196     }
    197     m_iteratingActiveDOMObjects = false;
     241    m_activeDOMObjectAdditionForbidden = true;
     242#if !ASSERT_DISABLED
     243    m_activeDOMObjectRemovalForbidden = true;
     244#endif
     245
     246    // We assume that m_activeDOMObjects will not change during iteration: suspend
     247    // functions should not add new active DOM objects, nor execute arbitrary JavaScript.
     248    // An ASSERT or RELEASE_ASSERT will fire if this happens, but it's important to code
     249    // suspend functions so it will not happen!
     250    for (auto* activeDOMObject : m_activeDOMObjects)
     251        activeDOMObject->suspend(why);
     252
     253    m_activeDOMObjectAdditionForbidden = false;
     254#if !ASSERT_DISABLED
     255    m_activeDOMObjectRemovalForbidden = false;
     256#endif
     257
    198258    m_activeDOMObjectsAreSuspended = true;
    199259    m_reasonForSuspendingActiveDOMObjects = why;
     
    202262void ScriptExecutionContext::resumeActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why)
    203263{
     264    checkConsistency();
     265
    204266    if (m_reasonForSuspendingActiveDOMObjects != why)
    205267        return;
    206 
    207268    m_activeDOMObjectsAreSuspended = false;
    208     // No protection against m_activeDOMObjects changing during iteration: resume() shouldn't execute arbitrary JS.
    209     m_iteratingActiveDOMObjects = true;
    210     ActiveDOMObjectsSet::iterator activeObjectsEnd = m_activeDOMObjects.end();
    211     for (ActiveDOMObjectsSet::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
    212         ASSERT((*iter)->scriptExecutionContext() == this);
    213         ASSERT((*iter)->suspendIfNeededCalled());
    214         (*iter)->resume();
    215     }
    216     m_iteratingActiveDOMObjects = false;
     269
     270    m_activeDOMObjectAdditionForbidden = true;
     271#if !ASSERT_DISABLED
     272    m_activeDOMObjectRemovalForbidden = true;
     273#endif
     274
     275    // We assume that m_activeDOMObjects will not change during iteration: resume
     276    // functions should not add new active DOM objects, nor execute arbitrary JavaScript.
     277    // An ASSERT or RELEASE_ASSERT will fire if this happens, but it's important to code
     278    // resume functions so it will not happen!
     279    for (auto* activeDOMObject : m_activeDOMObjects)
     280        activeDOMObject->resume();
     281
     282    m_activeDOMObjectAdditionForbidden = false;
     283#if !ASSERT_DISABLED
     284    m_activeDOMObjectRemovalForbidden = false;
     285#endif
    217286}
    218287
    219288void ScriptExecutionContext::stopActiveDOMObjects()
    220289{
     290    checkConsistency();
     291
    221292    if (m_activeDOMObjectsAreStopped)
    222293        return;
    223294    m_activeDOMObjectsAreStopped = true;
    224     // No protection against m_activeDOMObjects changing during iteration: stop() shouldn't execute arbitrary JS.
    225     m_iteratingActiveDOMObjects = true;
    226     ActiveDOMObjectsSet::iterator activeObjectsEnd = m_activeDOMObjects.end();
    227     for (ActiveDOMObjectsSet::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
    228         ASSERT((*iter)->scriptExecutionContext() == this);
    229         ASSERT((*iter)->suspendIfNeededCalled());
    230         (*iter)->stop();
    231     }
    232     m_iteratingActiveDOMObjects = false;
    233 
    234     // Also close MessagePorts. If they were ActiveDOMObjects (they could be) then they could be stopped instead.
    235     closeMessagePorts();
    236 }
    237 
    238 void ScriptExecutionContext::suspendActiveDOMObjectIfNeeded(ActiveDOMObject* object)
    239 {
    240     ASSERT(m_activeDOMObjects.contains(object));
    241     // Ensure all ActiveDOMObjects are suspended also newly created ones.
     295
     296    // Make a frozen copy of the objects so we can iterate while new ones might be destroyed.
     297    Vector<ActiveDOMObject*> possibleActiveDOMObjects;
     298    copyToVector(m_activeDOMObjects, possibleActiveDOMObjects);
     299
     300    m_activeDOMObjectAdditionForbidden = true;
     301
     302    // We assume that new objects will not be added to m_activeDOMObjects during iteration:
     303    // stop functions should not add new active DOM objects, nor execute arbitrary JavaScript.
     304    // A RELEASE_ASSERT will fire if this happens, but it's important to code stop functions
     305    // so it will not happen!
     306    for (auto* activeDOMObject : possibleActiveDOMObjects) {
     307        // Check if this object was deleted already. If so, just skip it.
     308        // Calling contains on a possibly-already-deleted object is OK because we guarantee
     309        // no new object can be added, so even if a new object ends up allocated with the
     310        // same address, that will be *after* this function exits.
     311        if (!m_activeDOMObjects.contains(activeDOMObject))
     312            continue;
     313        activeDOMObject->stop();
     314    }
     315
     316    m_activeDOMObjectAdditionForbidden = false;
     317
     318    // FIXME: Make message ports be active DOM objects and let them implement stop instead
     319    // of having this separate mechanism just for them.
     320    for (auto* messagePort : m_messagePorts)
     321        messagePort->close();
     322}
     323
     324void ScriptExecutionContext::suspendActiveDOMObjectIfNeeded(ActiveDOMObject& activeDOMObject)
     325{
     326    ASSERT(m_activeDOMObjects.contains(&activeDOMObject));
    242327    if (m_activeDOMObjectsAreSuspended)
    243         object->suspend(m_reasonForSuspendingActiveDOMObjects);
     328        activeDOMObject.suspend(m_reasonForSuspendingActiveDOMObjects);
    244329    if (m_activeDOMObjectsAreStopped)
    245         object->stop();
    246 }
    247 
    248 void ScriptExecutionContext::didCreateActiveDOMObject(ActiveDOMObject* object)
    249 {
    250     ASSERT(object);
    251     ASSERT(!m_inDestructor);
    252     if (m_iteratingActiveDOMObjects)
    253         CRASH();
    254     m_activeDOMObjects.add(object);
    255 }
    256 
    257 void ScriptExecutionContext::willDestroyActiveDOMObject(ActiveDOMObject* object)
    258 {
    259     ASSERT(object);
    260     if (m_iteratingActiveDOMObjects)
    261         CRASH();
    262     m_activeDOMObjects.remove(object);
    263 }
    264 
    265 void ScriptExecutionContext::didCreateDestructionObserver(ContextDestructionObserver* observer)
    266 {
    267     ASSERT(observer);
    268     ASSERT(!m_inDestructor);
    269     m_destructionObservers.add(observer);
    270 }
    271 
    272 void ScriptExecutionContext::willDestroyDestructionObserver(ContextDestructionObserver* observer)
    273 {
    274     ASSERT(observer);
    275     m_destructionObservers.remove(observer);
    276 }
    277 
    278 void ScriptExecutionContext::closeMessagePorts() {
    279     HashSet<MessagePort*>::iterator messagePortsEnd = m_messagePorts.end();
    280     for (HashSet<MessagePort*>::iterator iter = m_messagePorts.begin(); iter != messagePortsEnd; ++iter) {
    281         ASSERT((*iter)->scriptExecutionContext() == this);
    282         (*iter)->close();
    283     }
     330        activeDOMObject.stop();
     331}
     332
     333void ScriptExecutionContext::didCreateActiveDOMObject(ActiveDOMObject& activeDOMObject)
     334{
     335    // The m_activeDOMObjectAdditionForbidden check is a RELEASE_ASSERT because of the
     336    // consequences of having an ActiveDOMObject that is not correctly reflected in the set.
     337    // If we do have one of those, it can possibly be a security vulnerability. So we'd
     338    // rather have a crash than continue running with the set possibly compromised.
     339    ASSERT(!m_inScriptExecutionContextDestructor);
     340    RELEASE_ASSERT(!m_activeDOMObjectAdditionForbidden);
     341    m_activeDOMObjects.add(&activeDOMObject);
     342}
     343
     344void ScriptExecutionContext::willDestroyActiveDOMObject(ActiveDOMObject& activeDOMObject)
     345{
     346    ASSERT(!m_activeDOMObjectRemovalForbidden);
     347    m_activeDOMObjects.remove(&activeDOMObject);
     348}
     349
     350void ScriptExecutionContext::didCreateDestructionObserver(ContextDestructionObserver& observer)
     351{
     352    ASSERT(!m_inScriptExecutionContextDestructor);
     353    m_destructionObservers.add(&observer);
     354}
     355
     356void ScriptExecutionContext::willDestroyDestructionObserver(ContextDestructionObserver& observer)
     357{
     358    m_destructionObservers.remove(&observer);
    284359}
    285360
     
    370445{
    371446    if (minimumTimerInterval() != oldMinimumTimerInterval) {
    372         for (TimeoutMap::iterator iter = m_timeouts.begin(); iter != m_timeouts.end(); ++iter) {
    373             DOMTimer* timer = iter->value;
     447        for (auto* timer : m_timeouts.values())
    374448            timer->adjustMinimumTimerInterval(oldMinimumTimerInterval);
    375         }
    376449    }
    377450}
     
    389462void ScriptExecutionContext::didChangeTimerAlignmentInterval()
    390463{
    391     for (TimeoutMap::iterator iter = m_timeouts.begin(); iter != m_timeouts.end(); ++iter) {
    392         DOMTimer* timer = iter->value;
     464    for (auto* timer : m_timeouts.values())
    393465        timer->didChangeAlignmentInterval();
    394     }
    395466}
    396467
     
    420491#endif
    421492
     493bool ScriptExecutionContext::hasPendingActivity() const
     494{
     495    checkConsistency();
     496
     497    for (auto* activeDOMObject : m_activeDOMObjects) {
     498        if (activeDOMObject->hasPendingActivity())
     499            return true;
     500    }
     501
     502    for (auto* messagePort : m_messagePorts) {
     503        if (messagePort->hasPendingActivity())
     504            return true;
     505    }
     506
     507    return false;
     508}
     509
    422510} // namespace WebCore
  • trunk/Source/WebCore/dom/ScriptExecutionContext.h

    r165710 r167579  
    3232#include "SecurityContext.h"
    3333#include "Supplementable.h"
    34 #include "URL.h"
    3534#include <runtime/ConsoleTypes.h>
    3635#include <wtf/HashSet.h>
     
    5049class DatabaseContext;
    5150class DOMTimer;
    52 class EventListener;
    5351class EventQueue;
    5452class EventTarget;
    5553class MessagePort;
    56 
    57 #if ENABLE(BLOB)
    5854class PublicURLManager;
    59 #endif
     55class URL;
    6056
    6157class ScriptExecutionContext : public SecurityContext, public Supplementable<ScriptExecutionContext> {
     
    7773    virtual void disableEval(const String& errorMessage) = 0;
    7874
    79     bool sanitizeScriptError(String& errorMessage, int& lineNumber, int& columnNumber, String& sourceURL, CachedScript* = 0);
    80     // FIXME: <http://webkit.org/b/114315> ScriptExecutionContext log exception should include a column number
    81     void reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, PassRefPtr<Inspector::ScriptCallStack>, CachedScript* = 0);
    82 
    83     void addConsoleMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, JSC::ExecState* = 0, unsigned long requestIdentifier = 0);
     75    bool sanitizeScriptError(String& errorMessage, int& lineNumber, int& columnNumber, String& sourceURL, CachedScript* = nullptr);
     76    void reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, PassRefPtr<Inspector::ScriptCallStack>, CachedScript* = nullptr);
     77
     78    void addConsoleMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, JSC::ExecState* = nullptr, unsigned long requestIdentifier = 0);
    8479    virtual void addConsoleMessage(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier = 0) = 0;
    8580
     
    10297
    10398    // Called from the constructor and destructors of ActiveDOMObject.
    104     void didCreateActiveDOMObject(ActiveDOMObject*);
    105     void willDestroyActiveDOMObject(ActiveDOMObject*);
     99    void didCreateActiveDOMObject(ActiveDOMObject&);
     100    void willDestroyActiveDOMObject(ActiveDOMObject&);
    106101
    107102    // Called after the construction of an ActiveDOMObject to synchronize suspend state.
    108     void suspendActiveDOMObjectIfNeeded(ActiveDOMObject*);
    109 
    110     typedef HashSet<ActiveDOMObject*> ActiveDOMObjectsSet;
    111     const ActiveDOMObjectsSet& activeDOMObjects() const { return m_activeDOMObjects; }
    112 
    113     void didCreateDestructionObserver(ContextDestructionObserver*);
    114     void willDestroyDestructionObserver(ContextDestructionObserver*);
     103    void suspendActiveDOMObjectIfNeeded(ActiveDOMObject&);
     104
     105    void didCreateDestructionObserver(ContextDestructionObserver&);
     106    void willDestroyDestructionObserver(ContextDestructionObserver&);
    115107
    116108    // MessagePort is conceptually a kind of ActiveDOMObject, but it needs to be tracked separately for message dispatch.
    117109    void processMessagePortMessagesSoon();
    118110    void dispatchMessagePortEvents();
    119     void createdMessagePort(MessagePort*);
    120     void destroyedMessagePort(MessagePort*);
    121     const HashSet<MessagePort*>& messagePorts() const { return m_messagePorts; }
     111    void createdMessagePort(MessagePort&);
     112    void destroyedMessagePort(MessagePort&);
    122113
    123114    void ref() { refScriptExecutionContext(); }
     
    186177    ActiveDOMObject::ReasonForSuspension reasonForSuspendingActiveDOMObjects() const { return m_reasonForSuspendingActiveDOMObjects; }
    187178
     179    bool hasPendingActivity() const;
     180
    188181private:
    189     virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, PassRefPtr<Inspector::ScriptCallStack>, JSC::ExecState* = 0, unsigned long requestIdentifier = 0) = 0;
     182    virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, PassRefPtr<Inspector::ScriptCallStack>, JSC::ExecState* = nullptr, unsigned long requestIdentifier = 0) = 0;
    190183    virtual EventTarget* errorEventTarget() = 0;
    191184    virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<Inspector::ScriptCallStack>) = 0;
    192185    bool dispatchErrorEvent(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, CachedScript*);
    193186
    194     void closeMessagePorts();
    195 
    196187    virtual void refScriptExecutionContext() = 0;
    197188    virtual void derefScriptExecutionContext() = 0;
    198189
     190    void checkConsistency() const;
     191
    199192    HashSet<MessagePort*> m_messagePorts;
    200193    HashSet<ContextDestructionObserver*> m_destructionObservers;
    201     ActiveDOMObjectsSet m_activeDOMObjects;
    202     bool m_iteratingActiveDOMObjects;
    203     bool m_inDestructor;
     194    HashSet<ActiveDOMObject*> m_activeDOMObjects;
    204195
    205196    int m_circularSequentialID;
    206     typedef HashMap<int, DOMTimer*> TimeoutMap;
    207     TimeoutMap m_timeouts;
     197    HashMap<int, DOMTimer*> m_timeouts;
    208198
    209199    bool m_inDispatchErrorEvent;
     
    222212    RefPtr<DatabaseContext> m_databaseContext;
    223213#endif
     214
     215    bool m_activeDOMObjectAdditionForbidden;
     216
     217#if !ASSERT_DISABLED
     218    bool m_inScriptExecutionContextDestructor;
     219    bool m_activeDOMObjectRemovalForbidden;
     220#endif
    224221};
    225222
  • trunk/Source/WebCore/workers/WorkerGlobalScope.cpp

    r165676 r167579  
    160160}
    161161
    162 bool WorkerGlobalScope::hasPendingActivity() const
    163 {
    164     ActiveDOMObjectsSet::const_iterator activeObjectsEnd = activeDOMObjects().end();
    165     for (ActiveDOMObjectsSet::const_iterator iter = activeDOMObjects().begin(); iter != activeObjectsEnd; ++iter) {
    166         if ((*iter)->hasPendingActivity())
    167             return true;
    168     }
    169 
    170     HashSet<MessagePort*>::const_iterator messagePortsEnd = messagePorts().end();
    171     for (HashSet<MessagePort*>::const_iterator iter = messagePorts().begin(); iter != messagePortsEnd; ++iter) {
    172         if ((*iter)->hasPendingActivity())
    173             return true;
    174     }
    175 
    176     return false;
    177 }
    178 
    179162void WorkerGlobalScope::postTask(PassOwnPtr<Task> task)
    180163{
  • trunk/Source/WebCore/workers/WorkerGlobalScope.h

    r165676 r167579  
    7777        WorkerThread& thread() const { return m_thread; }
    7878
    79         bool hasPendingActivity() const;
     79        using ScriptExecutionContext::hasPendingActivity;
    8080
    8181        virtual void postTask(PassOwnPtr<Task>) override; // Executes the task on context's thread asynchronously.
Note: See TracChangeset for help on using the changeset viewer.