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