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