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