Home | History | Annotate | Download | only in v8
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "config.h"
      6 #include "bindings/v8/ScriptPromiseResolverWithContext.h"
      7 
      8 #include "bindings/v8/V8RecursionScope.h"
      9 
     10 namespace WebCore {
     11 
     12 ScriptPromiseResolverWithContext::ScriptPromiseResolverWithContext(ScriptState* scriptState)
     13     : ActiveDOMObject(scriptState->executionContext())
     14     , m_state(Pending)
     15     , m_scriptState(scriptState)
     16     , m_mode(Default)
     17     , m_timer(this, &ScriptPromiseResolverWithContext::onTimerFired)
     18     , m_resolver(ScriptPromiseResolver::create(m_scriptState.get()))
     19 #if ASSERTION_ENABLED
     20     , m_isPromiseCalled(false)
     21 #endif
     22 {
     23     if (executionContext()->activeDOMObjectsAreStopped())
     24         m_state = ResolvedOrRejected;
     25 }
     26 
     27 void ScriptPromiseResolverWithContext::suspend()
     28 {
     29     m_timer.stop();
     30 }
     31 
     32 void ScriptPromiseResolverWithContext::resume()
     33 {
     34     if (m_state == Resolving || m_state == Rejecting)
     35         m_timer.startOneShot(0, FROM_HERE);
     36 }
     37 
     38 void ScriptPromiseResolverWithContext::stop()
     39 {
     40     m_timer.stop();
     41     clear();
     42 }
     43 
     44 void ScriptPromiseResolverWithContext::keepAliveWhilePending()
     45 {
     46     if (m_state == ResolvedOrRejected || m_mode == KeepAliveWhilePending)
     47         return;
     48 
     49     // Keep |this| while the promise is Pending.
     50     // deref() will be called in clear().
     51     m_mode = KeepAliveWhilePending;
     52     ref();
     53 }
     54 
     55 void ScriptPromiseResolverWithContext::onTimerFired(Timer<ScriptPromiseResolverWithContext>*)
     56 {
     57     ScriptState::Scope scope(m_scriptState.get());
     58     resolveOrRejectImmediately();
     59 }
     60 
     61 void ScriptPromiseResolverWithContext::resolveOrRejectImmediately()
     62 {
     63     ASSERT(!executionContext()->activeDOMObjectsAreStopped());
     64     ASSERT(!executionContext()->activeDOMObjectsAreSuspended());
     65     {
     66         // FIXME: The V8RecursionScope is only necessary to force microtask delivery for promises
     67         // resolved or rejected in workers. It can be removed once worker threads run microtasks
     68         // at the end of every task (rather than just the main thread).
     69         V8RecursionScope scope(m_scriptState->isolate(), m_scriptState->executionContext());
     70         if (m_state == Resolving) {
     71             m_resolver->resolve(m_value.newLocal(m_scriptState->isolate()));
     72         } else {
     73             ASSERT(m_state == Rejecting);
     74             m_resolver->reject(m_value.newLocal(m_scriptState->isolate()));
     75         }
     76     }
     77     clear();
     78 }
     79 
     80 void ScriptPromiseResolverWithContext::clear()
     81 {
     82     if (m_state == ResolvedOrRejected)
     83         return;
     84     ResolutionState state = m_state;
     85     m_state = ResolvedOrRejected;
     86     m_resolver.clear();
     87     m_value.clear();
     88     if (m_mode == KeepAliveWhilePending) {
     89         // |ref| was called in |keepAliveWhilePending|.
     90         deref();
     91     }
     92     // |this| may be deleted here, but it is safe to check |state| because
     93     // it doesn't depend on |this|. When |this| is deleted, |state| can't be
     94     // |Resolving| nor |Rejecting| and hence |this->deref()| can't be executed.
     95     if (state == Resolving || state == Rejecting) {
     96         // |ref| was called in |resolveOrReject|.
     97         deref();
     98     }
     99 }
    100 
    101 } // namespace WebCore
    102