]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Structure.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / Structure.h
index 55b7186089dc7b2c6ddc1ef0a1aa71c11c4cdbcd..25a97fedd341a96abcb66d930b88887d93954f0e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2012, 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  *    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
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE 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
 #ifndef Structure_h
 #define Structure_h
 
-#include "Identifier.h"
+#include "ClassInfo.h"
+#include "ConcurrentJITLock.h"
+#include "IndexingType.h"
+#include "JSCJSValue.h"
+#include "JSCell.h"
 #include "JSType.h"
-#include "JSValue.h"
-#include "PropertyMapHashTable.h"
-#include "StructureChain.h"
+#include "PropertyName.h"
+#include "PropertyNameArray.h"
+#include "PropertyOffset.h"
+#include "Protect.h"
+#include "PutPropertySlot.h"
+#include "StructureIDBlob.h"
+#include "StructureRareData.h"
 #include "StructureTransitionTable.h"
-#include "TypeInfo.h"
-#include "UString.h"
+#include "JSTypeInfo.h"
+#include "Watchpoint.h"
+#include "Weak.h"
+#include "WriteBarrierInlines.h"
+#include <wtf/CompilationThread.h>
 #include <wtf/PassRefPtr.h>
+#include <wtf/PrintStream.h>
 #include <wtf/RefCounted.h>
 
-#ifndef NDEBUG
-#define DUMP_PROPERTYMAP_STATS 0
-#else
-#define DUMP_PROPERTYMAP_STATS 0
-#endif
+namespace WTF {
+
+class UniquedStringImpl;
+
+} // namespace WTF
 
 namespace JSC {
 
-    class PropertyNameArray;
-    class PropertyNameArrayData;
+class DeferGC;
+class LLIntOffsetsExtractor;
+class PropertyNameArray;
+class PropertyNameArrayData;
+class PropertyTable;
+class StructureChain;
+class StructureShape;
+class SlotVisitor;
+class JSString;
+struct DumpContext;
+
+// The out-of-line property storage capacity to use when first allocating out-of-line
+// storage. Note that all objects start out without having any out-of-line storage;
+// this comes into play only on the first property store that exhausts inline storage.
+static const unsigned initialOutOfLineCapacity = 4;
+
+// The factor by which to grow out-of-line storage when it is exhausted, after the
+// initial allocation.
+static const unsigned outOfLineGrowthFactor = 2;
+
+struct PropertyMapEntry {
+    UniquedStringImpl* key;
+    PropertyOffset offset;
+    unsigned attributes;
+
+    PropertyMapEntry()
+        : key(nullptr)
+        , offset(invalidOffset)
+        , attributes(0)
+    {
+    }
+    
+    PropertyMapEntry(UniquedStringImpl* key, PropertyOffset offset, unsigned attributes)
+        : key(key)
+        , offset(offset)
+        , attributes(attributes)
+    {
+    }
+};
 
-    class Structure : public RefCounted<Structure> {
-    public:
-        friend class JIT;
-        static PassRefPtr<Structure> create(JSValue prototype, const TypeInfo& typeInfo)
-        {
-            return adoptRef(new Structure(prototype, typeInfo));
-        }
+class Structure final : public JSCell {
+public:
+    friend class StructureTransitionTable;
 
-        static void startIgnoringLeaks();
-        static void stopIgnoringLeaks();
+    typedef JSCell Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+    
+    static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
 
-        static void dumpStatistics();
+    ~Structure();
 
-        static PassRefPtr<Structure> addPropertyTransition(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
-        static PassRefPtr<Structure> addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
-        static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset);
-        static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype);
-        static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&);        
-        static PassRefPtr<Structure> getterSetterTransition(Structure*);
-        static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*);
-        static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*);
+protected:
+    void finishCreation(VM& vm)
+    {
+        Base::finishCreation(vm);
+        ASSERT(m_prototype);
+        ASSERT(m_prototype.isObject() || m_prototype.isNull());
+    }
 
