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