• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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 JSCell {
59     public:
60         friend class StructureTransitionTable;
create(JSGlobalData & globalData,JSValue prototype,const TypeInfo & typeInfo,unsigned anonymousSlotCount,const ClassInfo * classInfo)61         static Structure* create(JSGlobalData& globalData, JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo)
62         {
63             ASSERT(globalData.structureStructure);
64             return new (&globalData) Structure(globalData, prototype, typeInfo, anonymousSlotCount, classInfo);
65         }
66 
67         static void dumpStatistics();
68 
69         static Structure* addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
70         static Structure* addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
71         static Structure* removePropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, size_t& offset);
72         static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype);
73         static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, const Identifier&);
74         static Structure* getterSetterTransition(JSGlobalData&, Structure*);
75         static Structure* toCacheableDictionaryTransition(JSGlobalData&, Structure*);
76         static Structure* toUncacheableDictionaryTransition(JSGlobalData&, Structure*);
77         static Structure* sealTransition(JSGlobalData&, Structure*);
78         static Structure* freezeTransition(JSGlobalData&, Structure*);
79         static Structure* preventExtensionsTransition(JSGlobalData&, Structure*);
80 
81         bool isSealed(JSGlobalData&);
82         bool isFrozen(JSGlobalData&);
isExtensible()83         bool isExtensible() const { return !m_preventExtensions; }
84 
85         Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
86 
87         ~Structure();
88 
89         // These should be used with caution.
90         size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
91         size_t removePropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName);
setPrototypeWithoutTransition(JSGlobalData & globalData,JSValue prototype)92         void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); }
93 
isDictionary()94         bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
isUncacheableDictionary()95         bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
96 
typeInfo()97         const TypeInfo& typeInfo() const { return m_typeInfo; }
98 
storedPrototype()99         JSValue storedPrototype() const { return m_prototype.get(); }
100         JSValue prototypeForLookup(ExecState*) const;
101         StructureChain* prototypeChain(ExecState*) const;
102         void markChildren(MarkStack&);
103 
previousID()104         Structure* previousID() const { return m_previous.get(); }
105 
106         void growPropertyStorageCapacity();
propertyStorageCapacity()107         unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity; }
propertyStorageSize()108         unsigned propertyStorageSize() const { return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
109         bool isUsingInlineStorage() const;
110 
111         size_t get(JSGlobalData&, const Identifier& propertyName);
112         size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
get(JSGlobalData & globalData,const Identifier & propertyName,unsigned & attributes,JSCell * & specificValue)113         size_t get(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
114         {
115             ASSERT(!propertyName.isNull());
116             return get(globalData, propertyName.impl(), attributes, specificValue);
117         }
118 
hasGetterSetterProperties()119         bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
setHasGetterSetterProperties(bool hasGetterSetterProperties)120         void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
121 
hasNonEnumerableProperties()122         bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
123 
hasAnonymousSlots()124         bool hasAnonymousSlots() const { return !!m_anonymousSlotCount; }
anonymousSlotCount()125         unsigned anonymousSlotCount() const { return m_anonymousSlotCount; }
126 
isEmpty()127         bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
128 
129         void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName);
disableSpecificFunctionTracking()130         void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
131 
132         void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
133         JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
134         void getPropertyNames(JSGlobalData&, PropertyNameArray&, EnumerationMode mode);
135 
classInfo()136         const ClassInfo* classInfo() const { return m_classInfo; }
137 
prototypeOffset()138         static ptrdiff_t prototypeOffset()
139         {
140             return OBJECT_OFFSETOF(Structure, m_prototype);
141         }
142 
typeInfoFlagsOffset()143         static ptrdiff_t typeInfoFlagsOffset()
144         {
145             return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
146         }
147 
typeInfoTypeOffset()148         static ptrdiff_t typeInfoTypeOffset()
149         {
150             return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
151         }
152 
createStructure(JSGlobalData & globalData)153         static Structure* createStructure(JSGlobalData& globalData)
154         {
155             ASSERT(!globalData.structureStructure);
156             return new (&globalData) Structure(globalData);
157         }
158 
159     private:
160         Structure(JSGlobalData&, JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount, const ClassInfo*);
161         Structure(JSGlobalData&);
162         Structure(JSGlobalData&, const Structure*);
163 
create(JSGlobalData & globalData,const Structure * structure)164         static Structure* create(JSGlobalData& globalData, const Structure* structure)
165         {
166             ASSERT(globalData.structureStructure);
167             return new (&globalData) Structure(globalData, structure);
168         }
169 
170         static const ClassInfo s_info;
171 
172         typedef enum {
173             NoneDictionaryKind = 0,
174             CachedDictionaryKind = 1,
175             UncachedDictionaryKind = 2
176         } DictionaryKind;
177         static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
178 
179         size_t putSpecificValue(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
180         size_t remove(const Identifier& propertyName);
181 
182         void createPropertyMap(unsigned keyCount = 0);
183         void checkConsistency();
184 
185         bool despecifyFunction(JSGlobalData&, const Identifier&);
186         void despecifyAllFunctions(JSGlobalData&);
187 
188         PropertyTable* copyPropertyTable(JSGlobalData&, Structure* owner);
189         void materializePropertyMap(JSGlobalData&);
materializePropertyMapIfNecessary(JSGlobalData & globalData)190         void materializePropertyMapIfNecessary(JSGlobalData& globalData)
191         {
192             if (!m_propertyTable && m_previous)
193                 materializePropertyMap(globalData);
194         }
195 
transitionCount()196         signed char transitionCount() const
197         {
198             // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
199             return m_offset == noOffset ? 0 : m_offset + 1;
200         }
201 
202         bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
203 
204         static const signed char s_maxTransitionLength = 64;
205 
206         static const signed char noOffset = -1;
207 
208         static const unsigned maxSpecificFunctionThrashCount = 3;
209 
210         TypeInfo m_typeInfo;
211 
212         WriteBarrier<Unknown> m_prototype;
213         mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
214 
215         WriteBarrier<Structure> m_previous;
216         RefPtr<StringImpl> m_nameInPrevious;
217         WriteBarrier<JSCell> m_specificValueInPrevious;
218 
219         const ClassInfo* m_classInfo;
220 
221         StructureTransitionTable m_transitionTable;
222 
223         WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
224 
225         OwnPtr<PropertyTable> m_propertyTable;
226 
227         uint32_t m_propertyStorageCapacity;
228 
229         // m_offset does not account for anonymous slots
230         signed char m_offset;
231 
232         unsigned m_dictionaryKind : 2;
233         bool m_isPinnedPropertyTable : 1;
234         bool m_hasGetterSetterProperties : 1;
235         bool m_hasNonEnumerableProperties : 1;
236 #if COMPILER(WINSCW)
237         // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared
238         // bitfield, when used as argument in make_pair() function calls in structure.ccp.
239         // This bitfield optimization is insignificant for the Symbian emulator target.
240         unsigned m_attributesInPrevious;
241 #else
242         unsigned m_attributesInPrevious : 7;
243 #endif
244         unsigned m_specificFunctionThrashCount : 2;
245         unsigned m_anonymousSlotCount : 5;
246         unsigned m_preventExtensions : 1;
247         // 4 free bits
248     };
249 
get(JSGlobalData & globalData,const Identifier & propertyName)250     inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName)
251     {
252         materializePropertyMapIfNecessary(globalData);
253         if (!m_propertyTable)
254             return notFound;
255 
256         PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
257         ASSERT(!entry || entry->offset >= m_anonymousSlotCount);
258         return entry ? entry->offset : notFound;
259     }
260 
isObject()261     inline bool JSCell::isObject() const
262     {
263         return m_structure->typeInfo().type() == ObjectType;
264     }
265 
isString()266     inline bool JSCell::isString() const
267     {
268         return m_structure->typeInfo().type() == StringType;
269     }
270 
classInfo()271     inline const ClassInfo* JSCell::classInfo() const
272     {
273         return m_structure->classInfo();
274     }
275 
createDummyStructure(JSGlobalData & globalData)276     inline Structure* JSCell::createDummyStructure(JSGlobalData& globalData)
277     {
278         return Structure::create(globalData, jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount, 0);
279     }
280 
needsThisConversion()281     inline bool JSValue::needsThisConversion() const
282     {
283         if (UNLIKELY(!isCell()))
284             return true;
285         return asCell()->structure()->typeInfo().needsThisConversion();
286     }
287 
internalAppend(JSCell * cell)288     ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell)
289     {
290         ASSERT(!m_isCheckingForDefaultMarkViolation);
291         ASSERT(cell);
292         if (Heap::testAndSetMarked(cell))
293             return;
294         if (cell->structure()->typeInfo().type() >= CompoundType)
295             m_values.append(cell);
296     }
297 
keyForWeakGCMapFinalizer(void *,Structure * structure)298     inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure)
299     {
300         return Hash::Key(structure->m_nameInPrevious.get(), structure->m_attributesInPrevious);
301     }
302 
303 } // namespace JSC
304 
305 #endif // Structure_h
306