-        PassRefPtr<Structure> flattenDictionaryStructure(JSObject*);
+    void finishCreation(VM& vm, CreatingEarlyCellTag)
+    {
+        Base::finishCreation(vm, this, CreatingEarlyCell);
+        ASSERT(m_prototype);
+        ASSERT(m_prototype.isNull());
+        ASSERT(!vm.structureStructure);
+    }
 
-        ~Structure();
+public:
+    StructureID id() const { return m_blob.structureID(); }
+    int32_t objectInitializationBlob() const { return m_blob.blobExcludingStructureID(); }
+    int64_t idBlob() const { return m_blob.blob(); }
 
-        void mark()
-        {
-            if (!m_prototype.marked())
-                m_prototype.mark();
-        }
+    bool isProxy() const
+    {
+        JSType type = m_blob.type();
+        return type == ImpureProxyType || type == PureForwardingProxyType;
+    }
 
-        // These should be used with caution.  
-        size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
-        size_t removePropertyWithoutTransition(const Identifier& propertyName);
-        void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; }
+    static void dumpStatistics();
+
+    JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext);
+    static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
+    JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
+    static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&);
+    JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype);
+    JS_EXPORT_PRIVATE static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes);
+    JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*);
+    static Structure* toUncacheableDictionaryTransition(VM&, Structure*);
+    JS_EXPORT_PRIVATE static Structure* sealTransition(VM&, Structure*);
+    JS_EXPORT_PRIVATE static Structure* freezeTransition(VM&, Structure*);
+    static Structure* preventExtensionsTransition(VM&, Structure*);
+    JS_EXPORT_PRIVATE static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition);
+
+    JS_EXPORT_PRIVATE bool isSealed(VM&);
+    JS_EXPORT_PRIVATE bool isFrozen(VM&);
+    bool isExtensible() const { return !preventExtensions(); }
+    bool putWillGrowOutOfLineStorage();
+    size_t suggestedNewOutOfLineStorageCapacity(); 
+
+    JS_EXPORT_PRIVATE Structure* flattenDictionaryStructure(VM&, JSObject*);
+
+    static const bool needsDestruction = true;
+    static void destroy(JSCell*);
+
+    // These should be used with caution.  
+    JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes);
+    PropertyOffset removePropertyWithoutTransition(VM&, PropertyName);
+    void setPrototypeWithoutTransition(VM& vm, JSValue prototype) { m_prototype.set(vm, this, prototype); }
         
-        bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
-        bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
+    bool isDictionary() const { return dictionaryKind() != NoneDictionaryKind; }
+    bool isUncacheableDictionary() const { return dictionaryKind() == UncachedDictionaryKind; }
+  
+    bool propertyAccessesAreCacheable() { return dictionaryKind() != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); }
+
+    // We use SlowPath in GetByIdStatus for structures that may get new impure properties later to prevent
+    // DFG from inlining property accesses since structures don't transition when a new impure property appears.
+    bool takesSlowPathInDFGForImpureProperty()
+    {
+        return typeInfo().hasImpureGetOwnPropertySlot();
+    }
+
+    // Type accessors.
+    TypeInfo typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_blob.typeInfo(m_outOfLineTypeFlags); }
+    bool isObject() const { return typeInfo().isObject(); }
 
-        const TypeInfo& typeInfo() const { return m_typeInfo; }
+    IndexingType indexingType() const { return m_blob.indexingType() & AllArrayTypes; }
+    IndexingType indexingTypeIncludingHistory() const { return m_blob.indexingType(); }
+        
+    bool mayInterceptIndexedAccesses() const
+    {
+        return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors);
+    }
+        
+    bool anyObjectInChainMayInterceptIndexedAccesses() const;
+    bool holesMustForwardToPrototype(VM&) const;
+        
+    bool needsSlowPutIndexing() const;
+    NonPropertyTransition suggestedArrayStorageTransition() const;
+        
+    JSGlobalObject* globalObject() const { return m_globalObject.get(); }
+    void setGlobalObject(VM& vm, JSGlobalObject* globalObject) { m_globalObject.set(vm, this, globalObject); }
+        
+    JSValue storedPrototype() const { return m_prototype.get(); }
+    JSObject* storedPrototypeObject() const;
+    Structure* storedPrototypeStructure() const;
+    JSValue prototypeForLookup(ExecState*) const;
+    JSValue prototypeForLookup(JSGlobalObject*) const;
+    JSValue prototypeForLookup(CodeBlock*) const;
+    StructureChain* prototypeChain(VM&, JSGlobalObject*) const;
+    StructureChain* prototypeChain(ExecState*) const;
+    static void visitChildren(JSCell*, SlotVisitor&);
+        
+    // Will just the prototype chain intercept this property access?
+    bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
+        
+    Structure* previousID() const
+    {
+        ASSERT(structure()->classInfo() == info());
+        if (hasRareData())
+            return rareData()->previousID();
+        return previous();
+    }
+    bool transitivelyTransitionedFrom(Structure* structureToFind);
 
