Revert r85550 and r85575.
[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 { ASSERT(structure()->classInfo() == &s_info); 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 { ASSERT(structure()->classInfo() == &s_info); return m_previous.get(); }
109
110         void growPropertyStorageCapacity();
111         unsigned propertyStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); return m_propertyStorageCapacity; }
112         unsigned propertyStorageSize() const { ASSERT(structure()->classInfo() == &s_info); 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             ASSERT(structure()->classInfo() == &s_info);
121             return get(globalData, propertyName.impl(), attributes, specificValue);
122         }
123
124         bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
125         void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
126
127         bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
128
129         bool hasAnonymousSlots() const { return !!m_anonymousSlotCount; }
130         unsigned anonymousSlotCount() const { return m_anonymousSlotCount; }
131         
132         bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
133
134         void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName);
135         void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
136
137         void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
138         JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
139         void getPropertyNames(JSGlobalData&, PropertyNameArray&, EnumerationMode mode);
140
141         const ClassInfo* classInfo() const { return m_classInfo; }
142
143         static ptrdiff_t prototypeOffset()
144         {
145             return OBJECT_OFFSETOF(Structure, m_prototype);
146         }
147
148         static ptrdiff_t typeInfoFlagsOffset()
149         {
150             return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
151         }
152
153         static ptrdiff_t typeInfoTypeOffset()
154         {
155             return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
156         }
157
158         static Structure* createStructure(JSGlobalData& globalData)
159         {
160             ASSERT(!globalData.structureStructure);
161             return new (&globalData) Structure(globalData);
162         }
163
164     private:
165         Structure(JSGlobalData&, JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount, const ClassInfo*);
166         Structure(JSGlobalData&);
167         Structure(JSGlobalData&, const Structure*);
168
169         static Structure* create(JSGlobalData& globalData, const Structure* structure)
170         {
171             ASSERT(globalData.structureStructure);
172             return new (&globalData) Structure(globalData, structure);
173         }
174         
175         static JS_EXPORTDATA const ClassInfo s_info;
176
177         typedef enum { 
178             NoneDictionaryKind = 0,
179             CachedDictionaryKind = 1,
180             UncachedDictionaryKind = 2
181         } DictionaryKind;
182         static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
183
184         size_t putSpecificValue(JSGlobalData&, 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(JSGlobalData&, const Identifier&);
191         void despecifyAllFunctions(JSGlobalData&);
192
193         PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
194         void materializePropertyMap(JSGlobalData&);
195         void materializePropertyMapIfNecessary(JSGlobalData& globalData)
196         {
197             ASSERT(structure()->classInfo() == &s_info);
198             if (!m_propertyTable && m_previous)
199                 materializePropertyMap(globalData);
200         }
201
202         signed char transitionCount() const
203         {
204             // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
205             return m_offset == noOffset ? 0 : m_offset + 1;
206         }
207
208         bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
209
210         static const signed char s_maxTransitionLength = 64;
211
212         static const signed char noOffset = -1;
213
214         static const unsigned maxSpecificFunctionThrashCount = 3;
215
216         TypeInfo m_typeInfo;
217
218         WriteBarrier<Unknown> m_prototype;
219         mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
220
221         WriteBarrier<Structure> m_previous;
222         RefPtr<StringImpl> m_nameInPrevious;
223         WriteBarrier<JSCell> m_specificValueInPrevious;
224
225         const ClassInfo* m_classInfo;
226
227         StructureTransitionTable m_transitionTable;
228
229         WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
230
231         OwnPtr<PropertyTable> m_propertyTable;
232
233         uint32_t m_propertyStorageCapacity;
234
235         // m_offset does not account for anonymous slots
236         signed char m_offset;
237
238         unsigned m_dictionaryKind : 2;
239         bool m_isPinnedPropertyTable : 1;
240         bool m_hasGetterSetterProperties : 1;
241         bool m_hasNonEnumerableProperties : 1;
242 #if COMPILER(WINSCW)
243         // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared 
244         // bitfield, when used as argument in make_pair() function calls in structure.ccp.
245         // This bitfield optimization is insignificant for the Symbian emulator target.
246         unsigned m_attributesInPrevious;
247 #else
248         unsigned m_attributesInPrevious : 7;
249 #endif
250         unsigned m_specificFunctionThrashCount : 2;
251         unsigned m_anonymousSlotCount : 5;
252         unsigned m_preventExtensions : 1;
253         unsigned m_didTransition : 1;
254         // 3 free bits
255     };
256
257     inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName)
258     {
259         ASSERT(structure()->classInfo() == &s_info);
260         materializePropertyMapIfNecessary(globalData);
261         if (!m_propertyTable)
262             return notFound;
263
264         PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
265         ASSERT(!entry || entry->offset >= m_anonymousSlotCount);
266         return entry ? entry->offset : notFound;
267     }
268
269     inline bool JSCell::isObject() const
270     {
271         return m_structure->typeInfo().type() == ObjectType;
272     }
273
274     inline bool JSCell::isString() const
275     {
276         return m_structure->typeInfo().type() == StringType;
277     }
278
279     inline const ClassInfo* JSCell::classInfo() const
280     {
281         return m_structure->classInfo();
282     }
283
284     inline Structure* JSCell::createDummyStructure(JSGlobalData& globalData)
285     {
286         return Structure::create(globalData, jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount, &s_dummyCellInfo);
287     }
288
289     inline bool JSValue::needsThisConversion() const
290     {
291         if (UNLIKELY(!isCell()))
292             return true;
293         return asCell()->structure()->typeInfo().needsThisConversion();
294     }
295
296     ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell)
297     {
298         ASSERT(!m_isCheckingForDefaultMarkViolation);
299         ASSERT(cell);
300         if (Heap::testAndSetMarked(cell))
301             return;
302         if (cell->structure()->typeInfo().type() >= CompoundType)
303             m_values.append(cell);
304     }
305
306     inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure)
307     {
308         return Hash::Key(structure->m_nameInPrevious.get(), structure->m_attributesInPrevious);
309     }
310
311 } // namespace JSC
312
313 #endif // Structure_h