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