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