JSArray.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
  3. * Copyright (C) 2003, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. *
  19. */
  20. #ifndef JSArray_h
  21. #define JSArray_h
  22. #include "ArrayConventions.h"
  23. #include "ButterflyInlines.h"
  24. #include "JSObject.h"
  25. namespace JSC {
  26. class JSArray;
  27. class LLIntOffsetsExtractor;
  28. class JSArray : public JSNonFinalObject {
  29. friend class LLIntOffsetsExtractor;
  30. friend class Walker;
  31. friend class JIT;
  32. public:
  33. typedef JSNonFinalObject Base;
  34. protected:
  35. explicit JSArray(VM& vm, Structure* structure, Butterfly* butterfly)
  36. : JSNonFinalObject(vm, structure, butterfly)
  37. {
  38. }
  39. public:
  40. static JSArray* create(VM&, Structure*, unsigned initialLength = 0);
  41. // tryCreateUninitialized is used for fast construction of arrays whose size and
  42. // contents are known at time of creation. Clients of this interface must:
  43. // - null-check the result (indicating out of memory, or otherwise unable to allocate vector).
  44. // - call 'initializeIndex' for all properties in sequence, for 0 <= i < initialLength.
  45. static JSArray* tryCreateUninitialized(VM&, Structure*, unsigned initialLength);
  46. JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool throwException);
  47. static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
  48. static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
  49. static JS_EXPORTDATA const ClassInfo s_info;
  50. unsigned length() const { return getArrayLength(); }
  51. // OK to use on new arrays, but not if it might be a RegExpMatchArray.
  52. bool setLength(ExecState*, unsigned, bool throwException = false);
  53. void sort(ExecState*);
  54. void sort(ExecState*, JSValue compareFunction, CallType, const CallData&);
  55. void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&);
  56. void push(ExecState*, JSValue);
  57. JSValue pop(ExecState*);
  58. enum ShiftCountMode {
  59. // This form of shift hints that we're doing queueing. With this assumption in hand,
  60. // we convert to ArrayStorage, which has queue optimizations.
  61. ShiftCountForShift,
  62. // This form of shift hints that we're just doing care and feeding on an array that
  63. // is probably typically used for ordinary accesses. With this assumption in hand,
  64. // we try to preserve whatever indexing type it has already.
  65. ShiftCountForSplice
  66. };
  67. bool shiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count)
  68. {
  69. return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
  70. }
  71. bool shiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count)
  72. {
  73. return shiftCountWithAnyIndexingType(exec, startIndex, count);
  74. }
  75. template<ShiftCountMode shiftCountMode>
  76. bool shiftCount(ExecState* exec, unsigned startIndex, unsigned count)
  77. {
  78. switch (shiftCountMode) {
  79. case ShiftCountForShift:
  80. return shiftCountForShift(exec, startIndex, count);
  81. case ShiftCountForSplice:
  82. return shiftCountForSplice(exec, startIndex, count);
  83. default:
  84. CRASH();
  85. return false;
  86. }
  87. }
  88. bool unshiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count)
  89. {
  90. return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
  91. }
  92. bool unshiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count)
  93. {
  94. return unshiftCountWithAnyIndexingType(exec, startIndex, count);
  95. }
  96. template<ShiftCountMode shiftCountMode>
  97. bool unshiftCount(ExecState* exec, unsigned startIndex, unsigned count)
  98. {
  99. switch (shiftCountMode) {
  100. case ShiftCountForShift:
  101. return unshiftCountForShift(exec, startIndex, count);
  102. case ShiftCountForSplice:
  103. return unshiftCountForSplice(exec, startIndex, count);
  104. default:
  105. CRASH();
  106. return false;
  107. }
  108. }
  109. void fillArgList(ExecState*, MarkedArgumentBuffer&);
  110. void copyToArguments(ExecState*, CallFrame*, uint32_t length);
  111. static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType)
  112. {
  113. return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, indexingType);
  114. }
  115. protected:
  116. static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
  117. static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
  118. static bool deleteProperty(JSCell*, ExecState*, PropertyName);
  119. JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
  120. private:
  121. bool isLengthWritable()
  122. {
  123. ArrayStorage* storage = arrayStorageOrNull();
  124. if (!storage)
  125. return true;
  126. SparseArrayValueMap* map = storage->m_sparseMap.get();
  127. return !map || !map->lengthIsReadOnly();
  128. }
  129. bool shiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count);
  130. bool shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage*);
  131. bool unshiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count);
  132. bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*);
  133. bool unshiftCountSlowCase(VM&, bool, unsigned);
  134. template<IndexingType indexingType>
  135. void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
  136. template<IndexingType indexingType, typename StorageType>
  137. void sortCompactedVector(ExecState*, ContiguousData<StorageType>, unsigned relevantLength);
  138. template<IndexingType indexingType>
  139. void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
  140. bool setLengthWithArrayStorage(ExecState*, unsigned newLength, bool throwException, ArrayStorage*);
  141. void setLengthWritable(ExecState*, bool writable);
  142. template<IndexingType indexingType>
  143. void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength);
  144. template<IndexingType indexingType, typename StorageType>
  145. ContiguousData<StorageType> storage();
  146. };
  147. inline Butterfly* createContiguousArrayButterfly(VM& vm, unsigned length, unsigned& vectorLength)
  148. {
  149. IndexingHeader header;
  150. vectorLength = std::max(length, BASE_VECTOR_LEN);
  151. header.setVectorLength(vectorLength);
  152. header.setPublicLength(length);
  153. Butterfly* result = Butterfly::create(
  154. vm, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue));
  155. return result;
  156. }
  157. inline Butterfly* createArrayButterfly(VM& vm, unsigned initialLength)
  158. {
  159. Butterfly* butterfly = Butterfly::create(
  160. vm, 0, 0, true, baseIndexingHeaderForArray(initialLength), ArrayStorage::sizeFor(BASE_VECTOR_LEN));
  161. ArrayStorage* storage = butterfly->arrayStorage();
  162. storage->m_indexBias = 0;
  163. storage->m_sparseMap.clear();
  164. storage->m_numValuesInVector = 0;
  165. return butterfly;
  166. }
  167. Butterfly* createArrayButterflyInDictionaryIndexingMode(VM&, unsigned initialLength);
  168. inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLength)
  169. {
  170. Butterfly* butterfly;
  171. if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
  172. ASSERT(
  173. hasUndecided(structure->indexingType())
  174. || hasInt32(structure->indexingType())
  175. || hasDouble(structure->indexingType())
  176. || hasContiguous(structure->indexingType()));
  177. unsigned vectorLength;
  178. butterfly = createContiguousArrayButterfly(vm, initialLength, vectorLength);
  179. ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX);
  180. if (hasDouble(structure->indexingType())) {
  181. for (unsigned i = 0; i < vectorLength; ++i)
  182. butterfly->contiguousDouble()[i] = QNaN;
  183. }
  184. } else {
  185. ASSERT(
  186. structure->indexingType() == ArrayWithSlowPutArrayStorage
  187. || structure->indexingType() == ArrayWithArrayStorage);
  188. butterfly = createArrayButterfly(vm, initialLength);
  189. }
  190. JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly);
  191. array->finishCreation(vm);
  192. return array;
  193. }
  194. inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, unsigned initialLength)
  195. {
  196. unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength);
  197. if (vectorLength > MAX_STORAGE_VECTOR_LENGTH)
  198. return 0;
  199. Butterfly* butterfly;
  200. if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
  201. ASSERT(
  202. hasUndecided(structure->indexingType())
  203. || hasInt32(structure->indexingType())
  204. || hasDouble(structure->indexingType())
  205. || hasContiguous(structure->indexingType()));
  206. void* temp;
  207. if (!vm.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp))
  208. return 0;
  209. butterfly = Butterfly::fromBase(temp, 0, 0);
  210. butterfly->setVectorLength(vectorLength);
  211. butterfly->setPublicLength(initialLength);
  212. if (hasDouble(structure->indexingType())) {
  213. for (unsigned i = initialLength; i < vectorLength; ++i)
  214. butterfly->contiguousDouble()[i] = QNaN;
  215. }
  216. } else {
  217. void* temp;
  218. if (!vm.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp))
  219. return 0;
  220. butterfly = Butterfly::fromBase(temp, 0, 0);
  221. *butterfly->indexingHeader() = indexingHeaderForArray(initialLength, vectorLength);
  222. ArrayStorage* storage = butterfly->arrayStorage();
  223. storage->m_indexBias = 0;
  224. storage->m_sparseMap.clear();
  225. storage->m_numValuesInVector = initialLength;
  226. }
  227. JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly);
  228. array->finishCreation(vm);
  229. return array;
  230. }
  231. JSArray* asArray(JSValue);
  232. inline JSArray* asArray(JSCell* cell)
  233. {
  234. ASSERT(cell->inherits(&JSArray::s_info));
  235. return jsCast<JSArray*>(cell);
  236. }
  237. inline JSArray* asArray(JSValue value)
  238. {
  239. return asArray(value.asCell());
  240. }
  241. inline bool isJSArray(JSCell* cell) { DEFINE_STATIC_CLASSINFO(JSArray); return cell->classInfo() == sJSArrayClassInfo; }
  242. inline bool isJSArray(JSValue v) { return v.isCell() && isJSArray(v.asCell()); }
  243. inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const ArgList& values)
  244. {
  245. VM& vm = exec->vm();
  246. unsigned length = values.size();
  247. JSArray* array = JSArray::tryCreateUninitialized(vm, arrayStructure, length);
  248. // FIXME: we should probably throw an out of memory error here, but
  249. // when making this change we should check that all clients of this
  250. // function will correctly handle an exception being thrown from here.
  251. RELEASE_ASSERT(array);
  252. for (unsigned i = 0; i < length; ++i)
  253. array->initializeIndex(vm, i, values.at(i));
  254. return array;
  255. }
  256. inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const JSValue* values, unsigned length)
  257. {
  258. VM& vm = exec->vm();
  259. JSArray* array = JSArray::tryCreateUninitialized(vm, arrayStructure, length);
  260. // FIXME: we should probably throw an out of memory error here, but
  261. // when making this change we should check that all clients of this
  262. // function will correctly handle an exception being thrown from here.
  263. RELEASE_ASSERT(array);
  264. for (unsigned i = 0; i < length; ++i)
  265. array->initializeIndex(vm, i, values[i]);
  266. return array;
  267. }
  268. } // namespace JSC
  269. #endif // JSArray_h