JSArray.cpp 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699
  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 <>
  924. ContiguousJSValues JSArray::storage<ArrayWithInt32, WriteBarrier<Unknown> >()
  925. {
  926. return m_butterfly->contiguousInt32();
  927. }
  928. template <>
  929. ContiguousDoubles JSArray::storage<ArrayWithDouble, double>()
  930. {
  931. return m_butterfly->contiguousDouble();
  932. }
  933. template <>
  934. ContiguousJSValues JSArray::storage<ArrayWithContiguous, WriteBarrier<Unknown> >()
  935. {
  936. return m_butterfly->contiguous();
  937. }
  938. template <>
  939. ContiguousJSValues JSArray::storage<ArrayWithArrayStorage, WriteBarrier<Unknown> >()
  940. {
  941. ArrayStorage* storage = m_butterfly->arrayStorage();
  942. ASSERT(!storage->m_sparseMap);
  943. return storage->vector();
  944. }
  945. template<IndexingType indexingType, typename StorageType>
  946. void JSArray::sortCompactedVector(ExecState* exec, ContiguousData<StorageType> data, unsigned relevantLength)
  947. {
  948. data = storage<indexingType, StorageType>();
  949. if (!relevantLength)
  950. return;
  951. VM& vm = exec->vm();
  952. // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.
  953. // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary
  954. // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return
  955. // random or otherwise changing results, effectively making compare function inconsistent.
  956. Vector<ValueStringPair, 0, UnsafeVectorOverflow> values(relevantLength);
  957. if (!values.begin()) {
  958. throwOutOfMemoryError(exec);
  959. return;
  960. }
  961. Heap::heap(this)->pushTempSortVector(&values);
  962. bool isSortingPrimitiveValues = true;
  963. for (size_t i = 0; i < relevantLength; i++) {
  964. JSValue value = ContiguousTypeAccessor<indexingType>::getAsValue(data, i);
  965. ASSERT(indexingType != ArrayWithInt32 || value.isInt32());
  966. ASSERT(!value.isUndefined());
  967. values[i].first = value;
  968. if (indexingType != ArrayWithDouble && indexingType != ArrayWithInt32)
  969. isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
  970. }
  971. // FIXME: The following loop continues to call toString on subsequent values even after
  972. // a toString call raises an exception.
  973. for (size_t i = 0; i < relevantLength; i++)
  974. values[i].second = values[i].first.toWTFStringInline(exec);
  975. if (exec->hadException()) {
  976. Heap::heap(this)->popTempSortVector(&values);
  977. return;
  978. }
  979. // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
  980. // than O(N log N).
  981. #if HAVE(MERGESORT)
  982. if (isSortingPrimitiveValues)
  983. qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
  984. else
  985. mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
  986. #else
  987. // FIXME: The qsort library function is likely to not be a stable sort.
  988. // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
  989. qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
  990. #endif
  991. // If the toString function changed the length of the array or vector storage,
  992. // increase the length to handle the orignal number of actual values.
  993. switch (indexingType) {
  994. case ArrayWithInt32:
  995. case ArrayWithDouble:
  996. case ArrayWithContiguous:
  997. ensureLength(vm, relevantLength);
  998. break;
  999. case ArrayWithArrayStorage:
  1000. if (arrayStorage()->vectorLength() < relevantLength) {
  1001. increaseVectorLength(exec->vm(), relevantLength);
  1002. ContiguousTypeAccessor<indexingType>::replaceDataReference(&data, arrayStorage()->vector());
  1003. }
  1004. if (arrayStorage()->length() < relevantLength)
  1005. arrayStorage()->setLength(relevantLength);
  1006. break;
  1007. default:
  1008. CRASH();
  1009. }
  1010. data = storage<indexingType, StorageType>();
  1011. for (size_t i = 0; i < relevantLength; i++)
  1012. ContiguousTypeAccessor<indexingType>::setWithValue(vm, this, data, i, values[i].first);
  1013. Heap::heap(this)->popTempSortVector(&values);
  1014. }
  1015. void JSArray::sort(ExecState* exec)
  1016. {
  1017. ASSERT(!inSparseIndexingMode());
  1018. switch (structure()->indexingType()) {
  1019. case ArrayClass:
  1020. case ArrayWithUndecided:
  1021. return;
  1022. case ArrayWithInt32: {
  1023. unsigned lengthNotIncludingUndefined;
  1024. unsigned newRelevantLength;
  1025. compactForSorting<ArrayWithInt32>(
  1026. lengthNotIncludingUndefined, newRelevantLength);
  1027. sortCompactedVector<ArrayWithInt32>(
  1028. exec, m_butterfly->contiguousInt32(), lengthNotIncludingUndefined);
  1029. return;
  1030. }
  1031. case ArrayWithDouble: {
  1032. unsigned lengthNotIncludingUndefined;
  1033. unsigned newRelevantLength;
  1034. compactForSorting<ArrayWithDouble>(
  1035. lengthNotIncludingUndefined, newRelevantLength);
  1036. sortCompactedVector<ArrayWithDouble>(
  1037. exec, m_butterfly->contiguousDouble(), lengthNotIncludingUndefined);
  1038. return;
  1039. }
  1040. case ArrayWithContiguous: {
  1041. unsigned lengthNotIncludingUndefined;
  1042. unsigned newRelevantLength;
  1043. compactForSorting<ArrayWithContiguous>(
  1044. lengthNotIncludingUndefined, newRelevantLength);
  1045. sortCompactedVector<ArrayWithContiguous>(
  1046. exec, m_butterfly->contiguous(), lengthNotIncludingUndefined);
  1047. return;
  1048. }
  1049. case ArrayWithArrayStorage: {
  1050. unsigned lengthNotIncludingUndefined;
  1051. unsigned newRelevantLength;
  1052. compactForSorting<ArrayWithArrayStorage>(
  1053. lengthNotIncludingUndefined, newRelevantLength);
  1054. ArrayStorage* storage = m_butterfly->arrayStorage();
  1055. ASSERT(!storage->m_sparseMap);
  1056. sortCompactedVector<ArrayWithArrayStorage>(exec, storage->vector(), lengthNotIncludingUndefined);
  1057. return;
  1058. }
  1059. default:
  1060. RELEASE_ASSERT_NOT_REACHED();
  1061. }
  1062. }
  1063. struct AVLTreeNodeForArrayCompare {
  1064. JSValue value;
  1065. // Child pointers. The high bit of gt is robbed and used as the
  1066. // balance factor sign. The high bit of lt is robbed and used as
  1067. // the magnitude of the balance factor.
  1068. int32_t gt;
  1069. int32_t lt;
  1070. };
  1071. struct AVLTreeAbstractorForArrayCompare {
  1072. typedef int32_t handle; // Handle is an index into m_nodes vector.
  1073. typedef JSValue key;
  1074. typedef int32_t size;
  1075. Vector<AVLTreeNodeForArrayCompare, 0, UnsafeVectorOverflow> m_nodes;
  1076. ExecState* m_exec;
  1077. JSValue m_compareFunction;
  1078. CallType m_compareCallType;
  1079. const CallData* m_compareCallData;
  1080. OwnPtr<CachedCall> m_cachedCall;
  1081. handle get_less(handle h) { return m_nodes[h].lt & 0x7FFFFFFF; }
  1082. void set_less(handle h, handle lh) { m_nodes[h].lt &= 0x80000000; m_nodes[h].lt |= lh; }
  1083. handle get_greater(handle h) { return m_nodes[h].gt & 0x7FFFFFFF; }
  1084. void set_greater(handle h, handle gh) { m_nodes[h].gt &= 0x80000000; m_nodes[h].gt |= gh; }
  1085. int get_balance_factor(handle h)
  1086. {
  1087. if (m_nodes[h].gt & 0x80000000)
  1088. return -1;
  1089. return static_cast<unsigned>(m_nodes[h].lt) >> 31;
  1090. }
  1091. void set_balance_factor(handle h, int bf)
  1092. {
  1093. if (bf == 0) {
  1094. m_nodes[h].lt &= 0x7FFFFFFF;
  1095. m_nodes[h].gt &= 0x7FFFFFFF;
  1096. } else {
  1097. m_nodes[h].lt |= 0x80000000;
  1098. if (bf < 0)
  1099. m_nodes[h].gt |= 0x80000000;
  1100. else
  1101. m_nodes[h].gt &= 0x7FFFFFFF;
  1102. }
  1103. }
  1104. int compare_key_key(key va, key vb)
  1105. {
  1106. ASSERT(!va.isUndefined());
  1107. ASSERT(!vb.isUndefined());
  1108. if (m_exec->hadException())
  1109. return 1;
  1110. double compareResult;
  1111. if (m_cachedCall) {
  1112. m_cachedCall->setThis(jsUndefined());
  1113. m_cachedCall->setArgument(0, va);
  1114. m_cachedCall->setArgument(1, vb);
  1115. compareResult = m_cachedCall->call().toNumber(m_cachedCall->newCallFrame(m_exec));
  1116. } else {
  1117. MarkedArgumentBuffer arguments;
  1118. arguments.append(va);
  1119. arguments.append(vb);
  1120. compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, jsUndefined(), arguments).toNumber(m_exec);
  1121. }
  1122. return (compareResult < 0) ? -1 : 1; // Not passing equality through, because we need to store all values, even if equivalent.
  1123. }
  1124. int compare_key_node(key k, handle h) { return compare_key_key(k, m_nodes[h].value); }
  1125. int compare_node_node(handle h1, handle h2) { return compare_key_key(m_nodes[h1].value, m_nodes[h2].value); }
  1126. static handle null() { return 0x7FFFFFFF; }
  1127. };
  1128. template<IndexingType indexingType>
  1129. void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
  1130. {
  1131. ASSERT(!inSparseIndexingMode());
  1132. ASSERT(indexingType == structure()->indexingType());
  1133. // FIXME: This ignores exceptions raised in the compare function or in toNumber.
  1134. // The maximum tree depth is compiled in - but the caller is clearly up to no good
  1135. // if a larger array is passed.
  1136. ASSERT(m_butterfly->publicLength() <= static_cast<unsigned>(std::numeric_limits<int>::max()));
  1137. if (m_butterfly->publicLength() > static_cast<unsigned>(std::numeric_limits<int>::max()))
  1138. return;
  1139. unsigned usedVectorLength = relevantLength<indexingType>();
  1140. unsigned nodeCount = usedVectorLength;
  1141. if (!nodeCount)
  1142. return;
  1143. AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items
  1144. tree.abstractor().m_exec = exec;
  1145. tree.abstractor().m_compareFunction = compareFunction;
  1146. tree.abstractor().m_compareCallType = callType;
  1147. tree.abstractor().m_compareCallData = &callData;
  1148. tree.abstractor().m_nodes.grow(nodeCount);
  1149. if (callType == CallTypeJS)
  1150. tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, jsCast<JSFunction*>(compareFunction), 2));
  1151. if (!tree.abstractor().m_nodes.begin()) {
  1152. throwOutOfMemoryError(exec);
  1153. return;
  1154. }
  1155. // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified
  1156. // right out from under us while we're building the tree here.
  1157. unsigned numDefined = 0;
  1158. unsigned numUndefined = 0;
  1159. // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
  1160. for (; numDefined < usedVectorLength; ++numDefined) {
  1161. if (numDefined >= m_butterfly->vectorLength())
  1162. break;
  1163. JSValue v = getHolyIndexQuickly(numDefined);
  1164. if (!v || v.isUndefined())
  1165. break;
  1166. tree.abstractor().m_nodes[numDefined].value = v;
  1167. tree.insert(numDefined);
  1168. }
  1169. for (unsigned i = numDefined; i < usedVectorLength; ++i) {
  1170. if (i >= m_butterfly->vectorLength())
  1171. break;
  1172. JSValue v = getHolyIndexQuickly(i);
  1173. if (v) {
  1174. if (v.isUndefined())
  1175. ++numUndefined;
  1176. else {
  1177. tree.abstractor().m_nodes[numDefined].value = v;
  1178. tree.insert(numDefined);
  1179. ++numDefined;
  1180. }
  1181. }
  1182. }
  1183. unsigned newUsedVectorLength = numDefined + numUndefined;
  1184. // The array size may have changed. Figure out the new bounds.
  1185. unsigned newestUsedVectorLength = currentRelevantLength();
  1186. unsigned elementsToExtractThreshold = min(min(newestUsedVectorLength, numDefined), static_cast<unsigned>(tree.abstractor().m_nodes.size()));
  1187. unsigned undefinedElementsThreshold = min(newestUsedVectorLength, newUsedVectorLength);
  1188. unsigned clearElementsThreshold = min(newestUsedVectorLength, usedVectorLength);
  1189. // Copy the values back into m_storage.
  1190. AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter;
  1191. iter.start_iter_least(tree);
  1192. VM& vm = exec->vm();
  1193. for (unsigned i = 0; i < elementsToExtractThreshold; ++i) {
  1194. ASSERT(i < butterfly()->vectorLength());
  1195. if (structure()->indexingType() == ArrayWithDouble)
  1196. butterfly()->contiguousDouble()[i] = tree.abstractor().m_nodes[*iter].value.asNumber();
  1197. else
  1198. currentIndexingData()[i].set(vm, this, tree.abstractor().m_nodes[*iter].value);
  1199. ++iter;
  1200. }
  1201. // Put undefined values back in.
  1202. switch (structure()->indexingType()) {
  1203. case ArrayWithInt32:
  1204. case ArrayWithDouble:
  1205. ASSERT(elementsToExtractThreshold == undefinedElementsThreshold);
  1206. break;
  1207. default:
  1208. for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i) {
  1209. ASSERT(i < butterfly()->vectorLength());
  1210. currentIndexingData()[i].setUndefined();
  1211. }
  1212. }
  1213. // Ensure that unused values in the vector are zeroed out.
  1214. for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) {
  1215. ASSERT(i < butterfly()->vectorLength());
  1216. if (structure()->indexingType() == ArrayWithDouble)
  1217. butterfly()->contiguousDouble()[i] = QNaN;
  1218. else
  1219. currentIndexingData()[i].clear();
  1220. }
  1221. if (hasArrayStorage(structure()->indexingType()))
  1222. arrayStorage()->m_numValuesInVector = newUsedVectorLength;
  1223. }
  1224. void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
  1225. {
  1226. ASSERT(!inSparseIndexingMode());
  1227. switch (structure()->indexingType()) {
  1228. case ArrayClass:
  1229. case ArrayWithUndecided:
  1230. return;
  1231. case ArrayWithInt32:
  1232. sortVector<ArrayWithInt32>(exec, compareFunction, callType, callData);
  1233. return;
  1234. case ArrayWithDouble:
  1235. sortVector<ArrayWithDouble>(exec, compareFunction, callType, callData);
  1236. return;
  1237. case ArrayWithContiguous:
  1238. sortVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
  1239. return;
  1240. case ArrayWithArrayStorage:
  1241. sortVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData);
  1242. return;
  1243. default:
  1244. RELEASE_ASSERT_NOT_REACHED();
  1245. }
  1246. }
  1247. void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
  1248. {
  1249. unsigned i = 0;
  1250. unsigned vectorEnd;
  1251. WriteBarrier<Unknown>* vector;
  1252. switch (structure()->indexingType()) {
  1253. case ArrayClass:
  1254. return;
  1255. case ArrayWithUndecided: {
  1256. vector = 0;
  1257. vectorEnd = 0;
  1258. break;
  1259. }
  1260. case ArrayWithInt32:
  1261. case ArrayWithContiguous: {
  1262. vectorEnd = m_butterfly->publicLength();
  1263. vector = m_butterfly->contiguous().data();
  1264. break;
  1265. }
  1266. case ArrayWithDouble: {
  1267. vector = 0;
  1268. vectorEnd = 0;
  1269. for (; i < m_butterfly->publicLength(); ++i) {
  1270. double v = butterfly()->contiguousDouble()[i];
  1271. if (v != v)
  1272. break;
  1273. args.append(JSValue(JSValue::EncodeAsDouble, v));
  1274. }
  1275. break;
  1276. }
  1277. case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
  1278. ArrayStorage* storage = m_butterfly->arrayStorage();
  1279. vector = storage->m_vector;
  1280. vectorEnd = min(storage->length(), storage->vectorLength());
  1281. break;
  1282. }
  1283. default:
  1284. CRASH();
  1285. vector = 0;
  1286. vectorEnd = 0;
  1287. break;
  1288. }
  1289. for (; i < vectorEnd; ++i) {
  1290. WriteBarrier<Unknown>& v = vector[i];
  1291. if (!v)
  1292. break;
  1293. args.append(v.get());
  1294. }
  1295. for (; i < length(); ++i)
  1296. args.append(get(exec, i));
  1297. }
  1298. void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length)
  1299. {
  1300. unsigned i = 0;
  1301. WriteBarrier<Unknown>* vector;
  1302. unsigned vectorEnd;
  1303. ASSERT(length == this->length());
  1304. switch (structure()->indexingType()) {
  1305. case ArrayClass:
  1306. return;
  1307. case ArrayWithUndecided: {
  1308. vector = 0;
  1309. vectorEnd = 0;
  1310. break;
  1311. }
  1312. case ArrayWithInt32:
  1313. case ArrayWithContiguous: {
  1314. vector = m_butterfly->contiguous().data();
  1315. vectorEnd = m_butterfly->publicLength();
  1316. break;
  1317. }
  1318. case ArrayWithDouble: {
  1319. vector = 0;
  1320. vectorEnd = 0;
  1321. for (; i < m_butterfly->publicLength(); ++i) {
  1322. ASSERT(i < butterfly()->vectorLength());
  1323. double v = m_butterfly->contiguousDouble()[i];
  1324. if (v != v)
  1325. break;
  1326. callFrame->setArgument(i, JSValue(JSValue::EncodeAsDouble, v));
  1327. }
  1328. break;
  1329. }
  1330. case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
  1331. ArrayStorage* storage = m_butterfly->arrayStorage();
  1332. vector = storage->m_vector;
  1333. vectorEnd = min(length, storage->vectorLength());
  1334. break;
  1335. }
  1336. default:
  1337. CRASH();
  1338. vector = 0;
  1339. vectorEnd = 0;
  1340. break;
  1341. }
  1342. for (; i < vectorEnd; ++i) {
  1343. WriteBarrier<Unknown>& v = vector[i];
  1344. if (!v)
  1345. break;
  1346. callFrame->setArgument(i, v.get());
  1347. }
  1348. for (; i < length; ++i)
  1349. callFrame->setArgument(i, get(exec, i));
  1350. }
  1351. template<IndexingType indexingType>
  1352. void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLength)
  1353. {
  1354. ASSERT(!inSparseIndexingMode());
  1355. ASSERT(indexingType == structure()->indexingType());
  1356. unsigned myRelevantLength = relevantLength<indexingType>();
  1357. numDefined = 0;
  1358. unsigned numUndefined = 0;
  1359. for (; numDefined < myRelevantLength; ++numDefined) {
  1360. ASSERT(numDefined < m_butterfly->vectorLength());
  1361. if (indexingType == ArrayWithInt32) {
  1362. JSValue v = m_butterfly->contiguousInt32()[numDefined].get();
  1363. if (!v)
  1364. break;
  1365. ASSERT(v.isInt32());
  1366. continue;
  1367. }
  1368. if (indexingType == ArrayWithDouble) {
  1369. double v = m_butterfly->contiguousDouble()[numDefined];
  1370. if (v != v)
  1371. break;
  1372. continue;
  1373. }
  1374. JSValue v = indexingData<indexingType>()[numDefined].get();
  1375. if (!v || v.isUndefined())
  1376. break;
  1377. }
  1378. for (unsigned i = numDefined; i < myRelevantLength; ++i) {
  1379. ASSERT(i < m_butterfly->vectorLength());
  1380. if (indexingType == ArrayWithInt32) {
  1381. JSValue v = m_butterfly->contiguousInt32()[i].get();
  1382. if (!v)
  1383. continue;
  1384. ASSERT(v.isInt32());
  1385. ASSERT(numDefined < m_butterfly->vectorLength());
  1386. m_butterfly->contiguousInt32()[numDefined++].setWithoutWriteBarrier(v);
  1387. continue;
  1388. }
  1389. if (indexingType == ArrayWithDouble) {
  1390. double v = m_butterfly->contiguousDouble()[i];
  1391. if (v != v)
  1392. continue;
  1393. ASSERT(numDefined < m_butterfly->vectorLength());
  1394. m_butterfly->contiguousDouble()[numDefined++] = v;
  1395. continue;
  1396. }
  1397. JSValue v = indexingData<indexingType>()[i].get();
  1398. if (v) {
  1399. if (v.isUndefined())
  1400. ++numUndefined;
  1401. else {
  1402. ASSERT(numDefined < m_butterfly->vectorLength());
  1403. indexingData<indexingType>()[numDefined++].setWithoutWriteBarrier(v);
  1404. }
  1405. }
  1406. }
  1407. newRelevantLength = numDefined + numUndefined;
  1408. if (hasArrayStorage(indexingType))
  1409. RELEASE_ASSERT(!arrayStorage()->m_sparseMap);
  1410. switch (indexingType) {
  1411. case ArrayWithInt32:
  1412. case ArrayWithDouble:
  1413. RELEASE_ASSERT(numDefined == newRelevantLength);
  1414. break;
  1415. default:
  1416. for (unsigned i = numDefined; i < newRelevantLength; ++i) {
  1417. ASSERT(i < m_butterfly->vectorLength());
  1418. indexingData<indexingType>()[i].setUndefined();
  1419. }
  1420. break;
  1421. }
  1422. for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) {
  1423. ASSERT(i < m_butterfly->vectorLength());
  1424. if (indexingType == ArrayWithDouble)
  1425. m_butterfly->contiguousDouble()[i] = QNaN;
  1426. else
  1427. indexingData<indexingType>()[i].clear();
  1428. }
  1429. if (hasArrayStorage(indexingType))
  1430. arrayStorage()->m_numValuesInVector = newRelevantLength;
  1431. }
  1432. } // namespace JSC