-        JSValue storedPrototype() const { return m_prototype; }
-        JSValue prototypeForLookup(ExecState*) const;
-        StructureChain* prototypeChain(ExecState*) const;
+    unsigned outOfLineCapacity() const
+    {
+        ASSERT(checkOffsetConsistency());
+            
+        unsigned outOfLineSize = this->outOfLineSize();
 
-        Structure* previousID() const { return m_previous.get(); }
+        if (!outOfLineSize)
+            return 0;
 
-        void growPropertyStorageCapacity();
-        size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; }
-        size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; }
-        bool isUsingInlineStorage() const;
+        if (outOfLineSize <= initialOutOfLineCapacity)
+            return initialOutOfLineCapacity;
 
-        size_t get(const Identifier& propertyName);
-        size_t get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue);
-        size_t get(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
-        {
-            ASSERT(!propertyName.isNull());
-            return get(propertyName.ustring().rep(), attributes, specificValue);
-        }
-        bool transitionedFor(const JSCell* specificValue)
-        {
-            return m_specificValueInPrevious == specificValue;
-        }
-        bool hasTransition(UString::Rep*, unsigned attributes);
-        bool hasTransition(const Identifier& propertyName, unsigned attributes)
-        {
-            return hasTransition(propertyName._ustring.rep(), attributes);
-        }
+        ASSERT(outOfLineSize > initialOutOfLineCapacity);
+        COMPILE_ASSERT(outOfLineGrowthFactor == 2, outOfLineGrowthFactor_is_two);
+        return WTF::roundUpToPowerOfTwo(outOfLineSize);
+    }
+    unsigned outOfLineSize() const
+    {
+        ASSERT(checkOffsetConsistency());
+        ASSERT(structure()->classInfo() == info());
+            
+        return numberOfOutOfLineSlotsForLastOffset(m_offset);
+    }
+    bool hasInlineStorage() const
+    {
+        return !!m_inlineCapacity;
+    }
+    unsigned inlineCapacity() const
+    {
+        return m_inlineCapacity;
+    }
+    unsigned inlineSize() const
+    {
+        return std::min<unsigned>(m_offset + 1, m_inlineCapacity);
+    }
+    unsigned totalStorageSize() const
+    {
+        return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
+    }
+    unsigned totalStorageCapacity() const
+    {
+        ASSERT(structure()->classInfo() == info());
+        return outOfLineCapacity() + inlineCapacity();
+    }
 
