PropertyAttribute needs a CustomValue bit.
[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             RELEASE_AND_RETURN(scope, proxy->ProxyObject::put(proxy, exec, propertyName, value, slot));
661         }
662
663         // 9.1.9.1-2 Let ownDesc be ? O.[[GetOwnProperty]](P).
664         bool ownDescriptorFound = current->getOwnPropertyDescriptor(exec, propertyName, ownDescriptor);
665         RETURN_IF_EXCEPTION(scope, false);
666
667         if (!ownDescriptorFound) {
668             // 9.1.9.1-3-a Let parent be ? O.[[GetPrototypeOf]]().
669             JSValue prototype = current->getPrototype(vm, exec);
670             RETURN_IF_EXCEPTION(scope, false);
671
672             // 9.1.9.1-3-b If parent is not null, then
673             if (!prototype.isNull()) {
674                 // 9.1.9.1-3-b-i Return ? parent.[[Set]](P, V, Receiver).
675                 current = asObject(prototype);
676                 continue;
677             }
678             // 9.1.9.1-3-c-i Let ownDesc be the PropertyDescriptor{[[Value]]: undefined, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}.
679             ownDescriptor = PropertyDescriptor(jsUndefined(), static_cast<unsigned>(PropertyAttribute::None));
680         }
681         break;
682     }
683
684     // 9.1.9.1-4 If IsDataDescriptor(ownDesc) is true, then
685     if (ownDescriptor.isDataDescriptor()) {
686         // 9.1.9.1-4-a If ownDesc.[[Writable]] is false, return false.
687         if (!ownDescriptor.writable())
688             return typeError(exec, scope, shouldThrow, ReadonlyPropertyWriteError);
689
690         // 9.1.9.1-4-b If Type(Receiver) is not Object, return false.
691         if (!receiver.isObject())
692             return typeError(exec, scope, shouldThrow, ReadonlyPropertyWriteError);
693
694         // In OrdinarySet, the receiver may not be the same to the object.
695         // So, we perform [[GetOwnProperty]] onto the receiver while we already perform [[GetOwnProperty]] onto the object.
696
697         // 9.1.9.1-4-c Let existingDescriptor be ? Receiver.[[GetOwnProperty]](P).
698         JSObject* receiverObject = asObject(receiver);
699         PropertyDescriptor existingDescriptor;
700         bool existingDescriptorFound = receiverObject->getOwnPropertyDescriptor(exec, propertyName, existingDescriptor);
701         RETURN_IF_EXCEPTION(scope, false);
702
703         // 9.1.9.1-4-d If existingDescriptor is not undefined, then
704         if (existingDescriptorFound) {
705             // 9.1.9.1-4-d-i If IsAccessorDescriptor(existingDescriptor) is true, return false.
706             if (existingDescriptor.isAccessorDescriptor())
707                 return typeError(exec, scope, shouldThrow, ReadonlyPropertyWriteError);
708
709             // 9.1.9.1-4-d-ii If existingDescriptor.[[Writable]] is false, return false.
710             if (!existingDescriptor.writable())
711                 return typeError(exec, scope, shouldThrow, ReadonlyPropertyWriteError);
712
713             // 9.1.9.1-4-d-iii Let valueDesc be the PropertyDescriptor{[[Value]]: V}.
714             PropertyDescriptor valueDescriptor;
715             valueDescriptor.setValue(value);
716
717             // 9.1.9.1-4-d-iv Return ? Receiver.[[DefineOwnProperty]](P, valueDesc).
718             RELEASE_AND_RETURN(scope, receiverObject->methodTable(vm)->defineOwnProperty(receiverObject, exec, propertyName, valueDescriptor, shouldThrow));
719         }
720
721         // 9.1.9.1-4-e Else Receiver does not currently have a property P,
722         // 9.1.9.1-4-e-i Return ? CreateDataProperty(Receiver, P, V).
723         RELEASE_AND_RETURN(scope, receiverObject->methodTable(vm)->defineOwnProperty(receiverObject, exec, propertyName, PropertyDescriptor(value, static_cast<unsigned>(PropertyAttribute::None)), shouldThrow));
724     }
725
726     // 9.1.9.1-5 Assert: IsAccessorDescriptor(ownDesc) is true.
727     ASSERT(ownDescriptor.isAccessorDescriptor());
728
729     // 9.1.9.1-6 Let setter be ownDesc.[[Set]].
730     // 9.1.9.1-7 If setter is undefined, return false.
731     JSValue setter = ownDescriptor.setter();
732     if (!setter.isObject())
733         return typeError(exec, scope, shouldThrow, ReadonlyPropertyWriteError);
734
735     // 9.1.9.1-8 Perform ? Call(setter, Receiver, << V >>).
736     JSObject* setterObject = asObject(setter);
737     MarkedArgumentBuffer args;
738     args.append(value);
739     ASSERT(!args.hasOverflowed());
740
741     CallData callData;
742     CallType callType = setterObject->methodTable(vm)->getCallData(setterObject, callData);
743     scope.release();
744     call(exec, setterObject, callType, callData, receiver, args);
745
746     // 9.1.9.1-9 Return true.
747     return true;
748 }
749
750 // ECMA 8.6.2.2
751 bool JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
752 {
753     return putInlineForJSObject(cell, exec, propertyName, value, slot);
754 }
755
756 bool JSObject::putInlineSlow(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
757 {
758     ASSERT(!isThisValueAltered(slot, this));
759
760     VM& vm = exec->vm();
761     auto scope = DECLARE_THROW_SCOPE(vm);
762
763     JSObject* obj = this;
764     for (;;) {
765         unsigned attributes;
766         PropertyOffset offset = obj->structure(vm)->get(vm, propertyName, attributes);
767         if (isValidOffset(offset)) {
768             if (attributes & PropertyAttribute::ReadOnly) {
769                 ASSERT(this->prototypeChainMayInterceptStoreTo(vm, propertyName) || obj == this);
770                 return typeError(exec, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
771             }
772
773             JSValue gs = obj->getDirect(offset);
774             if (gs.isGetterSetter()) {
775                 // We need to make sure that we decide to cache this property before we potentially execute aribitrary JS.
776                 if (!structure(vm)->isDictionary())
777                     slot.setCacheableSetter(obj, offset);
778
779                 bool result = callSetter(exec, slot.thisValue(), gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode);
780                 RETURN_IF_EXCEPTION(scope, false);
781                 return result;
782             }
783             if (gs.isCustomGetterSetter()) {
784                 // We need to make sure that we decide to cache this property before we potentially execute aribitrary JS.
785                 if (attributes & PropertyAttribute::CustomAccessor)
786                     slot.setCustomAccessor(obj, jsCast<CustomGetterSetter*>(gs.asCell())->setter());
787                 else
788                     slot.setCustomValue(obj, jsCast<CustomGetterSetter*>(gs.asCell())->setter());
789
790                 bool result = callCustomSetter(exec, gs, attributes & PropertyAttribute::CustomAccessor, obj, slot.thisValue(), value);
791                 RETURN_IF_EXCEPTION(scope, false);
792                 return result;
793             }
794             ASSERT(!(attributes & PropertyAttribute::Accessor));
795
796             // If there's an existing property on the object or one of its 
797             // prototypes it should be replaced, so break here.
798             break;
799         }
800         if (!obj->staticPropertiesReified(vm)) {
801             if (obj->classInfo(vm)->hasStaticSetterOrReadonlyProperties()) {
802                 if (auto entry = obj->findPropertyHashEntry(vm, propertyName))
803                     RELEASE_AND_RETURN(scope, putEntry(exec, entry->table->classForThis, entry->value, obj, this, propertyName, value, slot));
804             }
805         }
806         if (obj->type() == ProxyObjectType && propertyName != vm.propertyNames->underscoreProto) {
807             // FIXME: We shouldn't unconditionally perform [[Set]] here.
808             // We need to do more because this is observable behavior.
809             // https://bugs.webkit.org/show_bug.cgi?id=155012
810             ProxyObject* proxy = jsCast<ProxyObject*>(obj);
811             RELEASE_AND_RETURN(scope, proxy->ProxyObject::put(proxy, exec, propertyName, value, slot));
812         }
813         JSValue prototype = obj->getPrototype(vm, exec);
814         RETURN_IF_EXCEPTION(scope, false);
815         if (prototype.isNull())
816             break;
817         obj = asObject(prototype);
818     }
819
820     if (!putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot))
821         return typeError(exec, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
822     return true;
823 }
824
825 bool JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
826 {
827     VM& vm = exec->vm();
828     JSObject* thisObject = jsCast<JSObject*>(cell);
829
830     if (propertyName > MAX_ARRAY_INDEX) {
831         PutPropertySlot slot(cell, shouldThrow);
832         return thisObject->methodTable(vm)->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot);
833     }
834
835     thisObject->ensureWritable(vm);
836
837     switch (thisObject->indexingType()) {
838     case ALL_BLANK_INDEXING_TYPES:
839         break;
840         
841     case ALL_UNDECIDED_INDEXING_TYPES: {
842         thisObject->convertUndecidedForValue(vm, value);
843         // Reloop.
844         return putByIndex(cell, exec, propertyName, value, shouldThrow);
845     }
846         
847     case ALL_INT32_INDEXING_TYPES: {
848         if (!value.isInt32()) {
849             thisObject->convertInt32ForValue(vm, value);
850             return putByIndex(cell, exec, propertyName, value, shouldThrow);
851         }
852         FALLTHROUGH;
853     }
854         
855     case ALL_CONTIGUOUS_INDEXING_TYPES: {
856         Butterfly* butterfly = thisObject->butterfly();
857         if (propertyName >= butterfly->vectorLength())
858             break;
859         butterfly->contiguous().at(thisObject, propertyName).set(vm, thisObject, value);
860         if (propertyName >= butterfly->publicLength())
861             butterfly->setPublicLength(propertyName + 1);
862         return true;
863     }
864         
865     case ALL_DOUBLE_INDEXING_TYPES: {
866         if (!value.isNumber()) {
867             thisObject->convertDoubleToContiguous(vm);
868             // Reloop.
869             return putByIndex(cell, exec, propertyName, value, shouldThrow);
870         }
871
872         double valueAsDouble = value.asNumber();
873         if (valueAsDouble != valueAsDouble) {
874             thisObject->convertDoubleToContiguous(vm);
875             // Reloop.
876             return putByIndex(cell, exec, propertyName, value, shouldThrow);
877         }
878         Butterfly* butterfly = thisObject->butterfly();
879         if (propertyName >= butterfly->vectorLength())
880             break;
881         butterfly->contiguousDouble().at(thisObject, propertyName) = valueAsDouble;
882         if (propertyName >= butterfly->publicLength())
883             butterfly->setPublicLength(propertyName + 1);
884         return true;
885     }
886         
887     case NonArrayWithArrayStorage:
888     case ArrayWithArrayStorage: {
889         ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
890         
891         if (propertyName >= storage->vectorLength())
892             break;
893         
894         WriteBarrier<Unknown>& valueSlot = storage->m_vector[propertyName];
895         unsigned length = storage->length();
896         
897         // Update length & m_numValuesInVector as necessary.
898         if (propertyName >= length) {
899             length = propertyName + 1;
900             storage->setLength(length);
901             ++storage->m_numValuesInVector;
902         } else if (!valueSlot)
903             ++storage->m_numValuesInVector;
904         
905         valueSlot.set(vm, thisObject, value);
906         return true;
907     }
908         
909     case NonArrayWithSlowPutArrayStorage:
910     case ArrayWithSlowPutArrayStorage: {
911         ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
912         
913         if (propertyName >= storage->vectorLength())
914             break;
915         
916         WriteBarrier<Unknown>& valueSlot = storage->m_vector[propertyName];
917         unsigned length = storage->length();
918         
919         // Update length & m_numValuesInVector as necessary.
920         if (propertyName >= length) {
921             bool putResult = false;
922             if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow, putResult))
923                 return putResult;
924             length = propertyName + 1;
925             storage->setLength(length);
926             ++storage->m_numValuesInVector;
927         } else if (!valueSlot) {
928             bool putResult = false;
929             if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow, putResult))
930                 return putResult;
931             ++storage->m_numValuesInVector;
932         }
933         
934         valueSlot.set(vm, thisObject, value);
935         return true;
936     }
937         
938     default:
939         RELEASE_ASSERT_NOT_REACHED();
940     }
941     
942     return thisObject->putByIndexBeyondVectorLength(exec, propertyName, value, shouldThrow);
943 }
944
945 ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM& vm, ArrayStorage* storage)
946 {
947     SparseArrayValueMap* map = storage->m_sparseMap.get();
948
949     if (!map)
950         map = allocateSparseIndexMap(vm);
951
952     if (map->sparseMode())
953         return storage;
954
955     map->setSparseMode();
956
957     unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
958     for (unsigned i = 0; i < usedVectorLength; ++i) {
959         JSValue value = storage->m_vector[i].get();
960         // This will always be a new entry in the map, so no need to check we can write,
961         // and attributes are default so no need to set them.
962         if (value)
963             map->add(this, i).iterator->value.forceSet(vm, map, value, 0);
964     }
965
966     DeferGC deferGC(vm.heap);
967     Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, this, structure(vm), 0, ArrayStorage::sizeFor(0));
968     RELEASE_ASSERT(newButterfly);
969     newButterfly->arrayStorage()->m_indexBias = 0;
970     newButterfly->arrayStorage()->setVectorLength(0);
971     newButterfly->arrayStorage()->m_sparseMap.set(vm, this, map);
972     setButterfly(vm, newButterfly);
973     
974     return newButterfly->arrayStorage();
975 }
976
977 void JSObject::enterDictionaryIndexingMode(VM& vm)
978 {
979     switch (indexingType()) {
980     case ALL_BLANK_INDEXING_TYPES:
981     case ALL_UNDECIDED_INDEXING_TYPES:
982     case ALL_INT32_INDEXING_TYPES:
983     case ALL_DOUBLE_INDEXING_TYPES:
984     case ALL_CONTIGUOUS_INDEXING_TYPES:
985         // NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize
986         // this case if we ever cared. Note that ensureArrayStorage() can return null if the object
987         // doesn't support traditional indexed properties. At the time of writing, this just affects
988         // typed arrays.
989         if (ArrayStorage* storage = ensureArrayStorageSlow(vm))
990             enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, storage);
991         break;
992     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
993         enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage());
994         break;
995         
996     default:
997         break;
998     }
999 }
1000
1001 void JSObject::notifyPresenceOfIndexedAccessors(VM& vm)
1002 {
1003     if (mayInterceptIndexedAccesses(vm))
1004         return;
1005     
1006     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AddIndexedAccessors));
1007     
1008     if (!mayBePrototype())
1009         return;
1010     
1011     globalObject(vm)->haveABadTime(vm);
1012 }
1013
1014 Butterfly* JSObject::createInitialIndexedStorage(VM& vm, unsigned length)
1015 {
1016     ASSERT(length <= MAX_STORAGE_VECTOR_LENGTH);
1017     IndexingType oldType = indexingType();
1018     ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
1019     ASSERT(!needsSlowPutIndexing(vm));
1020     ASSERT(!indexingShouldBeSparse(vm));
1021     Structure* structure = this->structure(vm);
1022     unsigned propertyCapacity = structure->outOfLineCapacity();
1023     unsigned vectorLength = Butterfly::optimalContiguousVectorLength(propertyCapacity, length);
1024     Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
1025         butterfly(), vm, this, structure, propertyCapacity, false, 0,
1026         sizeof(EncodedJSValue) * vectorLength);
1027     newButterfly->setPublicLength(length);
1028     newButterfly->setVectorLength(vectorLength);
1029     return newButterfly;
1030 }
1031
1032 Butterfly* JSObject::createInitialUndecided(VM& vm, unsigned length)
1033 {
1034     DeferGC deferGC(vm.heap);
1035     Butterfly* newButterfly = createInitialIndexedStorage(vm, length);
1036     StructureID oldStructureID = this->structureID();
1037     Structure* oldStructure = vm.getStructure(oldStructureID);
1038     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateUndecided);
1039     nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly);
1040     setStructure(vm, newStructure);
1041     return newButterfly;
1042 }
1043
1044 ContiguousJSValues JSObject::createInitialInt32(VM& vm, unsigned length)
1045 {
1046     DeferGC deferGC(vm.heap);
1047     Butterfly* newButterfly = createInitialIndexedStorage(vm, length);
1048     for (unsigned i = newButterfly->vectorLength(); i--;)
1049         newButterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue());
1050     StructureID oldStructureID = this->structureID();
1051     Structure* oldStructure = vm.getStructure(oldStructureID);
1052     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateInt32);
1053     nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly);
1054     setStructure(vm, newStructure);
1055     return newButterfly->contiguousInt32();
1056 }
1057
1058 ContiguousDoubles JSObject::createInitialDouble(VM& vm, unsigned length)
1059 {
1060     DeferGC deferGC(vm.heap);
1061     Butterfly* newButterfly = createInitialIndexedStorage(vm, length);
1062     for (unsigned i = newButterfly->vectorLength(); i--;)
1063         newButterfly->contiguousDouble().at(this, i) = PNaN;
1064     StructureID oldStructureID = this->structureID();
1065     Structure* oldStructure = vm.getStructure(oldStructureID);
1066     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateDouble);
1067     nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly);
1068     setStructure(vm, newStructure);
1069     return newButterfly->contiguousDouble();
1070 }
1071
1072 ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length)
1073 {
1074     DeferGC deferGC(vm.heap);
1075     Butterfly* newButterfly = createInitialIndexedStorage(vm, length);
1076     for (unsigned i = newButterfly->vectorLength(); i--;)
1077         newButterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue());
1078     StructureID oldStructureID = this->structureID();
1079     Structure* oldStructure = vm.getStructure(oldStructureID);
1080     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateContiguous);
1081     nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly);
1082     setStructure(vm, newStructure);
1083     return newButterfly->contiguous();
1084 }
1085
1086 Butterfly* JSObject::createArrayStorageButterfly(VM& vm, JSObject* intendedOwner, Structure* structure, unsigned length, unsigned vectorLength, Butterfly* oldButterfly)
1087 {
1088     Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
1089         oldButterfly, vm, intendedOwner, structure, structure->outOfLineCapacity(), false, 0,
1090         ArrayStorage::sizeFor(vectorLength));
1091     RELEASE_ASSERT(newButterfly);
1092
1093     ArrayStorage* result = newButterfly->arrayStorage();
1094     result->setLength(length);
1095     result->setVectorLength(vectorLength);
1096     result->m_sparseMap.clear();
1097     result->m_numValuesInVector = 0;
1098     result->m_indexBias = 0;
1099     for (size_t i = vectorLength; i--;)
1100         result->m_vector[i].setWithoutWriteBarrier(JSValue());
1101
1102     return newButterfly;
1103 }
1104
1105 ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vectorLength)
1106 {
1107     DeferGC deferGC(vm.heap);
1108     StructureID oldStructureID = this->structureID();
1109     Structure* oldStructure = vm.getStructure(oldStructureID);
1110     IndexingType oldType = indexingType();
1111     ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
1112
1113     Butterfly* newButterfly = createArrayStorageButterfly(vm, this, oldStructure, length, vectorLength, butterfly());
1114     ArrayStorage* result = newButterfly->arrayStorage();
1115     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, suggestedArrayStorageTransition(vm));
1116     nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly);
1117     setStructure(vm, newStructure);
1118     return result;
1119 }
1120
1121 ArrayStorage* JSObject::createInitialArrayStorage(VM& vm)
1122 {
1123     return createArrayStorage(
1124         vm, 0, ArrayStorage::optimalVectorLength(0, structure(vm)->outOfLineCapacity(), 0));
1125 }
1126
1127 ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm)
1128 {
1129     ASSERT(hasUndecided(indexingType()));
1130
1131     Butterfly* butterfly = this->butterfly();
1132     for (unsigned i = butterfly->vectorLength(); i--;)
1133         butterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue());
1134
1135     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateInt32));
1136     return m_butterfly->contiguousInt32();
1137 }
1138
1139 ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm)
1140 {
1141     ASSERT(hasUndecided(indexingType()));
1142
1143     Butterfly* butterfly = m_butterfly.get();
1144     for (unsigned i = butterfly->vectorLength(); i--;)
1145         butterfly->contiguousDouble().at(this, i) = PNaN;
1146     
1147     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateDouble));
1148     return m_butterfly->contiguousDouble();
1149 }
1150
1151 ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm)
1152 {
1153     ASSERT(hasUndecided(indexingType()));
1154
1155     Butterfly* butterfly = m_butterfly.get();
1156     for (unsigned i = butterfly->vectorLength(); i--;)
1157         butterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue());
1158
1159     WTF::storeStoreFence();
1160     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateContiguous));
1161     return m_butterfly->contiguous();
1162 }
1163
1164 ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM& vm, unsigned neededLength)
1165 {
1166     Structure* structure = this->structure(vm);
1167     unsigned publicLength = m_butterfly->publicLength();
1168     unsigned propertyCapacity = structure->outOfLineCapacity();
1169
1170     Butterfly* newButterfly = Butterfly::createUninitialized(vm, this, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
1171     
1172     memcpy(
1173         newButterfly->base(0, propertyCapacity),
1174         m_butterfly->base(0, propertyCapacity),
1175         propertyCapacity * sizeof(EncodedJSValue));
1176
1177     ArrayStorage* newStorage = newButterfly->arrayStorage();
1178     newStorage->setVectorLength(neededLength);
1179     newStorage->setLength(publicLength);
1180     newStorage->m_sparseMap.clear();
1181     newStorage->m_indexBias = 0;
1182     newStorage->m_numValuesInVector = 0;
1183     
1184     return newStorage;
1185 }
1186
1187 ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition)
1188 {
1189     DeferGC deferGC(vm.heap);
1190     ASSERT(hasUndecided(indexingType()));
1191
1192     unsigned vectorLength = m_butterfly->vectorLength();
1193     ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
1194     
1195     for (unsigned i = vectorLength; i--;)
1196         storage->m_vector[i].setWithoutWriteBarrier(JSValue());
1197     
1198     StructureID oldStructureID = this->structureID();
1199     Structure* oldStructure = vm.getStructure(oldStructureID);
1200     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, transition);
1201     nukeStructureAndSetButterfly(vm, oldStructureID, storage->butterfly());
1202     setStructure(vm, newStructure);
1203     return storage;
1204 }
1205
1206 ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm)
1207 {
1208     return convertUndecidedToArrayStorage(vm, suggestedArrayStorageTransition(vm));
1209 }
1210
1211 ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm)
1212 {
1213     ASSERT(hasInt32(indexingType()));
1214     ASSERT(!isCopyOnWrite(indexingMode()));
1215
1216     Butterfly* butterfly = m_butterfly.get();
1217     for (unsigned i = butterfly->vectorLength(); i--;) {
1218         WriteBarrier<Unknown>* current = &butterfly->contiguous().atUnsafe(i);
1219         double* currentAsDouble = bitwise_cast<double*>(current);
1220         JSValue v = current->get();
1221         // NOTE: Since this may be used during initialization, v could be garbage. If it's garbage,
1222         // that means it will be overwritten later.
1223         if (!v.isInt32()) {
1224             *currentAsDouble = PNaN;
1225             continue;
1226         }
1227         *currentAsDouble = v.asInt32();
1228     }
1229     
1230     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateDouble));
1231     return m_butterfly->contiguousDouble();
1232 }
1233
1234 ContiguousJSValues JSObject::convertInt32ToContiguous(VM& vm)
1235 {
1236     ASSERT(hasInt32(indexingType()));
1237     
1238     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateContiguous));
1239     return m_butterfly->contiguous();
1240 }
1241
1242 ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition)
1243 {
1244     DeferGC deferGC(vm.heap);
1245     ASSERT(hasInt32(indexingType()));
1246
1247     unsigned vectorLength = m_butterfly->vectorLength();
1248     ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
1249     Butterfly* butterfly = m_butterfly.get();
1250     for (unsigned i = 0; i < vectorLength; i++) {
1251         JSValue v = butterfly->contiguous().at(this, i).get();
1252         newStorage->m_vector[i].setWithoutWriteBarrier(v);
1253         if (v)
1254             newStorage->m_numValuesInVector++;
1255     }
1256     
1257     StructureID oldStructureID = this->structureID();
1258     Structure* oldStructure = vm.getStructure(oldStructureID);
1259     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, transition);
1260     nukeStructureAndSetButterfly(vm, oldStructureID, newStorage->butterfly());
1261     setStructure(vm, newStructure);
1262     return newStorage;
1263 }
1264
1265 ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm)
1266 {
1267     return convertInt32ToArrayStorage(vm, suggestedArrayStorageTransition(vm));
1268 }
1269
1270 ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm)
1271 {
1272     ASSERT(hasDouble(indexingType()));
1273     ASSERT(!isCopyOnWrite(indexingMode()));
1274
1275     Butterfly* butterfly = m_butterfly.get();
1276     for (unsigned i = butterfly->vectorLength(); i--;) {
1277         double* current = &butterfly->contiguousDouble().atUnsafe(i);
1278         WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current);
1279         double value = *current;
1280         if (value != value) {
1281             currentAsValue->clear();
1282             continue;
1283         }
1284         JSValue v = JSValue(JSValue::EncodeAsDouble, value);
1285         currentAsValue->setWithoutWriteBarrier(v);
1286     }
1287     
1288     WTF::storeStoreFence();
1289     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateContiguous));
1290     return m_butterfly->contiguous();
1291 }
1292
1293 ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition)
1294 {
1295     DeferGC deferGC(vm.heap);
1296     ASSERT(hasDouble(indexingType()));
1297
1298     unsigned vectorLength = m_butterfly->vectorLength();
1299     ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
1300     Butterfly* butterfly = m_butterfly.get();
1301     for (unsigned i = 0; i < vectorLength; i++) {
1302         double value = butterfly->contiguousDouble().at(this, i);
1303         if (value != value) {
1304             newStorage->m_vector[i].clear();
1305             continue;
1306         }
1307         newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
1308         newStorage->m_numValuesInVector++;
1309     }
1310     
1311     StructureID oldStructureID = this->structureID();
1312     Structure* oldStructure = vm.getStructure(oldStructureID);
1313     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, transition);
1314     nukeStructureAndSetButterfly(vm, oldStructureID, newStorage->butterfly());
1315     setStructure(vm, newStructure);
1316     return newStorage;
1317 }
1318
1319 ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm)
1320 {
1321     return convertDoubleToArrayStorage(vm, suggestedArrayStorageTransition(vm));
1322 }
1323
1324 ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition)
1325 {
1326     DeferGC deferGC(vm.heap);
1327     ASSERT(hasContiguous(indexingType()));
1328
1329     unsigned vectorLength = m_butterfly->vectorLength();
1330     ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
1331     Butterfly* butterfly = m_butterfly.get();
1332     for (unsigned i = 0; i < vectorLength; i++) {
1333         JSValue v = butterfly->contiguous().at(this, i).get();
1334         newStorage->m_vector[i].setWithoutWriteBarrier(v);
1335         if (v)
1336             newStorage->m_numValuesInVector++;
1337     }
1338
1339     // While we modify the butterfly of Contiguous Array, we do not take any cellLock here. This is because
1340     // (1) the old butterfly is not changed and (2) new butterfly is not changed after it is exposed to
1341     // the collector.
1342     // The mutator performs the following operations are sequentially executed by using storeStoreFence.
1343     //
1344     //     CreateNewButterfly NukeStructure ChangeButterfly PutNewStructure
1345     //
1346     // Meanwhile the collector performs the following steps sequentially:
1347     //
1348     //     ReadStructureEarly ReadButterfly ReadStructureLate
1349     //
1350     // We list up all the patterns by writing a tiny script, and ensure all the cases are categorized into BEFORE, AFTER, and IGNORE.
1351     //
1352     // CreateNewButterfly NukeStructure ChangeButterfly PutNewStructure ReadStructureEarly ReadButterfly ReadStructureLate: AFTER, trivially
1353     // CreateNewButterfly NukeStructure ChangeButterfly ReadStructureEarly PutNewStructure ReadButterfly ReadStructureLate: IGNORE, because nuked structure read early
1354     // CreateNewButterfly NukeStructure ChangeButterfly ReadStructureEarly ReadButterfly PutNewStructure ReadStructureLate: IGNORE, because nuked structure read early
1355     // CreateNewButterfly NukeStructure ChangeButterfly ReadStructureEarly ReadButterfly ReadStructureLate PutNewStructure: IGNORE, because nuked structure read early
1356     // CreateNewButterfly NukeStructure ReadStructureEarly ChangeButterfly PutNewStructure ReadButterfly ReadStructureLate: IGNORE, because nuked structure read early
1357     // CreateNewButterfly NukeStructure ReadStructureEarly ChangeButterfly ReadButterfly PutNewStructure ReadStructureLate: IGNORE, because nuked structure read early
1358     // CreateNewButterfly NukeStructure ReadStructureEarly ChangeButterfly ReadButterfly ReadStructureLate PutNewStructure: IGNORE, because nuked structure read early
1359     // CreateNewButterfly NukeStructure ReadStructureEarly ReadButterfly ChangeButterfly PutNewStructure ReadStructureLate: IGNORE, because nuked structure read early
1360     // CreateNewButterfly NukeStructure ReadStructureEarly ReadButterfly ChangeButterfly ReadStructureLate PutNewStructure: IGNORE, because nuked structure read early
1361     // CreateNewButterfly NukeStructure ReadStructureEarly ReadButterfly ReadStructureLate ChangeButterfly PutNewStructure: IGNORE, because nuked structure read early
1362     // CreateNewButterfly ReadStructureEarly NukeStructure ChangeButterfly PutNewStructure ReadButterfly ReadStructureLate: IGNORE, because early and late structures don't match
1363     // CreateNewButterfly ReadStructureEarly NukeStructure ChangeButterfly ReadButterfly PutNewStructure ReadStructureLate: IGNORE, because early and late structures don't match
1364     // CreateNewButterfly ReadStructureEarly NukeStructure ChangeButterfly ReadButterfly ReadStructureLate PutNewStructure: IGNORE, because nuked structure read late
1365     // CreateNewButterfly ReadStructureEarly NukeStructure ReadButterfly ChangeButterfly PutNewStructure ReadStructureLate: IGNORE, because early and late structures don't match
1366     // CreateNewButterfly ReadStructureEarly NukeStructure ReadButterfly ChangeButterfly ReadStructureLate PutNewStructure: IGNORE, because nuked structure read late
1367     // CreateNewButterfly ReadStructureEarly NukeStructure ReadButterfly ReadStructureLate ChangeButterfly PutNewStructure: IGNORE, because nuked structure read late
1368     // CreateNewButterfly ReadStructureEarly ReadButterfly NukeStructure ChangeButterfly PutNewStructure ReadStructureLate: IGNORE, because early and late structures don't match
1369     // CreateNewButterfly ReadStructureEarly ReadButterfly NukeStructure ChangeButterfly ReadStructureLate PutNewStructure: IGNORE, because nuked structure read late
1370     // CreateNewButterfly ReadStructureEarly ReadButterfly NukeStructure ReadStructureLate ChangeButterfly PutNewStructure: IGNORE, because nuked structure read late
1371     // CreateNewButterfly ReadStructureEarly ReadButterfly ReadStructureLate NukeStructure ChangeButterfly PutNewStructure: BEFORE, trivially.
1372     // ReadStructureEarly CreateNewButterfly NukeStructure ChangeButterfly PutNewStructure ReadButterfly ReadStructureLate: IGNORE, because early and late structures don't match
1373     // ReadStructureEarly CreateNewButterfly NukeStructure ChangeButterfly ReadButterfly PutNewStructure ReadStructureLate: IGNORE, because early and late structures don't match
1374     // ReadStructureEarly CreateNewButterfly NukeStructure ChangeButterfly ReadButterfly ReadStructureLate PutNewStructure: IGNORE, because nuked structure read late
1375     // ReadStructureEarly CreateNewButterfly NukeStructure ReadButterfly ChangeButterfly PutNewStructure ReadStructureLate: IGNORE, because early and late structures don't match
1376     // ReadStructureEarly CreateNewButterfly NukeStructure ReadButterfly ChangeButterfly ReadStructureLate PutNewStructure: IGNORE, because nuked structure read late
1377     // ReadStructureEarly CreateNewButterfly NukeStructure ReadButterfly ReadStructureLate ChangeButterfly PutNewStructure: IGNORE, because nuked structure read late
1378     // ReadStructureEarly CreateNewButterfly ReadButterfly NukeStructure ChangeButterfly PutNewStructure ReadStructureLate: IGNORE, because early and late structures don't match
1379     // ReadStructureEarly CreateNewButterfly ReadButterfly NukeStructure ChangeButterfly ReadStructureLate PutNewStructure: IGNORE, because nuked structure read late
1380     // ReadStructureEarly CreateNewButterfly ReadButterfly NukeStructure ReadStructureLate ChangeButterfly PutNewStructure: IGNORE, because nuked structure read late
1381     // ReadStructureEarly CreateNewButterfly ReadButterfly ReadStructureLate NukeStructure ChangeButterfly PutNewStructure: BEFORE, CreateNewButterfly is not visible to collector.
1382     // ReadStructureEarly ReadButterfly CreateNewButterfly NukeStructure ChangeButterfly PutNewStructure ReadStructureLate: IGNORE, because early and late structures don't match
1383     // ReadStructureEarly ReadButterfly CreateNewButterfly NukeStructure ChangeButterfly ReadStructureLate PutNewStructure: IGNORE, because nuked structure read late
1384     // ReadStructureEarly ReadButterfly CreateNewButterfly NukeStructure ReadStructureLate ChangeButterfly PutNewStructure: IGNORE, because nuked structure read late
1385     // ReadStructureEarly ReadButterfly CreateNewButterfly ReadStructureLate NukeStructure ChangeButterfly PutNewStructure: BEFORE, CreateNewButterfly is not visible to collector.
1386     // ReadStructureEarly ReadButterfly ReadStructureLate CreateNewButterfly NukeStructure ChangeButterfly PutNewStructure: BEFORE, trivially.
1387
1388     ASSERT(newStorage->butterfly() != butterfly);
1389     StructureID oldStructureID = this->structureID();
1390     Structure* oldStructure = vm.getStructure(oldStructureID);
1391     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, transition);
1392
1393     // Ensure new Butterfly initialization is correctly done before exposing it to the concurrent threads.
1394     if (isX86() || vm.heap.mutatorShouldBeFenced())
1395         WTF::storeStoreFence();
1396     nukeStructureAndSetButterfly(vm, oldStructureID, newStorage->butterfly());
1397     setStructure(vm, newStructure);
1398     
1399     return newStorage;
1400 }
1401
1402 ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm)
1403 {
1404     return convertContiguousToArrayStorage(vm, suggestedArrayStorageTransition(vm));
1405 }
1406
1407 void JSObject::convertUndecidedForValue(VM& vm, JSValue value)
1408 {
1409     IndexingType type = indexingTypeForValue(value);
1410     if (type == Int32Shape) {
1411         convertUndecidedToInt32(vm);
1412         return;
1413     }
1414     
1415     if (type == DoubleShape) {
1416         convertUndecidedToDouble(vm);
1417         return;
1418     }
1419
1420     ASSERT(type == ContiguousShape);
1421     convertUndecidedToContiguous(vm);
1422 }
1423
1424 void JSObject::createInitialForValueAndSet(VM& vm, unsigned index, JSValue value)
1425 {
1426     if (value.isInt32()) {
1427         createInitialInt32(vm, index + 1).at(this, index).set(vm, this, value);
1428         return;
1429     }
1430     
1431     if (value.isDouble()) {
1432         double doubleValue = value.asNumber();
1433         if (doubleValue == doubleValue) {
1434             createInitialDouble(vm, index + 1).at(this, index) = doubleValue;
1435             return;
1436         }
1437     }
1438     
1439     createInitialContiguous(vm, index + 1).at(this, index).set(vm, this, value);
1440 }
1441
1442 void JSObject::convertInt32ForValue(VM& vm, JSValue value)
1443 {
1444     ASSERT(!value.isInt32());
1445     
1446     if (value.isDouble() && !std::isnan(value.asDouble())) {
1447         convertInt32ToDouble(vm);
1448         return;
1449     }
1450
1451     convertInt32ToContiguous(vm);
1452 }
1453
1454 void JSObject::convertFromCopyOnWrite(VM& vm)
1455 {
1456     ASSERT(isCopyOnWrite(indexingMode()));
1457     ASSERT(structure(vm)->indexingMode() == indexingMode());
1458
1459     const bool hasIndexingHeader = true;
1460     Butterfly* oldButterfly = butterfly();
1461     size_t propertyCapacity = 0;
1462     unsigned newVectorLength = Butterfly::optimalContiguousVectorLength(propertyCapacity, std::min(oldButterfly->vectorLength() * 2, MAX_STORAGE_VECTOR_LENGTH));
1463     Butterfly* newButterfly = Butterfly::createUninitialized(vm, this, 0, propertyCapacity, hasIndexingHeader, newVectorLength * sizeof(JSValue));
1464
1465     memcpy(newButterfly->propertyStorage(), oldButterfly->propertyStorage(), oldButterfly->vectorLength() * sizeof(JSValue) + sizeof(IndexingHeader));
1466
1467     WTF::storeStoreFence();
1468     NonPropertyTransition transition = ([&] () {
1469         switch (indexingType()) {
1470         case ArrayWithInt32:
1471             return NonPropertyTransition::AllocateInt32;
1472         case ArrayWithDouble:
1473             return NonPropertyTransition::AllocateDouble;
1474         case ArrayWithContiguous:
1475             return NonPropertyTransition::AllocateContiguous;
1476         default:
1477             RELEASE_ASSERT_NOT_REACHED();
1478             return NonPropertyTransition::AllocateContiguous;
1479         }
1480     })();
1481     StructureID oldStructureID = structureID();
1482     Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
1483     nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly);
1484     setStructure(vm, newStructure);
1485 }
1486
1487 void JSObject::setIndexQuicklyToUndecided(VM& vm, unsigned index, JSValue value)
1488 {
1489     ASSERT(index < m_butterfly->publicLength());
1490     ASSERT(index < m_butterfly->vectorLength());
1491     convertUndecidedForValue(vm, value);
1492     setIndexQuickly(vm, index, value);
1493 }
1494
1495 void JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value)
1496 {
1497     ASSERT(!value.isInt32());
1498     convertInt32ForValue(vm, value);
1499     setIndexQuickly(vm, index, value);
1500 }
1501
1502 void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value)
1503 {
1504     ASSERT(!value.isNumber() || value.asNumber() != value.asNumber());
1505     convertDoubleToContiguous(vm);
1506     setIndexQuickly(vm, index, value);
1507 }
1508
1509 ContiguousJSValues JSObject::tryMakeWritableInt32Slow(VM& vm)
1510 {
1511     ASSERT(inherits(vm, info()));
1512
1513     if (isCopyOnWrite(indexingMode())) {
1514         if (leastUpperBoundOfIndexingTypes(indexingType() & IndexingShapeMask, Int32Shape) == Int32Shape) {
1515             ASSERT(hasInt32(indexingMode()));
1516             convertFromCopyOnWrite(vm);
1517             return butterfly()->contiguousInt32();
1518         }
1519         return ContiguousJSValues();
1520     }
1521
1522     if (structure(vm)->hijacksIndexingHeader())
1523         return ContiguousJSValues();
1524     
1525     switch (indexingType()) {
1526     case ALL_BLANK_INDEXING_TYPES:
1527         if (UNLIKELY(indexingShouldBeSparse(vm) || needsSlowPutIndexing(vm)))
1528             return ContiguousJSValues();
1529         return createInitialInt32(vm, 0);
1530         
1531     case ALL_UNDECIDED_INDEXING_TYPES:
1532         return convertUndecidedToInt32(vm);
1533         
1534     case ALL_DOUBLE_INDEXING_TYPES:
1535     case ALL_CONTIGUOUS_INDEXING_TYPES:
1536     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
1537         return ContiguousJSValues();
1538         
1539     default:
1540         CRASH();
1541         return ContiguousJSValues();
1542     }
1543 }
1544
1545 ContiguousDoubles JSObject::tryMakeWritableDoubleSlow(VM& vm)
1546 {
1547     ASSERT(inherits(vm, info()));
1548
1549     if (isCopyOnWrite(indexingMode())) {
1550         if (leastUpperBoundOfIndexingTypes(indexingType() & IndexingShapeMask, DoubleShape) == DoubleShape) {
1551             convertFromCopyOnWrite(vm);
1552             if (hasDouble(indexingMode()))
1553                 return butterfly()->contiguousDouble();
1554             ASSERT(hasInt32(indexingMode()));
1555         } else
1556             return ContiguousDoubles();
1557     }
1558
1559     if (structure(vm)->hijacksIndexingHeader())
1560         return ContiguousDoubles();
1561     
1562     switch (indexingType()) {
1563     case ALL_BLANK_INDEXING_TYPES:
1564         if (UNLIKELY(indexingShouldBeSparse(vm) || needsSlowPutIndexing(vm)))
1565             return ContiguousDoubles();
1566         return createInitialDouble(vm, 0);
1567         
1568     case ALL_UNDECIDED_INDEXING_TYPES:
1569         return convertUndecidedToDouble(vm);
1570         
1571     case ALL_INT32_INDEXING_TYPES:
1572         return convertInt32ToDouble(vm);
1573         
1574     case ALL_CONTIGUOUS_INDEXING_TYPES:
1575     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
1576         return ContiguousDoubles();
1577         
1578     default:
1579         CRASH();
1580         return ContiguousDoubles();
1581     }
1582 }
1583
1584 ContiguousJSValues JSObject::tryMakeWritableContiguousSlow(VM& vm)
1585 {
1586     ASSERT(inherits(vm, info()));
1587
1588     if (isCopyOnWrite(indexingMode())) {
1589         if (leastUpperBoundOfIndexingTypes(indexingType() & IndexingShapeMask, ContiguousShape) == ContiguousShape) {
1590             convertFromCopyOnWrite(vm);
1591             if (hasContiguous(indexingMode()))
1592                 return butterfly()->contiguous();
1593             ASSERT(hasInt32(indexingMode()) || hasDouble(indexingMode()));
1594         } else
1595             return ContiguousJSValues();
1596     }
1597
1598     if (structure(vm)->hijacksIndexingHeader())
1599         return ContiguousJSValues();
1600     
1601     switch (indexingType()) {
1602     case ALL_BLANK_INDEXING_TYPES:
1603         if (UNLIKELY(indexingShouldBeSparse(vm) || needsSlowPutIndexing(vm)))
1604             return ContiguousJSValues();
1605         return createInitialContiguous(vm, 0);
1606         
1607     case ALL_UNDECIDED_INDEXING_TYPES:
1608         return convertUndecidedToContiguous(vm);
1609         
1610     case ALL_INT32_INDEXING_TYPES:
1611         return convertInt32ToContiguous(vm);
1612         
1613     case ALL_DOUBLE_INDEXING_TYPES:
1614         return convertDoubleToContiguous(vm);
1615         
1616     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
1617         return ContiguousJSValues();
1618         
1619     default:
1620         CRASH();
1621         return ContiguousJSValues();
1622     }
1623 }
1624
1625 ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm)
1626 {
1627     ASSERT(inherits(vm, info()));
1628
1629     if (structure(vm)->hijacksIndexingHeader())
1630         return nullptr;
1631
1632     ensureWritable(vm);
1633
1634     switch (indexingType()) {
1635     case ALL_BLANK_INDEXING_TYPES:
1636         if (UNLIKELY(indexingShouldBeSparse(vm)))
1637             return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm);
1638         return createInitialArrayStorage(vm);
1639         
1640     case ALL_UNDECIDED_INDEXING_TYPES:
1641         ASSERT(!indexingShouldBeSparse(vm));
1642         ASSERT(!needsSlowPutIndexing(vm));
1643         return convertUndecidedToArrayStorage(vm);
1644         
1645     case ALL_INT32_INDEXING_TYPES:
1646         ASSERT(!indexingShouldBeSparse(vm));
1647         ASSERT(!needsSlowPutIndexing(vm));
1648         return convertInt32ToArrayStorage(vm);
1649         
1650     case ALL_DOUBLE_INDEXING_TYPES:
1651         ASSERT(!indexingShouldBeSparse(vm));
1652         ASSERT(!needsSlowPutIndexing(vm));
1653         return convertDoubleToArrayStorage(vm);
1654         
1655     case ALL_CONTIGUOUS_INDEXING_TYPES:
1656         ASSERT(!indexingShouldBeSparse(vm));
1657         ASSERT(!needsSlowPutIndexing(vm));
1658         return convertContiguousToArrayStorage(vm);
1659         
1660     default:
1661         RELEASE_ASSERT_NOT_REACHED();
1662         return 0;
1663     }
1664 }
1665
1666 ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM& vm)
1667 {
1668     ensureWritable(vm);
1669
1670     switch (indexingType()) {
1671     case ALL_BLANK_INDEXING_TYPES: {
1672         createArrayStorage(vm, 0, 0);
1673         SparseArrayValueMap* map = allocateSparseIndexMap(vm);
1674         map->setSparseMode();
1675         return arrayStorage();
1676     }
1677         
1678     case ALL_UNDECIDED_INDEXING_TYPES:
1679         return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertUndecidedToArrayStorage(vm));
1680         
1681     case ALL_INT32_INDEXING_TYPES:
1682         return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertInt32ToArrayStorage(vm));
1683         
1684     case ALL_DOUBLE_INDEXING_TYPES:
1685         return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertDoubleToArrayStorage(vm));
1686         
1687     case ALL_CONTIGUOUS_INDEXING_TYPES:
1688         return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertContiguousToArrayStorage(vm));
1689         
1690     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
1691         return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage());
1692         
1693     default:
1694         CRASH();
1695         return 0;
1696     }
1697 }
1698
1699 void JSObject::switchToSlowPutArrayStorage(VM& vm)
1700 {
1701     ensureWritable(vm);
1702
1703     switch (indexingType()) {
1704     case ArrayClass:
1705         ensureArrayStorage(vm);
1706         RELEASE_ASSERT(hasAnyArrayStorage(indexingType()));
1707         if (hasSlowPutArrayStorage(indexingType()))
1708             return;
1709         switchToSlowPutArrayStorage(vm);
1710         break;
1711
1712     case ALL_UNDECIDED_INDEXING_TYPES:
1713         convertUndecidedToArrayStorage(vm, NonPropertyTransition::AllocateSlowPutArrayStorage);
1714         break;
1715         
1716     case ALL_INT32_INDEXING_TYPES:
1717         convertInt32ToArrayStorage(vm, NonPropertyTransition::AllocateSlowPutArrayStorage);
1718         break;
1719         
1720     case ALL_DOUBLE_INDEXING_TYPES:
1721         convertDoubleToArrayStorage(vm, NonPropertyTransition::AllocateSlowPutArrayStorage);
1722         break;
1723         
1724     case ALL_CONTIGUOUS_INDEXING_TYPES:
1725         convertContiguousToArrayStorage(vm, NonPropertyTransition::AllocateSlowPutArrayStorage);
1726         break;
1727         
1728     case NonArrayWithArrayStorage:
1729     case ArrayWithArrayStorage: {
1730         Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::SwitchToSlowPutArrayStorage);
1731         setStructure(vm, newStructure);
1732         break;
1733     }
1734         
1735     default:
1736         CRASH();
1737         break;
1738     }
1739 }
1740
1741 void JSObject::setPrototypeDirect(VM& vm, JSValue prototype)
1742 {
1743     ASSERT(prototype);
1744     if (prototype.isObject())
1745         prototype.asCell()->didBecomePrototype();
1746     
1747     if (structure(vm)->hasMonoProto()) {
1748         DeferredStructureTransitionWatchpointFire deferred(vm, structure(vm));
1749         Structure* newStructure = Structure::changePrototypeTransition(vm, structure(vm), prototype, deferred);
1750         setStructure(vm, newStructure);
1751     } else
1752         putDirect(vm, knownPolyProtoOffset, prototype);
1753
1754     if (!anyObjectInChainMayInterceptIndexedAccesses(vm))
1755         return;
1756     
1757     if (mayBePrototype()) {
1758         structure(vm)->globalObject()->haveABadTime(vm);
1759         return;
1760     }
1761     
1762     if (!hasIndexedProperties(indexingType()))
1763         return;
1764     
1765     if (shouldUseSlowPut(indexingType()))
1766         return;
1767     
1768     switchToSlowPutArrayStorage(vm);
1769 }
1770
1771 bool JSObject::setPrototypeWithCycleCheck(VM& vm, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
1772 {
1773     auto scope = DECLARE_THROW_SCOPE(vm);
1774
1775     if (this->structure(vm)->isImmutablePrototypeExoticObject()) {
1776         // This implements https://tc39.github.io/ecma262/#sec-set-immutable-prototype.
1777         if (this->getPrototype(vm, exec) == prototype)
1778             return true;
1779
1780         return typeError(exec, scope, shouldThrowIfCantSet, "Cannot set prototype of immutable prototype object"_s);
1781     }
1782
1783     ASSERT(methodTable(vm)->toThis(this, exec, NotStrictMode) == this);
1784
1785     if (this->getPrototypeDirect(vm) == prototype)
1786         return true;
1787
1788     bool isExtensible = this->isExtensible(exec);
1789     RETURN_IF_EXCEPTION(scope, false);
1790
1791     if (!isExtensible)
1792         return typeError(exec, scope, shouldThrowIfCantSet, ReadonlyPropertyWriteError);
1793
1794     JSValue nextPrototype = prototype;
1795     while (nextPrototype && nextPrototype.isObject()) {
1796         if (nextPrototype == this)
1797             return typeError(exec, scope, shouldThrowIfCantSet, "cyclic __proto__ value"_s);
1798         // FIXME: The specification currently says we should check if the [[GetPrototypeOf]] internal method of nextPrototype
1799         // is not the ordinary object internal method. However, we currently restrict this to Proxy objects as it would allow
1800         // for cycles with certain HTML objects (WindowProxy, Location) otherwise.
1801         // https://bugs.webkit.org/show_bug.cgi?id=161534
1802         if (UNLIKELY(asObject(nextPrototype)->type() == ProxyObjectType))
1803             break; // We're done. Set the prototype.
1804         nextPrototype = asObject(nextPrototype)->getPrototypeDirect(vm);
1805     }
1806     setPrototypeDirect(vm, prototype);
1807     return true;
1808 }
1809
1810 bool JSObject::setPrototype(JSObject* object, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
1811 {
1812     return object->setPrototypeWithCycleCheck(exec->vm(), exec, prototype, shouldThrowIfCantSet);
1813 }
1814
1815 JSValue JSObject::getPrototype(JSObject* object, ExecState* exec)
1816 {
1817     return object->getPrototypeDirect(exec->vm());
1818 }
1819
1820 bool JSObject::setPrototype(VM& vm, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
1821 {
1822     return methodTable(vm)->setPrototype(this, exec, prototype, shouldThrowIfCantSet);
1823 }
1824
1825 bool JSObject::putGetter(ExecState* exec, PropertyName propertyName, JSValue getter, unsigned attributes)
1826 {
1827     PropertyDescriptor descriptor;
1828     descriptor.setGetter(getter);
1829
1830     ASSERT(attributes & PropertyAttribute::Accessor);
1831     if (!(attributes & PropertyAttribute::ReadOnly))
1832         descriptor.setConfigurable(true);
1833     if (!(attributes & PropertyAttribute::DontEnum))
1834         descriptor.setEnumerable(true);
1835
1836     return defineOwnProperty(this, exec, propertyName, descriptor, true);
1837 }
1838
1839 bool JSObject::putSetter(ExecState* exec, PropertyName propertyName, JSValue setter, unsigned attributes)
1840 {
1841     PropertyDescriptor descriptor;
1842     descriptor.setSetter(setter);
1843
1844     ASSERT(attributes & PropertyAttribute::Accessor);
1845     if (!(attributes & PropertyAttribute::ReadOnly))
1846         descriptor.setConfigurable(true);
1847     if (!(attributes & PropertyAttribute::DontEnum))
1848         descriptor.setEnumerable(true);
1849
1850     return defineOwnProperty(this, exec, propertyName, descriptor, true);
1851 }
1852
1853 bool JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, GetterSetter* accessor, unsigned attributes)
1854 {
1855     ASSERT(attributes & PropertyAttribute::Accessor);
1856
1857     if (std::optional<uint32_t> index = parseIndex(propertyName))
1858         return putDirectIndex(exec, index.value(), accessor, attributes, PutDirectIndexLikePutDirect);
1859
1860     return putDirectNonIndexAccessor(exec->vm(), propertyName, accessor, attributes);
1861 }
1862
1863 // FIXME: Introduce a JSObject::putDirectCustomValue() method instead of using
1864 // JSObject::putDirectCustomAccessor() to put CustomValues.
1865 // https://bugs.webkit.org/show_bug.cgi?id=192576
1866 bool JSObject::putDirectCustomAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
1867 {
1868     ASSERT(!parseIndex(propertyName));
1869     ASSERT(value.isCustomGetterSetter());
1870     if (!(attributes & PropertyAttribute::CustomAccessor))
1871         attributes |= PropertyAttribute::CustomValue;
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     ASSERT(attributes & PropertyAttribute::Accessor);
1888     PutPropertySlot slot(this);
1889     bool result = putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, accessor, attributes, slot);
1890
1891     Structure* structure = this->structure(vm);
1892     if (attributes & PropertyAttribute::ReadOnly)
1893         structure->setContainsReadOnlyProperties();
1894
1895     structure->setHasGetterSetterPropertiesWithProtoCheck(propertyName == vm.propertyNames->underscoreProto);
1896     return result;
1897 }
1898
1899 // HasProperty(O, P) from Section 7.3.10 of the spec.
1900 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasproperty
1901 bool JSObject::hasProperty(ExecState* exec, PropertyName propertyName) const
1902 {
1903     return hasPropertyGeneric(exec, propertyName, PropertySlot::InternalMethodType::HasProperty);
1904 }
1905
1906 bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
1907 {
1908     return hasPropertyGeneric(exec, propertyName, PropertySlot::InternalMethodType::HasProperty);
1909 }
1910
1911 bool JSObject::hasPropertyGeneric(ExecState* exec, PropertyName propertyName, PropertySlot::InternalMethodType internalMethodType) const
1912 {
1913     PropertySlot slot(this, internalMethodType);
1914     return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
1915 }
1916
1917 bool JSObject::hasPropertyGeneric(ExecState* exec, unsigned propertyName, PropertySlot::InternalMethodType internalMethodType) const
1918 {
1919     PropertySlot slot(this, internalMethodType);
1920     return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
1921 }
1922
1923 // ECMA 8.6.2.5
1924 bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
1925 {
1926     JSObject* thisObject = jsCast<JSObject*>(cell);
1927     VM& vm = exec->vm();
1928     
1929     if (std::optional<uint32_t> index = parseIndex(propertyName))
1930         return thisObject->methodTable(vm)->deletePropertyByIndex(thisObject, exec, index.value());
1931
1932     unsigned attributes;
1933
1934     if (!thisObject->staticPropertiesReified(vm)) {
1935         if (auto entry = thisObject->findPropertyHashEntry(vm, propertyName)) {
1936             // If the static table contains a non-configurable (DontDelete) property then we can return early;
1937             // if there is a property in the storage array it too must be non-configurable (the language does
1938             // not allow repacement of a non-configurable property with a configurable one).
1939             if (entry->value->attributes() & PropertyAttribute::DontDelete && vm.deletePropertyMode() != VM::DeletePropertyMode::IgnoreConfigurable) {
1940                 ASSERT(!isValidOffset(thisObject->structure(vm)->get(vm, propertyName, attributes)) || attributes & PropertyAttribute::DontDelete);
1941                 return false;
1942             }
1943             thisObject->reifyAllStaticProperties(exec);
1944         }
1945     }
1946
1947     Structure* structure = thisObject->structure(vm);
1948
1949     bool propertyIsPresent = isValidOffset(structure->get(vm, propertyName, attributes));
1950     if (propertyIsPresent) {
1951         if (attributes & PropertyAttribute::DontDelete && vm.deletePropertyMode() != VM::DeletePropertyMode::IgnoreConfigurable)
1952             return false;
1953
1954         PropertyOffset offset;
1955         if (structure->isUncacheableDictionary())
1956             offset = structure->removePropertyWithoutTransition(vm, propertyName, [] (const ConcurrentJSLocker&, PropertyOffset) { });
1957         else
1958             thisObject->setStructure(vm, Structure::removePropertyTransition(vm, structure, propertyName, offset));
1959
1960         if (offset != invalidOffset)
1961             thisObject->locationForOffset(offset)->clear();
1962     }
1963
1964     return true;
1965 }
1966
1967 bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
1968 {
1969     VM& vm = exec->vm();
1970     JSObject* thisObject = jsCast<JSObject*>(cell);
1971     
1972     if (i > MAX_ARRAY_INDEX)
1973         return thisObject->methodTable(vm)->deleteProperty(thisObject, exec, Identifier::from(exec, i));
1974     
1975     switch (thisObject->indexingMode()) {
1976     case ALL_BLANK_INDEXING_TYPES:
1977     case ALL_UNDECIDED_INDEXING_TYPES:
1978         return true;
1979
1980     case CopyOnWriteArrayWithInt32:
1981     case CopyOnWriteArrayWithContiguous: {
1982         Butterfly* butterfly = thisObject->butterfly();
1983         if (i >= butterfly->vectorLength())
1984             return true;
1985         thisObject->convertFromCopyOnWrite(vm);
1986         FALLTHROUGH;
1987     }
1988
1989     case ALL_WRITABLE_INT32_INDEXING_TYPES:
1990     case ALL_WRITABLE_CONTIGUOUS_INDEXING_TYPES: {
1991         Butterfly* butterfly = thisObject->butterfly();
1992         if (i >= butterfly->vectorLength())
1993             return true;
1994         butterfly->contiguous().at(thisObject, i).clear();
1995         return true;
1996     }
1997
1998     case CopyOnWriteArrayWithDouble: {
1999         Butterfly* butterfly = thisObject->butterfly();
2000         if (i >= butterfly->vectorLength())
2001             return true;
2002         thisObject->convertFromCopyOnWrite(vm);
2003         FALLTHROUGH;
2004     }
2005
2006     case ALL_WRITABLE_DOUBLE_INDEXING_TYPES: {
2007         Butterfly* butterfly = thisObject->butterfly();
2008         if (i >= butterfly->vectorLength())
2009             return true;
2010         butterfly->contiguousDouble().at(thisObject, i) = PNaN;
2011         return true;
2012     }
2013         
2014     case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
2015         ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
2016         
2017         if (i < storage->vectorLength()) {
2018             WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
2019             if (valueSlot) {
2020                 valueSlot.clear();
2021                 --storage->m_numValuesInVector;
2022             }
2023         } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
2024             SparseArrayValueMap::iterator it = map->find(i);
2025             if (it != map->notFound()) {
2026                 if (it->value.attributes() & PropertyAttribute::DontDelete)
2027                     return false;
2028                 map->remove(it);
2029             }
2030         }
2031         
2032         return true;
2033     }
2034         
2035     default:
2036         RELEASE_ASSERT_NOT_REACHED();
2037         return false;
2038     }
2039 }
2040
2041 enum class TypeHintMode { TakesHint, DoesNotTakeHint };
2042
2043 template<TypeHintMode mode = TypeHintMode::DoesNotTakeHint>
2044 static ALWAYS_INLINE JSValue callToPrimitiveFunction(ExecState* exec, const JSObject* object, PropertyName propertyName, PreferredPrimitiveType hint)
2045 {
2046     VM& vm = exec->vm();
2047     auto scope = DECLARE_THROW_SCOPE(vm);
2048
2049     PropertySlot slot(object, PropertySlot::InternalMethodType::Get);
2050     // FIXME: Remove this when we have fixed: rdar://problem/33451840
2051     // https://bugs.webkit.org/show_bug.cgi?id=187109.
2052     constexpr bool debugNullStructure = mode == TypeHintMode::TakesHint;
2053     bool hasProperty = const_cast<JSObject*>(object)->getPropertySlot<debugNullStructure>(exec, propertyName, slot);
2054     RETURN_IF_EXCEPTION(scope, scope.exception());
2055     JSValue function = hasProperty ? slot.getValue(exec, propertyName) : jsUndefined();
2056     RETURN_IF_EXCEPTION(scope, scope.exception());
2057     if (function.isUndefinedOrNull() && mode == TypeHintMode::TakesHint)
2058         return JSValue();
2059     CallData callData;
2060     CallType callType = getCallData(vm, function, callData);
2061     if (callType == CallType::None) {
2062         if (mode == TypeHintMode::TakesHint)
2063             throwTypeError(exec, scope, "Symbol.toPrimitive is not a function, undefined, or null"_s);
2064         return scope.exception();
2065     }
2066
2067     MarkedArgumentBuffer callArgs;
2068     if (mode == TypeHintMode::TakesHint) {
2069         JSString* hintString = nullptr;
2070         switch (hint) {
2071         case NoPreference:
2072             hintString = vm.smallStrings.defaultString();
2073             break;
2074         case PreferNumber:
2075             hintString = vm.smallStrings.numberString();
2076             break;
2077         case PreferString:
2078             hintString = vm.smallStrings.stringString();
2079             break;
2080         }
2081         callArgs.append(hintString);
2082     }
2083     ASSERT(!callArgs.hasOverflowed());
2084
2085     JSValue result = call(exec, function, callType, callData, const_cast<JSObject*>(object), callArgs);
2086     RETURN_IF_EXCEPTION(scope, scope.exception());
2087     ASSERT(!result.isGetterSetter());
2088     if (result.isObject())
2089         return mode == TypeHintMode::DoesNotTakeHint ? JSValue() : throwTypeError(exec, scope, "Symbol.toPrimitive returned an object"_s);
2090     return result;
2091 }
2092
2093 // ECMA 7.1.1
2094 JSValue JSObject::ordinaryToPrimitive(ExecState* exec, PreferredPrimitiveType hint) const
2095 {
2096     VM& vm = exec->vm();
2097     auto scope = DECLARE_THROW_SCOPE(vm);
2098
2099     // Make sure that whatever default value methods there are on object's prototype chain are
2100     // being watched.
2101     for (const JSObject* object = this; object; object = object->structure(vm)->storedPrototypeObject(object))
2102         object->structure(vm)->startWatchingInternalPropertiesIfNecessary(vm);
2103
2104     JSValue value;
2105     if (hint == PreferString) {
2106         value = callToPrimitiveFunction(exec, this, vm.propertyNames->toString, hint);
2107         EXCEPTION_ASSERT(!scope.exception() || scope.exception() == value.asCell());
2108         if (value)
2109             return value;
2110         value = callToPrimitiveFunction(exec, this, vm.propertyNames->valueOf, hint);
2111         EXCEPTION_ASSERT(!scope.exception() || scope.exception() == value.asCell());
2112         if (value)
2113             return value;
2114     } else {
2115         value = callToPrimitiveFunction(exec, this, vm.propertyNames->valueOf, hint);
2116         EXCEPTION_ASSERT(!scope.exception() || scope.exception() == value.asCell());
2117         if (value)
2118             return value;
2119         value = callToPrimitiveFunction(exec, this, vm.propertyNames->toString, hint);
2120         EXCEPTION_ASSERT(!scope.exception() || scope.exception() == value.asCell());
2121         if (value)
2122             return value;
2123     }
2124
2125     scope.assertNoException();
2126
2127     return throwTypeError(exec, scope, "No default value"_s);
2128 }
2129
2130 JSValue JSObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint)
2131 {
2132     return object->ordinaryToPrimitive(exec, hint);
2133 }
2134
2135 JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
2136 {
2137     VM& vm = exec->vm();
2138     auto scope = DECLARE_THROW_SCOPE(vm);
2139
2140     JSValue value = callToPrimitiveFunction<TypeHintMode::TakesHint>(exec, this, vm.propertyNames->toPrimitiveSymbol, preferredType);
2141     RETURN_IF_EXCEPTION(scope, { });
2142     if (value)
2143         return value;
2144
2145     RELEASE_AND_RETURN(scope, 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         RELEASE_AND_RETURN(scope, defaultHasInstance(exec, value, prototype));
2208     }
2209     if (info.implementsHasInstance())
2210         RELEASE_AND_RETURN(scope, methodTable(vm)->customHasInstance(this, exec, value));
2211
2212     throwException(exec, scope, createInvalidInstanceofParameterErrorNotFunction(exec, this));
2213     return false;
2214 }
2215
2216 bool JSObject::hasInstance(ExecState* exec, JSValue value)
2217 {
2218     VM& vm = exec->vm();
2219     auto scope = DECLARE_THROW_SCOPE(vm);
2220     JSValue hasInstanceValue = get(exec, vm.propertyNames->hasInstanceSymbol);
2221     RETURN_IF_EXCEPTION(scope, false);
2222
2223     RELEASE_AND_RETURN(scope, hasInstance(exec, value, hasInstanceValue));
2224 }
2225
2226 bool JSObject::defaultHasInstance(ExecState* exec, JSValue value, JSValue proto)
2227 {
2228     VM& vm = exec->vm();
2229     auto scope = DECLARE_THROW_SCOPE(vm);
2230
2231     if (!value.isObject())
2232         return false;
2233
2234     if (!proto.isObject()) {
2235         throwTypeError(exec, scope, "instanceof called on an object with an invalid prototype property."_s);
2236         return false;
2237     }
2238
2239     JSObject* object = asObject(value);
2240     while (true) {
2241         JSValue objectValue = object->getPrototype(vm, exec);
2242         RETURN_IF_EXCEPTION(scope, false);
2243         if (!objectValue.isObject())
2244             return false;
2245         object = asObject(objectValue);
2246         if (proto == object)
2247             return true;
2248     }
2249     ASSERT_NOT_REACHED();
2250 }
2251
2252 EncodedJSValue JSC_HOST_CALL objectPrivateFuncInstanceOf(ExecState* exec)
2253 {
2254     JSValue value = exec->uncheckedArgument(0);
2255     JSValue proto = exec->uncheckedArgument(1);
2256
2257     return JSValue::encode(jsBoolean(JSObject::defaultHasInstance(exec, value, proto)));
2258 }
2259
2260 void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
2261 {
2262     VM& vm = exec->vm();
2263     auto scope = DECLARE_THROW_SCOPE(vm);
2264     object->methodTable(vm)->getOwnPropertyNames(object, exec, propertyNames, mode);
2265     RETURN_IF_EXCEPTION(scope, void());
2266
2267     JSValue nextProto = object->getPrototype(vm, exec);
2268     RETURN_IF_EXCEPTION(scope, void());
2269     if (nextProto.isNull())
2270         return;
2271
2272     JSObject* prototype = asObject(nextProto);
2273     while(1) {
2274         if (prototype->structure(vm)->typeInfo().overridesGetPropertyNames()) {
2275             scope.release();
2276             prototype->methodTable(vm)->getPropertyNames(prototype, exec, propertyNames, mode);
2277             return;
2278         }
2279         prototype->methodTable(vm)->getOwnPropertyNames(prototype, exec, propertyNames, mode);
2280         RETURN_IF_EXCEPTION(scope, void());
2281         nextProto = prototype->getPrototype(vm, exec);
2282         RETURN_IF_EXCEPTION(scope, void());
2283         if (nextProto.isNull())
2284             break;
2285         prototype = asObject(nextProto);
2286     }
2287 }
2288
2289 void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
2290 {
2291     VM& vm = exec->vm();
2292     if (!mode.includeJSObjectProperties()) {
2293         // We still have to get non-indexed properties from any subclasses of JSObject that have them.
2294         object->methodTable(vm)->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
2295         return;
2296     }
2297
2298     if (propertyNames.includeStringProperties()) {
2299         // Add numeric properties first. That appears to be the accepted convention.
2300         // FIXME: Filling PropertyNameArray with an identifier for every integer
2301         // is incredibly inefficient for large arrays. We need a different approach,
2302         // which almost certainly means a different structure for PropertyNameArray.
2303         switch (object->indexingType()) {
2304         case ALL_BLANK_INDEXING_TYPES:
2305         case ALL_UNDECIDED_INDEXING_TYPES:
2306             break;
2307             
2308         case ALL_INT32_INDEXING_TYPES:
2309         case ALL_CONTIGUOUS_INDEXING_TYPES: {
2310             Butterfly* butterfly = object->butterfly();
2311             unsigned usedLength = butterfly->publicLength();
2312             for (unsigned i = 0; i < usedLength; ++i) {
2313                 if (!butterfly->contiguous().at(object, i))
2314                     continue;
2315                 propertyNames.add(i);
2316             }
2317             break;
2318         }
2319             
2320         case ALL_DOUBLE_INDEXING_TYPES: {
2321             Butterfly* butterfly = object->butterfly();
2322             unsigned usedLength = butterfly->publicLength();
2323             for (unsigned i = 0; i < usedLength; ++i) {
2324                 double value = butterfly->contiguousDouble().at(object, i);
2325                 if (value != value)
2326                     continue;
2327                 propertyNames.add(i);
2328             }
2329             break;
2330         }
2331             
2332         case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
2333             ArrayStorage* storage = object->m_butterfly->arrayStorage();
2334             
2335             unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
2336             for (unsigned i = 0; i < usedVectorLength; ++i) {
2337                 if (storage->m_vector[i])
2338                     propertyNames.add(i);
2339             }
2340             
2341             if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
2342                 Vector<unsigned, 0, UnsafeVectorOverflow> keys;
2343                 keys.reserveInitialCapacity(map->size());
2344                 
2345                 SparseArrayValueMap::const_iterator end = map->end();
2346                 for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
2347                     if (mode.includeDontEnumProperties() || !(it->value.attributes() & PropertyAttribute::DontEnum))
2348                         keys.uncheckedAppend(static_cast<unsigned>(it->key));
2349                 }
2350                 
2351                 std::sort(keys.begin(), keys.end());
2352                 for (unsigned i = 0; i < keys.size(); ++i)
2353                     propertyNames.add(keys[i]);
2354             }
2355             break;
2356         }
2357             
2358         default:
2359             RELEASE_ASSERT_NOT_REACHED();
2360         }
2361     }
2362
2363     object->methodTable(vm)->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
2364 }
2365
2366 void JSObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
2367 {
2368     VM& vm = exec->vm();
2369     if (!object->staticPropertiesReified(vm))
2370         getClassPropertyNames(exec, object->classInfo(vm), propertyNames, mode);
2371
2372     if (!mode.includeJSObjectProperties())
2373         return;
2374     
2375     object->structure(vm)->getPropertyNamesFromStructure(vm, propertyNames, mode);
2376 }
2377
2378 double JSObject::toNumber(ExecState* exec) const
2379 {
2380     VM& vm = exec->vm();
2381     auto scope = DECLARE_THROW_SCOPE(vm);
2382     JSValue primitive = toPrimitive(exec, PreferNumber);
2383     RETURN_IF_EXCEPTION(scope, 0.0); // should be picked up soon in Nodes.cpp
2384     RELEASE_AND_RETURN(scope, primitive.toNumber(exec));
2385 }
2386
2387 JSString* JSObject::toString(ExecState* exec) const
2388 {
2389     VM& vm = exec->vm();
2390     auto scope = DECLARE_THROW_SCOPE(vm);
2391     JSValue primitive = toPrimitive(exec, PreferString);
2392     RETURN_IF_EXCEPTION(scope, jsEmptyString(exec));
2393     return primitive.toString(exec);
2394 }
2395
2396 JSValue JSObject::toThis(JSCell* cell, ExecState*, ECMAMode)
2397 {
2398     return jsCast<JSObject*>(cell);
2399 }
2400
2401 void JSObject::seal(VM& vm)
2402 {
2403     if (isSealed(vm))
2404         return;
2405     enterDictionaryIndexingMode(vm);
2406     setStructure(vm, Structure::sealTransition(vm, structure(vm)));
2407 }
2408
2409 void JSObject::freeze(VM& vm)
2410 {
2411     if (isFrozen(vm))
2412         return;
2413     enterDictionaryIndexingMode(vm);
2414     setStructure(vm, Structure::freezeTransition(vm, structure(vm)));
2415 }
2416
2417 bool JSObject::preventExtensions(JSObject* object, ExecState* exec)
2418 {
2419     VM& vm = exec->vm();
2420     if (!object->isStructureExtensible(vm)) {
2421         // We've already set the internal [[PreventExtensions]] field to false.
2422         // We don't call the methodTable isExtensible here because it's not defined
2423         // that way in the specification. We are just doing an optimization here.
2424         return true;
2425     }
2426
2427     object->enterDictionaryIndexingMode(vm);
2428     object->setStructure(vm, Structure::preventExtensionsTransition(vm, object->structure(vm)));
2429     return true;
2430 }
2431
2432 bool JSObject::isExtensible(JSObject* obj, ExecState* exec)
2433 {
2434     return obj->isExtensibleImpl(exec->vm());
2435 }
2436
2437 bool JSObject::isExtensible(ExecState* exec)
2438
2439     VM& vm = exec->vm();
2440     return methodTable(vm)->isExtensible(this, exec);
2441 }
2442
2443 void JSObject::reifyAllStaticProperties(ExecState* exec)
2444 {
2445     VM& vm = exec->vm();
2446     ASSERT(!staticPropertiesReified(vm));
2447
2448     // If this object's ClassInfo has no static properties, then nothing to reify!
2449     // We can safely set the flag to avoid the expensive check again in the future.
2450     if (!TypeInfo::hasStaticPropertyTable(inlineTypeFlags())) {
2451         structure(vm)->setStaticPropertiesReified(true);
2452         return;
2453     }
2454
2455     if (!structure(vm)->isDictionary())
2456         setStructure(vm, Structure::toCacheableDictionaryTransition(vm, structure(vm)));
2457
2458     for (const ClassInfo* info = classInfo(vm); info; info = info->parentClass) {
2459         const HashTable* hashTable = info->staticPropHashTable;
2460         if (!hashTable)
2461             continue;
2462
2463         for (auto& value : *hashTable) {
2464             unsigned attributes;
2465             auto key = Identifier::fromString(&vm, value.m_key);
2466             PropertyOffset offset = getDirectOffset(vm, key, attributes);
2467             if (!isValidOffset(offset))
2468                 reifyStaticProperty(vm, hashTable->classForThis, key, value, *this);
2469         }
2470     }
2471
2472     structure(vm)->setStaticPropertiesReified(true);
2473 }
2474
2475 NEVER_INLINE void JSObject::fillGetterPropertySlot(VM& vm, PropertySlot& slot, JSCell* getterSetter, unsigned attributes, PropertyOffset offset)
2476 {
2477     if (structure(vm)->isUncacheableDictionary()) {
2478         slot.setGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter));
2479         return;
2480     }
2481
2482     // This access is cacheable because Structure requires an attributeChangedTransition
2483     // if this property stops being an accessor.
2484     slot.setCacheableGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter), offset);
2485 }
2486
2487 static bool putIndexedDescriptor(ExecState* exec, SparseArrayValueMap* map, SparseArrayEntry* entryInMap, const PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor)
2488 {
2489     VM& vm = exec->vm();
2490
2491     if (descriptor.isDataDescriptor()) {
2492         unsigned attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~PropertyAttribute::Accessor;
2493         if (descriptor.value())
2494             entryInMap->forceSet(vm, map, descriptor.value(), attributes);
2495         else if (oldDescriptor.isAccessorDescriptor())
2496             entryInMap->forceSet(vm, map, jsUndefined(), attributes);
2497         else
2498             entryInMap->forceSet(attributes);
2499         return true;
2500     }
2501
2502     if (descriptor.isAccessorDescriptor()) {
2503         JSObject* getter = nullptr;
2504         if (descriptor.getterPresent())
2505             getter = descriptor.getterObject();
2506         else if (oldDescriptor.isAccessorDescriptor())
2507             getter = oldDescriptor.getterObject();
2508         JSObject* setter = nullptr;
2509         if (descriptor.setterPresent())
2510             setter = descriptor.setterObject();
2511         else if (oldDescriptor.isAccessorDescriptor())
2512             setter = oldDescriptor.setterObject();
2513
2514         GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject(), getter, setter);
2515         entryInMap->forceSet(vm, map, accessor, descriptor.attributesOverridingCurrent(oldDescriptor) & ~PropertyAttribute::ReadOnly);
2516         return true;
2517     }
2518
2519     ASSERT(descriptor.isGenericDescriptor());
2520     entryInMap->forceSet(descriptor.attributesOverridingCurrent(oldDescriptor));
2521     return true;
2522 }
2523
2524 ALWAYS_INLINE static bool canDoFastPutDirectIndex(VM& vm, JSObject* object)
2525 {
2526     return (isJSArray(object) && !isCopyOnWrite(object->indexingMode()))
2527         || jsDynamicCast<JSFinalObject*>(vm, object)
2528         || TypeInfo::isArgumentsType(object->type());
2529 }
2530
2531 // Defined in ES5.1 8.12.9
2532 bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, const PropertyDescriptor& descriptor, bool throwException)
2533 {
2534     VM& vm = exec->vm();
2535     auto scope = DECLARE_THROW_SCOPE(vm);
2536
2537     ASSERT(index <= MAX_ARRAY_INDEX);
2538
2539     ensureWritable(vm);
2540
2541     if (!inSparseIndexingMode()) {
2542         // Fast case: we're putting a regular property to a regular array
2543         // FIXME: this will pessimistically assume that if attributes are missing then they'll default to false
2544         // however if the property currently exists missing attributes will override from their current 'true'
2545         // state (i.e. defineOwnProperty could be used to set a value without needing to entering 'SparseMode').
2546         if (!descriptor.attributes() && descriptor.value() && canDoFastPutDirectIndex(vm, this)) {
2547             ASSERT(!descriptor.isAccessorDescriptor());
2548             RELEASE_AND_RETURN(scope, putDirectIndex(exec, index, descriptor.value(), 0, throwException ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow));
2549         }
2550         
2551         ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm);
2552     }
2553
2554     if (descriptor.attributes() & (PropertyAttribute::ReadOnly | PropertyAttribute::Accessor))
2555         notifyPresenceOfIndexedAccessors(vm);
2556
2557     SparseArrayValueMap* map = m_butterfly->arrayStorage()->m_sparseMap.get();
2558     RELEASE_ASSERT(map);
2559     
2560     // 1. Let current be the result of calling the [[GetOwnProperty]] internal method of O with property name P.
2561     SparseArrayValueMap::AddResult result = map->add(this, index);
2562     SparseArrayEntry* entryInMap = &result.iterator->value;
2563
2564     // 2. Let extensible be the value of the [[Extensible]] internal property of O.
2565     // 3. If current is undefined and extensible is false, then Reject.
2566     // 4. If current is undefined and extensible is true, then
2567     if (result.isNewEntry) {
2568         if (!isStructureExtensible(vm)) {
2569             map->remove(result.iterator);
2570             return typeError(exec, scope, throwException, NonExtensibleObjectPropertyDefineError);
2571         }
2572
2573         // 4.a. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then create an own data property
2574         // named P of object O whose [[Value]], [[Writable]], [[Enumerable]] and [[Configurable]] attribute values
2575         // are described by Desc. If the value of an attribute field of Desc is absent, the attribute of the newly
2576         // created property is set to its default value.
2577         // 4.b. Else, Desc must be an accessor Property Descriptor so, create an own accessor property named P of
2578         // object O whose [[Get]], [[Set]], [[Enumerable]] and [[Configurable]] attribute values are described by
2579         // Desc. If the value of an attribute field of Desc is absent, the attribute of the newly created property
2580         // is set to its default value.
2581         // 4.c. Return true.
2582
2583         PropertyDescriptor defaults(jsUndefined(), PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
2584         putIndexedDescriptor(exec, map, entryInMap, descriptor, defaults);
2585         Butterfly* butterfly = m_butterfly.get();
2586         if (index >= butterfly->arrayStorage()->length())
2587             butterfly->arrayStorage()->setLength(index + 1);
2588         return true;
2589     }
2590
2591     // 5. Return true, if every field in Desc is absent.
2592     // 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).
2593     PropertyDescriptor current;
2594     entryInMap->get(current);
2595     bool isEmptyOrEqual = descriptor.isEmpty() || descriptor.equalTo(exec, current);
2596     RETURN_IF_EXCEPTION(scope, false);
2597     if (isEmptyOrEqual)
2598         return true;
2599
2600     // 7. If the [[Configurable]] field of current is false then
2601     if (!current.configurable()) {
2602         // 7.a. Reject, if the [[Configurable]] field of Desc is true.
2603         if (descriptor.configurablePresent() && descriptor.configurable())
2604             return typeError(exec, scope, throwException, UnconfigurablePropertyChangeConfigurabilityError);
2605         // 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.
2606         if (descriptor.enumerablePresent() && current.enumerable() != descriptor.enumerable())
2607             return typeError(exec, scope, throwException, UnconfigurablePropertyChangeEnumerabilityError);
2608     }
2609
2610     // 8. If IsGenericDescriptor(Desc) is true, then no further validation is required.
2611     if (!descriptor.isGenericDescriptor()) {
2612         // 9. Else, if IsDataDescriptor(current) and IsDataDescriptor(Desc) have different results, then
2613         if (current.isDataDescriptor() != descriptor.isDataDescriptor()) {
2614             // 9.a. Reject, if the [[Configurable]] field of current is false.
2615             if (!current.configurable())
2616                 return typeError(exec, scope, throwException, UnconfigurablePropertyChangeAccessMechanismError);
2617             // 9.b. If IsDataDescriptor(current) is true, then convert the property named P of object O from a
2618             // data property to an accessor property. Preserve the existing values of the converted property's
2619             // [[Configurable]] and [[Enumerable]] attributes and set the rest of the property's attributes to
2620             // their default values.
2621             // 9.c. Else, convert the property named P of object O from an accessor property to a data property.
2622             // Preserve the existing values of the converted property's [[Configurable]] and [[Enumerable]]
2623             // attributes and set the rest of the property's attributes to their default values.
2624         } else if (current.isDataDescriptor() && descriptor.isDataDescriptor()) {
2625             // 10. Else, if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
2626             // 10.a. If the [[Configurable]] field of current is false, then
2627             if (!current.configurable() && !current.writable()) {
2628                 // 10.a.i. Reject, if the [[Writable]] field of current is false and the [[Writable]] field of Desc is true.
2629                 if (descriptor.writable())
2630                     return typeError(exec, scope, throwException, UnconfigurablePropertyChangeWritabilityError);
2631                 // 10.a.ii. If the [[Writable]] field of current is false, then
2632                 // 10.a.ii.1. Reject, if the [[Value]] field of Desc is present and SameValue(Desc.[[Value]], current.[[Value]]) is false.
2633                 if (descriptor.value() && !sameValue(exec, descriptor.value(), current.value()))
2634                     return typeError(exec, scope, throwException, ReadonlyPropertyChangeError);
2635             }
2636             // 10.b. else, the [[Configurable]] field of current is true, so any change is acceptable.
2637         } else {
2638             ASSERT(current.isAccessorDescriptor() && current.getterPresent() && current.setterPresent());
2639             // 11. Else, IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true so, if the [[Configurable]] field of current is false, then
2640             if (!current.configurable()) {
2641                 // 11.i. Reject, if the [[Set]] field of Desc is present and SameValue(Desc.[[Set]], current.[[Set]]) is false.
2642                 if (descriptor.setterPresent() && descriptor.setter() != current.setter())
2643                     return typeError(exec, scope, throwException, "Attempting to change the setter of an unconfigurable property."_s);
2644                 // 11.ii. Reject, if the [[Get]] field of Desc is present and SameValue(Desc.[[Get]], current.[[Get]]) is false.
2645                 if (descriptor.getterPresent() && descriptor.getter() != current.getter())
2646                     return typeError(exec, scope, throwException, "Attempting to change the getter of an unconfigurable property."_s);
2647             }
2648         }
2649     }
2650
2651     // 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.
2652     putIndexedDescriptor(exec, map, entryInMap, descriptor, current);
2653     // 13. Return true.
2654     return true;
2655 }
2656
2657 SparseArrayValueMap* JSObject::allocateSparseIndexMap(VM& vm)
2658 {
2659     SparseArrayValueMap* result = SparseArrayValueMap::create(vm);
2660     arrayStorage()->m_sparseMap.set(vm, this, result);
2661     return result;
2662 }
2663
2664 void JSObject::deallocateSparseIndexMap()
2665 {
2666     if (ArrayStorage* arrayStorage = arrayStorageOrNull())
2667         arrayStorage->m_sparseMap.clear();
2668 }
2669
2670 bool JSObject::attemptToInterceptPutByIndexOnHoleForPrototype(ExecState* exec, JSValue thisValue, unsigned i, JSValue value, bool shouldThrow, bool& putResult)
2671 {
2672     VM& vm = exec->vm();
2673     for (JSObject* current = this; ;) {
2674         // This has the same behavior with respect to prototypes as JSObject::put(). It only
2675         // allows a prototype to intercept a put if (a) the prototype declares the property
2676         // we're after rather than intercepting it via an override of JSObject::put(), and
2677         // (b) that property is declared as ReadOnly or Accessor.
2678         
2679         ArrayStorage* storage = current->arrayStorageOrNull();
2680         if (storage && storage->m_sparseMap) {
2681             SparseArrayValueMap::iterator iter = storage->m_sparseMap->find(i);
2682             if (iter != storage->m_sparseMap->notFound() && (iter->value.attributes() & (PropertyAttribute::Accessor | PropertyAttribute::ReadOnly))) {
2683                 putResult = iter->value.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow);
2684                 return true;
2685             }
2686         }
2687
2688         if (current->type() == ProxyObjectType) {
2689             ProxyObject* proxy = jsCast<ProxyObject*>(current);
2690             putResult = proxy->putByIndexCommon(exec, thisValue, i, value, shouldThrow);
2691             return true;
2692         }
2693         
2694         JSValue prototypeValue = current->getPrototypeDirect(vm);
2695         if (prototypeValue.isNull())
2696             return false;
2697         
2698         current = asObject(prototypeValue);
2699     }
2700 }
2701
2702 bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, bool& putResult)
2703 {
2704     JSValue prototypeValue = getPrototypeDirect(exec->vm());
2705     if (prototypeValue.isNull())
2706         return false;
2707     
2708     return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow, putResult);
2709 }
2710
2711 template<IndexingType indexingShape>
2712 bool JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, unsigned i, JSValue value)
2713 {
2714     VM& vm = exec->vm();
2715     auto scope = DECLARE_THROW_SCOPE(vm);
2716
2717     RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!isCopyOnWrite(indexingMode()));
2718     ASSERT((indexingType() & IndexingShapeMask) == indexingShape);
2719     ASSERT(!indexingShouldBeSparse(vm));
2720
2721     Butterfly* butterfly = m_butterfly.get();
2722     
2723     // For us to get here, the index is either greater than the public length, or greater than
2724     // or equal to the vector length.
2725     ASSERT(i >= butterfly->vectorLength());
2726     
2727     if (i > MAX_STORAGE_VECTOR_INDEX
2728         || (i >= MIN_SPARSE_ARRAY_INDEX && !isDenseEnoughForVector(i, countElements<indexingShape>(butterfly)))
2729         || indexIsSufficientlyBeyondLengthForSparseMap(i, butterfly->vectorLength())) {
2730         ASSERT(i <= MAX_ARRAY_INDEX);
2731         ensureArrayStorageSlow(vm);
2732         SparseArrayValueMap* map = allocateSparseIndexMap(vm);
2733         bool result = map->putEntry(exec, this, i, value, false);
2734         RETURN_IF_EXCEPTION(scope, false);
2735         ASSERT(i >= arrayStorage()->length());
2736         arrayStorage()->setLength(i + 1);
2737         return result;
2738     }
2739
2740     if (!ensureLength(vm, i + 1)) {
2741         throwOutOfMemoryError(exec, scope);
2742         return false;
2743     }
2744     butterfly = m_butterfly.get();
2745
2746     RELEASE_ASSERT(i < butterfly->vectorLength());
2747     switch (indexingShape) {
2748     case Int32Shape:
2749         ASSERT(value.isInt32());
2750         butterfly->contiguous().at(this, i).setWithoutWriteBarrier(value);
2751         return true;
2752         
2753     case DoubleShape: {
2754         ASSERT(value.isNumber());
2755         double valueAsDouble = value.asNumber();
2756         ASSERT(valueAsDouble == valueAsDouble);
2757         butterfly->contiguousDouble().at(this, i) = valueAsDouble;
2758         return true;
2759     }
2760         
2761     case ContiguousShape:
2762         butterfly->contiguous().at(this, i).set(vm, this, value);
2763         return true;
2764         
2765     default:
2766         CRASH();
2767         return false;
2768     }
2769 }
2770
2771 // Explicit instantiations needed by JSArray.cpp.
2772 template bool JSObject::putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(ExecState*, unsigned, JSValue);
2773 template bool JSObject::putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(ExecState*, unsigned, JSValue);
2774 template bool JSObject::putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(ExecState*, unsigned, JSValue);
2775
2776 bool JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage)
2777 {
2778     VM& vm = exec->vm();
2779     auto scope = DECLARE_THROW_SCOPE(vm);
2780
2781     ASSERT(!isCopyOnWrite(indexingMode()));
2782     // i should be a valid array index that is outside of the current vector.
2783     ASSERT(i <= MAX_ARRAY_INDEX);
2784     ASSERT(i >= storage->vectorLength());
2785     
2786     SparseArrayValueMap* map = storage->m_sparseMap.get();
2787     
2788     // First, handle cases where we don't currently have a sparse map.
2789     if (LIKELY(!map)) {
2790         // If the array is not extensible, we should have entered dictionary mode, and created the sparse map.
2791         ASSERT(isStructureExtensible(vm));
2792     
2793         // Update m_length if necessary.
2794         if (i >= storage->length())
2795             storage->setLength(i + 1);
2796
2797         // Check that it is sensible to still be using a vector, and then try to grow the vector.
2798         if (LIKELY(!indexIsSufficientlyBeyondLengthForSparseMap(i, storage->vectorLength()) 
2799             && isDenseEnoughForVector(i, storage->m_numValuesInVector)
2800             && increaseVectorLength(vm, i + 1))) {
2801             // success! - reread m_storage since it has likely been reallocated, and store to the vector.
2802             storage = arrayStorage();
2803             storage->m_vector[i].set(vm, this, value);
2804             ++storage->m_numValuesInVector;
2805             return true;
2806         }
2807         // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value.
2808         map = allocateSparseIndexMap(vm);
2809         RELEASE_AND_RETURN(scope, map->putEntry(exec, this, i, value, shouldThrow));
2810     }
2811
2812     // Update m_length if necessary.
2813     unsigned length = storage->length();
2814     if (i >= length) {
2815         // Prohibit growing the array if length is not writable.
2816         if (map->lengthIsReadOnly() || !isStructureExtensible(vm))
2817             return typeError(exec, scope, shouldThrow, ReadonlyPropertyWriteError);
2818         length = i + 1;
2819         storage->setLength(length);
2820     }
2821
2822     // We are currently using a map - check whether we still want to be doing so.
2823     // We will continue  to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails.
2824     unsigned numValuesInArray = storage->m_numValuesInVector + map->size();
2825     if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(vm, length))
2826         RELEASE_AND_RETURN(scope, map->putEntry(exec, this, i, value, shouldThrow));
2827
2828     // Reread m_storage after increaseVectorLength, update m_numValuesInVector.
2829     storage = arrayStorage();
2830     storage->m_numValuesInVector = numValuesInArray;
2831
2832     // Copy all values from the map into the vector, and delete the map.
2833     WriteBarrier<Unknown>* vector = storage->m_vector;
2834     SparseArrayValueMap::const_iterator end = map->end();
2835     for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
2836         vector[it->key].set(vm, this, it->value.getNonSparseMode());
2837     deallocateSparseIndexMap();
2838
2839     // Store the new property into the vector.
2840     WriteBarrier<Unknown>& valueSlot = vector[i];
2841     if (!valueSlot)
2842         ++storage->m_numValuesInVector;
2843     valueSlot.set(vm, this, value);
2844     return true;
2845 }
2846
2847 bool JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
2848 {
2849     VM& vm = exec->vm();
2850
2851     RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!isCopyOnWrite(indexingMode()));
2852
2853     // i should be a valid array index that is outside of the current vector.
2854     ASSERT(i <= MAX_ARRAY_INDEX);
2855     
2856     switch (indexingType()) {
2857     case ALL_BLANK_INDEXING_TYPES: {
2858         if (indexingShouldBeSparse(vm)) {
2859             return putByIndexBeyondVectorLengthWithArrayStorage(
2860                 exec, i, value, shouldThrow,
2861                 ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
2862         }
2863         if (indexIsSufficientlyBeyondLengthForSparseMap(i, 0) || i >= MIN_SPARSE_ARRAY_INDEX) {
2864             return putByIndexBeyondVectorLengthWithArrayStorage(
2865                 exec, i, value, shouldThrow, createArrayStorage(vm, 0, 0));
2866         }
2867         if (needsSlowPutIndexing(vm)) {
2868             // Convert the indexing type to the SlowPutArrayStorage and retry.
2869             createArrayStorage(vm, i + 1, getNewVectorLength(vm, 0, 0, 0, i + 1));
2870             return putByIndex(this, exec, i, value, shouldThrow);
2871         }
2872         
2873         createInitialForValueAndSet(vm, i, value);
2874         return true;
2875     }
2876         
2877     case ALL_UNDECIDED_INDEXING_TYPES: {
2878         CRASH();
2879         break;
2880     }
2881         
2882     case ALL_INT32_INDEXING_TYPES:
2883         return putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value);
2884         
2885     case ALL_DOUBLE_INDEXING_TYPES:
2886         return putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value);
2887         
2888     case ALL_CONTIGUOUS_INDEXING_TYPES:
2889         return putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value);
2890         
2891     case NonArrayWithSlowPutArrayStorage:
2892     case ArrayWithSlowPutArrayStorage: {
2893         // No own property present in the vector, but there might be in the sparse map!
2894         SparseArrayValueMap* map = arrayStorage()->m_sparseMap.get();
2895         bool putResult = false;
2896         if (!(map && map->contains(i)) && attemptToInterceptPutByIndexOnHole(exec, i, value, shouldThrow, putResult))
2897             return putResult;
2898         FALLTHROUGH;
2899     }
2900
2901     case NonArrayWithArrayStorage:
2902     case ArrayWithArrayStorage:
2903         return putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, arrayStorage());
2904         
2905     default:
2906         RELEASE_ASSERT_NOT_REACHED();
2907     }
2908     return false;
2909 }
2910
2911 bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode, ArrayStorage* storage)
2912 {
2913     VM& vm = exec->vm();
2914     auto scope = DECLARE_THROW_SCOPE(vm);
2915     
2916     // i should be a valid array index that is outside of the current vector.
2917     ASSERT(hasAnyArrayStorage(indexingType()));
2918     ASSERT(arrayStorage() == storage);
2919     ASSERT(i >= storage->vectorLength() || attributes);
2920     ASSERT(i <= MAX_ARRAY_INDEX);
2921
2922     SparseArrayValueMap* map = storage->m_sparseMap.get();
2923
2924     // First, handle cases where we don't currently have a sparse map.
2925     if (LIKELY(!map)) {
2926         // If the array is not extensible, we should have entered dictionary mode, and created the spare map.
2927         ASSERT(isStructureExtensible(vm));
2928     
2929         // Update m_length if necessary.
2930         if (i >= storage->length())
2931             storage->setLength(i + 1);
2932
2933         // Check that it is sensible to still be using a vector, and then try to grow the vector.
2934         if (LIKELY(
2935                 !attributes
2936                 && (isDenseEnoughForVector(i, storage->m_numValuesInVector))
2937                 && !indexIsSufficientlyBeyondLengthForSparseMap(i, storage->vectorLength()))
2938                 && increaseVectorLength(vm, i + 1)) {
2939             // success! - reread m_storage since it has likely been reallocated, and store to the vector.
2940             storage = arrayStorage();
2941             storage->m_vector[i].set(vm, this, value);
2942             ++storage->m_numValuesInVector;
2943             return true;
2944         }
2945         // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value.
2946         map = allocateSparseIndexMap(vm);
2947         RELEASE_AND_RETURN(scope, map->putDirect(exec, this, i, value, attributes, mode));
2948     }
2949
2950     // Update m_length if necessary.
2951     unsigned length = storage->length();
2952     if (i >= length) {
2953         if (mode != PutDirectIndexLikePutDirect) {
2954             // Prohibit growing the array if length is not writable.
2955             if (map->lengthIsReadOnly())
2956                 return typeError(exec, scope, mode == PutDirectIndexShouldThrow, ReadonlyPropertyWriteError);
2957             if (!isStructureExtensible(vm))
2958                 return typeError(exec, scope, mode == PutDirectIndexShouldThrow, NonExtensibleObjectPropertyDefineError);
2959         }
2960         length = i + 1;
2961         storage->setLength(length);
2962     }
2963
2964     // We are currently using a map - check whether we still want to be doing so.
2965     // We will continue  to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails.
2966     unsigned numValuesInArray = storage->m_numValuesInVector + map->size();
2967     if (map->sparseMode() || attributes || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(vm, length))
2968         RELEASE_AND_RETURN(scope, map->putDirect(exec, this, i, value, attributes, mode));
2969
2970     // Reread m_storage after increaseVectorLength, update m_numValuesInVector.
2971     storage = arrayStorage();
2972     storage->m_numValuesInVector = numValuesInArray;
2973
2974     // Copy all values from the map into the vector, and delete the map.
2975     WriteBarrier<Unknown>* vector = storage->m_vector;
2976     SparseArrayValueMap::const_iterator end = map->end();
2977     for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
2978         vector[it->key].set(vm, this, it->value.getNonSparseMode());
2979     deallocateSparseIndexMap();
2980
2981     // Store the new property into the vector.
2982     WriteBarrier<Unknown>& valueSlot = vector[i];
2983     if (!valueSlot)
2984         ++storage->m_numValuesInVector;
2985     valueSlot.set(vm, this, value);
2986     return true;
2987 }
2988
2989 bool JSObject::putDirectIndexSlowOrBeyondVectorLength(ExecState* exec, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode)
2990 {
2991     VM& vm = exec->vm();
2992     ASSERT(!value.isCustomGetterSetter());
2993
2994     if (!canDoFastPutDirectIndex(vm, this)) {
2995         PropertyDescriptor descriptor;
2996         descriptor.setDescriptor(value, attributes);
2997         return methodTable(vm)->defineOwnProperty(this, exec, Identifier::from(exec, i), descriptor, mode == PutDirectIndexShouldThrow);
2998     }
2999
3000     // i should be a valid array index that is outside of the current vector.
3001     ASSERT(i <= MAX_ARRAY_INDEX);
3002     
3003     if (attributes & (PropertyAttribute::ReadOnly | PropertyAttribute::Accessor))
3004         notifyPresenceOfIndexedAccessors(vm);
3005     
3006     switch (indexingType()) {
3007     case ALL_BLANK_INDEXING_TYPES: {
3008         if (indexingShouldBeSparse(vm) || attributes) {
3009             return putDirectIndexBeyondVectorLengthWithArrayStorage(
3010                 exec, i, value, attributes, mode,
3011                 ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
3012         }
3013         if (i >= MIN_SPARSE_ARRAY_INDEX) {
3014             return putDirectIndexBeyondVectorLengthWithArrayStorage(
3015                 exec, i, value, attributes, mode, createArrayStorage(vm, 0, 0));
3016         }
3017         if (needsSlowPutIndexing(vm)) {
3018             ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(vm, 0, 0, 0, i + 1));
3019             storage->m_vector[i].set(vm, this, value);
3020             storage->m_numValuesInVector++;
3021             return true;
3022         }
3023         
3024         createInitialForValueAndSet(vm, i, value);
3025         return true;
3026     }
3027         
3028     case ALL_UNDECIDED_INDEXING_TYPES: {
3029         convertUndecidedForValue(vm, value);
3030         // Reloop.
3031         return putDirectIndex(exec, i, value, attributes, mode);
3032     }
3033         
3034     case ALL_INT32_INDEXING_TYPES: {
3035         ASSERT(!indexingShouldBeSparse(vm));
3036         if (attributes)
3037             return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
3038         if (!value.isInt32()) {
3039             convertInt32ForValue(vm, value);
3040             return putDirectIndexSlowOrBeyondVectorLength(exec, i, value, attributes, mode);
3041         }
3042         putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value);
3043         return true;
3044     }
3045         
3046     case ALL_DOUBLE_INDEXING_TYPES: {
3047         ASSERT(!indexingShouldBeSparse(vm));
3048         if (attributes)
3049             return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
3050         if (!value.isNumber()) {
3051             convertDoubleToContiguous(vm);
3052             return putDirectIndexSlowOrBeyondVectorLength(exec, i, value, attributes, mode);
3053         }
3054         double valueAsDouble = value.asNumber();
3055         if (valueAsDouble != valueAsDouble) {
3056             convertDoubleToContiguous(vm);
3057             return putDirectIndexSlowOrBeyondVectorLength(exec, i, value, attributes, mode);
3058         }
3059         putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value);
3060         return true;
3061     }
3062         
3063     case ALL_CONTIGUOUS_INDEXING_TYPES: {
3064         ASSERT(!indexingShouldBeSparse(vm));
3065         if (attributes)
3066             return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
3067         putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value);
3068         return true;
3069     }
3070
3071     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
3072         if (attributes)
3073             return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
3074         return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, arrayStorage());
3075         
3076     default:
3077         RELEASE_ASSERT_NOT_REACHED();
3078         return false;
3079     }
3080 }
3081
3082 bool JSObject::putDirectNativeIntrinsicGetter(VM& vm, JSGlobalObject* globalObject, Identifier name, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
3083 {
3084     JSFunction* function = JSFunction::create(vm, globalObject, 0, makeString("get ", name.string()), nativeFunction, intrinsic);
3085     GetterSetter* accessor = GetterSetter::create(vm, globalObject, function, nullptr);
3086     return putDirectNonIndexAccessor(vm, name, accessor, attributes);
3087 }
3088
3089 bool JSObject::putDirectNativeFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
3090 {
3091     StringImpl* name = propertyName.publicName();
3092     if (!name)
3093         name = vm.propertyNames->anonymous.impl();
3094     ASSERT(name);
3095
3096     JSFunction* function = JSFunction::create(vm, globalObject, functionLength, name, nativeFunction, intrinsic);
3097     return putDirect(vm, propertyName, function, attributes);
3098 }
3099
3100 bool JSObject::putDirectNativeFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, const DOMJIT::Signature* signature, unsigned attributes)
3101 {
3102     StringImpl* name = propertyName.publicName();
3103     if (!name)
3104         name = vm.propertyNames->anonymous.impl();
3105     ASSERT(name);
3106
3107     JSFunction* function = JSFunction::create(vm, globalObject, functionLength, name, nativeFunction, intrinsic, callHostFunctionAsConstructor, signature);
3108     return putDirect(vm, propertyName, function, attributes);
3109 }
3110
3111 void JSObject::putDirectNativeFunctionWithoutTransition(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
3112 {
3113     StringImpl* name = propertyName.publicName();
3114     if (!name)
3115         name = vm.propertyNames->anonymous.impl();
3116     ASSERT(name);
3117     JSFunction* function = JSFunction::create(vm, globalObject, functionLength, name, nativeFunction, intrinsic);
3118     putDirectWithoutTransition(vm, propertyName, function, attributes);
3119 }
3120
3121 JSFunction* JSObject::putDirectBuiltinFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, FunctionExecutable* functionExecutable, 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, static_cast<FunctionExecutable*>(functionExecutable), globalObject);
3128     putDirect(vm, propertyName, function, attributes);
3129     return function;
3130 }
3131
3132 JSFunction* JSObject::putDirectBuiltinFunctionWithoutTransition(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, FunctionExecutable* functionExecutable, unsigned attributes)
3133 {
3134     JSFunction* function = JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), globalObject);
3135     putDirectWithoutTransition(vm, propertyName, function, attributes);
3136     return function;
3137 }
3138
3139 // NOTE: This method is for ArrayStorage vectors.
3140 ALWAYS_INLINE unsigned JSObject::getNewVectorLength(VM& vm, unsigned indexBias, unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength)
3141 {
3142     ASSERT(desiredLength <= MAX_STORAGE_VECTOR_LENGTH);
3143
3144     unsigned increasedLength;
3145     unsigned maxInitLength = std::min(currentLength, 100000U);
3146
3147     if (desiredLength < maxInitLength)
3148         increasedLength = maxInitLength;
3149     else if (!currentVectorLength)
3150         increasedLength = std::max(desiredLength, lastArraySize);
3151     else {
3152         increasedLength = timesThreePlusOneDividedByTwo(desiredLength);
3153     }
3154
3155     ASSERT(increasedLength >= desiredLength);
3156
3157     lastArraySize = std::min(increasedLength, FIRST_ARRAY_STORAGE_VECTOR_GROW);
3158
3159     return ArrayStorage::optimalVectorLength(
3160         indexBias, structure(vm)->outOfLineCapacity(),
3161         std::min(increasedLength, MAX_STORAGE_VECTOR_LENGTH));
3162 }
3163
3164 ALWAYS_INLINE unsigned JSObject::getNewVectorLength(VM& vm, unsigned desiredLength)
3165 {
3166     unsigned indexBias = 0;
3167     unsigned vectorLength = 0;
3168     unsigned length = 0;
3169     
3170     if (hasIndexedProperties(indexingType())) {
3171         if (ArrayStorage* storage = arrayStorageOrNull())
3172             indexBias = storage->m_indexBias;
3173         vectorLength = m_butterfly->vectorLength();
3174         length = m_butterfly->publicLength();
3175     }
3176
3177     return getNewVectorLength(vm, indexBias, vectorLength, length, desiredLength);
3178 }
3179
3180 template<IndexingType indexingShape>
3181 unsigned JSObject::countElements(Butterfly* butterfly)
3182 {
3183     unsigned numValues = 0;
3184     for (unsigned i = butterfly->publicLength(); i--;) {
3185         switch (indexingShape) {
3186         case Int32Shape:
3187         case ContiguousShape:
3188             if (butterfly->contiguous().at(this, i))
3189                 numValues++;
3190             break;
3191             
3192         case DoubleShape: {
3193             double value = butterfly->contiguousDouble().at(this, i);
3194             if (value == value)
3195                 numValues++;
3196             break;
3197         }
3198             
3199         default:
3200             CRASH();
3201         }
3202     }
3203     return numValues;
3204 }
3205
3206 unsigned JSObject::countElements()
3207 {
3208     switch (indexingType()) {
3209     case ALL_BLANK_INDEXING_TYPES:
3210     case ALL_UNDECIDED_INDEXING_TYPES:
3211         return 0;
3212         
3213     case ALL_INT32_INDEXING_TYPES:
3214         return countElements<Int32Shape>(butterfly());
3215         
3216     case ALL_DOUBLE_INDEXING_TYPES:
3217         return countElements&l