Structure.h 11.7 KB
Newer Older
weinig@apple.com's avatar
weinig@apple.com committed
1
/*
2
 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
weinig@apple.com's avatar
weinig@apple.com committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

darin@apple.com's avatar
darin@apple.com committed
26 27
#ifndef Structure_h
#define Structure_h
weinig@apple.com's avatar
weinig@apple.com committed
28

29
#include "Identifier.h"
30
#include "JSCell.h"
31
#include "JSType.h"
weinig@apple.com's avatar
weinig@apple.com committed
32
#include "JSValue.h"
33
#include "PropertyMapHashTable.h"
34
#include "PropertyNameArray.h"
35
#include "Protect.h"
darin@apple.com's avatar
darin@apple.com committed
36
#include "StructureTransitionTable.h"
37
#include "JSTypeInfo.h"
38
#include "UString.h"
39
#include "WeakGCPtr.h"
weinig@apple.com's avatar
weinig@apple.com committed
40 41 42
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>

43

44
namespace JSC {
weinig@apple.com's avatar
weinig@apple.com committed
45

46
    class MarkStack;
47
    class PropertyNameArray;
48
    class PropertyNameArrayData;
49
    class StructureChain;
weinig@apple.com's avatar
weinig@apple.com committed
50

51 52
    struct ClassInfo;

53 54 55 56 57
    enum EnumerationMode {
        ExcludeDontEnumProperties,
        IncludeDontEnumProperties
    };

darin@apple.com's avatar
darin@apple.com committed
58
    class Structure : public RefCounted<Structure> {
weinig@apple.com's avatar
weinig@apple.com committed
59
    public:
60
        friend class StructureTransitionTable;
61
        static PassRefPtr<Structure> create(JSGlobalData&, JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo)
weinig@apple.com's avatar
weinig@apple.com committed
62
        {
63
            return adoptRef(new Structure(prototype, typeInfo, anonymousSlotCount, classInfo));
weinig@apple.com's avatar
weinig@apple.com committed
64
        }
weinig@apple.com's avatar
weinig@apple.com committed
65

66 67 68 69 70 71
        enum VPtrStealingHackType { VPtrStealingHack };
        static PassRefPtr<Structure> create(VPtrStealingHackType, const ClassInfo* classInfo)
        {
            return adoptRef(new Structure(jsNull(), TypeInfo(UnspecifiedType), 0, classInfo));
        }

weinig@apple.com's avatar
weinig@apple.com committed
72 73 74
        static void startIgnoringLeaks();
        static void stopIgnoringLeaks();

75 76
        static void dumpStatistics();

77
        static PassRefPtr<Structure> addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
78
        static PassRefPtr<Structure> addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
darin@apple.com's avatar
darin@apple.com committed
79
        static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset);
ggaren@apple.com's avatar
ggaren@apple.com committed
80
        static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype);
81
        static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&);
darin@apple.com's avatar
darin@apple.com committed
82
        static PassRefPtr<Structure> getterSetterTransition(Structure*);
83 84
        static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*);
        static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*);
85 86 87 88 89 90 91
        static PassRefPtr<Structure> sealTransition(Structure*);
        static PassRefPtr<Structure> freezeTransition(Structure*);
        static PassRefPtr<Structure> preventExtensionsTransition(Structure*);

        bool isSealed();
        bool isFrozen();
        bool isExtensible() const { return !m_preventExtensions; }
92

93
        PassRefPtr<Structure> flattenDictionaryStructure(JSGlobalData&, JSObject*);
weinig@apple.com's avatar
weinig@apple.com committed
94

darin@apple.com's avatar
darin@apple.com committed
95
        ~Structure();
weinig@apple.com's avatar
weinig@apple.com committed
96

97
        // These should be used with caution.  
98
        size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
99
        size_t removePropertyWithoutTransition(const Identifier& propertyName);
ggaren@apple.com's avatar
ggaren@apple.com committed
100
        void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; }
101 102 103
        
        bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
        bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
weinig@apple.com's avatar
weinig@apple.com committed
104

mjs@apple.com's avatar
mjs@apple.com committed
105
        const TypeInfo& typeInfo() const { return m_typeInfo; }
106

107
        JSValue storedPrototype() const { return m_prototype.get(); }
ggaren@apple.com's avatar
ggaren@apple.com committed
108
        JSValue prototypeForLookup(ExecState*) const;
ggaren@apple.com's avatar
ggaren@apple.com committed
109
        StructureChain* prototypeChain(ExecState*) const;
110 111 112 113 114
        void markAggregate(MarkStack& markStack)
        {
            if (m_prototype)
                markStack.append(&m_prototype);
        }
115

darin@apple.com's avatar
darin@apple.com committed
116
        Structure* previousID() const { return m_previous.get(); }
117

118
        void growPropertyStorageCapacity();
119
        unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity; }
120
        unsigned propertyStorageSize() const { return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
121
        bool isUsingInlineStorage() const;
122

123
        size_t get(const Identifier& propertyName);
124
        size_t get(StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
125 126 127
        size_t get(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
        {
            ASSERT(!propertyName.isNull());
128
            return get(propertyName.impl(), attributes, specificValue);
129 130
        }

131 132 133
        bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
        void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }

134 135
        bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }

136 137
        bool hasAnonymousSlots() const { return !!m_anonymousSlotCount; }
        unsigned anonymousSlotCount() const { return m_anonymousSlotCount; }
138
        
139
        bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
140

141
        void despecifyDictionaryFunction(const Identifier& propertyName);
142
        void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
143

144 145
        void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
        void clearEnumerationCache(); // Defined in JSPropertyNameIterator.h.
146
        JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
147
        void getPropertyNames(PropertyNameArray&, EnumerationMode mode);
148 149 150

        const ClassInfo* classInfo() const { return m_classInfo; }

151 152
        static void initializeThreading();

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
        static ptrdiff_t prototypeOffset()
        {
            return OBJECT_OFFSETOF(Structure, m_prototype);
        }

        static ptrdiff_t typeInfoFlagsOffset()
        {
            return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
        }

        static ptrdiff_t typeInfoTypeOffset()
        {
            return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
        }

weinig@apple.com's avatar
weinig@apple.com committed
168
    private:
169 170
        Structure(JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount, const ClassInfo*);
        Structure(const Structure*);
171

172 173 174 175
        static PassRefPtr<Structure> create(const Structure* structure)
        {
            return adoptRef(new Structure(structure));
        }
176 177 178 179 180 181 182
        
        typedef enum { 
            NoneDictionaryKind = 0,
            CachedDictionaryKind = 1,
            UncachedDictionaryKind = 2
        } DictionaryKind;
        static PassRefPtr<Structure> toDictionaryTransition(Structure*, DictionaryKind);
183

184
        size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
185 186
        size_t remove(const Identifier& propertyName);

187
        void createPropertyMap(unsigned keyCount = 0);
188 189
        void checkConsistency();

190
        bool despecifyFunction(const Identifier&);
191
        void despecifyAllFunctions();
192

193
        PropertyTable* copyPropertyTable();
194 195 196
        void materializePropertyMap();
        void materializePropertyMapIfNecessary()
        {
197 198
            if (!m_propertyTable && m_previous)
                materializePropertyMap();
199
        }
200

201 202 203 204 205
        signed char transitionCount() const
        {
            // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
            return m_offset == noOffset ? 0 : m_offset + 1;
        }
206

ggaren@apple.com's avatar
ggaren@apple.com committed
207
        bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
208 209 210 211

        static const signed char s_maxTransitionLength = 64;

        static const signed char noOffset = -1;
weinig@apple.com's avatar
weinig@apple.com committed
212

213 214
        static const unsigned maxSpecificFunctionThrashCount = 3;

mjs@apple.com's avatar
mjs@apple.com committed
215 216
        TypeInfo m_typeInfo;

217
        DeprecatedPtr<Unknown> m_prototype;
218
        mutable WeakGCPtr<StructureChain> m_cachedPrototypeChain;
weinig@apple.com's avatar
weinig@apple.com committed
219

darin@apple.com's avatar
darin@apple.com committed
220
        RefPtr<Structure> m_previous;
221
        RefPtr<StringImpl> m_nameInPrevious;
222
        JSCell* m_specificValueInPrevious;
weinig@apple.com's avatar
weinig@apple.com committed
223

224 225
        const ClassInfo* m_classInfo;

226
        StructureTransitionTable m_transitionTable;
weinig@apple.com's avatar
weinig@apple.com committed
227

228
        WeakGCPtr<JSPropertyNameIterator> m_enumerationCache;
229

230
        OwnPtr<PropertyTable> m_propertyTable;
231

232
        uint32_t m_propertyStorageCapacity;
233 234

        // m_offset does not account for anonymous slots
235
        signed char m_offset;
236

237
        unsigned m_dictionaryKind : 2;
238
        bool m_isPinnedPropertyTable : 1;
239
        bool m_hasGetterSetterProperties : 1;
240
        bool m_hasNonEnumerableProperties : 1;
241 242 243 244 245 246
#if COMPILER(WINSCW)
        // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared 
        // bitfield, when used as argument in make_pair() function calls in structure.ccp.
        // This bitfield optimization is insignificant for the Symbian emulator target.
        unsigned m_attributesInPrevious;
#else
247
        unsigned m_attributesInPrevious : 7;
248
#endif
249
        unsigned m_specificFunctionThrashCount : 2;
250
        unsigned m_anonymousSlotCount : 5;
251 252
        unsigned m_preventExtensions : 1;
        // 4 free bits
weinig@apple.com's avatar
weinig@apple.com committed
253 254
    };

darin@apple.com's avatar
darin@apple.com committed
255
    inline size_t Structure::get(const Identifier& propertyName)
256
    {
257
        materializePropertyMapIfNecessary();
258
        if (!m_propertyTable)
259
            return notFound;
260

261 262 263
        PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
        ASSERT(!entry || entry->offset >= m_anonymousSlotCount);
        return entry ? entry->offset : notFound;
264 265
    }

266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
    inline bool JSCell::isObject() const
    {
        return m_structure->typeInfo().type() == ObjectType;
    }

    inline bool JSCell::isString() const
    {
        return m_structure->typeInfo().type() == StringType;
    }

    inline const ClassInfo* JSCell::classInfo() const
    {
        return m_structure->classInfo();
    }

    inline PassRefPtr<Structure> JSCell::createDummyStructure(JSGlobalData& globalData)
    {
        return Structure::create(globalData, jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount, 0);
    }

    inline bool JSValue::needsThisConversion() const
    {
        if (UNLIKELY(!isCell()))
            return true;
        return asCell()->structure()->typeInfo().needsThisConversion();
    }

    ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell)
    {
        ASSERT(!m_isCheckingForDefaultMarkViolation);
        ASSERT(cell);
        if (Heap::testAndSetMarked(cell))
            return;
        if (cell->structure()->typeInfo().type() >= CompoundType)
            m_values.append(cell);
    }

303
} // namespace JSC
weinig@apple.com's avatar
weinig@apple.com committed
304

darin@apple.com's avatar
darin@apple.com committed
305
#endif // Structure_h