2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "Identifier.h"
32 #include "PropertyMapHashTable.h"
33 #include "PropertyNameArray.h"
35 #include "StructureChain.h"
36 #include "StructureTransitionTable.h"
37 #include "JSTypeInfo.h"
39 #include "WeakGCPtr.h"
40 #include <wtf/PassRefPtr.h>
41 #include <wtf/RefCounted.h>
44 #define DUMP_PROPERTYMAP_STATS 0
46 #define DUMP_PROPERTYMAP_STATS 0
52 class PropertyNameArray
;
53 class PropertyNameArrayData
;
55 enum EnumerationMode
{
56 ExcludeDontEnumProperties
,
57 IncludeDontEnumProperties
60 class Structure
: public RefCounted
<Structure
> {
63 friend class StructureTransitionTable
;
64 static PassRefPtr
<Structure
> create(JSValue prototype
, const TypeInfo
& typeInfo
, unsigned anonymousSlotCount
)
66 return adoptRef(new Structure(prototype
, typeInfo
, anonymousSlotCount
));
69 static void startIgnoringLeaks();
70 static void stopIgnoringLeaks();
72 static void dumpStatistics();
74 static PassRefPtr
<Structure
> addPropertyTransition(Structure
*, const Identifier
& propertyName
, unsigned attributes
, JSCell
* specificValue
, size_t& offset
);
75 static PassRefPtr
<Structure
> addPropertyTransitionToExistingStructure(Structure
*, const Identifier
& propertyName
, unsigned attributes
, JSCell
* specificValue
, size_t& offset
);
76 static PassRefPtr
<Structure
> removePropertyTransition(Structure
*, const Identifier
& propertyName
, size_t& offset
);
77 static PassRefPtr
<Structure
> changePrototypeTransition(Structure
*, JSValue prototype
);
78 static PassRefPtr
<Structure
> despecifyFunctionTransition(Structure
*, const Identifier
&);
79 static PassRefPtr
<Structure
> getterSetterTransition(Structure
*);
80 static PassRefPtr
<Structure
> toCacheableDictionaryTransition(Structure
*);
81 static PassRefPtr
<Structure
> toUncacheableDictionaryTransition(Structure
*);
83 PassRefPtr
<Structure
> flattenDictionaryStructure(JSObject
*);
87 // These should be used with caution.
88 size_t addPropertyWithoutTransition(const Identifier
& propertyName
, unsigned attributes
, JSCell
* specificValue
);
89 size_t removePropertyWithoutTransition(const Identifier
& propertyName
);
90 void setPrototypeWithoutTransition(JSValue prototype
) { m_prototype
= prototype
; }
92 bool isDictionary() const { return m_dictionaryKind
!= NoneDictionaryKind
; }
93 bool isUncacheableDictionary() const { return m_dictionaryKind
== UncachedDictionaryKind
; }
95 const TypeInfo
& typeInfo() const { return m_typeInfo
; }
97 JSValue
storedPrototype() const { return m_prototype
; }
98 JSValue
prototypeForLookup(ExecState
*) const;
99 StructureChain
* prototypeChain(ExecState
*) const;
101 Structure
* previousID() const { return m_previous
.get(); }
103 void growPropertyStorageCapacity();
104 unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity
; }
105 unsigned propertyStorageSize() const { return m_anonymousSlotCount
+ (m_propertyTable
? m_propertyTable
->keyCount
+ (m_propertyTable
->deletedOffsets
? m_propertyTable
->deletedOffsets
->size() : 0) : static_cast<unsigned>(m_offset
+ 1)); }
106 bool isUsingInlineStorage() const;
108 size_t get(const Identifier
& propertyName
);
109 size_t get(const UString::Rep
* rep
, unsigned& attributes
, JSCell
*& specificValue
);
110 size_t get(const Identifier
& propertyName
, unsigned& attributes
, JSCell
*& specificValue
)
112 ASSERT(!propertyName
.isNull());
113 return get(propertyName
.ustring().rep(), attributes
, specificValue
);
115 bool transitionedFor(const JSCell
* specificValue
)
117 return m_specificValueInPrevious
== specificValue
;
119 bool hasTransition(UString::Rep
*, unsigned attributes
);
120 bool hasTransition(const Identifier
& propertyName
, unsigned attributes
)
122 return hasTransition(propertyName
._ustring
.rep(), attributes
);
125 bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties
; }
126 void setHasGetterSetterProperties(bool hasGetterSetterProperties
) { m_hasGetterSetterProperties
= hasGetterSetterProperties
; }
128 bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties
; }
130 bool hasAnonymousSlots() const { return !!m_anonymousSlotCount
; }
131 unsigned anonymousSlotCount() const { return m_anonymousSlotCount
; }
133 bool isEmpty() const { return m_propertyTable
? !m_propertyTable
->keyCount
: m_offset
== noOffset
; }
135 void despecifyDictionaryFunction(const Identifier
& propertyName
);
136 void disableSpecificFunctionTracking() { m_specificFunctionThrashCount
= maxSpecificFunctionThrashCount
; }
138 void setEnumerationCache(JSPropertyNameIterator
* enumerationCache
); // Defined in JSPropertyNameIterator.h.
139 void clearEnumerationCache(JSPropertyNameIterator
* enumerationCache
); // Defined in JSPropertyNameIterator.h.
140 JSPropertyNameIterator
* enumerationCache(); // Defined in JSPropertyNameIterator.h.
141 void getPropertyNames(PropertyNameArray
&, EnumerationMode mode
);
145 Structure(JSValue prototype
, const TypeInfo
&, unsigned anonymousSlotCount
);
148 NoneDictionaryKind
= 0,
149 CachedDictionaryKind
= 1,
150 UncachedDictionaryKind
= 2
152 static PassRefPtr
<Structure
> toDictionaryTransition(Structure
*, DictionaryKind
);
154 size_t put(const Identifier
& propertyName
, unsigned attributes
, JSCell
* specificValue
);
155 size_t remove(const Identifier
& propertyName
);
157 void expandPropertyMapHashTable();
158 void rehashPropertyMapHashTable();
159 void rehashPropertyMapHashTable(unsigned newTableSize
);
160 void createPropertyMapHashTable();
161 void createPropertyMapHashTable(unsigned newTableSize
);
162 void insertIntoPropertyMapHashTable(const PropertyMapEntry
&);
163 void checkConsistency();
165 bool despecifyFunction(const Identifier
&);
166 void despecifyAllFunctions();
168 PropertyMapHashTable
* copyPropertyTable();
169 void materializePropertyMap();
170 void materializePropertyMapIfNecessary()
172 if (m_propertyTable
|| !m_previous
)
174 materializePropertyMap();
177 signed char transitionCount() const
179 // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
180 return m_offset
== noOffset
? 0 : m_offset
+ 1;
183 typedef std::pair
<Structure
*, Structure
*> Transition
;
184 typedef HashMap
<StructureTransitionTableHash::Key
, Transition
, StructureTransitionTableHash
, StructureTransitionTableHashTraits
> TransitionTable
;
186 inline bool transitionTableContains(const StructureTransitionTableHash::Key
& key
, JSCell
* specificValue
);
187 inline void transitionTableRemove(const StructureTransitionTableHash::Key
& key
, JSCell
* specificValue
);
188 inline void transitionTableAdd(const StructureTransitionTableHash::Key
& key
, Structure
* structure
, JSCell
* specificValue
);
189 inline bool transitionTableHasTransition(const StructureTransitionTableHash::Key
& key
) const;
190 inline Structure
* transitionTableGet(const StructureTransitionTableHash::Key
& key
, JSCell
* specificValue
) const;
192 TransitionTable
* transitionTable() const { ASSERT(!m_isUsingSingleSlot
); return m_transitions
.m_table
; }
193 inline void setTransitionTable(TransitionTable
* table
);
194 Structure
* singleTransition() const { ASSERT(m_isUsingSingleSlot
); return m_transitions
.m_singleTransition
; }
195 void setSingleTransition(Structure
* structure
) { ASSERT(m_isUsingSingleSlot
); m_transitions
.m_singleTransition
= structure
; }
197 bool isValid(ExecState
*, StructureChain
* cachedPrototypeChain
) const;
199 static const unsigned emptyEntryIndex
= 0;
201 static const signed char s_maxTransitionLength
= 64;
203 static const signed char noOffset
= -1;
205 static const unsigned maxSpecificFunctionThrashCount
= 3;
210 mutable RefPtr
<StructureChain
> m_cachedPrototypeChain
;
212 RefPtr
<Structure
> m_previous
;
213 RefPtr
<UString::Rep
> m_nameInPrevious
;
214 JSCell
* m_specificValueInPrevious
;
216 // 'm_isUsingSingleSlot' indicates whether we are using the single transition optimisation.
218 TransitionTable
* m_table
;
219 Structure
* m_singleTransition
;
222 WeakGCPtr
<JSPropertyNameIterator
> m_enumerationCache
;
224 PropertyMapHashTable
* m_propertyTable
;
226 uint32_t m_propertyStorageCapacity
;
228 // m_offset does not account for anonymous slots
229 signed char m_offset
;
231 unsigned m_dictionaryKind
: 2;
232 bool m_isPinnedPropertyTable
: 1;
233 bool m_hasGetterSetterProperties
: 1;
234 bool m_hasNonEnumerableProperties
: 1;
236 // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared
237 // bitfield, when used as argument in make_pair() function calls in structure.ccp.
238 // This bitfield optimization is insignificant for the Symbian emulator target.
239 unsigned m_attributesInPrevious
;
241 unsigned m_attributesInPrevious
: 7;
243 unsigned m_specificFunctionThrashCount
: 2;
244 unsigned m_anonymousSlotCount
: 5;
245 unsigned m_isUsingSingleSlot
: 1;
249 inline size_t Structure::get(const Identifier
& propertyName
)
251 ASSERT(!propertyName
.isNull());
253 materializePropertyMapIfNecessary();
254 if (!m_propertyTable
)
255 return WTF::notFound
;
257 UString::Rep
* rep
= propertyName
._ustring
.rep();
259 unsigned i
= rep
->existingHash();
261 #if DUMP_PROPERTYMAP_STATS
265 unsigned entryIndex
= m_propertyTable
->entryIndices
[i
& m_propertyTable
->sizeMask
];
266 if (entryIndex
== emptyEntryIndex
)
267 return WTF::notFound
;
269 if (rep
== m_propertyTable
->entries()[entryIndex
- 1].key
)
270 return m_propertyTable
->entries()[entryIndex
- 1].offset
;
272 #if DUMP_PROPERTYMAP_STATS
276 unsigned k
= 1 | WTF::doubleHash(rep
->existingHash());
281 #if DUMP_PROPERTYMAP_STATS
285 entryIndex
= m_propertyTable
->entryIndices
[i
& m_propertyTable
->sizeMask
];
286 if (entryIndex
== emptyEntryIndex
)
287 return WTF::notFound
;
289 if (rep
== m_propertyTable
->entries()[entryIndex
- 1].key
)
290 return m_propertyTable
->entries()[entryIndex
- 1].offset
;
296 #endif // Structure_h