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
40namespace JSC {
41
42STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ArrayConstructor);
43
44const 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
53static EncodedJSValue JSC_HOST_CALL callArrayConstructor(ExecState*);
54static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState*);
55
56ArrayConstructor::ArrayConstructor(VM& vm, Structure* structure)
57 : InternalFunction(vm, structure, callArrayConstructor, constructWithArrayConstructor)
58{
59}
60
61void ArrayConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, ArrayPrototype* arrayPrototype, GetterSetter* speciesSymbol)
62{
63 Base::finishCreation(vm, vm.propertyNames->Array.string(), NameVisibility::Visible, NameAdditionMode::WithoutStructureTransition);
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 putDirectNonIndexAccessorWithoutTransition(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
72JSArray* 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 RELEASE_AND_RETURN(scope, constructArrayNegativeIndexed(exec, profile, globalObject, &length, 1, newTarget));
78
79 uint32_t n = length.toUInt32(exec);
80 if (n != length.toNumber(exec)) {
81 throwException(exec, scope, createRangeError(exec, "Array size is not a small enough positive integer."_s));
82 return nullptr;
83 }
84 RELEASE_AND_RETURN(scope, constructEmptyArray(exec, profile, globalObject, n, newTarget));
85}
86
87static inline JSArray* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args, JSValue newTarget)
88{
89 VM& vm = exec->vm();
90 JSGlobalObject* globalObject = jsCast<InternalFunction*>(exec->jsCallee())->globalObject(vm);
91
92 // a single numeric argument denotes the array size (!)
93 if (args.size() == 1)
94 return constructArrayWithSizeQuirk(exec, nullptr, globalObject, args.at(0), newTarget);
95
96 // otherwise the array is constructed with the arguments in it
97 return constructArray(exec, nullptr, globalObject, args, newTarget);
98}
99
100static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec)
101{
102 ArgList args(exec);
103 return JSValue::encode(constructArrayWithSizeQuirk(exec, args, exec->newTarget()));
104}
105
106static EncodedJSValue JSC_HOST_CALL callArrayConstructor(ExecState* exec)
107{
108 ArgList args(exec);
109 return JSValue::encode(constructArrayWithSizeQuirk(exec, args, JSValue()));
110}
111
112static ALWAYS_INLINE bool isArraySlowInline(ExecState* exec, ProxyObject* proxy)
113{
114 VM& vm = exec->vm();
115 auto scope = DECLARE_THROW_SCOPE(vm);
116
117 while (true) {
118 if (proxy->isRevoked()) {
119 throwTypeError(exec, scope, "Array.isArray cannot be called on a Proxy that has been revoked"_s);
120 return false;
121 }
122 JSObject* argument = proxy->target();
123
124 if (argument->type() == ArrayType || argument->type() == DerivedArrayType)
125 return true;
126
127 if (argument->type() != ProxyObjectType)
128 return false;
129
130 proxy = jsCast<ProxyObject*>(argument);
131 }
132
133 ASSERT_NOT_REACHED();
134}
135
136bool isArraySlow(ExecState* exec, ProxyObject* argument)
137{
138 return isArraySlowInline(exec, argument);
139}
140
141// ES6 7.2.2
142// https://tc39.github.io/ecma262/#sec-isarray
143EncodedJSValue JSC_HOST_CALL arrayConstructorPrivateFuncIsArraySlow(ExecState* exec)
144{
145 ASSERT(jsDynamicCast<ProxyObject*>(exec->vm(), exec->argument(0)));
146 return JSValue::encode(jsBoolean(isArraySlowInline(exec, jsCast<ProxyObject*>(exec->uncheckedArgument(0)))));
147}
148
149EncodedJSValue JSC_HOST_CALL arrayConstructorPrivateFuncIsArrayConstructor(ExecState* exec)
150{
151 VM& vm = exec->vm();
152 return JSValue::encode(jsBoolean(jsDynamicCast<ArrayConstructor*>(vm, exec->uncheckedArgument(0))));
153}
154
155} // namespace JSC
156