initial import
[vuplus_webkit] / 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 PropertyNameArray;
48     class PropertyNameArrayData;
49     class StructureChain;
50     class SlotVisitor;
51
52     struct ClassInfo;
53
54     enum EnumerationMode {
55         ExcludeDontEnumProperties,
56         IncludeDontEnumProperties
57     };
58
59     class Structure : public JSCell {
60     public:
61         friend class StructureTransitionTable;
62
63         typedef JSCell Base;
64
65         static Structure* create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo)
66         {
67             ASSERT(globalData.structureStructure);
68             ASSERT(classInfo);
69             Structure* structure = new (allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo);
70             structure->finishCreation(globalData);
71             return structure;
72         }
73
74     protected:
75         void finishCreation(JSGlobalData& globalData)
76         {
77             Base::finishCreation(globalData);
78             ASSERT(m_prototype);
79             ASSERT(m_prototype.isObject() || m_prototype.isNull());
80         }
81
82         void finishCreation(JSGlobalData& globalData, CreatingEarlyCellTag)
83         {
84             Base::finishCreation(globalData, this, CreatingEarlyCell);
85             ASSERT(m_prototype);
86             ASSERT(m_prototype.isNull());
87             ASSERT(!globalData.structureStructure);
88         }
89
90     public:
91         static void dumpStatistics();
92
93         static Structure* addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
94         static Structure* addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
95         static Structure* removePropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, size_t& offset);
96         static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype);
97         static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, const Identifier&);
98         static Structure* getterSetterTransition(JSGlobalData&, Structure*);
99         static Structure* toCacheableDictionaryTransition(JSGlobalData&, Structure*);
100         static Structure* toUncacheableDictionaryTransition(JSGlobalData&, Structure*);
101         static Structure* sealTransition(JSGlobalData&, Structure*);
102         static Structure* freezeTransition(JSGlobalData&, Structure*);
103         static Structure* preventExtensionsTransition(JSGlobalData&, Structure*);
104
105         bool isSealed(JSGlobalData&);
106         bool isFrozen(JSGlobalData&);
107         bool isExtensible() const { return !m_preventExtensions; }
108         bool didTransition() const { return m_didTransition; }
109
110         Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
111
112         ~Structure();
113
114         // These should be used with caution.  
115         size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
116         size_t removePropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName);
117         void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); }
118         
119         bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
120         bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
121
122         const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; }
123
124         JSGlobalObject* globalObject() const { return m_globalObject.get(); }
125         void setGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject) { m_globalObject.set(globalData, this, globalObject); }
126         
127         JSValue storedPrototype() const { return m_prototype.get(); }
128         JSValue prototypeForLookup(ExecState*) const;
129         StructureChain* prototypeChain(ExecState*) const;
130         void visitChildren(SlotVisitor&);
131
132         Structure* previousID() const { ASSERT(structure()->classInfo() == &s_info); return m_previous.get(); }
133
134         void growPropertyStorageCapacity();
135         unsigned propertyStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); return m_propertyStorageCapacity; }
136         unsigned propertyStorageSize() const { ASSERT(structure()->classInfo() == &s_info); return (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
137         bool isUsingInlineStorage() const;
138
139         size_t get(JSGlobalData&, const Identifier& propertyName);
140         size_t get(JSGlobalData&, const UString& name);
141         size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
142         size_t get(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
143         {
144             ASSERT(!propertyName.isNull());
145             ASSERT(structure()->classInfo() == &s_info);
146             return get(globalData, propertyName.impl(), attributes, specificValue);
147         }
148
149         bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
150         void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
151
152         bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
153         
154         bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
155
156         void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName);
157         void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
158
159         void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
160         JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
161         void getPropertyNames(JSGlobalData&, PropertyNameArray&, EnumerationMode mode);
162
163         const ClassInfo* classInfo() const { return m_classInfo; }
164
165         static ptrdiff_t prototypeOffset()
166         {
167             return OBJECT_OFFSETOF(Structure, m_prototype);
168         }
169
170         static ptrdiff_t typeInfoFlagsOffset()
171         {
172             return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
173         }
174
175         static ptrdiff_t typeInfoTypeOffset()
176         {
177             return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
178         }
179
180         static Structure* createStructure(JSGlobalData& globalData)
181         {
182             ASSERT(!globalData.structureStructure);
183             Structure* structure = new (allocateCell<Structure>(globalData.heap)) Structure(globalData);
184             structure->finishCreation(globalData, CreatingEarlyCell);
185             return structure;
186         }
187         
188         static JS_EXPORTDATA const ClassInfo s_info;
189
190     private:
191         Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*);
192         Structure(JSGlobalData&);
193         Structure(JSGlobalData&, const Structure*);
194
195         static Structure* create(JSGlobalData& globalData, const Structure* structure)
196         {
197             ASSERT(globalData.structureStructure);
198             Structure* newStructure = new (allocateCell<Structure>(globalData.heap)) Structure(globalData, structure);
199             newStructure->finishCreation(globalData);
200             return newStructure;
201         }
202         
203         typedef enum { 
204             NoneDictionaryKind = 0,
205             CachedDictionaryKind = 1,
206             UncachedDictionaryKind = 2
207         } DictionaryKind;
208         static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
209
210         size_t putSpecificValue(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
211         size_t remove(const Identifier& propertyName);
212
213         void createPropertyMap(unsigned keyCount = 0);
214         void checkConsistency();
215
216         bool despecifyFunction(JSGlobalData&, const Identifier&);
217         void despecifyAllFunctions(JSGlobalData&);
218
219         PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
220         void materializePropertyMap(JSGlobalData&);
221         void materializePropertyMapIfNecessary(JSGlobalData& globalData)
222         {
223             ASSERT(structure()->classInfo() == &s_info);
224             if (!m_propertyTable && m_previous)
225                 materializePropertyMap(globalData);
226         }
227
228         signed char transitionCount() const
229         {
230             // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
231             return m_offset == noOffset ? 0 : m_offset + 1;
232         }
233
234         bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
235
236         static const signed char s_maxTransitionLength = 64;
237
238         static const signed char noOffset = -1;
239
240         static const unsigned maxSpecificFunctionThrashCount = 3;
241
242         TypeInfo m_typeInfo;
243         
244         WriteBarrier<JSGlobalObject> m_globalObject;
245         WriteBarrier<Unknown> m_prototype;
246         mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
247
248         WriteBarrier<Structure> m_previous;
249         RefPtr<StringImpl> m_nameInPrevious;
250         WriteBarrier<JSCell> m_specificValueInPrevious;
251
252         const ClassInfo* m_classInfo;
253
254         StructureTransitionTable m_transitionTable;
255
256         WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
257
258         OwnPtr<PropertyTable> m_propertyTable;
259
260         uint32_t m_propertyStorageCapacity;
261
262         // m_offset does not account for anonymous slots
263         signed char m_offset;
264
265         unsigned m_dictionaryKind : 2;
266         bool m_isPinnedPropertyTable : 1;
267         bool m_hasGetterSetterProperties : 1;
268         bool m_hasNonEnumerableProperties : 1;
269 #if COMPILER(WINSCW)
270         // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared 
271         // bitfield, when used as argument in make_pair() function calls in structure.ccp.
272         // This bitfield optimization is insignificant for the Symbian emulator target.
273         unsigned m_attributesInPrevious;
274 #else
275         unsigned m_attributesInPrevious : 7;
276 #endif
277         unsigned m_specificFunctionThrashCount : 2;
278         unsigned m_preventExtensions : 1;
279         unsigned m_didTransition : 1;
280         // 8 free bits
281     };
282
283     inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName)
284     {
285         ASSERT(structure()->classInfo() == &s_info);
286         materializePropertyMapIfNecessary(globalData);
287         if (!m_propertyTable)
288             return notFound;
289
290         PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
291         return entry ? entry->offset : notFound;
292     }
293
294     inline size_t Structure::get(JSGlobalData& globalData, const UString& name)
295     {
296         ASSERT(structure()->classInfo() == &s_info);
297         materializePropertyMapIfNecessary(globalData);
298         if (!m_propertyTable)
299             return notFound;
300
301         PropertyMapEntry* entry = m_propertyTable->findWithString(name.impl()).first;
302         return entry ? entry->offset : notFound;
303     }
304
305     inline bool JSCell::isObject() const
306     {
307         return m_structure->typeInfo().type() == ObjectType;
308     }
309
310     inline bool JSCell::isString() const
311     {
312         return m_structure->typeInfo().type() == StringType;
313     }
314
315     inline bool JSCell::isGetterSetter() const
316     {
317         return m_structure->typeInfo().type() == GetterSetterType;
318     }
319
320     inline bool JSCell::isAPIValueWrapper() const
321     {
322         return m_structure->typeInfo().type() == APIValueWrapper;
323     }
324
325     inline const ClassInfo* JSCell::classInfo() const
326     {
327 #if ENABLE(GC_VALIDATION)
328         return m_structure.unvalidatedGet()->classInfo();
329 #else
330         return m_structure->classInfo();
331 #endif
332     }
333
334     ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell)
335     {
336         ASSERT(!m_isCheckingForDefaultMarkViolation);
337         ASSERT(cell);
338         if (Heap::testAndSetMarked(cell))
339             return;
340         if (cell->structure() && cell->structure()->typeInfo().type() >= CompoundType)
341             m_values.append(cell);
342     }
343
344     inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure)
345     {
346         // Newer versions of the STL have an std::make_pair function that takes rvalue references.
347         // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
348         // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details.
349         return Hash::Key(structure->m_nameInPrevious.get(), +structure->m_attributesInPrevious);
350     }
351
352 } // namespace JSC
353
354 #endif // Structure_h