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