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