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