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