3e6999fb330a37a7237e127472524dd2570e1ae7
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSPromise.cpp
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 "JSPromise.h"
28
29 #include "BuiltinNames.h"
30 #include "Error.h"
31 #include "JSCInlines.h"
32 #include "JSInternalFieldObjectImplInlines.h"
33 #include "JSPromiseConstructor.h"
34 #include "Microtask.h"
35 #include "PromiseTimer.h"
36
37 namespace JSC {
38
39 const ClassInfo JSPromise::s_info = { "Promise", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSPromise) };
40
41 JSPromise* JSPromise::create(VM& vm, Structure* structure)
42 {
43     JSPromise* promise = new (NotNull, allocateCell<JSPromise>(vm.heap)) JSPromise(vm, structure);
44     promise->finishCreation(vm);
45     return promise;
46 }
47
48 Structure* JSPromise::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
49 {
50     return Structure::create(vm, globalObject, prototype, TypeInfo(JSPromiseType, StructureFlags), info());
51 }
52
53 JSPromise::JSPromise(VM& vm, Structure* structure)
54     : Base(vm, structure)
55 {
56 }
57
58 void JSPromise::finishCreation(VM& vm)
59 {
60     Base::finishCreation(vm);
61     internalField(static_cast<unsigned>(Field::Flags)).set(vm, this, jsNumber(static_cast<unsigned>(Status::Pending)));
62     internalField(static_cast<unsigned>(Field::ReactionsOrResult)).set(vm, this, jsUndefined());
63 }
64
65 void JSPromise::visitChildren(JSCell* cell, SlotVisitor& visitor)
66 {
67     auto* thisObject = jsCast<JSPromise*>(cell);
68     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
69     Base::visitChildren(thisObject, visitor);
70 }
71
72 auto JSPromise::status(VM&) const -> Status
73 {
74     JSValue value = internalField(static_cast<unsigned>(Field::Flags)).get();
75     uint32_t flags = value.asUInt32AsAnyInt();
76     return static_cast<Status>(flags & stateMask);
77 }
78
79 JSValue JSPromise::result(VM& vm) const
80 {
81     Status status = this->status(vm);
82     if (status == Status::Pending)
83         return jsUndefined();
84     return internalField(static_cast<unsigned>(Field::ReactionsOrResult)).get();
85 }
86
87 uint32_t JSPromise::flags() const
88 {
89     JSValue value = internalField(static_cast<unsigned>(Field::Flags)).get();
90     return value.asUInt32AsAnyInt();
91 }
92
93 bool JSPromise::isHandled(VM&) const
94 {
95     return flags() & isHandledFlag;
96 }
97
98 JSPromise::DeferredData JSPromise::createDeferredData(JSGlobalObject* globalObject, JSPromiseConstructor* promiseConstructor)
99 {
100     VM& vm = globalObject->vm();
101     auto scope = DECLARE_THROW_SCOPE(vm);
102
103     JSFunction* newPromiseCapabilityFunction = globalObject->newPromiseCapabilityFunction();
104     CallData callData;
105     CallType callType = JSC::getCallData(globalObject->vm(), newPromiseCapabilityFunction, callData);
106     ASSERT(callType != CallType::None);
107
108     MarkedArgumentBuffer arguments;
109     arguments.append(promiseConstructor);
110     ASSERT(!arguments.hasOverflowed());
111     JSValue deferred = call(globalObject, newPromiseCapabilityFunction, callType, callData, jsUndefined(), arguments);
112     RETURN_IF_EXCEPTION(scope, { });
113
114     DeferredData result;
115     result.promise = jsCast<JSPromise*>(deferred.get(globalObject, vm.propertyNames->builtinNames().promisePrivateName()));
116     RETURN_IF_EXCEPTION(scope, { });
117     result.resolve = jsCast<JSFunction*>(deferred.get(globalObject, vm.propertyNames->builtinNames().resolvePrivateName()));
118     RETURN_IF_EXCEPTION(scope, { });
119     result.reject = jsCast<JSFunction*>(deferred.get(globalObject, vm.propertyNames->builtinNames().rejectPrivateName()));
120     RETURN_IF_EXCEPTION(scope, { });
121
122     return result;
123 }
124
125 JSPromise* JSPromise::resolvedPromise(JSGlobalObject* globalObject, JSValue value)
126 {
127     VM& vm = globalObject->vm();
128     auto scope = DECLARE_THROW_SCOPE(vm);
129
130     JSFunction* function = globalObject->promiseResolveFunction();
131     CallData callData;
132     CallType callType = JSC::getCallData(vm, function, callData);
133     ASSERT(callType != CallType::None);
134
135     MarkedArgumentBuffer arguments;
136     arguments.append(value);
137     auto result = call(globalObject, function, callType, callData, globalObject->promiseConstructor(), arguments);
138     RETURN_IF_EXCEPTION(scope, nullptr);
139     ASSERT(result.inherits<JSPromise>(vm));
140     return jsCast<JSPromise*>(result);
141 }
142
143 static inline void callFunction(JSGlobalObject* globalObject, JSValue function, JSPromise* promise, JSValue value)
144 {
145     CallData callData;
146     CallType callType = getCallData(globalObject->vm(), function, callData);
147     ASSERT(callType != CallType::None);
148
149     MarkedArgumentBuffer arguments;
150     arguments.append(promise);
151     arguments.append(value);
152     ASSERT(!arguments.hasOverflowed());
153
154     call(globalObject, function, callType, callData, jsUndefined(), arguments);
155 }
156
157 void JSPromise::resolve(JSGlobalObject* lexicalGlobalObject, JSValue value)
158 {
159     VM& vm = lexicalGlobalObject->vm();
160     auto scope = DECLARE_THROW_SCOPE(vm);
161     uint32_t flags = this->flags();
162     if (!(flags & isFirstResolvingFunctionCalledFlag)) {
163         internalField(static_cast<unsigned>(Field::Flags)).set(vm, this, jsNumber(flags | isFirstResolvingFunctionCalledFlag));
164         JSGlobalObject* globalObject = this->globalObject(vm);
165         callFunction(lexicalGlobalObject, globalObject->resolvePromiseFunction(), this, value);
166         RETURN_IF_EXCEPTION(scope, void());
167     }
168     vm.promiseTimer->cancelPendingPromise(this);
169 }
170
171 void JSPromise::reject(JSGlobalObject* lexicalGlobalObject, JSValue value)
172 {
173     VM& vm = lexicalGlobalObject->vm();
174     auto scope = DECLARE_THROW_SCOPE(vm);
175     uint32_t flags = this->flags();
176     if (!(flags & isFirstResolvingFunctionCalledFlag)) {
177         internalField(static_cast<unsigned>(Field::Flags)).set(vm, this, jsNumber(flags | isFirstResolvingFunctionCalledFlag));
178         JSGlobalObject* globalObject = this->globalObject(vm);
179         callFunction(lexicalGlobalObject, globalObject->rejectPromiseFunction(), this, value);
180         RETURN_IF_EXCEPTION(scope, void());
181     }
182     vm.promiseTimer->cancelPendingPromise(this);
183 }
184
185 void JSPromise::reject(JSGlobalObject* lexicalGlobalObject, Exception* reason)
186 {
187     reject(lexicalGlobalObject, reason->value());
188 }
189
190 } // namespace JSC