Pass VM instead of JSGlobalObject to function constructors.
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSPromisePrototype.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 "JSPromisePrototype.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 "JSPromise.h"
36 #include "JSPromiseCallback.h"
37 #include "JSPromiseResolver.h"
38 #include "StructureInlines.h"
39
40 namespace JSC {
41
42 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSPromisePrototype);
43
44 // Promise then([TreatUndefinedAs=Missing] optional AnyCallback fulfillCallback, [TreatUndefinedAs=Missing] optional AnyCallback rejectCallback);
45 static EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncThen(ExecState*);
46 // Promise catch([TreatUndefinedAs=Missing] optional AnyCallback rejectCallback);
47 static EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncCatch(ExecState*);
48
49 }
50
51 #include "JSPromisePrototype.lut.h"
52
53 namespace JSC {
54
55 const ClassInfo JSPromisePrototype::s_info = { "PromisePrototype", &JSNonFinalObject::s_info, 0, ExecState::promisePrototypeTable, CREATE_METHOD_TABLE(JSPromisePrototype) };
56
57 /* Source for JSPromisePrototype.lut.h
58 @begin promisePrototypeTable
59   then         JSPromisePrototypeFuncThen             DontEnum|Function 0
60   catch        JSPromisePrototypeFuncCatch            DontEnum|Function 0
61 @end
62 */
63
64 JSPromisePrototype* JSPromisePrototype::create(ExecState* exec, JSGlobalObject*, Structure* structure)
65 {
66     VM& vm = exec->vm();
67     JSPromisePrototype* object = new (NotNull, allocateCell<JSPromisePrototype>(vm.heap)) JSPromisePrototype(exec, structure);
68     object->finishCreation(vm, structure);
69     return object;
70 }
71
72 Structure* JSPromisePrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
73 {
74     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
75 }
76
77 JSPromisePrototype::JSPromisePrototype(ExecState* exec, Structure* structure)
78     : JSNonFinalObject(exec->vm(), structure)
79 {
80 }
81
82 void JSPromisePrototype::finishCreation(VM& vm, Structure*)
83 {
84     Base::finishCreation(vm);
85 }
86
87 bool JSPromisePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
88 {
89     return getStaticFunctionSlot<JSObject>(exec, ExecState::promisePrototypeTable(exec), jsCast<JSPromisePrototype*>(object), propertyName, slot);
90 }
91
92 static InternalFunction* wrapCallback(ExecState* exec, JSGlobalObject* globalObject, JSValue callback, JSPromiseResolver* resolver, JSPromiseCallback::Algorithm algorithm)
93 {
94     if (!callback.isUndefined())
95         return JSPromiseWrapperCallback::create(exec->vm(), globalObject->promiseWrapperCallbackStructure(), resolver, callback);
96     return JSPromiseCallback::create(exec->vm(), globalObject->promiseCallbackStructure(), resolver, algorithm);
97 }
98
99 EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncThen(ExecState* exec)
100 {
101     JSPromise* thisObject = jsDynamicCast<JSPromise*>(exec->thisValue());
102     if (!thisObject)
103         return throwVMError(exec, createTypeError(exec, "Receiver of then must be a Promise"));
104
105     JSValue fulfillCallback = exec->argument(0);
106     if (!fulfillCallback.isUndefined()) {
107         CallData callData;
108         CallType callType = getCallData(fulfillCallback, callData);
109         if (callType == CallTypeNone)
110             return throwVMError(exec, createTypeError(exec, "Expected function or undefined as as first argument"));
111     }
112     
113     JSValue rejectCallback = exec->argument(1);
114     if (!rejectCallback.isUndefined()) {
115         CallData callData;
116         CallType callType = getCallData(rejectCallback, callData);
117         if (callType == CallTypeNone)
118             return throwVMError(exec, createTypeError(exec, "Expected function or undefined as as second argument"));
119     }
120
121     JSFunction* callee = jsCast<JSFunction*>(exec->callee());
122     JSGlobalObject* globalObject = callee->globalObject();
123
124     // 1. Let promise be a new promise.
125     JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject);
126
127     // 2. Let resolver be promise's associated resolver.
128     JSPromiseResolver* resolver = promise->resolver();
129
130     // 3. Let fulfillWrapper be a promise wrapper callback for resolver and fulfillCallback if fulfillCallback is
131     //    not omitted and a promise callback for resolver and its fulfill algorithm otherwise.
132     InternalFunction* fulfillWrapper = wrapCallback(exec, globalObject, fulfillCallback, resolver, JSPromiseCallback::Fulfill);
133
134     // 4. Let rejectWrapper be a promise wrapper callback for resolver and rejectCallback if rejectCallback is
135     //    not omitted and a promise callback for resolver and its reject algorithm otherwise.
136     InternalFunction* rejectWrapper = wrapCallback(exec, globalObject, rejectCallback, resolver, JSPromiseCallback::Reject);
137
138     // 5. Append fulfillWrapper and rejectWrapper to the context object.
139     thisObject->appendCallbacks(exec, fulfillWrapper, rejectWrapper);
140
141     // 6. Return promise.
142     return JSValue::encode(promise);
143 }
144
145 EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncCatch(ExecState* exec)
146 {
147     JSPromise* thisObject = jsDynamicCast<JSPromise*>(exec->thisValue());
148     if (!thisObject)
149         return throwVMError(exec, createTypeError(exec, "Receiver of catch must be a Promise"));
150     
151     JSValue rejectCallback = exec->argument(0);
152     if (!rejectCallback.isUndefined()) {
153         CallData callData;
154         CallType callType = getCallData(rejectCallback, callData);
155         if (callType == CallTypeNone)
156             return throwVMError(exec, createTypeError(exec, "Expected function or undefined as as first argument"));
157     }
158
159     JSFunction* callee = jsCast<JSFunction*>(exec->callee());
160     JSGlobalObject* globalObject = callee->globalObject();
161     VM& vm = exec->vm();
162
163     // 1. Let promise be a new promise.
164     JSPromise* promise = JSPromise::createWithResolver(vm, globalObject);
165
166     // 2. Let resolver be promise's associated resolver.
167     JSPromiseResolver* resolver = promise->resolver();
168
169     // 3. Let fulfillCallback be a new promise callback for resolver and its fulfill algorithm.
170     InternalFunction* fulfillWrapper = JSPromiseCallback::create(vm, globalObject->promiseCallbackStructure(), resolver, JSPromiseCallback::Fulfill);
171
172     // 4. Let rejectWrapper be a promise wrapper callback for resolver and rejectCallback if rejectCallback is
173     //    not omitted and a promise callback for resolver and its reject algorithm otherwise.
174     InternalFunction* rejectWrapper = wrapCallback(exec, globalObject, rejectCallback, resolver, JSPromiseCallback::Reject);
175
176     // 5. Append fulfillWrapper and rejectWrapper to the context object.
177     thisObject->appendCallbacks(exec, fulfillWrapper, rejectWrapper);
178
179     // 6. Return promise.
180     return JSValue::encode(promise);
181 }
182
183 } // namespace JSC
184
185 #endif // ENABLE(PROMISES)