diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/Structure.h')
| -rw-r--r-- | Source/JavaScriptCore/runtime/Structure.h | 475 |
1 files changed, 130 insertions, 345 deletions
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index 392ca9176..c73e8cb96 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2012-2016 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 @@ -10,10 +10,10 @@ * 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 INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -29,7 +29,6 @@ #include "ClassInfo.h" #include "ConcurrentJITLock.h" #include "IndexingType.h" -#include "InferredTypeTable.h" #include "JSCJSValue.h" #include "JSCell.h" #include "JSType.h" @@ -38,24 +37,17 @@ #include "PropertyOffset.h" #include "Protect.h" #include "PutPropertySlot.h" -#include "StructureIDBlob.h" #include "StructureRareData.h" -#include "StructureRareDataInlines.h" #include "StructureTransitionTable.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> +#include <wtf/text/StringImpl.h> -namespace WTF { - -class UniquedStringImpl; - -} // namespace WTF namespace JSC { @@ -65,7 +57,6 @@ class PropertyNameArray; class PropertyNameArrayData; class PropertyTable; class StructureChain; -class StructureShape; class SlotVisitor; class JSString; struct DumpContext; @@ -79,66 +70,14 @@ static const unsigned initialOutOfLineCapacity = 4; // initial allocation. static const unsigned outOfLineGrowthFactor = 2; -struct PropertyMapEntry { - UniquedStringImpl* key; - PropertyOffset offset; - uint8_t attributes; - bool hasInferredType; // This caches whether or not a property has an inferred type in the inferred type table, and is used for a fast check in JSObject::putDirectInternal(). - - 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) - { - } - - virtual 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 { +class Structure : public JSCell { public: friend class StructureTransitionTable; 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); - ~Structure(); - protected: void finishCreation(VM& vm) { @@ -156,90 +95,66 @@ protected: } 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&, 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&); + JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext); + static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, StringImpl* uid, 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* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes); - JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr); + 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*); - JS_EXPORT_PRIVATE static Structure* sealTransition(VM&, Structure*); - JS_EXPORT_PRIVATE static Structure* freezeTransition(VM&, Structure*); + static Structure* sealTransition(VM&, Structure*); + static Structure* freezeTransition(VM&, Structure*); static Structure* preventExtensionsTransition(VM&, Structure*); - JS_EXPORT_PRIVATE static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition); + static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition); - JS_EXPORT_PRIVATE bool isSealed(VM&); - JS_EXPORT_PRIVATE bool isFrozen(VM&); - bool isExtensible() const { return !preventExtensions(); } + bool isSealed(VM&); + bool isFrozen(VM&); + bool isExtensible() const { return !m_preventExtensions; } + bool didTransition() const { return m_didTransition; } bool putWillGrowOutOfLineStorage(); - size_t suggestedNewOutOfLineStorageCapacity(); + JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity(); - JS_EXPORT_PRIVATE Structure* flattenDictionaryStructure(VM&, JSObject*); + 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); + 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); } - bool isDictionary() const { return dictionaryKind() != NoneDictionaryKind; } - bool isUncacheableDictionary() const { return dictionaryKind() == UncachedDictionaryKind; } - - bool propertyAccessesAreCacheable() - { - return dictionaryKind() != UncachedDictionaryKind - && !typeInfo().prohibitsPropertyCaching() - && !(typeInfo().getOwnPropertySlotIsImpure() && !typeInfo().newImpurePropertyFiresWatchpoints()); - } + bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; } + bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; } - bool propertyAccessesAreCacheableForAbsence() - { - return !typeInfo().getOwnPropertySlotIsImpureForPropertyAbsence(); - } - - bool needImpurePropertyWatchpoint() - { - return propertyAccessesAreCacheable() - && typeInfo().getOwnPropertySlotIsImpure() - && typeInfo().newImpurePropertyFiresWatchpoints(); - } + bool propertyAccessesAreCacheable() { return m_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().getOwnPropertySlotIsImpure(); + ASSERT(!typeInfo().hasImpureGetOwnPropertySlot() || typeInfo().newImpurePropertyFiresWatchpoints()); + return typeInfo().hasImpureGetOwnPropertySlot(); } - + // Type accessors. - TypeInfo typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_blob.typeInfo(m_outOfLineTypeFlags); } + const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_typeInfo; } bool isObject() const { return typeInfo().isObject(); } - IndexingType indexingType() const { return m_blob.indexingType() & AllArrayTypes; } - IndexingType indexingTypeIncludingHistory() const { return m_blob.indexingType(); } + IndexingType indexingType() const { return m_indexingType & AllArrayTypes; } + IndexingType indexingTypeIncludingHistory() const { return m_indexingType; } bool mayInterceptIndexedAccesses() const { return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors); } - JS_EXPORT_PRIVATE bool anyObjectInChainMayInterceptIndexedAccesses() const; - bool holesMustForwardToPrototype(VM&) const; + bool anyObjectInChainMayInterceptIndexedAccesses() const; bool needsSlowPutIndexing() const; NonPropertyTransition suggestedArrayStorageTransition() const; @@ -258,12 +173,14 @@ public: static void visitChildren(JSCell*, SlotVisitor&); // Will just the prototype chain intercept this property access? - JS_EXPORT_PRIVATE bool prototypeChainMayInterceptStoreTo(VM&, PropertyName); + bool prototypeChainMayInterceptStoreTo(VM&, PropertyName); + + bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; } Structure* previousID() const { ASSERT(structure()->classInfo() == info()); - if (hasRareData()) + if (typeInfo().structureHasRareData()) return rareData()->previousID(); return previous(); } @@ -320,16 +237,11 @@ public: && offset <= m_offset && (offset < m_inlineCapacity || offset >= firstOutOfLineOffset); } - - bool hijacksIndexingHeader() const - { - return isTypedView(m_classInfo->typedArrayStorageType); - } bool couldHaveIndexingHeader() const { return hasIndexedProperties(indexingType()) - || hijacksIndexingHeader(); + || isTypedView(m_classInfo->typedArrayStorageType); } bool hasIndexingHeader(const JSCell*) const; @@ -337,66 +249,66 @@ public: bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject); PropertyOffset get(VM&, PropertyName); - PropertyOffset get(VM&, PropertyName, unsigned& attributes); - PropertyOffset get(VM&, PropertyName, unsigned& attributes, bool& hasInferredType); - - // 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__) + PropertyOffset get(VM&, const WTF::String& name); + JS_EXPORT_PRIVATE PropertyOffset get(VM&, PropertyName, unsigned& attributes, JSCell*& specificValue); + + PropertyOffset getConcurrently(VM&, StringImpl* uid); + PropertyOffset getConcurrently(VM&, StringImpl* uid, unsigned& attributes, JSCell*& specificValue); + + bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } + bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; } + void setHasGetterSetterProperties(bool is__proto__) { - setHasGetterSetterProperties(true); + m_hasGetterSetterProperties = true; if (!is__proto__) - setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); + m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; } - - void setContainsReadOnlyProperties() { setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); } - - void setHasCustomGetterSetterPropertiesWithProtoCheck(bool is__proto__) + void setContainsReadOnlyProperties() { - setHasCustomGetterSetterProperties(true); - if (!is__proto__) - setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); + m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; } - + + bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; } + bool isEmpty() const { ASSERT(checkOffsetConsistency()); return !JSC::isValidOffset(m_offset); } - void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*); - JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const; - bool canCachePropertyNameEnumerator() const; - bool canAccessPropertiesQuickly() 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 (!hasRareData()) + if (!typeInfo().structureHasRareData()) return 0; return rareData()->objectToStringValue(); } - void setObjectToStringValue(ExecState*, VM&, JSString* value, PropertySlot toStringTagSymbolSlot); + void setObjectToStringValue(VM& vm, const JSCell* owner, JSString* value) + { + if (!typeInfo().structureHasRareData()) + allocateRareData(vm); + rareData()->setObjectToStringValue(vm, owner, value); + } - const ClassInfo* classInfo() const { return m_classInfo; } + bool staticFunctionsReified() + { + return m_staticFunctionReified; + } - static ptrdiff_t structureIDOffset() + void setStaticFunctionsReified() { - return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::structureIDOffset(); + m_staticFunctionReified = true; } + const ClassInfo* classInfo() const { return m_classInfo; } + static ptrdiff_t prototypeOffset() { return OBJECT_OFFSETOF(Structure, m_prototype); @@ -407,6 +319,16 @@ public: 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); @@ -414,7 +336,7 @@ public: static ptrdiff_t indexingTypeOffset() { - return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeOffset(); + return OBJECT_OFFSETOF(Structure, m_indexingType); } static Structure* createStructure(VM&); @@ -428,124 +350,22 @@ public: { 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 - - // - We don't watch Structures that either decided not to be watched, or whose predecessors - // decided not to be watched. This happens either when a transition is fired while being - // watched. - if (transitionWatchpointIsLikelyToBeFired()) - return false; - - // - Don't watch Structures that had been dictionaries. - 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) + + void notifyTransitionFromThisStructure() const { - if (LIKELY(didWatchInternalProperties())) - return; - startWatchingInternalProperties(vm); + m_transitionWatchpointSet.fireAll(); } - void startWatchingInternalPropertiesIfNecessaryForEntireChain(VM& vm) - { - for (Structure* structure = this; structure; structure = structure->storedPrototypeStructure()) - structure->startWatchingInternalPropertiesIfNecessary(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; - } - - // Call this when we know that this is a brand new property. Note that it's not enough for the - // property to be brand new to some object. It has to be brand new to the Structure. - 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); - } - - // Call this when we know that this is a new property for the object, but not new for the - // structure. Therefore, under the InferredTypeTable's rules, absence of the property from the - // table means Top rather than Bottom. - ALWAYS_INLINE void willStoreValueForExistingTransition( - VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize) - { - if (hasBeenDictionary() || !m_inferredTypeTable) - return; - willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::NewProperty); - } - - // Call this when we know that the inferred type table exists and has an entry for this property. - ALWAYS_INLINE void willStoreValueForReplace( - VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize) + InlineWatchpointSet& transitionWatchpointSet() const { - if (hasBeenDictionary()) - return; - willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::OldProperty); + return m_transitionWatchpointSet; } - - 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; @@ -556,49 +376,15 @@ public: 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, 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); - DEFINE_BITFIELD(bool, transitionWatchpointIsLikelyToBeFired, TransitionWatchpointIsLikelyToBeFired, 1, 27); - DEFINE_BITFIELD(bool, hasBeenDictionary, HasBeenDictionary, 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*); + Structure(VM&, const Structure*); - static Structure* create(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr); + static Structure* create(VM&, const Structure*); - static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&); + static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&); // 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 @@ -606,20 +392,28 @@ private: // to unlock it. void findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*&, PropertyTable*&); - static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind, DeferredStructureTransitionWatchpointFire* = nullptr); + typedef enum { + NoneDictionaryKind = 0, + CachedDictionaryKind = 1, + UncachedDictionaryKind = 2 + } DictionaryKind; + static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind); - PropertyOffset add(VM&, PropertyName, unsigned attributes); + PropertyOffset putSpecificValue(VM&, PropertyName, unsigned attributes, JSCell* specificValue); PropertyOffset remove(PropertyName); void createPropertyMap(const GCSafeConcurrentJITLocker&, VM&, unsigned keyCount = 0); void checkConsistency(); + bool despecifyFunction(VM&, PropertyName); + void despecifyAllFunctions(VM&); + WriteBarrier<PropertyTable>& propertyTable(); - PropertyTable* takePropertyTableOrCloneIfPinned(VM&); - PropertyTable* copyPropertyTable(VM&); - PropertyTable* copyPropertyTableForPinning(VM&); + PropertyTable* takePropertyTableOrCloneIfPinned(VM&, Structure* owner); + PropertyTable* copyPropertyTable(VM&, Structure* owner); + PropertyTable* copyPropertyTableForPinning(VM&, Structure* owner); JS_EXPORT_PRIVATE void materializePropertyMap(VM&); - ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, DeferGC&) + void materializePropertyMapIfNecessary(VM& vm, DeferGC&) { ASSERT(!isCompilationThread()); ASSERT(structure()->classInfo() == info()); @@ -627,18 +421,6 @@ private: 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()); @@ -647,17 +429,17 @@ private: materializePropertyMap(vm); } - void setPreviousID(VM& vm, Structure* structure) + void setPreviousID(VM& vm, Structure* transition, Structure* structure) { - if (hasRareData()) - rareData()->setPreviousID(vm, structure); + if (typeInfo().structureHasRareData()) + rareData()->setPreviousID(vm, transition, structure); else - m_previousOrRareData.set(vm, this, structure); + m_previousOrRareData.set(vm, transition, structure); } void clearPreviousID() { - if (hasRareData()) + if (typeInfo().structureHasRareData()) rareData()->clearPreviousID(); else m_previousOrRareData.clear(); @@ -676,40 +458,34 @@ private: Structure* previous() const { - ASSERT(!hasRareData()); + ASSERT(!typeInfo().structureHasRareData()); return static_cast<Structure*>(m_previousOrRareData.get()); } StructureRareData* rareData() const { - ASSERT(hasRareData()); + ASSERT(typeInfo().structureHasRareData()); return static_cast<StructureRareData*>(m_previousOrRareData.get()); } bool checkOffsetConsistency() const; - JS_EXPORT_PRIVATE void allocateRareData(VM&); - - void startWatchingInternalProperties(VM&); - - JS_EXPORT_PRIVATE void willStoreValueSlow( - VM&, PropertyName, JSValue, bool, InferredTypeTable::StoredPropertyAge); + void allocateRareData(VM&); + void cloneRareDataFrom(VM&, const Structure*); static const int s_maxTransitionLength = 64; static const int s_maxTransitionLengthForNonEvalPutById = 512; - // These need to be properly aligned at the beginning of the 'Structure' - // part of the object. - StructureIDBlob m_blob; - TypeInfo::OutOfLineTypeFlags m_outOfLineTypeFlags; - + static const unsigned maxSpecificFunctionThrashCount = 3; + WriteBarrier<JSGlobalObject> m_globalObject; WriteBarrier<Unknown> m_prototype; mutable WriteBarrier<StructureChain> m_cachedPrototypeChain; WriteBarrier<JSCell> m_previousOrRareData; - RefPtr<UniquedStringImpl> m_nameInPrevious; + RefPtr<StringImpl> m_nameInPrevious; + WriteBarrier<JSCell> m_specificValueInPrevious; const ClassInfo* m_classInfo; @@ -718,8 +494,6 @@ private: // Should be accessed through propertyTable(). During GC, it may be set to 0 by another thread. WriteBarrier<PropertyTable> m_propertyTableUnsafe; - WriteBarrier<InferredTypeTable> m_inferredTypeTable; - mutable InlineWatchpointSet m_transitionWatchpointSet; COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits); @@ -727,11 +501,22 @@ private: // m_offset does not account for anonymous slots PropertyOffset m_offset; + TypeInfo m_typeInfo; + IndexingType m_indexingType; uint8_t m_inlineCapacity; ConcurrentJITLock m_lock; - uint32_t m_bitField; + 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 : 1; }; } // namespace JSC |
