Home | History | Annotate | Download | only in runtime
      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