1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2003, 2007-2008, 2011, 2016 Apple Inc. All rights reserved.
4 * Copyright (C) 2003 Peter Kelly ([email protected])
5 * Copyright (C) 2006 Alexey Proskuryakov ([email protected])
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(JSGlobalObject*, CallFrame*);
54static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(JSGlobalObject*, CallFrame*);
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(), 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(JSGlobalObject* globalObject, ArrayAllocationProfile* profile, JSValue length, JSValue newTarget)
73{
74 VM& vm = globalObject->vm();
75 auto scope = DECLARE_THROW_SCOPE(vm);
76 if (!length.isNumber())
77 RELEASE_AND_RETURN(scope, constructArrayNegativeIndexed(globalObject, profile, &length, 1, newTarget));
78
79 uint32_t n = length.toUInt32(globalObject);
80 if (n != length.toNumber(globalObject)) {
81 throwException(globalObject, scope, createRangeError(globalObject, "Array size is not a small enough positive integer."_s));
82 return nullptr;
83 }
84 RELEASE_AND_RETURN(scope, constructEmptyArray(globalObject, profile, n, newTarget));
85}
86
87static inline JSArray* constructArrayWithSizeQuirk(JSGlobalObject* globalObject, const ArgList& args, JSValue newTarget)
88{
89 // a single numeric argument denotes the array size (!)
90 if (args.size() == 1)
91 return constructArrayWithSizeQuirk(globalObject, nullptr, args.at(0), newTarget);
92
93 // otherwise the array is constructed with the arguments in it
94 return constructArray(globalObject, static_cast<ArrayAllocationProfile*>(nullptr), args, newTarget);
95}
96
97static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(JSGlobalObject* globalObject, CallFrame* callFrame)
98{
99 ArgList args(callFrame);
100 return JSValue::encode(constructArrayWithSizeQuirk(globalObject, args, callFrame->newTarget()));
101}
102
103static EncodedJSValue JSC_HOST_CALL callArrayConstructor(JSGlobalObject* globalObject, CallFrame* callFrame)
104{
105 ArgList args(callFrame);
106 return JSValue::encode(constructArrayWithSizeQuirk(globalObject, args, JSValue()));
107}
108
109static ALWAYS_INLINE bool isArraySlowInline(JSGlobalObject* globalObject, ProxyObject* proxy)
110{
111 VM& vm = globalObject->vm();
112 auto scope = DECLARE_THROW_SCOPE(vm);
113
114 while (true) {
115 if (proxy->isRevoked()) {
116 throwTypeError(globalObject, scope, "Array.isArray cannot be called on a Proxy that has been revoked"_s);
117 return false;
118 }
119 JSObject* argument = proxy->target();
120
121 if (argument->type() == ArrayType || argument->type() == DerivedArrayType)
122 return true;
123
124 if (argument->type() != ProxyObjectType)
125 return false;
126
127 proxy = jsCast<ProxyObject*>(argument);
128 }
129
130 ASSERT_NOT_REACHED();
131}
132
133bool isArraySlow(JSGlobalObject* globalObject, ProxyObject* argument)
134{
135 return isArraySlowInline(globalObject, argument);
136}
137
138// ES6 7.2.2
139// https://tc39.github.io/ecma262/#sec-isarray
140EncodedJSValue JSC_HOST_CALL arrayConstructorPrivateFuncIsArraySlow(JSGlobalObject* globalObject, CallFrame* callFrame)
141{
142 ASSERT_UNUSED(globalObject, jsDynamicCast<ProxyObject*>(globalObject->vm(), callFrame->argument(0)));
143 return JSValue::encode(jsBoolean(isArraySlowInline(globalObject, jsCast<ProxyObject*>(callFrame->uncheckedArgument(0)))));
144}
145
146} // namespace JSC
147