-        void getEnumerablePropertyNames(ExecState*, PropertyNameArray&, JSObject*);
+    bool isValidOffset(PropertyOffset offset) const
+    {
+        return JSC::isValidOffset(offset)
+            && offset <= m_offset
+            && (offset < m_inlineCapacity || offset >= firstOutOfLineOffset);
+    }
+    
+    bool couldHaveIndexingHeader() const
+    {
+        return hasIndexedProperties(indexingType())
+            || isTypedView(m_classInfo->typedArrayStorageType);
+    }
+    
+    bool hasIndexingHeader(const JSCell*) const;
+    
+    bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject);
+
+    PropertyOffset get(VM&, PropertyName);
+    PropertyOffset get(VM&, PropertyName, unsigned& attributes);
+
+    // This is a somewhat internalish method. It will call your functor while possibly holding the
+    // Structure's lock. There is no guarantee whether the lock is held or not in any particular
+    // call. So, you have to assume the worst. Also, the functor returns true if it wishes for you
+    // to continue or false if it's done.
+    template<typename Functor>
+    void forEachPropertyConcurrently(const Functor&);
+    
+    PropertyOffset getConcurrently(UniquedStringImpl* uid);
+    PropertyOffset getConcurrently(UniquedStringImpl* uid, unsigned& attributes);
+    
+    Vector<PropertyMapEntry> getPropertiesConcurrently();
+    
+    void setHasGetterSetterPropertiesWithProtoCheck(bool is__proto__)
+    {
+        setHasGetterSetterProperties(true);
+        if (!is__proto__)
+            setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
+    }
+    
+    void setContainsReadOnlyProperties() { setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); }
+    
+    void setHasCustomGetterSetterPropertiesWithProtoCheck(bool is__proto__)
+    {
+        setHasCustomGetterSetterProperties(true);
+        if (!is__proto__)
+            setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
+    }
+    
+    bool isEmpty() const
+    {
+        ASSERT(checkOffsetConsistency());
+        return !JSC::isValidOffset(m_offset);
+    }
 
-        bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
-        void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
+    void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
+    JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
+    bool canCachePropertyNameEnumerator() const;
+    bool canAccessPropertiesQuickly() const;
 
-        bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; }
+    void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
 
-        JSCell* specificValue() { return m_specificValueInPrevious; }
-        void despecifyDictionaryFunction(const Identifier& propertyName);
+    JSString* objectToStringValue()
+    {
+        if (!hasRareData())
+            return 0;
+        return rareData()->objectToStringValue();
+    }
 
-    private:
-        Structure(JSValue prototype, const TypeInfo&);
-        
-        typedef enum { 
-            NoneDictionaryKind = 0,
-            CachedDictionaryKind = 1,
-            UncachedDictionaryKind = 2
-        } DictionaryKind;
-        static PassRefPtr<Structure> toDictionaryTransition(Structure*, DictionaryKind);
-
-        size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
-        size_t remove(const Identifier& propertyName);
-        void getEnumerableNamesFromPropertyTable(PropertyNameArray&);
-        void getEnumerableNamesFromClassInfoTable(ExecState*, const ClassInfo*, PropertyNameArray&);
-
-        void expandPropertyMapHashTable();
-        void rehashPropertyMapHashTable();
-        void rehashPropertyMapHashTable(unsigned newTableSize);
-        void createPropertyMapHashTable();
-        void createPropertyMapHashTable(unsigned newTableSize);
-        void insertIntoPropertyMapHashTable(const PropertyMapEntry&);
-        void checkConsistency();
-
-        bool despecifyFunction(const Identifier&);
-
-        PropertyMapHashTable* copyPropertyTable();
-        void materializePropertyMap();
-        void materializePropertyMapIfNecessary()
-        {
-            if (m_propertyTable || !m_previous)             
-                return;
-            materializePropertyMap();
-        }
+    void setObjectToStringValue(VM& vm, JSString* value)
+    {
+        if (!hasRareData())
+            allocateRareData(vm);
+        rareData()->setObjectToStringValue(vm, value);
+    }
 
-        void clearEnumerationCache();
+    const ClassInfo* classInfo() const { return m_classInfo; }
 
