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