PageRenderTime 56ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/src/qt/qtwebkit/Source/JavaScriptCore/runtime/JSArray.cpp

https://gitlab.com/x33n/phantomjs
C++ | 1250 lines | 876 code | 199 blank | 175 comment | 209 complexity | 8db7e45a9071bc64a01ea163e569eb29 MD5 | raw file
  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. * 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 USA
  20. *
  21. */
  22. #include "config.h"
  23. #include "JSArray.h"
  24. #include "ArrayPrototype.h"
  25. #include "ButterflyInlines.h"
  26. #include "CachedCall.h"
  27. #include "CopiedSpace.h"
  28. #include "CopiedSpaceInlines.h"
  29. #include "Error.h"
  30. #include "Executable.h"
  31. #include "GetterSetter.h"
  32. #include "IndexingHeaderInlines.h"
  33. #include "PropertyNameArray.h"
  34. #include "Reject.h"
  35. #include <wtf/AVLTree.h>
  36. #include <wtf/Assertions.h>
  37. #include <wtf/OwnPtr.h>
  38. #include <Operations.h>
  39. using namespace std;
  40. using namespace WTF;
  41. namespace JSC {
  42. ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSArray);
  43. const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSArray)};
  44. Butterfly* createArrayButterflyInDictionaryIndexingMode(VM& vm, unsigned initialLength)
  45. {
  46. Butterfly* butterfly = Butterfly::create(
  47. vm, 0, 0, true, IndexingHeader(), ArrayStorage::sizeFor(0));
  48. ArrayStorage* storage = butterfly->arrayStorage();
  49. storage->setLength(initialLength);
  50. storage->setVectorLength(0);
  51. storage->m_indexBias = 0;
  52. storage->m_sparseMap.clear();
  53. storage->m_numValuesInVector = 0;
  54. return butterfly;
  55. }
  56. void JSArray::setLengthWritable(ExecState* exec, bool writable)
  57. {
  58. ASSERT(isLengthWritable() || !writable);
  59. if (!isLengthWritable() || writable)
  60. return;
  61. enterDictionaryIndexingMode(exec->vm());
  62. SparseArrayValueMap* map = arrayStorage()->m_sparseMap.get();
  63. ASSERT(map);
  64. map->setLengthIsReadOnly();
  65. }
  66. // Defined in ES5.1 15.4.5.1
  67. bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException)
  68. {
  69. JSArray* array = jsCast<JSArray*>(object);
  70. // 3. If P is "length", then
  71. if (propertyName == exec->propertyNames().length) {
  72. // All paths through length definition call the default [[DefineOwnProperty]], hence:
  73. // from ES5.1 8.12.9 7.a.
  74. if (descriptor.configurablePresent() && descriptor.configurable())
  75. return reject(exec, throwException, "Attempting to change configurable attribute of unconfigurable property.");
  76. // from ES5.1 8.12.9 7.b.
  77. if (descriptor.enumerablePresent() && descriptor.enumerable())
  78. return reject(exec, throwException, "Attempting to change enumerable attribute of unconfigurable property.");
  79. // a. If the [[Value]] field of Desc is absent, then
  80. // a.i. Return the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", Desc, and Throw as arguments.
  81. if (descriptor.isAccessorDescriptor())
  82. return reject(exec, throwException, "Attempting to change access mechanism for an unconfigurable property.");
  83. // from ES5.1 8.12.9 10.a.
  84. if (!array->isLengthWritable() && descriptor.writablePresent() && descriptor.writable())
  85. return reject(exec, throwException, "Attempting to change writable attribute of unconfigurable property.");
  86. // This descriptor is either just making length read-only, or changing nothing!
  87. if (!descriptor.value()) {
  88. if (descriptor.writablePresent())
  89. array->setLengthWritable(exec, descriptor.writable());
  90. return true;
  91. }
  92. // b. Let newLenDesc be a copy of Desc.
  93. // c. Let newLen be ToUint32(Desc.[[Value]]).
  94. unsigned newLen = descriptor.value().toUInt32(exec);
  95. // d. If newLen is not equal to ToNumber( Desc.[[Value]]), throw a RangeError exception.
  96. if (newLen != descriptor.value().toNumber(exec)) {
  97. throwError(exec, createRangeError(exec, "Invalid array length"));
  98. return false;
  99. }
  100. // Based on SameValue check in 8.12.9, this is always okay.
  101. if (newLen == array->length()) {
  102. if (descriptor.writablePresent())
  103. array->setLengthWritable(exec, descriptor.writable());
  104. return true;
  105. }
  106. // e. Set newLenDesc.[[Value] to newLen.
  107. // f. If newLen >= oldLen, then
  108. // f.i. Return the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", newLenDesc, and Throw as arguments.
  109. // g. Reject if oldLenDesc.[[Writable]] is false.
  110. if (!array->isLengthWritable())
  111. return reject(exec, throwException, "Attempting to change value of a readonly property.");
  112. // h. If newLenDesc.[[Writable]] is absent or has the value true, let newWritable be true.
  113. // i. Else,
  114. // i.i. Need to defer setting the [[Writable]] attribute to false in case any elements cannot be deleted.
  115. // i.ii. Let newWritable be false.
  116. // i.iii. Set newLenDesc.[[Writable] to true.
  117. // j. Let succeeded be the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", newLenDesc, and Throw as arguments.
  118. // k. If succeeded is false, return false.
  119. // l. While newLen < oldLen repeat,
  120. // l.i. Set oldLen to oldLen – 1.
  121. // l.ii. Let deleteSucceeded be the result of calling the [[Delete]] internal method of A passing ToString(oldLen) and false as arguments.
  122. // l.iii. If deleteSucceeded is false, then
  123. if (!array->setLength(exec, newLen, throwException)) {
  124. // 1. Set newLenDesc.[[Value] to oldLen+1.
  125. // 2. If newWritable is false, set newLenDesc.[[Writable] to false.
  126. // 3. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", newLenDesc, and false as arguments.
  127. // 4. Reject.
  128. if (descriptor.writablePresent())
  129. array->setLengthWritable(exec, descriptor.writable());
  130. return false;
  131. }
  132. // m. If newWritable is false, then
  133. // i. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length",
  134. // Property Descriptor{[[Writable]]: false}, and false as arguments. This call will always
  135. // return true.
  136. if (descriptor.writablePresent())
  137. array->setLengthWritable(exec, descriptor.writable());
  138. // n. Return true.
  139. return true;
  140. }
  141. // 4. Else if P is an array index (15.4), then
  142. // a. Let index be ToUint32(P).
  143. unsigned index = propertyName.asIndex();
  144. if (index != PropertyName::NotAnIndex) {
  145. // b. Reject if index >= oldLen and oldLenDesc.[[Writable]] is false.
  146. if (index >= array->length() && !array->isLengthWritable())
  147. return reject(exec, throwException, "Attempting to define numeric property on array with non-writable length property.");
  148. // c. Let succeeded be the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing P, Desc, and false as arguments.
  149. // d. Reject if succeeded is false.
  150. // e. If index >= oldLen
  151. // e.i. Set oldLenDesc.[[Value]] to index + 1.
  152. // e.ii. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", oldLenDesc, and false as arguments. This call will always return true.
  153. // f. Return true.
  154. return array->defineOwnIndexedProperty(exec, index, descriptor, throwException);
  155. }
  156. return array->JSObject::defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException);
  157. }
  158. bool JSArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
  159. {
  160. JSArray* thisObject = jsCast<JSArray*>(cell);
  161. if (propertyName == exec->propertyNames().length) {
  162. slot.setValue(jsNumber(thisObject->length()));
  163. return true;
  164. }
  165. return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
  166. }
  167. bool JSArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
  168. {
  169. JSArray* thisObject = jsCast<JSArray*>(object);
  170. if (propertyName == exec->propertyNames().length) {
  171. descriptor.setDescriptor(jsNumber(thisObject->length()), thisObject->isLengthWritable() ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly);
  172. return true;
  173. }
  174. return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
  175. }
  176. // ECMA 15.4.5.1
  177. void JSArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
  178. {
  179. JSArray* thisObject = jsCast<JSArray*>(cell);
  180. if (propertyName == exec->propertyNames().length) {
  181. unsigned newLength = value.toUInt32(exec);
  182. if (value.toNumber(exec) != static_cast<double>(newLength)) {
  183. throwError(exec, createRangeError(exec, ASCIILiteral("Invalid array length")));
  184. return;
  185. }
  186. thisObject->setLength(exec, newLength, slot.isStrictMode());
  187. return;
  188. }
  189. JSObject::put(thisObject, exec, propertyName, value, slot);
  190. }
  191. bool JSArray::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
  192. {
  193. JSArray* thisObject = jsCast<JSArray*>(cell);
  194. if (propertyName == exec->propertyNames().length)
  195. return false;
  196. return JSObject::deleteProperty(thisObject, exec, propertyName);
  197. }
  198. static int compareKeysForQSort(const void* a, const void* b)
  199. {
  200. unsigned da = *static_cast<const unsigned*>(a);
  201. unsigned db = *static_cast<const unsigned*>(b);
  202. return (da > db) - (da < db);
  203. }
  204. void JSArray::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
  205. {
  206. JSArray* thisObject = jsCast<JSArray*>(object);
  207. if (mode == IncludeDontEnumProperties)
  208. propertyNames.add(exec->propertyNames().length);
  209. JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
  210. }
  211. // This method makes room in the vector, but leaves the new space for count slots uncleared.
  212. bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count)
  213. {
  214. ArrayStorage* storage = ensureArrayStorage(vm);
  215. Butterfly* butterfly = storage->butterfly();
  216. unsigned propertyCapacity = structure()->outOfLineCapacity();
  217. unsigned propertySize = structure()->outOfLineSize();
  218. // If not, we should have handled this on the fast path.
  219. ASSERT(!addToFront || count > storage->m_indexBias);
  220. // Step 1:
  221. // Gather 4 key metrics:
  222. // * usedVectorLength - how many entries are currently in the vector (conservative estimate - fewer may be in use in sparse vectors).
  223. // * requiredVectorLength - how many entries are will there be in the vector, after allocating space for 'count' more.
  224. // * currentCapacity - what is the current size of the vector, including any pre-capacity.
  225. // * desiredCapacity - how large should we like to grow the vector to - based on 2x requiredVectorLength.
  226. unsigned length = storage->length();
  227. unsigned usedVectorLength = min(storage->vectorLength(), length);
  228. ASSERT(usedVectorLength <= MAX_STORAGE_VECTOR_LENGTH);
  229. // Check that required vector length is possible, in an overflow-safe fashion.
  230. if (count > MAX_STORAGE_VECTOR_LENGTH - usedVectorLength)
  231. return false;
  232. unsigned requiredVectorLength = usedVectorLength + count;
  233. ASSERT(requiredVectorLength <= MAX_STORAGE_VECTOR_LENGTH);
  234. // The sum of m_vectorLength and m_indexBias will never exceed MAX_STORAGE_VECTOR_LENGTH.
  235. ASSERT(storage->vectorLength() <= MAX_STORAGE_VECTOR_LENGTH && (MAX_STORAGE_VECTOR_LENGTH - storage->vectorLength()) >= storage->m_indexBias);
  236. unsigned currentCapacity = storage->vectorLength() + storage->m_indexBias;
  237. // The calculation of desiredCapacity won't overflow, due to the range of MAX_STORAGE_VECTOR_LENGTH.
  238. unsigned desiredCapacity = min(MAX_STORAGE_VECTOR_LENGTH, max(BASE_VECTOR_LEN, requiredVectorLength) << 1);
  239. // Step 2:
  240. // We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing one.
  241. void* newAllocBase = 0;
  242. unsigned newStorageCapacity;
  243. // If the current storage array is sufficiently large (but not too large!) then just keep using it.
  244. if (currentCapacity > desiredCapacity && isDenseEnoughForVector(currentCapacity, requiredVectorLength)) {
  245. newAllocBase = butterfly->base(structure());
  246. newStorageCapacity = currentCapacity;
  247. } else {
  248. size_t newSize = Butterfly::totalSize(0, propertyCapacity, true, ArrayStorage::sizeFor(desiredCapacity));
  249. if (!vm.heap.tryAllocateStorage(newSize, &newAllocBase))
  250. return false;
  251. newStorageCapacity = desiredCapacity;
  252. }
  253. // Step 3:
  254. // Work out where we're going to move things to.
  255. // Determine how much of the vector to use as pre-capacity, and how much as post-capacity.
  256. // If we're adding to the end, we'll add all the new space to the end.
  257. // If the vector had no free post-capacity (length >= m_vectorLength), don't give it any.
  258. // If it did, we calculate the amount that will remain based on an atomic decay - leave the
  259. // vector with half the post-capacity it had previously.
  260. unsigned postCapacity = 0;
  261. if (!addToFront)
  262. postCapacity = max(newStorageCapacity - requiredVectorLength, count);
  263. else if (length < storage->vectorLength()) {
  264. // Atomic decay, + the post-capacity cannot be greater than what is available.
  265. postCapacity = min((storage->vectorLength() - length) >> 1, newStorageCapacity - requiredVectorLength);
  266. // If we're moving contents within the same allocation, the post-capacity is being reduced.
  267. ASSERT(newAllocBase != butterfly->base(structure()) || postCapacity < storage->vectorLength() - length);
  268. }
  269. unsigned newVectorLength = requiredVectorLength + postCapacity;
  270. unsigned newIndexBias = newStorageCapacity - newVectorLength;
  271. Butterfly* newButterfly = Butterfly::fromBase(newAllocBase, newIndexBias, propertyCapacity);
  272. if (addToFront) {
  273. ASSERT(count + usedVectorLength <= newVectorLength);
  274. memmove(newButterfly->arrayStorage()->m_vector + count, storage->m_vector, sizeof(JSValue) * usedVectorLength);
  275. memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0));
  276. } else if ((newAllocBase != butterfly->base(structure())) || (newIndexBias != storage->m_indexBias)) {
  277. memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0));
  278. memmove(newButterfly->arrayStorage()->m_vector, storage->m_vector, sizeof(JSValue) * usedVectorLength);
  279. WriteBarrier<Unknown>* newVector = newButterfly->arrayStorage()->m_vector;
  280. for (unsigned i = requiredVectorLength; i < newVectorLength; i++)
  281. newVector[i].clear();
  282. }
  283. newButterfly->arrayStorage()->setVectorLength(newVectorLength);
  284. newButterfly->arrayStorage()->m_indexBias = newIndexBias;
  285. m_butterfly = newButterfly;
  286. return true;
  287. }
  288. bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, bool throwException, ArrayStorage* storage)
  289. {
  290. unsigned length = storage->length();
  291. // If the length is read only then we enter sparse mode, so should enter the following 'if'.
  292. ASSERT(isLengthWritable() || storage->m_sparseMap);
  293. if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
  294. // Fail if the length is not writable.
  295. if (map->lengthIsReadOnly())
  296. return reject(exec, throwException, StrictModeReadonlyPropertyWriteError);
  297. if (newLength < length) {
  298. // Copy any keys we might be interested in into a vector.
  299. Vector<unsigned, 0, UnsafeVectorOverflow> keys;
  300. keys.reserveInitialCapacity(min(map->size(), static_cast<size_t>(length - newLength)));
  301. SparseArrayValueMap::const_iterator end = map->end();
  302. for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
  303. unsigned index = static_cast<unsigned>(it->key);
  304. if (index < length && index >= newLength)
  305. keys.append(index);
  306. }
  307. // Check if the array is in sparse mode. If so there may be non-configurable
  308. // properties, so we have to perform deletion with caution, if not we can
  309. // delete values in any order.
  310. if (map->sparseMode()) {
  311. qsort(keys.begin(), keys.size(), sizeof(unsigned), compareKeysForQSort);
  312. unsigned i = keys.size();
  313. while (i) {
  314. unsigned index = keys[--i];
  315. SparseArrayValueMap::iterator it = map->find(index);
  316. ASSERT(it != map->notFound());
  317. if (it->value.attributes & DontDelete) {
  318. storage->setLength(index + 1);
  319. return reject(exec, throwException, "Unable to delete property.");
  320. }
  321. map->remove(it);
  322. }
  323. } else {
  324. for (unsigned i = 0; i < keys.size(); ++i)
  325. map->remove(keys[i]);
  326. if (map->isEmpty())
  327. deallocateSparseIndexMap();
  328. }
  329. }
  330. }
  331. if (newLength < length) {
  332. // Delete properties from the vector.
  333. unsigned usedVectorLength = min(length, storage->vectorLength());
  334. for (unsigned i = newLength; i < usedVectorLength; ++i) {
  335. WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
  336. bool hadValue = valueSlot;
  337. valueSlot.clear();
  338. storage->m_numValuesInVector -= hadValue;
  339. }
  340. }
  341. storage->setLength(newLength);
  342. return true;
  343. }
  344. bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException)
  345. {
  346. switch (structure()->indexingType()) {
  347. case ArrayClass:
  348. if (!newLength)
  349. return true;
  350. if (newLength >= MIN_SPARSE_ARRAY_INDEX) {
  351. return setLengthWithArrayStorage(
  352. exec, newLength, throwException,
  353. convertContiguousToArrayStorage(exec->vm()));
  354. }
  355. createInitialUndecided(exec->vm(), newLength);
  356. return true;
  357. case ArrayWithUndecided:
  358. case ArrayWithInt32:
  359. case ArrayWithDouble:
  360. case ArrayWithContiguous:
  361. if (newLength == m_butterfly->publicLength())
  362. return true;
  363. if (newLength >= MAX_ARRAY_INDEX // This case ensures that we can do fast push.
  364. || (newLength >= MIN_SPARSE_ARRAY_INDEX
  365. && !isDenseEnoughForVector(newLength, countElements()))) {
  366. return setLengthWithArrayStorage(
  367. exec, newLength, throwException,
  368. ensureArrayStorage(exec->vm()));
  369. }
  370. if (newLength > m_butterfly->publicLength()) {
  371. ensureLength(exec->vm(), newLength);
  372. return true;
  373. }
  374. if (structure()->indexingType() == ArrayWithDouble) {
  375. for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
  376. m_butterfly->contiguousDouble()[i] = QNaN;
  377. } else {
  378. for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
  379. m_butterfly->contiguous()[i].clear();
  380. }
  381. m_butterfly->setPublicLength(newLength);
  382. return true;
  383. case ArrayWithArrayStorage:
  384. case ArrayWithSlowPutArrayStorage:
  385. return setLengthWithArrayStorage(exec, newLength, throwException, arrayStorage());
  386. default:
  387. CRASH();
  388. return false;
  389. }
  390. }
  391. JSValue JSArray::pop(ExecState* exec)
  392. {
  393. switch (structure()->indexingType()) {
  394. case ArrayClass:
  395. return jsUndefined();
  396. case ArrayWithUndecided:
  397. if (!m_butterfly->publicLength())
  398. return jsUndefined();
  399. // We have nothing but holes. So, drop down to the slow version.
  400. break;
  401. case ArrayWithInt32:
  402. case ArrayWithContiguous: {
  403. unsigned length = m_butterfly->publicLength();
  404. if (!length--)
  405. return jsUndefined();
  406. RELEASE_ASSERT(length < m_butterfly->vectorLength());
  407. JSValue value = m_butterfly->contiguous()[length].get();
  408. if (value) {
  409. m_butterfly->contiguous()[length].clear();
  410. m_butterfly->setPublicLength(length);
  411. return value;
  412. }
  413. break;
  414. }
  415. case ArrayWithDouble: {
  416. unsigned length = m_butterfly->publicLength();
  417. if (!length--)
  418. return jsUndefined();
  419. RELEASE_ASSERT(length < m_butterfly->vectorLength());
  420. double value = m_butterfly->contiguousDouble()[length];
  421. if (value == value) {
  422. m_butterfly->contiguousDouble()[length] = QNaN;
  423. m_butterfly->setPublicLength(length);
  424. return JSValue(JSValue::EncodeAsDouble, value);
  425. }
  426. break;
  427. }
  428. case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
  429. ArrayStorage* storage = m_butterfly->arrayStorage();
  430. unsigned length = storage->length();
  431. if (!length) {
  432. if (!isLengthWritable())
  433. throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
  434. return jsUndefined();
  435. }
  436. unsigned index = length - 1;
  437. if (index < storage->vectorLength()) {
  438. WriteBarrier<Unknown>& valueSlot = storage->m_vector[index];
  439. if (valueSlot) {
  440. --storage->m_numValuesInVector;
  441. JSValue element = valueSlot.get();
  442. valueSlot.clear();
  443. RELEASE_ASSERT(isLengthWritable());
  444. storage->setLength(index);
  445. return element;
  446. }
  447. }
  448. break;
  449. }
  450. default:
  451. CRASH();
  452. return JSValue();
  453. }
  454. unsigned index = getArrayLength() - 1;
  455. // Let element be the result of calling the [[Get]] internal method of O with argument indx.
  456. JSValue element = get(exec, index);
  457. if (exec->hadException())
  458. return jsUndefined();
  459. // Call the [[Delete]] internal method of O with arguments indx and true.
  460. if (!deletePropertyByIndex(this, exec, index)) {
  461. throwTypeError(exec, "Unable to delete property.");
  462. return jsUndefined();
  463. }
  464. // Call the [[Put]] internal method of O with arguments "length", indx, and true.
  465. setLength(exec, index, true);
  466. // Return element.
  467. return element;
  468. }
  469. // Push & putIndex are almost identical, with two small differences.
  470. // - we always are writing beyond the current array bounds, so it is always necessary to update m_length & m_numValuesInVector.
  471. // - pushing to an array of length 2^32-1 stores the property, but throws a range error.
  472. void JSArray::push(ExecState* exec, JSValue value)
  473. {
  474. switch (structure()->indexingType()) {
  475. case ArrayClass: {
  476. createInitialUndecided(exec->vm(), 0);
  477. // Fall through.
  478. }
  479. case ArrayWithUndecided: {
  480. convertUndecidedForValue(exec->vm(), value);
  481. push(exec, value);
  482. return;
  483. }
  484. case ArrayWithInt32: {
  485. if (!value.isInt32()) {
  486. convertInt32ForValue(exec->vm(), value);
  487. push(exec, value);
  488. return;
  489. }
  490. unsigned length = m_butterfly->publicLength();
  491. ASSERT(length <= m_butterfly->vectorLength());
  492. if (length < m_butterfly->vectorLength()) {
  493. m_butterfly->contiguousInt32()[length].setWithoutWriteBarrier(value);
  494. m_butterfly->setPublicLength(length + 1);
  495. return;
  496. }
  497. if (length > MAX_ARRAY_INDEX) {
  498. methodTable()->putByIndex(this, exec, length, value, true);
  499. if (!exec->hadException())
  500. throwError(exec, createRangeError(exec, "Invalid array length"));
  501. return;
  502. }
  503. putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, length, value);
  504. return;
  505. }
  506. case ArrayWithContiguous: {
  507. unsigned length = m_butterfly->publicLength();
  508. ASSERT(length <= m_butterfly->vectorLength());
  509. if (length < m_butterfly->vectorLength()) {
  510. m_butterfly->contiguous()[length].set(exec->vm(), this, value);
  511. m_butterfly->setPublicLength(length + 1);
  512. return;
  513. }
  514. if (length > MAX_ARRAY_INDEX) {
  515. methodTable()->putByIndex(this, exec, length, value, true);
  516. if (!exec->hadException())
  517. throwError(exec, createRangeError(exec, "Invalid array length"));
  518. return;
  519. }
  520. putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, length, value);
  521. return;
  522. }
  523. case ArrayWithDouble: {
  524. if (!value.isNumber()) {
  525. convertDoubleToContiguous(exec->vm());
  526. push(exec, value);
  527. return;
  528. }
  529. double valueAsDouble = value.asNumber();
  530. if (valueAsDouble != valueAsDouble) {
  531. convertDoubleToContiguous(exec->vm());
  532. push(exec, value);
  533. return;
  534. }
  535. unsigned length = m_butterfly->publicLength();
  536. ASSERT(length <= m_butterfly->vectorLength());
  537. if (length < m_butterfly->vectorLength()) {
  538. m_butterfly->contiguousDouble()[length] = valueAsDouble;
  539. m_butterfly->setPublicLength(length + 1);
  540. return;
  541. }
  542. if (length > MAX_ARRAY_INDEX) {
  543. methodTable()->putByIndex(this, exec, length, value, true);
  544. if (!exec->hadException())
  545. throwError(exec, createRangeError(exec, "Invalid array length"));
  546. return;
  547. }
  548. putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, length, value);
  549. break;
  550. }
  551. case ArrayWithSlowPutArrayStorage: {
  552. unsigned oldLength = length();
  553. if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true)) {
  554. if (!exec->hadException() && oldLength < 0xFFFFFFFFu)
  555. setLength(exec, oldLength + 1, true);
  556. return;
  557. }
  558. // Fall through.
  559. }
  560. case ArrayWithArrayStorage: {
  561. ArrayStorage* storage = m_butterfly->arrayStorage();
  562. // Fast case - push within vector, always update m_length & m_numValuesInVector.
  563. unsigned length = storage->length();
  564. if (length < storage->vectorLength()) {
  565. storage->m_vector[length].set(exec->vm(), this, value);
  566. storage->setLength(length + 1);
  567. ++storage->m_numValuesInVector;
  568. return;
  569. }
  570. // Pushing to an array of invalid length (2^31-1) stores the property, but throws a range error.
  571. if (storage->length() > MAX_ARRAY_INDEX) {
  572. methodTable()->putByIndex(this, exec, storage->length(), value, true);
  573. // Per ES5.1 15.4.4.7 step 6 & 15.4.5.1 step 3.d.
  574. if (!exec->hadException())
  575. throwError(exec, createRangeError(exec, "Invalid array length"));
  576. return;
  577. }
  578. // Handled the same as putIndex.
  579. putByIndexBeyondVectorLengthWithArrayStorage(exec, storage->length(), value, true, storage);
  580. break;
  581. }
  582. default:
  583. RELEASE_ASSERT_NOT_REACHED();
  584. }
  585. }
  586. bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage* storage)
  587. {
  588. unsigned oldLength = storage->length();
  589. RELEASE_ASSERT(count <= oldLength);
  590. // If the array contains holes or is otherwise in an abnormal state,
  591. // use the generic algorithm in ArrayPrototype.
  592. if (oldLength != storage->m_numValuesInVector || inSparseIndexingMode() || shouldUseSlowPut(structure()->indexingType()))
  593. return false;
  594. if (!oldLength)
  595. return true;
  596. unsigned length = oldLength - count;
  597. storage->m_numValuesInVector -= count;
  598. storage->setLength(length);
  599. unsigned vectorLength = storage->vectorLength();
  600. if (!vectorLength)
  601. return true;
  602. if (startIndex >= vectorLength)
  603. return true;
  604. if (startIndex + count > vectorLength)
  605. count = vectorLength - startIndex;
  606. unsigned usedVectorLength = min(vectorLength, oldLength);
  607. vectorLength -= count;
  608. storage->setVectorLength(vectorLength);
  609. if (vectorLength) {
  610. if (startIndex < usedVectorLength - (startIndex + count)) {
  611. if (startIndex) {
  612. memmove(
  613. storage->m_vector + count,
  614. storage->m_vector,
  615. sizeof(JSValue) * startIndex);
  616. }
  617. m_butterfly = m_butterfly->shift(structure(), count);
  618. storage = m_butterfly->arrayStorage();
  619. storage->m_indexBias += count;
  620. } else {
  621. memmove(
  622. storage->m_vector + startIndex,
  623. storage->m_vector + startIndex + count,
  624. sizeof(JSValue) * (usedVectorLength - (startIndex + count)));
  625. for (unsigned i = usedVectorLength - count; i < usedVectorLength; ++i)
  626. storage->m_vector[i].clear();
  627. }
  628. }
  629. return true;
  630. }
  631. bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count)
  632. {
  633. RELEASE_ASSERT(count > 0);
  634. switch (structure()->indexingType()) {
  635. case ArrayClass:
  636. return true;
  637. case ArrayWithUndecided:
  638. // Don't handle this because it's confusing and it shouldn't come up.
  639. return false;
  640. case ArrayWithInt32:
  641. case ArrayWithContiguous: {
  642. unsigned oldLength = m_butterfly->publicLength();
  643. RELEASE_ASSERT(count <= oldLength);
  644. // We may have to walk the entire array to do the shift. We're willing to do
  645. // so only if it's not horribly slow.
  646. if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
  647. return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
  648. unsigned end = oldLength - count;
  649. for (unsigned i = startIndex; i < end; ++i) {
  650. // Storing to a hole is fine since we're still having a good time. But reading
  651. // from a hole is totally not fine, since we might have to read from the proto
  652. // chain.
  653. JSValue v = m_butterfly->contiguous()[i + count].get();
  654. if (UNLIKELY(!v)) {
  655. // The purpose of this path is to ensure that we don't make the same
  656. // mistake in the future: shiftCountWithArrayStorage() can't do anything
  657. // about holes (at least for now), but it can detect them quickly. So
  658. // we convert to array storage and then allow the array storage path to
  659. // figure it out.
  660. return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
  661. }
  662. // No need for a barrier since we're just moving data around in the same vector.
  663. // This is in line with our standing assumption that we won't have a deletion
  664. // barrier.
  665. m_butterfly->contiguous()[i].setWithoutWriteBarrier(v);
  666. }
  667. for (unsigned i = end; i < oldLength; ++i)
  668. m_butterfly->contiguous()[i].clear();
  669. m_butterfly->setPublicLength(oldLength - count);
  670. return true;
  671. }
  672. case ArrayWithDouble: {
  673. unsigned oldLength = m_butterfly->publicLength();
  674. RELEASE_ASSERT(count <= oldLength);
  675. // We may have to walk the entire array to do the shift. We're willing to do
  676. // so only if it's not horribly slow.
  677. if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
  678. return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
  679. unsigned end = oldLength - count;
  680. for (unsigned i = startIndex; i < end; ++i) {
  681. // Storing to a hole is fine since we're still having a good time. But reading
  682. // from a hole is totally not fine, since we might have to read from the proto
  683. // chain.
  684. double v = m_butterfly->contiguousDouble()[i + count];
  685. if (UNLIKELY(v != v)) {
  686. // The purpose of this path is to ensure that we don't make the same
  687. // mistake in the future: shiftCountWithArrayStorage() can't do anything
  688. // about holes (at least for now), but it can detect them quickly. So
  689. // we convert to array storage and then allow the array storage path to
  690. // figure it out.
  691. return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
  692. }
  693. // No need for a barrier since we're just moving data around in the same vector.
  694. // This is in line with our standing assumption that we won't have a deletion
  695. // barrier.
  696. m_butterfly->contiguousDouble()[i] = v;
  697. }
  698. for (unsigned i = end; i < oldLength; ++i)
  699. m_butterfly->contiguousDouble()[i] = QNaN;
  700. m_butterfly->setPublicLength(oldLength - count);
  701. return true;
  702. }
  703. case ArrayWithArrayStorage:
  704. case ArrayWithSlowPutArrayStorage:
  705. return shiftCountWithArrayStorage(startIndex, count, arrayStorage());
  706. default:
  707. CRASH();
  708. return false;
  709. }
  710. }
  711. // Returns true if the unshift can be handled, false to fallback.
  712. bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, unsigned count, ArrayStorage* storage)
  713. {
  714. unsigned length = storage->length();
  715. RELEASE_ASSERT(startIndex <= length);
  716. // If the array contains holes or is otherwise in an abnormal state,
  717. // use the generic algorithm in ArrayPrototype.
  718. if (length != storage->m_numValuesInVector || storage->inSparseMode() || shouldUseSlowPut(structure()->indexingType()))
  719. return false;
  720. bool moveFront = !startIndex || startIndex < length / 2;
  721. unsigned vectorLength = storage->vectorLength();
  722. if (moveFront && storage->m_indexBias >= count) {
  723. m_butterfly = storage->butterfly()->unshift(structure(), count);
  724. storage = m_butterfly->arrayStorage();
  725. storage->m_indexBias -= count;
  726. storage->setVectorLength(vectorLength + count);
  727. } else if (!moveFront && vectorLength - length >= count)
  728. storage = storage->butterfly()->arrayStorage();
  729. else if (unshiftCountSlowCase(exec->vm(), moveFront, count))
  730. storage = arrayStorage();
  731. else {
  732. throwOutOfMemoryError(exec);
  733. return true;
  734. }
  735. WriteBarrier<Unknown>* vector = storage->m_vector;
  736. if (startIndex) {
  737. if (moveFront)
  738. memmove(vector, vector + count, startIndex * sizeof(JSValue));
  739. else if (length - startIndex)
  740. memmove(vector + startIndex + count, vector + startIndex, (length - startIndex) * sizeof(JSValue));
  741. }
  742. for (unsigned i = 0; i < count; i++)
  743. vector[i + startIndex].clear();
  744. return true;
  745. }
  746. bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count)
  747. {
  748. switch (structure()->indexingType()) {
  749. case ArrayClass:
  750. case ArrayWithUndecided:
  751. // We could handle this. But it shouldn't ever come up, so we won't.
  752. return false;
  753. case ArrayWithInt32:
  754. case ArrayWithContiguous: {
  755. unsigned oldLength = m_butterfly->publicLength();
  756. // We may have to walk the entire array to do the unshift. We're willing to do so
  757. // only if it's not horribly slow.
  758. if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX)
  759. return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
  760. ensureLength(exec->vm(), oldLength + count);
  761. for (unsigned i = oldLength; i-- > startIndex;) {
  762. JSValue v = m_butterfly->contiguous()[i].get();
  763. if (UNLIKELY(!v))
  764. return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
  765. m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v);
  766. }
  767. // NOTE: we're leaving being garbage in the part of the array that we shifted out
  768. // of. This is fine because the caller is required to store over that area, and
  769. // in contiguous mode storing into a hole is guaranteed to behave exactly the same
  770. // as storing over an existing element.
  771. return true;
  772. }
  773. case ArrayWithDouble: {
  774. unsigned oldLength = m_butterfly->publicLength();
  775. // We may have to walk the entire array to do the unshift. We're willing to do so
  776. // only if it's not horribly slow.
  777. if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX)
  778. return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
  779. ensureLength(exec->vm(), oldLength + count);
  780. for (unsigned i = oldLength; i-- > startIndex;) {
  781. double v = m_butterfly->contiguousDouble()[i];
  782. if (UNLIKELY(v != v))
  783. return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
  784. m_butterfly->contiguousDouble()[i + count] = v;
  785. }
  786. // NOTE: we're leaving being garbage in the part of the array that we shifted out
  787. // of. This is fine because the caller is required to store over that area, and
  788. // in contiguous mode storing into a hole is guaranteed to behave exactly the same
  789. // as storing over an existing element.
  790. return true;
  791. }
  792. case ArrayWithArrayStorage:
  793. case ArrayWithSlowPutArrayStorage:
  794. return unshiftCountWithArrayStorage(exec, startIndex, count, arrayStorage());
  795. default:
  796. CRASH();
  797. return false;
  798. }
  799. }
  800. static int compareNumbersForQSortWithInt32(const void* a, const void* b)
  801. {
  802. int32_t ia = static_cast<const JSValue*>(a)->asInt32();
  803. int32_t ib = static_cast<const JSValue*>(b)->asInt32();
  804. return ia - ib;
  805. }
  806. static int compareNumbersForQSortWithDouble(const void* a, const void* b)
  807. {
  808. double da = *static_cast<const double*>(a);
  809. double db = *static_cast<const double*>(b);
  810. return (da > db) - (da < db);
  811. }
  812. static int compareNumbersForQSort(const void* a, const void* b)
  813. {
  814. double da = static_cast<const JSValue*>(a)->asNumber();
  815. double db = static_cast<const JSValue*>(b)->asNumber();
  816. return (da > db) - (da < db);
  817. }
  818. static int compareByStringPairForQSort(const void* a, const void* b)
  819. {
  820. const ValueStringPair* va = static_cast<const ValueStringPair*>(a);
  821. const ValueStringPair* vb = static_cast<const ValueStringPair*>(b);
  822. return codePointCompare(va->second, vb->second);
  823. }
  824. template<IndexingType indexingType>
  825. void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
  826. {
  827. ASSERT(indexingType == ArrayWithInt32 || indexingType == ArrayWithDouble || indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage);
  828. unsigned lengthNotIncludingUndefined;
  829. unsigned newRelevantLength;
  830. compactForSorting<indexingType>(
  831. lengthNotIncludingUndefined,
  832. newRelevantLength);
  833. ContiguousJSValues data = indexingData<indexingType>();
  834. if (indexingType == ArrayWithArrayStorage && arrayStorage()->m_sparseMap.get()) {
  835. throwOutOfMemoryError(exec);
  836. return;
  837. }
  838. if (!lengthNotIncludingUndefined)
  839. return;
  840. bool allValuesAreNumbers = true;
  841. switch (indexingType) {
  842. case ArrayWithInt32:
  843. case ArrayWithDouble:
  844. break;
  845. default:
  846. for (size_t i = 0; i < newRelevantLength; ++i) {
  847. if (!data[i].isNumber()) {
  848. allValuesAreNumbers = false;
  849. break;
  850. }
  851. }
  852. break;
  853. }
  854. if (!allValuesAreNumbers)
  855. return sort(exec, compareFunction, callType, callData);
  856. // For numeric comparison, which is fast, qsort is faster than mergesort. We
  857. // also don't require mergesort's stability, since there's no user visible
  858. // side-effect from swapping the order of equal primitive values.
  859. int (*compare)(const void*, const void*);
  860. switch (indexingType) {
  861. case ArrayWithInt32:
  862. compare = compareNumbersForQSortWithInt32;
  863. break;
  864. case ArrayWithDouble:
  865. compare = compareNumbersForQSortWithDouble;
  866. ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(double));
  867. break;
  868. default:
  869. compare = compareNumbersForQSort;
  870. break;
  871. }
  872. ASSERT(data.length() >= newRelevantLength);
  873. qsort(data.data(), newRelevantLength, sizeof(WriteBarrier<Unknown>), compare);
  874. return;
  875. }
  876. void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
  877. {
  878. ASSERT(!inSparseIndexingMode());
  879. switch (structure()->indexingType()) {
  880. case ArrayClass:
  881. return;
  882. case ArrayWithInt32:
  883. sortNumericVector<ArrayWithInt32>(exec, compareFunction, callType, callData);
  884. break;
  885. case ArrayWithDouble:
  886. sortNumericVector<ArrayWithDouble>(exec, compareFunction, callType, callData);
  887. break;
  888. case ArrayWithContiguous:
  889. sortNumericVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
  890. return;
  891. case ArrayWithArrayStorage:
  892. sortNumericVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData);
  893. return;
  894. default:
  895. CRASH();
  896. return;
  897. }
  898. }
  899. template <IndexingType> struct ContiguousTypeAccessor {
  900. typedef WriteBarrier<Unknown> Type;
  901. static JSValue getAsValue(ContiguousData<Type> data, size_t i) { return data[i].get(); }
  902. static void setWithValue(VM& vm, JSArray* thisValue, ContiguousData<Type> data, size_t i, JSValue value)
  903. {
  904. data[i].set(vm, thisValue, value);
  905. }
  906. static void replaceDataReference(ContiguousData<Type>* outData, ContiguousJSValues inData)
  907. {
  908. *outData = inData;
  909. }
  910. };
  911. template <> struct ContiguousTypeAccessor<ArrayWithDouble> {
  912. typedef double Type;
  913. static JSValue getAsValue(ContiguousData<Type> data, size_t i) { ASSERT(data[i] == data[i]); return JSValue(JSValue::EncodeAsDouble, data[i]); }
  914. static void setWithValue(VM&, JSArray*, ContiguousData<Type> data, size_t i, JSValue value)
  915. {
  916. data[i] = value.asNumber();
  917. }
  918. static NO_RETURN_DUE_TO_CRASH void replaceDataReference(ContiguousData<Type>*, ContiguousJSValues)
  919. {
  920. RELEASE_ASSERT_WITH_MESSAGE(0, "Inconsistent indexing types during compact array sort.");
  921. }
  922. };
  923. template<IndexingType indexingType, typename StorageType>
  924. void JSArray::sortCompactedVector(ExecState* exec, ContiguousData<StorageType> data, unsigned relevantLength)
  925. {
  926. if (!relevantLength)
  927. return;
  928. VM& vm = exec->vm();
  929. // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.
  930. // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary
  931. // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return
  932. // random or otherwise changing results, effectively making compare function inconsistent.
  933. Vector<ValueStringPair, 0, UnsafeVectorOverflow> values(relevantLength);
  934. if (!values.begin()) {
  935. throwOutOfMemoryError(exec);
  936. return;
  937. }
  938. Heap::heap(this)->pushTempSortVector(&values);
  939. bool isSortingPrimitiveValues = true;
  940. for (size_t i = 0; i < relevantLength; i++) {
  941. JSValue value = ContiguousTypeAccessor<indexingType>::getAsValue(data, i);
  942. ASSERT(indexingType != ArrayWithInt32 || value.isInt32());
  943. ASSERT(!value.isUndefined());
  944. values[i].first = value;
  945. if (indexingType != ArrayWithDouble && indexingType != ArrayWithInt32)
  946. isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
  947. }
  948. // FIXME: The following loop continues to call toString on subsequent values even after
  949. // a toString call raises an exception.
  950. for (size_t i = 0; i < relevantLength; i++)
  951. values[i].second = values[i].first.toWTFStringInline(exec);
  952. if (exec->hadException()) {
  953. Heap::heap(this)->popTempSortVector(&values);
  954. return;
  955. }
  956. // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
  957. // than O(N log N).
  958. #if HAVE(MERGESORT)
  959. if (isSortingPrimitiveValues)
  960. qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
  961. else
  962. mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
  963. #else
  964. // FIXME: The qsort library function is likely to not be a stable sort.
  965. // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
  966. qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
  967. #endif
  968. // If the toString function changed the length of the array or vector storage,
  969. // increase the length to handle the orignal number of actual values.
  970. switch (indexingType) {
  971. case ArrayWithInt32:
  972. case ArrayWithDouble:
  973. case ArrayWithContiguous:
  974. ensureLength(vm, relevantLength);
  975. break;
  976. case ArrayWithArrayStorage:
  977. if (arrayStorage()->vectorLength() < relevantLength) {
  978. increaseVectorLength(exec->vm(), relevantLength);
  979. ContiguousTypeAccessor<indexingType>::replaceDataReference(&data, arrayStorage()->vector());
  980. }
  981. if (arrayStorage()->length() < relevantLength)
  982. arrayStorage()->setLength(relevantLength);
  983. break;
  984. default:
  985. CRASH();
  986. }
  987. for (size_t i = 0; i < relevantLength; i++)
  988. ContiguousTypeAccessor<indexingType>::setWithValue(vm, this, data, i, values[i].first);
  989. Heap::heap(this)->popTempSortVector(&values);
  990. }
  991. void JSArray::sort(ExecState* exec)
  992. {
  993. ASSERT(!inSparseIndexingMode());
  994. switch (structure()->indexingType()) {
  995. case ArrayClass:
  996. case ArrayWithUndecided:
  997. return;
  998. case ArrayWithInt32: {
  999. unsigned lengthNotIncludingUndefined;
  1000. unsigned newRelevantLength;
  1001. compactForSorting<ArrayWithInt32>(
  1002. lengthNotIncludingUndefined, newRelevantLength);
  1003. sortCompactedVector<ArrayWithInt32>(
  1004. exec, m_butterfly->contiguousInt32(), lengthNotIncludingUndefined);
  1005. return;
  1006. }
  1007. case ArrayWithDouble: {
  1008. unsigned lengthNotIncludingUndefined;
  1009. unsigned newRelevantLength;
  1010. compactForSorting<ArrayWithDouble>(
  1011. lengthNotIncludingUndefined, newRelevantLength);
  1012. sortCompactedVector<ArrayWithDouble>(
  1013. exec, m_butterfly->contiguousDouble(), lengthNotIncludingUndefined);
  1014. return;
  1015. }
  1016. case ArrayWithContiguous: {
  1017. unsigned lengthNotIncludingUndefined;
  1018. unsigned newRelevantLength;
  1019. compactForSorting<ArrayWithContiguous>(
  1020. lengthNotIncludingUndefined, newRelevantLength);
  1021. sortCompactedVector<ArrayWithContiguous>(
  1022. exec, m_butterfly->contiguous(), lengthNotIncludingUndefined);
  1023. return;
  1024. }
  1025. case ArrayWithArrayStorage: {
  1026. unsigned lengthNotIncludingUndefined;
  1027. unsigned newRelevantLength;
  1028. compactForSorting<ArrayWithArrayStorage>(
  1029. lengthNotIncludingUndefined, newRelevantLength);
  1030. ArrayStorage* storage = m_butterfly->arrayStorage();
  1031. ASSERT(!storage->m_sparseMap);
  1032. sortCompactedVector<ArrayWithArrayStorage>(exec, storage->vector(), lengthNotIncludingUndefined);
  1033. return;
  1034. }
  1035. default:
  1036. RELEASE_ASSERT_NOT_REACHED();
  1037. }
  1038. }
  1039. struct AVLTreeNodeForArrayCompare {
  1040. JSValue value;
  1041. // Child pointers. The high bit of gt is robbed and used as the
  1042. // balance factor sign. The high bit of lt is robbed and used as
  1043. // the magnitude of the balance factor.
  1044. int32_t gt;
  1045. int32_t lt;
  1046. };
  1047. struct AVLTreeAbstractorForArrayCompare {
  1048. typedef int32_t handle; // Handle is an index into m_nodes vector.
  1049. typedef JSValue key;
  1050. typedef int32_t size;
  1051. Vector<AVLTreeNodeForArrayCompare, 0, UnsafeVectorOverflow> m_