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