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"
33 #include "PropertyMapHashTable.h"
34 #include "PropertyNameArray.h"
36 #include "StructureTransitionTable.h"
37 #include "JSTypeInfo.h"
40 #include <wtf/PassOwnPtr.h>
41 #include <wtf/PassRefPtr.h>
42 #include <wtf/RefCounted.h>
47 class PropertyNameArray;
48 class PropertyNameArrayData;
54 enum EnumerationMode {
55 ExcludeDontEnumProperties,
56 IncludeDontEnumProperties
59 class Structure : public JSCell {
61 friend class StructureTransitionTable;
65 static Structure* create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo)
67 ASSERT(globalData.structureStructure);
69 Structure* structure = new (allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo);
70 structure->finishCreation(globalData);
75 void finishCreation(JSGlobalData& globalData)
77 Base::finishCreation(globalData);
79 ASSERT(m_prototype.isObject() || m_prototype.isNull());
82 void finishCreation(JSGlobalData& globalData, CreatingEarlyCellTag)
84 Base::finishCreation(globalData, this, CreatingEarlyCell);
86 ASSERT(m_prototype.isNull());
87 ASSERT(!globalData.structureStructure);
91 static void dumpStatistics();
93 static Structure* addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
94 static Structure* addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
95 static Structure* removePropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, size_t& offset);
96 static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype);
97 static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, const Identifier&);
98 static Structure* getterSetterTransition(JSGlobalData&, Structure*);
99 static Structure* toCacheableDictionaryTransition(JSGlobalData&, Structure*);
100 static Structure* toUncacheableDictionaryTransition(JSGlobalData&, Structure*);
101 static Structure* sealTransition(JSGlobalData&, Structure*);
102 static Structure* freezeTransition(JSGlobalData&, Structure*);
103 static Structure* preventExtensionsTransition(JSGlobalData&, Structure*);
105 bool isSealed(JSGlobalData&);
106 bool isFrozen(JSGlobalData&);
107 bool isExtensible() const { return !m_preventExtensions; }
108 bool didTransition() const { return m_didTransition; }
110 Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
114 // These should be used with caution.
115 size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
116 size_t removePropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName);
117 void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); }
119 bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
120 bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
122 const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; }
124 JSGlobalObject* globalObject() const { return m_globalObject.get(); }
125 void setGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject) { m_globalObject.set(globalData, this, globalObject); }
127 JSValue storedPrototype() const { return m_prototype.get(); }
128 JSValue prototypeForLookup(ExecState*) const;
129 StructureChain* prototypeChain(ExecState*) const;
130 void visitChildren(SlotVisitor&);
132 Structure* previousID() const { ASSERT(structure()->classInfo() == &s_info); return m_previous.get(); }
134 void growPropertyStorageCapacity();
135 unsigned propertyStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); return m_propertyStorageCapacity; }
136 unsigned propertyStorageSize() const { ASSERT(structure()->classInfo() == &s_info); return (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
137 bool isUsingInlineStorage() const;
139 size_t get(JSGlobalData&, const Identifier& propertyName);
140 size_t get(JSGlobalData&, const UString& name);
141 size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
142 size_t get(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
144 ASSERT(!propertyName.isNull());
145 ASSERT(structure()->classInfo() == &s_info);
146 return get(globalData, propertyName.impl(), attributes, specificValue);
149 bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
150 void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
152 bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
154 bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
156 void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName);
157 void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
159 void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
160 JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
161 void getPropertyNames(JSGlobalData&, PropertyNameArray&, EnumerationMode mode);
163 const ClassInfo* classInfo() const { return m_classInfo; }
165 static ptrdiff_t prototypeOffset()
167 return OBJECT_OFFSETOF(Structure, m_prototype);
170 static ptrdiff_t typeInfoFlagsOffset()
172 return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
175 static ptrdiff_t typeInfoTypeOffset()
177 return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
180 static Structure* createStructure(JSGlobalData& globalData)
182 ASSERT(!globalData.structureStructure);
183 Structure* structure = new (allocateCell<Structure>(globalData.heap)) Structure(globalData);
184 structure->finishCreation(globalData, CreatingEarlyCell);
188 static JS_EXPORTDATA const ClassInfo s_info;
191 Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*);
192 Structure(JSGlobalData&);
193 Structure(JSGlobalData&, const Structure*);
195 static Structure* create(JSGlobalData& globalData, const Structure* structure)
197 ASSERT(globalData.structureStructure);
198 Structure* newStructure = new (allocateCell<Structure>(globalData.heap)) Structure(globalData, structure);
199 newStructure->finishCreation(globalData);
204 NoneDictionaryKind = 0,
205 CachedDictionaryKind = 1,
206 UncachedDictionaryKind = 2
208 static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
210 size_t putSpecificValue(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
211 size_t remove(const Identifier& propertyName);
213 void createPropertyMap(unsigned keyCount = 0);
214 void checkConsistency();
216 bool despecifyFunction(JSGlobalData&, const Identifier&);
217 void despecifyAllFunctions(JSGlobalData&);
219 PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
220 void materializePropertyMap(JSGlobalData&);
221 void materializePropertyMapIfNecessary(JSGlobalData& globalData)
223 ASSERT(structure()->classInfo() == &s_info);
224 if (!m_propertyTable && m_previous)
225 materializePropertyMap(globalData);
228 signed char transitionCount() const
230 // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
231 return m_offset == noOffset ? 0 : m_offset + 1;
234 bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
236 static const signed char s_maxTransitionLength = 64;
238 static const signed char noOffset = -1;
240 static const unsigned maxSpecificFunctionThrashCount = 3;
244 WriteBarrier<JSGlobalObject> m_globalObject;
245 WriteBarrier<Unknown> m_prototype;
246 mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
248 WriteBarrier<Structure> m_previous;
249 RefPtr<StringImpl> m_nameInPrevious;
250 WriteBarrier<JSCell> m_specificValueInPrevious;
252 const ClassInfo* m_classInfo;
254 StructureTransitionTable m_transitionTable;
256 WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
258 OwnPtr<PropertyTable> m_propertyTable;
260 uint32_t m_propertyStorageCapacity;
262 // m_offset does not account for anonymous slots
263 signed char m_offset;
265 unsigned m_dictionaryKind : 2;
266 bool m_isPinnedPropertyTable : 1;
267 bool m_hasGetterSetterProperties : 1;
268 bool m_hasNonEnumerableProperties : 1;
270 // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared
271 // bitfield, when used as argument in make_pair() function calls in structure.ccp.
272 // This bitfield optimization is insignificant for the Symbian emulator target.
273 unsigned m_attributesInPrevious;
275 unsigned m_attributesInPrevious : 7;
277 unsigned m_specificFunctionThrashCount : 2;
278 unsigned m_preventExtensions : 1;
279 unsigned m_didTransition : 1;
283 inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName)
285 ASSERT(structure()->classInfo() == &s_info);
286 materializePropertyMapIfNecessary(globalData);
287 if (!m_propertyTable)
290 PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
291 return entry ? entry->offset : notFound;
294 inline size_t Structure::get(JSGlobalData& globalData, const UString& name)
296 ASSERT(structure()->classInfo() == &s_info);
297 materializePropertyMapIfNecessary(globalData);
298 if (!m_propertyTable)
301 PropertyMapEntry* entry = m_propertyTable->findWithString(name.impl()).first;
302 return entry ? entry->offset : notFound;
305 inline bool JSCell::isObject() const
307 return m_structure->typeInfo().type() == ObjectType;
310 inline bool JSCell::isString() const
312 return m_structure->typeInfo().type() == StringType;
315 inline bool JSCell::isGetterSetter() const
317 return m_structure->typeInfo().type() == GetterSetterType;
320 inline bool JSCell::isAPIValueWrapper() const
322 return m_structure->typeInfo().type() == APIValueWrapper;
325 inline const ClassInfo* JSCell::classInfo() const
327 #if ENABLE(GC_VALIDATION)
328 return m_structure.unvalidatedGet()->classInfo();
330 return m_structure->classInfo();
334 ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell)
336 ASSERT(!m_isCheckingForDefaultMarkViolation);
338 if (Heap::testAndSetMarked(cell))
340 if (cell->structure() && cell->structure()->typeInfo().type() >= CompoundType)
341 m_values.append(cell);
344 inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure)
346 // Newer versions of the STL have an std::make_pair function that takes rvalue references.
347 // 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.
348 // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details.
349 return Hash::Key(structure->m_nameInPrevious.get(), +structure->m_attributesInPrevious);
354 #endif // Structure_h