[tsan] start using AllocatorCache in CombinedAllocator

git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@159825 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/sanitizer_common/sanitizer_allocator64.h b/lib/sanitizer_common/sanitizer_allocator64.h
index 679e07d..966c128 100644
--- a/lib/sanitizer_common/sanitizer_allocator64.h
+++ b/lib/sanitizer_common/sanitizer_allocator64.h
@@ -152,6 +152,8 @@
     return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClasses;
   }
 
+  uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
+
   void *GetMetaData(void *p) {
     uptr class_id = GetSizeClass(p);
     uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), class_id);
@@ -384,8 +386,10 @@
 // internal allocators:
 // PrimaryAllocator is efficient, but may not allocate some sizes (alignments).
 //  When allocating 2^x bytes it should return 2^x aligned chunk.
+// PrimaryAllocator is used via a local AllocatorCache.
 // SecondaryAllocator can allocate anything, but is not efficient.
-template <class PrimaryAllocator, class SecondaryAllocator>
+template <class PrimaryAllocator, class AllocatorCache,
+         class SecondaryAllocator>
 class CombinedAllocator {
  public:
   void Init() {
@@ -393,13 +397,13 @@
     secondary_.Init();
   }
 
-  void *Allocate(uptr size, uptr alignment) {
+  void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) {
     CHECK_GT(size, 0);
     if (alignment > 8)
       size = RoundUpTo(size, alignment);
     void *res;
     if (primary_.CanAllocate(size, alignment))
-      res = primary_.Allocate(size, alignment);
+      res = cache->Allocate(&primary_, primary_.ClassID(size));
     else
       res = secondary_.Allocate(size, alignment);
     if (alignment > 8)
@@ -407,9 +411,9 @@
     return res;
   }
 
-  void Deallocate(void *p) {
+  void Deallocate(AllocatorCache *cache, void *p) {
     if (primary_.PointerIsMine(p))
-      primary_.Deallocate(p);
+      cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
     else
       secondary_.Deallocate(p);
   }
@@ -432,6 +436,10 @@
 
   void TestOnlyUnmap() { primary_.TestOnlyUnmap(); }
 
+  void SwallowCache(AllocatorCache *cache) {
+    cache->Drain(&primary_);
+  }
+
  private:
   PrimaryAllocator primary_;
   SecondaryAllocator secondary_;
diff --git a/lib/sanitizer_common/sanitizer_list.h b/lib/sanitizer_common/sanitizer_list.h
index 4c7ce68..ef98eee 100644
--- a/lib/sanitizer_common/sanitizer_list.h
+++ b/lib/sanitizer_common/sanitizer_list.h
@@ -74,8 +74,8 @@
     CHECK_NE(this, l);
     if (empty()) {
       *this = *l;
-    } else {
-      l->last_ = first_;
+    } else if (!l->empty()) {
+      l->last_->next = first_;
       first_ = l->first_;
       size_ += l->size();
     }
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
index 62b4329..cbb71db 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
@@ -20,6 +20,8 @@
 typedef DefaultSizeClassMap SCMap;
 typedef
   SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 16, SCMap> Allocator;
+typedef SizeClassAllocatorLocalCache<Allocator::kNumClasses, Allocator>
+  AllocatorCache;
 
 TEST(SanitizerCommon, DefaultSizeClassMap) {
 #if 0
@@ -182,10 +184,13 @@
 TEST(SanitizerCommon, CombinedAllocator) {
   typedef Allocator PrimaryAllocator;
   typedef LargeMmapAllocator SecondaryAllocator;
-  typedef CombinedAllocator<PrimaryAllocator, SecondaryAllocator> Allocator;
+  typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+          SecondaryAllocator> Allocator;
 
+  AllocatorCache cache;
   Allocator a;
   a.Init();
+  cache.Init();
   const uptr kNumAllocs = 100000;
   const uptr kNumIter = 10;
   for (uptr iter = 0; iter < kNumIter; iter++) {
@@ -194,7 +199,7 @@
       uptr size = (i % (1 << 14)) + 1;
       if ((i % 1024) == 0)
         size = 1 << (10 + (i % 14));
-      void *x = a.Allocate(size, 1);
+      void *x = a.Allocate(&cache, size, 1);
       uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
       CHECK_EQ(*meta, 0);
       *meta = size;
@@ -209,15 +214,14 @@
       CHECK_NE(*meta, 0);
       CHECK(a.PointerIsMine(x));
       *meta = 0;
-      a.Deallocate(x);
+      a.Deallocate(&cache, x);
     }
     allocated.clear();
+    a.SwallowCache(&cache);
   }
   a.TestOnlyUnmap();
 }
 
-typedef SizeClassAllocatorLocalCache<Allocator::kNumClasses, Allocator>
-  AllocatorCache;
 static THREADLOCAL AllocatorCache static_allocator_cache;
 
 TEST(SanitizerCommon, SizeClassAllocatorLocalCache) {
diff --git a/lib/sanitizer_common/tests/sanitizer_list_test.cc b/lib/sanitizer_common/tests/sanitizer_list_test.cc
index c2ca7e8..d328fbf 100644
--- a/lib/sanitizer_common/tests/sanitizer_list_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_list_test.cc
@@ -24,9 +24,10 @@
 // Check that IntrusiveList can be made thread-local.
 static THREADLOCAL List static_list;
 
-static void SetList(List *l, ListItem *x, ListItem *y = 0, ListItem *z = 0) {
+static void SetList(List *l, ListItem *x = 0,
+                    ListItem *y = 0, ListItem *z = 0) {
   l->clear();
-  l->push_back(x);
+  if (x) l->push_back(x);
   if (y) l->push_back(y);
   if (z) l->push_back(z);
 }
@@ -145,6 +146,12 @@
   l1.append_back(&l2);
   CheckList(&l1, x, y, z, a, b, c);
   CHECK(l2.empty());
+
+  SetList(&l1, x, y);
+  SetList(&l2);
+  l1.append_front(&l2);
+  CheckList(&l1, x, y);
+  CHECK(l2.empty());
 }
 
 }  // namespace __sanitizer