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