7556da9d00485afb278f71a8c5847d4a36533b60
[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 "Weak.h"
40 #include <wtf/PassOwnPtr.h>
41 #include <wtf/PassRefPtr.h>
42 #include <wtf/RefCounted.h>
43
44
45 namespace JSC {
46
47     class MarkStack;
48     class PropertyNameArray;
49     class PropertyNameArrayData;
50     class StructureChain;
51     typedef MarkStack SlotVisitor;
52
53     struct ClassInfo;
54
55     enum EnumerationMode {
56         ExcludeDontEnumProperties,
57         IncludeDontEnumProperties
58     };
59
60     class Structure : public JSCell {
61     public:
62         friend class StructureTransitionTable;
63         static Structure* create(JSGlobalData& globalData, JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo)
64         {
65             ASSERT(globalData.structureStructure);
66             ASSERT(classInfo);
67             return new (&globalData) Structure(globalData, prototype, typeInfo, anonymousSlotCount, classInfo);
68         }
69
70         static void dumpStatistics();
71
72         static Structure* addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
73         static Structure* addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
74         static Structure* removePropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, size_t& offset);
75         static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype);
76         static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, const Identifier&);
77         static Structure* getterSetterTransition(JSGlobalData&, Structure*);
78         static Structure* toCacheableDictionaryTransition(JSGlobalData&, Structure*);
79         static Structure* toUncacheableDictionaryTransition(JSGlobalData&, Structure*);
80         static Structure* sealTransition(JSGlobalData&, Structure*);
81         static Structure* freezeTransition(JSGlobalData&, Structure*);
82         static Structure* preventExtensionsTransition(JSGlobalData&, Structure*);
83
84         bool isSealed(JSGlobalData&);
85         bool isFrozen(JSGlobalData&);
86         bool isExtensible() const { return !m_preventExtensions; }
87         bool didTransition() const { return m_didTransition; }
88
89         Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
90
91         ~Structure();
92
93         // These should be used with caution.  
94         size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
95         size_t removePropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName);
96         void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); }
97         
98         bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
99         bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
100
101         const TypeInfo& typeInfo() const { return m_typeInfo; }
102
103         JSValue storedPrototype() const { return m_prototype.get(); }
104         JSValue prototypeForLookup(ExecState*) const;
105         StructureChain* prototypeChain(ExecState*) const;
106         void visitChildren(SlotVisitor&);
107
108         Structure* previousID() const { return m_previous.get(); }
109
110         void growPropertyStorageCapacity();
111         unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity; }
112         unsigned propertyStorageSize() const { return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
113         bool isUsingInlineStorage() const;
114
115         size_t get(JSGlobalData&, const Identifier& propertyName);
116         size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
117         size_t get(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
118         {
119             ASSERT(!propertyName.isNull());
120             return get(globalData, propertyName.impl(), attributes, specificValue);
121         }
122
123         bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
124         void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
125
126         bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
127
128         bool hasAnonymousSlots() const { return !!m_anonymousSlotCount; }
129         unsigned anonymousSlotCount() const { return m_anonymousSlotCount; }
130         
131         bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
132
133         void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName);
134         void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
135
136         void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
137         JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
138         void getPropertyNames(JSGlobalData&, PropertyNameArray&, EnumerationMode mode);
139
140         const ClassInfo* classInfo() const { return m_classInfo; }
141
142         static ptrdiff_t prototypeOffset()
143         {
144             return OBJECT_OFFSETOF(Structure, m_prototype);
145         }
146
147         static ptrdiff_t typeInfoFlagsOffset()
148         {
149             return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
150         }
151
152         static ptrdiff_t typeInfoTypeOffset()
153         {
154             return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
155         }
156
157         static Structure* createStructure(JSGlobalData& globalData)
158         {
159             ASSERT(!globalData.structureStructure);
160             return new (&globalData) Structure(globalData);
161         }
162
163     private:
164         Structure(JSGlobalData&, JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount, const ClassInfo*);
165         Structure(JSGlobalData&);
166         Structure(JSGlobalData&, const Structure*);
167
168         static Structure* create(JSGlobalData& globalData, const Structure* structure)
169         {
170             ASSERT(globalData.structureStructure);
171             return new (&globalData) Structure(globalData, structure);
172         }
173         
174         static const ClassInfo s_info;
175
176         typedef enum { 
177             NoneDictionaryKind = 0,
178             CachedDictionaryKind = 1,
179             UncachedDictionaryKind = 2
180         } DictionaryKind;
181         static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
182
183         size_t putSpecificValue(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
184         size_t remove(const Identifier& propertyName);
185
186         void createPropertyMap(unsigned keyCount = 0);
187         void checkConsistency();
188
189         bool despecifyFunction(JSGlobalData&, const Identifier&);
190         void despecifyAllFunctions(JSGlobalData&);
191
192         PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
193         void materializePropertyMap(JSGlobalData&);
194         void materializePropertyMapIfNecessary(JSGlobalData& globalData)
195         {
196             if (!m_propertyTable && m_previous)
197                 materializePropertyMap(globalData);
198         }
199
200         signed char transitionCount() const
201         {
202             // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
203             return m_offset == noOffset ? 0 : m_offset + 1;
204         }
205
206         bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
207
208         static const signed char s_maxTransitionLength = 64;
209
210         static const signed char noOffset = -1;
211
212         static const unsigned maxSpecificFunctionThrashCount = 3;
213
214         TypeInfo m_typeInfo;
215
216         WriteBarrier<Unknown> m_prototype;
217         mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
218
219         WriteBarrier<Structure> m_previous;
220         RefPtr<StringImpl> m_nameInPrevious;
221         WriteBarrier<JSCell> m_specificValueInPrevious;
222
223         const ClassInfo* m_classInfo;
224
225         StructureTransitionTable m_transitionTable;
226
227         WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
228
229         OwnPtr<PropertyTable> m_propertyTable;
230
231         uint32_t m_propertyStorageCapacity;
232
233         // m_offset does not account for anonymous slots
234         signed char m_offset;
235
236         unsigned m_dictionaryKind : 2;
237         bool m_isPinnedPropertyTable : 1;
238         bool m_hasGetterSetterProperties : 1;
239         bool m_hasNonEnumerableProperties : 1;
240 #if COMPILER(WINSCW)
241         // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared 
242         // bitfield, when used as argument in make_pair() function calls in structure.ccp.
243         // This bitfield optimization is insignificant for the Symbian emulator target.
244         unsigned m_attributesInPrevious;
245 #else
246         unsigned m_attributesInPrevious : 7;
247 #endif
248         unsigned m_specificFunctionThrashCount : 2;
249         unsigned m_anonymousSlotCount : 5;
250         unsigned m_preventExtensions : 1;
251         unsigned m_didTransition : 1;
252         // 3 free bits
253     };
254
255     inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName)
256     {
257         materializePropertyMapIfNecessary(globalData);
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 Structure* JSCell::createDummyStructure(JSGlobalData& globalData)
282     {
283         return Structure::create(globalData, jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount, &s_dummyCellInfo);
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     inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure)
304     {
305         return Hash::Key(structure->m_nameInPrevious.get(), structure->m_attributesInPrevious);
306     }
307
308 } // namespace JSC
309
310 #endif // Structure_h