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