• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ScriptPromiseResolverWithContext(ScriptState * scriptState)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 
suspend()27 void ScriptPromiseResolverWithContext::suspend()
28 {
29     m_timer.stop();
30 }
31 
resume()32 void ScriptPromiseResolverWithContext::resume()
33 {
34     if (m_state == Resolving || m_state == Rejecting)
35         m_timer.startOneShot(0, FROM_HERE);
36 }
37 
stop()38 void ScriptPromiseResolverWithContext::stop()
39 {
40     m_timer.stop();
41     clear();
42 }
43 
keepAliveWhilePending()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 
onTimerFired(Timer<ScriptPromiseResolverWithContext> *)55 void ScriptPromiseResolverWithContext::onTimerFired(Timer<ScriptPromiseResolverWithContext>*)
56 {
57     ScriptState::Scope scope(m_scriptState.get());
58     resolveOrRejectImmediately();
59 }
60 
resolveOrRejectImmediately()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 
clear()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