Structure.h 14.3 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 "Weak.h"
40
#include <wtf/PassOwnPtr.h>
weinig@apple.com's avatar
weinig@apple.com committed
41 42 43
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>

44

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

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

52 53
    struct ClassInfo;

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

59
    class Structure : public JSCell {
weinig@apple.com's avatar
weinig@apple.com committed
60
    public:
61
        friend class StructureTransitionTable;
62 63 64

        typedef JSCell Base;

65
        static Structure* create(JSGlobalData& globalData, JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo)
weinig@apple.com's avatar
weinig@apple.com committed
66
        {
67
            ASSERT(globalData.structureStructure);
68
            ASSERT(classInfo);
69 70 71
            Structure* structure = new (allocateCell<Structure>(globalData.heap)) Structure(globalData, prototype, typeInfo, anonymousSlotCount, classInfo);
            structure->finishCreation(globalData);
            return structure;
weinig@apple.com's avatar
weinig@apple.com committed
72
        }
weinig@apple.com's avatar
weinig@apple.com committed
73

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
    protected:
        void finishCreation(JSGlobalData& globalData)
        {
            Base::finishCreation(globalData);
            ASSERT(m_prototype);
            ASSERT(m_prototype.isObject() || m_prototype.isNull());
        }

        void finishCreation(JSGlobalData& globalData, CreatingEarlyCellTag)
        {
            Base::finishCreation(globalData, this, CreatingEarlyCell);
            ASSERT(m_prototype);
            ASSERT(m_prototype.isNull());
            ASSERT(!globalData.structureStructure);
        }

    public:
91 92
        static void dumpStatistics();

93 94 95 96 97 98 99 100 101 102 103
        static Structure* addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
        static Structure* addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
        static Structure* removePropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, size_t& offset);
        static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype);
        static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, const Identifier&);
        static Structure* getterSetterTransition(JSGlobalData&, Structure*);
        static Structure* toCacheableDictionaryTransition(JSGlobalData&, Structure*);
        static Structure* toUncacheableDictionaryTransition(JSGlobalData&, Structure*);
        static Structure* sealTransition(JSGlobalData&, Structure*);
        static Structure* freezeTransition(JSGlobalData&, Structure*);
        static Structure* preventExtensionsTransition(JSGlobalData&, Structure*);
104 105 106

        bool isSealed(JSGlobalData&);
        bool isFrozen(JSGlobalData&);
107
        bool isExtensible() const { return !m_preventExtensions; }
108
        bool didTransition() const { return m_didTransition; }
109

110
        Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
weinig@apple.com's avatar
weinig@apple.com committed
111

darin@apple.com's avatar
darin@apple.com committed
112
        ~Structure();
weinig@apple.com's avatar
weinig@apple.com committed
113

114
        // These should be used with caution.  
115 116
        size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
        size_t removePropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName);
117
        void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); }
118 119 120
        
        bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
        bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
weinig@apple.com's avatar
weinig@apple.com committed
121

jberlin@webkit.org's avatar
jberlin@webkit.org committed
122
        const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; }
123

124
        JSValue storedPrototype() const { return m_prototype.get(); }
ggaren@apple.com's avatar
ggaren@apple.com committed
125
        JSValue prototypeForLookup(ExecState*) const;
ggaren@apple.com's avatar
ggaren@apple.com committed
126
        StructureChain* prototypeChain(ExecState*) const;
127
        void visitChildren(SlotVisitor&);
128

jberlin@webkit.org's avatar
jberlin@webkit.org committed
129
        Structure* previousID() const { ASSERT(structure()->classInfo() == &s_info); return m_previous.get(); }
130

131
        void growPropertyStorageCapacity();
jberlin@webkit.org's avatar
jberlin@webkit.org committed
132 133
        unsigned propertyStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); return m_propertyStorageCapacity; }
        unsigned propertyStorageSize() const { ASSERT(structure()->classInfo() == &s_info); return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
134
        bool isUsingInlineStorage() const;
135

136
        size_t get(JSGlobalData&, const Identifier& propertyName);
137
        size_t get(JSGlobalData&, const UString& name);
138 139
        size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
        size_t get(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
140 141
        {
            ASSERT(!propertyName.isNull());
jberlin@webkit.org's avatar
jberlin@webkit.org committed
142
            ASSERT(structure()->classInfo() == &s_info);
143
            return get(globalData, propertyName.impl(), attributes, specificValue);
144 145
        }

146 147 148
        bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
        void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }

149 150
        bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }

151 152
        bool hasAnonymousSlots() const { return !!m_anonymousSlotCount; }
        unsigned anonymousSlotCount() const { return m_anonymousSlotCount; }
153
        
154
        bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
155

156
        void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName);
157
        void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
158

159
        void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
160
        JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
161
        void getPropertyNames(JSGlobalData&, PropertyNameArray&, EnumerationMode mode);
162 163 164

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

165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
        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();
        }

180 181 182
        static Structure* createStructure(JSGlobalData& globalData)
        {
            ASSERT(!globalData.structureStructure);
183 184 185
            Structure* structure = new (allocateCell<Structure>(globalData.heap)) Structure(globalData);
            structure->finishCreation(globalData, CreatingEarlyCell);
            return structure;
186
        }
