ac6f3e979e10b84399fdb24af6dfa3f68a48563a
[WebKit.git] / Source / JavaScriptCore / runtime / ArrayConstructor.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003, 2007-2008, 2011, 2016 Apple Inc. All rights reserved.
4  *  Copyright (C) 2003 Peter Kelly (pmk@post.com)
5  *  Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
20  *  USA
21  *
22  */
23
24 #include "config.h"
25 #include "ArrayConstructor.h"
26
27 #include "ArrayPrototype.h"
28 #include "ButterflyInlines.h"
29 #include "Error.h"
30 #include "ExceptionHelpers.h"
31 #include "GetterSetter.h"
32 #include "JSArray.h"
33 #include "JSFunction.h"
34 #include "Lookup.h"
35 #include "ProxyObject.h"
36 #include "JSCInlines.h"
37
38 #include "ArrayConstructor.lut.h"
39
40 namespace JSC {
41
42 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ArrayConstructor);
43
44 const ClassInfo ArrayConstructor::s_info = { "Function", &InternalFunction::s_info, &arrayConstructorTable, nullptr, CREATE_METHOD_TABLE(ArrayConstructor) };
45
46 /* Source for ArrayConstructor.lut.h
47 @begin arrayConstructorTable
48   of        JSBuiltin                   DontEnum|Function 0
49   from      JSBuiltin                   DontEnum|Function 0
50 @end
51 */
52
53 static EncodedJSValue JSC_HOST_CALL callArrayConstructor(ExecState*);
54 static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState*);
55
56 ArrayConstructor::ArrayConstructor(VM& vm, Structure* structure)
57     : InternalFunction(vm, structure, callArrayConstructor, constructWithArrayConstructor)
58 {
59 }
60
61 void ArrayConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, ArrayPrototype* arrayPrototype, GetterSetter* speciesSymbol)
62 {
63     Base::finishCreation(vm, arrayPrototype->classInfo(vm)->className);
64     putDirectWithoutTransition(vm, vm.propertyNames->prototype, arrayPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
65     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
66     putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
67     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->isArray, arrayConstructorIsArrayCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
68 }
69
70 // ------------------------------ Functions ---------------------------
71
72 JSArray* constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length, JSValue newTarget)
73 {
74     VM& vm = exec->vm();
75     auto scope = DECLARE_THROW_SCOPE(vm);
76     if (!length.isNumber()) {
77         scope.release();
78         return constructArrayNegativeIndexed(exec, profile, globalObject, &length, 1, newTarget);
79     }
80     
81     uint32_t n = length.toUInt32(exec);
82     if (n != length.toNumber(exec)) {
83         throwException(exec, scope, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer.")));
84         return nullptr;
85     }
86     scope.release();
87     return constructEmptyArray(exec, profile, globalObject, n, newTarget);
88 }
89
90 static inline JSArray* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args, JSValue newTarget)
91 {
92     JSGlobalObject* globalObject = jsCast<InternalFunction*>(exec->jsCallee())->globalObject();
93
94     // a single numeric argument denotes the array size (!)
95     if (args.size() == 1)
96         return constructArrayWithSizeQuirk(exec, nullptr, globalObject, args.at(0), newTarget);
97
98     // otherwise the array is constructed with the arguments in it
99     return constructArray(exec, nullptr, globalObject, args, newTarget);
100 }
101
102 static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec)
103 {
104     ArgList args(exec);
105     return JSValue::encode(constructArrayWithSizeQuirk(exec, args, exec->newTarget()));
106 }
107
108 static EncodedJSValue JSC_HOST_CALL callArrayConstructor(ExecState* exec)
109 {
110     ArgList args(exec);
111     return JSValue::encode(constructArrayWithSizeQuirk(exec, args, JSValue()));
112 }
113
114 static ALWAYS_INLINE bool isArraySlowInline(ExecState* exec, ProxyObject* proxy)
115 {
116     VM& vm = exec->vm();
117     auto scope = DECLARE_THROW_SCOPE(vm);
118
119     while (true) {
120         if (proxy->isRevoked()) {
121             throwTypeError(exec, scope, ASCIILiteral("Array.isArray cannot be called on a Proxy that has been revoked"));
122             return false;
123         }
124         JSObject* argument = proxy->target();
125
126         if (argument->type() == ArrayType ||  argument->type() == DerivedArrayType)
127             return true;
128
129         if (argument->type() != ProxyObjectType)
130             return false;
131
132         proxy = jsCast<ProxyObject*>(argument);
133     }
134
135     ASSERT_NOT_REACHED();
136 }
137
138 bool isArraySlow(ExecState* exec, ProxyObject* argument)
139 {
140     return isArraySlowInline(exec, argument);
141 }
142
143 // ES6 7.2.2
144 // https://tc39.github.io/ecma262/#sec-isarray
145 EncodedJSValue JSC_HOST_CALL arrayConstructorPrivateFuncIsArraySlow(ExecState* exec)
146 {
147     ASSERT(jsDynamicCast<ProxyObject*>(exec->vm(), exec->argument(0)));
148     return JSValue::encode(jsBoolean(isArraySlowInline(exec, jsCast<ProxyObject*>(exec->uncheckedArgument(0)))));
149 }
150
151 EncodedJSValue JSC_HOST_CALL arrayConstructorPrivateFuncIsArrayConstructor(ExecState* exec)
152 {
153     VM& vm = exec->vm();
154     return JSValue::encode(jsBoolean(jsDynamicCast<ArrayConstructor*>(vm, exec->uncheckedArgument(0))));
155 }
156
157 } // namespace JSC