scudo: Move the configuration for the primary allocator to Config. NFCI.

This will allow the primary and secondary allocators to share
the MaySupportMemoryTagging bool.

Differential Revision: https://reviews.llvm.org/D93728

GitOrigin-RevId: 6dfe5801e01d259d00198147b27438ffea39e59f
diff --git a/allocator_config.h b/allocator_config.h
index 8f1757d..12daaa2 100644
--- a/allocator_config.h
+++ b/allocator_config.h
@@ -25,13 +25,18 @@
 
 struct DefaultConfig {
   using SizeClassMap = DefaultSizeClassMap;
+  static const bool MaySupportMemoryTagging = false;
+
 #if SCUDO_CAN_USE_PRIMARY64
-  // 1GB Regions
-  typedef SizeClassAllocator64<SizeClassMap, 30U> Primary;
+  typedef SizeClassAllocator64<DefaultConfig> Primary;
+  static const uptr PrimaryRegionSizeLog = 30U;
 #else
-  // 512KB regions
-  typedef SizeClassAllocator32<SizeClassMap, 19U> Primary;
+  typedef SizeClassAllocator32<DefaultConfig> Primary;
+  static const uptr PrimaryRegionSizeLog = 19U;
 #endif
+  static const s32 PrimaryMinReleaseToOsIntervalMs = INT32_MIN;
+  static const s32 PrimaryMaxReleaseToOsIntervalMs = INT32_MAX;
+
   typedef MapAllocatorCache<DefaultConfig> SecondaryCache;
   static const u32 SecondaryCacheEntriesArraySize = 32U;
   static const u32 SecondaryCacheDefaultMaxEntriesCount = 32U;
@@ -44,15 +49,18 @@
 
 struct AndroidConfig {
   using SizeClassMap = AndroidSizeClassMap;
+  static const bool MaySupportMemoryTagging = true;
+
 #if SCUDO_CAN_USE_PRIMARY64
-  // 256MB regions
-  typedef SizeClassAllocator64<SizeClassMap, 28U, 1000, 1000,
-                               /*MaySupportMemoryTagging=*/true>
-      Primary;
+  typedef SizeClassAllocator64<AndroidConfig> Primary;
+  static const uptr PrimaryRegionSizeLog = 28U;
 #else
-  // 256KB regions
-  typedef SizeClassAllocator32<SizeClassMap, 18U, 1000, 1000> Primary;
+  typedef SizeClassAllocator32<AndroidConfig> Primary;
+  static const uptr PrimaryRegionSizeLog = 18U;
 #endif
+  static const s32 PrimaryMinReleaseToOsIntervalMs = 1000;
+  static const s32 PrimaryMaxReleaseToOsIntervalMs = 1000;
+
   typedef MapAllocatorCache<AndroidConfig> SecondaryCache;
   static const u32 SecondaryCacheEntriesArraySize = 256U;
   static const u32 SecondaryCacheDefaultMaxEntriesCount = 32U;
@@ -66,13 +74,18 @@
 
 struct AndroidSvelteConfig {
   using SizeClassMap = SvelteSizeClassMap;
+  static const bool MaySupportMemoryTagging = false;
+
 #if SCUDO_CAN_USE_PRIMARY64
-  // 128MB regions
-  typedef SizeClassAllocator64<SizeClassMap, 27U, 1000, 1000> Primary;
+  typedef SizeClassAllocator64<AndroidSvelteConfig> Primary;
+  static const uptr PrimaryRegionSizeLog = 27U;
 #else
-  // 64KB regions
-  typedef SizeClassAllocator32<SizeClassMap, 16U, 1000, 1000> Primary;
+  typedef SizeClassAllocator32<AndroidSvelteConfig> Primary;
+  static const uptr PrimaryRegionSizeLog = 16U;
 #endif
+  static const s32 PrimaryMinReleaseToOsIntervalMs = 1000;
+  static const s32 PrimaryMaxReleaseToOsIntervalMs = 1000;
+
   typedef MapAllocatorCache<AndroidSvelteConfig> SecondaryCache;
   static const u32 SecondaryCacheEntriesArraySize = 16U;
   static const u32 SecondaryCacheDefaultMaxEntriesCount = 4U;
@@ -86,8 +99,14 @@
 
 #if SCUDO_CAN_USE_PRIMARY64
 struct FuchsiaConfig {
-  // 1GB Regions
-  typedef SizeClassAllocator64<DefaultSizeClassMap, 30U> Primary;
+  using SizeClassMap = DefaultSizeClassMap;
+  static const bool MaySupportMemoryTagging = false;
+
+  typedef SizeClassAllocator64<FuchsiaConfig> Primary;
+  static const uptr PrimaryRegionSizeLog = 30U;
+  static const s32 PrimaryMinReleaseToOsIntervalMs = INT32_MIN;
+  static const s32 PrimaryMaxReleaseToOsIntervalMs = INT32_MAX;
+
   typedef MapAllocatorNoCache SecondaryCache;
   template <class A>
   using TSDRegistryT = TSDRegistrySharedT<A, 8U, 4U>; // Shared, max 8 TSDs.
diff --git a/memtag.h b/memtag.h
index c3c4f57..d848e3a 100644
--- a/memtag.h
+++ b/memtag.h
@@ -268,6 +268,11 @@
   *TaggedEnd = storeTags(*TaggedBegin, *TaggedBegin + Size);
 }
 
+template <typename Config>
+inline constexpr bool allocatorSupportsMemoryTagging() {
+  return archSupportsMemoryTagging() && Config::MaySupportMemoryTagging;
+}
+
 } // namespace scudo
 
 #endif
diff --git a/primary32.h b/primary32.h
index 0db95d2..c744670 100644
--- a/primary32.h
+++ b/primary32.h
@@ -39,20 +39,15 @@
 // Memory used by this allocator is never unmapped but can be partially
 // reclaimed if the platform allows for it.
 
-template <class SizeClassMapT, uptr RegionSizeLog,
-          s32 MinReleaseToOsIntervalMs = INT32_MIN,
-          s32 MaxReleaseToOsIntervalMs = INT32_MAX>
-class SizeClassAllocator32 {
+template <typename Config> class SizeClassAllocator32 {
 public:
-  typedef SizeClassMapT SizeClassMap;
+  typedef typename Config::SizeClassMap SizeClassMap;
   // The bytemap can only track UINT8_MAX - 1 classes.
   static_assert(SizeClassMap::LargestClassId <= (UINT8_MAX - 1), "");
   // Regions should be large enough to hold the largest Block.
-  static_assert((1UL << RegionSizeLog) >= SizeClassMap::MaxSize, "");
-  typedef SizeClassAllocator32<SizeClassMapT, RegionSizeLog,
-                               MinReleaseToOsIntervalMs,
-                               MaxReleaseToOsIntervalMs>
-      ThisT;
+  static_assert((1UL << Config::PrimaryRegionSizeLog) >= SizeClassMap::MaxSize,
+                "");
+  typedef SizeClassAllocator32<Config> ThisT;
   typedef SizeClassAllocatorLocalCache<ThisT> CacheT;
   typedef typename CacheT::TransferBatch TransferBatch;
   static const bool SupportsMemoryTagging = false;
@@ -199,9 +194,9 @@
 
   bool setOption(Option O, sptr Value) {
     if (O == Option::ReleaseInterval) {
-      const s32 Interval =
-          Max(Min(static_cast<s32>(Value), MaxReleaseToOsIntervalMs),
-              MinReleaseToOsIntervalMs);
+      const s32 Interval = Max(
+          Min(static_cast<s32>(Value), Config::PrimaryMaxReleaseToOsIntervalMs),
+          Config::PrimaryMinReleaseToOsIntervalMs);
       atomic_store_relaxed(&ReleaseToOsIntervalMs, Interval);
       return true;
     }
@@ -236,8 +231,9 @@
 
 private:
   static const uptr NumClasses = SizeClassMap::NumClasses;
-  static const uptr RegionSize = 1UL << RegionSizeLog;
-  static const uptr NumRegions = SCUDO_MMAP_RANGE_SIZE >> RegionSizeLog;
+  static const uptr RegionSize = 1UL << Config::PrimaryRegionSizeLog;
+  static const uptr NumRegions =
+      SCUDO_MMAP_RANGE_SIZE >> Config::PrimaryRegionSizeLog;
   static const u32 MaxNumBatches = SCUDO_ANDROID ? 4U : 8U;
   typedef FlatByteMap<NumRegions> ByteMap;
 
@@ -270,7 +266,7 @@
   static_assert(sizeof(SizeClassInfo) % SCUDO_CACHE_LINE_SIZE == 0, "");
 
   uptr computeRegionId(uptr Mem) {
-    const uptr Id = Mem >> RegionSizeLog;
+    const uptr Id = Mem >> Config::PrimaryRegionSizeLog;
     CHECK_LT(Id, NumRegions);
     return Id;
   }
diff --git a/primary64.h b/primary64.h
index f9854cb..df1310a 100644
--- a/primary64.h
+++ b/primary64.h
@@ -40,21 +40,14 @@
 // The memory used by this allocator is never unmapped, but can be partially
 // released if the platform allows for it.
 
-template <class SizeClassMapT, uptr RegionSizeLog,
-          s32 MinReleaseToOsIntervalMs = INT32_MIN,
-          s32 MaxReleaseToOsIntervalMs = INT32_MAX,
-          bool MaySupportMemoryTagging = false>
-class SizeClassAllocator64 {
+template <typename Config> class SizeClassAllocator64 {
 public:
-  typedef SizeClassMapT SizeClassMap;
-  typedef SizeClassAllocator64<
-      SizeClassMap, RegionSizeLog, MinReleaseToOsIntervalMs,
-      MaxReleaseToOsIntervalMs, MaySupportMemoryTagging>
-      ThisT;
+  typedef typename Config::SizeClassMap SizeClassMap;
+  typedef SizeClassAllocator64<Config> ThisT;
   typedef SizeClassAllocatorLocalCache<ThisT> CacheT;
   typedef typename CacheT::TransferBatch TransferBatch;
   static const bool SupportsMemoryTagging =
-      MaySupportMemoryTagging && archSupportsMemoryTagging();
+      allocatorSupportsMemoryTagging<Config>();
 
   static uptr getSizeByClassId(uptr ClassId) {
     return (ClassId == SizeClassMap::BatchClassId)
@@ -178,9 +171,9 @@
 
   bool setOption(Option O, sptr Value) {
     if (O == Option::ReleaseInterval) {
-      const s32 Interval =
-          Max(Min(static_cast<s32>(Value), MaxReleaseToOsIntervalMs),
-              MinReleaseToOsIntervalMs);
+      const s32 Interval = Max(
+          Min(static_cast<s32>(Value), Config::PrimaryMaxReleaseToOsIntervalMs),
+          Config::PrimaryMinReleaseToOsIntervalMs);
       atomic_store_relaxed(&ReleaseToOsIntervalMs, Interval);
       return true;
     }
@@ -258,7 +251,7 @@
   AtomicOptions Options;
 
 private:
-  static const uptr RegionSize = 1UL << RegionSizeLog;
+  static const uptr RegionSize = 1UL << Config::PrimaryRegionSizeLog;
   static const uptr NumClasses = SizeClassMap::NumClasses;
   static const uptr PrimarySize = RegionSize * NumClasses;
 
@@ -308,7 +301,7 @@
   }
 
   uptr getRegionBaseByClassId(uptr ClassId) const {
-    return PrimaryBase + (ClassId << RegionSizeLog);
+    return PrimaryBase + (ClassId << Config::PrimaryRegionSizeLog);
   }
 
   NOINLINE TransferBatch *populateFreeList(CacheT *C, uptr ClassId,
diff --git a/tests/combined_test.cpp b/tests/combined_test.cpp
index b0ab024..5387493 100644
--- a/tests/combined_test.cpp
+++ b/tests/combined_test.cpp
@@ -401,10 +401,15 @@
 
 static const scudo::uptr DeathRegionSizeLog = 20U;
 struct DeathConfig {
+  static const bool MaySupportMemoryTagging = false;
+
   // Tiny allocator, its Primary only serves chunks of four sizes.
-  using DeathSizeClassMap = scudo::FixedSizeClassMap<DeathSizeClassConfig>;
-  typedef scudo::SizeClassAllocator64<DeathSizeClassMap, DeathRegionSizeLog>
-      Primary;
+  using SizeClassMap = scudo::FixedSizeClassMap<DeathSizeClassConfig>;
+  typedef scudo::SizeClassAllocator64<DeathConfig> Primary;
+  static const scudo::uptr PrimaryRegionSizeLog = DeathRegionSizeLog;
+  static const scudo::s32 PrimaryMinReleaseToOsIntervalMs = INT32_MIN;
+  static const scudo::s32 PrimaryMaxReleaseToOsIntervalMs = INT32_MAX;
+
   typedef scudo::MapAllocatorNoCache SecondaryCache;
   template <class A> using TSDRegistryT = scudo::TSDRegistrySharedT<A, 1U, 1U>;
 };
@@ -460,13 +465,13 @@
   std::vector<void *> V;
   scudo::uptr FailedAllocationsCount = 0;
   for (scudo::uptr ClassId = 1U;
-       ClassId <= DeathConfig::DeathSizeClassMap::LargestClassId; ClassId++) {
+       ClassId <= DeathConfig::SizeClassMap::LargestClassId; ClassId++) {
     const scudo::uptr Size =
-        DeathConfig::DeathSizeClassMap::getSizeByClassId(ClassId);
+        DeathConfig::SizeClassMap::getSizeByClassId(ClassId);
     // Allocate enough to fill all of the regions above this one.
     const scudo::uptr MaxNumberOfChunks =
         ((1U << DeathRegionSizeLog) / Size) *
-        (DeathConfig::DeathSizeClassMap::LargestClassId - ClassId + 1);
+        (DeathConfig::SizeClassMap::LargestClassId - ClassId + 1);
     void *P;
     for (scudo::uptr I = 0; I <= MaxNumberOfChunks; I++) {
       P = Allocator->allocate(Size - 64U, Origin);
diff --git a/tests/primary_test.cpp b/tests/primary_test.cpp
index 67d1fe5..eed6431 100644
--- a/tests/primary_test.cpp
+++ b/tests/primary_test.cpp
@@ -52,20 +52,51 @@
   Str.output();
 }
 
+template <typename SizeClassMapT> struct TestConfig1 {
+  using SizeClassMap = SizeClassMapT;
+  static const scudo::uptr PrimaryRegionSizeLog = 18U;
+  static const scudo::s32 PrimaryMinReleaseToOsIntervalMs = INT32_MIN;
+  static const scudo::s32 PrimaryMaxReleaseToOsIntervalMs = INT32_MAX;
+  static const bool MaySupportMemoryTagging = false;
+};
+
+template <typename SizeClassMapT> struct TestConfig2 {
+  using SizeClassMap = SizeClassMapT;
+  static const scudo::uptr PrimaryRegionSizeLog = 24U;
+  static const scudo::s32 PrimaryMinReleaseToOsIntervalMs = INT32_MIN;
+  static const scudo::s32 PrimaryMaxReleaseToOsIntervalMs = INT32_MAX;
+  static const bool MaySupportMemoryTagging = false;
+};
+
+template <typename SizeClassMapT> struct TestConfig3 {
+  using SizeClassMap = SizeClassMapT;
+  static const scudo::uptr PrimaryRegionSizeLog = 24U;
+  static const scudo::s32 PrimaryMinReleaseToOsIntervalMs = INT32_MIN;
+  static const scudo::s32 PrimaryMaxReleaseToOsIntervalMs = INT32_MAX;
+  static const bool MaySupportMemoryTagging = true;
+};
+
 TEST(ScudoPrimaryTest, BasicPrimary) {
   using SizeClassMap = scudo::DefaultSizeClassMap;
 #if !SCUDO_FUCHSIA
-  testPrimary<scudo::SizeClassAllocator32<SizeClassMap, 18U>>();
+  testPrimary<scudo::SizeClassAllocator32<TestConfig1<SizeClassMap>>>();
 #endif
-  testPrimary<scudo::SizeClassAllocator64<SizeClassMap, 24U>>();
-  testPrimary<scudo::SizeClassAllocator64<SizeClassMap, 24U, INT32_MIN,
-                                          INT32_MAX, true>>();
+  testPrimary<scudo::SizeClassAllocator64<TestConfig2<SizeClassMap>>>();
+  testPrimary<scudo::SizeClassAllocator64<TestConfig3<SizeClassMap>>>();
 }
 
+struct SmallRegionsConfig {
+  using SizeClassMap = scudo::DefaultSizeClassMap;
+  static const scudo::uptr PrimaryRegionSizeLog = 20U;
+  static const scudo::s32 PrimaryMinReleaseToOsIntervalMs = INT32_MIN;
+  static const scudo::s32 PrimaryMaxReleaseToOsIntervalMs = INT32_MAX;
+  static const bool MaySupportMemoryTagging = false;
+};
+
 // The 64-bit SizeClassAllocator can be easily OOM'd with small region sizes.
 // For the 32-bit one, it requires actually exhausting memory, so we skip it.
 TEST(ScudoPrimaryTest, Primary64OOM) {
-  using Primary = scudo::SizeClassAllocator64<scudo::DefaultSizeClassMap, 20U>;
+  using Primary = scudo::SizeClassAllocator64<SmallRegionsConfig>;
   using TransferBatch = Primary::CacheT::TransferBatch;
   Primary Allocator;
   Allocator.init(/*ReleaseToOsInterval=*/-1);
@@ -142,11 +173,10 @@
 TEST(ScudoPrimaryTest, PrimaryIterate) {
   using SizeClassMap = scudo::DefaultSizeClassMap;
 #if !SCUDO_FUCHSIA
-  testIteratePrimary<scudo::SizeClassAllocator32<SizeClassMap, 18U>>();
+  testIteratePrimary<scudo::SizeClassAllocator32<TestConfig1<SizeClassMap>>>();
 #endif
-  testIteratePrimary<scudo::SizeClassAllocator64<SizeClassMap, 24U>>();
-  testIteratePrimary<scudo::SizeClassAllocator64<SizeClassMap, 24U, INT32_MIN,
-                                                 INT32_MAX, true>>();
+  testIteratePrimary<scudo::SizeClassAllocator64<TestConfig2<SizeClassMap>>>();
+  testIteratePrimary<scudo::SizeClassAllocator64<TestConfig3<SizeClassMap>>>();
 }
 
 static std::mutex Mutex;
@@ -204,11 +234,10 @@
 TEST(ScudoPrimaryTest, PrimaryThreaded) {
   using SizeClassMap = scudo::SvelteSizeClassMap;
 #if !SCUDO_FUCHSIA
-  testPrimaryThreaded<scudo::SizeClassAllocator32<SizeClassMap, 18U>>();
+  testPrimaryThreaded<scudo::SizeClassAllocator32<TestConfig1<SizeClassMap>>>();
 #endif
-  testPrimaryThreaded<scudo::SizeClassAllocator64<SizeClassMap, 24U>>();
-  testPrimaryThreaded<scudo::SizeClassAllocator64<SizeClassMap, 24U, INT32_MIN,
-                                                  INT32_MAX, true>>();
+  testPrimaryThreaded<scudo::SizeClassAllocator64<TestConfig2<SizeClassMap>>>();
+  testPrimaryThreaded<scudo::SizeClassAllocator64<TestConfig3<SizeClassMap>>>();
 }
 
 // Through a simple allocation that spans two pages, verify that releaseToOS
@@ -236,9 +265,8 @@
 TEST(ScudoPrimaryTest, ReleaseToOS) {
   using SizeClassMap = scudo::DefaultSizeClassMap;
 #if !SCUDO_FUCHSIA
-  testReleaseToOS<scudo::SizeClassAllocator32<SizeClassMap, 18U>>();
+  testReleaseToOS<scudo::SizeClassAllocator32<TestConfig1<SizeClassMap>>>();
 #endif
-  testReleaseToOS<scudo::SizeClassAllocator64<SizeClassMap, 24U>>();
-  testReleaseToOS<scudo::SizeClassAllocator64<SizeClassMap, 24U, INT32_MIN,
-                                              INT32_MAX, true>>();
+  testReleaseToOS<scudo::SizeClassAllocator64<TestConfig2<SizeClassMap>>>();
+  testReleaseToOS<scudo::SizeClassAllocator64<TestConfig3<SizeClassMap>>>();
 }