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