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