299 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			299 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * Copyright (C) 2014 The Android Open Source Project
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *      http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| #ifndef ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_INL_H_
 | |
| #define ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_INL_H_
 | |
| 
 | |
| #include "memory_tool_malloc_space.h"
 | |
| 
 | |
| #include "base/memory_tool.h"
 | |
| #include "memory_tool_settings.h"
 | |
| #include "mirror/object-inl.h"
 | |
| 
 | |
| namespace art {
 | |
| namespace gc {
 | |
| namespace space {
 | |
| 
 | |
| namespace memory_tool_details {
 | |
| 
 | |
| template <size_t kMemoryToolRedZoneBytes, bool kUseObjSizeForUsable>
 | |
| inline mirror::Object* AdjustForMemoryTool(void* obj_with_rdz,
 | |
|                                            size_t num_bytes,
 | |
|                                            size_t bytes_allocated,
 | |
|                                            size_t usable_size,
 | |
|                                            size_t bytes_tl_bulk_allocated,
 | |
|                                            size_t* bytes_allocated_out,
 | |
|                                            size_t* usable_size_out,
 | |
|                                            size_t* bytes_tl_bulk_allocated_out) {
 | |
|   if (bytes_allocated_out != nullptr) {
 | |
|     *bytes_allocated_out = bytes_allocated;
 | |
|   }
 | |
|   if (bytes_tl_bulk_allocated_out != nullptr) {
 | |
|     *bytes_tl_bulk_allocated_out = bytes_tl_bulk_allocated;
 | |
|   }
 | |
| 
 | |
|   // This cuts over-provision and is a trade-off between testing the over-provisioning code paths
 | |
|   // vs checking overflows in the regular paths.
 | |
|   if (usable_size_out != nullptr) {
 | |
|     if (kUseObjSizeForUsable) {
 | |
|       *usable_size_out = num_bytes;
 | |
|     } else {
 | |
|       *usable_size_out = usable_size - 2 * kMemoryToolRedZoneBytes;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Left redzone.
 | |
|   MEMORY_TOOL_MAKE_NOACCESS(obj_with_rdz, kMemoryToolRedZoneBytes);
 | |
| 
 | |
|   // Make requested memory readable.
 | |
|   // (If the allocator assumes memory is zeroed out, we might get UNDEFINED warnings, so make
 | |
|   //  everything DEFINED initially.)
 | |
|   mirror::Object* result = reinterpret_cast<mirror::Object*>(
 | |
|       reinterpret_cast<uint8_t*>(obj_with_rdz) + kMemoryToolRedZoneBytes);
 | |
|   MEMORY_TOOL_MAKE_DEFINED(result, num_bytes);
 | |
| 
 | |
|   // Right redzone. Assumes that if bytes_allocated > usable_size, then the difference is
 | |
|   // management data at the upper end, and for simplicity we will not protect that.
 | |
|   // At the moment, this fits RosAlloc (no management data in a slot, usable_size == alloc_size)
 | |
|   // and DlMalloc (allocation_size = (usable_size == num_bytes) + 4, 4 is management)
 | |
|   MEMORY_TOOL_MAKE_NOACCESS(reinterpret_cast<uint8_t*>(result) + num_bytes,
 | |
|                     usable_size - (num_bytes + kMemoryToolRedZoneBytes));
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| inline size_t GetObjSizeNoThreadSafety(mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS {
 | |
|   return obj->SizeOf<kVerifyNone>();
 | |
| }
 | |
| 
 | |
| }  // namespace memory_tool_details
 | |
| 
 | |
| template <typename S,
 | |
|           size_t kMemoryToolRedZoneBytes,
 | |
|           bool kAdjustForRedzoneInAllocSize,
 | |
|           bool kUseObjSizeForUsable>
 | |
| mirror::Object*
 | |
| MemoryToolMallocSpace<S,
 | |
|                       kMemoryToolRedZoneBytes,
 | |
|                       kAdjustForRedzoneInAllocSize,
 | |
|                       kUseObjSizeForUsable>::AllocWithGrowth(
 | |
|     Thread* self,
 | |
|     size_t num_bytes,
 | |
|     size_t* bytes_allocated_out,
 | |
|     size_t* usable_size_out,
 | |
|     size_t* bytes_tl_bulk_allocated_out) {
 | |
|   size_t bytes_allocated;
 | |
|   size_t usable_size;
 | |
|   size_t bytes_tl_bulk_allocated;
 | |
|   void* obj_with_rdz = S::AllocWithGrowth(self,
 | |
|                                           num_bytes + 2 * kMemoryToolRedZoneBytes,
 | |
|                                           &bytes_allocated,
 | |
|                                           &usable_size,
 | |
|                                           &bytes_tl_bulk_allocated);
 | |
|   if (obj_with_rdz == nullptr) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   return memory_tool_details::AdjustForMemoryTool<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
 | |
|       obj_with_rdz,
 | |
|       num_bytes,
 | |
|       bytes_allocated,
 | |
|       usable_size,
 | |
|       bytes_tl_bulk_allocated,
 | |
|       bytes_allocated_out,
 | |
|       usable_size_out,
 | |
|       bytes_tl_bulk_allocated_out);
 | |
| }
 | |
| 
 | |
| template <typename S,
 | |
|           size_t kMemoryToolRedZoneBytes,
 | |
|           bool kAdjustForRedzoneInAllocSize,
 | |
|           bool kUseObjSizeForUsable>
 | |
| mirror::Object* MemoryToolMallocSpace<S,
 | |
|                                       kMemoryToolRedZoneBytes,
 | |
|                                       kAdjustForRedzoneInAllocSize,
 | |
|                                       kUseObjSizeForUsable>::Alloc(
 | |
|     Thread* self,
 | |
|     size_t num_bytes,
 | |
|     size_t* bytes_allocated_out,
 | |
|     size_t* usable_size_out,
 | |
|     size_t* bytes_tl_bulk_allocated_out) {
 | |
|   size_t bytes_allocated;
 | |
|   size_t usable_size;
 | |
|   size_t bytes_tl_bulk_allocated;
 | |
|   void* obj_with_rdz = S::Alloc(self,
 | |
|                                 num_bytes + 2 * kMemoryToolRedZoneBytes,
 | |
|                                 &bytes_allocated,
 | |
|                                 &usable_size,
 | |
|                                 &bytes_tl_bulk_allocated);
 | |
|   if (obj_with_rdz == nullptr) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   return memory_tool_details::AdjustForMemoryTool<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
 | |
|       obj_with_rdz,
 | |
|       num_bytes,
 | |
|       bytes_allocated,
 | |
|       usable_size,
 | |
|       bytes_tl_bulk_allocated,
 | |
|       bytes_allocated_out,
 | |
|       usable_size_out,
 | |
|       bytes_tl_bulk_allocated_out);
 | |
| }
 | |
| 
 | |
| template <typename S,
 | |
|           size_t kMemoryToolRedZoneBytes,
 | |
|           bool kAdjustForRedzoneInAllocSize,
 | |
|           bool kUseObjSizeForUsable>
 | |
| mirror::Object* MemoryToolMallocSpace<S,
 | |
|                                       kMemoryToolRedZoneBytes,
 | |
|                                       kAdjustForRedzoneInAllocSize,
 | |
|                                       kUseObjSizeForUsable>::AllocThreadUnsafe(
 | |
|     Thread* self,
 | |
|     size_t num_bytes,
 | |
|     size_t* bytes_allocated_out,
 | |
|     size_t* usable_size_out,
 | |
|     size_t* bytes_tl_bulk_allocated_out) {
 | |
|   size_t bytes_allocated;
 | |
|   size_t usable_size;
 | |
|   size_t bytes_tl_bulk_allocated;
 | |
|   void* obj_with_rdz = S::AllocThreadUnsafe(self,
 | |
|                                             num_bytes + 2 * kMemoryToolRedZoneBytes,
 | |
|                                             &bytes_allocated,
 | |
|                                             &usable_size,
 | |
|                                             &bytes_tl_bulk_allocated);
 | |
|   if (obj_with_rdz == nullptr) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   return memory_tool_details::AdjustForMemoryTool<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
 | |
|       obj_with_rdz,
 | |
|       num_bytes,
 | |
|       bytes_allocated,
 | |
|       usable_size,
 | |
|       bytes_tl_bulk_allocated,
 | |
|       bytes_allocated_out,
 | |
|       usable_size_out,
 | |
|       bytes_tl_bulk_allocated_out);
 | |
| }
 | |
| 
 | |
| template <typename S,
 | |
|           size_t kMemoryToolRedZoneBytes,
 | |
|           bool kAdjustForRedzoneInAllocSize,
 | |
|           bool kUseObjSizeForUsable>
 | |
| size_t MemoryToolMallocSpace<S,
 | |
|                              kMemoryToolRedZoneBytes,
 | |
|                              kAdjustForRedzoneInAllocSize,
 | |
|                              kUseObjSizeForUsable>::AllocationSize(
 | |
|     mirror::Object* obj, size_t* usable_size) {
 | |
|   size_t result = S::AllocationSize(
 | |
|       reinterpret_cast<mirror::Object*>(
 | |
|           reinterpret_cast<uint8_t*>(obj)
 | |
|               - (kAdjustForRedzoneInAllocSize ? kMemoryToolRedZoneBytes : 0)),
 | |
|       usable_size);
 | |
|   if (usable_size != nullptr) {
 | |
|     if (kUseObjSizeForUsable) {
 | |
|       *usable_size = memory_tool_details::GetObjSizeNoThreadSafety(obj);
 | |
|     } else {
 | |
|       *usable_size = *usable_size - 2 * kMemoryToolRedZoneBytes;
 | |
|     }
 | |
|   }
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| template <typename S,
 | |
|           size_t kMemoryToolRedZoneBytes,
 | |
|           bool kAdjustForRedzoneInAllocSize,
 | |
|           bool kUseObjSizeForUsable>
 | |
| size_t MemoryToolMallocSpace<S,
 | |
|                              kMemoryToolRedZoneBytes,
 | |
|                              kAdjustForRedzoneInAllocSize,
 | |
|                              kUseObjSizeForUsable>::Free(Thread* self, mirror::Object* ptr) {
 | |
|   void* obj_after_rdz = reinterpret_cast<void*>(ptr);
 | |
|   uint8_t* obj_with_rdz = reinterpret_cast<uint8_t*>(obj_after_rdz) - kMemoryToolRedZoneBytes;
 | |
| 
 | |
|   // Make redzones undefined.
 | |
|   size_t usable_size;
 | |
|   size_t allocation_size = AllocationSize(ptr, &usable_size);
 | |
| 
 | |
|   // Unprotect the allocation.
 | |
|   // Use the obj-size-for-usable flag to determine whether usable_size is the more important one,
 | |
|   // e.g., whether there's data in the allocation_size (and usable_size can't be trusted).
 | |
|   if (kUseObjSizeForUsable) {
 | |
|     MEMORY_TOOL_MAKE_UNDEFINED(obj_with_rdz, allocation_size);
 | |
|   } else {
 | |
|     MEMORY_TOOL_MAKE_UNDEFINED(obj_with_rdz, usable_size + 2 * kMemoryToolRedZoneBytes);
 | |
|   }
 | |
| 
 | |
|   return S::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
 | |
| }
 | |
| 
 | |
| template <typename S,
 | |
|           size_t kMemoryToolRedZoneBytes,
 | |
|           bool kAdjustForRedzoneInAllocSize,
 | |
|           bool kUseObjSizeForUsable>
 | |
| size_t MemoryToolMallocSpace<S,
 | |
|                              kMemoryToolRedZoneBytes,
 | |
|                              kAdjustForRedzoneInAllocSize,
 | |
|                              kUseObjSizeForUsable>::FreeList(
 | |
|                                  Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
 | |
|   size_t freed = 0;
 | |
|   // Sort the pointers to free non class objects first. See b/131542326 for why this is necessary to
 | |
|   // avoid crashes.
 | |
|   std::sort(ptrs, ptrs + num_ptrs, [](mirror::Object* a, mirror::Object* b)
 | |
|       REQUIRES_SHARED(Locks::mutator_lock_) {
 | |
|     return a->IsClass() < b->IsClass();
 | |
|   });
 | |
|   for (size_t i = 0; i < num_ptrs; i++) {
 | |
|     freed += Free(self, ptrs[i]);
 | |
|     ptrs[i] = nullptr;
 | |
|   }
 | |
|   return freed;
 | |
| }
 | |
| 
 | |
| template <typename S,
 | |
|           size_t kMemoryToolRedZoneBytes,
 | |
|           bool kAdjustForRedzoneInAllocSize,
 | |
|           bool kUseObjSizeForUsable>
 | |
| template <typename... Params>
 | |
| MemoryToolMallocSpace<S,
 | |
|                       kMemoryToolRedZoneBytes,
 | |
|                       kAdjustForRedzoneInAllocSize,
 | |
|                       kUseObjSizeForUsable>::MemoryToolMallocSpace(
 | |
|                           MemMap&& mem_map, size_t initial_size, Params... params)
 | |
|                           : S(std::move(mem_map), initial_size, params...) {
 | |
|   // Don't want to change the memory tool states of the mem map here as the allocator is already
 | |
|   // initialized at this point and that may interfere with what the allocator does internally. Note
 | |
|   // that the tail beyond the initial size is mprotected.
 | |
| }
 | |
| 
 | |
| template <typename S,
 | |
|           size_t kMemoryToolRedZoneBytes,
 | |
|           bool kAdjustForRedzoneInAllocSize,
 | |
|           bool kUseObjSizeForUsable>
 | |
| size_t MemoryToolMallocSpace<S,
 | |
|                              kMemoryToolRedZoneBytes,
 | |
|                              kAdjustForRedzoneInAllocSize,
 | |
|                              kUseObjSizeForUsable>::MaxBytesBulkAllocatedFor(size_t num_bytes) {
 | |
|   return S::MaxBytesBulkAllocatedFor(num_bytes + 2 * kMemoryToolRedZoneBytes);
 | |
| }
 | |
| 
 | |
| }  // namespace space
 | |
| }  // namespace gc
 | |
| }  // namespace art
 | |
| 
 | |
| #endif  // ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_INL_H_
 |