Promise constructor should throw when not called with "new"
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSPromiseConstructor.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 "JSPromiseConstructor.h"
28
29 #include "BuiltinNames.h"
30 #include "Error.h"
31 #include "Exception.h"
32 #include "IteratorOperations.h"
33 #include "JSCBuiltins.h"
34 #include "JSCJSValueInlines.h"
35 #include "JSCellInlines.h"
36 #include "JSPromise.h"
37 #include "JSPromisePrototype.h"
38 #include "Lookup.h"
39 #include "NumberObject.h"
40 #include "StructureInlines.h"
41
42 namespace JSC {
43
44 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSPromiseConstructor);
45
46 }
47
48 #include "JSPromiseConstructor.lut.h"
49
50 namespace JSC {
51
52 const ClassInfo JSPromiseConstructor::s_info = { "Function", &Base::s_info, &promiseConstructorTable, CREATE_METHOD_TABLE(JSPromiseConstructor) };
53
54 /* Source for JSPromiseConstructor.lut.h
55 @begin promiseConstructorTable
56   resolve         JSPromiseConstructorFuncResolve             DontEnum|Function 1
57   reject          JSPromiseConstructorFuncReject              DontEnum|Function 1
58   race            JSPromiseConstructorFuncRace                DontEnum|Function 1
59   all             JSPromiseConstructorFuncAll                 DontEnum|Function 1
60 @end
61 */
62
63 JSPromiseConstructor* JSPromiseConstructor::create(VM& vm, Structure* structure, JSPromisePrototype* promisePrototype)
64 {
65     JSPromiseConstructor* constructor = new (NotNull, allocateCell<JSPromiseConstructor>(vm.heap)) JSPromiseConstructor(vm, structure);
66     constructor->finishCreation(vm, promisePrototype);
67     return constructor;
68 }
69
70 Structure* JSPromiseConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
71 {
72     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
73 }
74
75 JSPromiseConstructor::JSPromiseConstructor(VM& vm, Structure* structure)
76     : Base(vm, structure)
77 {
78 }
79
80 void JSPromiseConstructor::finishCreation(VM& vm, JSPromisePrototype* promisePrototype)
81 {
82     Base::finishCreation(vm, ASCIILiteral("Promise"));
83     putDirectWithoutTransition(vm, vm.propertyNames->prototype, promisePrototype, DontEnum | DontDelete | ReadOnly);
84     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
85 }
86
87 static EncodedJSValue JSC_HOST_CALL constructPromise(ExecState* exec)
88 {
89     JSGlobalObject* globalObject = exec->callee()->globalObject();
90     VM& vm = exec->vm();
91
92     JSValue newTarget = exec->newTarget();
93     if (!newTarget || newTarget.isUndefined())
94         return throwVMTypeError(exec);
95
96     JSPromise* promise = JSPromise::create(vm, globalObject->promiseStructure());
97     if (!jsDynamicCast<JSPromiseConstructor*>(newTarget)) {
98         JSValue proto = asObject(newTarget)->getDirect(vm, vm.propertyNames->prototype);
99         asObject(promise)->setPrototypeWithCycleCheck(exec, proto);
100     }
101     promise->initialize(exec, globalObject, exec->argument(0));
102
103     return JSValue::encode(promise);
104 }
105
106 static EncodedJSValue JSC_HOST_CALL callPromise(ExecState* exec)
107 {
108     return throwVMTypeError(exec);
109 }
110
111 ConstructType JSPromiseConstructor::getConstructData(JSCell*, ConstructData& constructData)
112 {
113     constructData.native.function = constructPromise;
114     return ConstructTypeHost;
115 }
116
117 CallType JSPromiseConstructor::getCallData(JSCell*, CallData& callData)
118 {
119     // FIXME: This is workaround. Since JSC does not expose @isConstructor to JS builtins,
120     // we use typeof function === "function" now. And since typeof constructorWithoutCallability
121     // returns "object", we need to define [[Call]] for now.
122     // https://bugs.webkit.org/show_bug.cgi?id=144093
123     callData.native.function = callPromise;
124     return CallTypeHost;
125 }
126
127 bool JSPromiseConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
128 {
129     return getStaticFunctionSlot<Base>(exec, promiseConstructorTable, jsCast<JSPromiseConstructor*>(object), propertyName, slot);
130 }
131
132 } // namespace JSC