| 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, 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 | |
| 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 | 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 | |
| 87 | static 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 | |
| 100 | static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec) |
| 101 | { |
| 102 | ArgList args(exec); |
| 103 | return JSValue::encode(constructArrayWithSizeQuirk(exec, args, exec->newTarget())); |
| 104 | } |
| 105 | |
| 106 | static EncodedJSValue JSC_HOST_CALL callArrayConstructor(ExecState* exec) |
| 107 | { |
| 108 | ArgList args(exec); |
| 109 | return JSValue::encode(constructArrayWithSizeQuirk(exec, args, JSValue())); |
| 110 | } |
| 111 | |
| 112 | static 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 | |
| 136 | bool 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 |
| 143 | EncodedJSValue 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 | |
| 149 | EncodedJSValue 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 | |