1/*
2 * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "JSPromiseDeferred.h"
28
29#include "BuiltinNames.h"
30#include "Error.h"
31#include "Exception.h"
32#include "JSCInlines.h"
33#include "JSObjectInlines.h"
34#include "JSPromise.h"
35#include "JSPromiseConstructor.h"
36#include "PromiseDeferredTimer.h"
37
38namespace JSC {
39
40const ClassInfo JSPromiseDeferred::s_info = { "JSPromiseDeferred", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSPromiseDeferred) };
41
42JSPromiseDeferred::DeferredData JSPromiseDeferred::createDeferredData(ExecState* exec, JSGlobalObject* globalObject, JSPromiseConstructor* promiseConstructor)
43{
44 VM& vm = exec->vm();
45 auto scope = DECLARE_THROW_SCOPE(vm);
46
47 JSFunction* newPromiseCapabilityFunction = globalObject->newPromiseCapabilityFunction();
48 CallData callData;
49 CallType callType = JSC::getCallData(exec->vm(), newPromiseCapabilityFunction, callData);
50 ASSERT(callType != CallType::None);
51
52 MarkedArgumentBuffer arguments;
53 arguments.append(promiseConstructor);
54 ASSERT(!arguments.hasOverflowed());
55 JSValue deferred = call(exec, newPromiseCapabilityFunction, callType, callData, jsUndefined(), arguments);
56 RETURN_IF_EXCEPTION(scope, { });
57
58 DeferredData result;
59 result.promise = jsCast<JSPromise*>(deferred.get(exec, vm.propertyNames->builtinNames().promisePrivateName()));
60 RETURN_IF_EXCEPTION(scope, { });
61 result.resolve = jsCast<JSFunction*>(deferred.get(exec, vm.propertyNames->builtinNames().resolvePrivateName()));
62 RETURN_IF_EXCEPTION(scope, { });
63 result.reject = jsCast<JSFunction*>(deferred.get(exec, vm.propertyNames->builtinNames().rejectPrivateName()));
64 RETURN_IF_EXCEPTION(scope, { });
65
66 return result;
67}
68
69JSPromiseDeferred* JSPromiseDeferred::tryCreate(ExecState* exec, JSGlobalObject* globalObject)
70{
71 VM& vm = exec->vm();
72 auto scope = DECLARE_THROW_SCOPE(vm);
73
74 DeferredData data = createDeferredData(exec, globalObject, globalObject->promiseConstructor());
75 RETURN_IF_EXCEPTION(scope, { });
76 return JSPromiseDeferred::create(vm, data.promise, data.resolve, data.reject);
77}
78
79JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSPromise* promise, JSFunction* resolve, JSFunction* reject)
80{
81 JSPromiseDeferred* deferred = new (NotNull, allocateCell<JSPromiseDeferred>(vm.heap)) JSPromiseDeferred(vm);
82 deferred->finishCreation(vm, promise, resolve, reject);
83 return deferred;
84}
85
86JSPromiseDeferred::JSPromiseDeferred(VM& vm)
87 : JSPromiseDeferred(vm, vm.promiseDeferredStructure.get())
88{
89}
90
91JSPromiseDeferred::JSPromiseDeferred(VM& vm, Structure* structure)
92 : Base(vm, structure)
93{
94}
95
96static inline void callFunction(ExecState* exec, JSValue function, JSValue value)
97{
98 CallData callData;
99 CallType callType = getCallData(exec->vm(), function, callData);
100 ASSERT(callType != CallType::None);
101
102 MarkedArgumentBuffer arguments;
103 arguments.append(value);
104 ASSERT(!arguments.hasOverflowed());
105
106 call(exec, function, callType, callData, jsUndefined(), arguments);
107}
108
109void JSPromiseDeferred::resolve(ExecState* exec, JSValue value)
110{
111 callFunction(exec, m_resolve.get(), value);
112 bool wasPending = exec->vm().promiseDeferredTimer->cancelPendingPromise(this);
113 ASSERT_UNUSED(wasPending, wasPending == m_promiseIsAsyncPending);
114}
115
116void JSPromiseDeferred::reject(ExecState* exec, JSValue reason)
117{
118 callFunction(exec, m_reject.get(), reason);
119 bool wasPending = exec->vm().promiseDeferredTimer->cancelPendingPromise(this);
120 ASSERT_UNUSED(wasPending, wasPending == m_promiseIsAsyncPending);
121}
122
123void JSPromiseDeferred::reject(ExecState* exec, Exception* reason)
124{
125 reject(exec, reason->value());
126}
127
128void JSPromiseDeferred::finishCreation(VM& vm, JSPromise* promise, JSFunction* resolve, JSFunction* reject)
129{
130 Base::finishCreation(vm);
131 m_promise.set(vm, this, promise);
132 m_resolve.set(vm, this, resolve);
133 m_reject.set(vm, this, reject);
134}
135
136void JSPromiseDeferred::visitChildren(JSCell* cell, SlotVisitor& visitor)
137{
138 JSPromiseDeferred* thisObject = jsCast<JSPromiseDeferred*>(cell);
139 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
140
141 Base::visitChildren(thisObject, visitor);
142
143 visitor.append(thisObject->m_promise);
144 visitor.append(thisObject->m_resolve);
145 visitor.append(thisObject->m_reject);
146}
147
148} // namespace JSC
149