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