-        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;
-        }
+    static ptrdiff_t structureIDOffset()
+    {
+        return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::structureIDOffset();
+    }
+
+    static ptrdiff_t prototypeOffset()
+    {
+        return OBJECT_OFFSETOF(Structure, m_prototype);
+    }
+
+    static ptrdiff_t globalObjectOffset()
+    {
+        return OBJECT_OFFSETOF(Structure, m_globalObject);
+    }
+
+    static ptrdiff_t classInfoOffset()
+    {
+        return OBJECT_OFFSETOF(Structure, m_classInfo);
+    }
+        
+    static ptrdiff_t indexingTypeOffset()
+    {
+        return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeOffset();
+    }
+
+    static Structure* createStructure(VM&);
+        
+    bool transitionWatchpointSetHasBeenInvalidated() const
+    {
+        return m_transitionWatchpointSet.hasBeenInvalidated();
+    }
+        
+    bool transitionWatchpointSetIsStillValid() const
+    {
+        return m_transitionWatchpointSet.isStillValid();
+    }
+    
+    bool dfgShouldWatchIfPossible() const
+    {
+        // FIXME: We would like to not watch things that are unprofitable to watch, like
+        // dictionaries. Unfortunately, we can't do such things: a dictionary could get flattened,
+        // in which case it will start to appear watchable and so the DFG will think that it is
+        // watching it. We should come up with a comprehensive story for not watching things that
+        // aren't profitable to watch.
+        // https://bugs.webkit.org/show_bug.cgi?id=133625
+        return true;
+    }
+    
+    bool dfgShouldWatch() const
+    {
+        return dfgShouldWatchIfPossible() && transitionWatchpointSetIsStillValid();
+    }
         
-        bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
+    void addTransitionWatchpoint(Watchpoint* watchpoint) const
+    {
+        ASSERT(transitionWatchpointSetIsStillValid());
+        m_transitionWatchpointSet.add(watchpoint);
+    }
+    
+    void didTransitionFromThisStructure() const;
+    
+    InlineWatchpointSet& transitionWatchpointSet() const
+    {
+        return m_transitionWatchpointSet;
+    }
+    
+    WatchpointSet* ensurePropertyReplacementWatchpointSet(VM&, PropertyOffset);
+    void startWatchingPropertyForReplacements(VM& vm, PropertyOffset offset)
+    {
+        ensurePropertyReplacementWatchpointSet(vm, offset);
+    }
+    void startWatchingPropertyForReplacements(VM&, PropertyName);
+    WatchpointSet* propertyReplacementWatchpointSet(PropertyOffset);
+    void didReplaceProperty(PropertyOffset);
+    void didCachePropertyReplacement(VM&, PropertyOffset);
+    
+    void startWatchingInternalPropertiesIfNecessary(VM& vm)
+    {
+        if (LIKELY(didWatchInternalProperties()))
+            return;
+        startWatchingInternalProperties(vm);
+    }
+    
+    void startWatchingInternalPropertiesIfNecessaryForEntireChain(VM& vm)
+    {
+        for (Structure* structure = this; structure; structure = structure->storedPrototypeStructure())
+            structure->startWatchingInternalPropertiesIfNecessary(vm);
+    }
 
-        static const unsigned emptyEntryIndex = 0;
+    PassRefPtr<StructureShape> toStructureShape(JSValue);
+    
+    // Determines if the two structures match enough that this one could be used for allocations
+    // of the other one.
+    bool canUseForAllocationsOf(Structure*);
+    
+    void dump(PrintStream&) const;
+    void dumpInContext(PrintStream&, DumpContext*) const;
+    void dumpBrief(PrintStream&, const CString&) const;
     
