Merge r169628 from ftlopt.
[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     JS_EXPORT_PRIVATE void setPrototype(VM&, JSValue prototype);
115     JS_EXPORT_PRIVATE 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     JS_EXPORT_PRIVATE bool getOwnPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
136
137     JS_EXPORT_PRIVATE 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     JS_EXPORT_PRIVATE 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     JS_EXPORT_PRIVATE 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     JS_EXPORT_PRIVATE void seal(VM&);
607     JS_EXPORT_PRIVATE 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     void shiftButterflyAfterFlattening(VM&, size_t outOfLineCapacityBefore, size_t outOfLineCapacityAfter);
639
640     JSGlobalObject* globalObject() const
641     {
642         ASSERT(structure()->globalObject());
643         ASSERT(!isGlobalObject() || ((JSObject*)structure()->globalObject()) == this);
644         return structure()->globalObject();
645     }
646         
647     void switchToSlowPutArrayStorage(VM&);
648         
649     // The receiver is the prototype in this case. The following:
650     //
651     // asObject(foo->structure()->storedPrototype())->attemptToInterceptPutByIndexOnHoleForPrototype(...)
652     //
653     // is equivalent to:
654     //
655     // foo->attemptToInterceptPutByIndexOnHole(...);
656     bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow);
657         
658     // Returns 0 if int32 storage cannot be created - either because
659     // indexing should be sparse, we're having a bad time, or because
660     // we already have a more general form of storage (double,
661     // contiguous, array storage).
662     ContiguousJSValues ensureInt32(VM& vm)
663     {
664         if (LIKELY(hasInt32(indexingType())))
665             return m_butterfly->contiguousInt32();
666             
667         return ensureInt32Slow(vm);
668     }
669         
670     // Returns 0 if double storage cannot be created - either because
671     // indexing should be sparse, we're having a bad time, or because
672     // we already have a more general form of storage (contiguous,
673     // or array storage).
674     ContiguousDoubles ensureDouble(VM& vm)
675     {
676         if (LIKELY(hasDouble(indexingType())))
677             return m_butterfly->contiguousDouble();
678             
679         return ensureDoubleSlow(vm);
680     }
681         
682     // Returns 0 if contiguous storage cannot be created - either because
683     // indexing should be sparse or because we're having a bad time.
684     ContiguousJSValues ensureContiguous(VM& vm)
685     {
686         if (LIKELY(hasContiguous(indexingType())))
687             return m_butterfly->contiguous();
688             
689         return ensureContiguousSlow(vm);
690     }
691         
692     // Same as ensureContiguous(), except that if the indexed storage is in
693     // double mode, then it does a rage conversion to contiguous: it
694     // attempts to convert each double to an int32.
695     ContiguousJSValues rageEnsureContiguous(VM& vm)
696     {
697         if (LIKELY(hasContiguous(indexingType())))
698             return m_butterfly->contiguous();
699             
700         return rageEnsureContiguousSlow(vm);
701     }
702         
703     // Ensure that the object is in a mode where it has array storage. Use
704     // this if you're about to perform actions that would have required the
705     // object to be converted to have array storage, if it didn't have it
706     // already.
707     ArrayStorage* ensureArrayStorage(VM& vm)
708     {
709         if (LIKELY(hasAnyArrayStorage(indexingType())))
710             return m_butterfly->arrayStorage();
711
712         return ensureArrayStorageSlow(vm);
713     }
714         
715     static size_t offsetOfInlineStorage();
716         
717     static ptrdiff_t butterflyOffset()
718     {
719         return OBJECT_OFFSETOF(JSObject, m_butterfly);
720     }
721         
722     void* butterflyAddress()
723     {
724         return &m_butterfly;
725     }
726
727     DECLARE_EXPORT_INFO;
728
729 protected:
730     void finishCreation(VM& vm)
731     {
732         Base::finishCreation(vm);
733         ASSERT(inherits(info()));
734         ASSERT(!structure()->outOfLineCapacity());
735         ASSERT(structure()->isEmpty());
736         ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
737         ASSERT(structure()->isObject());
738         ASSERT(classInfo());
739     }
740
741     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
742     {
743         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
744     }
745
746     // To instantiate objects you likely want JSFinalObject, below.
747     // To create derived types you likely want JSNonFinalObject, below.
748     JSObject(VM&, Structure*, Butterfly* = 0);
749         
750     void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize);
751     void copyButterfly(CopyVisitor&, Butterfly*, size_t storageSize);
752
753     // Call this if you know that the object is in a mode where it has array
754     // storage. This will assert otherwise.
755     ArrayStorage* arrayStorage()
756     {
757         ASSERT(hasAnyArrayStorage(indexingType()));
758         return m_butterfly->arrayStorage();
759     }
760         
761     // Call this if you want to predicate some actions on whether or not the
762     // object is in a mode where it has array storage.
763     ArrayStorage* arrayStorageOrNull()
764     {
765         switch (indexingType()) {
766         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
767             return m_butterfly->arrayStorage();
768                 
769         default:
770             return 0;
771         }
772     }
773         
774     size_t butterflyTotalSize();
775     size_t butterflyPreCapacity();
776
777     Butterfly* createInitialUndecided(VM&, unsigned length);
778     ContiguousJSValues createInitialInt32(VM&, unsigned length);
779     ContiguousDoubles createInitialDouble(VM&, unsigned length);
780     ContiguousJSValues createInitialContiguous(VM&, unsigned length);
781         
782     void convertUndecidedForValue(VM&, JSValue);
783     void createInitialForValueAndSet(VM&, unsigned index, JSValue);
784     void convertInt32ForValue(VM&, JSValue);
785         
786     ArrayStorage* createArrayStorage(VM&, unsigned length, unsigned vectorLength);
787     ArrayStorage* createInitialArrayStorage(VM&);
788         
789     ContiguousJSValues convertUndecidedToInt32(VM&);
790     ContiguousDoubles convertUndecidedToDouble(VM&);
791     ContiguousJSValues convertUndecidedToContiguous(VM&);
792     ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength);
793     ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition);
794     ArrayStorage* convertUndecidedToArrayStorage(VM&);
795         
796     ContiguousDoubles convertInt32ToDouble(VM&);
797     ContiguousJSValues convertInt32ToContiguous(VM&);
798     ArrayStorage* convertInt32ToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength);
799     ArrayStorage* convertInt32ToArrayStorage(VM&, NonPropertyTransition);
800     ArrayStorage* convertInt32ToArrayStorage(VM&);
801     
802     ContiguousJSValues convertDoubleToContiguous(VM&);
803     ContiguousJSValues rageConvertDoubleToContiguous(VM&);
804     ArrayStorage* convertDoubleToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength);
805     ArrayStorage* convertDoubleToArrayStorage(VM&, NonPropertyTransition);
806     ArrayStorage* convertDoubleToArrayStorage(VM&);
807         
808     ArrayStorage* convertContiguousToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength);
809     ArrayStorage* convertContiguousToArrayStorage(VM&, NonPropertyTransition);
810     ArrayStorage* convertContiguousToArrayStorage(VM&);
811
812         
813     ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM&);
814         
815     bool defineOwnNonIndexProperty(ExecState*, PropertyName, const PropertyDescriptor&, bool throwException);
816
817     template<IndexingType indexingShape>
818     void putByIndexBeyondVectorLengthWithoutAttributes(ExecState*, unsigned propertyName, JSValue);
819     void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*);
820
821     bool increaseVectorLength(VM&, unsigned newLength);
822     void deallocateSparseIndexMap();
823     bool defineOwnIndexedProperty(ExecState*, unsigned, const PropertyDescriptor&, bool throwException);
824     SparseArrayValueMap* allocateSparseIndexMap(VM&);
825         
826     void notifyPresenceOfIndexedAccessors(VM&);
827         
828     bool attemptToInterceptPutByIndexOnHole(ExecState*, unsigned index, JSValue, bool shouldThrow);
829         
830     // Call this if you want setIndexQuickly to succeed and you're sure that
831     // the array is contiguous.
832     void ensureLength(VM& vm, unsigned length)
833     {
834         ASSERT(length < MAX_ARRAY_INDEX);
835         ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
836             
837         if (m_butterfly->vectorLength() < length)
838             ensureLengthSlow(vm, length);
839             
840         if (m_butterfly->publicLength() < length)
841             m_butterfly->setPublicLength(length);
842     }
843         
844     template<IndexingType indexingShape>
845     unsigned countElements(Butterfly*);
846         
847     // This is relevant to undecided, int32, double, and contiguous.
848     unsigned countElements();
849         
850     // This strange method returns a pointer to the start of the indexed data
851     // as if it contained JSValues. But it won't always contain JSValues.
852     // Make sure you cast this to the appropriate type before using.
853     template<IndexingType indexingType>
854     ContiguousJSValues indexingData()
855     {
856         switch (indexingType) {
857         case ALL_INT32_INDEXING_TYPES:
858         case ALL_DOUBLE_INDEXING_TYPES:
859         case ALL_CONTIGUOUS_INDEXING_TYPES:
860             return m_butterfly->contiguous();
861                 
862         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
863             return m_butterfly->arrayStorage()->vector();
864
865         default:
866             CRASH();
867             return ContiguousJSValues();
868         }
869     }
870
871     ContiguousJSValues currentIndexingData()
872     {
873         switch (indexingType()) {
874         case ALL_INT32_INDEXING_TYPES:
875         case ALL_CONTIGUOUS_INDEXING_TYPES:
876             return m_butterfly->contiguous();
877
878         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
879             return m_butterfly->arrayStorage()->vector();
880
881         default:
882             CRASH();
883             return ContiguousJSValues();
884         }
885     }
886         
887     JSValue getHolyIndexQuickly(unsigned i)
888     {
889         ASSERT(i < m_butterfly->vectorLength());
890         switch (indexingType()) {
891         case ALL_INT32_INDEXING_TYPES:
892         case ALL_CONTIGUOUS_INDEXING_TYPES:
893             return m_butterfly->contiguous()[i].get();
894         case ALL_DOUBLE_INDEXING_TYPES: {
895             double value = m_butterfly->contiguousDouble()[i];
896             if (value == value)
897                 return JSValue(JSValue::EncodeAsDouble, value);
898             return JSValue();
899         }
900         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
901             return m_butterfly->arrayStorage()->m_vector[i].get();
902         default:
903             CRASH();
904             return JSValue();
905         }
906     }
907         
908     template<IndexingType indexingType>
909     unsigned relevantLength()
910     {
911         switch (indexingType) {
912         case ALL_INT32_INDEXING_TYPES:
913         case ALL_DOUBLE_INDEXING_TYPES:
914         case ALL_CONTIGUOUS_INDEXING_TYPES:
915             return m_butterfly->publicLength();
916                 
917         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
918             return std::min(
919                 m_butterfly->arrayStorage()->length(),
920                 m_butterfly->arrayStorage()->vectorLength());
921                 
922         default:
923             CRASH();
924             return 0;
925         }
926     }
927
928     unsigned currentRelevantLength()
929     {
930         switch (indexingType()) {
931         case ALL_INT32_INDEXING_TYPES:
932         case ALL_DOUBLE_INDEXING_TYPES:
933         case ALL_CONTIGUOUS_INDEXING_TYPES:
934             return m_butterfly->publicLength();
935
936         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
937             return std::min(
938                 m_butterfly->arrayStorage()->length(),
939                 m_butterfly->arrayStorage()->vectorLength());
940
941         default:
942             CRASH();
943             return 0;
944         }
945     }
946
947 private:
948     friend class LLIntOffsetsExtractor;
949         
950     // Nobody should ever ask any of these questions on something already known to be a JSObject.
951     using JSCell::isAPIValueWrapper;
952     using JSCell::isGetterSetter;
953     void getObject();
954     void getString(ExecState* exec);
955     void isObject();
956     void isString();
957         
958     Butterfly* createInitialIndexedStorage(VM&, unsigned length, size_t elementSize);
959         
960     ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM&, ArrayStorage*);
961         
962     template<PutMode>
963     bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*);
964
965     bool inlineGetOwnPropertySlot(VM&, Structure&, PropertyName, PropertySlot&);
966     JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, JSValue, unsigned, PropertyOffset);
967     void fillCustomGetterPropertySlot(PropertySlot&, JSValue, unsigned, Structure&);
968
969     const HashTableValue* findPropertyHashEntry(VM&, PropertyName) const;
970         
971     void putIndexedDescriptor(ExecState*, SparseArrayEntry*, const PropertyDescriptor&, PropertyDescriptor& old);
972         
973     void putByIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
974     bool putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode, ArrayStorage*);
975     JS_EXPORT_PRIVATE bool putDirectIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode);
976         
977     unsigned getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength);
978     unsigned getNewVectorLength(unsigned desiredLength);
979
980     ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(VM&, unsigned neededLength);
981         
982     JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(VM&, unsigned index, JSValue);
983     JS_EXPORT_PRIVATE void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM&, unsigned index, JSValue);
984     JS_EXPORT_PRIVATE void convertDoubleToContiguousWhilePerformingSetIndex(VM&, unsigned index, JSValue);
985         
986     void ensureLengthSlow(VM&, unsigned length);
987         
988     ContiguousJSValues ensureInt32Slow(VM&);
989     ContiguousDoubles ensureDoubleSlow(VM&);
990     ContiguousJSValues ensureContiguousSlow(VM&);
991     ContiguousJSValues rageEnsureContiguousSlow(VM&);
992     JS_EXPORT_PRIVATE ArrayStorage* ensureArrayStorageSlow(VM&);
993     
994     enum DoubleToContiguousMode { EncodeValueAsDouble, RageConvertDoubleToValue };
995     template<DoubleToContiguousMode mode>
996     ContiguousJSValues genericConvertDoubleToContiguous(VM&);
997     ContiguousJSValues ensureContiguousSlow(VM&, DoubleToContiguousMode);
998     
999 protected:
1000     CopyWriteBarrier<Butterfly> m_butterfly;
1001 #if USE(JSVALUE32_64)
1002 private:
1003     uint32_t m_padding;
1004 #endif
1005 };
1006
1007 // JSNonFinalObject is a type of JSObject that has some internal storage,
1008 // but also preserves some space in the collector cell for additional
1009 // data members in derived types.
1010 class JSNonFinalObject : public JSObject {
1011     friend class JSObject;
1012
1013 public:
1014     typedef JSObject Base;
1015
1016     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
1017     {
1018         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
1019     }
1020
1021 protected:
1022     explicit JSNonFinalObject(VM& vm, Structure* structure, Butterfly* butterfly = 0)
1023         : JSObject(vm, structure, butterfly)
1024     {
1025     }
1026
1027     void finishCreation(VM& vm)
1028     {
1029         Base::finishCreation(vm);
1030         ASSERT(!this->structure()->totalStorageCapacity());
1031         ASSERT(classInfo());
1032     }
1033 };
1034
1035 class JSFinalObject;
1036
1037 // JSFinalObject is a type of JSObject that contains sufficent internal
1038 // storage to fully make use of the colloctor cell containing it.
1039 class JSFinalObject : public JSObject {
1040     friend class JSObject;
1041
1042 public:
1043     typedef JSObject Base;
1044
1045     static size_t allocationSize(size_t inlineCapacity)
1046     {
1047         return sizeof(JSObject) + inlineCapacity * sizeof(WriteBarrierBase<Unknown>);
1048     }
1049         
1050     static const unsigned defaultSize = 64;
1051     static inline unsigned defaultInlineCapacity()
1052     {
1053         return (defaultSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>);
1054     }
1055
1056     static const unsigned maxSize = 512;
1057     static inline unsigned maxInlineCapacity()
1058     {
1059         return (maxSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>);
1060     }
1061
1062     static JSFinalObject* create(ExecState*, Structure*);
1063     static JSFinalObject* create(VM&, Structure*);
1064     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, unsigned inlineCapacity)
1065     {
1066         return Structure::create(vm, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), info(), NonArray, inlineCapacity);
1067     }
1068
1069     JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
1070
1071     DECLARE_EXPORT_INFO;
1072
1073 protected:
1074     void visitChildrenCommon(SlotVisitor&);
1075         
1076     void finishCreation(VM& vm)
1077     {
1078         Base::finishCreation(vm);
1079         ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity());
1080         ASSERT(classInfo());
1081     }
1082
1083 private:
1084     friend class LLIntOffsetsExtractor;
1085
1086     explicit JSFinalObject(VM& vm, Structure* structure)
1087         : JSObject(vm, structure)
1088     {
1089     }
1090
1091     static const unsigned StructureFlags = JSObject::StructureFlags;
1092 };
1093
1094 inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structure)
1095 {
1096     JSFinalObject* finalObject = new (
1097         NotNull, 
1098         allocateCell<JSFinalObject>(
1099             *exec->heap(),
1100             allocationSize(structure->inlineCapacity())
1101         )
1102     ) JSFinalObject(exec->vm(), structure);
1103     finalObject->finishCreation(exec->vm());
1104     return finalObject;
1105 }
1106
1107 inline JSFinalObject* JSFinalObject::create(VM& vm, Structure* structure)
1108 {
1109     JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(vm.heap, allocationSize(structure->inlineCapacity()))) JSFinalObject(vm, structure);
1110     finalObject->finishCreation(vm);
1111     return finalObject;
1112 }
1113
1114 inline bool isJSFinalObject(JSCell* cell)
1115 {
1116     return cell->classInfo() == JSFinalObject::info();
1117 }
1118
1119 inline bool isJSFinalObject(JSValue value)
1120 {
1121     return value.isCell() && isJSFinalObject(value.asCell());
1122 }
1123
1124 inline size_t JSObject::offsetOfInlineStorage()
1125 {
1126     return sizeof(JSObject);
1127 }
1128
1129 inline bool JSObject::isGlobalObject() const
1130 {
1131     return type() == GlobalObjectType;
1132 }
1133
1134 inline bool JSObject::isVariableObject() const
1135 {
1136     return type() == GlobalObjectType || type() == ActivationObjectType;
1137 }
1138
1139 inline bool JSObject::isStaticScopeObject() const
1140 {
1141     JSType type = this->type();
1142     return type == NameScopeObjectType || type == ActivationObjectType;
1143 }
1144
1145
1146 inline bool JSObject::isNameScopeObject() const
1147 {
1148     return type() == NameScopeObjectType;
1149 }
1150
1151 inline bool JSObject::isActivationObject() const
1152 {
1153     return type() == ActivationObjectType;
1154 }
1155
1156 inline bool JSObject::isErrorInstance() const
1157 {
1158     return type() == ErrorInstanceType;
1159 }
1160
1161 inline void JSObject::setStructureAndButterfly(VM& vm, Structure* structure, Butterfly* butterfly)
1162 {
1163     ASSERT(structure);
1164     ASSERT(!butterfly == (!structure->outOfLineCapacity() && !structure->hasIndexingHeader(this)));
1165     m_butterfly.set(vm, this, butterfly);
1166     setStructure(vm, structure);
1167 }
1168
1169 inline void JSObject::setStructure(VM& vm, Structure* structure)
1170 {
1171     ASSERT(structure);
1172     ASSERT(!m_butterfly == !(structure->outOfLineCapacity() || structure->hasIndexingHeader(this)));
1173     JSCell::setStructure(vm, structure);
1174 }
1175
1176 inline void JSObject::setButterflyWithoutChangingStructure(VM& vm, Butterfly* butterfly)
1177 {
1178     m_butterfly.set(vm, this, butterfly);
1179 }
1180
1181 inline CallType getCallData(JSValue value, CallData& callData)
1182 {
1183     CallType result = value.isCell() ? value.asCell()->methodTable()->getCallData(value.asCell(), callData) : CallTypeNone;
1184     ASSERT(result == CallTypeNone || value.isValidCallee());
1185     return result;
1186 }
1187
1188 inline ConstructType getConstructData(JSValue value, ConstructData& constructData)
1189 {
1190     ConstructType result = value.isCell() ? value.asCell()->methodTable()->getConstructData(value.asCell(), constructData) : ConstructTypeNone;
1191     ASSERT(result == ConstructTypeNone || value.isValidCallee());
1192     return result;
1193 }
1194
1195 inline JSObject* asObject(JSCell* cell)
1196 {
1197     ASSERT(cell->isObject());
1198     return jsCast<JSObject*>(cell);
1199 }
1200
1201 inline JSObject* asObject(JSValue value)
1202 {
1203     return asObject(value.asCell());
1204 }
1205
1206 inline JSObject::JSObject(VM& vm, Structure* structure, Butterfly* butterfly)
1207     : JSCell(vm, structure)
1208     , m_butterfly(vm, this, butterfly)
1209 {
1210     vm.heap.ascribeOwner(this, butterfly);
1211 }
1212
1213 inline JSValue JSObject::prototype() const
1214 {
1215     return structure()->storedPrototype();
1216 }
1217
1218 ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(VM& vm, Structure& structure, PropertyName propertyName, PropertySlot& slot)
1219 {
1220     unsigned attributes;
1221     JSCell* specific;
1222     PropertyOffset offset = structure.get(vm, propertyName, attributes, specific);
1223     if (!isValidOffset(offset))
1224         return false;
1225
1226     JSValue value = getDirect(offset);
1227     if (structure.hasGetterSetterProperties() && value.isGetterSetter())
1228         fillGetterPropertySlot(slot, value, attributes, offset);
1229     else if (structure.hasCustomGetterSetterProperties() && value.isCustomGetterSetter())
1230         fillCustomGetterPropertySlot(slot, value, attributes, structure);
1231     else
1232         slot.setValue(this, attributes, value, offset);
1233
1234     return true;
1235 }
1236
1237 ALWAYS_INLINE void JSObject::fillCustomGetterPropertySlot(PropertySlot& slot, JSValue customGetterSetter, unsigned attributes, Structure& structure)
1238 {
1239     if (structure.isDictionary()) {
1240         slot.setCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter());
1241         return;
1242     }
1243     slot.setCacheableCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter());
1244 }
1245
1246 // It may seem crazy to inline a function this large, especially a virtual function,
1247 // but it makes a big difference to property lookup that derived classes can inline their
1248 // base class call to this.
1249 ALWAYS_INLINE bool JSObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1250 {
1251     VM& vm = exec->vm();
1252     Structure& structure = *object->structure(vm);
1253     if (object->inlineGetOwnPropertySlot(vm, structure, propertyName, slot))
1254         return true;
1255     unsigned index = propertyName.asIndex();
1256     if (index != PropertyName::NotAnIndex)
1257         return getOwnPropertySlotByIndex(object, exec, index, slot);
1258     return false;
1259 }
1260
1261 ALWAYS_INLINE bool JSObject::fastGetOwnPropertySlot(ExecState* exec, VM& vm, Structure& structure, PropertyName propertyName, PropertySlot& slot)
1262 {
1263     if (LIKELY(!TypeInfo::overridesGetOwnPropertySlot(inlineTypeFlags())))
1264         return inlineGetOwnPropertySlot(vm, structure, propertyName, slot);
1265     return structure.classInfo()->methodTable.getOwnPropertySlot(this, exec, propertyName, slot);
1266 }
1267
1268 // It may seem crazy to inline a function this large but it makes a big difference
1269 // since this is function very hot in variable lookup
1270 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1271 {
1272     VM& vm = exec->vm();
1273     auto& structureIDTable = vm.heap.structureIDTable();
1274     JSObject* object = this;
1275     while (true) {
1276         Structure& structure = *structureIDTable.get(object->structureID());
1277         if (object->fastGetOwnPropertySlot(exec, vm, structure, propertyName, slot))
1278             return true;
1279         JSValue prototype = structure.storedPrototype();
1280         if (!prototype.isObject())
1281             break;
1282         object = asObject(prototype);
1283     }
1284
1285     unsigned index = propertyName.asIndex();
1286     if (index != PropertyName::NotAnIndex)
1287         return getPropertySlot(exec, index, slot);
1288     return false;
1289 }
1290
1291 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
1292 {
1293     VM& vm = exec->vm();
1294     auto& structureIDTable = vm.heap.structureIDTable();
1295     JSObject* object = this;
1296     while (true) {
1297         Structure& structure = *structureIDTable.get(object->structureID());
1298         if (structure.classInfo()->methodTable.getOwnPropertySlotByIndex(object, exec, propertyName, slot))
1299             return true;
1300         JSValue prototype = structure.storedPrototype();
1301         if (!prototype.isObject())
1302             return false;
1303         object = asObject(prototype);
1304     }
1305 }
1306
1307 inline JSValue JSObject::get(ExecState* exec, PropertyName propertyName) const
1308 {
1309     PropertySlot slot(this);
1310     if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
1311         return slot.getValue(exec, propertyName);
1312     
1313     return jsUndefined();
1314 }
1315
1316 inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
1317 {
1318     PropertySlot slot(this);
1319     if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
1320         return slot.getValue(exec, propertyName);
1321
1322     return jsUndefined();
1323 }
1324
1325 template<JSObject::PutMode mode>
1326 inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot, JSCell* specificFunction)
1327 {
1328     ASSERT(value);
1329     ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
1330     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
1331     ASSERT(propertyName.asIndex() == PropertyName::NotAnIndex);
1332
1333     Structure* structure = this->structure(vm);
1334     if (structure->isDictionary()) {
1335         unsigned currentAttributes;
1336         JSCell* currentSpecificFunction;
1337         PropertyOffset offset = structure->get(vm, propertyName, currentAttributes, currentSpecificFunction);
1338         if (offset != invalidOffset) {
1339             // If there is currently a specific function, and there now either isn't,
1340             // or the new value is different, then despecify.
1341             if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
1342                 structure->despecifyDictionaryFunction(vm, propertyName);
1343             if ((mode == PutModePut) && currentAttributes & ReadOnly)
1344                 return false;
1345
1346             putDirect(vm, offset, value);
1347             // At this point, the objects structure only has a specific value set if previously there
1348             // had been one set, and if the new value being specified is the same (otherwise we would
1349             // have despecified, above).  So, if currentSpecificFunction is not set, or if the new
1350             // value is different (or there is no new value), then the slot now has no value - and
1351             // as such it is cachable.
1352             // If there was previously a value, and the new value is the same, then we cannot cache.
1353             if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
1354                 slot.setExistingProperty(this, offset);
1355             return true;
1356         }
1357
1358         if ((mode == PutModePut) && !isExtensible())
1359             return false;
1360
1361         DeferGC deferGC(vm.heap);
1362         Butterfly* newButterfly = butterfly();
1363         if (this->structure()->putWillGrowOutOfLineStorage())
1364             newButterfly = growOutOfLineStorage(vm, this->structure()->outOfLineCapacity(), this->structure()->suggestedNewOutOfLineStorageCapacity());
1365         offset = this->structure()->addPropertyWithoutTransition(vm, propertyName, attributes, specificFunction);
1366         setStructureAndButterfly(vm, this->structure(), newButterfly);
1367
1368         validateOffset(offset);
1369         ASSERT(this->structure()->isValidOffset(offset));
1370         putDirect(vm, offset, value);
1371         // See comment on setNewProperty call below.
1372         if (!specificFunction)
1373             slot.setNewProperty(this, offset);
1374         if (attributes & ReadOnly)
1375             this->structure()->setContainsReadOnlyProperties();
1376         return true;
1377     }
1378
1379     PropertyOffset offset;
1380     size_t currentCapacity = this->structure()->outOfLineCapacity();
1381     if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
1382         DeferGC deferGC(vm.heap);
1383         Butterfly* newButterfly = butterfly();
1384         if (currentCapacity != structure->outOfLineCapacity()) {
1385             ASSERT(structure != this->structure());
1386             newButterfly = growOutOfLineStorage(vm, currentCapacity, structure->outOfLineCapacity());
1387         }
1388
1389         validateOffset(offset);
1390         ASSERT(structure->isValidOffset(offset));
1391         setStructureAndButterfly(vm, structure, newButterfly);
1392         putDirect(vm, offset, value);
1393         // This is a new property; transitions with specific values are not currently cachable,
1394         // so leave the slot in an uncachable state.
1395         if (!specificFunction)
1396             slot.setNewProperty(this, offset);
1397         return true;
1398     }
1399
1400     unsigned currentAttributes;
1401     JSCell* currentSpecificFunction;
1402     offset = structure->get(vm, propertyName, currentAttributes, currentSpecificFunction);
1403     if (offset != invalidOffset) {
1404         if ((mode == PutModePut) && currentAttributes & ReadOnly)
1405             return false;
1406
1407         // There are three possibilities here:
1408         //  (1) There is an existing specific value set, and we're overwriting with *the same value*.
1409         //       * Do nothing - no need to despecify, but that means we can't cache (a cached
1410         //         put could write a different value). Leave the slot in an uncachable state.
1411         //  (2) There is a specific value currently set, but we're writing a different value.
1412         //       * First, we have to despecify.  Having done so, this is now a regular slot
1413         //         with no specific value, so go ahead & cache like normal.
1414         //  (3) Normal case, there is no specific value set.
1415         //       * Go ahead & cache like normal.
1416         if (currentSpecificFunction) {
1417             // case (1) Do the put, then return leaving the slot uncachable.
1418             if (specificFunction == currentSpecificFunction) {
1419                 putDirect(vm, offset, value);
1420                 return true;
1421             }
1422             // case (2) Despecify, fall through to (3).
1423             setStructure(vm, Structure::despecifyFunctionTransition(vm, structure, propertyName));
1424         }
1425
1426         // case (3) set the slot, do the put, return.
1427         slot.setExistingProperty(this, offset);
1428         putDirect(vm, offset, value);
1429         return true;
1430     }
1431
1432     if ((mode == PutModePut) && !isExtensible())
1433         return false;
1434
1435     structure = Structure::addPropertyTransition(vm, structure, propertyName, attributes, specificFunction, offset, slot.context());
1436     
1437     validateOffset(offset);
1438     ASSERT(structure->isValidOffset(offset));
1439     setStructureAndReallocateStorageIfNecessary(vm, structure);
1440
1441     putDirect(vm, offset, value);
1442     // This is a new property; transitions with specific values are not currently cachable,
1443     // so leave the slot in an uncachable state.
1444     if (!specificFunction)
1445         slot.setNewProperty(this, offset);
1446     if (attributes & ReadOnly)
1447         structure->setContainsReadOnlyProperties();
1448     return true;
1449 }
1450
1451 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, unsigned oldCapacity, Structure* newStructure)
1452 {
1453     ASSERT(oldCapacity <= newStructure->outOfLineCapacity());
1454     
1455     if (oldCapacity == newStructure->outOfLineCapacity()) {
1456         setStructure(vm, newStructure);
1457         return;
1458     }
1459
1460     DeferGC deferGC(vm.heap); 
1461     Butterfly* newButterfly = growOutOfLineStorage(
1462         vm, oldCapacity, newStructure->outOfLineCapacity());
1463     setStructureAndButterfly(vm, newStructure, newButterfly);
1464 }
1465
1466 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, Structure* newStructure)
1467 {
1468     setStructureAndReallocateStorageIfNecessary(
1469         vm, structure(vm)->outOfLineCapacity(), newStructure);
1470 }
1471
1472 inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
1473 {
1474     ASSERT(value);
1475     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
1476     ASSERT(!structure()->hasGetterSetterProperties());
1477     ASSERT(!structure()->hasCustomGetterSetterProperties());
1478
1479     return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value));
1480 }
1481
1482 inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
1483 {
1484     ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
1485     ASSERT(!value.isCustomGetterSetter());
1486     PutPropertySlot slot(this);
1487     putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value));
1488 }
1489
1490 inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
1491 {
1492     ASSERT(!value.isGetterSetter());
1493     ASSERT(!value.isCustomGetterSetter());
1494     putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot, getCallableObject(value));
1495 }
1496
1497 inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
1498 {
1499     DeferGC deferGC(vm.heap);
1500     ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
1501     ASSERT(!value.isCustomGetterSetter());
1502     Butterfly* newButterfly = m_butterfly.get();
1503     if (structure()->putWillGrowOutOfLineStorage())
1504         newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
1505     PropertyOffset offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes, getCallableObject(value));
1506     setStructureAndButterfly(vm, structure(), newButterfly);
1507     putDirect(vm, offset, value);
1508 }
1509
1510 inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
1511 {
1512     return methodTable()->defaultValue(this, exec, preferredType);
1513 }
1514
1515 ALWAYS_INLINE JSObject* Register::function() const
1516 {
1517     if (!jsValue())
1518         return 0;
1519     return asObject(jsValue());
1520 }
1521
1522 ALWAYS_INLINE Register Register::withCallee(JSObject* callee)
1523 {
1524     Register r;
1525     r = JSValue(callee);
1526     return r;
1527 }
1528
1529 inline size_t offsetInButterfly(PropertyOffset offset)
1530 {
1531     return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
1532 }
1533
1534 inline size_t JSObject::butterflyPreCapacity()
1535 {
1536     if (UNLIKELY(hasIndexingHeader()))
1537         return butterfly()->indexingHeader()->preCapacity(structure());
1538     return 0;
1539 }
1540
1541 inline size_t JSObject::butterflyTotalSize()
1542 {
1543     Structure* structure = this->structure();
1544     Butterfly* butterfly = this->butterfly();
1545     size_t preCapacity;
1546     size_t indexingPayloadSizeInBytes;
1547     bool hasIndexingHeader = this->hasIndexingHeader();
1548
1549     if (UNLIKELY(hasIndexingHeader)) {
1550         preCapacity = butterfly->indexingHeader()->preCapacity(structure);
1551         indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
1552     } else {
1553         preCapacity = 0;
1554         indexingPayloadSizeInBytes = 0;
1555     }
1556
1557     return Butterfly::totalSize(preCapacity, structure->outOfLineCapacity(), hasIndexingHeader, indexingPayloadSizeInBytes);
1558 }
1559
1560 // Helpers for patching code where you want to emit a load or store and
1561 // the base is:
1562 // For inline offsets: a pointer to the out-of-line storage pointer.
1563 // For out-of-line offsets: the base of the out-of-line storage.
1564 inline size_t offsetRelativeToPatchedStorage(PropertyOffset offset)
1565 {
1566     if (isOutOfLineOffset(offset))
1567         return sizeof(EncodedJSValue) * offsetInButterfly(offset);
1568     return JSObject::offsetOfInlineStorage() - JSObject::butterflyOffset() + sizeof(EncodedJSValue) * offsetInInlineStorage(offset);
1569 }
1570
1571 // Returns the maximum offset (away from zero) a load instruction will encode.
1572 inline size_t maxOffsetRelativeToPatchedStorage(PropertyOffset offset)
1573 {
1574     ptrdiff_t addressOffset = static_cast<ptrdiff_t>(offsetRelativeToPatchedStorage(offset));
1575 #if USE(JSVALUE32_64)
1576     if (addressOffset >= 0)
1577         return static_cast<size_t>(addressOffset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag);
1578 #endif
1579     return static_cast<size_t>(addressOffset);
1580 }
1581
1582 inline int indexRelativeToBase(PropertyOffset offset)
1583 {
1584     if (isOutOfLineOffset(offset))
1585         return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
1586     ASSERT(!(JSObject::offsetOfInlineStorage() % sizeof(EncodedJSValue)));
1587     return JSObject::offsetOfInlineStorage() / sizeof(EncodedJSValue) + offsetInInlineStorage(offset);
1588 }
1589
1590 inline int offsetRelativeToBase(PropertyOffset offset)
1591 {
1592     if (isOutOfLineOffset(offset))
1593         return offsetInOutOfLineStorage(offset) * sizeof(EncodedJSValue) + Butterfly::offsetOfPropertyStorage();
1594     return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset) * sizeof(EncodedJSValue);
1595 }
1596
1597 COMPILE_ASSERT(!(sizeof(JSObject) % sizeof(WriteBarrierBase<Unknown>)), JSObject_inline_storage_has_correct_alignment);
1598
1599 ALWAYS_INLINE Identifier makeIdentifier(VM& vm, const char* name)
1600 {
1601     return Identifier(&vm, name);
1602 }
1603
1604 ALWAYS_INLINE Identifier makeIdentifier(VM&, const Identifier& name)
1605 {
1606     return name;
1607 }
1608
1609 // Helper for defining native functions, if you're not using a static hash table.
1610 // Use this macro from within finishCreation() methods in prototypes. This assumes
1611 // you've defined variables called exec, globalObject, and vm, and they
1612 // have the expected meanings.
1613 #define JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, attributes, length, intrinsic) \
1614     putDirectNativeFunction(\
1615         vm, globalObject, makeIdentifier(vm, (jsName)), (length), cppName, \
1616         (intrinsic), (attributes))
1617
1618 // As above, but this assumes that the function you're defining doesn't have an
1619 // intrinsic.
1620 #define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \
1621     JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic)
1622
1623 ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, PropertyName propertyName) const
1624 {
1625     if (m_propertyType == TypeValue)
1626         return JSValue::decode(m_data.value);
1627     if (m_propertyType == TypeGetter)
1628         return functionGetter(exec);
1629     return JSValue::decode(m_data.custom.getValue(exec, slotBase(), JSValue::encode(m_thisValue), propertyName));
1630 }
1631
1632 ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, unsigned propertyName) const
1633 {
1634     if (m_propertyType == TypeValue)
1635         return JSValue::decode(m_data.value);
1636     if (m_propertyType == TypeGetter)
1637         return functionGetter(exec);
1638     return JSValue::decode(m_data.custom.getValue(exec, slotBase(), JSValue::encode(m_thisValue), Identifier::from(exec, propertyName)));
1639 }
1640
1641 } // namespace JSC
1642
1643 #endif // JSObject_h