Pass VM instead of JSGlobalObject to function constructors.
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSPromiseCallback.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 "JSPromiseCallback.h"
28
29 #if ENABLE(PROMISES)
30
31 #include "JSCJSValueInlines.h"
32 #include "JSCellInlines.h"
33 #include "JSPromise.h"
34 #include "JSPromiseResolver.h"
35 #include "SlotVisitorInlines.h"
36 #include "StructureInlines.h"
37
38 namespace JSC {
39
40 const ClassInfo JSPromiseCallback::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSPromiseCallback) };
41
42 JSPromiseCallback* JSPromiseCallback::create(VM& vm, Structure* structure, JSPromiseResolver* resolver, Algorithm algorithm)
43 {
44     JSPromiseCallback* constructor = new (NotNull, allocateCell<JSPromiseCallback>(vm.heap)) JSPromiseCallback(vm, structure, algorithm);
45     constructor->finishCreation(vm, resolver);
46     return constructor;
47 }
48
49 Structure* JSPromiseCallback::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
50 {
51     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
52 }
53
54 JSPromiseCallback::JSPromiseCallback(VM& vm, Structure* structure, Algorithm algorithm)
55     : InternalFunction(vm, structure)
56     , m_algorithm(algorithm)
57 {
58 }
59
60 void JSPromiseCallback::finishCreation(VM& vm, JSPromiseResolver* resolver)
61 {
62     Base::finishCreation(vm, "PromiseCallback");
63     m_resolver.set(vm, this, resolver);
64 }
65
66 void JSPromiseCallback::visitChildren(JSCell* cell, SlotVisitor& visitor)
67 {
68     JSPromiseCallback* thisObject = jsCast<JSPromiseCallback*>(cell);
69     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
70     COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
71     ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
72
73     Base::visitChildren(thisObject, visitor);
74
75     visitor.append(&thisObject->m_resolver);
76 }
77
78 EncodedJSValue JSC_HOST_CALL JSPromiseCallback::callPromiseCallback(ExecState* exec)
79 {
80     JSPromiseCallback* promiseCallback = jsCast<JSPromiseCallback*>(exec->callee());
81     JSPromiseResolver* resolver = promiseCallback->m_resolver.get();
82
83     // 1. Let value be the first argument that is passed, and undefined otherwise.
84     JSValue value = exec->argument(0);
85
86     // 2. Run resolver's algorithm with value and the synchronous flag set.
87     switch (promiseCallback->m_algorithm) {
88     case JSPromiseCallback::Fulfill:
89         resolver->fulfill(exec, value, JSPromiseResolver::ResolveSynchronously);
90         break;
91
92     case JSPromiseCallback::Resolve:
93         resolver->resolve(exec, value, JSPromiseResolver::ResolveSynchronously);
94         break;
95
96     case JSPromiseCallback::Reject:
97         resolver->reject(exec, value, JSPromiseResolver::ResolveSynchronously);
98         break;
99     }
100
101     return JSValue::encode(jsUndefined());
102 }
103
104 CallType JSPromiseCallback::getCallData(JSCell*, CallData& callData)
105 {
106     callData.native.function = callPromiseCallback;
107     return CallTypeHost;
108 }
109
110
111
112
113 const ClassInfo JSPromiseWrapperCallback::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSPromiseWrapperCallback) };
114
115 JSPromiseWrapperCallback* JSPromiseWrapperCallback::create(VM& vm, Structure* structure, JSPromiseResolver* resolver, JSValue callback)
116 {
117     JSPromiseWrapperCallback* constructor = new (NotNull, allocateCell<JSPromiseWrapperCallback>(vm.heap)) JSPromiseWrapperCallback(vm, structure);
118     constructor->finishCreation(vm, resolver, callback);
119     return constructor;
120 }
121
122 Structure* JSPromiseWrapperCallback::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
123 {
124     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
125 }
126
127 JSPromiseWrapperCallback::JSPromiseWrapperCallback(VM& vm, Structure* structure)
128     : InternalFunction(vm, structure)
129 {
130 }
131
132 void JSPromiseWrapperCallback::finishCreation(VM& vm, JSPromiseResolver* resolver, JSValue callback)
133 {
134     Base::finishCreation(vm, "PromiseWrapperCallback");
135     m_resolver.set(vm, this, resolver);
136     m_callback.set(vm, this, callback);
137 }
138
139 void JSPromiseWrapperCallback::visitChildren(JSCell* cell, SlotVisitor& visitor)
140 {
141     JSPromiseWrapperCallback* thisObject = jsCast<JSPromiseWrapperCallback*>(cell);
142     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
143     COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
144     ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
145
146     Base::visitChildren(thisObject, visitor);
147
148     visitor.append(&thisObject->m_resolver);
149     visitor.append(&thisObject->m_callback);
150 }
151
152 EncodedJSValue JSC_HOST_CALL JSPromiseWrapperCallback::callPromiseWrapperCallback(ExecState* exec)
153 {
154     JSPromiseWrapperCallback* promiseWrapperCallback = jsCast<JSPromiseWrapperCallback*>(exec->callee());
155
156     JSPromiseResolver* resolver = promiseWrapperCallback->m_resolver.get();
157     JSValue callback = promiseWrapperCallback->m_callback.get();
158
159     // 1. Let argument be the first argument that is passed, and undefined otherwise.
160     JSValue argument = exec->argument(0);
161
162     // 2. Set callback's callback this value to resolver's associated promise.
163     // 3. Let value be the result of invoking callback with argument as argument.
164     CallData callData;
165     CallType callType = JSC::getCallData(callback, callData);
166     ASSERT(callType != CallTypeNone);
167
168     MarkedArgumentBuffer callbackArguments;
169     callbackArguments.append(argument);
170     JSValue value = JSC::call(exec, callback, callType, callData, resolver->promise(), callbackArguments);
171
172     // 4. If invoking callback threw an exception, catch it and run resolver's reject
173     //    with the thrown exception as argument and the synchronous flag set.
174     if (exec->hadException()) {
175         JSValue exception = exec->exception();
176         exec->clearException();
177
178         resolver->reject(exec, exception, JSPromiseResolver::ResolveSynchronously);
179         return JSValue::encode(jsUndefined());
180     }
181
182     // 5. Otherwise, run resolver's resolve with value and the synchronous flag set.
183     resolver->resolve(exec, value, JSPromiseResolver::ResolveSynchronously);
184
185     return JSValue::encode(jsUndefined());
186 }
187
188 CallType JSPromiseWrapperCallback::getCallData(JSCell*, CallData& callData)
189 {
190     callData.native.function = callPromiseWrapperCallback;
191     return CallTypeHost;
192 }
193
194 } // namespace JSC
195
196 #endif // ENABLE(PROMISES)