summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/Structure.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/Structure.h')
-rw-r--r--Source/JavaScriptCore/runtime/Structure.h843
1 files changed, 358 insertions, 485 deletions
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index 6e4402c52..45379efd6 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,18 +28,17 @@
#include "ClassInfo.h"
#include "IndexingType.h"
+#include "JSCJSValue.h"
#include "JSCell.h"
#include "JSType.h"
-#include "JSValue.h"
-#include "PropertyMapHashTable.h"
#include "PropertyName.h"
#include "PropertyNameArray.h"
+#include "PropertyOffset.h"
#include "Protect.h"
+#include "StructureRareData.h"
#include "StructureTransitionTable.h"
#include "JSTypeInfo.h"
#include "Watchpoint.h"
-#include "Weak.h"
-#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/text/StringImpl.h>
@@ -47,562 +46,436 @@
namespace JSC {
- class LLIntOffsetsExtractor;
- class PropertyNameArray;
- class PropertyNameArrayData;
- class StructureChain;
- class SlotVisitor;
- class JSString;
-
- // 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;
-
- class Structure : public JSCell {
- public:
- friend class StructureTransitionTable;
-
- typedef JSCell Base;
-
- static Structure* create(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, PropertyOffset inlineCapacity = 0);
-
- 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:
- static void dumpStatistics();
-
- JS_EXPORT_PRIVATE static Structure* addPropertyTransition(JSGlobalData&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&);
- JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&);
- static Structure* removePropertyTransition(JSGlobalData&, Structure*, PropertyName, PropertyOffset&);
- JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype);
- JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, PropertyName);
- static Structure* attributeChangeTransition(JSGlobalData&, Structure*, PropertyName, unsigned attributes);
- 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*);
- static Structure* nonPropertyTransition(JSGlobalData&, Structure*, NonPropertyTransition);
-
- bool isSealed(JSGlobalData&);
- bool isFrozen(JSGlobalData&);
- bool isExtensible() const { return !m_preventExtensions; }
- bool didTransition() const { return m_didTransition; }
- bool putWillGrowOutOfLineStorage()
- {
- ASSERT(outOfLineCapacity() >= outOfLineSize());
-
- if (!m_propertyTable) {
- unsigned currentSize = numberOfOutOfLineSlotsForLastOffset(m_offset);
- ASSERT(outOfLineCapacity() >= currentSize);
- return currentSize == outOfLineCapacity();
- }
-
- ASSERT(totalStorageCapacity() >= m_propertyTable->propertyStorageSize());
- if (m_propertyTable->hasDeletedOffset())
- return false;
-
- ASSERT(totalStorageCapacity() >= m_propertyTable->size());
- return m_propertyTable->size() == totalStorageCapacity();
- }
- JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity();
+class LLIntOffsetsExtractor;
+class PropertyNameArray;
+class PropertyNameArrayData;
+class PropertyTable;
+class StructureChain;
+class SlotVisitor;
+class JSString;
- Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
+// 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;
- static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
- static void destroy(JSCell*);
+// The factor by which to grow out-of-line storage when it is exhausted, after the
+// initial allocation.
+static const unsigned outOfLineGrowthFactor = 2;
- // These should be used with caution.
- JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue);
- PropertyOffset removePropertyWithoutTransition(JSGlobalData&, PropertyName);
- void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); }
-
- bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
- bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
+class Structure : public JSCell {
+public:
+ friend class StructureTransitionTable;
- bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); }
+ typedef JSCell Base;
- // Type accessors.
- const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; }
- bool isObject() const { return typeInfo().isObject(); }
+ static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
- IndexingType indexingType() const { return m_indexingType & AllArrayTypes; }
- IndexingType indexingTypeIncludingHistory() const { return m_indexingType; }
-
- bool mayInterceptIndexedAccesses() const
- {
- return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors);
- }
-
- bool anyObjectInChainMayInterceptIndexedAccesses() const;
-
- bool needsSlowPutIndexing() const;
- NonPropertyTransition suggestedArrayStorageTransition() const;
-
- JSGlobalObject* globalObject() const { return m_globalObject.get(); }
- void setGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject) { m_globalObject.set(globalData, this, globalObject); }
-
- JSValue storedPrototype() const { return m_prototype.get(); }
- JSValue prototypeForLookup(ExecState*) const;
- JSValue prototypeForLookup(JSGlobalObject*) const;
- JSValue prototypeForLookup(CodeBlock*) const;
- StructureChain* prototypeChain(JSGlobalData&, JSGlobalObject*) const;
- StructureChain* prototypeChain(ExecState*) const;
- static void visitChildren(JSCell*, SlotVisitor&);
-
- // Will just the prototype chain intercept this property access?
- bool prototypeChainMayInterceptStoreTo(JSGlobalData&, PropertyName);
-
- bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; }
-
- Structure* previousID() const
- {
- ASSERT(structure()->classInfo() == &s_info);
- return m_previous.get();
- }
- bool transitivelyTransitionedFrom(Structure* structureToFind);
-
- void growOutOfLineCapacity();
- unsigned outOfLineCapacity() const
- {
- ASSERT(structure()->classInfo() == &s_info);
- return m_outOfLineCapacity;
- }
- unsigned outOfLineSize() const
- {
- ASSERT(structure()->classInfo() == &s_info);
- if (m_propertyTable) {
- unsigned totalSize = m_propertyTable->propertyStorageSize();
- unsigned inlineCapacity = this->inlineCapacity();
- if (totalSize < inlineCapacity)
- return 0;
- return totalSize - inlineCapacity;
- }
- return numberOfOutOfLineSlotsForLastOffset(m_offset);
- }
- bool hasInlineStorage() const
- {
- return !!m_inlineCapacity;
- }
- unsigned inlineCapacity() const
- {
- return m_inlineCapacity;
- }
- unsigned inlineSize() const
- {
- unsigned result;
- if (m_propertyTable)
- result = m_propertyTable->propertyStorageSize();
- else
- result = m_offset + 1;
- return std::min<unsigned>(result, m_inlineCapacity);
- }
- unsigned totalStorageSize() const
- {
- if (m_propertyTable)
- return m_propertyTable->propertyStorageSize();
- return numberOfSlotsForLastOffset(m_offset, m_typeInfo.type());
- }
- unsigned totalStorageCapacity() const
- {
- ASSERT(structure()->classInfo() == &s_info);
- return m_outOfLineCapacity + inlineCapacity();
- }
-
- PropertyOffset firstValidOffset() const
- {
- if (hasInlineStorage())
- return 0;
- return firstOutOfLineOffset;
- }
- PropertyOffset lastValidOffset() const
- {
- if (m_propertyTable)
- return propertyOffsetFor(m_propertyTable->propertyStorageSize() - 1, m_inlineCapacity);
- return m_offset;
- }
- bool isValidOffset(PropertyOffset offset) const
- {
- return offset >= firstValidOffset()
- && offset <= lastValidOffset();
- }
-
- bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject);
-
- PropertyOffset get(JSGlobalData&, PropertyName);
- PropertyOffset get(JSGlobalData&, const WTF::String& name);
- JS_EXPORT_PRIVATE PropertyOffset get(JSGlobalData&, PropertyName, unsigned& attributes, JSCell*& specificValue);
-
- bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
- bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; }
- void setHasGetterSetterProperties(bool is__proto__)
- {
- m_hasGetterSetterProperties = true;
- if (!is__proto__)
- m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
- }
- void setContainsReadOnlyProperties()
- {
- m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
- }
+protected:
+ void finishCreation(VM& vm)
+ {
+ Base::finishCreation(vm);
+ ASSERT(m_prototype);
+ ASSERT(m_prototype.isObject() || m_prototype.isNull());
+ }
- bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
-
- bool isEmpty() const
- {
- if (m_propertyTable)
- return m_propertyTable->isEmpty();
- return !JSC::isValidOffset(m_offset);
- }
-
- JS_EXPORT_PRIVATE void despecifyDictionaryFunction(JSGlobalData&, PropertyName);
- void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
-
- void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
- JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
- void getPropertyNamesFromStructure(JSGlobalData&, PropertyNameArray&, EnumerationMode);
-
- JSString* objectToStringValue() { return m_objectToStringValue.get(); }
-
- void setObjectToStringValue(JSGlobalData& globalData, const JSCell* owner, JSString* value)
- {
- m_objectToStringValue.set(globalData, owner, value);
- }
-
- bool staticFunctionsReified()
- {
- return m_staticFunctionReified;
- }
-
- void setStaticFunctionsReified()
- {
- m_staticFunctionReified = true;
- }
-
- const ClassInfo* classInfo() const { return m_classInfo; }
-
- static ptrdiff_t prototypeOffset()
- {
- return OBJECT_OFFSETOF(Structure, m_prototype);
- }
-
- static ptrdiff_t globalObjectOffset()
- {
- return OBJECT_OFFSETOF(Structure, m_globalObject);
- }
-
- static ptrdiff_t typeInfoFlagsOffset()
- {
- return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
- }
-
- static ptrdiff_t typeInfoTypeOffset()
- {
- return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
- }
-
- static ptrdiff_t classInfoOffset()
- {
- return OBJECT_OFFSETOF(Structure, m_classInfo);
- }
+ void finishCreation(VM& vm, CreatingEarlyCellTag)
+ {
+ Base::finishCreation(vm, this, CreatingEarlyCell);
+ ASSERT(m_prototype);
+ ASSERT(m_prototype.isNull());
+ ASSERT(!vm.structureStructure);
+ }
+
+public:
+ static void dumpStatistics();
+
+ JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&);
+ JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&);
+ static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&);
+ JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype);
+ JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(VM&, Structure*, PropertyName);
+ static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes);
+ static Structure* toCacheableDictionaryTransition(VM&, Structure*);
+ static Structure* toUncacheableDictionaryTransition(VM&, Structure*);
+ static Structure* sealTransition(VM&, Structure*);
+ static Structure* freezeTransition(VM&, Structure*);
+ static Structure* preventExtensionsTransition(VM&, Structure*);
+ static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition);
+
+ bool isSealed(VM&);
+ bool isFrozen(VM&);
+ bool isExtensible() const { return !m_preventExtensions; }
+ bool didTransition() const { return m_didTransition; }
+ bool putWillGrowOutOfLineStorage();
+ JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity();
+
+ Structure* flattenDictionaryStructure(VM&, JSObject*);
+
+ static const bool needsDestruction = true;
+ static const bool hasImmortalStructure = true;
+ static void destroy(JSCell*);
+
+ // These should be used with caution.
+ JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes, JSCell* specificValue);
+ PropertyOffset removePropertyWithoutTransition(VM&, PropertyName);
+ void setPrototypeWithoutTransition(VM& vm, JSValue prototype) { m_prototype.set(vm, this, prototype); }
- static ptrdiff_t indexingTypeOffset()
- {
- return OBJECT_OFFSETOF(Structure, m_indexingType);
- }
+ bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
+ bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
+
+ bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); }
+
+ // Type accessors.
+ const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; }
+ bool isObject() const { return typeInfo().isObject(); }
- static Structure* createStructure(JSGlobalData&);
+ IndexingType indexingType() const { return m_indexingType & AllArrayTypes; }
+ IndexingType indexingTypeIncludingHistory() const { return m_indexingType; }
- bool transitionWatchpointSetHasBeenInvalidated() const
- {
- return m_transitionWatchpointSet.hasBeenInvalidated();
- }
+ bool mayInterceptIndexedAccesses() const
+ {
+ return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors);
+ }
- bool transitionWatchpointSetIsStillValid() const
- {
- return m_transitionWatchpointSet.isStillValid();
- }
+ bool anyObjectInChainMayInterceptIndexedAccesses() const;
- void addTransitionWatchpoint(Watchpoint* watchpoint) const
- {
- ASSERT(transitionWatchpointSetIsStillValid());
- m_transitionWatchpointSet.add(watchpoint);
- }
+ bool needsSlowPutIndexing() const;
+ NonPropertyTransition suggestedArrayStorageTransition() const;
- void notifyTransitionFromThisStructure() const
- {
- m_transitionWatchpointSet.notifyWrite();
- }
+ JSGlobalObject* globalObject() const { return m_globalObject.get(); }
+ void setGlobalObject(VM& vm, JSGlobalObject* globalObject) { m_globalObject.set(vm, this, globalObject); }
- static JS_EXPORTDATA const ClassInfo s_info;
-
- private:
- friend class LLIntOffsetsExtractor;
-
- JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, PropertyOffset inlineCapacity);
- Structure(JSGlobalData&);
- Structure(JSGlobalData&, const Structure*);
-
- static Structure* create(JSGlobalData&, const Structure*);
+ JSValue storedPrototype() const { return m_prototype.get(); }
+ 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&);
- typedef enum {
- NoneDictionaryKind = 0,
- CachedDictionaryKind = 1,
- UncachedDictionaryKind = 2
- } DictionaryKind;
- static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
-
- PropertyOffset putSpecificValue(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue);
- PropertyOffset remove(PropertyName);
-
- void createPropertyMap(unsigned keyCount = 0);
- void checkConsistency();
-
- bool despecifyFunction(JSGlobalData&, PropertyName);
- void despecifyAllFunctions(JSGlobalData&);
-
- PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
- PassOwnPtr<PropertyTable> copyPropertyTableForPinning(JSGlobalData&, Structure* owner);
- JS_EXPORT_PRIVATE void materializePropertyMap(JSGlobalData&);
- void materializePropertyMapIfNecessary(JSGlobalData& globalData)
- {
- ASSERT(structure()->classInfo() == &s_info);
- if (!m_propertyTable && m_previous)
- materializePropertyMap(globalData);
- }
- void materializePropertyMapIfNecessaryForPinning(JSGlobalData& globalData)
- {
- ASSERT(structure()->classInfo() == &s_info);
- if (!m_propertyTable)
- materializePropertyMap(globalData);
- }
-
- 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_typeInfo.type());
- }
-
- bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const;
- bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
+ // Will just the prototype chain intercept this property access?
+ bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
- void pin();
-
- static const int s_maxTransitionLength = 64;
-
- static const unsigned maxSpecificFunctionThrashCount = 3;
-
- TypeInfo m_typeInfo;
- IndexingType m_indexingType;
+ bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; }
- WriteBarrier<JSGlobalObject> m_globalObject;
- WriteBarrier<Unknown> m_prototype;
- mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
-
- WriteBarrier<Structure> m_previous;
- RefPtr<StringImpl> m_nameInPrevious;
- WriteBarrier<JSCell> m_specificValueInPrevious;
-
- const ClassInfo* m_classInfo;
+ Structure* previousID() const
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ if (typeInfo().structureHasRareData())
+ return rareData()->previousID();
+ return previous();
+ }
+ bool transitivelyTransitionedFrom(Structure* structureToFind);
- StructureTransitionTable m_transitionTable;
+ unsigned outOfLineCapacity() const
+ {
+ ASSERT(checkOffsetConsistency());
+
+ unsigned outOfLineSize = this->outOfLineSize();
- WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
+ if (!outOfLineSize)
+ return 0;
- OwnPtr<PropertyTable> m_propertyTable;
+ if (outOfLineSize <= initialOutOfLineCapacity)
+ return initialOutOfLineCapacity;
- WriteBarrier<JSString> m_objectToStringValue;
-
- mutable InlineWatchpointSet m_transitionWatchpointSet;
-
- uint32_t m_outOfLineCapacity;
- uint8_t m_inlineCapacity;
- COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
-
- // m_offset does not account for anonymous slots
- PropertyOffset m_offset;
-
- unsigned m_dictionaryKind : 2;
- bool m_isPinnedPropertyTable : 1;
- bool m_hasGetterSetterProperties : 1;
- bool m_hasReadOnlyOrGetterSetterPropertiesExcludingProto : 1;
- bool m_hasNonEnumerableProperties : 1;
- unsigned m_attributesInPrevious : 22;
- unsigned m_specificFunctionThrashCount : 2;
- unsigned m_preventExtensions : 1;
- unsigned m_didTransition : 1;
- unsigned m_staticFunctionReified;
- };
-
- inline Structure* Structure::create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity)
- {
- ASSERT(globalData.structureStructure);
- ASSERT(classInfo);
- Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity);
- structure->finishCreation(globalData);
- return structure;
+ ASSERT(outOfLineSize > initialOutOfLineCapacity);
+ COMPILE_ASSERT(outOfLineGrowthFactor == 2, outOfLineGrowthFactor_is_two);
+ return WTF::roundUpToPowerOfTwo(outOfLineSize);
}
-
- inline Structure* Structure::createStructure(JSGlobalData& globalData)
+ unsigned outOfLineSize() const
{
- ASSERT(!globalData.structureStructure);
- Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData);
- structure->finishCreation(globalData, CreatingEarlyCell);
- return structure;
+ ASSERT(checkOffsetConsistency());
+ ASSERT(structure()->classInfo() == &s_info);
+
+ return numberOfOutOfLineSlotsForLastOffset(m_offset);
}
-
- inline Structure* Structure::create(JSGlobalData& globalData, const Structure* structure)
+ bool hasInlineStorage() const
{
- ASSERT(globalData.structureStructure);
- Structure* newStructure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, structure);
- newStructure->finishCreation(globalData);
- return newStructure;
+ return !!m_inlineCapacity;
}
-
- inline PropertyOffset Structure::get(JSGlobalData& globalData, PropertyName propertyName)
+ 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() == &s_info);
- materializePropertyMapIfNecessary(globalData);
- if (!m_propertyTable)
- return invalidOffset;
-
- PropertyMapEntry* entry = m_propertyTable->find(propertyName.uid()).first;
- return entry ? entry->offset : invalidOffset;
+ return outOfLineCapacity() + inlineCapacity();
}
- inline PropertyOffset Structure::get(JSGlobalData& globalData, const WTF::String& name)
+ PropertyOffset firstValidOffset() const
{
- ASSERT(structure()->classInfo() == &s_info);
- materializePropertyMapIfNecessary(globalData);
- if (!m_propertyTable)
- return invalidOffset;
+ if (hasInlineStorage())
+ return 0;
+ return firstOutOfLineOffset;
+ }
+ PropertyOffset lastValidOffset() const
+ {
+ return m_offset;
+ }
+ bool isValidOffset(PropertyOffset offset) const
+ {
+ return offset >= firstValidOffset()
+ && offset <= lastValidOffset();
+ }
+
+ bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject);
- PropertyMapEntry* entry = m_propertyTable->findWithString(name.impl()).first;
- return entry ? entry->offset : invalidOffset;
+ PropertyOffset get(VM&, PropertyName);
+ PropertyOffset get(VM&, const WTF::String& name);
+ JS_EXPORT_PRIVATE PropertyOffset get(VM&, PropertyName, unsigned& attributes, JSCell*& specificValue);
+
+ bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
+ bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; }
+ void setHasGetterSetterProperties(bool is__proto__)
+ {
+ m_hasGetterSetterProperties = true;
+ if (!is__proto__)
+ m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
}
-
- inline bool Structure::masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject)
+ void setContainsReadOnlyProperties()
+ {
+ m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
+ }
+
+ bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
+
+ bool isEmpty() const
{
- return typeInfo().masqueradesAsUndefined() && globalObject() == lexicalGlobalObject;
+ ASSERT(checkOffsetConsistency());
+ return !JSC::isValidOffset(m_offset);
}
- inline JSValue JSValue::structureOrUndefined() const
+ JS_EXPORT_PRIVATE void despecifyDictionaryFunction(VM&, PropertyName);
+ void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
+
+ void setEnumerationCache(VM&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
+ JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
+ void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
+
+ JSString* objectToStringValue()
{
- if (isCell())
- return JSValue(asCell()->structure());
- return jsUndefined();
+ if (!typeInfo().structureHasRareData())
+ return 0;
+ return rareData()->objectToStringValue();
}
- inline bool JSCell::isObject() const
+ void setObjectToStringValue(VM& vm, const JSCell* owner, JSString* value)
{
- return m_structure->isObject();
+ if (!typeInfo().structureHasRareData())
+ allocateRareData(vm);
+ rareData()->setObjectToStringValue(vm, owner, value);
}
- inline bool JSCell::isString() const
+ bool staticFunctionsReified()
{
- return m_structure->typeInfo().type() == StringType;
+ return m_staticFunctionReified;
}
- inline bool JSCell::isGetterSetter() const
+ void setStaticFunctionsReified()
{
- return m_structure->typeInfo().type() == GetterSetterType;
+ m_staticFunctionReified = true;
}
- inline bool JSCell::isProxy() const
+ const ClassInfo* classInfo() const { return m_classInfo; }
+
+ static ptrdiff_t prototypeOffset()
{
- return structure()->typeInfo().type() == ProxyType;
+ return OBJECT_OFFSETOF(Structure, m_prototype);
}
- inline bool JSCell::isAPIValueWrapper() const
+ static ptrdiff_t globalObjectOffset()
{
- return m_structure->typeInfo().type() == APIValueWrapperType;
+ return OBJECT_OFFSETOF(Structure, m_globalObject);
}
- inline void JSCell::setStructure(JSGlobalData& globalData, Structure* structure)
+ static ptrdiff_t typeInfoFlagsOffset()
{
- ASSERT(structure->typeInfo().overridesVisitChildren() == this->structure()->typeInfo().overridesVisitChildren());
- ASSERT(structure->classInfo() == m_structure->classInfo());
- ASSERT(!m_structure
- || m_structure->transitionWatchpointSetHasBeenInvalidated()
- || m_structure.get() == structure);
- m_structure.set(globalData, this, structure);
+ return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
}
- ALWAYS_INLINE void SlotVisitor::internalAppend(JSCell* cell)
+ static ptrdiff_t typeInfoTypeOffset()
+ {
+ return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
+ }
+
+ static ptrdiff_t classInfoOffset()
+ {
+ return OBJECT_OFFSETOF(Structure, m_classInfo);
+ }
+
+ static ptrdiff_t indexingTypeOffset()
{
- ASSERT(!m_isCheckingForDefaultMarkViolation);
- if (!cell)
- return;
-#if ENABLE(GC_VALIDATION)
- validate(cell);
-#endif
- if (Heap::testAndSetMarked(cell) || !cell->structure())
- return;
+ return OBJECT_OFFSETOF(Structure, m_indexingType);
+ }
- m_visitCount++;
+ static Structure* createStructure(VM&);
+
+ bool transitionWatchpointSetHasBeenInvalidated() const
+ {
+ return m_transitionWatchpointSet.hasBeenInvalidated();
+ }
+
+ bool transitionWatchpointSetIsStillValid() const
+ {
+ return m_transitionWatchpointSet.isStillValid();
+ }
+
+ void addTransitionWatchpoint(Watchpoint* watchpoint) const
+ {
+ ASSERT(transitionWatchpointSetIsStillValid());
+ m_transitionWatchpointSet.add(watchpoint);
+ }
+
+ void notifyTransitionFromThisStructure() const
+ {
+ m_transitionWatchpointSet.notifyWrite();
+ }
- MARK_LOG_CHILD(*this, cell);
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+private:
+ friend class LLIntOffsetsExtractor;
- // Should never attempt to mark something that is zapped.
- ASSERT(!cell->isZapped());
+ JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity);
+ Structure(VM&);
+ Structure(VM&, const Structure*);
+
+ static Structure* create(VM&, const Structure*);
- m_stack.append(cell);
+ typedef enum {
+ NoneDictionaryKind = 0,
+ CachedDictionaryKind = 1,
+ UncachedDictionaryKind = 2
+ } DictionaryKind;
+ static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind);
+
+ PropertyOffset putSpecificValue(VM&, PropertyName, unsigned attributes, JSCell* specificValue);
+ PropertyOffset remove(PropertyName);
+
+ void createPropertyMap(VM&, unsigned keyCount = 0);
+ void checkConsistency();
+
+ bool despecifyFunction(VM&, PropertyName);
+ void despecifyAllFunctions(VM&);
+
+ WriteBarrier<PropertyTable>& propertyTable();
+ PropertyTable* takePropertyTableOrCloneIfPinned(VM&, Structure* owner);
+ PropertyTable* copyPropertyTable(VM&, Structure* owner);
+ PropertyTable* copyPropertyTableForPinning(VM&, Structure* owner);
+ JS_EXPORT_PRIVATE void materializePropertyMap(VM&);
+ void materializePropertyMapIfNecessary(VM& vm)
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ ASSERT(checkOffsetConsistency());
+ if (!propertyTable() && previousID())
+ materializePropertyMap(vm);
+ }
+ void materializePropertyMapIfNecessaryForPinning(VM& vm)
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ checkOffsetConsistency();
+ if (!propertyTable())
+ materializePropertyMap(vm);
}
- inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure)
+ void setPreviousID(VM& vm, Structure* transition, Structure* structure)
{
- // 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);
+ if (typeInfo().structureHasRareData())
+ rareData()->setPreviousID(vm, transition, structure);
+ else
+ m_previousOrRareData.set(vm, transition, structure);
}
- inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind)
+ void clearPreviousID()
{
- for (Structure* current = this; current; current = current->previousID()) {
- if (current == structureToFind)
- return true;
- }
- return false;
+ if (typeInfo().structureHasRareData())
+ rareData()->clearPreviousID();
+ else
+ m_previousOrRareData.clear();
}
- inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure)
- : m_structure(globalData, this, structure)
+ 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);
}
- inline void JSCell::finishCreation(JSGlobalData& globalData, Structure* structure, CreatingEarlyCellTag)
+ bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const;
+ bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
+
+ void pin();
+
+ Structure* previous() const
{
-#if ENABLE(GC_VALIDATION)
- ASSERT(globalData.isInitializingObject());
- globalData.setInitializingObjectClass(0);
- if (structure)
-#endif
- m_structure.setEarlyValue(globalData, this, structure);
- // Very first set of allocations won't have a real structure.
- ASSERT(m_structure || !globalData.structureStructure);
+ ASSERT(!typeInfo().structureHasRareData());
+ return static_cast<Structure*>(m_previousOrRareData.get());
}
+ StructureRareData* rareData() const
+ {
+ ASSERT(typeInfo().structureHasRareData());
+ return static_cast<StructureRareData*>(m_previousOrRareData.get());
+ }
+
+ bool checkOffsetConsistency() const;
+
+ void allocateRareData(VM&);
+ void cloneRareDataFrom(VM&, const Structure*);
+
+ static const int s_maxTransitionLength = 64;
+
+ static const unsigned maxSpecificFunctionThrashCount = 3;
+
+ WriteBarrier<JSGlobalObject> m_globalObject;
+ WriteBarrier<Unknown> m_prototype;
+ mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
+
+ WriteBarrier<JSCell> m_previousOrRareData;
+
+ RefPtr<StringImpl> m_nameInPrevious;
+ WriteBarrier<JSCell> m_specificValueInPrevious;
+
+ const ClassInfo* m_classInfo;
+
+ StructureTransitionTable m_transitionTable;
+
+ // Should be accessed through propertyTable(). During GC, it may be set to 0 by another thread.
+ WriteBarrier<PropertyTable> m_propertyTableUnsafe;
+
+ mutable InlineWatchpointSet m_transitionWatchpointSet;
+
+ COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
+
+ // m_offset does not account for anonymous slots
+ PropertyOffset m_offset;
+
+ TypeInfo m_typeInfo;
+ IndexingType m_indexingType;
+
+ uint8_t m_inlineCapacity;
+ unsigned m_dictionaryKind : 2;
+ bool m_isPinnedPropertyTable : 1;
+ bool m_hasGetterSetterProperties : 1;
+ bool m_hasReadOnlyOrGetterSetterPropertiesExcludingProto : 1;
+ bool m_hasNonEnumerableProperties : 1;
+ unsigned m_attributesInPrevious : 14;
+ unsigned m_specificFunctionThrashCount : 2;
+ unsigned m_preventExtensions : 1;
+ unsigned m_didTransition : 1;
+ unsigned m_staticFunctionReified;
+};
+
} // namespace JSC
#endif // Structure_h