PropertyAttribute needs a CustomValue bit.
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSObject.h
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4  *  Copyright (C) 2003-2018 Apple Inc. All rights reserved.
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public License
17  *  along with this library; see the file COPYING.LIB.  If not, write to
18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #pragma once
24
25 #include "ArrayConventions.h"
26 #include "ArrayStorage.h"
27 #include "Butterfly.h"
28 #include "CPU.h"
29 #include "CagedBarrierPtr.h"
30 #include "CallFrame.h"
31 #include "ClassInfo.h"
32 #include "CustomGetterSetter.h"
33 #include "DOMAttributeGetterSetter.h"
34 #include "Heap.h"
35 #include "IndexingHeaderInlines.h"
36 #include "JSCast.h"
37 #include "ObjectInitializationScope.h"
38 #include "PropertySlot.h"
39 #include "PropertyStorage.h"
40 #include "PutDirectIndexMode.h"
41 #include "PutPropertySlot.h"
42 #include "Structure.h"
43 #include "StructureTransitionTable.h"
44 #include "VM.h"
45 #include "JSString.h"
46 #include "SparseArrayValueMap.h"
47 #include <wtf/StdLibExtras.h>
48
49 namespace JSC {
50 namespace DOMJIT {
51 class Signature;
52 }
53
54 inline JSCell* getJSFunction(JSValue value)
55 {
56     if (value.isCell() && (value.asCell()->type() == JSFunctionType))
57         return value.asCell();
58     return 0;
59 }
60
61 class GetterSetter;
62 class InternalFunction;
63 class JSFunction;
64 class LLIntOffsetsExtractor;
65 class MarkedBlock;
66 class PropertyDescriptor;
67 class PropertyNameArray;
68 class Structure;
69 class ThrowScope;
70 struct HashTable;
71 struct HashTableValue;
72
73 JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*, ThrowScope&, const String&);
74 extern JS_EXPORT_PRIVATE const ASCIILiteral NonExtensibleObjectPropertyDefineError;
75 extern JS_EXPORT_PRIVATE const ASCIILiteral ReadonlyPropertyWriteError;
76 extern JS_EXPORT_PRIVATE const ASCIILiteral ReadonlyPropertyChangeError;
77 extern JS_EXPORT_PRIVATE const ASCIILiteral UnableToDeletePropertyError;
78 extern JS_EXPORT_PRIVATE const ASCIILiteral UnconfigurablePropertyChangeAccessMechanismError;
79 extern JS_EXPORT_PRIVATE const ASCIILiteral UnconfigurablePropertyChangeConfigurabilityError;
80 extern JS_EXPORT_PRIVATE const ASCIILiteral UnconfigurablePropertyChangeEnumerabilityError;
81 extern JS_EXPORT_PRIVATE const ASCIILiteral UnconfigurablePropertyChangeWritabilityError;
82
83 COMPILE_ASSERT(PropertyAttribute::None < FirstInternalAttribute, None_is_below_FirstInternalAttribute);
84 COMPILE_ASSERT(PropertyAttribute::ReadOnly < FirstInternalAttribute, ReadOnly_is_below_FirstInternalAttribute);
85 COMPILE_ASSERT(PropertyAttribute::DontEnum < FirstInternalAttribute, DontEnum_is_below_FirstInternalAttribute);
86 COMPILE_ASSERT(PropertyAttribute::DontDelete < FirstInternalAttribute, DontDelete_is_below_FirstInternalAttribute);
87 COMPILE_ASSERT(PropertyAttribute::Accessor < FirstInternalAttribute, Accessor_is_below_FirstInternalAttribute);
88
89 class JSFinalObject;
90
91 class JSObject : public JSCell {
92     friend class BatchedTransitionOptimizer;
93     friend class JIT;
94     friend class JSCell;
95     friend class JSFinalObject;
96     friend class MarkedBlock;
97     JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(VM&, const HashTableValue*, JSObject*, PropertyName, PropertySlot&);
98
99     enum PutMode {
100         PutModePut,
101         PutModeDefineOwnProperty,
102     };
103
104 public:
105     typedef JSCell Base;
106
107     template<typename>
108     static CompleteSubspace* subspaceFor(VM& vm)
109     {
110         return &vm.cellJSValueOOBSpace;
111     }
112
113     // This is a super dangerous method for JITs. Sometimes the JITs will want to create either a
114     // JSFinalObject or a JSArray. This is the method that will do that.
115     static JSObject* createRawObject(ExecState* exec, Structure* structure, Butterfly* = nullptr);
116
117     JS_EXPORT_PRIVATE static size_t estimatedSize(JSCell*, VM&);
118     JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
119     JS_EXPORT_PRIVATE static void heapSnapshot(JSCell*, HeapSnapshotBuilder&);
120
121     JS_EXPORT_PRIVATE static String className(const JSObject*, VM&);
122     JS_EXPORT_PRIVATE static String calculatedClassName(JSObject*);
123
124     // This function is what Object.prototype.toString() will use to get the name of
125     // an object when using Symbol.toStringTag fails. For the most part there is no
126     // difference between this and className(). The main use case is for new JS language
127     // objects to set the default tag to "Object".
128     JS_EXPORT_PRIVATE static String toStringName(const JSObject*, ExecState*);
129
130     // This is the fully virtual [[GetPrototypeOf]] internal function defined
131     // in the ECMAScript 6 specification. Use this when doing a [[GetPrototypeOf]] 
132     // operation as dictated in the specification.
133     JSValue getPrototype(VM&, ExecState*);
134     JS_EXPORT_PRIVATE static JSValue getPrototype(JSObject*, ExecState*);
135     // This gets the prototype directly off of the structure. This does not do
136     // dynamic dispatch on the getPrototype method table method. It is not valid 
137     // to use this when performing a [[GetPrototypeOf]] operation in the specification.
138     // It is valid to use though when you know that you want to directly get it
139     // without consulting the method table. This is akin to getting the [[Prototype]]
140     // internal field directly as described in the specification.
141     JSValue getPrototypeDirect(VM&) const;
142
143     // This sets the prototype without checking for cycles and without
144     // doing dynamic dispatch on [[SetPrototypeOf]] operation in the specification.
145     // It is not valid to use this when performing a [[SetPrototypeOf]] operation in
146     // the specification. It is valid to use though when you know that you want to directly
147     // set it without consulting the method table and when you definitely won't
148     // introduce a cycle in the prototype chain. This is akin to setting the
149     // [[Prototype]] internal field directly as described in the specification.
150     JS_EXPORT_PRIVATE void setPrototypeDirect(VM&, JSValue prototype);
151 private:
152     // This is OrdinarySetPrototypeOf in the specification. Section 9.1.2.1
153     // https://tc39.github.io/ecma262/#sec-ordinarysetprototypeof
154     JS_EXPORT_PRIVATE bool setPrototypeWithCycleCheck(VM&, ExecState*, JSValue prototype, bool shouldThrowIfCantSet);
155 public:
156     // This is the fully virtual [[SetPrototypeOf]] internal function defined
157     // in the ECMAScript 6 specification. Use this when doing a [[SetPrototypeOf]] 
158     // operation as dictated in the specification.
159     bool setPrototype(VM&, ExecState*, JSValue prototype, bool shouldThrowIfCantSet = false);
160     JS_EXPORT_PRIVATE static bool setPrototype(JSObject*, ExecState*, JSValue prototype, bool shouldThrowIfCantSet);
161         
162     inline bool mayInterceptIndexedAccesses(VM&);
163
164     JSValue get(ExecState*, PropertyName) const;
165     JSValue get(ExecState*, unsigned propertyName) const;
166
167     template<bool checkNullStructure = false>
168     bool getPropertySlot(ExecState*, PropertyName, PropertySlot&);
169     bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
170     template<typename CallbackWhenNoException> typename std::result_of<CallbackWhenNoException(bool, PropertySlot&)>::type getPropertySlot(ExecState*, PropertyName, CallbackWhenNoException) const;
171     template<typename CallbackWhenNoException> typename std::result_of<CallbackWhenNoException(bool, PropertySlot&)>::type getPropertySlot(ExecState*, PropertyName, PropertySlot&, CallbackWhenNoException) const;
172
173     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
174     JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
175     bool getOwnPropertySlotInline(ExecState*, PropertyName, PropertySlot&);
176
177     // The key difference between this and getOwnPropertySlot is that getOwnPropertySlot
178     // currently returns incorrect results for the DOM window (with non-own properties)
179     // being returned. Once this is fixed we should migrate code & remove this method.
180     JS_EXPORT_PRIVATE bool getOwnPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
181
182     unsigned getArrayLength() const
183     {
184         if (!hasIndexedProperties(indexingType()))
185             return 0;
186         return m_butterfly->publicLength();
187     }
188         
189     unsigned getVectorLength()
190     {
191         if (!hasIndexedProperties(indexingType()))
192             return 0;
193         return m_butterfly->vectorLength();
194     }
195     
196     static bool putInlineForJSObject(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
197     
198     JS_EXPORT_PRIVATE static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
199     // putByIndex assumes that the receiver is this JSCell object.
200     JS_EXPORT_PRIVATE static bool putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
201         
202     // This performs the ECMAScript Set() operation.
203     ALWAYS_INLINE bool putByIndexInline(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
204     {
205         if (canSetIndexQuickly(propertyName)) {
206             setIndexQuickly(exec->vm(), propertyName, value);
207             return true;
208         }
209         return methodTable(exec->vm())->putByIndex(this, exec, propertyName, value, shouldThrow);
210     }
211         
212     // This is similar to the putDirect* methods:
213     //  - the prototype chain is not consulted
214     //  - accessors are not called.
215     //  - it will ignore extensibility and read-only properties if PutDirectIndexLikePutDirect is passed as the mode (the default).
216     // This method creates a property with attributes writable, enumerable and configurable all set to true if attributes is zero,
217     // otherwise, it creates a property with the provided attributes. Semantically, this is performing defineOwnProperty.
218     bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes, PutDirectIndexMode mode)
219     {
220         ASSERT(!value.isCustomGetterSetter());
221         auto canSetIndexQuicklyForPutDirect = [&] () -> bool {
222             switch (indexingMode()) {
223             case ALL_BLANK_INDEXING_TYPES:
224             case ALL_UNDECIDED_INDEXING_TYPES:
225                 return false;
226             case ALL_WRITABLE_INT32_INDEXING_TYPES:
227             case ALL_WRITABLE_DOUBLE_INDEXING_TYPES:
228             case ALL_WRITABLE_CONTIGUOUS_INDEXING_TYPES:
229             case ALL_ARRAY_STORAGE_INDEXING_TYPES:
230                 return propertyName < m_butterfly->vectorLength();
231             default:
232                 if (isCopyOnWrite(indexingMode()))
233                     return false;
234                 RELEASE_ASSERT_NOT_REACHED();
235                 return false;
236             }
237         };
238         
239         if (!attributes && canSetIndexQuicklyForPutDirect()) {
240             setIndexQuickly(exec->vm(), propertyName, value);
241             return true;
242         }
243         return putDirectIndexSlowOrBeyondVectorLength(exec, propertyName, value, attributes, mode);
244     }
245     // This is semantically equivalent to performing defineOwnProperty(propertyName, {configurable:true, writable:true, enumerable:true, value:value}).
246     bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value)
247     {
248         return putDirectIndex(exec, propertyName, value, 0, PutDirectIndexLikePutDirect);
249     }
250
251     // A generally non-throwing version of putDirect and putDirectIndex.
252     // However, it's only guaranteed to not throw based on what the receiver is.
253     // For example, if the receiver is a ProxyObject, this is not guaranteed, since
254     // it may call into arbitrary JS code. It's the responsibility of the user of
255     // this API to ensure that the receiver object is a well known type if they
256     // want to ensure that this won't throw an exception.
257     JS_EXPORT_PRIVATE bool putDirectMayBeIndex(ExecState*, PropertyName, JSValue);
258         
259     bool hasIndexingHeader(VM& vm) const
260     {
261         return structure(vm)->hasIndexingHeader(this);
262     }
263     
264     bool canGetIndexQuickly(unsigned i)
265     {
266         Butterfly* butterfly = this->butterfly();
267         switch (indexingType()) {
268         case ALL_BLANK_INDEXING_TYPES:
269         case ALL_UNDECIDED_INDEXING_TYPES:
270             return false;
271         case ALL_INT32_INDEXING_TYPES:
272         case ALL_CONTIGUOUS_INDEXING_TYPES:
273             return i < butterfly->vectorLength() && butterfly->contiguous().at(this, i);
274         case ALL_DOUBLE_INDEXING_TYPES: {
275             if (i >= butterfly->vectorLength())
276                 return false;
277             double value = butterfly->contiguousDouble().at(this, i);
278             if (value != value)
279                 return false;
280             return true;
281         }
282         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
283             return i < butterfly->arrayStorage()->vectorLength() && butterfly->arrayStorage()->m_vector[i];
284         default:
285             RELEASE_ASSERT_NOT_REACHED();
286             return false;
287         }
288     }
289         
290     JSValue getIndexQuickly(unsigned i)
291     {
292         Butterfly* butterfly = this->butterfly();
293         switch (indexingType()) {
294         case ALL_INT32_INDEXING_TYPES:
295             return jsNumber(butterfly->contiguous().at(this, i).get().asInt32());
296         case ALL_CONTIGUOUS_INDEXING_TYPES:
297             return butterfly->contiguous().at(this, i).get();
298         case ALL_DOUBLE_INDEXING_TYPES:
299             return JSValue(JSValue::EncodeAsDouble, butterfly->contiguousDouble().at(this, i));
300         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
301             return butterfly->arrayStorage()->m_vector[i].get();
302         default:
303             RELEASE_ASSERT_NOT_REACHED();
304             return JSValue();
305         }
306     }
307         
308     JSValue tryGetIndexQuickly(unsigned i) const
309     {
310         Butterfly* butterfly = const_cast<JSObject*>(this)->butterfly();
311         switch (indexingType()) {
312         case ALL_BLANK_INDEXING_TYPES:
313         case ALL_UNDECIDED_INDEXING_TYPES:
314             break;
315         case ALL_INT32_INDEXING_TYPES:
316             if (i < butterfly->publicLength()) {
317                 JSValue result = butterfly->contiguous().at(this, i).get();
318                 ASSERT(result.isInt32() || !result);
319                 return result;
320             }
321             break;
322         case ALL_CONTIGUOUS_INDEXING_TYPES:
323             if (i < butterfly->publicLength())
324                 return butterfly->contiguous().at(this, i).get();
325             break;
326         case ALL_DOUBLE_INDEXING_TYPES: {
327             if (i >= butterfly->publicLength())
328                 break;
329             double result = butterfly->contiguousDouble().at(this, i);
330             if (result != result)
331                 break;
332             return JSValue(JSValue::EncodeAsDouble, result);
333         }
334         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
335             if (i < butterfly->arrayStorage()->vectorLength())
336                 return butterfly->arrayStorage()->m_vector[i].get();
337             break;
338         default:
339             RELEASE_ASSERT_NOT_REACHED();
340             break;
341         }
342         return JSValue();
343     }
344         
345     JSValue getDirectIndex(ExecState* exec, unsigned i)
346     {
347         if (JSValue result = tryGetIndexQuickly(i))
348             return result;
349         PropertySlot slot(this, PropertySlot::InternalMethodType::Get);
350         if (methodTable(exec->vm())->getOwnPropertySlotByIndex(this, exec, i, slot))
351             return slot.getValue(exec, i);
352         return JSValue();
353     }
354         
355     JSValue getIndex(ExecState* exec, unsigned i) const
356     {
357         if (JSValue result = tryGetIndexQuickly(i))
358             return result;
359         return get(exec, i);
360     }
361         
362     bool canSetIndexQuickly(unsigned i)
363     {
364         Butterfly* butterfly = this->butterfly();
365         switch (indexingMode()) {
366         case ALL_BLANK_INDEXING_TYPES:
367         case ALL_UNDECIDED_INDEXING_TYPES:
368             return false;
369         case ALL_WRITABLE_INT32_INDEXING_TYPES:
370         case ALL_WRITABLE_DOUBLE_INDEXING_TYPES:
371         case ALL_WRITABLE_CONTIGUOUS_INDEXING_TYPES:
372         case NonArrayWithArrayStorage:
373         case ArrayWithArrayStorage:
374             return i < butterfly->vectorLength();
375         case NonArrayWithSlowPutArrayStorage:
376         case ArrayWithSlowPutArrayStorage:
377             return i < butterfly->arrayStorage()->vectorLength()
378                 && !!butterfly->arrayStorage()->m_vector[i];
379         default:
380             if (isCopyOnWrite(indexingMode()))
381                 return false;
382             RELEASE_ASSERT_NOT_REACHED();
383             return false;
384         }
385     }
386         
387     void setIndexQuickly(VM& vm, unsigned i, JSValue v)
388     {
389         Butterfly* butterfly = m_butterfly.get();
390         ASSERT(!isCopyOnWrite(indexingMode()));
391         switch (indexingType()) {
392         case ALL_INT32_INDEXING_TYPES: {
393             ASSERT(i < butterfly->vectorLength());
394             if (!v.isInt32()) {
395                 convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm, i, v);
396                 return;
397             }
398             FALLTHROUGH;
399         }
400         case ALL_CONTIGUOUS_INDEXING_TYPES: {
401             ASSERT(i < butterfly->vectorLength());
402             butterfly->contiguous().at(this, i).set(vm, this, v);
403             if (i >= butterfly->publicLength())
404                 butterfly->setPublicLength(i + 1);
405             break;
406         }
407         case ALL_DOUBLE_INDEXING_TYPES: {
408             ASSERT(i < butterfly->vectorLength());
409             if (!v.isNumber()) {
410                 convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
411                 return;
412             }
413             double value = v.asNumber();
414             if (value != value) {
415                 convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
416                 return;
417             }
418             butterfly->contiguousDouble().at(this, i) = value;
419             if (i >= butterfly->publicLength())
420                 butterfly->setPublicLength(i + 1);
421             break;
422         }
423         case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
424             ArrayStorage* storage = butterfly->arrayStorage();
425             WriteBarrier<Unknown>& x = storage->m_vector[i];
426             JSValue old = x.get();
427             x.set(vm, this, v);
428             if (!old) {
429                 ++storage->m_numValuesInVector;
430                 if (i >= storage->length())
431                     storage->setLength(i + 1);
432             }
433             break;
434         }
435         default:
436             RELEASE_ASSERT_NOT_REACHED();
437         }
438     }
439
440     void initializeIndex(ObjectInitializationScope& scope, unsigned i, JSValue v)
441     {
442         initializeIndex(scope, i, v, indexingType());
443     }
444
445     // NOTE: Clients of this method may call it more than once for any index, and this is supposed
446     // to work.
447     ALWAYS_INLINE void initializeIndex(ObjectInitializationScope& scope, unsigned i, JSValue v, IndexingType indexingType)
448     {
449         VM& vm = scope.vm();
450         Butterfly* butterfly = m_butterfly.get();
451         switch (indexingType) {
452         case ALL_UNDECIDED_INDEXING_TYPES: {
453             setIndexQuicklyToUndecided(vm, i, v);
454             break;
455         }
456         case ALL_INT32_INDEXING_TYPES: {
457             ASSERT(i < butterfly->publicLength());
458             ASSERT(i < butterfly->vectorLength());
459             if (!v.isInt32()) {
460                 convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm, i, v);
461                 break;
462             }
463             FALLTHROUGH;
464         }
465         case ALL_CONTIGUOUS_INDEXING_TYPES: {
466             ASSERT(i < butterfly->publicLength());
467             ASSERT(i < butterfly->vectorLength());
468             butterfly->contiguous().at(this, i).set(vm, this, v);
469             break;
470         }
471         case ALL_DOUBLE_INDEXING_TYPES: {
472             ASSERT(i < butterfly->publicLength());
473             ASSERT(i < butterfly->vectorLength());
474             if (!v.isNumber()) {
475                 convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
476                 return;
477             }
478             double value = v.asNumber();
479             if (value != value) {
480                 convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
481                 return;
482             }
483             butterfly->contiguousDouble().at(this, i) = value;
484             break;
485         }
486         case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
487             ArrayStorage* storage = butterfly->arrayStorage();
488             ASSERT(i < storage->length());
489             ASSERT(i < storage->m_numValuesInVector);
490             storage->m_vector[i].set(vm, this, v);
491             break;
492         }
493         default:
494             RELEASE_ASSERT_NOT_REACHED();
495         }
496     }
497         
498     void initializeIndexWithoutBarrier(ObjectInitializationScope& scope, unsigned i, JSValue v)
499     {
500         initializeIndexWithoutBarrier(scope, i, v, indexingType());
501     }
502
503     // This version of initializeIndex is for cases where you know that you will not need any
504     // barriers. This implies not having any data format conversions.
505     ALWAYS_INLINE void initializeIndexWithoutBarrier(ObjectInitializationScope&, unsigned i, JSValue v, IndexingType indexingType)
506     {
507         Butterfly* butterfly = m_butterfly.get();
508         switch (indexingType) {
509         case ALL_UNDECIDED_INDEXING_TYPES: {
510             RELEASE_ASSERT_NOT_REACHED();
511             break;
512         }
513         case ALL_INT32_INDEXING_TYPES: {
514             ASSERT(i < butterfly->publicLength());
515             ASSERT(i < butterfly->vectorLength());
516             RELEASE_ASSERT(v.isInt32());
517             FALLTHROUGH;
518         }
519         case ALL_CONTIGUOUS_INDEXING_TYPES: {
520             ASSERT(i < butterfly->publicLength());
521             ASSERT(i < butterfly->vectorLength());
522             butterfly->contiguous().at(this, i).setWithoutWriteBarrier(v);
523             break;
524         }
525         case ALL_DOUBLE_INDEXING_TYPES: {
526             ASSERT(i < butterfly->publicLength());
527             ASSERT(i < butterfly->vectorLength());
528             RELEASE_ASSERT(v.isNumber());
529             double value = v.asNumber();
530             RELEASE_ASSERT(value == value);
531             butterfly->contiguousDouble().at(this, i) = value;
532             break;
533         }
534         case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
535             ArrayStorage* storage = butterfly->arrayStorage();
536             ASSERT(i < storage->length());
537             ASSERT(i < storage->m_numValuesInVector);
538             storage->m_vector[i].setWithoutWriteBarrier(v);
539             break;
540         }
541         default:
542             RELEASE_ASSERT_NOT_REACHED();
543         }
544     }
545         
546     bool hasSparseMap()
547     {
548         switch (indexingType()) {
549         case ALL_BLANK_INDEXING_TYPES:
550         case ALL_UNDECIDED_INDEXING_TYPES:
551         case ALL_INT32_INDEXING_TYPES:
552         case ALL_DOUBLE_INDEXING_TYPES:
553         case ALL_CONTIGUOUS_INDEXING_TYPES:
554             return false;
555         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
556             return !!m_butterfly->arrayStorage()->m_sparseMap;
557         default:
558             RELEASE_ASSERT_NOT_REACHED();
559             return false;
560         }
561     }
562         
563     bool inSparseIndexingMode()
564     {
565         switch (indexingType()) {
566         case ALL_BLANK_INDEXING_TYPES:
567         case ALL_UNDECIDED_INDEXING_TYPES:
568         case ALL_INT32_INDEXING_TYPES:
569         case ALL_DOUBLE_INDEXING_TYPES:
570         case ALL_CONTIGUOUS_INDEXING_TYPES:
571             return false;
572         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
573             return m_butterfly->arrayStorage()->inSparseMode();
574         default:
575             RELEASE_ASSERT_NOT_REACHED();
576             return false;
577         }
578     }
579         
580     void enterDictionaryIndexingMode(VM&);
581
582     // putDirect is effectively an unchecked vesion of 'defineOwnProperty':
583     //  - the prototype chain is not consulted
584     //  - accessors are not called.
585     //  - attributes will be respected (after the call the property will exist with the given attributes)
586     //  - the property name is assumed to not be an index.
587     bool putDirect(VM&, PropertyName, JSValue, unsigned attributes = 0);
588     bool putDirect(VM&, PropertyName, JSValue, PutPropertySlot&);
589     void putDirectWithoutTransition(VM&, PropertyName, JSValue, unsigned attributes = 0);
590     bool putDirectNonIndexAccessor(VM&, PropertyName, GetterSetter*, unsigned attributes);
591     bool putDirectAccessor(ExecState*, PropertyName, GetterSetter*, unsigned attributes);
592     JS_EXPORT_PRIVATE bool putDirectCustomAccessor(VM&, PropertyName, JSValue, unsigned attributes);
593
594     bool putGetter(ExecState*, PropertyName, JSValue, unsigned attributes);
595     bool putSetter(ExecState*, PropertyName, JSValue, unsigned attributes);
596
597     JS_EXPORT_PRIVATE bool hasProperty(ExecState*, PropertyName) const;
598     JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const;
599     bool hasPropertyGeneric(ExecState*, PropertyName, PropertySlot::InternalMethodType) const;
600     bool hasPropertyGeneric(ExecState*, unsigned propertyName, PropertySlot::InternalMethodType) const;
601     bool hasOwnProperty(ExecState*, PropertyName, PropertySlot&) const;
602     bool hasOwnProperty(ExecState*, PropertyName) const;
603     bool hasOwnProperty(ExecState*, unsigned) const;
604
605     JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
606     JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
607
608     JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
609     JSValue ordinaryToPrimitive(ExecState*, PreferredPrimitiveType) const;
610
611     JS_EXPORT_PRIVATE bool hasInstance(ExecState*, JSValue value, JSValue hasInstanceValue);
612     JS_EXPORT_PRIVATE bool hasInstance(ExecState*, JSValue);
613     static bool defaultHasInstance(ExecState*, JSValue, JSValue prototypeProperty);
614
615     JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
616     JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
617     JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
618
619     JS_EXPORT_PRIVATE static uint32_t getEnumerableLength(ExecState*, JSObject*);
620     JS_EXPORT_PRIVATE static void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
621     JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
622
623     JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
624     bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
625     JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
626     JS_EXPORT_PRIVATE JSString* toString(ExecState*) const;
627
628     JS_EXPORT_PRIVATE static JSValue toThis(JSCell*, ExecState*, ECMAMode);
629
630     // This get function only looks at the property map.
631     JSValue getDirect(VM& vm, PropertyName propertyName) const
632     {
633         Structure* structure = this->structure(vm);
634         PropertyOffset offset = structure->get(vm, propertyName);
635         checkOffset(offset, structure->inlineCapacity());
636         return offset != invalidOffset ? getDirect(offset) : JSValue();
637     }
638     
639     JSValue getDirect(VM& vm, PropertyName propertyName, unsigned& attributes) const
640     {
641         Structure* structure = this->structure(vm);
642         PropertyOffset offset = structure->get(vm, propertyName, attributes);
643         checkOffset(offset, structure->inlineCapacity());
644         return offset != invalidOffset ? getDirect(offset) : JSValue();
645     }
646
647     PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName)
648     {
649         Structure* structure = this->structure(vm);
650         PropertyOffset offset = structure->get(vm, propertyName);
651         checkOffset(offset, structure->inlineCapacity());
652         return offset;
653     }
654
655     PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName, unsigned& attributes)
656     {
657         Structure* structure = this->structure(vm);
658         PropertyOffset offset = structure->get(vm, propertyName, attributes);
659         checkOffset(offset, structure->inlineCapacity());
660         return offset;
661     }
662
663     bool hasInlineStorage() const { return structure()->hasInlineStorage(); }
664     ConstPropertyStorage inlineStorageUnsafe() const
665     {
666         return bitwise_cast<ConstPropertyStorage>(this + 1);
667     }
668     PropertyStorage inlineStorageUnsafe()
669     {
670         return bitwise_cast<PropertyStorage>(this + 1);
671     }
672     ConstPropertyStorage inlineStorage() const
673     {
674         ASSERT(hasInlineStorage());
675         return inlineStorageUnsafe();
676     }
677     PropertyStorage inlineStorage()
678     {
679         ASSERT(hasInlineStorage());
680         return inlineStorageUnsafe();
681     }
682         
683     const Butterfly* butterfly() const { return m_butterfly.get(); }
684     Butterfly* butterfly() { return m_butterfly.get(); }
685     
686     ConstPropertyStorage outOfLineStorage() const { return m_butterfly->propertyStorage(); }
687     PropertyStorage outOfLineStorage() { return m_butterfly->propertyStorage(); }
688
689     ALWAYS_INLINE const WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset) const
690     {
691         if (isInlineOffset(offset))
692             return &inlineStorage()[offsetInInlineStorage(offset)];
693         return &outOfLineStorage()[offsetInOutOfLineStorage(offset)];
694     }
695
696     ALWAYS_INLINE WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset)
697     {
698         if (isInlineOffset(offset))
699             return &inlineStorage()[offsetInInlineStorage(offset)];
700         return &outOfLineStorage()[offsetInOutOfLineStorage(offset)];
701     }
702
703     void transitionTo(VM&, Structure*);
704
705     bool hasCustomProperties(VM& vm) { return structure(vm)->didTransition(); }
706     bool hasGetterSetterProperties(VM& vm) { return structure(vm)->hasGetterSetterProperties(); }
707     bool hasCustomGetterSetterProperties(VM& vm) { return structure(vm)->hasCustomGetterSetterProperties(); }
708
709     // putOwnDataProperty has 'put' like semantics, however this method:
710     //  - assumes the object contains no own getter/setter properties.
711     //  - provides no special handling for __proto__
712     //  - does not walk the prototype chain (to check for accessors or non-writable properties).
713     // This is used by JSLexicalEnvironment.
714     bool putOwnDataProperty(VM&, PropertyName, JSValue, PutPropertySlot&);
715     bool putOwnDataPropertyMayBeIndex(ExecState*, PropertyName, JSValue, PutPropertySlot&);
716
717     // Fast access to known property offsets.
718     ALWAYS_INLINE JSValue getDirect(PropertyOffset offset) const { return locationForOffset(offset)->get(); }
719     JSValue getDirectConcurrently(Structure* expectedStructure, PropertyOffset) const;
720     void putDirect(VM& vm, PropertyOffset offset, JSValue value) { locationForOffset(offset)->set(vm, this, value); }
721     void putDirectWithoutBarrier(PropertyOffset offset, JSValue value) { locationForOffset(offset)->setWithoutWriteBarrier(value); }
722     void putDirectUndefined(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); }
723
724     JS_EXPORT_PRIVATE bool putDirectNativeIntrinsicGetter(VM&, JSGlobalObject*, Identifier, NativeFunction, Intrinsic, unsigned attributes);
725     JS_EXPORT_PRIVATE bool putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
726     JS_EXPORT_PRIVATE bool putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, const DOMJIT::Signature*, unsigned attributes);
727     JS_EXPORT_PRIVATE void putDirectNativeFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
728
729     JS_EXPORT_PRIVATE JSFunction* putDirectBuiltinFunction(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
730     JSFunction* putDirectBuiltinFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
731
732     JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
733
734     bool isEnvironment() const;
735     bool isGlobalObject() const;
736     bool isJSLexicalEnvironment() const;
737     bool isGlobalLexicalEnvironment() const;
738     bool isStrictEvalActivation() const;
739     bool isWithScope() const;
740
741     bool isErrorInstance() const;
742
743     JS_EXPORT_PRIVATE void seal(VM&);
744     JS_EXPORT_PRIVATE void freeze(VM&);
745     JS_EXPORT_PRIVATE static bool preventExtensions(JSObject*, ExecState*);
746     JS_EXPORT_PRIVATE static bool isExtensible(JSObject*, ExecState*);
747     bool isSealed(VM& vm) { return structure(vm)->isSealed(vm); }
748     bool isFrozen(VM& vm) { return structure(vm)->isFrozen(vm); }
749
750     bool anyObjectInChainMayInterceptIndexedAccesses(VM&) const;
751     JS_EXPORT_PRIVATE bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
752     bool needsSlowPutIndexing(VM&) const;
753
754 private:
755     NonPropertyTransition suggestedArrayStorageTransition(VM&) const;
756     ALWAYS_INLINE bool isExtensibleImpl(VM& vm) { return isStructureExtensible(vm); }
757 public:
758     // You should only call isStructureExtensible() when:
759     // - Performing this check in a way that isn't described in the specification 
760     //   as calling the virtual [[IsExtensible]] trap.
761     // - When you're guaranteed that object->methodTable(vm)->isExtensible isn't
762     //   overridden.
763     ALWAYS_INLINE bool isStructureExtensible(VM& vm) { return structure(vm)->isStructureExtensible(); }
764     // You should call this when performing [[IsExtensible]] trap in a place
765     // that is described in the specification. This performs the fully virtual
766     // [[IsExtensible]] trap.
767     bool isExtensible(ExecState*);
768     bool indexingShouldBeSparse(VM& vm)
769     {
770         return !isStructureExtensible(vm)
771             || structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero();
772     }
773
774     bool staticPropertiesReified(VM& vm) { return structure(vm)->staticPropertiesReified(); }
775     void reifyAllStaticProperties(ExecState*);
776
777     JS_EXPORT_PRIVATE Butterfly* allocateMoreOutOfLineStorage(VM&, size_t oldSize, size_t newSize);
778
779     // Call this when you do not need to change the structure.
780     void setButterfly(VM&, Butterfly*);
781     
782     // Call this if you do need to change the structure, or if you changed something about a structure
783     // in-place.
784     void nukeStructureAndSetButterfly(VM&, StructureID oldStructureID, Butterfly*);
785
786     void setStructure(VM&, Structure*);
787
788     JS_EXPORT_PRIVATE void convertToDictionary(VM&);
789
790     void flattenDictionaryObject(VM& vm)
791     {
792         structure(vm)->flattenDictionaryStructure(vm, this);
793     }
794     void shiftButterflyAfterFlattening(const GCSafeConcurrentJSLocker&, VM&, Structure* structure, size_t outOfLineCapacityAfter);
795
796     JSGlobalObject* globalObject() const
797     {
798         ASSERT(structure()->globalObject());
799         ASSERT(!isGlobalObject() || ((JSObject*)structure()->globalObject()) == this);
800         return structure()->globalObject();
801     }
802         
803     JSGlobalObject* globalObject(VM& vm) const
804     {
805         ASSERT(structure(vm)->globalObject());
806         ASSERT(!isGlobalObject() || ((JSObject*)structure(vm)->globalObject()) == this);
807         return structure(vm)->globalObject();
808     }
809         
810     void switchToSlowPutArrayStorage(VM&);
811         
812     // The receiver is the prototype in this case. The following:
813     //
814     // asObject(foo->structure()->storedPrototype())->attemptToInterceptPutByIndexOnHoleForPrototype(...)
815     //
816     // is equivalent to:
817     //
818     // foo->attemptToInterceptPutByIndexOnHole(...);
819     bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow, bool& putResult);
820         
821     // Returns 0 if int32 storage cannot be created - either because
822     // indexing should be sparse, we're having a bad time, or because
823     // we already have a more general form of storage (double,
824     // contiguous, array storage).
825     ContiguousJSValues tryMakeWritableInt32(VM& vm)
826     {
827         if (LIKELY(hasInt32(indexingType()) && !isCopyOnWrite(indexingMode())))
828             return m_butterfly->contiguousInt32();
829             
830         return tryMakeWritableInt32Slow(vm);
831     }
832         
833     // Returns 0 if double storage cannot be created - either because
834     // indexing should be sparse, we're having a bad time, or because
835     // we already have a more general form of storage (contiguous,
836     // or array storage).
837     ContiguousDoubles tryMakeWritableDouble(VM& vm)
838     {
839         if (LIKELY(hasDouble(indexingType()) && !isCopyOnWrite(indexingMode())))
840             return m_butterfly->contiguousDouble();
841             
842         return tryMakeWritableDoubleSlow(vm);
843     }
844         
845     // Returns 0 if contiguous storage cannot be created - either because
846     // indexing should be sparse or because we're having a bad time.
847     ContiguousJSValues tryMakeWritableContiguous(VM& vm)
848     {
849         if (LIKELY(hasContiguous(indexingType()) && !isCopyOnWrite(indexingMode())))
850             return m_butterfly->contiguous();
851             
852         return tryMakeWritableContiguousSlow(vm);
853     }
854
855     // Ensure that the object is in a mode where it has array storage. Use
856     // this if you're about to perform actions that would have required the
857     // object to be converted to have array storage, if it didn't have it
858     // already.
859     ArrayStorage* ensureArrayStorage(VM& vm)
860     {
861         if (LIKELY(hasAnyArrayStorage(indexingType())))
862             return m_butterfly->arrayStorage();
863
864         return ensureArrayStorageSlow(vm);
865     }
866
867     void ensureWritable(VM& vm)
868     {
869         if (isCopyOnWrite(indexingMode()))
870             convertFromCopyOnWrite(vm);
871     }
872         
873     static size_t offsetOfInlineStorage();
874         
875     static ptrdiff_t butterflyOffset()
876     {
877         return OBJECT_OFFSETOF(JSObject, m_butterfly);
878     }
879     void* butterflyAddress()
880     {
881         return &m_butterfly;
882     }
883
884     JS_EXPORT_PRIVATE JSValue getMethod(ExecState*, CallData&, CallType&, const Identifier&, const String& errorMessage);
885
886     bool canPerformFastPutInline(VM&, PropertyName);
887     bool canPerformFastPutInlineExcludingProto(VM&);
888
889     DECLARE_EXPORT_INFO;
890
891 protected:
892     void finishCreation(VM& vm)
893     {
894         Base::finishCreation(vm);
895         ASSERT(jsDynamicCast<JSObject*>(vm, this));
896         ASSERT(structure(vm)->hasPolyProto() || getPrototypeDirect(vm).isNull() || Heap::heap(this) == Heap::heap(getPrototypeDirect(vm)));
897         ASSERT(structure(vm)->isObject());
898         ASSERT(classInfo(vm));
899     }
900
901     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
902     {
903         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
904     }
905
906     // To instantiate objects you likely want JSFinalObject, below.
907     // To create derived types you likely want JSNonFinalObject, below.
908     JSObject(VM&, Structure*, Butterfly* = nullptr);
909     
910     // Visits the butterfly unless there is a race. Returns the structure if there was no race.
911     Structure* visitButterfly(SlotVisitor&);
912     
913     Structure* visitButterflyImpl(SlotVisitor&);
914     
915     void markAuxiliaryAndVisitOutOfLineProperties(SlotVisitor&, Butterfly*, Structure*, PropertyOffset lastOffset);
916
917     // Call this if you know that the object is in a mode where it has array
918     // storage. This will assert otherwise.
919     ArrayStorage* arrayStorage()
920     {
921         ASSERT(hasAnyArrayStorage(indexingType()));
922         return m_butterfly->arrayStorage();
923     }
924         
925     // Call this if you want to predicate some actions on whether or not the
926     // object is in a mode where it has array storage.
927     ArrayStorage* arrayStorageOrNull()
928     {
929         switch (indexingType()) {
930         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
931             return m_butterfly->arrayStorage();
932                 
933         default:
934             return 0;
935         }
936     }
937         
938     size_t butterflyTotalSize();
939     size_t butterflyPreCapacity();
940
941     Butterfly* createInitialUndecided(VM&, unsigned length);
942     ContiguousJSValues createInitialInt32(VM&, unsigned length);
943     ContiguousDoubles createInitialDouble(VM&, unsigned length);
944     ContiguousJSValues createInitialContiguous(VM&, unsigned length);
945
946     void convertUndecidedForValue(VM&, JSValue);
947     void createInitialForValueAndSet(VM&, unsigned index, JSValue);
948     void convertInt32ForValue(VM&, JSValue);
949     void convertDoubleForValue(VM&, JSValue);
950     void convertFromCopyOnWrite(VM&);
951
952     static Butterfly* createArrayStorageButterfly(VM&, JSObject* intendedOwner, Structure*, unsigned length, unsigned vectorLength, Butterfly* oldButterfly = nullptr);
953     ArrayStorage* createArrayStorage(VM&, unsigned length, unsigned vectorLength);
954     ArrayStorage* createInitialArrayStorage(VM&);
955         
956     ContiguousJSValues convertUndecidedToInt32(VM&);
957     ContiguousDoubles convertUndecidedToDouble(VM&);
958     ContiguousJSValues convertUndecidedToContiguous(VM&);
959     ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition);
960     ArrayStorage* convertUndecidedToArrayStorage(VM&);
961         
962     ContiguousDoubles convertInt32ToDouble(VM&);
963     ContiguousJSValues convertInt32ToContiguous(VM&);
964     ArrayStorage* convertInt32ToArrayStorage(VM&, NonPropertyTransition);
965     ArrayStorage* convertInt32ToArrayStorage(VM&);
966
967     ContiguousJSValues convertDoubleToContiguous(VM&);
968     ArrayStorage* convertDoubleToArrayStorage(VM&, NonPropertyTransition);
969     ArrayStorage* convertDoubleToArrayStorage(VM&);
970         
971     ArrayStorage* convertContiguousToArrayStorage(VM&, NonPropertyTransition);
972     ArrayStorage* convertContiguousToArrayStorage(VM&);
973
974         
975     ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM&);
976         
977     bool defineOwnNonIndexProperty(ExecState*, PropertyName, const PropertyDescriptor&, bool throwException);
978
979     template<IndexingType indexingShape>
980     bool putByIndexBeyondVectorLengthWithoutAttributes(ExecState*, unsigned propertyName, JSValue);
981     bool putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*);
982
983     bool increaseVectorLength(VM&, unsigned newLength);
984     void deallocateSparseIndexMap();
985     bool defineOwnIndexedProperty(ExecState*, unsigned, const PropertyDescriptor&, bool throwException);
986     SparseArrayValueMap* allocateSparseIndexMap(VM&);
987         
988     void notifyPresenceOfIndexedAccessors(VM&);
989         
990     bool attemptToInterceptPutByIndexOnHole(ExecState*, unsigned index, JSValue, bool shouldThrow, bool& putResult);
991         
992     // Call this if you want setIndexQuickly to succeed and you're sure that
993     // the array is contiguous.
994     bool WARN_UNUSED_RETURN ensureLength(VM& vm, unsigned length)
995     {
996         RELEASE_ASSERT(length <= MAX_STORAGE_VECTOR_LENGTH);
997         ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
998
999         if (m_butterfly->vectorLength() < length || isCopyOnWrite(indexingMode())) {
1000             if (!ensureLengthSlow(vm, length))
1001                 return false;
1002         }
1003             
1004         if (m_butterfly->publicLength() < length)
1005             m_butterfly->setPublicLength(length);
1006         return true;
1007     }
1008         
1009     // Call this if you want to shrink the butterfly backing store, and you're
1010     // sure that the array is contiguous.
1011     void reallocateAndShrinkButterfly(VM&, unsigned length);
1012     
1013     template<IndexingType indexingShape>
1014     unsigned countElements(Butterfly*);
1015         
1016     // This is relevant to undecided, int32, double, and contiguous.
1017     unsigned countElements();
1018         
1019 private:
1020     friend class LLIntOffsetsExtractor;
1021     friend class VMInspector;
1022
1023     // Nobody should ever ask any of these questions on something already known to be a JSObject.
1024     using JSCell::isAPIValueWrapper;
1025     using JSCell::isGetterSetter;
1026     void getObject();
1027     void getString(ExecState* exec);
1028     void isObject();
1029     void isString();
1030         
1031     Butterfly* createInitialIndexedStorage(VM&, unsigned length);
1032         
1033     ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM&, ArrayStorage*);
1034         
1035     template<PutMode>
1036     bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&);
1037
1038     JS_EXPORT_PRIVATE NEVER_INLINE bool putInlineSlow(ExecState*, PropertyName, JSValue, PutPropertySlot&);
1039
1040     bool getNonIndexPropertySlot(ExecState*, PropertyName, PropertySlot&);
1041     bool getOwnNonIndexPropertySlot(VM&, Structure*, PropertyName, PropertySlot&);
1042     JS_EXPORT_PRIVATE void fillGetterPropertySlot(VM&, PropertySlot&, JSCell*, unsigned, PropertyOffset);
1043     void fillCustomGetterPropertySlot(VM&, PropertySlot&, CustomGetterSetter*, unsigned, Structure*);
1044
1045     JS_EXPORT_PRIVATE bool getOwnStaticPropertySlot(VM&, PropertyName, PropertySlot&);
1046     struct PropertyHashEntry {
1047         const HashTable* table;
1048         const HashTableValue* value;
1049     };
1050     std::optional<PropertyHashEntry> findPropertyHashEntry(VM&, PropertyName) const;
1051         
1052     bool putByIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
1053     bool putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode, ArrayStorage*);
1054     JS_EXPORT_PRIVATE bool putDirectIndexSlowOrBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode);
1055         
1056     unsigned getNewVectorLength(VM&, unsigned indexBias, unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength);
1057     unsigned getNewVectorLength(VM&, unsigned desiredLength);
1058
1059     ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(VM&, unsigned neededLength);
1060         
1061     JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(VM&, unsigned index, JSValue);
1062     JS_EXPORT_PRIVATE void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM&, unsigned index, JSValue);
1063     JS_EXPORT_PRIVATE void convertDoubleToContiguousWhilePerformingSetIndex(VM&, unsigned index, JSValue);
1064         
1065     bool ensureLengthSlow(VM&, unsigned length);
1066         
1067     ContiguousJSValues tryMakeWritableInt32Slow(VM&);
1068     ContiguousDoubles tryMakeWritableDoubleSlow(VM&);
1069     ContiguousJSValues tryMakeWritableContiguousSlow(VM&);
1070     JS_EXPORT_PRIVATE ArrayStorage* ensureArrayStorageSlow(VM&);
1071
1072     PropertyOffset prepareToPutDirectWithoutTransition(VM&, PropertyName, unsigned attributes, StructureID, Structure*);
1073
1074     AuxiliaryBarrier<Butterfly*> m_butterfly;
1075 #if CPU(ADDRESS32)
1076     unsigned m_32BitPadding;
1077 #endif
1078 };
1079
1080 // JSNonFinalObject is a type of JSObject that has some internal storage,
1081 // but also preserves some space in the collector cell for additional
1082 // data members in derived types.
1083 class JSNonFinalObject : public JSObject {
1084     friend class JSObject;
1085
1086 public:
1087     typedef JSObject Base;
1088
1089     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
1090     {
1091         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
1092     }
1093
1094 protected:
1095     explicit JSNonFinalObject(VM& vm, Structure* structure, Butterfly* butterfly = 0)
1096         : JSObject(vm, structure, butterfly)
1097     {
1098     }
1099
1100     void finishCreation(VM& vm)
1101     {
1102         Base::finishCreation(vm);
1103         ASSERT(!this->structure(vm)->hasInlineStorage());
1104         ASSERT(classInfo(vm));
1105     }
1106 };
1107
1108 class JSFinalObject;
1109
1110 // JSFinalObject is a type of JSObject that contains sufficient internal
1111 // storage to fully make use of the collector cell containing it.
1112 class JSFinalObject final : public JSObject {
1113     friend class JSObject;
1114
1115 public:
1116     typedef JSObject Base;
1117     static const unsigned StructureFlags = Base::StructureFlags;
1118
1119     static size_t allocationSize(Checked<size_t> inlineCapacity)
1120     {
1121         return (sizeof(JSObject) + inlineCapacity * sizeof(WriteBarrierBase<Unknown>)).unsafeGet();
1122     }
1123
1124     static inline const TypeInfo typeInfo() { return TypeInfo(FinalObjectType, StructureFlags); }
1125     static const IndexingType defaultIndexingType = NonArray;
1126         
1127     static const unsigned defaultSize = 64;
1128     static inline unsigned defaultInlineCapacity()
1129     {
1130         return (defaultSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>);
1131     }
1132
1133     static const unsigned maxSize = 512;
1134     static inline unsigned maxInlineCapacity()
1135     {
1136         return (maxSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>);
1137     }
1138
1139     static JSFinalObject* create(ExecState*, Structure*, Butterfly* = nullptr);
1140     static JSFinalObject* create(VM&, Structure*);
1141     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, unsigned inlineCapacity)
1142     {
1143         return Structure::create(vm, globalObject, prototype, typeInfo(), info(), defaultIndexingType, inlineCapacity);
1144     }
1145
1146     JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
1147
1148     DECLARE_EXPORT_INFO;
1149
1150 protected:
1151     void visitChildrenCommon(SlotVisitor&);
1152         
1153     void finishCreation(VM& vm)
1154     {
1155         Base::finishCreation(vm);
1156         ASSERT(structure(vm)->totalStorageCapacity() == structure(vm)->inlineCapacity());
1157         ASSERT(classInfo(vm));
1158     }
1159
1160 private:
1161     friend class LLIntOffsetsExtractor;
1162
1163     explicit JSFinalObject(VM& vm, Structure* structure, Butterfly* butterfly = nullptr)
1164         : JSObject(vm, structure, butterfly)
1165     {
1166         memset(inlineStorageUnsafe(), 0, structure->inlineCapacity() * sizeof(EncodedJSValue));
1167     }
1168 };
1169
1170 JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL objectPrivateFuncInstanceOf(ExecState*);
1171
1172 inline JSObject* JSObject::createRawObject(
1173     ExecState* exec, Structure* structure, Butterfly* butterfly)
1174 {
1175     VM& vm = exec->vm();
1176     JSObject* finalObject = new (
1177         NotNull, 
1178         allocateCell<JSFinalObject>(
1179             vm.heap,
1180             JSFinalObject::allocationSize(structure->inlineCapacity())
1181         )
1182     ) JSObject(vm, structure, butterfly);
1183     finalObject->finishCreation(vm);
1184     return finalObject;
1185 }
1186
1187 inline JSFinalObject* JSFinalObject::create(
1188     ExecState* exec, Structure* structure, Butterfly* butterfly)
1189 {
1190     VM& vm = exec->vm();
1191     JSFinalObject* finalObject = new (
1192         NotNull, 
1193         allocateCell<JSFinalObject>(
1194             vm.heap,
1195             allocationSize(structure->inlineCapacity())
1196         )
1197     ) JSFinalObject(vm, structure, butterfly);
1198     finalObject->finishCreation(vm);
1199     return finalObject;
1200 }
1201
1202 inline JSFinalObject* JSFinalObject::create(VM& vm, Structure* structure)
1203 {
1204     JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(vm.heap, allocationSize(structure->inlineCapacity()))) JSFinalObject(vm, structure);
1205     finalObject->finishCreation(vm);
1206     return finalObject;
1207 }
1208
1209 inline size_t JSObject::offsetOfInlineStorage()
1210 {
1211     return sizeof(JSObject);
1212 }
1213
1214 inline bool JSObject::isGlobalObject() const
1215 {
1216     return type() == GlobalObjectType;
1217 }
1218
1219 inline bool JSObject::isJSLexicalEnvironment() const
1220 {
1221     return type() == LexicalEnvironmentType || type() == ModuleEnvironmentType;
1222 }
1223
1224 inline bool JSObject::isGlobalLexicalEnvironment() const
1225 {
1226     return type() == GlobalLexicalEnvironmentType;
1227 }
1228
1229 inline bool JSObject::isStrictEvalActivation() const
1230 {
1231     return type() == StrictEvalActivationType;
1232 }
1233
1234 inline bool JSObject::isEnvironment() const
1235 {
1236     bool result = GlobalObjectType <= type() && type() <= StrictEvalActivationType;
1237     ASSERT((isGlobalObject() || isJSLexicalEnvironment() || isGlobalLexicalEnvironment() || isStrictEvalActivation()) == result);
1238     return result;
1239 }
1240
1241 inline bool JSObject::isErrorInstance() const
1242 {
1243     return type() == ErrorInstanceType;
1244 }
1245
1246 inline bool JSObject::isWithScope() const
1247 {
1248     return type() == WithScopeType;
1249 }
1250
1251 inline void JSObject::setStructure(VM& vm, Structure* structure)
1252 {
1253     ASSERT(structure);
1254     ASSERT(!m_butterfly == !(structure->outOfLineCapacity() || structure->hasIndexingHeader(this)));
1255     JSCell::setStructure(vm, structure);
1256 }
1257
1258 inline void JSObject::setButterfly(VM& vm, Butterfly* butterfly)
1259 {
1260     if (isX86() || vm.heap.mutatorShouldBeFenced()) {
1261         WTF::storeStoreFence();
1262         m_butterfly.set(vm, this, butterfly);
1263         WTF::storeStoreFence();
1264         return;
1265     }
1266
1267     m_butterfly.set(vm, this, butterfly);
1268 }
1269
1270 inline void JSObject::nukeStructureAndSetButterfly(VM& vm, StructureID oldStructureID, Butterfly* butterfly)
1271 {
1272     if (isX86() || vm.heap.mutatorShouldBeFenced()) {
1273         setStructureIDDirectly(nuke(oldStructureID));
1274         WTF::storeStoreFence();
1275         m_butterfly.set(vm, this, butterfly);
1276         WTF::storeStoreFence();
1277         return;
1278     }
1279
1280     m_butterfly.set(vm, this, butterfly);
1281 }
1282
1283 inline CallType getCallData(VM& vm, JSValue value, CallData& callData)
1284 {
1285     CallType result = value.isCell() ? value.asCell()->methodTable(vm)->getCallData(value.asCell(), callData) : CallType::None;
1286     ASSERT(result == CallType::None || value.isValidCallee());
1287     return result;
1288 }
1289
1290 inline ConstructType getConstructData(VM& vm, JSValue value, ConstructData& constructData)
1291 {
1292     ConstructType result = value.isCell() ? value.asCell()->methodTable(vm)->getConstructData(value.asCell(), constructData) : ConstructType::None;
1293     ASSERT(result == ConstructType::None || value.isValidCallee());
1294     return result;
1295 }
1296
1297 inline JSObject* asObject(JSCell* cell)
1298 {
1299     ASSERT(cell->isObject());
1300     return jsCast<JSObject*>(cell);
1301 }
1302
1303 inline JSObject* asObject(JSValue value)
1304 {
1305     return asObject(value.asCell());
1306 }
1307
1308 inline JSObject::JSObject(VM& vm, Structure* structure, Butterfly* butterfly)
1309     : JSCell(vm, structure)
1310     , m_butterfly(vm, this, butterfly)
1311 {
1312 }
1313
1314 inline JSValue JSObject::getPrototypeDirect(VM& vm) const
1315 {
1316     return structure(vm)->storedPrototype(this);
1317 }
1318
1319 inline JSValue JSObject::getPrototype(VM& vm, ExecState* exec)
1320 {
1321     auto getPrototypeMethod = methodTable(vm)->getPrototype;
1322     MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
1323     if (LIKELY(getPrototypeMethod == defaultGetPrototype))
1324         return getPrototypeDirect(vm);
1325     return getPrototypeMethod(this, exec);
1326 }
1327
1328 // Normally, we never shrink the butterfly so if we know an offset is valid for some
1329 // past structure then it should be valid for any new structure. However, we may sometimes
1330 // shrink the butterfly when we are holding the Structure's ConcurrentJSLock, such as when we
1331 // flatten an object.
1332 inline JSValue JSObject::getDirectConcurrently(Structure* structure, PropertyOffset offset) const
1333 {
1334     ConcurrentJSLocker locker(structure->lock());
1335     if (!structure->isValidOffset(offset))
1336         return { };
1337     return getDirect(offset);
1338 }
1339
1340 // It is safe to call this method with a PropertyName that is actually an index,
1341 // but if so will always return false (doesn't search index storage).
1342 ALWAYS_INLINE bool JSObject::getOwnNonIndexPropertySlot(VM& vm, Structure* structure, PropertyName propertyName, PropertySlot& slot)
1343 {
1344     unsigned attributes;
1345     PropertyOffset offset = structure->get(vm, propertyName, attributes);
1346     if (!isValidOffset(offset)) {
1347         if (!TypeInfo::hasStaticPropertyTable(inlineTypeFlags()))
1348             return false;
1349         return getOwnStaticPropertySlot(vm, propertyName, slot);
1350     }
1351     
1352     // getPropertySlot relies on this method never returning index properties!
1353     ASSERT(!parseIndex(propertyName));
1354
1355     JSValue value = getDirect(offset);
1356     if (value.isCell()) {
1357         ASSERT(value);
1358         JSCell* cell = value.asCell();
1359         JSType type = cell->type();
1360         switch (type) {
1361         case GetterSetterType:
1362             fillGetterPropertySlot(vm, slot, cell, attributes, offset);
1363             return true;
1364         case CustomGetterSetterType:
1365             fillCustomGetterPropertySlot(vm, slot, jsCast<CustomGetterSetter*>(cell), attributes, structure);
1366             return true;
1367         default:
1368             break;
1369         }
1370     }
1371     
1372     slot.setValue(this, attributes, value, offset);
1373     return true;
1374 }
1375
1376 ALWAYS_INLINE void JSObject::fillCustomGetterPropertySlot(VM& vm, PropertySlot& slot, CustomGetterSetter* customGetterSetter, unsigned attributes, Structure* structure)
1377 {
1378     ASSERT(attributes & PropertyAttribute::CustomAccessorOrValue);
1379     if (customGetterSetter->inherits<DOMAttributeGetterSetter>(vm)) {
1380         auto* domAttribute = jsCast<DOMAttributeGetterSetter*>(customGetterSetter);
1381         if (structure->isUncacheableDictionary())
1382             slot.setCustom(this, attributes, domAttribute->getter(), domAttribute->domAttribute());
1383         else
1384             slot.setCacheableCustom(this, attributes, domAttribute->getter(), domAttribute->domAttribute());
1385         return;
1386     }
1387
1388     if (structure->isUncacheableDictionary())
1389         slot.setCustom(this, attributes, customGetterSetter->getter());
1390     else
1391         slot.setCacheableCustom(this, attributes, customGetterSetter->getter());
1392 }
1393
1394 // It may seem crazy to inline a function this large, especially a virtual function,
1395 // but it makes a big difference to property lookup that derived classes can inline their
1396 // base class call to this.
1397 ALWAYS_INLINE bool JSObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1398 {
1399     VM& vm = exec->vm();
1400     Structure* structure = object->structure(vm);
1401     if (object->getOwnNonIndexPropertySlot(vm, structure, propertyName, slot))
1402         return true;
1403     if (std::optional<uint32_t> index = parseIndex(propertyName))
1404         return getOwnPropertySlotByIndex(object, exec, index.value(), slot);
1405     return false;
1406 }
1407
1408 // It may seem crazy to inline a function this large but it makes a big difference
1409 // since this is function very hot in variable lookup
1410 template<bool checkNullStructure>
1411 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1412 {
1413     VM& vm = exec->vm();
1414     auto& structureIDTable = vm.heap.structureIDTable();
1415     JSObject* object = this;
1416     while (true) {
1417         if (UNLIKELY(TypeInfo::overridesGetOwnPropertySlot(object->inlineTypeFlags()))) {
1418             // If propertyName is an index then we may have missed it (as this loop is using
1419             // getOwnNonIndexPropertySlot), so we cannot safely call the overridden getOwnPropertySlot
1420             // (lest we return a property from a prototype that is shadowed). Check now for an index,
1421             // if so we need to start afresh from this object.
1422             if (std::optional<uint32_t> index = parseIndex(propertyName))
1423                 return getPropertySlot(exec, index.value(), slot);
1424             // Safe to continue searching from current position; call getNonIndexPropertySlot to avoid
1425             // parsing the int again.
1426             return object->getNonIndexPropertySlot(exec, propertyName, slot);
1427         }
1428         ASSERT(object->type() != ProxyObjectType);
1429         Structure* structure = structureIDTable.get(object->structureID());
1430 #if USE(JSVALUE64)
1431         if (checkNullStructure && UNLIKELY(!structure))
1432             CRASH_WITH_INFO(object->type(), object->structureID(), structureIDTable.size());
1433 #endif
1434         if (object->getOwnNonIndexPropertySlot(vm, structure, propertyName, slot))
1435             return true;
1436         // FIXME: This doesn't look like it's following the specification:
1437         // https://bugs.webkit.org/show_bug.cgi?id=172572
1438         JSValue prototype = structure->storedPrototype(object);
1439         if (!prototype.isObject())
1440             break;
1441         object = asObject(prototype);
1442     }
1443
1444     if (std::optional<uint32_t> index = parseIndex(propertyName))
1445         return getPropertySlot(exec, index.value(), slot);
1446     return false;
1447 }
1448
1449 inline JSValue JSObject::get(ExecState* exec, PropertyName propertyName) const
1450 {
1451     VM& vm = exec->vm();
1452     auto scope = DECLARE_THROW_SCOPE(vm);
1453     PropertySlot slot(this, PropertySlot::InternalMethodType::Get);
1454     bool hasProperty = const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
1455     EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
1456     if (hasProperty)
1457         RELEASE_AND_RETURN(scope, slot.getValue(exec, propertyName));
1458
1459     return jsUndefined();
1460 }
1461
1462 inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
1463 {
1464     VM& vm = exec->vm();
1465     auto scope = DECLARE_THROW_SCOPE(vm);
1466     PropertySlot slot(this, PropertySlot::InternalMethodType::Get);
1467     bool hasProperty = const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
1468     EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
1469     if (hasProperty)
1470         RELEASE_AND_RETURN(scope, slot.getValue(exec, propertyName));
1471
1472     return jsUndefined();
1473 }
1474
1475 inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
1476 {
1477     ASSERT(value);
1478     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
1479     ASSERT(!structure(vm)->hasGetterSetterProperties());
1480     ASSERT(!structure(vm)->hasCustomGetterSetterProperties());
1481
1482     return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot);
1483 }
1484
1485 inline bool JSObject::putOwnDataPropertyMayBeIndex(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
1486 {
1487     VM& vm = exec->vm();
1488     ASSERT(value);
1489     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
1490     ASSERT(!structure(vm)->hasGetterSetterProperties());
1491     ASSERT(!structure(vm)->hasCustomGetterSetterProperties());
1492
1493     if (std::optional<uint32_t> index = parseIndex(propertyName))
1494         return putDirectIndex(exec, index.value(), value, 0, PutDirectIndexLikePutDirect);
1495
1496     return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot);
1497 }
1498
1499 inline bool JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
1500 {
1501     ASSERT(!value.isGetterSetter() && !(attributes & PropertyAttribute::Accessor));
1502     ASSERT(!value.isCustomGetterSetter() && !(attributes & PropertyAttribute::CustomAccessorOrValue));
1503     PutPropertySlot slot(this);
1504     return putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
1505 }
1506
1507 inline bool JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
1508 {
1509     ASSERT(!value.isGetterSetter());
1510     ASSERT(!value.isCustomGetterSetter());
1511     return putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot);
1512 }
1513
1514 ALWAYS_INLINE JSObject* Register::object() const
1515 {
1516     return asObject(jsValue());
1517 }
1518
1519 ALWAYS_INLINE Register& Register::operator=(JSObject* object)
1520 {
1521     u.value = JSValue::encode(JSValue(object));
1522     return *this;
1523 }
1524
1525 inline size_t offsetInButterfly(PropertyOffset offset)
1526 {
1527     return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
1528 }
1529
1530 inline size_t JSObject::butterflyPreCapacity()
1531 {
1532     VM& vm = *this->vm();
1533     if (UNLIKELY(hasIndexingHeader(vm)))
1534         return butterfly()->indexingHeader()->preCapacity(structure(vm));
1535     return 0;
1536 }
1537
1538 inline size_t JSObject::butterflyTotalSize()
1539 {
1540     VM& vm = *this->vm();
1541     Structure* structure = this->structure(vm);
1542     Butterfly* butterfly = this->butterfly();
1543     size_t preCapacity;
1544     size_t indexingPayloadSizeInBytes;
1545     bool hasIndexingHeader = this->hasIndexingHeader(vm);
1546
1547     if (UNLIKELY(hasIndexingHeader)) {
1548         preCapacity = butterfly->indexingHeader()->preCapacity(structure);
1549         indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
1550     } else {
1551         preCapacity = 0;
1552         indexingPayloadSizeInBytes = 0;
1553     }
1554
1555     return Butterfly::totalSize(preCapacity, structure->outOfLineCapacity(), hasIndexingHeader, indexingPayloadSizeInBytes);
1556 }
1557
1558 inline int indexRelativeToBase(PropertyOffset offset)
1559 {
1560     if (isOutOfLineOffset(offset))
1561         return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
1562     ASSERT(!(JSObject::offsetOfInlineStorage() % sizeof(EncodedJSValue)));
1563     return JSObject::offsetOfInlineStorage() / sizeof(EncodedJSValue) + offsetInInlineStorage(offset);
1564 }
1565
1566 inline int offsetRelativeToBase(PropertyOffset offset)
1567 {
1568     if (isOutOfLineOffset(offset))
1569         return offsetInOutOfLineStorage(offset) * sizeof(EncodedJSValue) + Butterfly::offsetOfPropertyStorage();
1570     return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset) * sizeof(EncodedJSValue);
1571 }
1572
1573 // Returns the maximum offset (away from zero) a load instruction will encode.
1574 inline size_t maxOffsetRelativeToBase(PropertyOffset offset)
1575 {
1576     ptrdiff_t addressOffset = offsetRelativeToBase(offset);
1577 #if USE(JSVALUE32_64)
1578     if (addressOffset >= 0)
1579         return static_cast<size_t>(addressOffset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag);
1580 #endif
1581     return static_cast<size_t>(addressOffset);
1582 }
1583
1584 COMPILE_ASSERT(!(sizeof(JSObject) % sizeof(WriteBarrierBase<Unknown>)), JSObject_inline_storage_has_correct_alignment);
1585
1586 template<unsigned charactersCount>
1587 ALWAYS_INLINE Identifier makeIdentifier(VM& vm, const char (&characters)[charactersCount])
1588 {
1589     return Identifier::fromString(&vm, characters);
1590 }
1591
1592 ALWAYS_INLINE Identifier makeIdentifier(VM& vm, const char* name)
1593 {
1594     return Identifier::fromString(&vm, name);
1595 }
1596
1597 ALWAYS_INLINE Identifier makeIdentifier(VM&, const Identifier& name)
1598 {
1599     return name;
1600 }
1601
1602 bool validateAndApplyPropertyDescriptor(ExecState*, JSObject*, PropertyName, bool isExtensible,
1603     const PropertyDescriptor& descriptor, bool isCurrentDefined, const PropertyDescriptor& current, bool throwException);
1604
1605 JS_EXPORT_PRIVATE NEVER_INLINE bool ordinarySetSlow(ExecState*, JSObject*, PropertyName, JSValue, JSValue receiver, bool shouldThrow);
1606
1607 // Helper for defining native functions, if you're not using a static hash table.
1608 // Use this macro from within finishCreation() methods in prototypes. This assumes
1609 // you've defined variables called exec, globalObject, and vm, and they
1610 // have the expected meanings.
1611 #define JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, attributes, length, intrinsic) \
1612     putDirectNativeFunction(\
1613         vm, globalObject, makeIdentifier(vm, (jsName)), (length), cppName, \
1614         (intrinsic), (attributes))
1615
1616 #define JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(jsName, cppName, attributes, length, intrinsic) \
1617     putDirectNativeFunctionWithoutTransition(\
1618         vm, globalObject, makeIdentifier(vm, (jsName)), (length), cppName, \
1619         (intrinsic), (attributes))
1620
1621 // As above, but this assumes that the function you're defining doesn't have an
1622 // intrinsic.
1623 #define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \
1624     JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic)
1625
1626 #define JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(jsName, cppName, attributes, length) \
1627     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(jsName, cppName, (attributes), (length), NoIntrinsic)
1628
1629 // Identical helpers but for builtins. Note that currently, we don't support builtins that are
1630 // also intrinsics, but we probably will do that eventually.
1631 #define JSC_BUILTIN_FUNCTION(jsName, generatorName, attributes) \
1632     putDirectBuiltinFunction(\
1633         vm, globalObject, makeIdentifier(vm, (jsName)), (generatorName)(vm), (attributes))
1634
1635 #define JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(jsName, generatorName, attributes) \
1636     putDirectBuiltinFunctionWithoutTransition(\
1637         vm, globalObject, makeIdentifier(vm, (jsName)), (generatorName)(vm), (attributes))
1638
1639 // Helper for defining native getters on properties.
1640 #define JSC_NATIVE_INTRINSIC_GETTER(jsName, cppName, attributes, intrinsic)  \
1641     putDirectNativeIntrinsicGetter(\
1642         vm, globalObject, makeIdentifier(vm, (jsName)), (cppName), \
1643         (intrinsic), ((attributes) | PropertyAttribute::Accessor))
1644
1645 #define JSC_NATIVE_GETTER(jsName, cppName, attributes) \
1646     JSC_NATIVE_INTRINSIC_GETTER((jsName), (cppName), (attributes), NoIntrinsic)
1647
1648 } // namespace JSC