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 "JSPromiseReaction.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"
42 class ExecutePromiseReactionMicrotask final
: public Microtask
{
44 ExecutePromiseReactionMicrotask(VM
& vm
, JSPromiseReaction
* reaction
, JSValue argument
)
46 m_reaction
.set(vm
, reaction
);
47 m_argument
.set(vm
, argument
);
50 virtual ~ExecutePromiseReactionMicrotask()
55 virtual void run(ExecState
*) override
;
57 Strong
<JSPromiseReaction
> m_reaction
;
58 Strong
<Unknown
> m_argument
;
61 PassRefPtr
<Microtask
> createExecutePromiseReactionMicrotask(VM
& vm
, JSPromiseReaction
* reaction
, JSValue argument
)
63 return adoptRef(new ExecutePromiseReactionMicrotask(vm
, reaction
, argument
));
66 void ExecutePromiseReactionMicrotask::run(ExecState
* exec
)
68 // 1. Let 'deferred' be reaction.[[Deferred]].
69 JSPromiseDeferred
* deferred
= m_reaction
->deferred();
71 // 2. Let 'handler' be reaction.[[Handler]].
72 JSValue handler
= m_reaction
->handler();
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
78 CallData handlerCallData
;
79 CallType handlerCallType
= getCallData(handler
, handlerCallData
);
80 ASSERT(handlerCallType
!= CallTypeNone
);
82 MarkedArgumentBuffer handlerArguments
;
83 handlerArguments
.append(m_argument
.get());
85 JSValue handlerResult
= call(exec
, handler
, handlerCallType
, handlerCallData
, jsUndefined(), handlerArguments
);
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();
94 performDeferredReject(exec
, deferred
, exception
);
97 // 5. Let 'handlerResult' be handlerResult.[[value]].
98 // Note: Nothing to do.
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"));
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
);
110 // 7. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(handlerResult, deferred).
111 ThenableStatus updateResult
= updateDeferredFromPotentialThenable(exec
, handlerResult
, deferred
);
113 // 8. ReturnIfAbrupt(updateResult).
114 if (exec
->hadException())
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
);
126 const ClassInfo
JSPromiseReaction::s_info
= { "JSPromiseReaction", 0, 0, 0, CREATE_METHOD_TABLE(JSPromiseReaction
) };
128 JSPromiseReaction
* JSPromiseReaction::create(VM
& vm
, JSPromiseDeferred
* deferred
, JSValue handler
)
130 JSPromiseReaction
* promiseReaction
= new (NotNull
, allocateCell
<JSPromiseReaction
>(vm
.heap
)) JSPromiseReaction(vm
);
131 promiseReaction
->finishCreation(vm
, deferred
, handler
);
132 return promiseReaction
;
135 JSPromiseReaction::JSPromiseReaction(VM
& vm
)
136 : Base(vm
, vm
.promiseReactionStructure
.get())
140 void JSPromiseReaction::finishCreation(VM
& vm
, JSPromiseDeferred
* deferred
, JSValue handler
)
142 Base::finishCreation(vm
);
143 m_deferred
.set(vm
, this, deferred
);
144 m_handler
.set(vm
, this, handler
);
147 void JSPromiseReaction::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
149 JSPromiseReaction
* thisObject
= jsCast
<JSPromiseReaction
*>(cell
);
150 ASSERT_GC_OBJECT_INHERITS(thisObject
, info());
151 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
152 ASSERT(thisObject
->structure()->typeInfo().overridesVisitChildren());
154 Base::visitChildren(thisObject
, visitor
);
156 visitor
.append(&thisObject
->m_deferred
);
157 visitor
.append(&thisObject
->m_handler
);
162 #endif // ENABLE(PROMISES)