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