#pragma once
#include "ClassInfo.h"
#include "ConcurrentJSLock.h"
#include "IndexingType.h"
#include "InferredTypeTable.h"
#include "JSCJSValue.h"
#include "JSCell.h"
#include "JSType.h"
#include "PropertyName.h"
#include "PropertyNameArray.h"
#include "PropertyOffset.h"
#include "PutPropertySlot.h"
#include "StructureIDBlob.h"
#include "StructureRareData.h"
#include "StructureRareDataInlines.h"
#include "StructureTransitionTable.h"
#include "JSTypeInfo.h"
#include "Watchpoint.h"
#include "WriteBarrierInlines.h"
#include <wtf/PrintStream.h>
namespace WTF {
class UniquedStringImpl;
}
namespace JSC {
class DeferGC;
class LLIntOffsetsExtractor;
class PropertyNameArray;
class PropertyNameArrayData;
class PropertyTable;
class StructureChain;
class StructureShape;
class SlotVisitor;
class JSString;
struct DumpContext;
static const unsigned initialOutOfLineCapacity = 4;
static const unsigned outOfLineGrowthFactor = 2;
struct PropertyMapEntry {
UniquedStringImpl* key;
PropertyOffset offset;
uint8_t attributes;
bool hasInferredType;
PropertyMapEntry()
: key(nullptr)
, offset(invalidOffset)
, attributes(0)
, hasInferredType(false)
{
}
PropertyMapEntry(UniquedStringImpl* key, PropertyOffset offset, unsigned attributes)
: key(key)
, offset(offset)
, attributes(attributes)
, hasInferredType(false)
{
ASSERT(this->attributes == attributes);
}
};
class StructureFireDetail : public FireDetail {
public:
StructureFireDetail(const Structure* structure)
: m_structure(structure)
{
}
void dump(PrintStream& out) const override;
private:
const Structure* m_structure;
};
class DeferredStructureTransitionWatchpointFire {
WTF_MAKE_NONCOPYABLE(DeferredStructureTransitionWatchpointFire);
public:
JS_EXPORT_PRIVATE DeferredStructureTransitionWatchpointFire();
JS_EXPORT_PRIVATE ~DeferredStructureTransitionWatchpointFire();
void add(const Structure*);
private:
const Structure* m_structure;
};
class Structure final : public JSCell {
public:
friend class StructureTransitionTable;
typedef JSCell Base;
static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
enum PolyProtoTag { PolyProto };
static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
static Structure* create(PolyProtoTag, VM&, JSGlobalObject*, JSObject* prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
~Structure();
template<typename CellType>
static IsoSubspace* subspaceFor(VM& vm)
{
return &vm.structureSpace;
}
protected:
void finishCreation(VM& vm)
{
Base::finishCreation(vm);
ASSERT(m_prototype.get().isEmpty() || m_prototype.isObject() || m_prototype.isNull());
}
void finishCreation(VM& vm, const Structure* previous)
{
this->finishCreation(vm);
if (previous->hasRareData()) {
const StructureRareData* previousRareData = previous->rareData();
if (previousRareData->hasSharedPolyProtoWatchpoint()) {
ensureRareData(vm);
rareData()->setSharedPolyProtoWatchpoint(previousRareData->copySharedPolyProtoWatchpoint());
}
}
}
void finishCreation(VM& vm, CreatingEarlyCellTag)
{
Base::finishCreation(vm, this, CreatingEarlyCell);
ASSERT(m_prototype);
ASSERT(m_prototype.isNull());
ASSERT(!vm.structureStructure);
}
public:
StructureID id() const { return m_blob.structureID(); }
int32_t objectInitializationBlob() const { return m_blob.blobExcludingStructureID(); }
int64_t idBlob() const { return m_blob.blob(); }
bool isProxy() const
{
JSType type = m_blob.type();
return type == ImpureProxyType || type == PureForwardingProxyType;
}
static void dumpStatistics();
JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&);
JS_EXPORT_PRIVATE static Structure* addNewPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext, DeferredStructureTransitionWatchpointFire* = nullptr);
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&);
static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype, DeferredStructureTransitionWatchpointFire&);
JS_EXPORT_PRIVATE static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes);
JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
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 isStructureExtensible() const { return !didPreventExtensions(); }
JS_EXPORT_PRIVATE Structure* flattenDictionaryStructure(VM&, JSObject*);
static const bool needsDestruction = true;
static void destroy(JSCell*);
template<typename Func>
PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes, const Func&);
template<typename Func>
PropertyOffset removePropertyWithoutTransition(VM&, PropertyName, const Func&);
void setPrototypeWithoutTransition(VM&, JSValue prototype);
bool isDictionary() const { return dictionaryKind() != NoneDictionaryKind; }
bool isUncacheableDictionary() const { return dictionaryKind() == UncachedDictionaryKind; }
bool propertyAccessesAreCacheable()
{
return dictionaryKind() != UncachedDictionaryKind
&& !typeInfo().prohibitsPropertyCaching()
&& !(typeInfo().getOwnPropertySlotIsImpure() && !typeInfo().newImpurePropertyFiresWatchpoints());
}
bool propertyAccessesAreCacheableForAbsence()
{
return !typeInfo().getOwnPropertySlotIsImpureForPropertyAbsence();
}
bool needImpurePropertyWatchpoint()
{
return propertyAccessesAreCacheable()
&& typeInfo().getOwnPropertySlotIsImpure()
&& typeInfo().newImpurePropertyFiresWatchpoints();
}
bool isImmutablePrototypeExoticObject()
{
return typeInfo().isImmutablePrototypeExoticObject();
}
bool takesSlowPathInDFGForImpureProperty()
{
return typeInfo().getOwnPropertySlotIsImpure();
}
TypeInfo typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_blob.typeInfo(m_outOfLineTypeFlags); }
bool isObject() const { return typeInfo().isObject(); }
IndexingType indexingType() const { return m_blob.indexingTypeIncludingHistory() & AllArrayTypes; }
IndexingType indexingTypeIncludingHistory() const { return m_blob.indexingTypeIncludingHistory(); }
bool mayInterceptIndexedAccesses() const
{
return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors);
}
bool holesMustForwardToPrototype(VM&, JSObject*) const;
JSGlobalObject* globalObject() const { return m_globalObject.get(); }
void setGlobalObject(VM&, JSGlobalObject*);
ALWAYS_INLINE bool hasMonoProto() const
{
return !m_prototype.get().isEmpty();
}
ALWAYS_INLINE bool hasPolyProto() const
{
return !hasMonoProto();
}
ALWAYS_INLINE JSValue storedPrototype() const
{
ASSERT(hasMonoProto());
return m_prototype.get();
}
JSValue storedPrototype(const JSObject*) const;
JSObject* storedPrototypeObject(const JSObject*) const;
Structure* storedPrototypeStructure(const JSObject*) const;
JSObject* storedPrototypeObject() const;
Structure* storedPrototypeStructure() const;
JSValue prototypeForLookup(JSGlobalObject*) const;
JSValue prototypeForLookup(JSGlobalObject*, JSCell* base) const;
StructureChain* prototypeChain(VM&, JSGlobalObject*, JSObject* base) const;
StructureChain* prototypeChain(ExecState*, JSObject* base) const;
static void visitChildren(JSCell*, SlotVisitor&);
bool isCheapDuringGC();
bool markIfCheap(SlotVisitor&);
bool hasRareData() const
{
return isRareData(m_previousOrRareData.get());
}
StructureRareData* rareData()
{
ASSERT(hasRareData());
return static_cast<StructureRareData*>(m_previousOrRareData.get());
}
const StructureRareData* rareData() const
{
ASSERT(hasRareData());
return static_cast<const StructureRareData*>(m_previousOrRareData.get());
}
StructureRareData* ensureRareData(VM& vm)
{
if (!hasRareData())
allocateRareData(vm);
return rareData();
}
Structure* previousID() const
{
ASSERT(structure()->classInfo() == info());
JSCell* cell = m_previousOrRareData.get();
if (isRareData(cell))
return static_cast<StructureRareData*>(cell)->previousID();
return static_cast<Structure*>(cell);
}
bool transitivelyTransitionedFrom(Structure* structureToFind);
PropertyOffset lastOffset() const { return m_offset; }
void setLastOffset(PropertyOffset offset) { m_offset = offset; }
static unsigned outOfLineCapacity(PropertyOffset lastOffset)
{
unsigned outOfLineSize = Structure::outOfLineSize(lastOffset);
if (!outOfLineSize)
return 0;
if (outOfLineSize <= initialOutOfLineCapacity)
return initialOutOfLineCapacity;
ASSERT(outOfLineSize > initialOutOfLineCapacity);
COMPILE_ASSERT(outOfLineGrowthFactor == 2, outOfLineGrowthFactor_is_two);
return WTF::roundUpToPowerOfTwo(outOfLineSize);
}
static unsigned outOfLineSize(PropertyOffset lastOffset)
{
return numberOfOutOfLineSlotsForLastOffset(lastOffset);
}
unsigned outOfLineCapacity() const
{
return outOfLineCapacity(m_offset);
}
unsigned outOfLineSize() const
{
return outOfLineSize(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();
}
bool isValidOffset(PropertyOffset offset) const
{
return JSC::isValidOffset(offset)
&& offset <= m_offset
&& (offset < m_inlineCapacity || offset >= firstOutOfLineOffset);
}
bool hijacksIndexingHeader() const
{
return isTypedView(m_classInfo->typedArrayStorageType);
}
bool couldHaveIndexingHeader() const
{
return hasIndexedProperties(indexingType())
|| hijacksIndexingHeader();
}
bool hasIndexingHeader(const JSCell*) const;
bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject);
PropertyOffset get(VM&, PropertyName);
PropertyOffset get(VM&, PropertyName, unsigned& attributes);
PropertyOffset get(VM&, PropertyName, unsigned& attributes, bool& hasInferredType);
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);
}
void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
bool canCachePropertyNameEnumerator() const;
bool canAccessPropertiesQuicklyForEnumeration() const;
void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
JSString* objectToStringValue()
{
if (!hasRareData())
return 0;
return rareData()->objectToStringValue();
}
void setObjectToStringValue(ExecState*, VM&, JSString* value, PropertySlot toStringTagSymbolSlot);
const ClassInfo* classInfo() const { return m_classInfo.unpoisoned(); }
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 indexingTypeIncludingHistoryOffset()
{
return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeIncludingHistoryOffset();
}
static ptrdiff_t propertyTableUnsafeOffset()
{
return OBJECT_OFFSETOF(Structure, m_propertyTableUnsafe);
}
static ptrdiff_t inlineCapacityOffset()
{
return OBJECT_OFFSETOF(Structure, m_inlineCapacity);
}
static Structure* createStructure(VM&);
bool transitionWatchpointSetHasBeenInvalidated() const
{
return m_transitionWatchpointSet.hasBeenInvalidated();
}
bool transitionWatchpointSetIsStillValid() const
{
return m_transitionWatchpointSet.isStillValid();
}
bool dfgShouldWatchIfPossible() const
{
if (transitionWatchpointIsLikelyToBeFired())
return false;
if (hasBeenDictionary())
return false;
return true;
}
bool dfgShouldWatch() const
{
return dfgShouldWatchIfPossible() && transitionWatchpointSetIsStillValid();
}
void addTransitionWatchpoint(Watchpoint* watchpoint) const
{
ASSERT(transitionWatchpointSetIsStillValid());
m_transitionWatchpointSet.add(watchpoint);
}
void didTransitionFromThisStructure(DeferredStructureTransitionWatchpointFire* = nullptr) 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);
}
bool hasInferredTypes() const
{
return !!m_inferredTypeTable;
}
InferredType* inferredTypeFor(UniquedStringImpl* uid)
{
if (InferredTypeTable* table = m_inferredTypeTable.get())
return table->get(uid);
return nullptr;
}
InferredType::Descriptor inferredTypeDescriptorFor(UniquedStringImpl* uid)
{
if (InferredType* result = inferredTypeFor(uid))
return result->descriptor();
return InferredType::Top;
}
ALWAYS_INLINE void willStoreValueForNewTransition(
VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
{
if (hasBeenDictionary() || (!shouldOptimize && !m_inferredTypeTable))
return;
willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::NewProperty);
}
ALWAYS_INLINE void willStoreValueForExistingTransition(
VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
{
if (hasBeenDictionary() || !m_inferredTypeTable)
return;
willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::NewProperty);
}
ALWAYS_INLINE void willStoreValueForReplace(
VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
{
if (hasBeenDictionary())
return;
willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::OldProperty);
}
Ref<StructureShape> toStructureShape(JSValue, bool& sawPolyProtoStructure);
void dump(PrintStream&) const;
void dumpInContext(PrintStream&, DumpContext*) const;
void dumpBrief(PrintStream&, const CString&) const;
static void dumpContextHeader(PrintStream&);
ConcurrentJSLock& lock() { return m_lock; }
unsigned propertyHash() const { return m_propertyHash; }
static bool shouldConvertToPolyProto(const Structure* a, const Structure* b);
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;\
}
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, isQuickPropertyAccessAllowedForEnumeration, IsQuickPropertyAccessAllowedForEnumeration, 1, 5);
DEFINE_BITFIELD(unsigned, attributesInPrevious, AttributesInPrevious, 14, 6);
DEFINE_BITFIELD(bool, didPreventExtensions, DidPreventExtensions, 1, 20);
DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 21);
DEFINE_BITFIELD(bool, staticPropertiesReified, StaticPropertiesReified, 1, 22);
DEFINE_BITFIELD(bool, hasBeenFlattenedBefore, HasBeenFlattenedBefore, 1, 23);
DEFINE_BITFIELD(bool, hasCustomGetterSetterProperties, HasCustomGetterSetterProperties, 1, 24);
DEFINE_BITFIELD(bool, didWatchInternalProperties, DidWatchInternalProperties, 1, 25);
DEFINE_BITFIELD(bool, transitionWatchpointIsLikelyToBeFired, TransitionWatchpointIsLikelyToBeFired, 1, 26);
DEFINE_BITFIELD(bool, hasBeenDictionary, HasBeenDictionary, 1, 27);
DEFINE_BITFIELD(bool, isAddingPropertyForTransition, IsAddingPropertyForTransition, 1, 28);
private:
friend class LLIntOffsetsExtractor;
JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity);
Structure(VM&);
Structure(VM&, Structure*, DeferredStructureTransitionWatchpointFire*);
static Structure* create(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
void findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*&, PropertyTable*&);
static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind, DeferredStructureTransitionWatchpointFire* = nullptr);
enum class ShouldPin { No, Yes };
template<ShouldPin, typename Func>
PropertyOffset add(VM&, PropertyName, unsigned attributes, const Func&);
PropertyOffset add(VM&, PropertyName, unsigned attributes);
template<typename Func>
PropertyOffset remove(PropertyName, const Func&);
PropertyOffset remove(PropertyName);
void checkConsistency();
PropertyTable* ensurePropertyTableIfNotEmpty(VM& vm)
{
if (PropertyTable* result = m_propertyTableUnsafe.get())
return result;
if (!previousID())
return nullptr;
return materializePropertyTable(vm);
}
PropertyTable* ensurePropertyTable(VM& vm)
{
if (PropertyTable* result = m_propertyTableUnsafe.get())
return result;
return materializePropertyTable(vm);
}
PropertyTable* propertyTableOrNull() const
{
return m_propertyTableUnsafe.get();
}
JS_EXPORT_PRIVATE PropertyTable* materializePropertyTable(VM&, bool setPropertyTable = true);
void setPropertyTable(VM& vm, PropertyTable* table);
PropertyTable* takePropertyTableOrCloneIfPinned(VM&);
PropertyTable* copyPropertyTableForPinning(VM&);
void setPreviousID(VM&, Structure*);
void clearPreviousID()
{
if (hasRareData())
rareData()->clearPreviousID();
else
m_previousOrRareData.clear();
}
int transitionCount() const
{
return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
}
bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain, JSObject* base) const;
JS_EXPORT_PRIVATE void pin(const AbstractLocker&, VM&, PropertyTable*);
void pinForCaching(const AbstractLocker&, VM&, PropertyTable*);
bool isRareData(JSCell* cell) const
{
return cell && cell->structureID() != structureID();
}
template<typename DetailsFunc>
bool checkOffsetConsistency(PropertyTable*, const DetailsFunc&) const;
bool checkOffsetConsistency() const;
JS_EXPORT_PRIVATE void allocateRareData(VM&);
void startWatchingInternalProperties(VM&);
JS_EXPORT_PRIVATE void willStoreValueSlow(
VM&, PropertyName, JSValue, bool, InferredTypeTable::StoredPropertyAge);
static const int s_maxTransitionLength = 64;
static const int s_maxTransitionLengthForNonEvalPutById = 512;
StructureIDBlob m_blob;
TypeInfo::OutOfLineTypeFlags m_outOfLineTypeFlags;
uint8_t m_inlineCapacity;
ConcurrentJSLock m_lock;
uint32_t m_bitField;
WriteBarrier<JSGlobalObject> m_globalObject;
WriteBarrier<Unknown> m_prototype;
mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
WriteBarrier<JSCell> m_previousOrRareData;
RefPtr<UniquedStringImpl> m_nameInPrevious;
PoisonedClassInfoPtr m_classInfo;
StructureTransitionTable m_transitionTable;
WriteBarrier<PropertyTable> m_propertyTableUnsafe;
WriteBarrier<InferredTypeTable> m_inferredTypeTable;
mutable InlineWatchpointSet m_transitionWatchpointSet;
COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
PropertyOffset m_offset;
uint32_t m_propertyHash;
};
}