From 6c0bb6af8b21fa5d29264200570b6012bdec00f1 Mon Sep 17 00:00:00 2001 From: Max Wang Date: Tue, 24 Mar 2020 13:42:44 -0700 Subject: [PATCH] Reorder Class data members Summary: Over the last five years, we've added a lot of miscellaneous gunk into Class in a non-deliberate order. Clean this up a bit, which saves a few words (pushing some Class allocations into a smaller size class). Additionally, the access profile for these data members have changed. Redo the layout to respect the current patterns. Reviewed By: ricklavoie Differential Revision: D20500342 fbshipit-source-id: aa992aed6b8eff930d29521e45234a38d457d7b3 --- hphp/runtime/vm/class.cpp | 23 ++-- hphp/runtime/vm/class.h | 293 +++++++++++++++++++++++++--------------------- 2 files changed, 171 insertions(+), 145 deletions(-) diff --git a/hphp/runtime/vm/class.cpp b/hphp/runtime/vm/class.cpp index 7b4b4c32a04..c1554c3eb68 100644 --- a/hphp/runtime/vm/class.cpp +++ b/hphp/runtime/vm/class.cpp @@ -250,9 +250,9 @@ struct assert_sizeof_class { // If this static_assert fails, the compiler error will have the real value // of sizeof_Class in it since it's in this struct's type. #ifndef NDEBUG - static_assert(sz == (use_lowptr ? 288 : 328), "Change this only on purpose"); + static_assert(sz == (use_lowptr ? 276 : 328), "Change this only on purpose"); #else - static_assert(sz == (use_lowptr ? 280 : 320), "Change this only on purpose"); + static_assert(sz == (use_lowptr ? 272 : 320), "Change this only on purpose"); #endif }; template struct assert_sizeof_class; @@ -1810,23 +1810,20 @@ void checkDeclarationCompat(const PreClass* preClass, Class::Class(PreClass* preClass, Class* parent, VMCompactVector&& usedTraits, unsigned classVecLen, unsigned funcVecLen) -#ifndef NDEBUG - : m_magic{kMagic} - , m_parent(parent) -#else - : m_parent(parent) -#endif + : m_releaseFunc{ObjectData::release} + , m_preClass(PreClassPtr(preClass)) + , m_classVecLen(always_safe_cast(classVecLen)) + , m_funcVecLen(always_safe_cast(funcVecLen)) , m_maybeRedefsPropTy{false} , m_selfMaybeRedefsPropTy{false} , m_needsPropInitialCheck{false} , m_hasReifiedGenerics{false} , m_hasReifiedParent{false} , m_serialized(false) - , m_preClass(PreClassPtr(preClass)) - , m_classVecLen(always_safe_cast(classVecLen)) - , m_funcVecLen(always_safe_cast(funcVecLen)) - // Will be overwritten if the class has a native dtor - , m_releaseFunc{ObjectData::release} + , m_parent(parent) +#ifndef NDEBUG + , m_magic{kMagic} +#endif { if (usedTraits.size()) { allocExtraData(); diff --git a/hphp/runtime/vm/class.h b/hphp/runtime/vm/class.h index 9cf2cb8e148..e5cd824a30a 100644 --- a/hphp/runtime/vm/class.h +++ b/hphp/runtime/vm/class.h @@ -188,6 +188,10 @@ struct Class : AtomicCountable { LowPtr baseCls; Attr attrs; + + /* + * Slot number that is only valid for reflection and serialization. + */ Slot serializationIdx; }; @@ -1554,28 +1558,9 @@ private: void checkPropInitialValues() const; ///////////////////////////////////////////////////////////////////////////// - // Static data members. - -public: - ///////////////////////////////////////////////////////////////////////////// - // Data members. - // - // Ordered by usage frequency. Do not re-order for cosmetic reasons. - // - // The ordering is reverse order of hotness because m_classVec is relatively - // hot, and must be the last member. - - LowPtr m_next{nullptr}; // used by NamedEntity + // Friendship. private: - static constexpr uint32_t kMagic = 0xce7adb33; - -#ifndef NDEBUG - // For asserts only. - uint32_t m_magic; -#endif - - mutable default_ptr m_extra; template friend typename std::enable_if::value, void>::type finish_class(); @@ -1584,95 +1569,94 @@ private: friend struct StandardExtension; - RequirementMap m_requirements; - VMCompactVector m_declInterfaces; - mutable rds::Link m_nonScalarConstantCache; + ///////////////////////////////////////////////////////////////////////////// + // Static data members. - LowPtr m_toString; - LowPtr m_invoke; // __invoke, iff non-static (or closure) +private: + static constexpr uint32_t kMagic = 0xce7adb33; - ConstMap m_constants; + ///////////////////////////////////////////////////////////////////////////// + // Data members. + // + // Ordered by usage frequency. Do not re-order for cosmetic reasons. + // + // The ordering is order of hotness because the funcVec() preallocation is + // relatively hot, and must be the first member. - ClassPtr m_parent; - int32_t m_declPropNumAccessible; - mutable rds::Link, rds::Mode::NonLocal> m_cachedClass; +private: + /* + * Atomic refcount; inherited from AtomicCountable. + */ + // mutable std::atomic m_count; /* - * Whether this is a subclass of Closure whose m_invoke->m_cls has been set - * to the closure's context class. + * An exclusive upper limit on the post-sort indices of properties of this + * class that may be countable. Properties that may be countable will have + * indices less than this bound. If we can guarantee that all properties of + * this class are uncounted, the bound will be 0. + * + * (Note that there may still be uncounted properties with indices less than + * this bound; in particular, we can't sort parent class properties freely.) */ - std::atomic m_scoped{false}; + ObjectProps::quick_index m_countablePropsEnd; - /* This class, or one of its transitive parents, has a property which maybe - * redefines an existing property in an incompatible way. */ - bool m_maybeRedefsPropTy : 1; - /* This class (and not any of its transitive parents) has a property which - * maybe redefines an existing property in an incompatible way. */ - bool m_selfMaybeRedefsPropTy : 1; - /* This class has a property with an initial value which might not satisfy its - * type-hint (and therefore requires a check when initialized). */ - bool m_needsPropInitialCheck : 1; - /* This class has reified generics */ - bool m_hasReifiedGenerics : 1; - /* This class has a refied parent */ - bool m_hasReifiedParent : 1; /* - * Whether the Class requires initialization, because it has either - * {p,s}init() methods or static members, or possibly has prop type invariance - * violations. + * An index that represent the size bin in the MemoryManager. */ - bool m_needInitialization : 1; + uint8_t m_sizeIdx{0}; - bool m_needsInitThrowable : 1; - bool m_hasDeepInitProps : 1; /* - * Whether this class has been serialized yet. + * Runtime attributes computed at runtime init-time. + * + * Not to be confused with m_attrCopy which are compile-time and stored in + * the repo. */ - mutable bool m_serialized : 1; + uint8_t m_RTAttrs; - // NB: 15 bits available here (in USE_LOWPTR builds). + /* + * Bitmap of parent classes and implemented interfaces. + * + * Each bit corresponds to a commonly used class name, determined during the + * profiling warmup requests. + */ + InstanceBits::BitSet m_instanceBits; /* - * Vector of 86pinit() methods that need to be called to complete instance - * property initialization, and a pointer to a 86sinit() method that needs to - * be called to complete static property initialization (or NULL). Such - * initialization is triggered only once, the first time one of the following - * happens: - * - An instance of this class is created. - * - A static property of this class is accessed. + * Map from logical slot to physical memory index for object properties. */ - VMFixedVector m_sinitVec; - VMFixedVector m_linitVec; - LowPtr m_ctor; - PropInitVec m_declPropInit; - VMFixedVector m_pinitVec; + VMFixedVector m_slotIndex; /* - * There are two ways to index m_staticProperties. - * 1. Key can be either name or Slot, value is Prop. When used this way, - * serializationIdx field of prop is meaningless and should not be - * accessed. - * 2. Key is sequence id for serialization, value is Prop. When used this way, - * the only meaningful field of prop is serializationIdx, - * which represents a slot number. All other field is meaningless and - * should not be accessed. - * The serializationIdx is used only for reflection. + * Metadata about static properties, indexable in two ways: + * + * 1. Key is property name or Slot. This is the normal use case. + * + * 2. Key is sequence ID for serialization. When accessed in this manner, + * only `serializationIdx` is valid, and all other fields are garbage. + * (This is also the only use case in which `serializationIdx` is valid.) */ SPropMap m_staticProperties; - PreClassPtr m_preClass; - InterfaceMap m_interfaces; /* - * Bitmap of parent classes and implemented interfaces. Each bit corresponds - * to a commonly used class name, determined during the profiling warmup - * requests. + * Vector of interfaces and their vtables. */ - InstanceBits::BitSet m_instanceBits; - MethodMap m_methods; + LowPtr m_vtableVec{nullptr}; + + /* + * Pointer to a function that releases object instances of this class type. + */ + ObjReleaseFunc m_releaseFunc; + + /* + * Instance property metadata. Access is analogous to access for + * m_staticProperties. + */ + PropMap m_declProperties; /* * Static properties are stored in RDS. There are three phases of sprop * initialization: + * * 1. The array of links is itself allocated on Class creation. * 2. The links are bound either when codegen needs the handle value, or when * initSProps() is called in any request. Afterwards, m_sPropCacheInit is @@ -1680,79 +1664,124 @@ private: * 3. The RDS value at m_sPropCacheInit is set to true when initSProps() is * called, and the values are actually initialized. * - * For non-persistent classes, we put sPropCache in rds::Local, but use the - * m_sPropCacheInit flag to indicate whether sPropCache needs to be + * For non-persistent classes, we put m_sPropCache in rds::Local, but use the + * m_sPropCacheInit flag to indicate whether m_sPropCache needs to be * reinitialized. */ - mutable rds::Link* - m_sPropCache{nullptr}; mutable rds::Link m_sPropCacheInit; + mutable rds::Link< + StaticPropData, + rds::Mode::NonNormal + >* m_sPropCache{nullptr}; + + mutable default_ptr m_extra; + uint32_t m_memoSize{0}; + + LowPtr m_invoke; // __invoke, iff non-static (or closure) + + ConstMap m_constants; + + PreClassPtr m_preClass; + + unsigned m_attrCopy; veclen_t m_classVecLen; veclen_t m_funcVecLen; veclen_t m_vtableVecLen{0}; - LowPtr m_vtableVec{nullptr}; + /* - * Each ObjectData is created with enough trailing space to directly store - * the vector of declared properties. To look up a property by name and - * determine whether it is declared, use m_declPropMap. If the declared - * property index is already known (as may be the case when executing via the - * TC), property metadata in m_declPropInfo can be directly accessed. - * - * m_declPropInit is indexed by the physical index of the property within the - * objects (and not by the logical slot), and contains initialization - * information. - * - * There are two ways to index m_declProperties. - * 1. Key can be either name or Slot, value is Prop. When used this way, - * serializationIdx field of prop is meaningless and should not be - * accessed. - * 2. Key is sequence id for serialization, value is Prop. When used this way, - * the only meaningful field of prop is serializationIdx, - * which represents a slot number. All other field is meaningless and - * should not be accessed. - * The serializationIdx is used for both serialization and reflection. + * This class, or one of its ancestors, has a property which maybe redefines + * an existing property in an incompatible way. */ - PropMap m_declProperties; - - MaybeDataType m_enumBaseTy; + bool m_maybeRedefsPropTy : 1; + /* + * This class (and not any of its transitive parents) has a property which + * maybe redefines an existing property in an incompatible way. + */ + bool m_selfMaybeRedefsPropTy : 1; + /* + * This class has a property with an initial value which might not satisfy + * its type-hint (and therefore requires a check when initialized). + */ + bool m_needsPropInitialCheck : 1; + /* + * This class has reified generics. + */ + bool m_hasReifiedGenerics : 1; + /* + * This class has a refied parent. + */ + bool m_hasReifiedParent : 1; + /* + * Whether the Class requires initialization, because it has either + * {p,s}init() methods or static members, or possibly has prop type + * invariance violations. + */ + bool m_needInitialization : 1; + bool m_needsInitThrowable : 1; + bool m_hasDeepInitProps : 1; /* - * runtime attributes computed at runtime init time. Not to be confused with - * m_attrCopy which are compile-time and stored in the repo. + * Whether this class has been serialized yet. */ - uint8_t m_RTAttrs; + mutable bool m_serialized : 1; - // An index that represent the size bin in the MemoryManager - uint8_t m_sizeIdx{0}; + // NB: 7 bits available here (in USE_LOWPTR builds). - mutable rds::Link m_propDataCache; + ClassPtr m_parent; - /* Indexed by logical Slot number, gives the corresponding index within the - * objects in memory. */ - VMFixedVector m_slotIndex; + MethodMap m_methods; + InterfaceMap m_interfaces; /* - * Cache of m_preClass->attrs(). + * Vector of 86pinit() methods that need to be called to complete instance + * property initialization, and a pointer to a 86sinit() method that needs to + * be called to complete static property initialization (or NULL). Such + * initialization is triggered only once, the first time one of the following + * happens: + * - An instance of this class is created. + * - A static property of this class is accessed. */ - unsigned m_attrCopy; - - // Pointer to a function that releases object instances of this class type. - ObjReleaseFunc m_releaseFunc; - // Determines the offset to the base pointer to be released - uint32_t m_memoSize{0}; + VMFixedVector m_sinitVec; + VMFixedVector m_linitVec; + VMFixedVector m_pinitVec; /* - * An exclusive upper limit on the post-sort indices of properties of this - * class that may be countable. Properties that may be countable will have - * indices less than this bound. If we can guarantee that all properties of - * this class are uncounted, the bound will be 0. + * Initialization information about instance properties. * - * (Note that there may still be uncounted properties with indices less than - * this bound; in particular, we can't sort parent class properties freely.) + * Indexed by the _physical_ index of the property within an object, not its + * logical Slot. */ - ObjectProps::quick_index m_countablePropsEnd; + PropInitVec m_declPropInit; + + MaybeDataType m_enumBaseTy; + /* + * Whether this is a subclass of Closure whose m_invoke->m_cls has been set + * to the closure's context class. + */ + std::atomic m_scoped{false}; + int32_t m_declPropNumAccessible; + + LowPtr m_ctor; + LowPtr m_toString; + + mutable rds::Link m_propDataCache; + mutable rds::Link, rds::Mode::NonLocal> m_cachedClass; + + RequirementMap m_requirements; + VMCompactVector m_declInterfaces; + + mutable rds::Link m_nonScalarConstantCache; + +public: + LowPtr m_next{nullptr}; // used by NamedEntity + +private: +#ifndef NDEBUG + // For asserts only. + uint32_t m_magic; +#endif /* * Vector of Class pointers that encodes the inheritance hierarchy, including -- 2.11.4.GIT