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.h475
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