8b9d5056c11c4617429f50124dd239b7cb2e7f68
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSObject.cpp
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4  *  Copyright (C) 2003-2006, 2008, 2009, 2012-2016 Apple Inc. All rights reserved.
5  *  Copyright (C) 2007 Eric Seidel (eric@webkit.org)
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Library 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  *  Library General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Library General Public License
18  *  along with this library; see the file COPYING.LIB.  If not, write to
19  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #include "config.h"
25 #include "JSObject.h"
26
27 #include "ButterflyInlines.h"
28 #include "CopiedBlockInlines.h"
29 #include "CopiedSpaceInlines.h"
30 #include "CopyVisitor.h"
31 #include "CopyVisitorInlines.h"
32 #include "CustomGetterSetter.h"
33 #include "DatePrototype.h"
34 #include "ErrorConstructor.h"
35 #include "Exception.h"
36 #include "Executable.h"
37 #include "GetterSetter.h"
38 #include "IndexingHeaderInlines.h"
39 #include "JSBoundSlotBaseFunction.h"
40 #include "JSFunction.h"
41 #include "JSGlobalObject.h"
42 #include "Lookup.h"
43 #include "NativeErrorConstructor.h"
44 #include "Nodes.h"
45 #include "ObjectPrototype.h"
46 #include "JSCInlines.h"
47 #include "PropertyDescriptor.h"
48 #include "PropertyNameArray.h"
49 #include "ProxyObject.h"
50 #include "Reject.h"
51 #include "SlotVisitorInlines.h"
52 #include <math.h>
53 #include <wtf/Assertions.h>
54
55 namespace JSC {
56
57 // We keep track of the size of the last array after it was grown. We use this
58 // as a simple heuristic for as the value to grow the next array from size 0.
59 // This value is capped by the constant FIRST_VECTOR_GROW defined in
60 // ArrayConventions.h.
61 static unsigned lastArraySize = 0;
62
63 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSObject);
64 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSFinalObject);
65
66 const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property.";
67
68 const ClassInfo JSObject::s_info = { "Object", 0, 0, CREATE_METHOD_TABLE(JSObject) };
69
70 const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(JSFinalObject) };
71
72 static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode)
73 {
74     VM& vm = exec->vm();
75
76     // Add properties from the static hashtables of properties
77     for (; classInfo; classInfo = classInfo->parentClass) {
78         const HashTable* table = classInfo->staticPropHashTable;
79         if (!table)
80             continue;
81
82         for (auto iter = table->begin(); iter != table->end(); ++iter) {
83             if (!(iter->attributes() & DontEnum) || mode.includeDontEnumProperties())
84                 propertyNames.add(Identifier::fromString(&vm, iter.key()));
85         }
86     }
87 }
88
89 ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butterfly, size_t storageSize)
90 {
91     ASSERT(butterfly);
92     
93     Structure* structure = this->structure();
94     
95     size_t propertyCapacity = structure->outOfLineCapacity();
96     size_t preCapacity;
97     size_t indexingPayloadSizeInBytes;
98     bool hasIndexingHeader = this->hasIndexingHeader();
99     if (UNLIKELY(hasIndexingHeader)) {
100         preCapacity = butterfly->indexingHeader()->preCapacity(structure);
101         indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
102     } else {
103         preCapacity = 0;
104         indexingPayloadSizeInBytes = 0;
105     }
106     size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
107     if (visitor.checkIfShouldCopy(butterfly->base(preCapacity, propertyCapacity))) {
108         Butterfly* newButterfly = Butterfly::createUninitializedDuringCollection(visitor, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
109
110         // Copy the properties.
111         PropertyStorage currentTarget = newButterfly->propertyStorage();
112         PropertyStorage currentSource = butterfly->propertyStorage();
113         for (size_t count = storageSize; count--;)
114             (--currentTarget)->setWithoutWriteBarrier((--currentSource)->get());
115         
116         if (UNLIKELY(hasIndexingHeader)) {
117             *newButterfly->indexingHeader() = *butterfly->indexingHeader();
118             
119             // Copy the array if appropriate.
120             
121             WriteBarrier<Unknown>* currentTarget;
122             WriteBarrier<Unknown>* currentSource;
123             size_t count;
124             
125             switch (this->indexingType()) {
126             case ALL_UNDECIDED_INDEXING_TYPES:
127             case ALL_CONTIGUOUS_INDEXING_TYPES:
128             case ALL_INT32_INDEXING_TYPES:
129             case ALL_DOUBLE_INDEXING_TYPES: {
130                 currentTarget = newButterfly->contiguous().data();
131                 currentSource = butterfly->contiguous().data();
132                 RELEASE_ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength());
133                 count = newButterfly->vectorLength();
134                 break;
135             }
136                 
137             case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
138                 newButterfly->arrayStorage()->copyHeaderFromDuringGC(*butterfly->arrayStorage());
139                 currentTarget = newButterfly->arrayStorage()->m_vector;
140                 currentSource = butterfly->arrayStorage()->m_vector;
141                 count = newButterfly->arrayStorage()->vectorLength();
142                 break;
143             }
144                 
145             default:
146                 currentTarget = 0;
147                 currentSource = 0;
148                 count = 0;
149                 break;
150             }
151
152             memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue));
153         }
154         
155         m_butterfly.setWithoutBarrier(newButterfly);
156         visitor.didCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
157     } 
158 }
159
160 ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize)
161 {
162     ASSERT(butterfly);
163     
164     Structure* structure = this->structure(visitor.vm());
165     
166     size_t propertyCapacity = structure->outOfLineCapacity();
167     size_t preCapacity;
168     size_t indexingPayloadSizeInBytes;
169     bool hasIndexingHeader = this->hasIndexingHeader();
170     if (UNLIKELY(hasIndexingHeader)) {
171         preCapacity = butterfly->indexingHeader()->preCapacity(structure);
172         indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
173     } else {
174         preCapacity = 0;
175         indexingPayloadSizeInBytes = 0;
176     }
177     size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
178
179     // Mark the properties.
180     visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize);
181     visitor.copyLater(
182         this, ButterflyCopyToken,
183         butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
184     
185     // Mark the array if appropriate.
186     switch (this->indexingType()) {
187     case ALL_CONTIGUOUS_INDEXING_TYPES:
188         visitor.appendValues(butterfly->contiguous().data(), butterfly->publicLength());
189         break;
190     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
191         visitor.appendValues(butterfly->arrayStorage()->m_vector, butterfly->arrayStorage()->vectorLength());
192         if (butterfly->arrayStorage()->m_sparseMap)
193             visitor.append(&butterfly->arrayStorage()->m_sparseMap);
194         break;
195     default:
196         break;
197     }
198 }
199
200 size_t JSObject::estimatedSize(JSCell* cell)
201 {
202     JSObject* thisObject = jsCast<JSObject*>(cell);
203     size_t butterflyOutOfLineSize = thisObject->m_butterfly ? thisObject->structure()->outOfLineSize() : 0;
204     return Base::estimatedSize(cell) + butterflyOutOfLineSize;
205 }
206
207 void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
208 {
209     JSObject* thisObject = jsCast<JSObject*>(cell);
210     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
211 #if !ASSERT_DISABLED
212     bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
213     visitor.m_isCheckingForDefaultMarkViolation = false;
214 #endif
215     
216     JSCell::visitChildren(thisObject, visitor);
217
218     Butterfly* butterfly = thisObject->m_butterfly.getWithoutBarrier();
219     if (butterfly)
220         thisObject->visitButterfly(visitor, butterfly, thisObject->structure(visitor.vm())->outOfLineSize());
221
222 #if !ASSERT_DISABLED
223     visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
224 #endif
225 }
226
227 void JSObject::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token)
228 {
229     JSObject* thisObject = jsCast<JSObject*>(cell);
230     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
231
232     if (token != ButterflyCopyToken)
233         return;
234     
235     Butterfly* butterfly = thisObject->m_butterfly.getWithoutBarrier();
236     if (butterfly)
237         thisObject->copyButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
238 }
239
240 void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
241 {
242     JSFinalObject* thisObject = jsCast<JSFinalObject*>(cell);
243     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
244 #if !ASSERT_DISABLED
245     bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
246     visitor.m_isCheckingForDefaultMarkViolation = false;
247 #endif
248     
249     JSCell::visitChildren(thisObject, visitor);
250
251     Structure* structure = thisObject->structure();
252     Butterfly* butterfly = thisObject->butterfly();
253     if (butterfly)
254         thisObject->visitButterfly(visitor, butterfly, structure->outOfLineSize());
255
256     size_t storageSize = structure->inlineSize();
257     visitor.appendValues(thisObject->inlineStorage(), storageSize);
258
259 #if !ASSERT_DISABLED
260     visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
261 #endif
262 }
263
264 String JSObject::className(const JSObject* object)
265 {
266     const ClassInfo* info = object->classInfo();
267     ASSERT(info);
268     return info->className;
269 }
270
271 String JSObject::calculatedClassName(JSObject* object)
272 {
273     String prototypeFunctionName;
274     ExecState* exec = object->globalObject()->globalExec();
275     PropertySlot slot(object->structure()->storedPrototype(), PropertySlot::InternalMethodType::VMInquiry);
276     PropertyName constructor(exec->propertyNames().constructor);
277     if (object->getPropertySlot(exec, constructor, slot)) {
278         if (slot.isValue()) {
279             JSValue constructorValue = slot.getValue(exec, constructor);
280             if (constructorValue.isCell()) {
281                 if (JSCell* constructorCell = constructorValue.asCell()) {
282                     if (JSObject* ctorObject = constructorCell->getObject()) {
283                         if (JSFunction* constructorFunction = jsDynamicCast<JSFunction*>(ctorObject))
284                             prototypeFunctionName = constructorFunction->calculatedDisplayName(exec);
285                         else if (InternalFunction* constructorFunction = jsDynamicCast<InternalFunction*>(ctorObject))
286                             prototypeFunctionName = constructorFunction->calculatedDisplayName(exec);
287                     }
288                 }
289             }
290         }
291     }
292
293     if (prototypeFunctionName.isNull() || prototypeFunctionName == "Object") {
294         String tableClassName = object->methodTable()->className(object);
295         if (!tableClassName.isNull() && tableClassName != "Object")
296             return tableClassName;
297
298         String classInfoName = object->classInfo()->className;
299         if (!classInfoName.isNull())
300             return classInfoName;
301
302         if (prototypeFunctionName.isNull())
303             return ASCIILiteral("Object");
304     }
305
306     return prototypeFunctionName;
307 }
308
309 bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec, unsigned i, PropertySlot& slot)
310 {
311     // NB. The fact that we're directly consulting our indexed storage implies that it is not
312     // legal for anyone to override getOwnPropertySlot() without also overriding
313     // getOwnPropertySlotByIndex().
314     
315     if (i > MAX_ARRAY_INDEX)
316         return thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
317     
318     switch (thisObject->indexingType()) {
319     case ALL_BLANK_INDEXING_TYPES:
320     case ALL_UNDECIDED_INDEXING_TYPES:
321         break;
322         
323     case ALL_INT32_INDEXING_TYPES:
324     case ALL_CONTIGUOUS_INDEXING_TYPES: {
325         Butterfly* butterfly = thisObject->butterfly();
326         if (i >= butterfly->vectorLength())
327             return false;
328         
329         JSValue value = butterfly->contiguous()[i].get();
330         if (value) {
331             slot.setValue(thisObject, None, value);
332             return true;
333         }
334         
335         return false;
336     }
337         
338     case ALL_DOUBLE_INDEXING_TYPES: {
339         Butterfly* butterfly = thisObject->butterfly();
340         if (i >= butterfly->vectorLength())
341             return false;
342         
343         double value = butterfly->contiguousDouble()[i];
344         if (value == value) {
345             slot.setValue(thisObject, None, JSValue(JSValue::EncodeAsDouble, value));
346             return true;
347         }
348         
349         return false;
350     }
351         
352     case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
353         ArrayStorage* storage = thisObject->m_butterfly.get(thisObject)->arrayStorage();
354         if (i >= storage->length())
355             return false;
356         
357         if (i < storage->vectorLength()) {
358             JSValue value = storage->m_vector[i].get();
359             if (value) {
360                 slot.setValue(thisObject, None, value);
361                 return true;
362             }
363         } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
364             SparseArrayValueMap::iterator it = map->find(i);
365             if (it != map->notFound()) {
366                 it->value.get(thisObject, slot);
367                 return true;
368             }
369         }
370         break;
371     }
372         
373     default:
374         RELEASE_ASSERT_NOT_REACHED();
375         break;
376     }
377     
378     return false;
379 }
380
381 // ECMA 8.6.2.2
382 void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
383 {
384     putInline(cell, exec, propertyName, value, slot);
385 }
386
387 void JSObject::putInlineSlow(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
388 {
389     VM& vm = exec->vm();
390
391     JSObject* obj = this;
392     for (;;) {
393         unsigned attributes;
394         PropertyOffset offset = obj->structure(vm)->get(vm, propertyName, attributes);
395         if (isValidOffset(offset)) {
396             if (attributes & ReadOnly) {
397                 ASSERT(structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == this);
398                 if (slot.isStrictMode())
399                     exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
400                 return;
401             }
402
403             JSValue gs = obj->getDirect(offset);
404             if (gs.isGetterSetter()) {
405                 callSetter(exec, this, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode);
406                 if (!structure()->isDictionary())
407                     slot.setCacheableSetter(obj, offset);
408                 return;
409             }
410             if (gs.isCustomGetterSetter()) {
411                 callCustomSetter(exec, gs, attributes & CustomAccessor, obj, slot.thisValue(), value);
412                 if (attributes & CustomAccessor)
413                     slot.setCustomAccessor(obj, jsCast<CustomGetterSetter*>(gs.asCell())->setter());
414                 else
415                     slot.setCustomValue(obj, jsCast<CustomGetterSetter*>(gs.asCell())->setter());
416                 return;
417             }
418             ASSERT(!(attributes & Accessor));
419
420             // If there's an existing property on the object or one of its 
421             // prototypes it should be replaced, so break here.
422             break;
423         }
424         if (!obj->staticFunctionsReified()) {
425             if (obj->classInfo()->hasStaticSetterOrReadonlyProperties()) {
426                 if (auto* entry = obj->findPropertyHashEntry(propertyName)) {
427                     putEntry(exec, entry, obj, this, propertyName, value, slot);
428                     return;
429                 }
430             }
431         }
432         if (obj->type() == ProxyObjectType) {
433             ProxyObject* proxy = jsCast<ProxyObject*>(obj);
434             proxy->ProxyObject::put(proxy, exec, propertyName, value, slot);
435             return;
436         }
437         JSValue prototype = obj->prototype();
438         if (prototype.isNull())
439             break;
440         obj = asObject(prototype);
441     }
442     
443     ASSERT(!structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == this);
444     if (!putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot) && slot.isStrictMode())
445         throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
446 }
447
448 void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
449 {
450     JSObject* thisObject = jsCast<JSObject*>(cell);
451     
452     if (propertyName > MAX_ARRAY_INDEX) {
453         PutPropertySlot slot(cell, shouldThrow);
454         thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot);
455         return;
456     }
457     
458     switch (thisObject->indexingType()) {
459     case ALL_BLANK_INDEXING_TYPES:
460         break;
461         
462     case ALL_UNDECIDED_INDEXING_TYPES: {
463         thisObject->convertUndecidedForValue(exec->vm(), value);
464         // Reloop.
465         putByIndex(cell, exec, propertyName, value, shouldThrow);
466         return;
467     }
468         
469     case ALL_INT32_INDEXING_TYPES: {
470         if (!value.isInt32()) {
471             thisObject->convertInt32ForValue(exec->vm(), value);
472             putByIndex(cell, exec, propertyName, value, shouldThrow);
473             return;
474         }
475         FALLTHROUGH;
476     }
477         
478     case ALL_CONTIGUOUS_INDEXING_TYPES: {
479         Butterfly* butterfly = thisObject->butterfly();
480         if (propertyName >= butterfly->vectorLength())
481             break;
482         butterfly->contiguous()[propertyName].set(exec->vm(), thisObject, value);
483         if (propertyName >= butterfly->publicLength())
484             butterfly->setPublicLength(propertyName + 1);
485         return;
486     }
487         
488     case ALL_DOUBLE_INDEXING_TYPES: {
489         if (!value.isNumber()) {
490             thisObject->convertDoubleToContiguous(exec->vm());
491             // Reloop.
492             putByIndex(cell, exec, propertyName, value, shouldThrow);
493             return;
494         }
495         double valueAsDouble = value.asNumber();
496         if (valueAsDouble != valueAsDouble) {
497             thisObject->convertDoubleToContiguous(exec->vm());
498             // Reloop.
499             putByIndex(cell, exec, propertyName, value, shouldThrow);
500             return;
501         }
502         Butterfly* butterfly = thisObject->butterfly();
503         if (propertyName >= butterfly->vectorLength())
504             break;
505         butterfly->contiguousDouble()[propertyName] = valueAsDouble;
506         if (propertyName >= butterfly->publicLength())
507             butterfly->setPublicLength(propertyName + 1);
508         return;
509     }
510         
511     case NonArrayWithArrayStorage:
512     case ArrayWithArrayStorage: {
513         ArrayStorage* storage = thisObject->m_butterfly.get(thisObject)->arrayStorage();
514         
515         if (propertyName >= storage->vectorLength())
516             break;
517         
518         WriteBarrier<Unknown>& valueSlot = storage->m_vector[propertyName];
519         unsigned length = storage->length();
520         
521         // Update length & m_numValuesInVector as necessary.
522         if (propertyName >= length) {
523             length = propertyName + 1;
524             storage->setLength(length);
525             ++storage->m_numValuesInVector;
526         } else if (!valueSlot)
527             ++storage->m_numValuesInVector;
528         
529         valueSlot.set(exec->vm(), thisObject, value);
530         return;
531     }
532         
533     case NonArrayWithSlowPutArrayStorage:
534     case ArrayWithSlowPutArrayStorage: {
535         ArrayStorage* storage = thisObject->m_butterfly.get(thisObject)->arrayStorage();
536         
537         if (propertyName >= storage->vectorLength())
538             break;
539         
540         WriteBarrier<Unknown>& valueSlot = storage->m_vector[propertyName];
541         unsigned length = storage->length();
542         
543         // Update length & m_numValuesInVector as necessary.
544         if (propertyName >= length) {
545             if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow))
546                 return;
547             length = propertyName + 1;
548             storage->setLength(length);
549             ++storage->m_numValuesInVector;
550         } else if (!valueSlot) {
551             if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow))
552                 return;
553             ++storage->m_numValuesInVector;
554         }
555         
556         valueSlot.set(exec->vm(), thisObject, value);
557         return;
558     }
559         
560     default:
561         RELEASE_ASSERT_NOT_REACHED();
562     }
563     
564     thisObject->putByIndexBeyondVectorLength(exec, propertyName, value, shouldThrow);
565 }
566
567 ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM& vm, ArrayStorage* storage)
568 {
569     SparseArrayValueMap* map = storage->m_sparseMap.get();
570
571     if (!map)
572         map = allocateSparseIndexMap(vm);
573
574     if (map->sparseMode())
575         return storage;
576
577     map->setSparseMode();
578
579     unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
580     for (unsigned i = 0; i < usedVectorLength; ++i) {
581         JSValue value = storage->m_vector[i].get();
582         // This will always be a new entry in the map, so no need to check we can write,
583         // and attributes are default so no need to set them.
584         if (value)
585             map->add(this, i).iterator->value.set(vm, map, value);
586     }
587
588     DeferGC deferGC(vm.heap);
589     Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, this, structure(vm), 0, ArrayStorage::sizeFor(0));
590     RELEASE_ASSERT(newButterfly);
591     newButterfly->arrayStorage()->m_indexBias = 0;
592     newButterfly->arrayStorage()->setVectorLength(0);
593     newButterfly->arrayStorage()->m_sparseMap.set(vm, this, map);
594     setButterflyWithoutChangingStructure(vm, newButterfly);
595     
596     return newButterfly->arrayStorage();
597 }
598
599 void JSObject::enterDictionaryIndexingMode(VM& vm)
600 {
601     switch (indexingType()) {
602     case ALL_BLANK_INDEXING_TYPES:
603     case ALL_UNDECIDED_INDEXING_TYPES:
604     case ALL_INT32_INDEXING_TYPES:
605     case ALL_DOUBLE_INDEXING_TYPES:
606     case ALL_CONTIGUOUS_INDEXING_TYPES:
607         // NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize
608         // this case if we ever cared. Note that ensureArrayStorage() can return null if the object
609         // doesn't support traditional indexed properties. At the time of writing, this just affects
610         // typed arrays.
611         if (ArrayStorage* storage = ensureArrayStorageSlow(vm))
612             enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, storage);
613         break;
614     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
615         enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly.get(this)->arrayStorage());
616         break;
617         
618     default:
619         break;
620     }
621 }
622
623 void JSObject::notifyPresenceOfIndexedAccessors(VM& vm)
624 {
625     if (mayInterceptIndexedAccesses())
626         return;
627     
628     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AddIndexedAccessors));
629     
630     if (!vm.prototypeMap.isPrototype(this))
631         return;
632     
633     globalObject()->haveABadTime(vm);
634 }
635
636 Butterfly* JSObject::createInitialIndexedStorage(VM& vm, unsigned length, size_t elementSize)
637 {
638     ASSERT(length < MAX_ARRAY_INDEX);
639     IndexingType oldType = indexingType();
640     ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
641     ASSERT(!structure()->needsSlowPutIndexing());
642     ASSERT(!indexingShouldBeSparse());
643     unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
644     Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
645         m_butterfly.get(this), vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
646         elementSize * vectorLength);
647     newButterfly->setPublicLength(length);
648     newButterfly->setVectorLength(vectorLength);
649     return newButterfly;
650 }
651
652 Butterfly* JSObject::createInitialUndecided(VM& vm, unsigned length)
653 {
654     DeferGC deferGC(vm.heap);
655     Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
656     Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateUndecided);
657     setStructureAndButterfly(vm, newStructure, newButterfly);
658     return newButterfly;
659 }
660
661 ContiguousJSValues JSObject::createInitialInt32(VM& vm, unsigned length)
662 {
663     DeferGC deferGC(vm.heap);
664     Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
665     Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateInt32);
666     setStructureAndButterfly(vm, newStructure, newButterfly);
667     return newButterfly->contiguousInt32();
668 }
669
670 ContiguousDoubles JSObject::createInitialDouble(VM& vm, unsigned length)
671 {
672     DeferGC deferGC(vm.heap);
673     Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(double));
674     for (unsigned i = newButterfly->vectorLength(); i--;)
675         newButterfly->contiguousDouble()[i] = PNaN;
676     Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble);
677     setStructureAndButterfly(vm, newStructure, newButterfly);
678     return newButterfly->contiguousDouble();
679 }
680
681 ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length)
682 {
683     DeferGC deferGC(vm.heap);
684     Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
685     Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous);
686     setStructureAndButterfly(vm, newStructure, newButterfly);
687     return newButterfly->contiguous();
688 }
689
690 ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vectorLength)
691 {
692     DeferGC deferGC(vm.heap);
693     Structure* structure = this->structure(vm);
694     IndexingType oldType = indexingType();
695     ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
696     Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
697         m_butterfly.get(this), vm, this, structure, structure->outOfLineCapacity(), false, 0,
698         ArrayStorage::sizeFor(vectorLength));
699     RELEASE_ASSERT(newButterfly);
700
701     ArrayStorage* result = newButterfly->arrayStorage();
702     result->setLength(length);
703     result->setVectorLength(vectorLength);
704     result->m_sparseMap.clear();
705     result->m_numValuesInVector = 0;
706     result->m_indexBias = 0;
707     Structure* newStructure = Structure::nonPropertyTransition(vm, structure, structure->suggestedArrayStorageTransition());
708     setStructureAndButterfly(vm, newStructure, newButterfly);
709     return result;
710 }
711
712 ArrayStorage* JSObject::createInitialArrayStorage(VM& vm)
713 {
714     return createArrayStorage(vm, 0, BASE_VECTOR_LEN);
715 }
716
717 ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm)
718 {
719     ASSERT(hasUndecided(indexingType()));
720     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateInt32));
721     return m_butterfly.get(this)->contiguousInt32();
722 }
723
724 ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm)
725 {
726     ASSERT(hasUndecided(indexingType()));
727
728     Butterfly* butterfly = m_butterfly.get(this);
729     for (unsigned i = butterfly->vectorLength(); i--;)
730         butterfly->contiguousDouble()[i] = PNaN;
731     
732     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble));
733     return m_butterfly.get(this)->contiguousDouble();
734 }
735
736 ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm)
737 {
738     ASSERT(hasUndecided(indexingType()));
739     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous));
740     return m_butterfly.get(this)->contiguous();
741 }
742
743 ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM& vm, unsigned neededLength)
744 {
745     Structure* structure = this->structure(vm);
746     unsigned publicLength = m_butterfly.get(this)->publicLength();
747     unsigned propertyCapacity = structure->outOfLineCapacity();
748     unsigned propertySize = structure->outOfLineSize();
749     
750     Butterfly* newButterfly = Butterfly::createUninitialized(
751         vm, this, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
752     
753     memcpy(
754         newButterfly->propertyStorage() - propertySize,
755         m_butterfly.get(this)->propertyStorage() - propertySize,
756         propertySize * sizeof(EncodedJSValue));
757     
758     ArrayStorage* newStorage = newButterfly->arrayStorage();
759     newStorage->setVectorLength(neededLength);
760     newStorage->setLength(publicLength);
761     newStorage->m_sparseMap.clear();
762     newStorage->m_indexBias = 0;
763     newStorage->m_numValuesInVector = 0;
764     
765     return newStorage;
766 }
767
768 ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition)
769 {
770     DeferGC deferGC(vm.heap);
771     ASSERT(hasUndecided(indexingType()));
772
773     unsigned vectorLength = m_butterfly.get(this)->vectorLength();
774     ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
775     // No need to copy elements.
776     
777     Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
778     setStructureAndButterfly(vm, newStructure, storage->butterfly());
779     return storage;
780 }
781
782 ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm)
783 {
784     return convertUndecidedToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
785 }
786
787 ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm)
788 {
789     ASSERT(hasInt32(indexingType()));
790
791     Butterfly* butterfly = m_butterfly.get(this);
792     for (unsigned i = butterfly->vectorLength(); i--;) {
793         WriteBarrier<Unknown>* current = &butterfly->contiguousInt32()[i];
794         double* currentAsDouble = bitwise_cast<double*>(current);
795         JSValue v = current->get();
796         if (!v) {
797             *currentAsDouble = PNaN;
798             continue;
799         }
800         ASSERT(v.isInt32());
801         *currentAsDouble = v.asInt32();
802     }
803     
804     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble));
805     return m_butterfly.get(this)->contiguousDouble();
806 }
807
808 ContiguousJSValues JSObject::convertInt32ToContiguous(VM& vm)
809 {
810     ASSERT(hasInt32(indexingType()));
811     
812     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous));
813     return m_butterfly.get(this)->contiguous();
814 }
815
816 ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition)
817 {
818     DeferGC deferGC(vm.heap);
819     ASSERT(hasInt32(indexingType()));
820
821     unsigned vectorLength = m_butterfly.get(this)->vectorLength();
822     ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
823     Butterfly* butterfly = m_butterfly.get(this);
824     for (unsigned i = 0; i < butterfly->publicLength(); i++) {
825         JSValue v = butterfly->contiguous()[i].get();
826         if (v) {
827             newStorage->m_vector[i].setWithoutWriteBarrier(v);
828             newStorage->m_numValuesInVector++;
829         } else
830             ASSERT(newStorage->m_vector[i].get().isEmpty());
831     }
832     
833     Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
834     setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
835     return newStorage;
836 }
837
838 ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm)
839 {
840     return convertInt32ToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
841 }
842
843 ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm)
844 {
845     ASSERT(hasDouble(indexingType()));
846
847     Butterfly* butterfly = m_butterfly.get(this);
848     for (unsigned i = butterfly->vectorLength(); i--;) {
849         double* current = &butterfly->contiguousDouble()[i];
850         WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current);
851         double value = *current;
852         if (value != value) {
853             currentAsValue->clear();
854             continue;
855         }
856         JSValue v = JSValue(JSValue::EncodeAsDouble, value);
857         currentAsValue->setWithoutWriteBarrier(v);
858     }
859     
860     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous));
861     return m_butterfly.get(this)->contiguous();
862 }
863
864 ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition)
865 {
866     DeferGC deferGC(vm.heap);
867     ASSERT(hasDouble(indexingType()));
868
869     unsigned vectorLength = m_butterfly.get(this)->vectorLength();
870     ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
871     Butterfly* butterfly = m_butterfly.get(this);
872     for (unsigned i = 0; i < butterfly->publicLength(); i++) {
873         double value = butterfly->contiguousDouble()[i];
874         if (value == value) {
875             newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
876             newStorage->m_numValuesInVector++;
877         } else
878             ASSERT(newStorage->m_vector[i].get().isEmpty());
879     }
880     
881     Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
882     setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
883     return newStorage;
884 }
885
886 ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm)
887 {
888     return convertDoubleToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
889 }
890
891 ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition)
892 {
893     DeferGC deferGC(vm.heap);
894     ASSERT(hasContiguous(indexingType()));
895
896     unsigned vectorLength = m_butterfly.get(this)->vectorLength();
897     ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
898     Butterfly* butterfly = m_butterfly.get(this);
899     for (unsigned i = 0; i < butterfly->publicLength(); i++) {
900         JSValue v = butterfly->contiguous()[i].get();
901         if (v) {
902             newStorage->m_vector[i].setWithoutWriteBarrier(v);
903             newStorage->m_numValuesInVector++;
904         } else
905             ASSERT(newStorage->m_vector[i].get().isEmpty());
906     }
907     
908     Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
909     setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
910     return newStorage;
911 }
912
913 ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm)
914 {
915     return convertContiguousToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
916 }
917
918 void JSObject::convertUndecidedForValue(VM& vm, JSValue value)
919 {
920     if (value.isInt32()) {
921         convertUndecidedToInt32(vm);
922         return;
923     }
924     
925     if (value.isDouble() && value.asNumber() == value.asNumber()) {
926         convertUndecidedToDouble(vm);
927         return;
928     }
929     
930     convertUndecidedToContiguous(vm);
931 }
932
933 void JSObject::createInitialForValueAndSet(VM& vm, unsigned index, JSValue value)
934 {
935     if (value.isInt32()) {
936         createInitialInt32(vm, index + 1)[index].set(vm, this, value);
937         return;
938     }
939     
940     if (value.isDouble()) {
941         double doubleValue = value.asNumber();
942         if (doubleValue == doubleValue) {
943             createInitialDouble(vm, index + 1)[index] = doubleValue;
944             return;
945         }
946     }
947     
948     createInitialContiguous(vm, index + 1)[index].set(vm, this, value);
949 }
950
951 void JSObject::convertInt32ForValue(VM& vm, JSValue value)
952 {
953     ASSERT(!value.isInt32());
954     
955     if (value.isDouble() && !std::isnan(value.asDouble())) {
956         convertInt32ToDouble(vm);
957         return;
958     }
959     
960     convertInt32ToContiguous(vm);
961 }
962
963 void JSObject::setIndexQuicklyToUndecided(VM& vm, unsigned index, JSValue value)
964 {
965     ASSERT(index < m_butterfly.get(this)->publicLength());
966     ASSERT(index < m_butterfly.get(this)->vectorLength());
967     convertUndecidedForValue(vm, value);
968     setIndexQuickly(vm, index, value);
969 }
970
971 void JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value)
972 {
973     ASSERT(!value.isInt32());
974     convertInt32ForValue(vm, value);
975     setIndexQuickly(vm, index, value);
976 }
977
978 void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value)
979 {
980     ASSERT(!value.isNumber() || value.asNumber() != value.asNumber());
981     convertDoubleToContiguous(vm);
982     setIndexQuickly(vm, index, value);
983 }
984
985 ContiguousJSValues JSObject::ensureInt32Slow(VM& vm)
986 {
987     ASSERT(inherits(info()));
988     
989     if (structure(vm)->hijacksIndexingHeader())
990         return ContiguousJSValues();
991     
992     switch (indexingType()) {
993     case ALL_BLANK_INDEXING_TYPES:
994         if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
995             return ContiguousJSValues();
996         return createInitialInt32(vm, 0);
997         
998     case ALL_UNDECIDED_INDEXING_TYPES:
999         return convertUndecidedToInt32(vm);
1000         
1001     case ALL_DOUBLE_INDEXING_TYPES:
1002     case ALL_CONTIGUOUS_INDEXING_TYPES:
1003     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
1004         return ContiguousJSValues();
1005         
1006     default:
1007         CRASH();
1008         return ContiguousJSValues();
1009     }
1010 }
1011
1012 ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm)
1013 {
1014     ASSERT(inherits(info()));
1015     
1016     if (structure(vm)->hijacksIndexingHeader())
1017         return ContiguousDoubles();
1018     
1019     switch (indexingType()) {
1020     case ALL_BLANK_INDEXING_TYPES:
1021         if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
1022             return ContiguousDoubles();
1023         return createInitialDouble(vm, 0);
1024         
1025     case ALL_UNDECIDED_INDEXING_TYPES:
1026         return convertUndecidedToDouble(vm);
1027         
1028     case ALL_INT32_INDEXING_TYPES:
1029         return convertInt32ToDouble(vm);
1030         
1031     case ALL_CONTIGUOUS_INDEXING_TYPES:
1032     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
1033         return ContiguousDoubles();
1034         
1035     default:
1036         CRASH();
1037         return ContiguousDoubles();
1038     }
1039 }
1040
1041 ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm)
1042 {
1043     ASSERT(inherits(info()));
1044     
1045     if (structure(vm)->hijacksIndexingHeader())
1046         return ContiguousJSValues();
1047     
1048     switch (indexingType()) {
1049     case ALL_BLANK_INDEXING_TYPES:
1050         if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
1051             return ContiguousJSValues();
1052         return createInitialContiguous(vm, 0);
1053         
1054     case ALL_UNDECIDED_INDEXING_TYPES:
1055         return convertUndecidedToContiguous(vm);
1056         
1057     case ALL_INT32_INDEXING_TYPES:
1058         return convertInt32ToContiguous(vm);
1059         
1060     case ALL_DOUBLE_INDEXING_TYPES:
1061         return convertDoubleToContiguous(vm);
1062         
1063     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
1064         return ContiguousJSValues();
1065         
1066     default:
1067         CRASH();
1068         return ContiguousJSValues();
1069     }
1070 }
1071
1072 ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm)
1073 {
1074     ASSERT(inherits(info()));
1075
1076     if (structure(vm)->hijacksIndexingHeader())
1077         return nullptr;
1078     
1079     switch (indexingType()) {
1080     case ALL_BLANK_INDEXING_TYPES:
1081         if (UNLIKELY(indexingShouldBeSparse()))
1082             return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm);
1083         return createInitialArrayStorage(vm);
1084         
1085     case ALL_UNDECIDED_INDEXING_TYPES:
1086         ASSERT(!indexingShouldBeSparse());
1087         ASSERT(!structure(vm)->needsSlowPutIndexing());
1088         return convertUndecidedToArrayStorage(vm);
1089         
1090     case ALL_INT32_INDEXING_TYPES:
1091         ASSERT(!indexingShouldBeSparse());
1092         ASSERT(!structure(vm)->needsSlowPutIndexing());
1093         return convertInt32ToArrayStorage(vm);
1094         
1095     case ALL_DOUBLE_INDEXING_TYPES:
1096         ASSERT(!indexingShouldBeSparse());
1097         ASSERT(!structure(vm)->needsSlowPutIndexing());
1098         return convertDoubleToArrayStorage(vm);
1099         
1100     case ALL_CONTIGUOUS_INDEXING_TYPES:
1101         ASSERT(!indexingShouldBeSparse());
1102         ASSERT(!structure(vm)->needsSlowPutIndexing());
1103         return convertContiguousToArrayStorage(vm);
1104         
1105     default:
1106         RELEASE_ASSERT_NOT_REACHED();
1107         return 0;
1108     }
1109 }
1110
1111 ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM& vm)
1112 {
1113     switch (indexingType()) {
1114     case ALL_BLANK_INDEXING_TYPES: {
1115         createArrayStorage(vm, 0, 0);
1116         SparseArrayValueMap* map = allocateSparseIndexMap(vm);
1117         map->setSparseMode();
1118         return arrayStorage();
1119     }
1120         
1121     case ALL_UNDECIDED_INDEXING_TYPES:
1122         return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertUndecidedToArrayStorage(vm));
1123         
1124     case ALL_INT32_INDEXING_TYPES:
1125         return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertInt32ToArrayStorage(vm));
1126         
1127     case ALL_DOUBLE_INDEXING_TYPES:
1128         return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertDoubleToArrayStorage(vm));
1129         
1130     case ALL_CONTIGUOUS_INDEXING_TYPES:
1131         return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertContiguousToArrayStorage(vm));
1132         
1133     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
1134         return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly.get(this)->arrayStorage());
1135         
1136     default:
1137         CRASH();
1138         return 0;
1139     }
1140 }
1141
1142 void JSObject::switchToSlowPutArrayStorage(VM& vm)
1143 {
1144     switch (indexingType()) {
1145     case ALL_UNDECIDED_INDEXING_TYPES:
1146         convertUndecidedToArrayStorage(vm, AllocateSlowPutArrayStorage);
1147         break;
1148         
1149     case ALL_INT32_INDEXING_TYPES:
1150         convertInt32ToArrayStorage(vm, AllocateSlowPutArrayStorage);
1151         break;
1152         
1153     case ALL_DOUBLE_INDEXING_TYPES:
1154         convertDoubleToArrayStorage(vm, AllocateSlowPutArrayStorage);
1155         break;
1156         
1157     case ALL_CONTIGUOUS_INDEXING_TYPES:
1158         convertContiguousToArrayStorage(vm, AllocateSlowPutArrayStorage);
1159         break;
1160         
1161     case NonArrayWithArrayStorage:
1162     case ArrayWithArrayStorage: {
1163         Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), SwitchToSlowPutArrayStorage);
1164         setStructure(vm, newStructure);
1165         break;
1166     }
1167         
1168     default:
1169         CRASH();
1170         break;
1171     }
1172 }
1173
1174 void JSObject::setPrototypeDirect(VM& vm, JSValue prototype)
1175 {
1176     ASSERT(prototype);
1177     if (prototype.isObject())
1178         vm.prototypeMap.addPrototype(asObject(prototype));
1179     
1180     Structure* newStructure = Structure::changePrototypeTransition(vm, structure(vm), prototype);
1181     setStructure(vm, newStructure);
1182     
1183     if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
1184         return;
1185     
1186     if (vm.prototypeMap.isPrototype(this)) {
1187         newStructure->globalObject()->haveABadTime(vm);
1188         return;
1189     }
1190     
1191     if (!hasIndexedProperties(indexingType()))
1192         return;
1193     
1194     if (shouldUseSlowPut(indexingType()))
1195         return;
1196     
1197     switchToSlowPutArrayStorage(vm);
1198 }
1199
1200 bool JSObject::setPrototypeWithCycleCheck(VM& vm, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
1201 {
1202     ASSERT(methodTable(vm)->toThis(this, exec, NotStrictMode) == this);
1203
1204     if (this->prototype() == prototype)
1205         return true;
1206
1207     bool isExtensible = this->isExtensible(exec);
1208     if (vm.exception())
1209         return false;
1210
1211     if (!isExtensible) {
1212         if (shouldThrowIfCantSet)
1213             throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
1214         return false;
1215     }
1216
1217     JSValue nextPrototype = prototype;
1218     while (nextPrototype && nextPrototype.isObject()) {
1219         if (nextPrototype == this) {
1220             if (shouldThrowIfCantSet)
1221                 vm.throwException(exec, createError(exec, ASCIILiteral("cyclic __proto__ value")));
1222             return false;
1223         }
1224         nextPrototype = asObject(nextPrototype)->prototype();
1225     }
1226     setPrototypeDirect(vm, prototype);
1227     return true;
1228 }
1229
1230 bool JSObject::setPrototype(JSObject* object, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
1231 {
1232     return object->setPrototypeWithCycleCheck(exec->vm(), exec, prototype, shouldThrowIfCantSet);
1233 }
1234
1235 bool JSObject::setPrototype(VM& vm, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
1236 {
1237     return methodTable(vm)->setPrototype(this, exec, prototype, shouldThrowIfCantSet);
1238 }
1239
1240 bool JSObject::allowsAccessFrom(ExecState* exec)
1241 {
1242     JSGlobalObject* globalObject = this->globalObject();
1243     return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec);
1244 }
1245
1246 void JSObject::putGetter(ExecState* exec, PropertyName propertyName, JSValue getter, unsigned attributes)
1247 {
1248     PropertyDescriptor descriptor;
1249     descriptor.setGetter(getter);
1250
1251     ASSERT(attributes & Accessor);
1252     if (!(attributes & ReadOnly))
1253         descriptor.setConfigurable(true);
1254     if (!(attributes & DontEnum))
1255         descriptor.setEnumerable(true);
1256
1257     defineOwnProperty(this, exec, propertyName, descriptor, false);
1258 }
1259
1260 void JSObject::putSetter(ExecState* exec, PropertyName propertyName, JSValue setter, unsigned attributes)
1261 {
1262     PropertyDescriptor descriptor;
1263     descriptor.setSetter(setter);
1264
1265     ASSERT(attributes & Accessor);
1266     if (!(attributes & ReadOnly))
1267         descriptor.setConfigurable(true);
1268     if (!(attributes & DontEnum))
1269         descriptor.setEnumerable(true);
1270
1271     defineOwnProperty(this, exec, propertyName, descriptor, false);
1272 }
1273
1274 void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
1275 {
1276     ASSERT(value.isGetterSetter() && (attributes & Accessor));
1277
1278     if (Optional<uint32_t> index = parseIndex(propertyName)) {
1279         putDirectIndex(exec, index.value(), value, attributes, PutDirectIndexLikePutDirect);
1280         return;
1281     }
1282
1283     putDirectNonIndexAccessor(exec->vm(), propertyName, value, attributes);
1284 }
1285
1286 void JSObject::putDirectCustomAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
1287 {
1288     ASSERT(!parseIndex(propertyName));
1289
1290     PutPropertySlot slot(this);
1291     putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
1292
1293     ASSERT(slot.type() == PutPropertySlot::NewProperty);
1294
1295     Structure* structure = this->structure(vm);
1296     if (attributes & ReadOnly)
1297         structure->setContainsReadOnlyProperties();
1298     structure->setHasCustomGetterSetterPropertiesWithProtoCheck(propertyName == vm.propertyNames->underscoreProto);
1299 }
1300
1301 void JSObject::putDirectNonIndexAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
1302 {
1303     PutPropertySlot slot(this);
1304     putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
1305
1306     Structure* structure = this->structure(vm);
1307     if (attributes & ReadOnly)
1308         structure->setContainsReadOnlyProperties();
1309
1310     structure->setHasGetterSetterPropertiesWithProtoCheck(propertyName == vm.propertyNames->underscoreProto);
1311 }
1312
1313 // HasProperty(O, P) from Section 7.3.10 of the spec.
1314 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasproperty
1315 bool JSObject::hasProperty(ExecState* exec, PropertyName propertyName) const
1316 {
1317     return hasPropertyGeneric(exec, propertyName, PropertySlot::InternalMethodType::HasProperty);
1318 }
1319
1320 bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
1321 {
1322     return hasPropertyGeneric(exec, propertyName, PropertySlot::InternalMethodType::HasProperty);
1323 }
1324
1325 bool JSObject::hasPropertyGeneric(ExecState* exec, PropertyName propertyName, PropertySlot::InternalMethodType internalMethodType) const
1326 {
1327     PropertySlot slot(this, internalMethodType);
1328     return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
1329 }
1330
1331 bool JSObject::hasPropertyGeneric(ExecState* exec, unsigned propertyName, PropertySlot::InternalMethodType internalMethodType) const
1332 {
1333     PropertySlot slot(this, internalMethodType);
1334     return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
1335 }
1336
1337 // ECMA 8.6.2.5
1338 bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
1339 {
1340     JSObject* thisObject = jsCast<JSObject*>(cell);
1341     VM& vm = exec->vm();
1342     
1343     if (Optional<uint32_t> index = parseIndex(propertyName))
1344         return thisObject->methodTable(vm)->deletePropertyByIndex(thisObject, exec, index.value());
1345
1346     if (!thisObject->staticFunctionsReified())
1347         thisObject->reifyAllStaticProperties(exec);
1348
1349     unsigned attributes;
1350     if (isValidOffset(thisObject->structure(vm)->get(vm, propertyName, attributes))) {
1351         if (attributes & DontDelete && !vm.isInDefineOwnProperty())
1352             return false;
1353         thisObject->removeDirect(vm, propertyName);
1354     }
1355
1356     return true;
1357 }
1358
1359 // HasOwnProperty(O, P) from section 7.3.11 in the spec.
1360 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasownproperty
1361 bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
1362 {
1363     PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
1364     return const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
1365 }
1366
1367 bool JSObject::hasOwnProperty(ExecState* exec, unsigned propertyName) const
1368 {
1369     PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
1370     return const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlotByIndex(const_cast<JSObject*>(this), exec, propertyName, slot);
1371 }
1372
1373 bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
1374 {
1375     JSObject* thisObject = jsCast<JSObject*>(cell);
1376     
1377     if (i > MAX_ARRAY_INDEX)
1378         return thisObject->methodTable(exec->vm())->deleteProperty(thisObject, exec, Identifier::from(exec, i));
1379     
1380     switch (thisObject->indexingType()) {
1381     case ALL_BLANK_INDEXING_TYPES:
1382     case ALL_UNDECIDED_INDEXING_TYPES:
1383         return true;
1384         
1385     case ALL_INT32_INDEXING_TYPES:
1386     case ALL_CONTIGUOUS_INDEXING_TYPES: {
1387         Butterfly* butterfly = thisObject->butterfly();
1388         if (i >= butterfly->vectorLength())
1389             return true;
1390         butterfly->contiguous()[i].clear();
1391         return true;
1392     }
1393         
1394     case ALL_DOUBLE_INDEXING_TYPES: {
1395         Butterfly* butterfly = thisObject->butterfly();
1396         if (i >= butterfly->vectorLength())
1397             return true;
1398         butterfly->contiguousDouble()[i] = PNaN;
1399         return true;
1400     }
1401         
1402     case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
1403         ArrayStorage* storage = thisObject->m_butterfly.get(thisObject)->arrayStorage();
1404         
1405         if (i < storage->vectorLength()) {
1406             WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
1407             if (valueSlot) {
1408                 valueSlot.clear();
1409                 --storage->m_numValuesInVector;
1410             }
1411         } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
1412             SparseArrayValueMap::iterator it = map->find(i);
1413             if (it != map->notFound()) {
1414                 if (it->value.attributes & DontDelete)
1415                     return false;
1416                 map->remove(it);
1417             }
1418         }
1419         
1420         return true;
1421     }
1422         
1423     default:
1424         RELEASE_ASSERT_NOT_REACHED();
1425         return false;
1426     }
1427 }
1428
1429 static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, PropertyName propertyName)
1430 {
1431     JSValue function = object->get(exec, propertyName);
1432     CallData callData;
1433     CallType callType = getCallData(function, callData);
1434     if (callType == CallTypeNone)
1435         return exec->exception();
1436
1437     // Prevent "toString" and "valueOf" from observing execution if an exception
1438     // is pending.
1439     if (exec->hadException())
1440         return exec->exception();
1441
1442     JSValue result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList());
1443     ASSERT(!result.isGetterSetter());
1444     if (exec->hadException())
1445         return exec->exception();
1446     if (result.isObject())
1447         return JSValue();
1448     return result;
1449 }
1450
1451 bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
1452 {
1453     result = methodTable(exec->vm())->defaultValue(this, exec, PreferNumber);
1454     number = result.toNumber(exec);
1455     return !result.isString();
1456 }
1457
1458 // ECMA 8.6.2.6
1459 JSValue JSObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint)
1460 {
1461     // Make sure that whatever default value methods there are on object's prototype chain are
1462     // being watched.
1463     object->structure()->startWatchingInternalPropertiesIfNecessaryForEntireChain(exec->vm());
1464     
1465     // Must call toString first for Date objects.
1466     if ((hint == PreferString) || (hint != PreferNumber && object->prototype() == exec->lexicalGlobalObject()->datePrototype())) {
1467         JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().toString);
1468         if (value)
1469             return value;
1470         value = callDefaultValueFunction(exec, object, exec->propertyNames().valueOf);
1471         if (value)
1472             return value;
1473     } else {
1474         JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().valueOf);
1475         if (value)
1476             return value;
1477         value = callDefaultValueFunction(exec, object, exec->propertyNames().toString);
1478         if (value)
1479             return value;
1480     }
1481
1482     ASSERT(!exec->hadException());
1483
1484     return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("No default value")));
1485 }
1486
1487 const HashTableValue* JSObject::findPropertyHashEntry(PropertyName propertyName) const
1488 {
1489     for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
1490         if (const HashTable* propHashTable = info->staticPropHashTable) {
1491             if (const HashTableValue* entry = propHashTable->entry(propertyName))
1492                 return entry;
1493         }
1494     }
1495     return 0;
1496 }
1497
1498 bool JSObject::hasInstance(ExecState* exec, JSValue value, JSValue hasInstanceValue)
1499 {
1500     VM& vm = exec->vm();
1501
1502     if (!hasInstanceValue.isUndefinedOrNull() && hasInstanceValue != exec->lexicalGlobalObject()->functionProtoHasInstanceSymbolFunction()) {
1503         CallData callData;
1504         CallType callType = JSC::getCallData(hasInstanceValue, callData);
1505         if (callType == CallTypeNone) {
1506             vm.throwException(exec, createInvalidInstanceofParameterErrorhasInstanceValueNotFunction(exec, this));
1507             return false;
1508         }
1509
1510         MarkedArgumentBuffer args;
1511         args.append(value);
1512         JSValue result = call(exec, hasInstanceValue, callType, callData, this, args);
1513         return result.toBoolean(exec);
1514     }
1515
1516     TypeInfo info = structure(vm)->typeInfo();
1517     if (info.implementsDefaultHasInstance())
1518         return defaultHasInstance(exec, value, get(exec, exec->propertyNames().prototype));
1519     if (info.implementsHasInstance())
1520         return methodTable(vm)->customHasInstance(this, exec, value);
1521     vm.throwException(exec, createInvalidInstanceofParameterErrorNotFunction(exec, this));
1522     return false;
1523 }
1524
1525 bool JSObject::hasInstance(ExecState* exec, JSValue value)
1526 {
1527     JSValue hasInstanceValue = get(exec, exec->propertyNames().hasInstanceSymbol);
1528
1529     return hasInstance(exec, value, hasInstanceValue);
1530 }
1531
1532 bool JSObject::defaultHasInstance(ExecState* exec, JSValue value, JSValue proto)
1533 {
1534     if (!value.isObject())
1535         return false;
1536
1537     if (!proto.isObject()) {
1538         exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("instanceof called on an object with an invalid prototype property.")));
1539         return false;
1540     }
1541
1542     JSObject* object = asObject(value);
1543     while ((object = object->prototype().getObject())) {
1544         if (proto == object)
1545             return true;
1546     }
1547     return false;
1548 }
1549
1550 EncodedJSValue JSC_HOST_CALL objectPrivateFuncInstanceOf(ExecState* exec)
1551 {
1552     JSValue value = exec->uncheckedArgument(0);
1553     JSValue proto = exec->uncheckedArgument(1);
1554
1555     return JSValue::encode(jsBoolean(JSObject::defaultHasInstance(exec, value, proto)));
1556 }
1557
1558 void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1559 {
1560     object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, propertyNames, mode);
1561
1562     if (object->prototype().isNull())
1563         return;
1564
1565     VM& vm = exec->vm();
1566     JSObject* prototype = asObject(object->prototype());
1567     while(1) {
1568         if (prototype->structure(vm)->typeInfo().overridesGetPropertyNames()) {
1569             prototype->methodTable(vm)->getPropertyNames(prototype, exec, propertyNames, mode);
1570             break;
1571         }
1572         prototype->methodTable(vm)->getOwnPropertyNames(prototype, exec, propertyNames, mode);
1573         JSValue nextProto = prototype->prototype();
1574         if (nextProto.isNull())
1575             break;
1576         prototype = asObject(nextProto);
1577     }
1578 }
1579
1580 void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1581 {
1582     if (!mode.includeJSObjectProperties()) {
1583         // We still have to get non-indexed properties from any subclasses of JSObject that have them.
1584         object->methodTable(exec->vm())->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
1585         return;
1586     }
1587
1588     if (propertyNames.includeStringProperties()) {
1589         // Add numeric properties first. That appears to be the accepted convention.
1590         // FIXME: Filling PropertyNameArray with an identifier for every integer
1591         // is incredibly inefficient for large arrays. We need a different approach,
1592         // which almost certainly means a different structure for PropertyNameArray.
1593         switch (object->indexingType()) {
1594         case ALL_BLANK_INDEXING_TYPES:
1595         case ALL_UNDECIDED_INDEXING_TYPES:
1596             break;
1597             
1598         case ALL_INT32_INDEXING_TYPES:
1599         case ALL_CONTIGUOUS_INDEXING_TYPES: {
1600             Butterfly* butterfly = object->butterfly();
1601             unsigned usedLength = butterfly->publicLength();
1602             for (unsigned i = 0; i < usedLength; ++i) {
1603                 if (!butterfly->contiguous()[i])
1604                     continue;
1605                 propertyNames.add(i);
1606             }
1607             break;
1608         }
1609             
1610         case ALL_DOUBLE_INDEXING_TYPES: {
1611             Butterfly* butterfly = object->butterfly();
1612             unsigned usedLength = butterfly->publicLength();
1613             for (unsigned i = 0; i < usedLength; ++i) {
1614                 double value = butterfly->contiguousDouble()[i];
1615                 if (value != value)
1616                     continue;
1617                 propertyNames.add(i);
1618             }
1619             break;
1620         }
1621             
1622         case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
1623             ArrayStorage* storage = object->m_butterfly.get(object)->arrayStorage();
1624             
1625             unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
1626             for (unsigned i = 0; i < usedVectorLength; ++i) {
1627                 if (storage->m_vector[i])
1628                     propertyNames.add(i);
1629             }
1630             
1631             if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
1632                 Vector<unsigned, 0, UnsafeVectorOverflow> keys;
1633                 keys.reserveInitialCapacity(map->size());
1634                 
1635                 SparseArrayValueMap::const_iterator end = map->end();
1636                 for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
1637                     if (mode.includeDontEnumProperties() || !(it->value.attributes & DontEnum))
1638                         keys.uncheckedAppend(static_cast<unsigned>(it->key));
1639                 }
1640                 
1641                 std::sort(keys.begin(), keys.end());
1642                 for (unsigned i = 0; i < keys.size(); ++i)
1643                     propertyNames.add(keys[i]);
1644             }
1645             break;
1646         }
1647             
1648         default:
1649             RELEASE_ASSERT_NOT_REACHED();
1650         }
1651     }
1652
1653     object->methodTable(exec->vm())->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
1654 }
1655
1656 void JSObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1657 {
1658     if (!object->staticFunctionsReified())
1659         getClassPropertyNames(exec, object->classInfo(), propertyNames, mode);
1660
1661     if (!mode.includeJSObjectProperties())
1662         return;
1663     
1664     VM& vm = exec->vm();
1665     object->structure(vm)->getPropertyNamesFromStructure(vm, propertyNames, mode);
1666 }
1667
1668 double JSObject::toNumber(ExecState* exec) const
1669 {
1670     JSValue primitive = toPrimitive(exec, PreferNumber);
1671     if (exec->hadException()) // should be picked up soon in Nodes.cpp
1672         return 0.0;
1673     return primitive.toNumber(exec);
1674 }
1675
1676 JSString* JSObject::toString(ExecState* exec) const
1677 {
1678     JSValue primitive = toPrimitive(exec, PreferString);
1679     if (exec->hadException())
1680         return jsEmptyString(exec);
1681     return primitive.toString(exec);
1682 }
1683
1684 JSValue JSObject::toThis(JSCell* cell, ExecState*, ECMAMode)
1685 {
1686     return jsCast<JSObject*>(cell);
1687 }
1688
1689 void JSObject::seal(VM& vm)
1690 {
1691     if (isSealed(vm))
1692         return;
1693     enterDictionaryIndexingMode(vm);
1694     setStructure(vm, Structure::sealTransition(vm, structure(vm)));
1695 }
1696
1697 void JSObject::freeze(VM& vm)
1698 {
1699     if (isFrozen(vm))
1700         return;
1701     enterDictionaryIndexingMode(vm);
1702     setStructure(vm, Structure::freezeTransition(vm, structure(vm)));
1703 }
1704
1705 bool JSObject::preventExtensions(JSObject* object, ExecState* exec)
1706 {
1707     if (!object->isStructureExtensible()) {
1708         // We've already set the internal [[PreventExtensions]] field to false.
1709         // We don't call the methodTable isExtensible here because it's not defined
1710         // that way in the specification. We are just doing an optimization here.
1711         return true;
1712     }
1713
1714     VM& vm = exec->vm();
1715     object->enterDictionaryIndexingMode(vm);
1716     object->setStructure(vm, Structure::preventExtensionsTransition(vm, object->structure(vm)));
1717     return true;
1718 }
1719
1720 bool JSObject::isExtensible(JSObject* obj, ExecState*)
1721 {
1722     return obj->isExtensibleImpl();
1723 }
1724
1725 bool JSObject::isExtensible(ExecState* exec)
1726
1727     VM& vm = exec->vm();
1728     return methodTable(vm)->isExtensible(this, exec);
1729 }
1730
1731 void JSObject::reifyAllStaticProperties(ExecState* exec)
1732 {
1733     ASSERT(!staticFunctionsReified());
1734     VM& vm = exec->vm();
1735
1736     // If this object's ClassInfo has no static properties, then nothing to reify!
1737     // We can safely set the flag to avoid the expensive check again in the future.
1738     if (!classInfo()->hasStaticProperties()) {
1739         structure(vm)->setStaticFunctionsReified(true);
1740         return;
1741     }
1742
1743     if (!structure(vm)->isUncacheableDictionary())
1744         setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure(vm)));
1745
1746     for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
1747         const HashTable* hashTable = info->staticPropHashTable;
1748         if (!hashTable)
1749             continue;
1750
1751         for (auto& value : *hashTable) {
1752             unsigned attributes;
1753             PropertyOffset offset = getDirectOffset(vm, Identifier::fromString(&vm, value.m_key), attributes);
1754             if (!isValidOffset(offset))
1755                 reifyStaticProperty(vm, value, *this);
1756         }
1757     }
1758
1759     structure(vm)->setStaticFunctionsReified(true);
1760 }
1761
1762 bool JSObject::removeDirect(VM& vm, PropertyName propertyName)
1763 {
1764     Structure* structure = this->structure(vm);
1765     if (!isValidOffset(structure->get(vm, propertyName)))
1766         return false;
1767
1768     PropertyOffset offset;
1769     if (structure->isUncacheableDictionary()) {
1770         offset = structure->removePropertyWithoutTransition(vm, propertyName);
1771         if (offset == invalidOffset)
1772             return false;
1773         putDirectUndefined(offset);
1774         return true;
1775     }
1776
1777     setStructure(vm, Structure::removePropertyTransition(vm, structure, propertyName, offset));
1778     if (offset == invalidOffset)
1779         return false;
1780     putDirectUndefined(offset);
1781     return true;
1782 }
1783
1784 NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue getterSetter, unsigned attributes, PropertyOffset offset)
1785 {
1786     if (structure()->isDictionary()) {
1787         slot.setGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter));
1788         return;
1789     }
1790     slot.setCacheableGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter), offset);
1791 }
1792
1793 void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, const PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor)
1794 {
1795     VM& vm = exec->vm();
1796     auto map = m_butterfly.get(this)->arrayStorage()->m_sparseMap.get();
1797
1798     if (descriptor.isDataDescriptor()) {
1799         if (descriptor.value())
1800             entryInMap->set(vm, map, descriptor.value());
1801         else if (oldDescriptor.isAccessorDescriptor())
1802             entryInMap->set(vm, map, jsUndefined());
1803         entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~Accessor;
1804         return;
1805     }
1806
1807     if (descriptor.isAccessorDescriptor()) {
1808         JSObject* getter = 0;
1809         if (descriptor.getterPresent())
1810             getter = descriptor.getterObject();
1811         else if (oldDescriptor.isAccessorDescriptor())
1812             getter = oldDescriptor.getterObject();
1813         JSObject* setter = 0;
1814         if (descriptor.setterPresent())
1815             setter = descriptor.setterObject();
1816         else if (oldDescriptor.isAccessorDescriptor())
1817             setter = oldDescriptor.setterObject();
1818
1819         GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject());
1820         if (getter)
1821             accessor->setGetter(vm, exec->lexicalGlobalObject(), getter);
1822         if (setter)
1823             accessor->setSetter(vm, exec->lexicalGlobalObject(), setter);
1824
1825         entryInMap->set(vm, map, accessor);
1826         entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~ReadOnly;
1827         return;
1828     }
1829
1830     ASSERT(descriptor.isGenericDescriptor());
1831     entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor);
1832 }
1833
1834 // Defined in ES5.1 8.12.9
1835 bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, const PropertyDescriptor& descriptor, bool throwException)
1836 {
1837     ASSERT(index <= MAX_ARRAY_INDEX);
1838
1839     if (!inSparseIndexingMode()) {
1840         // Fast case: we're putting a regular property to a regular array
1841         // FIXME: this will pessimistically assume that if attributes are missing then they'll default to false
1842         // however if the property currently exists missing attributes will override from their current 'true'
1843         // state (i.e. defineOwnProperty could be used to set a value without needing to entering 'SparseMode').
1844         if (!descriptor.attributes() && descriptor.value()) {
1845             ASSERT(!descriptor.isAccessorDescriptor());
1846             return putDirectIndex(exec, index, descriptor.value(), 0, throwException ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
1847         }
1848         
1849         ensureArrayStorageExistsAndEnterDictionaryIndexingMode(exec->vm());
1850     }
1851
1852     if (descriptor.attributes() & (ReadOnly | Accessor))
1853         notifyPresenceOfIndexedAccessors(exec->vm());
1854
1855     SparseArrayValueMap* map = m_butterfly.get(this)->arrayStorage()->m_sparseMap.get();
1856     RELEASE_ASSERT(map);
1857
1858     // 1. Let current be the result of calling the [[GetOwnProperty]] internal method of O with property name P.
1859     SparseArrayValueMap::AddResult result = map->add(this, index);
1860     SparseArrayEntry* entryInMap = &result.iterator->value;
1861
1862     // 2. Let extensible be the value of the [[Extensible]] internal property of O.
1863     // 3. If current is undefined and extensible is false, then Reject.
1864     // 4. If current is undefined and extensible is true, then
1865     if (result.isNewEntry) {
1866         if (!isStructureExtensible()) {
1867             map->remove(result.iterator);
1868             return reject(exec, throwException, "Attempting to define property on object that is not extensible.");
1869         }
1870
1871         // 4.a. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then create an own data property
1872         // named P of object O whose [[Value]], [[Writable]], [[Enumerable]] and [[Configurable]] attribute values
1873         // are described by Desc. If the value of an attribute field of Desc is absent, the attribute of the newly
1874         // created property is set to its default value.
1875         // 4.b. Else, Desc must be an accessor Property Descriptor so, create an own accessor property named P of
1876         // object O whose [[Get]], [[Set]], [[Enumerable]] and [[Configurable]] attribute values are described by
1877         // Desc. If the value of an attribute field of Desc is absent, the attribute of the newly created property
1878         // is set to its default value.
1879         // 4.c. Return true.
1880
1881         PropertyDescriptor defaults;
1882         entryInMap->setWithoutWriteBarrier(jsUndefined());
1883         entryInMap->attributes = DontDelete | DontEnum | ReadOnly;
1884         entryInMap->get(defaults);
1885
1886         putIndexedDescriptor(exec, entryInMap, descriptor, defaults);
1887         Butterfly* butterfly = m_butterfly.get(this);
1888         if (index >= butterfly->arrayStorage()->length())
1889             butterfly->arrayStorage()->setLength(index + 1);
1890         return true;
1891     }
1892
1893     // 5. Return true, if every field in Desc is absent.
1894     // 6. Return true, if every field in Desc also occurs in current and the value of every field in Desc is the same value as the corresponding field in current when compared using the SameValue algorithm (9.12).
1895     PropertyDescriptor current;
1896     entryInMap->get(current);
1897     if (descriptor.isEmpty() || descriptor.equalTo(exec, current))
1898         return true;
1899
1900     // 7. If the [[Configurable]] field of current is false then
1901     if (!current.configurable()) {
1902         // 7.a. Reject, if the [[Configurable]] field of Desc is true.
1903         if (descriptor.configurablePresent() && descriptor.configurable())
1904             return reject(exec, throwException, "Attempting to change configurable attribute of unconfigurable property.");
1905         // 7.b. Reject, if the [[Enumerable]] field of Desc is present and the [[Enumerable]] fields of current and Desc are the Boolean negation of each other.
1906         if (descriptor.enumerablePresent() && current.enumerable() != descriptor.enumerable())
1907             return reject(exec, throwException, "Attempting to change enumerable attribute of unconfigurable property.");
1908     }
1909
1910     // 8. If IsGenericDescriptor(Desc) is true, then no further validation is required.
1911     if (!descriptor.isGenericDescriptor()) {
1912         // 9. Else, if IsDataDescriptor(current) and IsDataDescriptor(Desc) have different results, then
1913         if (current.isDataDescriptor() != descriptor.isDataDescriptor()) {
1914             // 9.a. Reject, if the [[Configurable]] field of current is false.
1915             if (!current.configurable())
1916                 return reject(exec, throwException, "Attempting to change access mechanism for an unconfigurable property.");
1917             // 9.b. If IsDataDescriptor(current) is true, then convert the property named P of object O from a
1918             // data property to an accessor property. Preserve the existing values of the converted property's
1919             // [[Configurable]] and [[Enumerable]] attributes and set the rest of the property's attributes to
1920             // their default values.
1921             // 9.c. Else, convert the property named P of object O from an accessor property to a data property.
1922             // Preserve the existing values of the converted property's [[Configurable]] and [[Enumerable]]
1923             // attributes and set the rest of the property's attributes to their default values.
1924         } else if (current.isDataDescriptor() && descriptor.isDataDescriptor()) {
1925             // 10. Else, if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
1926             // 10.a. If the [[Configurable]] field of current is false, then
1927             if (!current.configurable() && !current.writable()) {
1928                 // 10.a.i. Reject, if the [[Writable]] field of current is false and the [[Writable]] field of Desc is true.
1929                 if (descriptor.writable())
1930                     return reject(exec, throwException, "Attempting to change writable attribute of unconfigurable property.");
1931                 // 10.a.ii. If the [[Writable]] field of current is false, then
1932                 // 10.a.ii.1. Reject, if the [[Value]] field of Desc is present and SameValue(Desc.[[Value]], current.[[Value]]) is false.
1933                 if (descriptor.value() && !sameValue(exec, descriptor.value(), current.value()))
1934                     return reject(exec, throwException, "Attempting to change value of a readonly property.");
1935             }
1936             // 10.b. else, the [[Configurable]] field of current is true, so any change is acceptable.
1937         } else {
1938             ASSERT(current.isAccessorDescriptor() && current.getterPresent() && current.setterPresent());
1939             // 11. Else, IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true so, if the [[Configurable]] field of current is false, then
1940             if (!current.configurable()) {
1941                 // 11.i. Reject, if the [[Set]] field of Desc is present and SameValue(Desc.[[Set]], current.[[Set]]) is false.
1942                 if (descriptor.setterPresent() && descriptor.setter() != current.setter())
1943                     return reject(exec, throwException, "Attempting to change the setter of an unconfigurable property.");
1944                 // 11.ii. Reject, if the [[Get]] field of Desc is present and SameValue(Desc.[[Get]], current.[[Get]]) is false.
1945                 if (descriptor.getterPresent() && descriptor.getter() != current.getter())
1946                     return reject(exec, throwException, "Attempting to change the getter of an unconfigurable property.");
1947             }
1948         }
1949     }
1950
1951     // 12. For each attribute field of Desc that is present, set the correspondingly named attribute of the property named P of object O to the value of the field.
1952     putIndexedDescriptor(exec, entryInMap, descriptor, current);
1953     // 13. Return true.
1954     return true;
1955 }
1956
1957 SparseArrayValueMap* JSObject::allocateSparseIndexMap(VM& vm)
1958 {
1959     SparseArrayValueMap* result = SparseArrayValueMap::create(vm);
1960     arrayStorage()->m_sparseMap.set(vm, this, result);
1961     return result;
1962 }
1963
1964 void JSObject::deallocateSparseIndexMap()
1965 {
1966     if (ArrayStorage* arrayStorage = arrayStorageOrNull())
1967         arrayStorage->m_sparseMap.clear();
1968 }
1969
1970 bool JSObject::attemptToInterceptPutByIndexOnHoleForPrototype(ExecState* exec, JSValue thisValue, unsigned i, JSValue value, bool shouldThrow)
1971 {
1972     for (JSObject* current = this; ;) {
1973         // This has the same behavior with respect to prototypes as JSObject::put(). It only
1974         // allows a prototype to intercept a put if (a) the prototype declares the property
1975         // we're after rather than intercepting it via an override of JSObject::put(), and
1976         // (b) that property is declared as ReadOnly or Accessor.
1977         
1978         ArrayStorage* storage = current->arrayStorageOrNull();
1979         if (storage && storage->m_sparseMap) {
1980             SparseArrayValueMap::iterator iter = storage->m_sparseMap->find(i);
1981             if (iter != storage->m_sparseMap->notFound() && (iter->value.attributes & (Accessor | ReadOnly))) {
1982                 iter->value.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow);
1983                 return true;
1984             }
1985         }
1986
1987         if (current->type() == ProxyObjectType) {
1988             ProxyObject* proxy = jsCast<ProxyObject*>(current);
1989             proxy->putByIndexCommon(exec, thisValue, i, value, shouldThrow);
1990             return true;
1991         }
1992         
1993         JSValue prototypeValue = current->prototype();
1994         if (prototypeValue.isNull())
1995             return false;
1996         
1997         current = asObject(prototypeValue);
1998     }
1999 }
2000
2001 bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
2002 {
2003     JSValue prototypeValue = prototype();
2004     if (prototypeValue.isNull())
2005         return false;
2006     
2007     return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow);
2008 }
2009
2010 template<IndexingType indexingShape>
2011 void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, unsigned i, JSValue value)
2012 {
2013     ASSERT((indexingType() & IndexingShapeMask) == indexingShape);
2014     ASSERT(!indexingShouldBeSparse());
2015
2016     Butterfly* butterfly = m_butterfly.get(this);
2017     
2018     // For us to get here, the index is either greater than the public length, or greater than
2019     // or equal to the vector length.
2020     ASSERT(i >= butterfly->vectorLength());
2021     
2022     VM& vm = exec->vm();
2023     
2024     if (i > MAX_STORAGE_VECTOR_INDEX
2025         || (i >= MIN_SPARSE_ARRAY_INDEX
2026             && !isDenseEnoughForVector(i, countElements<indexingShape>(butterfly)))
2027         || indexIsSufficientlyBeyondLengthForSparseMap(i, butterfly->vectorLength())) {
2028         ASSERT(i <= MAX_ARRAY_INDEX);
2029         ensureArrayStorageSlow(vm);
2030         SparseArrayValueMap* map = allocateSparseIndexMap(vm);
2031         map->putEntry(exec, this, i, value, false);
2032         ASSERT(i >= arrayStorage()->length());
2033         arrayStorage()->setLength(i + 1);
2034         return;
2035     }
2036
2037     ensureLength(vm, i + 1);
2038     butterfly = m_butterfly.get(this);
2039
2040     RELEASE_ASSERT(i < butterfly->vectorLength());
2041     switch (indexingShape) {
2042     case Int32Shape:
2043         ASSERT(value.isInt32());
2044         butterfly->contiguousInt32()[i].setWithoutWriteBarrier(value);
2045         break;
2046         
2047     case DoubleShape: {
2048         ASSERT(value.isNumber());
2049         double valueAsDouble = value.asNumber();
2050         ASSERT(valueAsDouble == valueAsDouble);
2051         butterfly->contiguousDouble()[i] = valueAsDouble;
2052         break;
2053     }
2054         
2055     case ContiguousShape:
2056         butterfly->contiguous()[i].set(vm, this, value);
2057         break;
2058         
2059     default:
2060         CRASH();
2061     }
2062 }
2063
2064 // Explicit instantiations needed by JSArray.cpp.
2065 template void JSObject::putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(ExecState*, unsigned, JSValue);
2066 template void JSObject::putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(ExecState*, unsigned, JSValue);
2067 template void JSObject::putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(ExecState*, unsigned, JSValue);
2068
2069 void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage)
2070 {
2071     VM& vm = exec->vm();
2072
2073     // i should be a valid array index that is outside of the current vector.
2074     ASSERT(i <= MAX_ARRAY_INDEX);
2075     ASSERT(i >= storage->vectorLength());
2076     
2077     SparseArrayValueMap* map = storage->m_sparseMap.get();
2078     
2079     // First, handle cases where we don't currently have a sparse map.
2080     if (LIKELY(!map)) {
2081         // If the array is not extensible, we should have entered dictionary mode, and created the sparse map.
2082         ASSERT(isStructureExtensible());
2083     
2084         // Update m_length if necessary.
2085         if (i >= storage->length())
2086             storage->setLength(i + 1);
2087
2088         // Check that it is sensible to still be using a vector, and then try to grow the vector.
2089         if (LIKELY(!indexIsSufficientlyBeyondLengthForSparseMap(i, storage->vectorLength()) 
2090             && isDenseEnoughForVector(i, storage->m_numValuesInVector)
2091             && increaseVectorLength(vm, i + 1))) {
2092             // success! - reread m_storage since it has likely been reallocated, and store to the vector.
2093             storage = arrayStorage();
2094             storage->m_vector[i].set(vm, this, value);
2095             ++storage->m_numValuesInVector;
2096             return;
2097         }
2098         // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value.
2099         map = allocateSparseIndexMap(exec->vm());
2100         map->putEntry(exec, this, i, value, shouldThrow);
2101         return;
2102     }
2103
2104     // Update m_length if necessary.
2105     unsigned length = storage->length();
2106     if (i >= length) {
2107         // Prohibit growing the array if length is not writable.
2108         if (map->lengthIsReadOnly() || !isStructureExtensible()) {
2109             if (shouldThrow)
2110                 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
2111             return;
2112         }
2113         length = i + 1;
2114         storage->setLength(length);
2115     }
2116
2117     // We are currently using a map - check whether we still want to be doing so.
2118     // We will continue  to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails.
2119     unsigned numValuesInArray = storage->m_numValuesInVector + map->size();
2120     if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->vm(), length)) {
2121         map->putEntry(exec, this, i, value, shouldThrow);
2122         return;
2123     }
2124
2125     // Reread m_storage after increaseVectorLength, update m_numValuesInVector.
2126     storage = arrayStorage();
2127     storage->m_numValuesInVector = numValuesInArray;
2128
2129     // Copy all values from the map into the vector, and delete the map.
2130     WriteBarrier<Unknown>* vector = storage->m_vector;
2131     SparseArrayValueMap::const_iterator end = map->end();
2132     for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
2133         vector[it->key].set(vm, this, it->value.getNonSparseMode());
2134     deallocateSparseIndexMap();
2135
2136     // Store the new property into the vector.
2137     WriteBarrier<Unknown>& valueSlot = vector[i];
2138     if (!valueSlot)
2139         ++storage->m_numValuesInVector;
2140     valueSlot.set(vm, this, value);
2141 }
2142
2143 void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
2144 {
2145     VM& vm = exec->vm();
2146
2147     // i should be a valid array index that is outside of the current vector.
2148     ASSERT(i <= MAX_ARRAY_INDEX);
2149     
2150     switch (indexingType()) {
2151     case ALL_BLANK_INDEXING_TYPES: {
2152         if (indexingShouldBeSparse()) {
2153             putByIndexBeyondVectorLengthWithArrayStorage(
2154                 exec, i, value, shouldThrow,
2155                 ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
2156             break;
2157         }
2158         if (indexIsSufficientlyBeyondLengthForSparseMap(i, 0) || i >= MIN_SPARSE_ARRAY_INDEX) {
2159             putByIndexBeyondVectorLengthWithArrayStorage(
2160                 exec, i, value, shouldThrow, createArrayStorage(vm, 0, 0));
2161             break;
2162         }
2163         if (structure(vm)->needsSlowPutIndexing()) {
2164             // Convert the indexing type to the SlowPutArrayStorage and retry.
2165             createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1));
2166             putByIndex(this, exec, i, value, shouldThrow);
2167             break;
2168         }
2169         
2170         createInitialForValueAndSet(vm, i, value);
2171         break;
2172     }
2173         
2174     case ALL_UNDECIDED_INDEXING_TYPES: {
2175         CRASH();
2176         break;
2177     }
2178         
2179     case ALL_INT32_INDEXING_TYPES: {
2180         putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value);
2181         break;
2182     }
2183         
2184     case ALL_DOUBLE_INDEXING_TYPES: {
2185         putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value);
2186         break;
2187     }
2188         
2189     case ALL_CONTIGUOUS_INDEXING_TYPES: {
2190         putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value);
2191         break;
2192     }
2193         
2194     case NonArrayWithSlowPutArrayStorage:
2195     case ArrayWithSlowPutArrayStorage: {
2196         // No own property present in the vector, but there might be in the sparse map!
2197         SparseArrayValueMap* map = arrayStorage()->m_sparseMap.get();
2198         if (!(map && map->contains(i)) && attemptToInterceptPutByIndexOnHole(exec, i, value, shouldThrow))
2199             return;
2200         FALLTHROUGH;
2201     }
2202
2203     case NonArrayWithArrayStorage:
2204     case ArrayWithArrayStorage:
2205         putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, arrayStorage());
2206         break;
2207         
2208     default:
2209         RELEASE_ASSERT_NOT_REACHED();
2210     }
2211 }
2212
2213 bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode, ArrayStorage* storage)
2214 {
2215     VM& vm = exec->vm();
2216     
2217     // i should be a valid array index that is outside of the current vector.
2218     ASSERT(hasAnyArrayStorage(indexingType()));
2219     ASSERT(arrayStorage() == storage);
2220     ASSERT(i >= storage->vectorLength() || attributes);
2221     ASSERT(i <= MAX_ARRAY_INDEX);
2222
2223     SparseArrayValueMap* map = storage->m_sparseMap.get();
2224
2225     // First, handle cases where we don't currently have a sparse map.
2226     if (LIKELY(!map)) {
2227         // If the array is not extensible, we should have entered dictionary mode, and created the spare map.
2228         ASSERT(isStructureExtensible());
2229     
2230         // Update m_length if necessary.
2231         if (i >= storage->length())
2232             storage->setLength(i + 1);
2233
2234         // Check that it is sensible to still be using a vector, and then try to grow the vector.
2235         if (LIKELY(
2236                 !attributes
2237                 && (isDenseEnoughForVector(i, storage->m_numValuesInVector))
2238                 && !indexIsSufficientlyBeyondLengthForSparseMap(i, storage->vectorLength()))
2239                 && increaseVectorLength(vm, i + 1)) {
2240             // success! - reread m_storage since it has likely been reallocated, and store to the vector.
2241             storage = arrayStorage();
2242             storage->m_vector[i].set(vm, this, value);
2243             ++storage->m_numValuesInVector;
2244             return true;
2245         }
2246         // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value.
2247         map = allocateSparseIndexMap(exec->vm());
2248         return map->putDirect(exec, this, i, value, attributes, mode);
2249     }
2250
2251     // Update m_length if necessary.
2252     unsigned length = storage->length();
2253     if (i >= length) {
2254         if (mode != PutDirectIndexLikePutDirect) {
2255             // Prohibit growing the array if length is not writable.
2256             if (map->lengthIsReadOnly())
2257                 return reject(exec, mode == PutDirectIndexShouldThrow, StrictModeReadonlyPropertyWriteError);
2258             if (!isStructureExtensible())
2259                 return reject(exec, mode == PutDirectIndexShouldThrow, "Attempting to define property on object that is not extensible.");
2260         }
2261         length = i + 1;
2262         storage->setLength(length);
2263     }
2264
2265     // We are currently using a map - check whether we still want to be doing so.
2266     // We will continue  to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails.
2267     unsigned numValuesInArray = storage->m_numValuesInVector + map->size();
2268     if (map->sparseMode() || attributes || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->vm(), length))
2269         return map->putDirect(exec, this, i, value, attributes, mode);
2270
2271     // Reread m_storage after increaseVectorLength, update m_numValuesInVector.
2272     storage = arrayStorage();
2273     storage->m_numValuesInVector = numValuesInArray;
2274
2275     // Copy all values from the map into the vector, and delete the map.
2276     WriteBarrier<Unknown>* vector = storage->m_vector;
2277     SparseArrayValueMap::const_iterator end = map->end();
2278     for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
2279         vector[it->key].set(vm, this, it->value.getNonSparseMode());
2280     deallocateSparseIndexMap();
2281
2282     // Store the new property into the vector.
2283     WriteBarrier<Unknown>& valueSlot = vector[i];
2284     if (!valueSlot)
2285         ++storage->m_numValuesInVector;
2286     valueSlot.set(vm, this, value);
2287     return true;
2288 }
2289
2290 bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode)
2291 {
2292     VM& vm = exec->vm();
2293
2294     // i should be a valid array index that is outside of the current vector.
2295     ASSERT(i <= MAX_ARRAY_INDEX);
2296     
2297     if (attributes & (ReadOnly | Accessor))
2298         notifyPresenceOfIndexedAccessors(vm);
2299     
2300     switch (indexingType()) {
2301     case ALL_BLANK_INDEXING_TYPES: {
2302         if (indexingShouldBeSparse() || attributes) {
2303             return putDirectIndexBeyondVectorLengthWithArrayStorage(
2304                 exec, i, value, attributes, mode,
2305                 ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
2306         }
2307         if (i >= MIN_SPARSE_ARRAY_INDEX) {
2308             return putDirectIndexBeyondVectorLengthWithArrayStorage(
2309                 exec, i, value, attributes, mode, createArrayStorage(vm, 0, 0));
2310         }
2311         if (structure(vm)->needsSlowPutIndexing()) {
2312             ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1));
2313             storage->m_vector[i].set(vm, this, value);
2314             storage->m_numValuesInVector++;
2315             return true;
2316         }
2317         
2318         createInitialForValueAndSet(vm, i, value);
2319         return true;
2320     }
2321         
2322     case ALL_UNDECIDED_INDEXING_TYPES: {
2323         convertUndecidedForValue(exec->vm(), value);
2324         // Reloop.
2325         return putDirectIndex(exec, i, value, attributes, mode);
2326     }
2327         
2328     case ALL_INT32_INDEXING_TYPES: {
2329         if (attributes) {
2330             if (i < m_butterfly.get(this)->vectorLength())
2331                 return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
2332             return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, convertInt32ToArrayStorage(vm));
2333         }
2334         if (!value.isInt32()) {
2335             convertInt32ForValue(vm, value);
2336             return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
2337         }
2338         putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value);
2339         return true;
2340     }
2341         
2342     case ALL_DOUBLE_INDEXING_TYPES: {
2343         if (attributes) {
2344             if (i < m_butterfly.get(this)->vectorLength())
2345                 return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
2346             return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, convertDoubleToArrayStorage(vm));
2347         }
2348         if (!value.isNumber()) {
2349             convertDoubleToContiguous(vm);
2350             return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
2351         }
2352         double valueAsDouble = value.asNumber();
2353         if (valueAsDouble != valueAsDouble) {
2354             convertDoubleToContiguous(vm);
2355             return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
2356         }
2357         putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value);
2358         return true;
2359     }
2360         
2361     case ALL_CONTIGUOUS_INDEXING_TYPES: {
2362         if (attributes) {
2363             if (i < m_butterfly.get(this)->vectorLength())
2364                 return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
2365             return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, convertContiguousToArrayStorage(vm));
2366         }
2367         putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value);
2368         return true;
2369     }
2370
2371     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
2372         if (attributes) {
2373             if (i < m_butterfly.get(this)->vectorLength())
2374                 return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
2375         }
2376         return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, arrayStorage());
2377         
2378     default:
2379         RELEASE_ASSERT_NOT_REACHED();
2380         return false;
2381     }
2382 }
2383
2384 void JSObject::putDirectNativeIntrinsicGetter(VM& vm, JSGlobalObject* globalObject, Identifier name, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
2385 {
2386     GetterSetter* accessor = GetterSetter::create(vm, globalObject);
2387     JSFunction* function = JSFunction::create(vm, globalObject, 0, name.string(), nativeFunction, intrinsic);
2388     accessor->setGetter(vm, globalObject, function);
2389     putDirectNonIndexAccessor(vm, name, accessor, attributes);
2390 }
2391
2392 void JSObject::putDirectNativeFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
2393 {
2394     StringImpl* name = propertyName.publicName();
2395     if (!name)
2396         name = vm.propertyNames->anonymous.impl();
2397     ASSERT(name);
2398
2399     JSFunction* function = JSFunction::create(vm, globalObject, functionLength, name, nativeFunction, intrinsic);
2400     putDirect(vm, propertyName, function, attributes);
2401 }
2402
2403 JSFunction* JSObject::putDirectBuiltinFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, FunctionExecutable* functionExecutable, unsigned attributes)
2404 {
2405     StringImpl* name = propertyName.publicName();
2406     if (!name)
2407         name = vm.propertyNames->anonymous.impl();
2408     ASSERT(name);
2409     JSFunction* function = JSFunction::createBuiltinFunction(vm, static_cast<FunctionExecutable*>(functionExecutable), globalObject);
2410     putDirect(vm, propertyName, function, attributes);
2411     return function;
2412 }
2413
2414 JSFunction* JSObject::putDirectBuiltinFunctionWithoutTransition(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, FunctionExecutable* functionExecutable, unsigned attributes)
2415 {
2416     JSFunction* function = JSFunction::createBuiltinFunction(vm, static_cast<FunctionExecutable*>(functionExecutable), globalObject);
2417     putDirectWithoutTransition(vm, propertyName, function, attributes);
2418     return function;
2419 }
2420
2421 void JSObject::putDirectNativeFunctionWithoutTransition(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
2422 {
2423     StringImpl* name = propertyName.publicName();
2424     if (!name)
2425         name = vm.propertyNames->anonymous.impl();
2426     ASSERT(name);
2427     JSFunction* function = JSFunction::create(vm, globalObject, functionLength, name, nativeFunction, intrinsic);
2428     putDirectWithoutTransition(vm, propertyName, function, attributes);
2429 }
2430
2431 ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength)
2432 {
2433     ASSERT(desiredLength <= MAX_STORAGE_VECTOR_LENGTH);
2434
2435     unsigned increasedLength;
2436     unsigned maxInitLength = std::min(currentLength, 100000U);
2437
2438     if (desiredLength < maxInitLength)
2439         increasedLength = maxInitLength;
2440     else if (!currentVectorLength)
2441         increasedLength = std::max(desiredLength, lastArraySize);
2442     else {
2443         increasedLength = timesThreePlusOneDividedByTwo(desiredLength);
2444     }
2445
2446     ASSERT(increasedLength >= desiredLength);
2447
2448     lastArraySize = std::min(increasedLength, FIRST_VECTOR_GROW);
2449
2450     return std::min(increasedLength, MAX_STORAGE_VECTOR_LENGTH);
2451 }
2452
2453 ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength)
2454 {
2455     unsigned vectorLength;
2456     unsigned length;
2457     
2458     if (hasIndexedProperties(indexingType())) {
2459         vectorLength = m_butterfly.get(this)->vectorLength();
2460         length = m_butterfly.get(this)->publicLength();
2461     } else {
2462         vectorLength = 0;
2463         length = 0;
2464     }
2465
2466     return getNewVectorLength(vectorLength, length, desiredLength);
2467 }
2468
2469 template<IndexingType indexingShape>
2470 unsigned JSObject::countElements(Butterfly* butterfly)
2471 {
2472     unsigned numValues = 0;
2473     for (unsigned i = butterfly->publicLength(); i--;) {
2474         switch (indexingShape) {
2475         case Int32Shape:
2476         case ContiguousShape:
2477             if (butterfly->contiguous()[i])
2478                 numValues++;
2479             break;
2480             
2481         case DoubleShape: {
2482             double value = butterfly->contiguousDouble()[i];
2483             if (value == value)
2484                 numValues++;
2485             break;
2486         }
2487             
2488         default:
2489             CRASH();
2490         }
2491     }
2492     return numValues;
2493 }
2494
2495 unsigned JSObject::countElements()
2496 {
2497     switch (indexingType()) {
2498     case ALL_BLANK_INDEXING_TYPES:
2499     case ALL_UNDECIDED_INDEXING_TYPES:
2500         return 0;
2501         
2502     case ALL_INT32_INDEXING_TYPES:
2503         return countElements<Int32Shape>(butterfly());
2504         
2505     case ALL_DOUBLE_INDEXING_TYPES:
2506         return countElements<DoubleShape>(butterfly());
2507         
2508     case ALL_CONTIGUOUS_INDEXING_TYPES:
2509         return countElements<ContiguousShape>(butterfly());
2510         
2511     default:
2512         CRASH();
2513         return 0;
2514     }
2515 }
2516
2517 bool JSObject::increaseVectorLength(VM& vm, unsigned newLength)
2518 {
2519     // This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map
2520     // to the vector. Callers have to account for that, because they can do it more efficiently.
2521     if (newLength > MAX_STORAGE_VECTOR_LENGTH)
2522         return false;
2523
2524     ArrayStorage* storage = arrayStorage();
2525     
2526     if (newLength >= MIN_SPARSE_ARRAY_INDEX
2527         && !isDenseEnoughForVector(newLength, storage->m_numValuesInVector))
2528         return false;
2529
2530     unsigned indexBias = storage->m_indexBias;
2531     unsigned vectorLength = storage->vectorLength();
2532     ASSERT(newLength > vectorLength);
2533     unsigned newVectorLength = getNewVectorLength(newLength);
2534
2535     // Fast case - there is no precapacity. In these cases a realloc makes sense.
2536     Structure* structure = this->structure(vm);
2537     if (LIKELY(!indexBias)) {
2538         DeferGC deferGC(vm.heap);
2539         Butterfly* newButterfly = storage->butterfly()->growArrayRight(
2540             vm, this, structure, structure->outOfLineCapacity(), true,
2541             ArrayStorage::sizeFor(vectorLength), ArrayStorage::sizeFor(newVectorLength));
2542         if (!newButterfly)
2543             return false;
2544         newButterfly->arrayStorage()->setVectorLength(newVectorLength);
2545         setButterflyWithoutChangingStructure(vm, newButterfly);
2546         return true;
2547     }
2548     
2549     // Remove some, but not all of the precapacity. Atomic decay, & capped to not overflow array length.
2550     DeferGC deferGC(vm.heap);
2551     unsigned newIndexBias = std::min(indexBias >> 1, MAX_STORAGE_VECTOR_LENGTH - newVectorLength);
2552     Butterfly* newButterfly = storage->butterfly()->resizeArray(
2553         vm, this,
2554         structure->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength),
2555         newIndexBias, true, ArrayStorage::sizeFor(newVectorLength));
2556     if (!newButterfly)
2557         return false;
2558     newButterfly->arrayStorage()->setVectorLength(newVectorLength);
2559     newButterfly->arrayStorage()->m_indexBias = newIndexBias;
2560     setButterflyWithoutChangingStructure(vm, newButterfly);
2561     return true;
2562 }
2563
2564 void JSObject::ensureLengthSlow(VM& vm, unsigned length)
2565 {
2566     Butterfly* butterfly = m_butterfly.get(this);
2567     
2568     ASSERT(length < MAX_ARRAY_INDEX);
2569     ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
2570     ASSERT(length > butterfly->vectorLength());
2571     
2572     unsigned newVectorLength = std::min(
2573         length << 1,
2574         MAX_STORAGE_VECTOR_LENGTH);
2575     unsigned oldVectorLength = butterfly->vectorLength();
2576     DeferGC deferGC(vm.heap);
2577     butterfly = butterfly->growArrayRight(
2578         vm, this, structure(), structure()->outOfLineCapacity(), true,
2579         oldVectorLength * sizeof(EncodedJSValue),
2580         newVectorLength * sizeof(EncodedJSValue));
2581     m_butterfly.set(vm, this, butterfly);
2582
2583     butterfly->setVectorLength(newVectorLength);
2584
2585     if (hasDouble(indexingType())) {
2586         for (unsigned i = oldVectorLength; i < newVectorLength; ++i)
2587             butterfly->contiguousDouble().data()[i] = PNaN;
2588     }
2589 }
2590
2591 void JSObject::reallocateAndShrinkButterfly(VM& vm, unsigned length)
2592 {
2593     ASSERT(length < MAX_ARRAY_INDEX);
2594     ASSERT(length < MAX_STORAGE_VECTOR_LENGTH);
2595     ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
2596     ASSERT(m_butterfly.get(this)->vectorLength() > length);
2597     ASSERT(!m_butterfly.get(this)->indexingHeader()->preCapacity(structure()));
2598
2599     DeferGC deferGC(vm.heap);
2600     Butterfly* newButterfly = m_butterfly.get(this)->resizeArray(vm, this, structure(), 0, ArrayStorage::sizeFor(length));
2601     m_butterfly.set(vm, this, newButterfly);
2602     newButterfly->setVectorLength(length);
2603     newButterfly->setPublicLength(length);
2604 }
2605
2606 Butterfly* JSObject::growOutOfLineStorage(VM& vm, size_t oldSize, size_t newSize)
2607 {
2608     ASSERT(newSize > oldSize);
2609
2610     // It's important that this function not rely on structure(), for the property
2611     // capacity, since we might have already mutated the structure in-place.
2612
2613     return Butterfly::createOrGrowPropertyStorage(m_butterfly.get(this), vm, this, structure(vm), oldSize, newSize);
2614 }
2615
2616 static JSBoundSlotBaseFunction* getBoundSlotBaseFunctionForGetterSetter(ExecState* exec, PropertyName propertyName, JSC::PropertySlot& slot, CustomGetterSetter* getterSetter, JSBoundSlotBaseFunction::Type type)
2617 {
2618     auto key = std::make_pair(getterSetter, (int)type);
2619     JSBoundSlotBaseFunction* boundSlotBase = exec->vm().customGetterSetterFunctionMap.get(key);
2620     if (!boundSlotBase) {
2621         boundSlotBase = JSBoundSlotBaseFunction::create(exec->vm(), exec->lexicalGlobalObject(), slot.slotBase(), getterSetter, type, propertyName.publicName());
2622         exec->vm().customGetterSetterFunctionMap.set(key, boundSlotBase);
2623     }
2624     return boundSlotBase;
2625 }
2626
2627 bool JSObject::getOwnPropertyDescriptor(ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
2628 {
2629     JSC::PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
2630     if (!methodTable(exec->vm())->getOwnPropertySlot(this, exec, propertyName, slot))
2631         return false;
2632
2633     // DebuggerScope::getOwnPropertySlot() (and possibly others) may return attributes from the prototype chain
2634     // but getOwnPropertyDescriptor() should only work for 'own' properties so we exit early if we detect that
2635     // the property is not an own property.
2636     if (slot.slotBase() != this && slot.slotBase()) {
2637         JSProxy* jsProxy = jsDynamicCast<JSProxy*>(this);
2638         if (!jsProxy || jsProxy->target() != slot.slotBase()) {
2639             // Try ProxyObject.
2640             ProxyObject* proxyObject = jsDynamicCast<ProxyObject*>(this);
2641             if (!proxyObject || proxyObject->target() != slot.slotBase())
2642                 return false;
2643         }
2644     }
2645
2646     if (slot.isAccessor())
2647         descriptor.setAccessorDescriptor(slot.getterSetter(), slot.attributes());
2648     else if (slot.attributes() & CustomAccessor) {
2649         descriptor.setCustomDescriptor(slot.attributes());
2650
2651         JSObject* thisObject = this;
2652         if (auto* proxy = jsDynamicCast<JSProxy*>(this))
2653             thisObject = proxy->target();
2654
2655         JSValue maybeGetterSetter = thisObject->getDirect(exec->vm(), propertyName);
2656         if (!maybeGetterSetter) {
2657             thisObject->reifyAllStaticProperties(exec);
2658             maybeGetterSetter = thisObject->getDirect(exec->vm(), propertyName);
2659         }
2660
2661         ASSERT(maybeGetterSetter);
2662         auto* getterSetter = jsCast<CustomGetterSetter*>(maybeGetterSetter);
2663         if (getterSetter->getter())
2664             descriptor.setGetter(getBoundSlotBaseFunctionForGetterSetter(exec, propertyName, slot, getterSetter, JSBoundSlotBaseFunction::Type::Getter));
2665         if (getterSetter->setter())
2666             descriptor.setSetter(getBoundSlotBaseFunctionForGetterSetter(exec, propertyName, slot, getterSetter, JSBoundSlotBaseFunction::Type::Setter));
2667     } else
2668         descriptor.setDescriptor(slot.getValue(exec, propertyName), slot.attributes());
2669     return true;
2670 }
2671
2672 static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName propertyName, const PropertyDescriptor& descriptor, unsigned attributes, const PropertyDescriptor& oldDescriptor)
2673 {
2674     VM& vm = exec->vm();
2675     if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) {
2676         if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) {
2677             GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject());
2678             if (oldDescriptor.getterPresent())
2679                 accessor->setGetter(vm, exec->lexicalGlobalObject(), oldDescriptor.getterObject());
2680             if (oldDescriptor.setterPresent())
2681                 accessor->setSetter(vm, exec->lexicalGlobalObject(), oldDescriptor.setterObject());
2682             target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor);
2683             return true;
2684         }
2685         JSValue newValue = jsUndefined();
2686         if (descriptor.value())
2687             newValue = descriptor.value();
2688         else if (oldDescriptor.value())
2689             newValue = oldDescriptor.value();
2690         target->putDirect(vm, propertyName, newValue, attributes & ~Accessor);
2691         if (attributes & ReadOnly)
2692             target->structure(vm)->setContainsReadOnlyProperties();
2693         return true;
2694     }
2695     attributes &= ~ReadOnly;
2696     GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject());
2697
2698     if (descriptor.getterPresent())
2699         accessor->setGetter(vm, exec->lexicalGlobalObject(), descriptor.getterObject());
2700     else if (oldDescriptor.getterPresent())
2701         accessor->setGetter(vm, exec->lexicalGlobalObject(), oldDescriptor.getterObject());
2702     if (descriptor.setterPresent())
2703         accessor->setSetter(vm, exec->lexicalGlobalObject(), descriptor.setterObject());
2704     else if (oldDescriptor.setterPresent())
2705         accessor->setSetter(vm, exec->lexicalGlobalObject(), oldDescriptor.setterObject());
2706
2707     target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor);
2708     return true;
2709 }
2710
2711 void JSObject::putDirectMayBeIndex(ExecState* exec, PropertyName propertyName, JSValue value)
2712 {
2713     if (Optional<uint32_t> index = parseIndex(propertyName))
2714         putDirectIndex(exec, index.value(), value);
2715     else
2716         putDirect(exec->vm(), propertyName, value);
2717 }
2718
2719 class DefineOwnPropertyScope {
2720 public:
2721     DefineOwnPropertyScope(ExecState* exec)
2722         : m_vm(exec->vm())
2723     {
2724         m_vm.setInDefineOwnProperty(true);
2725     }
2726
2727     ~DefineOwnPropertyScope()
2728     {
2729         m_vm.setInDefineOwnProperty(false);
2730     }
2731
2732 private:
2733     VM& m_vm;
2734 };
2735
2736
2737 // 9.1.6.3 of the spec
2738 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-validateandapplypropertydescriptor
2739 bool validateAndApplyPropertyDescriptor(ExecState* exec, JSObject* object, PropertyName propertyName, bool isExtensible,
2740     const PropertyDescriptor& descriptor, bool isCurrentDefined, const PropertyDescriptor& current, bool throwException)
2741 {
2742     // If we have a new property we can just put it on normally
2743     // Step 2.
2744     if (!isCurrentDefined) {
2745         // unless extensions are prevented!
2746         // Step 2.a
2747         if (!isExtensible) {
2748             if (throwException)
2749                 exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to define property on object that is not extensible.")));
2750             return false;
2751         }
2752         if (!object)
2753             return true;
2754         // Step 2.c/d
2755         PropertyDescriptor oldDescriptor;
2756         oldDescriptor.setValue(jsUndefined());
2757         // FIXME: spec says to always return true here.
2758         return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributes(), oldDescriptor);
2759     }
2760     // Step 3.
2761     if (descriptor.isEmpty())
2762         return true;
2763     // Step 4.
2764     if (current.equalTo(exec, descriptor))
2765         return true;
2766
2767     // Step 5.
2768     // Filter out invalid changes
2769     if (!current.configurable()) {
2770         if (descriptor.configurable()) {
2771             if (throwException)
2772                 exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change configurable attribute of unconfigurable property.")));
2773             return false;
2774         }
2775         if (descriptor.enumerablePresent() && descriptor.enumerable() != current.enumerable()) {
2776             if (throwException)
2777                 exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change enumerable attribute of unconfigurable property.")));
2778             return false;
2779         }
2780     }
2781     
2782     // Step 6.
2783     // A generic descriptor is simply changing the attributes of an existing property
2784     if (descriptor.isGenericDescriptor()) {
2785         if (!current.attributesEqual(descriptor) && object) {
2786             object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
2787             return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
2788         }
2789         return true;
2790     }
2791     
2792     // Step 7.
2793     // Changing between a normal property or an accessor property
2794     if (descriptor.isDataDescriptor() != current.isDataDescriptor()) {
2795         if (!current.configurable()) {
2796             if (throwException)
2797                 exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property.")));
2798             return false;
2799         }
2800
2801         if (!object)
2802             return true;
2803
2804         object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
2805         return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
2806     }
2807
2808     // Step 8.
2809     // Changing the value and attributes of an existing property
2810     if (descriptor.isDataDescriptor()) {
2811         if (!current.configurable()) {
2812             if (!current.writable() && descriptor.writable()) {
2813                 if (throwException)
2814                     exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change writable attribute of unconfigurable property.")));
2815                 return false;
2816             }
2817             if (!current.writable()) {
2818                 if (descriptor.value() && !sameValue(exec, current.value(), descriptor.value())) {
2819                     if (throwException)
2820                         exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change value of a readonly property.")));
2821                     return false;
2822                 }
2823             }
2824         }
2825         if (current.attributesEqual(descriptor) && !descriptor.value())
2826             return true;
2827         if (!object)
2828             return true;
2829         object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
2830         return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
2831     }
2832
2833     // Step 9.
2834     // Changing the accessor functions of an existing accessor property
2835     ASSERT(descriptor.isAccessorDescriptor());
2836     if (!current.configurable()) {
2837         if (descriptor.setterPresent() && !(current.setterPresent() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) {
2838             if (throwException)
2839                 exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change the setter of an unconfigurable property.")));
2840             return false;
2841         }
2842         if (descriptor.getterPresent() && !(current.getterPresent() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) {
2843             if (throwException)
2844                 exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change the getter of an unconfigurable property.")));
2845             return false;
2846         }
2847         if (current.attributes() & CustomAccessor) {
2848             if (throwException)
2849                 exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property.")));
2850             return false;
2851         }
2852     }
2853
2854     // Step 10/11.
2855     if (!object)
2856         return true;
2857     JSValue accessor = object->getDirect(exec->vm(), propertyName);
2858     if (!accessor)
2859         return false;
2860     GetterSetter* getterSetter;
2861     bool getterSetterChanged = false;
2862     if (accessor.isCustomGetterSetter())
2863         getterSetter = GetterSetter::create(exec->vm(), exec->lexicalGlobalObject());
2864     else {
2865         ASSERT(accessor.isGetterSetter());
2866         getterSetter = asGetterSetter(accessor);
2867     }
2868     if (descriptor.setterPresent()) {
2869         getterSetter = getterSetter->withSetter(exec->vm(), exec->lexicalGlobalObject(), descriptor.setterObject());
2870         getterSetterChanged = true;
2871     }
2872     if (descriptor.getterPresent()) {
2873         getterSetter = getterSetter->withGetter(exec->vm(), exec->lexicalGlobalObject(), descriptor.getterObject());
2874         getterSetterChanged = true;
2875     }
2876     if (current.attributesEqual(descriptor) && !getterSetterChanged)
2877         return true;
2878     object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
2879     unsigned attrs = descriptor.attributesOverridingCurrent(current);
2880     object->putDirectAccessor(exec, propertyName, getterSetter, attrs | Accessor);
2881     return true;
2882 }
2883
2884 bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
2885 {
2886     // Track on the globaldata that we're in define property.
2887     // Currently DefineOwnProperty uses delete to remove properties when they are being replaced
2888     // (particularly when changing attributes), however delete won't allow non-configurable (i.e.
2889     // DontDelete) properties to be deleted. For now, we can use this flag to make this work.
2890     DefineOwnPropertyScope scope(exec);
2891     PropertyDescriptor current;
2892     bool isCurrentDefined = getOwnPropertyDescriptor(exec, propertyName, current);
2893     bool isExtensible = this->isExtensible(exec);
2894     if (UNLIKELY(exec->hadException()))
2895         return false;
2896     return validateAndApplyPropertyDescriptor(exec, this, propertyName, isExtensible, descriptor, isCurrentDefined, current, throwException);
2897 }
2898
2899 bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
2900 {
2901     // If it's an array index, then use the indexed property storage.
2902     if (Optional<uint32_t> index = parseIndex(propertyName)) {
2903         // 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.
2904         // d. Reject if succeeded is false.
2905         // e. If index >= oldLen
2906         // e.i. Set oldLenDesc.[[Value]] to index + 1.
2907         // 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.
2908         // f. Return true.
2909         return object->defineOwnIndexedProperty(exec, index.value(), descriptor, throwException);
2910     }
2911     
2912     return object->defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException);
2913 }
2914
2915 JSObject* throwTypeError(ExecState* exec, const String& message)
2916 {
2917     return exec->vm().throwException(exec, createTypeError(exec, message));
2918 }
2919
2920 void JSObject::convertToDictionary(VM& vm)
2921 {
2922     DeferredStructureTransitionWatchpointFire deferredWatchpointFire;
2923     setStructure(
2924         vm, Structure::toCacheableDictionaryTransition(vm, structure(vm), &deferredWatchpointFire));
2925 }
2926
2927 void JSObject::shiftButterflyAfterFlattening(VM& vm, size_t outOfLineCapacityBefore, size_t outOfLineCapacityAfter)
2928 {
2929     Butterfly* butterfly = this->butterfly();
2930     size_t preCapacity = this->butterflyPreCapacity();
2931     void* currentBase = butterfly->base(preCapacity, outOfLineCapacityAfter);
2932     void* newBase = butterfly->base(preCapacity, outOfLineCapacityBefore);
2933
2934     memmove(newBase, currentBase, this->butterflyTotalSize());
2935     setButterflyWithoutChangingStructure(vm, Butterfly::fromBase(newBase, preCapacity, outOfLineCapacityAfter));
2936 }
2937
2938 uint32_t JSObject::getEnumerableLength(ExecState* exec, JSObject* object)
2939 {
2940     VM& vm = exec->vm();
2941     Structure* structure = object->structure(vm);
2942     if (structure->holesMustForwardToPrototype(vm))
2943         return 0;
2944     switch (object->indexingType()) {
2945     case ALL_BLANK_INDEXING_TYPES:
2946     case ALL_UNDECIDED_INDEXING_TYPES:
2947         return 0;
2948         
2949     case ALL_INT32_INDEXING_TYPES:
2950     case ALL_CONTIGUOUS_INDEXING_TYPES: {
2951         Butterfly* butterfly = object->butterfly();
2952         unsigned usedLength = butterfly->publicLength();
2953         for (unsigned i = 0; i < usedLength; ++i) {
2954             if (!butterfly->contiguous()[i])
2955                 return 0;
2956         }
2957         return usedLength;
2958     }
2959         
2960     case ALL_DOUBLE_INDEXING_TYPES: {
2961         Butterfly* butterfly = object->butterfly();
2962         unsigned usedLength = butterfly->publicLength();
2963         for (unsigned i = 0; i < usedLength; ++i) {
2964             double value = butterfly->contiguousDouble()[i];
2965             if (value != value)
2966                 return 0;
2967         }
2968         return usedLength;
2969     }
2970         
2971     case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
2972         ArrayStorage* storage = object->m_butterfly.get(object)->arrayStorage();
2973         if (storage->m_sparseMap.get())
2974             return 0;
2975         
2976         unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
2977         for (unsigned i = 0; i < usedVectorLength; ++i) {
2978             if (!storage->m_vector[i])
2979                 return 0;
2980         }
2981         return usedVectorLength;
2982     }
2983         
2984     default:
2985         RELEASE_ASSERT_NOT_REACHED();
2986         return 0;
2987     }
2988 }
2989
2990 void JSObject::getStructurePropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
2991 {
2992     VM& vm = exec->vm();
2993     object->structure(vm)->getPropertyNamesFromStructure(vm, propertyNames, mode);
2994 }
2995
2996 void JSObject::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
2997 {
2998     VM& vm = exec->vm();
2999     object->methodTable(vm)->getOwnPropertyNames(object, exec, propertyNames, EnumerationMode(mode, JSObjectPropertiesMode::Exclude));
3000
3001     if (object->prototype().isNull())
3002         return;
3003
3004     JSObject* prototype = asObject(object->prototype());
3005     while (true) {
3006         if (prototype->structure(vm)->typeInfo().overridesGetPropertyNames()) {
3007             prototype->methodTable(vm)->getPropertyNames(prototype, exec, propertyNames, mode);
3008             break;
3009         }
3010         prototype->methodTable(vm)->getOwnPropertyNames(prototype, exec, propertyNames, mode);
3011         JSValue nextProto = prototype->prototype();
3012         if (nextProto.isNull())
3013             break;
3014         prototype = asObject(nextProto);
3015     }
3016 }
3017
3018 // Implements GetMethod(O, P) in section 7.3.9 of the spec.
3019 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-getmethod
3020 JSValue JSObject::getMethod(ExecState* exec, CallData& callData, CallType& callType, const Identifier& ident, const String& errorMessage)
3021 {
3022     JSValue method = get(exec, ident);
3023     if (exec->hadException())
3024         return jsUndefined();
3025
3026     if (!method.isCell()) {
3027         if (method.isUndefinedOrNull())
3028             return jsUndefined();
3029
3030         throwVMTypeError(exec, errorMessage);
3031         return jsUndefined();
3032     }
3033
3034     callType = method.asCell()->methodTable()->getCallData(method.asCell(), callData);
3035     if (callType == CallTypeNone) {
3036         throwVMTypeError(exec, errorMessage);
3037         return jsUndefined();
3038     }
3039
3040     return method;
3041 }
3042
3043 } // namespace JSC