-        static const signed char s_maxTransitionLength = 64;
+    static void dumpContextHeader(PrintStream&);
+    
+    DECLARE_EXPORT_INFO;
+
+private:
+    typedef enum { 
+        NoneDictionaryKind = 0,
+        CachedDictionaryKind = 1,
+        UncachedDictionaryKind = 2
+    } DictionaryKind;
+
+public:
+#define DEFINE_BITFIELD(type, lowerName, upperName, width, offset) \
+    static const uint32_t s_##lowerName##Shift = offset;\
+    static const uint32_t s_##lowerName##Mask = ((1 << (width - 1)) | ((1 << (width - 1)) - 1));\
+    type lowerName() const { return static_cast<type>((m_bitField >> offset) & s_##lowerName##Mask); }\
+    void set##upperName(type newValue) \
+    {\
+        m_bitField &= ~(s_##lowerName##Mask << offset);\
+        m_bitField |= (newValue & s_##lowerName##Mask) << offset;\
+    }
 
-        static const signed char noOffset = -1;
+    DEFINE_BITFIELD(DictionaryKind, dictionaryKind, DictionaryKind, 2, 0);
+    DEFINE_BITFIELD(bool, isPinnedPropertyTable, IsPinnedPropertyTable, 1, 2);
+    DEFINE_BITFIELD(bool, hasGetterSetterProperties, HasGetterSetterProperties, 1, 3);
+    DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4);
+    DEFINE_BITFIELD(bool, hasNonEnumerableProperties, HasNonEnumerableProperties, 1, 5);
+    DEFINE_BITFIELD(unsigned, attributesInPrevious, AttributesInPrevious, 14, 6);
+    DEFINE_BITFIELD(bool, preventExtensions, PreventExtensions, 1, 20);
+    DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 21);
+    DEFINE_BITFIELD(bool, staticFunctionsReified, StaticFunctionsReified, 1, 22);
+    DEFINE_BITFIELD(bool, hasRareData, HasRareData, 1, 23);
+    DEFINE_BITFIELD(bool, hasBeenFlattenedBefore, HasBeenFlattenedBefore, 1, 24);
+    DEFINE_BITFIELD(bool, hasCustomGetterSetterProperties, HasCustomGetterSetterProperties, 1, 25);
+    DEFINE_BITFIELD(bool, didWatchInternalProperties, DidWatchInternalProperties, 1, 26);
+
+private:
+    friend class LLIntOffsetsExtractor;
+
+    JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity);
+    Structure(VM&);
+    Structure(VM&, Structure*);
+
+    static Structure* create(VM&, Structure*);
+    
+    static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
 
-        TypeInfo m_typeInfo;
+    // This will return the structure that has a usable property table, that property table,
+    // and the list of structures that we visited before we got to it. If it returns a
+    // non-null structure, it will also lock the structure that it returns; it is your job
+    // to unlock it.
+    void findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*&, PropertyTable*&);
+    
+    static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind);
 
-        JSValue m_prototype;
-        mutable RefPtr<StructureChain> m_cachedPrototypeChain;
+    PropertyOffset add(VM&, PropertyName, unsigned attributes);
+    PropertyOffset remove(PropertyName);
 
-        RefPtr<Structure> m_previous;
-        RefPtr<UString::Rep> m_nameInPrevious;
-        JSCell* m_specificValueInPrevious;
+    void createPropertyMap(const GCSafeConcurrentJITLocker&, VM&, unsigned keyCount = 0);
+    void checkConsistency();
 
-        union {
-            Structure* singleTransition;
-            StructureTransitionTable* table;
-        } m_transitions;
+    WriteBarrier<PropertyTable>& propertyTable();
+    PropertyTable* takePropertyTableOrCloneIfPinned(VM&);
+    PropertyTable* copyPropertyTable(VM&);
+    PropertyTable* copyPropertyTableForPinning(VM&);
+    JS_EXPORT_PRIVATE void materializePropertyMap(VM&);
+    ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, DeferGC&)
+    {
+        ASSERT(!isCompilationThread());
+        ASSERT(structure()->classInfo() == info());
+        ASSERT(checkOffsetConsistency());
+        if (!propertyTable() && previousID())
+            materializePropertyMap(vm);
+    }
+    ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, PropertyTable*& table)
+    {
+        ASSERT(!isCompilationThread());
+        ASSERT(structure()->classInfo() == info());
+        ASSERT(checkOffsetConsistency());
+        table = propertyTable().get();
+        if (!table && previousID()) {
+            DeferGC deferGC(vm.heap);
+            materializePropertyMap(vm);
+            table = propertyTable().get();
+        }
+    }
+    void materializePropertyMapIfNecessaryForPinning(VM& vm, DeferGC&)
+    {
+        ASSERT(structure()->classInfo() == info());
+        checkOffsetConsistency();
+        if (!propertyTable())
+            materializePropertyMap(vm);
+    }
+
+    void setPreviousID(VM& vm, Structure* structure)
+    {
+        if (hasRareData())
+            rareData()->setPreviousID(vm, structure);
+        else
+            m_previousOrRareData.set(vm, this, structure);
+    }
 
-        RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData;
+    void clearPreviousID()
+    {
+        if (hasRareData())
+            rareData()->clearPreviousID();
+        else
+            m_previousOrRareData.clear();
+    }
 
