summaryrefslogtreecommitdiffstats
path: root/compiler-rt/lib
diff options
context:
space:
mode:
Diffstat (limited to 'compiler-rt/lib')
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_allocator64.h73
-rw-r--r--compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc49
2 files changed, 112 insertions, 10 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator64.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator64.h
index 4b25158a41d..0bac2374202 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator64.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator64.h
@@ -97,12 +97,17 @@ class SizeClassAllocator64 {
CHECK_EQ(AllocBeg(), reinterpret_cast<uptr>(MmapFixedNoReserve(
AllocBeg(), AllocSize())));
}
- NOINLINE
- void *Allocate(uptr size) {
- CHECK_LE(size, SizeClassMap::kMaxSize);
+
+ bool CanAllocate(uptr size, uptr alignment) {
+ return size <= SizeClassMap::kMaxSize &&
+ alignment <= SizeClassMap::kMaxSize;
+ }
+
+ void *Allocate(uptr size, uptr alignment) {
+ CHECK(CanAllocate(size, alignment));
return AllocateBySizeClass(SizeClassMap::ClassID(size));
}
- NOINLINE
+
void Deallocate(void *p) {
CHECK(PointerIsMine(p));
DeallocateBySizeClass(p, GetSizeClass(p));
@@ -236,7 +241,8 @@ class LargeMmapAllocator {
void Init() {
internal_memset(this, 0, sizeof(*this));
}
- void *Allocate(uptr size) {
+ void *Allocate(uptr size, uptr alignment) {
+ CHECK_LE(alignment, kPageSize); // Not implemented. Do we need it?
uptr map_size = RoundUpMapSize(size);
void *map = MmapOrDie(map_size, "LargeMmapAllocator");
void *res = reinterpret_cast<void*>(reinterpret_cast<uptr>(map)
@@ -318,6 +324,63 @@ class LargeMmapAllocator {
uptr lock_; // FIXME
};
+// This class implements a complete memory allocator by using two
+// internal allocators:
+// PrimaryAllocator is efficient, but may not allocate some sizes (alignments).
+// When allocating 2^x bytes it should return 2^x aligned chunk.
+// SecondaryAllocator can allocate anything, but is not efficient.
+template <class PrimaryAllocator, class SecondaryAllocator>
+class CombinedAllocator {
+ public:
+ void Init() {
+ primary_.Init();
+ secondary_.Init();
+ }
+
+ void *Allocate(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);
+ else
+ res = secondary_.Allocate(size, alignment);
+ if (alignment > 8)
+ CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
+ return res;
+ }
+
+ void Deallocate(void *p) {
+ if (primary_.PointerIsMine(p))
+ primary_.Deallocate(p);
+ else
+ secondary_.Deallocate(p);
+ }
+
+ bool PointerIsMine(void *p) {
+ if (primary_.PointerIsMine(p))
+ return true;
+ return secondary_.PointerIsMine(p);
+ }
+
+ void *GetMetaData(void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetMetaData(p);
+ return secondary_.GetMetaData(p);
+ }
+
+ uptr TotalMemoryUsed() {
+ return primary_.TotalMemoryUsed() + secondary_.TotalMemoryUsed();
+ }
+
+ void TestOnlyUnmap() { primary_.TestOnlyUnmap(); }
+
+ private:
+ PrimaryAllocator primary_;
+ SecondaryAllocator secondary_;
+};
+
} // namespace __sanitizer
#endif // SANITIZER_ALLOCATOR_H
diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc b/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
index c0b7b7bd9f5..ba636439f90 100644
--- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
+++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
@@ -71,7 +71,7 @@ TEST(SanitizerCommon, SizeClassAllocator64) {
// printf("s = %ld\n", size);
uptr n_iter = std::max((uptr)2, 1000000 / size);
for (uptr i = 0; i < n_iter; i++) {
- void *x = a.Allocate(size);
+ void *x = a.Allocate(size, 1);
allocated.push_back(x);
CHECK(a.PointerIsMine(x));
uptr class_id = a.GetSizeClass(x);
@@ -112,7 +112,7 @@ TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) {
void *allocated[kNumAllocs];
for (uptr i = 0; i < kNumAllocs; i++) {
uptr size = (i % 4096) + 1;
- void *x = a.Allocate(size);
+ void *x = a.Allocate(size, 1);
allocated[i] = x;
}
// Get Metadata kNumAllocs^2 times.
@@ -134,7 +134,7 @@ void FailInAssertionOnOOM() {
a.Init();
const uptr size = 1 << 20;
for (int i = 0; i < 1000000; i++) {
- a.Allocate(size);
+ a.Allocate(size, 1);
}
a.TestOnlyUnmap();
@@ -154,7 +154,7 @@ TEST(SanitizerCommon, LargeMmapAllocator) {
static const uptr size = 1000;
// Allocate some.
for (int i = 0; i < kNumAllocs; i++) {
- allocated[i] = a.Allocate(size);
+ allocated[i] = a.Allocate(size, 1);
}
// Deallocate all.
CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
@@ -168,7 +168,7 @@ TEST(SanitizerCommon, LargeMmapAllocator) {
// Allocate some more, also add metadata.
for (int i = 0; i < kNumAllocs; i++) {
- void *x = a.Allocate(size);
+ void *x = a.Allocate(size, 1);
uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
*meta = i;
allocated[i] = x;
@@ -185,3 +185,42 @@ TEST(SanitizerCommon, LargeMmapAllocator) {
}
CHECK_EQ(a.TotalMemoryUsed(), 0);
}
+
+TEST(SanitizerCommon, CombinedAllocator) {
+ typedef DefaultSizeClassMap SCMap;
+ typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
+ 16, SCMap> PrimaryAllocator;
+ typedef LargeMmapAllocator SecondaryAllocator;
+ typedef CombinedAllocator<PrimaryAllocator, SecondaryAllocator> Allocator;
+
+ Allocator a;
+ a.Init();
+ const uptr kNumAllocs = 100000;
+ const uptr kNumIter = 10;
+ for (uptr iter = 0; iter < kNumIter; iter++) {
+ std::vector<void*> allocated;
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ uptr size = (i % (1 << 14)) + 1;
+ if ((i % 1024) == 0)
+ size = 1 << (10 + (i % 14));
+ void *x = a.Allocate(size, 1);
+ uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
+ CHECK_EQ(*meta, 0);
+ *meta = size;
+ allocated.push_back(x);
+ }
+
+ random_shuffle(allocated.begin(), allocated.end());
+
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ void *x = allocated[i];
+ uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
+ CHECK_NE(*meta, 0);
+ CHECK(a.PointerIsMine(x));
+ *meta = 0;
+ a.Deallocate(x);
+ }
+ allocated.clear();
+ }
+ a.TestOnlyUnmap();
+}
OpenPOWER on IntegriCloud