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