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