2 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "JSPromiseDeferred.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"
42 const ClassInfo
JSPromiseDeferred::s_info
= { "JSPromiseDeferred", 0, 0, 0, CREATE_METHOD_TABLE(JSPromiseDeferred
) };
44 JSPromiseDeferred
* JSPromiseDeferred::create(ExecState
* exec
, JSGlobalObject
* globalObject
)
48 JSFunction
* resolver
= createDeferredConstructionFunction(vm
, globalObject
);
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
);
54 return JSPromiseDeferred::create(vm
, promise
, resolve
, reject
);
57 JSPromiseDeferred
* JSPromiseDeferred::create(VM
& vm
, JSObject
* promise
, JSValue resolve
, JSValue reject
)
59 JSPromiseDeferred
* deferred
= new (NotNull
, allocateCell
<JSPromiseDeferred
>(vm
.heap
)) JSPromiseDeferred(vm
);
60 deferred
->finishCreation(vm
, promise
, resolve
, reject
);
64 JSPromiseDeferred::JSPromiseDeferred(VM
& vm
)
65 : Base(vm
, vm
.promiseDeferredStructure
.get())
69 void JSPromiseDeferred::finishCreation(VM
& vm
, JSObject
* promise
, JSValue resolve
, JSValue reject
)
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
);
77 void JSPromiseDeferred::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
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());
84 Base::visitChildren(thisObject
, visitor
);
86 visitor
.append(&thisObject
->m_promise
);
87 visitor
.append(&thisObject
->m_resolve
);
88 visitor
.append(&thisObject
->m_reject
);
91 JSValue
createJSPromiseDeferredFromConstructor(ExecState
* exec
, JSValue C
)
93 // -- This implements the GetDeferred(C) abstract operation --
95 // 1. If IsConstructor(C) is false, throw a TypeError.
97 return throwTypeError(exec
);
99 ConstructData constructData
;
100 ConstructType constructType
= getConstructData(C
, constructData
);
101 if (constructType
== ConstructTypeNone
)
102 return throwTypeError(exec
);
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());
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
);
115 // 4. ReturnIfAbrupt(promise).
116 if (exec
->hadException())
117 return jsUndefined();
119 // 5. Let 'resolve' be the value of resolver's [[Resolve]] internal slot.
120 JSValue resolve
= resolver
->get(exec
, vm
.propertyNames
->resolvePrivateName
);
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
);
128 // 7. Let 'reject' be the value of resolver's [[Reject]] internal slot.
129 JSValue reject
= resolver
->get(exec
, vm
.propertyNames
->rejectPrivateName
);
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
);
137 // 9. Return the Deferred { [[Promise]]: promise, [[Resolve]]: resolve, [[Reject]]: reject }.
138 return JSPromiseDeferred::create(exec
->vm(), promise
, resolve
, reject
);
141 ThenableStatus
updateDeferredFromPotentialThenable(ExecState
* exec
, JSValue x
, JSPromiseDeferred
* deferred
)
143 // 1. If Type(x) is not Object, return "not a thenable".
147 // 2. Let 'then' be the result of calling Get(x, "then").
148 JSValue thenValue
= x
.get(exec
, exec
->vm().propertyNames
->then
);
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();
158 performDeferredReject(exec
, deferred
, exception
);
160 // ii. ReturnIfAbrupt(rejectResult).
161 // NOTE: Nothing to do.
167 // 4. Let 'then' be then.[[value]].
168 // Note: Nothing to do.
170 // 5. If IsCallable(then) is false, return "not a thenable".
171 CallData thenCallData
;
172 CallType thenCallType
= getCallData(thenValue
, thenCallData
);
173 if (thenCallType
== CallTypeNone
)
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());
183 call(exec
, thenValue
, thenCallType
, thenCallData
, x
, thenArguments
);
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();
193 performDeferredReject(exec
, deferred
, exception
);
195 // ii. ReturnIfAbrupt(rejectResult).
196 // NOTE: Nothing to do.
202 void performDeferredResolve(ExecState
* exec
, JSPromiseDeferred
* deferred
, JSValue argument
)
204 JSValue deferredResolve
= deferred
->resolve();
206 CallData resolveCallData
;
207 CallType resolveCallType
= getCallData(deferredResolve
, resolveCallData
);
208 ASSERT(resolveCallType
!= CallTypeNone
);
210 MarkedArgumentBuffer arguments
;
211 arguments
.append(argument
);
213 call(exec
, deferredResolve
, resolveCallType
, resolveCallData
, jsUndefined(), arguments
);
216 void performDeferredReject(ExecState
* exec
, JSPromiseDeferred
* deferred
, JSValue argument
)
218 JSValue deferredReject
= deferred
->reject();
220 CallData rejectCallData
;
221 CallType rejectCallType
= getCallData(deferredReject
, rejectCallData
);
222 ASSERT(rejectCallType
!= CallTypeNone
);
224 MarkedArgumentBuffer arguments
;
225 arguments
.append(argument
);
227 call(exec
, deferredReject
, rejectCallType
, rejectCallData
, jsUndefined(), arguments
);
230 JSValue
abruptRejection(ExecState
* exec
, JSPromiseDeferred
* deferred
)
232 ASSERT(exec
->hadException());
233 JSValue argument
= exec
->exception();
234 exec
->clearException();
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
);
241 // ii. ReturnIfAbrupt(rejectResult).
242 if (exec
->hadException())
243 return jsUndefined();
245 // iii. Return deferred.[[Promise]].
246 return deferred
->promise();
251 #endif // ENABLE(PROMISES)