/ runtime / ArrayConstructor.cpp
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