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