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