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