]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/Structure.h
JavaScriptCore-584.tar.gz
[apple/javascriptcore.git] / runtime / Structure.h
CommitLineData
9dae56ea 1/*
f9bf01c6 2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
9dae56ea
A
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 "JSType.h"
31#include "JSValue.h"
32#include "PropertyMapHashTable.h"
f9bf01c6
A
33#include "PropertyNameArray.h"
34#include "Protect.h"
9dae56ea
A
35#include "StructureChain.h"
36#include "StructureTransitionTable.h"
f9bf01c6 37#include "JSTypeInfo.h"
9dae56ea 38#include "UString.h"
f9bf01c6 39#include "WeakGCPtr.h"
9dae56ea
A
40#include <wtf/PassRefPtr.h>
41#include <wtf/RefCounted.h>
42
43#ifndef NDEBUG
44#define DUMP_PROPERTYMAP_STATS 0
45#else
46#define DUMP_PROPERTYMAP_STATS 0
47#endif
48
49namespace JSC {
50
f9bf01c6 51 class MarkStack;
9dae56ea
A
52 class PropertyNameArray;
53 class PropertyNameArrayData;
54
f9bf01c6
A
55 enum EnumerationMode {
56 ExcludeDontEnumProperties,
57 IncludeDontEnumProperties
58 };
59
9dae56ea
A
60 class Structure : public RefCounted<Structure> {
61 public:
62 friend class JIT;
f9bf01c6
A
63 friend class StructureTransitionTable;
64 static PassRefPtr<Structure> create(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount)
9dae56ea 65 {
f9bf01c6 66 return adoptRef(new Structure(prototype, typeInfo, anonymousSlotCount));
9dae56ea
A
67 }
68
69 static void startIgnoringLeaks();
70 static void stopIgnoringLeaks();
71
72 static void dumpStatistics();
73
ba379fdc
A
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);
9dae56ea 76 static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset);
ba379fdc 77 static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype);
f9bf01c6 78 static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&);
9dae56ea 79 static PassRefPtr<Structure> getterSetterTransition(Structure*);
ba379fdc
A
80 static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*);
81 static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*);
82
83 PassRefPtr<Structure> flattenDictionaryStructure(JSObject*);
9dae56ea
A
84
85 ~Structure();
86
9dae56ea 87 // These should be used with caution.
ba379fdc 88 size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
9dae56ea 89 size_t removePropertyWithoutTransition(const Identifier& propertyName);
ba379fdc
A
90 void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; }
91
92 bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
93 bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
9dae56ea
A
94
95 const TypeInfo& typeInfo() const { return m_typeInfo; }
96
ba379fdc
A
97 JSValue storedPrototype() const { return m_prototype; }
98 JSValue prototypeForLookup(ExecState*) const;
9dae56ea
A
99 StructureChain* prototypeChain(ExecState*) const;
100
101 Structure* previousID() const { return m_previous.get(); }
102
103 void growPropertyStorageCapacity();
f9bf01c6
A
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) : m_offset + 1); }
ba379fdc 106 bool isUsingInlineStorage() const;
9dae56ea
A
107
108 size_t get(const Identifier& propertyName);
ba379fdc
A
109 size_t get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue);
110 size_t get(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
111 {
112 ASSERT(!propertyName.isNull());
113 return get(propertyName.ustring().rep(), attributes, specificValue);
114 }
115 bool transitionedFor(const JSCell* specificValue)
116 {
117 return m_specificValueInPrevious == specificValue;
118 }
119 bool hasTransition(UString::Rep*, unsigned attributes);
120 bool hasTransition(const Identifier& propertyName, unsigned attributes)
121 {
122 return hasTransition(propertyName._ustring.rep(), attributes);
123 }
124
9dae56ea
A
125 bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
126 void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
127
f9bf01c6
A
128 bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
129
130 bool hasAnonymousSlots() const { return !!m_anonymousSlotCount; }
131 unsigned anonymousSlotCount() const { return m_anonymousSlotCount; }
132
9dae56ea
A
133 bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; }
134
ba379fdc 135 void despecifyDictionaryFunction(const Identifier& propertyName);
f9bf01c6 136 void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
9dae56ea 137
f9bf01c6
A
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);
142
ba379fdc 143 private:
f9bf01c6
A
144
145 Structure(JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount);
ba379fdc
A
146
147 typedef enum {
148 NoneDictionaryKind = 0,
149 CachedDictionaryKind = 1,
150 UncachedDictionaryKind = 2
151 } DictionaryKind;
152 static PassRefPtr<Structure> toDictionaryTransition(Structure*, DictionaryKind);
153
154 size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
9dae56ea 155 size_t remove(const Identifier& propertyName);
9dae56ea
A
156
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();
164
ba379fdc 165 bool despecifyFunction(const Identifier&);
f9bf01c6 166 void despecifyAllFunctions();
ba379fdc 167
9dae56ea
A
168 PropertyMapHashTable* copyPropertyTable();
169 void materializePropertyMap();
170 void materializePropertyMapIfNecessary()
171 {
172 if (m_propertyTable || !m_previous)
173 return;
174 materializePropertyMap();
175 }
176
9dae56ea
A
177 signed char transitionCount() const
178 {
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;
181 }
182
183 bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
184
185 static const unsigned emptyEntryIndex = 0;
186
187 static const signed char s_maxTransitionLength = 64;
188
189 static const signed char noOffset = -1;
190
f9bf01c6
A
191 static const unsigned maxSpecificFunctionThrashCount = 3;
192
9dae56ea
A
193 TypeInfo m_typeInfo;
194
ba379fdc 195 JSValue m_prototype;
9dae56ea
A
196 mutable RefPtr<StructureChain> m_cachedPrototypeChain;
197
198 RefPtr<Structure> m_previous;
199 RefPtr<UString::Rep> m_nameInPrevious;
ba379fdc 200 JSCell* m_specificValueInPrevious;
9dae56ea 201
f9bf01c6 202 StructureTransitionTable table;
9dae56ea 203
f9bf01c6 204 WeakGCPtr<JSPropertyNameIterator> m_enumerationCache;
9dae56ea
A
205
206 PropertyMapHashTable* m_propertyTable;
207
f9bf01c6
A
208 uint32_t m_propertyStorageCapacity;
209
210 // m_offset does not account for anonymous slots
9dae56ea
A
211 signed char m_offset;
212
ba379fdc 213 unsigned m_dictionaryKind : 2;
9dae56ea
A
214 bool m_isPinnedPropertyTable : 1;
215 bool m_hasGetterSetterProperties : 1;
f9bf01c6
A
216 bool m_hasNonEnumerableProperties : 1;
217#if COMPILER(WINSCW)
218 // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared
219 // bitfield, when used as argument in make_pair() function calls in structure.ccp.
220 // This bitfield optimization is insignificant for the Symbian emulator target.
221 unsigned m_attributesInPrevious;
222#else
ba379fdc 223 unsigned m_attributesInPrevious : 7;
f9bf01c6
A
224#endif
225 unsigned m_specificFunctionThrashCount : 2;
226 unsigned m_anonymousSlotCount : 5;
227 // 5 free bits
9dae56ea
A
228 };
229
230 inline size_t Structure::get(const Identifier& propertyName)
231 {
232 ASSERT(!propertyName.isNull());
233
234 materializePropertyMapIfNecessary();
235 if (!m_propertyTable)
236 return WTF::notFound;
237
238 UString::Rep* rep = propertyName._ustring.rep();
239
f9bf01c6 240 unsigned i = rep->existingHash();
9dae56ea
A
241
242#if DUMP_PROPERTYMAP_STATS
243 ++numProbes;
244#endif
245
246 unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
247 if (entryIndex == emptyEntryIndex)
248 return WTF::notFound;
249
250 if (rep == m_propertyTable->entries()[entryIndex - 1].key)
251 return m_propertyTable->entries()[entryIndex - 1].offset;
252
253#if DUMP_PROPERTYMAP_STATS
254 ++numCollisions;
255#endif
256
f9bf01c6 257 unsigned k = 1 | WTF::doubleHash(rep->existingHash());
9dae56ea
A
258
259 while (1) {
260 i += k;
261
262#if DUMP_PROPERTYMAP_STATS
263 ++numRehashes;
264#endif
265
266 entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
267 if (entryIndex == emptyEntryIndex)
268 return WTF::notFound;
269
270 if (rep == m_propertyTable->entries()[entryIndex - 1].key)
271 return m_propertyTable->entries()[entryIndex - 1].offset;
272 }
273 }
ba379fdc
A
274
275 bool StructureTransitionTable::contains(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
276 {
f9bf01c6
A
277 if (usingSingleTransitionSlot()) {
278 Structure* existingTransition = singleTransition();
279 return existingTransition && existingTransition->m_nameInPrevious.get() == key.first
280 && existingTransition->m_attributesInPrevious == key.second
281 && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0);
282 }
283 TransitionTable::iterator find = table()->find(key);
284 if (find == table()->end())
ba379fdc
A
285 return false;
286
287 return find->second.first || find->second.second->transitionedFor(specificValue);
288 }
9dae56ea 289
ba379fdc
A
290 Structure* StructureTransitionTable::get(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const
291 {
f9bf01c6
A
292 if (usingSingleTransitionSlot()) {
293 Structure* existingTransition = singleTransition();
294 if (existingTransition && existingTransition->m_nameInPrevious.get() == key.first
295 && existingTransition->m_attributesInPrevious == key.second
296 && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0))
297 return existingTransition;
298 return 0;
299 }
300
301 Transition transition = table()->get(key);
ba379fdc
A
302 if (transition.second && transition.second->transitionedFor(specificValue))
303 return transition.second;
304 return transition.first;
305 }
f9bf01c6
A
306
307 bool StructureTransitionTable::hasTransition(const StructureTransitionTableHash::Key& key) const
308 {
309 if (usingSingleTransitionSlot()) {
310 Structure* transition = singleTransition();
311 return transition && transition->m_nameInPrevious == key.first
312 && transition->m_attributesInPrevious == key.second;
313 }
314 return table()->contains(key);
315 }
316
317 void StructureTransitionTable::reifySingleTransition()
318 {
319 ASSERT(usingSingleTransitionSlot());
320 Structure* existingTransition = singleTransition();
321 TransitionTable* transitionTable = new TransitionTable;
322 setTransitionTable(transitionTable);
323 if (existingTransition)
324 add(std::make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious);
325 }
9dae56ea
A
326} // namespace JSC
327
328#endif // Structure_h