d82a1ce2158566d67cad9748d1b64a5f3e080ec5
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSPromiseDeferred.cpp
1 /*
2  * Copyright (C) 2013 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 #if ENABLE(PROMISES)
30
31 #include "Error.h"
32 #include "JSCJSValueInlines.h"
33 #include "JSCellInlines.h"
34 #include "JSPromise.h"
35 #include "JSPromiseConstructor.h"
36 #include "JSPromiseFunctions.h"
37 #include "SlotVisitorInlines.h"
38 #include "StructureInlines.h"
39
40 namespace JSC {
41
42 const ClassInfo JSPromiseDeferred::s_info = { "JSPromiseDeferred", 0, 0, CREATE_METHOD_TABLE(JSPromiseDeferred) };
43
44 JSPromiseDeferred* JSPromiseDeferred::create(ExecState* exec, JSGlobalObject* globalObject)
45 {
46     VM& vm = exec->vm();
47     
48     JSFunction* resolver = createDeferredConstructionFunction(vm, globalObject);
49
50     JSPromise* promise = constructPromise(exec, globalObject, resolver);
51     JSValue resolve = resolver->get(exec, vm.propertyNames->resolvePrivateName);
52     JSValue reject = resolver->get(exec, vm.propertyNames->rejectPrivateName);
53
54     return JSPromiseDeferred::create(vm, promise, resolve, reject);
55 }
56
57 JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSObject* promise, JSValue resolve, JSValue reject)
58 {
59     JSPromiseDeferred* deferred = new (NotNull, allocateCell<JSPromiseDeferred>(vm.heap)) JSPromiseDeferred(vm);
60     deferred->finishCreation(vm, promise, resolve, reject);
61     return deferred;
62 }
63
64 JSPromiseDeferred::JSPromiseDeferred(VM& vm)
65     : Base(vm, vm.promiseDeferredStructure.get())
66 {
67 }
68
69 void JSPromiseDeferred::finishCreation(VM& vm, JSObject* promise, JSValue resolve, JSValue reject)
70 {
71     Base::finishCreation(vm);
72     m_promise.set(vm, this, promise);
73     m_resolve.set(vm, this, resolve);
74     m_reject.set(vm, this, reject);
75 }
76
77 void JSPromiseDeferred::visitChildren(JSCell* cell, SlotVisitor& visitor)
78 {
79     JSPromiseDeferred* thisObject = jsCast<JSPromiseDeferred*>(cell);
80     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
81
82     Base::visitChildren(thisObject, visitor);
83
84     visitor.append(&thisObject->m_promise);
85     visitor.append(&thisObject->m_resolve);
86     visitor.append(&thisObject->m_reject);
87 }
88
89 JSValue createJSPromiseDeferredFromConstructor(ExecState* exec, JSValue C)
90 {
91     // -- This implements the GetDeferred(C) abstract operation --
92
93     // 1. If IsConstructor(C) is false, throw a TypeError.
94     if (!C.isObject())
95         return throwTypeError(exec);
96
97     ConstructData constructData;
98     ConstructType constructType = getConstructData(C, constructData);
99     if (constructType == ConstructTypeNone)
100         return throwTypeError(exec);
101
102     VM& vm = exec->vm();
103
104     // 2. Let 'resolver' be a new built-in function object as defined in Deferred Construction Functions.
105     JSFunction* resolver = createDeferredConstructionFunction(vm, asObject(C)->globalObject());
106
107     // 3. Let 'promise' be the result of calling the [[Construct]] internal method of 'C' with
108     //    an argument list containing the single item resolver.
109     MarkedArgumentBuffer constructArguments;
110     constructArguments.append(resolver);
111     JSObject* promise = construct(exec, C, constructType, constructData, constructArguments);
112
113     // 4. ReturnIfAbrupt(promise).
114     if (exec->hadException())
115         return jsUndefined();
116
117     // 5. Let 'resolve' be the value of resolver's [[Resolve]] internal slot.
118     JSValue resolve = resolver->get(exec, vm.propertyNames->resolvePrivateName);
119
120     // 6. If IsCallable(resolve) is false, throw a TypeError.
121     CallData resolveCallData;
122     CallType resolveCallType = getCallData(resolve, resolveCallData);
123     if (resolveCallType == CallTypeNone)
124         return throwTypeError(exec);
125
126     // 7. Let 'reject' be the value of resolver's [[Reject]] internal slot.
127     JSValue reject = resolver->get(exec, vm.propertyNames->rejectPrivateName);
128
129     // 8. If IsCallable(reject) is false, throw a TypeError.
130     CallData rejectCallData;
131     CallType rejectCallType = getCallData(reject, rejectCallData);
132     if (rejectCallType == CallTypeNone)
133         return throwTypeError(exec);
134
135     // 9. Return the Deferred { [[Promise]]: promise, [[Resolve]]: resolve, [[Reject]]: reject }.
136     return JSPromiseDeferred::create(exec->vm(), promise, resolve, reject);
137 }
138
139 ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, JSPromiseDeferred* deferred)
140 {
141     // 1. If Type(x) is not Object, return "not a thenable".
142     if (!x.isObject())
143         return NotAThenable;
144     
145     // 2. Let 'then' be the result of calling Get(x, "then").
146     JSValue thenValue = x.get(exec, exec->vm().propertyNames->then);
147     
148     // 3. If then is an abrupt completion,
149     if (exec->hadException()) {
150         // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of
151         //    deferred.[[Reject]] with undefined as thisArgument and a List containing
152         //    then.[[value]] as argumentsList.
153         JSValue exception = exec->exception();
154         exec->clearException();
155
156         performDeferredReject(exec, deferred, exception);
157
158         // ii. ReturnIfAbrupt(rejectResult).
159         // NOTE: Nothing to do.
160
161         // iii. Return.
162         return WasAThenable;
163     }
164
165     // 4. Let 'then' be then.[[value]].
166     // Note: Nothing to do.
167
168     // 5. If IsCallable(then) is false, return "not a thenable".
169     CallData thenCallData;
170     CallType thenCallType = getCallData(thenValue, thenCallData);
171     if (thenCallType == CallTypeNone)
172         return NotAThenable;
173
174     // 6. Let 'thenCallResult' be the result of calling the [[Call]] internal method of
175     //    'then' passing x as thisArgument and a List containing deferred.[[Resolve]] and
176     //    deferred.[[Reject]] as argumentsList.
177     MarkedArgumentBuffer thenArguments;
178     thenArguments.append(deferred->resolve());
179     thenArguments.append(deferred->reject());
180     
181     call(exec, thenValue, thenCallType, thenCallData, x, thenArguments);
182
183     // 7. If 'thenCallResult' is an abrupt completion,
184     if (exec->hadException()) {
185         // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of
186         //    deferred.[[Reject]] with undefined as thisArgument and a List containing
187         //    thenCallResult.[[value]] as argumentsList.
188         JSValue exception = exec->exception();
189         exec->clearException();
190
191         performDeferredReject(exec, deferred, exception);
192
193         // ii. ReturnIfAbrupt(rejectResult).
194         // NOTE: Nothing to do.
195     }
196
197     return WasAThenable;
198 }
199
200 void performDeferredResolve(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument)
201 {
202     JSValue deferredResolve = deferred->resolve();
203
204     CallData resolveCallData;
205     CallType resolveCallType = getCallData(deferredResolve, resolveCallData);
206     ASSERT(resolveCallType != CallTypeNone);
207
208     MarkedArgumentBuffer arguments;
209     arguments.append(argument);
210
211     call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments);
212 }
213
214 void performDeferredReject(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument)
215 {
216     JSValue deferredReject = deferred->reject();
217
218     CallData rejectCallData;
219     CallType rejectCallType = getCallData(deferredReject, rejectCallData);
220     ASSERT(rejectCallType != CallTypeNone);
221
222     MarkedArgumentBuffer arguments;
223     arguments.append(argument);
224
225     call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), arguments);
226 }
227
228 JSValue abruptRejection(ExecState* exec, JSPromiseDeferred* deferred)
229 {
230     ASSERT(exec->hadException());
231     JSValue argument = exec->exception();
232     exec->clearException();
233
234     // i. Let 'rejectResult' be the result of calling the [[Call]] internal method
235     // of deferred.[[Reject]] with undefined as thisArgument and a List containing
236     // argument.[[value]] as argumentsList.
237     performDeferredReject(exec, deferred, argument);
238
239     // ii. ReturnIfAbrupt(rejectResult).
240     if (exec->hadException())
241         return jsUndefined();
242
243     // iii. Return deferred.[[Promise]].
244     return deferred->promise();
245 }
246
247 } // namespace JSC
248
249 #endif // ENABLE(PROMISES)