689abd203802b1ff005546bad0c88035d21b950e
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSPromiseReaction.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 "JSPromiseReaction.h"
28
29 #if ENABLE(PROMISES)
30
31 #include "Error.h"
32 #include "JSCJSValueInlines.h"
33 #include "JSCellInlines.h"
34 #include "JSGlobalObject.h"
35 #include "JSPromiseDeferred.h"
36 #include "Microtask.h"
37 #include "SlotVisitorInlines.h"
38 #include "StrongInlines.h"
39
40 namespace JSC {
41
42 class ExecutePromiseReactionMicrotask final : public Microtask {
43 public:
44     ExecutePromiseReactionMicrotask(VM& vm, JSPromiseReaction* reaction, JSValue argument)
45     {
46         m_reaction.set(vm, reaction);
47         m_argument.set(vm, argument);
48     }
49
50     virtual ~ExecutePromiseReactionMicrotask()
51     {
52     }
53
54 private:
55     virtual void run(ExecState*) override;
56
57     Strong<JSPromiseReaction> m_reaction;
58     Strong<Unknown> m_argument;
59 };
60
61 PassRefPtr<Microtask> createExecutePromiseReactionMicrotask(VM& vm, JSPromiseReaction* reaction, JSValue argument)
62 {
63     return adoptRef(new ExecutePromiseReactionMicrotask(vm, reaction, argument));
64 }
65
66 void ExecutePromiseReactionMicrotask::run(ExecState* exec)
67 {
68     // 1. Let 'deferred' be reaction.[[Deferred]].
69     JSPromiseDeferred* deferred = m_reaction->deferred();
70     
71     // 2. Let 'handler' be reaction.[[Handler]].
72     JSValue handler = m_reaction->handler();
73
74     // 3. Let 'handlerResult' be the result of calling the [[Call]] internal method of
75     //    handler passing undefined as thisArgument and a List containing argument as
76     //    argumentsList.
77
78     CallData handlerCallData;
79     CallType handlerCallType = getCallData(handler, handlerCallData);
80     ASSERT(handlerCallType != CallTypeNone);
81
82     MarkedArgumentBuffer handlerArguments;
83     handlerArguments.append(m_argument.get());
84
85     JSValue handlerResult = call(exec, handler, handlerCallType, handlerCallData, jsUndefined(), handlerArguments);
86
87     // 4. If handlerResult is an abrupt completion, return the result of calling the
88     //    [[Call]] internal method of deferred.[[Reject]] passing undefined as thisArgument
89     //    and a List containing handlerResult.[[value]] as argumentsList.
90     if (exec->hadException()) {
91         JSValue exception = exec->exception();
92         exec->clearException();
93
94         performDeferredReject(exec, deferred, exception);
95     }
96     
97     // 5. Let 'handlerResult' be handlerResult.[[value]].
98     // Note: Nothing to do.
99
100     // 6. If SameValue(handlerResult, deferred.[[Promise]]) is true,
101     if (sameValue(exec, handlerResult, deferred->promise())) {
102         // i. Let 'selfResolutionError' be a newly-created TypeError object.
103         JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself"));
104
105         // ii. Return the result of calling the [[Call]] internal method of deferred.[[Reject]] passing
106         //     undefined as thisArgument and a List containing selfResolutionError as argumentsList.
107         performDeferredReject(exec, deferred, selfResolutionError);
108     }
109
110     // 7. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(handlerResult, deferred).
111     ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, handlerResult, deferred);
112     
113     // 8. ReturnIfAbrupt(updateResult).
114     if (exec->hadException())
115         return;
116
117     // 9. If 'updateResult' is "not a thenable",
118     if (updateResult == NotAThenable) {
119         // i. Return the result of calling the [[Call]] internal method of deferred.[[Resolve]]
120         //    passing undefined as thisArgument and a List containing handlerResult as argumentsList.
121         performDeferredResolve(exec, deferred, handlerResult);
122     }
123 }
124
125
126 const ClassInfo JSPromiseReaction::s_info = { "JSPromiseReaction", 0, 0, CREATE_METHOD_TABLE(JSPromiseReaction) };
127
128 JSPromiseReaction* JSPromiseReaction::create(VM& vm, JSPromiseDeferred* deferred, JSValue handler)
129 {
130     JSPromiseReaction* promiseReaction = new (NotNull, allocateCell<JSPromiseReaction>(vm.heap)) JSPromiseReaction(vm);
131     promiseReaction->finishCreation(vm, deferred, handler);
132     return promiseReaction;
133 }
134
135 JSPromiseReaction::JSPromiseReaction(VM& vm)
136     : Base(vm, vm.promiseReactionStructure.get())
137 {
138 }
139
140 void JSPromiseReaction::finishCreation(VM& vm, JSPromiseDeferred* deferred, JSValue handler)
141 {
142     Base::finishCreation(vm);
143     m_deferred.set(vm, this, deferred);
144     m_handler.set(vm, this, handler);
145 }
146
147 void JSPromiseReaction::visitChildren(JSCell* cell, SlotVisitor& visitor)
148 {
149     JSPromiseReaction* thisObject = jsCast<JSPromiseReaction*>(cell);
150     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
151
152     Base::visitChildren(thisObject, visitor);
153
154     visitor.append(&thisObject->m_deferred);
155     visitor.append(&thisObject->m_handler);
156 }
157
158 } // namespace JSC
159
160 #endif // ENABLE(PROMISES)