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 "JSCInlines.h" 29 #include "ProxyObject.h" 30 31 #include "ArrayConstructor.lut.h" 32 33 namespace JSC { 34 35 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ArrayConstructor); 36 37 const ClassInfo ArrayConstructor::s_info = { "Function", &InternalFunction::s_info, &arrayConstructorTable, nullptr, CREATE_METHOD_TABLE(ArrayConstructor) }; 38 39 /* Source for ArrayConstructor.lut.h 40 @begin arrayConstructorTable 41 of JSBuiltin DontEnum|Function 0 42 from JSBuiltin DontEnum|Function 0 43 @end 44 */ 45 46 static JSC_DECLARE_HOST_FUNCTION(callArrayConstructor); 47 static JSC_DECLARE_HOST_FUNCTION(constructWithArrayConstructor); 48 49 ArrayConstructor::ArrayConstructor(VM& vm, Structure* structure) 50 : InternalFunction(vm, structure, callArrayConstructor, constructWithArrayConstructor) 51 { 52 } 53 54 void ArrayConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, ArrayPrototype* arrayPrototype, GetterSetter* speciesSymbol) 55 { 56 Base::finishCreation(vm, 1, vm.propertyNames->Array.string(), PropertyAdditionMode::WithoutStructureTransition); 57 putDirectWithoutTransition(vm, vm.propertyNames->prototype, arrayPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); 58 putDirectNonIndexAccessorWithoutTransition(vm, vm.propertyNames->speciesSymbol, speciesSymbol, PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum); 59 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->isArray, arrayConstructorIsArrayCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); 60 } 61 62 // ------------------------------ Functions --------------------------- 63 64 JSArray* constructArrayWithSizeQuirk(JSGlobalObject* globalObject, ArrayAllocationProfile* profile, JSValue length, JSValue newTarget) 65 { 66 VM& vm = globalObject->vm(); 67 auto scope = DECLARE_THROW_SCOPE(vm); 68 if (!length.isNumber()) 69 RELEASE_AND_RETURN(scope, constructArrayNegativeIndexed(globalObject, profile, &length, 1, newTarget)); 70 71 uint32_t n = length.toUInt32(globalObject); 72 if (n != length.toNumber(globalObject)) { 73 throwException(globalObject, scope, createRangeError(globalObject, "Array size is not a small enough positive integer."_s)); 74 return nullptr; 75 } 76 RELEASE_AND_RETURN(scope, constructEmptyArray(globalObject, profile, n, newTarget)); 77 } 78 79 static inline JSArray* constructArrayWithSizeQuirk(JSGlobalObject* globalObject, const ArgList& args, JSValue newTarget) 80 { 81 // a single numeric argument denotes the array size (!) 82 if (args.size() == 1) 83 return constructArrayWithSizeQuirk(globalObject, nullptr, args.at(0), newTarget); 84 85 // otherwise the array is constructed with the arguments in it 86 return constructArray(globalObject, static_cast<ArrayAllocationProfile*>(nullptr), args, newTarget); 87 } 88 89 JSC_DEFINE_HOST_FUNCTION(constructWithArrayConstructor, (JSGlobalObject* globalObject, CallFrame* callFrame)) 90 { 91 ArgList args(callFrame); 92 return JSValue::encode(constructArrayWithSizeQuirk(globalObject, args, callFrame->newTarget())); 93 } 94 95 JSC_DEFINE_HOST_FUNCTION(callArrayConstructor, (JSGlobalObject* globalObject, CallFrame* callFrame)) 96 { 97 ArgList args(callFrame); 98 return JSValue::encode(constructArrayWithSizeQuirk(globalObject, args, JSValue())); 99 } 100 101 static ALWAYS_INLINE bool isArraySlowInline(JSGlobalObject* globalObject, ProxyObject* proxy) 102 { 103 VM& vm = globalObject->vm(); 104 auto scope = DECLARE_THROW_SCOPE(vm); 105 106 while (true) { 107 if (proxy->isRevoked()) { 108 throwTypeError(globalObject, scope, "Array.isArray cannot be called on a Proxy that has been revoked"_s); 109 return false; 110 } 111 JSObject* argument = proxy->target(); 112 113 if (argument->type() == ArrayType || argument->type() == DerivedArrayType) 114 return true; 115 116 if (argument->type() != ProxyObjectType) 117 return false; 118 119 proxy = jsCast<ProxyObject*>(argument); 120 } 121 122 ASSERT_NOT_REACHED(); 123 } 124 125 bool isArraySlow(JSGlobalObject* globalObject, ProxyObject* argument) 126 { 127 return isArraySlowInline(globalObject, argument); 128 } 129 130 // ES6 7.2.2 131 // https://tc39.github.io/ecma262/#sec-isarray 132 JSC_DEFINE_HOST_FUNCTION(arrayConstructorPrivateFuncIsArraySlow, (JSGlobalObject* globalObject, CallFrame* callFrame)) 133 { 134 ASSERT_UNUSED(globalObject, jsDynamicCast<ProxyObject*>(globalObject->vm(), callFrame->argument(0))); 135 return JSValue::encode(jsBoolean(isArraySlowInline(globalObject, jsCast<ProxyObject*>(callFrame->uncheckedArgument(0))))); 136 } 137 138 } // namespace JSC