2 * Copyright (C) 2008 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 "StructureChain.h"
34 #include "StructureTransitionTable.h"
37 #include <wtf/PassRefPtr.h>
38 #include <wtf/RefCounted.h>
41 #define DUMP_PROPERTYMAP_STATS 0
43 #define DUMP_PROPERTYMAP_STATS 0
48 class PropertyNameArray
;
49 class PropertyNameArrayData
;
51 class Structure
: public RefCounted
<Structure
> {
54 static PassRefPtr
<Structure
> create(JSValuePtr prototype
, const TypeInfo
& typeInfo
)
56 return adoptRef(new Structure(prototype
, typeInfo
));
59 static void startIgnoringLeaks();
60 static void stopIgnoringLeaks();
62 static void dumpStatistics();
64 static PassRefPtr
<Structure
> addPropertyTransition(Structure
*, const Identifier
& propertyName
, unsigned attributes
, size_t& offset
);
65 static PassRefPtr
<Structure
> addPropertyTransitionToExistingStructure(Structure
*, const Identifier
& propertyName
, unsigned attributes
, size_t& offset
);
66 static PassRefPtr
<Structure
> removePropertyTransition(Structure
*, const Identifier
& propertyName
, size_t& offset
);
67 static PassRefPtr
<Structure
> changePrototypeTransition(Structure
*, JSValuePtr prototype
);
68 static PassRefPtr
<Structure
> getterSetterTransition(Structure
*);
69 static PassRefPtr
<Structure
> toDictionaryTransition(Structure
*);
70 static PassRefPtr
<Structure
> fromDictionaryTransition(Structure
*);
76 if (!m_prototype
.marked())
80 // These should be used with caution.
81 size_t addPropertyWithoutTransition(const Identifier
& propertyName
, unsigned attributes
);
82 size_t removePropertyWithoutTransition(const Identifier
& propertyName
);
83 void setPrototypeWithoutTransition(JSValuePtr prototype
) { m_prototype
= prototype
; }
85 bool isDictionary() const { return m_isDictionary
; }
87 const TypeInfo
& typeInfo() const { return m_typeInfo
; }
89 JSValuePtr
storedPrototype() const { return m_prototype
; }
90 JSValuePtr
prototypeForLookup(ExecState
*) const;
91 StructureChain
* prototypeChain(ExecState
*) const;
93 Structure
* previousID() const { return m_previous
.get(); }
95 void growPropertyStorageCapacity();
96 size_t propertyStorageCapacity() const { return m_propertyStorageCapacity
; }
97 size_t propertyStorageSize() const { return m_propertyTable
? m_propertyTable
->keyCount
+ (m_propertyTable
->deletedOffsets
? m_propertyTable
->deletedOffsets
->size() : 0) : m_offset
+ 1; }
99 size_t get(const Identifier
& propertyName
);
100 size_t get(const Identifier
& propertyName
, unsigned& attributes
);
101 void getEnumerablePropertyNames(ExecState
*, PropertyNameArray
&, JSObject
*);
103 bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties
; }
104 void setHasGetterSetterProperties(bool hasGetterSetterProperties
) { m_hasGetterSetterProperties
= hasGetterSetterProperties
; }
106 bool isEmpty() const { return m_propertyTable
? !m_propertyTable
->keyCount
: m_offset
== noOffset
; }
109 Structure(JSValuePtr prototype
, const TypeInfo
&);
111 size_t put(const Identifier
& propertyName
, unsigned attributes
);
112 size_t remove(const Identifier
& propertyName
);
113 void getEnumerableNamesFromPropertyTable(PropertyNameArray
&);
114 void getEnumerableNamesFromClassInfoTable(ExecState
*, const ClassInfo
*, PropertyNameArray
&);
116 void expandPropertyMapHashTable();
117 void rehashPropertyMapHashTable();
118 void rehashPropertyMapHashTable(unsigned newTableSize
);
119 void createPropertyMapHashTable();
120 void createPropertyMapHashTable(unsigned newTableSize
);
121 void insertIntoPropertyMapHashTable(const PropertyMapEntry
&);
122 void checkConsistency();
124 PropertyMapHashTable
* copyPropertyTable();
125 void materializePropertyMap();
126 void materializePropertyMapIfNecessary()
128 if (m_propertyTable
|| !m_previous
)
130 materializePropertyMap();
133 void clearEnumerationCache();
135 void* addressOfCount()
140 signed char transitionCount() const
142 // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
143 return m_offset
== noOffset
? 0 : m_offset
+ 1;
146 bool isValid(ExecState
*, StructureChain
* cachedPrototypeChain
) const;
148 static const unsigned emptyEntryIndex
= 0;
150 static const signed char s_maxTransitionLength
= 64;
152 static const signed char noOffset
= -1;
156 JSValuePtr m_prototype
;
157 mutable RefPtr
<StructureChain
> m_cachedPrototypeChain
;
159 RefPtr
<Structure
> m_previous
;
160 RefPtr
<UString::Rep
> m_nameInPrevious
;
163 Structure
* singleTransition
;
164 StructureTransitionTable
* table
;
167 RefPtr
<PropertyNameArrayData
> m_cachedPropertyNameArrayData
;
169 PropertyMapHashTable
* m_propertyTable
;
171 size_t m_propertyStorageCapacity
;
172 signed char m_offset
;
174 bool m_isDictionary
: 1;
175 bool m_isPinnedPropertyTable
: 1;
176 bool m_hasGetterSetterProperties
: 1;
177 bool m_usingSingleTransitionSlot
: 1;
178 unsigned m_attributesInPrevious
: 5;
181 inline size_t Structure::get(const Identifier
& propertyName
)
183 ASSERT(!propertyName
.isNull());
185 materializePropertyMapIfNecessary();
186 if (!m_propertyTable
)
187 return WTF::notFound
;
189 UString::Rep
* rep
= propertyName
._ustring
.rep();
191 unsigned i
= rep
->computedHash();
193 #if DUMP_PROPERTYMAP_STATS
197 unsigned entryIndex
= m_propertyTable
->entryIndices
[i
& m_propertyTable
->sizeMask
];
198 if (entryIndex
== emptyEntryIndex
)
199 return WTF::notFound
;
201 if (rep
== m_propertyTable
->entries()[entryIndex
- 1].key
)
202 return m_propertyTable
->entries()[entryIndex
- 1].offset
;
204 #if DUMP_PROPERTYMAP_STATS
208 unsigned k
= 1 | WTF::doubleHash(rep
->computedHash());
213 #if DUMP_PROPERTYMAP_STATS
217 entryIndex
= m_propertyTable
->entryIndices
[i
& m_propertyTable
->sizeMask
];
218 if (entryIndex
== emptyEntryIndex
)
219 return WTF::notFound
;
221 if (rep
== m_propertyTable
->entries()[entryIndex
- 1].key
)
222 return m_propertyTable
->entries()[entryIndex
- 1].offset
;
228 #endif // Structure_h