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