46e4670aadd3ab3fedd67601cc91f383e2798e17
[WebKit-https.git] / Source / JavaScriptCore / runtime / Structure.h
1 /*
2  * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef Structure_h
27 #define Structure_h
28
29 #include "Identifier.h"
30 #include "JSCell.h"
31 #include "JSType.h"
32 #include "JSValue.h"
33 #include "PropertyMapHashTable.h"
34 #include "PropertyNameArray.h"
35 #include "Protect.h"
36 #include "StructureTransitionTable.h"
37 #include "JSTypeInfo.h"
38 #include "UString.h"
39 #include "WeakGCPtr.h"
40 #include <wtf/PassRefPtr.h>
41 #include <wtf/RefCounted.h>
42
43
44 namespace JSC {
45
46     class MarkStack;
47     class PropertyNameArray;
48     class PropertyNameArrayData;
49     class StructureChain;
50
51     struct ClassInfo;
52
53     enum EnumerationMode {
54         ExcludeDontEnumProperties,
55         IncludeDontEnumProperties
56     };
57
58     class Structure : public RefCounted<Structure> {
59     public:
60         friend class StructureTransitionTable;
61         static PassRefPtr<Structure> create(JSGlobalData&, JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo)
62         {
63             return adoptRef(new Structure(prototype, typeInfo, anonymousSlotCount, classInfo));
64         }
65
66         enum VPtrStealingHackType { VPtrStealingHack };
67         static PassRefPtr<Structure> create(VPtrStealingHackType, const ClassInfo* classInfo)
68         {
69             return adoptRef(new Structure(jsNull(), TypeInfo(UnspecifiedType), 0, classInfo));
70         }
71
72         static void startIgnoringLeaks();
73         static void stopIgnoringLeaks();
74
75         static void dumpStatistics();
76
77         static PassRefPtr<Structure> addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
78         static PassRefPtr<Structure> addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
79         static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset);
80         static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype);
81         static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&);
82         static PassRefPtr<Structure> getterSetterTransition(Structure*);
83         static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*);
84         static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*);
85         static PassRefPtr<Structure> sealTransition(Structure*);
86         static PassRefPtr<Structure> freezeTransition(Structure*);
87         static PassRefPtr<Structure> preventExtensionsTransition(Structure*);
88
89         bool isSealed();
90         bool isFrozen();
91         bool isExtensible() const { return !m_preventExtensions; }
92
93         PassRefPtr<Structure> flattenDictionaryStructure(JSGlobalData&, JSObject*);
94
95         ~Structure();
96
97         // These should be used with caution.  
98         size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
99         size_t removePropertyWithoutTransition(const Identifier& propertyName);
100         void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; }
101         
102         bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
103         bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
104
105         const TypeInfo& typeInfo() const { return m_typeInfo; }
106
107         JSValue storedPrototype() const { return m_prototype.get(); }
108         JSValue prototypeForLookup(ExecState*) const;
109         StructureChain* prototypeChain(ExecState*) const;
110         void markAggregate(MarkStack& markStack)
111         {
112             if (m_prototype)
113                 markStack.append(&m_prototype);
114         }
115
116         Structure* previousID() const { return m_previous.get(); }
117
118         void growPropertyStorageCapacity();
119         unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity; }
120         unsigned propertyStorageSize() const { return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
121         bool isUsingInlineStorage() const;
122
123         size_t get(const Identifier& propertyName);
124         size_t get(StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
125         size_t get(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
126         {
127             ASSERT(!propertyName.isNull());
128             return get(propertyName.impl(), attributes, specificValue);
129         }
130
131         bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
132         void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
133
134         bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
135
136         bool hasAnonymousSlots() const { return !!m_anonymousSlotCount; }
137         unsigned anonymousSlotCount() const { return m_anonymousSlotCount; }
138         
139         bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
140
141         void despecifyDictionaryFunction(const Identifier& propertyName);
142         void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
143
144         void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
145         void clearEnumerationCache(); // Defined in JSPropertyNameIterator.h.
146         JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
147         void getPropertyNames(PropertyNameArray&, EnumerationMode mode);
148
149         const ClassInfo* classInfo() const { return m_classInfo; }
150
151         static void initializeThreading();
152
153         static ptrdiff_t prototypeOffset()
154         {
155             return OBJECT_OFFSETOF(Structure, m_prototype);
156         }
157
158         static ptrdiff_t typeInfoFlagsOffset()
159         {
160             return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
161         }
162
163         static ptrdiff_t typeInfoTypeOffset()
164         {
165             return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
166         }
167
168     private:
169         Structure(JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount, const ClassInfo*);
170         Structure(const Structure*);
171
172         static PassRefPtr<Structure> create(const Structure* structure)
173         {
174             return adoptRef(new Structure(structure));
175         }
176         
177         typedef enum { 
178             NoneDictionaryKind = 0,
179             CachedDictionaryKind = 1,
180             UncachedDictionaryKind = 2
181         } DictionaryKind;
182         static PassRefPtr<Structure> toDictionaryTransition(Structure*, DictionaryKind);
183
184         size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
185         size_t remove(const Identifier& propertyName);
186
187         void createPropertyMap(unsigned keyCount = 0);
188         void checkConsistency();
189
190         bool despecifyFunction(const Identifier&);
191         void despecifyAllFunctions();
192
193         PropertyTable* copyPropertyTable();
194         void materializePropertyMap();
195         void materializePropertyMapIfNecessary()
196         {
197             if (!m_propertyTable && m_previous)
198                 materializePropertyMap();
199         }
200
201         signed char transitionCount() const
202         {
203             // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
204             return m_offset == noOffset ? 0 : m_offset + 1;
205         }
206
207         bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
208
209         static const signed char s_maxTransitionLength = 64;
210
211         static const signed char noOffset = -1;
212
213         static const unsigned maxSpecificFunctionThrashCount = 3;
214
215         TypeInfo m_typeInfo;
216
217         DeprecatedPtr<Unknown> m_prototype;
218         mutable WeakGCPtr<StructureChain> m_cachedPrototypeChain;
219
220         RefPtr<Structure> m_previous;
221         RefPtr<StringImpl> m_nameInPrevious;
222         JSCell* m_specificValueInPrevious;
223
224         const ClassInfo* m_classInfo;
225
226         StructureTransitionTable m_transitionTable;
227
228         WeakGCPtr<JSPropertyNameIterator> m_enumerationCache;
229
230         OwnPtr<PropertyTable> m_propertyTable;
231
232         uint32_t m_propertyStorageCapacity;
233
234         // m_offset does not account for anonymous slots
235         signed char m_offset;
236
237         unsigned m_dictionaryKind : 2;
238         bool m_isPinnedPropertyTable : 1;
239         bool m_hasGetterSetterProperties : 1;
240         bool m_hasNonEnumerableProperties : 1;
241 #if COMPILER(WINSCW)
242         // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared 
243         // bitfield, when used as argument in make_pair() function calls in structure.ccp.
244         // This bitfield optimization is insignificant for the Symbian emulator target.
245         unsigned m_attributesInPrevious;
246 #else
247         unsigned m_attributesInPrevious : 7;
248 #endif
249         unsigned m_specificFunctionThrashCount : 2;
250         unsigned m_anonymousSlotCount : 5;
251         unsigned m_preventExtensions : 1;
252         // 4 free bits
253     };
254
255     inline size_t Structure::get(const Identifier& propertyName)
256     {
257         materializePropertyMapIfNecessary();
258         if (!m_propertyTable)
259             return notFound;
260
261         PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
262         ASSERT(!entry || entry->offset >= m_anonymousSlotCount);
263         return entry ? entry->offset : notFound;
264     }
265
266     inline bool JSCell::isObject() const
267     {
268         return m_structure->typeInfo().type() == ObjectType;
269     }
270
271     inline bool JSCell::isString() const
272     {
273         return m_structure->typeInfo().type() == StringType;
274     }
275
276     inline const ClassInfo* JSCell::classInfo() const
277     {
278         return m_structure->classInfo();
279     }
280
281     inline PassRefPtr<Structure> JSCell::createDummyStructure(JSGlobalData& globalData)
282     {
283         return Structure::create(globalData, jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount, 0);
284     }
285
286     inline bool JSValue::needsThisConversion() const
287     {
288         if (UNLIKELY(!isCell()))
289             return true;
290         return asCell()->structure()->typeInfo().needsThisConversion();
291     }
292
293     ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell)
294     {
295         ASSERT(!m_isCheckingForDefaultMarkViolation);
296         ASSERT(cell);
297         if (Heap::testAndSetMarked(cell))
298             return;
299         if (cell->structure()->typeInfo().type() >= CompoundType)
300             m_values.append(cell);
301     }
302
303 } // namespace JSC
304
305 #endif // Structure_h