Add Valgrind rosalloc support.
Bug: 9986565
Change-Id: Ibd2ba5e8b4fb7f2ed6c133a4b556a6dbb15a2f5e
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index b067bbc..10e9ed8 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -35,79 +35,6 @@
static const bool kPrefetchDuringDlMallocFreeList = true;
-// Number of bytes to use as a red zone (rdz). A red zone of this size will be placed before and
-// after each allocation. 8 bytes provides long/double alignment.
-const size_t kValgrindRedZoneBytes = 8;
-
-// A specialization of DlMallocSpace that provides information to valgrind wrt allocations.
-class ValgrindDlMallocSpace : public DlMallocSpace {
- public:
- virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes, size_t* bytes_allocated) {
- void* obj_with_rdz = DlMallocSpace::AllocWithGrowth(self, num_bytes + 2 * kValgrindRedZoneBytes,
- bytes_allocated);
- if (obj_with_rdz == NULL) {
- return NULL;
- }
- mirror::Object* result = reinterpret_cast<mirror::Object*>(
- reinterpret_cast<byte*>(obj_with_rdz) + kValgrindRedZoneBytes);
- // Make redzones as no access.
- VALGRIND_MAKE_MEM_NOACCESS(obj_with_rdz, kValgrindRedZoneBytes);
- VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<byte*>(result) + num_bytes, kValgrindRedZoneBytes);
- return result;
- }
-
- virtual mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated) {
- void* obj_with_rdz = DlMallocSpace::Alloc(self, num_bytes + 2 * kValgrindRedZoneBytes,
- bytes_allocated);
- if (obj_with_rdz == NULL) {
- return NULL;
- }
- mirror::Object* result = reinterpret_cast<mirror::Object*>(
- reinterpret_cast<byte*>(obj_with_rdz) + kValgrindRedZoneBytes);
- // Make redzones as no access.
- VALGRIND_MAKE_MEM_NOACCESS(obj_with_rdz, kValgrindRedZoneBytes);
- VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<byte*>(result) + num_bytes, kValgrindRedZoneBytes);
- return result;
- }
-
- virtual size_t AllocationSize(const mirror::Object* obj) {
- size_t result = DlMallocSpace::AllocationSize(reinterpret_cast<const mirror::Object*>(
- reinterpret_cast<const byte*>(obj) - kValgrindRedZoneBytes));
- return result - 2 * kValgrindRedZoneBytes;
- }
-
- virtual size_t Free(Thread* self, mirror::Object* ptr) {
- void* obj_after_rdz = reinterpret_cast<void*>(ptr);
- void* obj_with_rdz = reinterpret_cast<byte*>(obj_after_rdz) - kValgrindRedZoneBytes;
- // Make redzones undefined.
- size_t allocation_size = DlMallocSpace::AllocationSize(
- reinterpret_cast<mirror::Object*>(obj_with_rdz));
- VALGRIND_MAKE_MEM_UNDEFINED(obj_with_rdz, allocation_size);
- size_t freed = DlMallocSpace::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
- return freed - 2 * kValgrindRedZoneBytes;
- }
-
- virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
- size_t freed = 0;
- for (size_t i = 0; i < num_ptrs; i++) {
- freed += Free(self, ptrs[i]);
- }
- return freed;
- }
-
- ValgrindDlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin,
- byte* end, byte* limit, size_t growth_limit, size_t initial_size) :
- DlMallocSpace(name, mem_map, mspace, begin, end, limit, growth_limit) {
- VALGRIND_MAKE_MEM_UNDEFINED(mem_map->Begin() + initial_size, mem_map->Size() - initial_size);
- }
-
- virtual ~ValgrindDlMallocSpace() {
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ValgrindDlMallocSpace);
-};
-
DlMallocSpace::DlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin,
byte* end, byte* limit, size_t growth_limit)
: MallocSpace(name, mem_map, begin, end, limit, growth_limit),
@@ -155,8 +82,8 @@
DlMallocSpace* space;
byte* begin = mem_map->Begin();
if (RUNNING_ON_VALGRIND > 0) {
- space = new ValgrindDlMallocSpace(name, mem_map, mspace, begin, end, begin + capacity,
- growth_limit, initial_size);
+ space = new ValgrindMallocSpace<DlMallocSpace, void*>(
+ name, mem_map, mspace, begin, end, begin + capacity, growth_limit, initial_size);
} else {
space = new DlMallocSpace(name, mem_map, mspace, begin, end, begin + capacity, growth_limit);
}
diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h
index 189f01c..0f882d3 100644
--- a/runtime/gc/space/malloc_space.h
+++ b/runtime/gc/space/malloc_space.h
@@ -19,6 +19,9 @@
#include "space.h"
+#include <valgrind.h>
+#include <memcheck/memcheck.h>
+
namespace art {
namespace gc {
@@ -185,6 +188,80 @@
DISALLOW_COPY_AND_ASSIGN(MallocSpace);
};
+// Number of bytes to use as a red zone (rdz). A red zone of this size will be placed before and
+// after each allocation. 8 bytes provides long/double alignment.
+static constexpr size_t kValgrindRedZoneBytes = 8;
+
+// A specialization of DlMallocSpace/RosAllocSpace that provides information to valgrind wrt allocations.
+template <typename BaseMallocSpaceType, typename AllocatorType>
+class ValgrindMallocSpace : public BaseMallocSpaceType {
+ public:
+ virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes, size_t* bytes_allocated) {
+ void* obj_with_rdz = BaseMallocSpaceType::AllocWithGrowth(self, num_bytes + 2 * kValgrindRedZoneBytes,
+ bytes_allocated);
+ if (obj_with_rdz == NULL) {
+ return NULL;
+ }
+ mirror::Object* result = reinterpret_cast<mirror::Object*>(
+ reinterpret_cast<byte*>(obj_with_rdz) + kValgrindRedZoneBytes);
+ // Make redzones as no access.
+ VALGRIND_MAKE_MEM_NOACCESS(obj_with_rdz, kValgrindRedZoneBytes);
+ VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<byte*>(result) + num_bytes, kValgrindRedZoneBytes);
+ return result;
+ }
+
+ virtual mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated) {
+ void* obj_with_rdz = BaseMallocSpaceType::Alloc(self, num_bytes + 2 * kValgrindRedZoneBytes,
+ bytes_allocated);
+ if (obj_with_rdz == NULL) {
+ return NULL;
+ }
+ mirror::Object* result = reinterpret_cast<mirror::Object*>(
+ reinterpret_cast<byte*>(obj_with_rdz) + kValgrindRedZoneBytes);
+ // Make redzones as no access.
+ VALGRIND_MAKE_MEM_NOACCESS(obj_with_rdz, kValgrindRedZoneBytes);
+ VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<byte*>(result) + num_bytes, kValgrindRedZoneBytes);
+ return result;
+ }
+
+ virtual size_t AllocationSize(const mirror::Object* obj) {
+ size_t result = BaseMallocSpaceType::AllocationSize(reinterpret_cast<const mirror::Object*>(
+ reinterpret_cast<const byte*>(obj) - kValgrindRedZoneBytes));
+ return result - 2 * kValgrindRedZoneBytes;
+ }
+
+ virtual size_t Free(Thread* self, mirror::Object* ptr) {
+ void* obj_after_rdz = reinterpret_cast<void*>(ptr);
+ void* obj_with_rdz = reinterpret_cast<byte*>(obj_after_rdz) - kValgrindRedZoneBytes;
+ // Make redzones undefined.
+ size_t allocation_size = BaseMallocSpaceType::AllocationSize(
+ reinterpret_cast<mirror::Object*>(obj_with_rdz));
+ VALGRIND_MAKE_MEM_UNDEFINED(obj_with_rdz, allocation_size);
+ size_t freed = BaseMallocSpaceType::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
+ return freed - 2 * kValgrindRedZoneBytes;
+ }
+
+ virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
+ size_t freed = 0;
+ for (size_t i = 0; i < num_ptrs; i++) {
+ freed += Free(self, ptrs[i]);
+ }
+ return freed;
+ }
+
+ ValgrindMallocSpace(const std::string& name, MemMap* mem_map, AllocatorType allocator, byte* begin,
+ byte* end, byte* limit, size_t growth_limit, size_t initial_size) :
+ BaseMallocSpaceType(name, mem_map, allocator, begin, end, limit, growth_limit) {
+ VALGRIND_MAKE_MEM_UNDEFINED(mem_map->Begin() + initial_size, mem_map->Size() - initial_size);
+ }
+
+ virtual ~ValgrindMallocSpace() {
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ValgrindMallocSpace);
+};
+
} // namespace space
} // namespace gc
} // namespace art
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index a3d2dfa..1f8e324 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -1,3 +1,4 @@
+
/*
* Copyright (C) 2013 The Android Open Source Project
*
@@ -83,9 +84,8 @@
RosAllocSpace* space;
byte* begin = mem_map->Begin();
if (RUNNING_ON_VALGRIND > 0) {
- // TODO: support valgrind.
- LOG(FATAL) << "Unimplemented";
- space = NULL;
+ space = new ValgrindMallocSpace<RosAllocSpace, art::gc::allocator::RosAlloc*>(
+ name, mem_map, rosalloc, begin, end, begin + capacity, growth_limit, initial_size);
} else {
space = new RosAllocSpace(name, mem_map, rosalloc, begin, end, begin + capacity, growth_limit);
}