-        PropertyMapHashTable* m_propertyTable;
+    int 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 numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
+    }
 
-        size_t m_propertyStorageCapacity;
-        signed char m_offset;
+    bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const;
+    bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
+        
+    void pin();
 
-        unsigned m_dictionaryKind : 2;
-        bool m_isPinnedPropertyTable : 1;
-        bool m_hasGetterSetterProperties : 1;
-        bool m_usingSingleTransitionSlot : 1;
-        unsigned m_attributesInPrevious : 7;
-    };
+    Structure* previous() const
+    {
+        ASSERT(!hasRareData());
+        return static_cast<Structure*>(m_previousOrRareData.get());
+    }
 
-    inline size_t Structure::get(const Identifier& propertyName)
+    StructureRareData* rareData() const
     {
-        ASSERT(!propertyName.isNull());
+        ASSERT(hasRareData());
+        return static_cast<StructureRareData*>(m_previousOrRareData.get());
+    }
+        
+    bool checkOffsetConsistency() const;
 
-        materializePropertyMapIfNecessary();
-        if (!m_propertyTable)
-            return WTF::notFound;
+    JS_EXPORT_PRIVATE void allocateRareData(VM&);
+    
+    void startWatchingInternalProperties(VM&);
 
-        UString::Rep* rep = propertyName._ustring.rep();
+    static const int s_maxTransitionLength = 64;
+    static const int s_maxTransitionLengthForNonEvalPutById = 512;
 
-        unsigned i = rep->computedHash();
+    // These need to be properly aligned at the beginning of the 'Structure'
+    // part of the object.
+    StructureIDBlob m_blob;
+    TypeInfo::OutOfLineTypeFlags m_outOfLineTypeFlags;
 
-#if DUMP_PROPERTYMAP_STATS
-        ++numProbes;
-#endif
+    WriteBarrier<JSGlobalObject> m_globalObject;
+    WriteBarrier<Unknown> m_prototype;
+    mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
 
-        unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
-        if (entryIndex == emptyEntryIndex)
-            return WTF::notFound;
+    WriteBarrier<JSCell> m_previousOrRareData;
 
-        if (rep == m_propertyTable->entries()[entryIndex - 1].key)
-            return m_propertyTable->entries()[entryIndex - 1].offset;
+    RefPtr<UniquedStringImpl> m_nameInPrevious;
 
-#if DUMP_PROPERTYMAP_STATS
-        ++numCollisions;
-#endif
+    const ClassInfo* m_classInfo;
 
-        unsigned k = 1 | WTF::doubleHash(rep->computedHash());
+    StructureTransitionTable m_transitionTable;
 
-        while (1) {
-            i += k;
+    // Should be accessed through propertyTable(). During GC, it may be set to 0 by another thread.
+    WriteBarrier<PropertyTable> m_propertyTableUnsafe;
 
-#if DUMP_PROPERTYMAP_STATS
-            ++numRehashes;
-#endif
+    mutable InlineWatchpointSet m_transitionWatchpointSet;
 
-            entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
-            if (entryIndex == emptyEntryIndex)
-                return WTF::notFound;
+    COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
 
-            if (rep == m_propertyTable->entries()[entryIndex - 1].key)
-                return m_propertyTable->entries()[entryIndex - 1].offset;
-        }
-    }
-    
-    bool StructureTransitionTable::contains(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
-    {
-        TransitionTable::iterator find = m_table.find(key);
-        if (find == m_table.end())
-            return false;
+    // m_offset does not account for anonymous slots
+    PropertyOffset m_offset;
 
-        return find->second.first || find->second.second->transitionedFor(specificValue);
-    }
+    uint8_t m_inlineCapacity;
+    
+    ConcurrentJITLock m_lock;
+    
+    uint32_t m_bitField;
+};
 
-    Structure* StructureTransitionTable::get(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const
-    {
-        Transition transition = m_table.get(key);
-        if (transition.second && transition.second->transitionedFor(specificValue))
-            return transition.second;
-        return transition.first;
-    }
 } // namespace JSC
 
 #endif // Structure_h