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