187 188
        
        static JS_EXPORTDATA const ClassInfo s_info;
189

weinig@apple.com's avatar
weinig@apple.com committed
190
    private:
191 192 193
        Structure(JSGlobalData&, JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount, const ClassInfo*);
        Structure(JSGlobalData&);
        Structure(JSGlobalData&, const Structure*);
194

195
        static Structure* create(JSGlobalData& globalData, const Structure* structure)
196
        {
197
            ASSERT(globalData.structureStructure);
198 199 200
            Structure* newStructure = new (allocateCell<Structure>(globalData.heap)) Structure(globalData, structure);
            newStructure->finishCreation(globalData);
            return newStructure;
201
        }
202
        
203 204 205 206 207
        typedef enum { 
            NoneDictionaryKind = 0,
            CachedDictionaryKind = 1,
            UncachedDictionaryKind = 2
        } DictionaryKind;
208
        static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
209

210
        size_t putSpecificValue(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
211 212
        size_t remove(const Identifier& propertyName);

213
        void createPropertyMap(unsigned keyCount = 0);
214 215
        void checkConsistency();

216 217
        bool despecifyFunction(JSGlobalData&, const Identifier&);
        void despecifyAllFunctions(JSGlobalData&);
218

219
        PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
220 221
        void materializePropertyMap(JSGlobalData&);
        void materializePropertyMapIfNecessary(JSGlobalData& globalData)
222
        {
jberlin@webkit.org's avatar
jberlin@webkit.org committed
223
            ASSERT(structure()->classInfo() == &s_info);
224
            if (!m_propertyTable && m_previous)
225
                materializePropertyMap(globalData);
226
        }
227

228 229 230 231 232
        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;
        }
233

ggaren@apple.com's avatar
ggaren@apple.com committed
234
        bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
235 236 237 238

        static const signed char s_maxTransitionLength = 64;

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

240 241
        static const unsigned maxSpecificFunctionThrashCount = 3;

mjs@apple.com's avatar
mjs@apple.com committed
242 243
        TypeInfo m_typeInfo;

244 245
        WriteBarrier<Unknown> m_prototype;
        mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
weinig@apple.com's avatar
weinig@apple.com committed
246

247
        WriteBarrier<Structure> m_previous;
248
        RefPtr<StringImpl> m_nameInPrevious;
249
        WriteBarrier<JSCell> m_specificValueInPrevious;
weinig@apple.com's avatar
weinig@apple.com committed
250

251 252
        const ClassInfo* m_classInfo;

253
        StructureTransitionTable m_transitionTable;
weinig@apple.com's avatar
weinig@apple.com committed
254

255
        WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
256

257
        OwnPtr<PropertyTable> m_propertyTable;
258

259
        uint32_t m_propertyStorageCapacity;
260 261

        // m_offset does not account for anonymous slots
262
        signed char m_offset;
263

264
        unsigned m_dictionaryKind : 2;
265
        bool m_isPinnedPropertyTable : 1;
266
        bool m_hasGetterSetterProperties : 1;
267
        bool m_hasNonEnumerableProperties : 1;
268 269 270 271 272 273
#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
274
        unsigned m_attributesInPrevious : 7;
275
#endif
276
        unsigned m_specificFunctionThrashCount : 2;
277
        unsigned m_anonymousSlotCount : 5;
278
        unsigned m_preventExtensions : 1;
279 280
        unsigned m_didTransition : 1;
        // 3 free bits
weinig@apple.com's avatar
weinig@apple.com committed
281 282
    };

283
    inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName)
284
    {
jberlin@webkit.org's avatar
jberlin@webkit.org committed
285
        ASSERT(structure()->classInfo() == &s_info);
286
        materializePropertyMapIfNecessary(globalData);
287
        if (!m_propertyTable)
288
            return notFound;
289

290 291 292
        PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
        ASSERT(!entry || entry->offset >= m_anonymousSlotCount);
        return entry ? entry->offset : notFound;
293 294
    }

295 296 297 298 299 300 301 302 303 304 305 306
    inline size_t Structure::get(JSGlobalData& globalData, const UString& name)
    {
        ASSERT(structure()->classInfo() == &s_info);
        materializePropertyMapIfNecessary(globalData);
        if (!m_propertyTable)
            return notFound;

        PropertyMapEntry* entry = m_propertyTable->findWithString(name.impl()).first;
        ASSERT(!entry || entry->offset >= m_anonymousSlotCount);
        return entry ? entry->offset : notFound;
    }

307 308 309 310 311 312 313 314 315 316 317 318
    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
    {
319 320 321
#if ENABLE(GC_VALIDATION)
        return m_structure.unvalidatedGet()->classInfo();
#else
322
        return m_structure->classInfo();
323
#endif
324 325 326 327 328 329 330 331
    }

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

336 337
    inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure)
    {
338 339 340 341
        // Newer versions of the STL have an std::make_pair function that takes rvalue references.
        // 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.
        // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details.
        return Hash::Key(structure->m_nameInPrevious.get(), +structure->m_attributesInPrevious);
342 343
    }

344
} // namespace JSC
weinig@apple.com's avatar
weinig@apple.com committed
345

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