diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/Structure.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/Structure.h | 176 |
1 files changed, 146 insertions, 30 deletions
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index 448a81c27..d2d025b98 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -87,9 +87,9 @@ namespace JSC { public: static void dumpStatistics(); - JS_EXPORT_PRIVATE static Structure* addPropertyTransition(JSGlobalData&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, size_t& offset); - JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, size_t& offset); - static Structure* removePropertyTransition(JSGlobalData&, Structure*, PropertyName, size_t& offset); + 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); @@ -103,16 +103,32 @@ namespace JSC { bool isFrozen(JSGlobalData&); bool isExtensible() const { return !m_preventExtensions; } bool didTransition() const { return m_didTransition; } - bool shouldGrowPropertyStorage() { return propertyStorageCapacity() == propertyStorageSize(); } - JS_EXPORT_PRIVATE size_t suggestedNewPropertyStorageSize(); + 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(); Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*); static void destroy(JSCell*); // These should be used with caution. - JS_EXPORT_PRIVATE size_t addPropertyWithoutTransition(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue); - size_t removePropertyWithoutTransition(JSGlobalData&, PropertyName); + 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; } @@ -133,17 +149,114 @@ namespace JSC { StructureChain* prototypeChain(ExecState*) const; static void visitChildren(JSCell*, SlotVisitor&); - Structure* previousID() const { ASSERT(structure()->classInfo() == &s_info); return m_previous.get(); } + Structure* previousID() const + { + ASSERT(structure()->classInfo() == &s_info); + return m_previous.get(); + } bool transitivelyTransitionedFrom(Structure* structureToFind); - void growPropertyStorageCapacity(); - unsigned propertyStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); return m_propertyStorageCapacity; } - unsigned propertyStorageSize() const { ASSERT(structure()->classInfo() == &s_info); return (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); } - bool isUsingInlineStorage() const; + void growOutOfLineCapacity(); + unsigned outOfLineCapacity() const + { + ASSERT(structure()->classInfo() == &s_info); + return m_outOfLineCapacity; + } + unsigned outOfLineSizeForKnownFinalObject() const + { + ASSERT(m_typeInfo.type() == FinalObjectType); + if (m_propertyTable) { + unsigned totalSize = m_propertyTable->propertyStorageSize(); + if (totalSize < static_cast<unsigned>(inlineStorageCapacity)) + return 0; + return totalSize - inlineStorageCapacity; + } + return numberOfOutOfLineSlotsForLastOffset(m_offset); + } + unsigned outOfLineSizeForKnownNonFinalObject() const + { + ASSERT(m_typeInfo.type() != FinalObjectType); + if (m_propertyTable) + return m_propertyTable->propertyStorageSize(); + return numberOfOutOfLineSlotsForLastOffset(m_offset); + } + 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_typeInfo.type() == FinalObjectType; + } + unsigned inlineCapacity() const + { + if (hasInlineStorage()) + return inlineStorageCapacity; + return 0; + } + unsigned inlineSizeForKnownFinalObject() const + { + ASSERT(m_typeInfo.type() == FinalObjectType); + unsigned result; + if (m_propertyTable) + result = m_propertyTable->propertyStorageSize(); + else + result = m_offset + 1; + if (result > static_cast<unsigned>(inlineStorageCapacity)) + return inlineStorageCapacity; + return result; + } + unsigned inlineSize() const + { + if (!hasInlineStorage()) + return 0; + return inlineSizeForKnownFinalObject(); + } + 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 inlineStorageCapacity; + } + PropertyOffset lastValidOffset() const + { + if (m_propertyTable) { + PropertyOffset size = m_propertyTable->propertyStorageSize(); + if (!hasInlineStorage()) + size += inlineStorageCapacity; + return size - 1; + } + return m_offset; + } + bool isValidOffset(PropertyOffset offset) const + { + return offset >= firstValidOffset() + && offset <= lastValidOffset(); + } - size_t get(JSGlobalData&, PropertyName); - size_t get(JSGlobalData&, const UString& name); - JS_EXPORT_PRIVATE size_t get(JSGlobalData&, PropertyName, unsigned& attributes, JSCell*& specificValue); + PropertyOffset get(JSGlobalData&, PropertyName); + PropertyOffset get(JSGlobalData&, const UString& name); + JS_EXPORT_PRIVATE PropertyOffset get(JSGlobalData&, PropertyName, unsigned& attributes, JSCell*& specificValue); bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; } @@ -160,7 +273,12 @@ namespace JSC { bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; } - bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; } + 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; } @@ -256,8 +374,8 @@ namespace JSC { } DictionaryKind; static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind); - size_t putSpecificValue(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue); - size_t remove(PropertyName); + PropertyOffset putSpecificValue(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue); + PropertyOffset remove(PropertyName); void createPropertyMap(unsigned keyCount = 0); void checkConsistency(); @@ -284,7 +402,7 @@ namespace JSC { 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 m_offset == noOffset ? 0 : m_offset + 1; + return numberOfSlotsForLastOffset(m_offset, m_typeInfo.type()); } bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const; @@ -293,8 +411,6 @@ namespace JSC { static const int s_maxTransitionLength = 64; - static const int noOffset = -1; - static const unsigned maxSpecificFunctionThrashCount = 3; TypeInfo m_typeInfo; @@ -319,10 +435,10 @@ namespace JSC { mutable InlineWatchpointSet m_transitionWatchpointSet; - uint32_t m_propertyStorageCapacity; + uint32_t m_outOfLineCapacity; // m_offset does not account for anonymous slots - int m_offset; + PropertyOffset m_offset; unsigned m_dictionaryKind : 2; bool m_isPinnedPropertyTable : 1; @@ -336,26 +452,26 @@ namespace JSC { unsigned m_staticFunctionReified; }; - inline size_t Structure::get(JSGlobalData& globalData, PropertyName propertyName) + inline PropertyOffset Structure::get(JSGlobalData& globalData, PropertyName propertyName) { ASSERT(structure()->classInfo() == &s_info); materializePropertyMapIfNecessary(globalData); if (!m_propertyTable) - return notFound; + return invalidOffset; PropertyMapEntry* entry = m_propertyTable->find(propertyName.uid()).first; - return entry ? entry->offset : notFound; + return entry ? entry->offset : invalidOffset; } - inline size_t Structure::get(JSGlobalData& globalData, const UString& name) + inline PropertyOffset Structure::get(JSGlobalData& globalData, const UString& name) { ASSERT(structure()->classInfo() == &s_info); materializePropertyMapIfNecessary(globalData); if (!m_propertyTable) - return notFound; + return invalidOffset; PropertyMapEntry* entry = m_propertyTable->findWithString(name.impl()).first; - return entry ? entry->offset : notFound; + return entry ? entry->offset : invalidOffset; } inline JSValue JSValue::structureOrUndefined() const |