1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef LIBPANDABASE_MEM_POOL_MAP_H 17 #define LIBPANDABASE_MEM_POOL_MAP_H 18 19 #include <array> 20 #include <cstddef> 21 #include <cstdint> 22 23 #include "macros.h" 24 #include "mem.h" 25 #include "space.h" 26 27 WEAK_FOR_LTO_START 28 29 namespace panda { 30 31 enum class AllocatorType { 32 UNDEFINED, 33 RUNSLOTS_ALLOCATOR, 34 FREELIST_ALLOCATOR, 35 HUMONGOUS_ALLOCATOR, 36 ARENA_ALLOCATOR, 37 TLAB_ALLOCATOR, 38 BUMP_ALLOCATOR, 39 REGION_ALLOCATOR, 40 FRAME_ALLOCATOR, 41 BUMP_ALLOCATOR_WITH_TLABS, 42 }; 43 44 class AllocatorInfo { 45 public: AllocatorInfo(AllocatorType type,const void * addr)46 explicit constexpr AllocatorInfo(AllocatorType type, const void *addr) : type_(type), header_addr_(addr) 47 { 48 // We can't create AllocatorInfo without correct pointer to the allocator header 49 ASSERT(header_addr_ != nullptr); 50 } 51 GetType()52 AllocatorType GetType() const 53 { 54 return type_; 55 } 56 GetAllocatorHeaderAddr()57 const void *GetAllocatorHeaderAddr() const 58 { 59 return header_addr_; 60 } 61 62 virtual ~AllocatorInfo() = default; 63 64 DEFAULT_COPY_SEMANTIC(AllocatorInfo); 65 DEFAULT_MOVE_SEMANTIC(AllocatorInfo); 66 67 private: 68 AllocatorType type_; 69 const void *header_addr_; 70 }; 71 72 // PoolMap is used to manage all pools which has been given to the allocators. 73 // It can be used to find which allocator has been used to allocate an object. 74 class PoolMap { 75 public: 76 void AddPoolToMap(const void *pool_addr, size_t pool_size, SpaceType space_type, AllocatorType allocator_type, 77 const void *allocator_addr); 78 void RemovePoolFromMap(const void *pool_addr, size_t pool_size); 79 // Get Allocator info for the object allocated at this address. 80 AllocatorInfo GetAllocatorInfo(const void *addr) const; 81 82 void *GetFirstByteOfPoolForAddr(const void *addr) const; 83 84 SpaceType GetSpaceType(const void *addr) const; 85 86 bool IsEmpty() const; 87 88 private: 89 static constexpr uint64_t POOL_MAP_COVERAGE = PANDA_MAX_HEAP_SIZE; 90 static constexpr size_t POOL_MAP_GRANULARITY = PANDA_POOL_ALIGNMENT_IN_BYTES; 91 static constexpr size_t POOL_MAP_SIZE = POOL_MAP_COVERAGE / POOL_MAP_GRANULARITY; 92 93 static constexpr bool FIRST_BYTE_IN_SEGMENT_VALUE = true; 94 95 class PoolInfo { 96 public: Initialize(bool first_byte_in_segment,SpaceType space_type,AllocatorType allocator_type,const void * allocator_addr)97 void Initialize(bool first_byte_in_segment, SpaceType space_type, AllocatorType allocator_type, 98 const void *allocator_addr) 99 { 100 ASSERT(first_byte_in_segment_ == FIRST_BYTE_IN_SEGMENT_VALUE); 101 ASSERT(allocator_type_ == AllocatorType::UNDEFINED); 102 // Added a TSAN ignore here because TSAN thinks 103 // that we can have a data race here - concurrent 104 // initialization and reading. 105 // However, we can't get an access for this fields 106 // without initialization in the correct flow. 107 TSAN_ANNOTATE_IGNORE_WRITES_BEGIN(); 108 first_byte_in_segment_ = first_byte_in_segment; 109 allocator_addr_ = allocator_addr; 110 space_type_ = space_type; 111 allocator_type_ = allocator_type; 112 TSAN_ANNOTATE_IGNORE_WRITES_END(); 113 } 114 IsEmpty()115 inline bool IsEmpty() const 116 { 117 return space_type_ == SpaceType::SPACE_TYPE_UNDEFINED; 118 } 119 Destroy()120 void Destroy() 121 { 122 first_byte_in_segment_ = FIRST_BYTE_IN_SEGMENT_VALUE; 123 allocator_addr_ = nullptr; 124 allocator_type_ = AllocatorType::UNDEFINED; 125 space_type_ = SpaceType::SPACE_TYPE_UNDEFINED; 126 } 127 IsFirstByteInSegment()128 bool IsFirstByteInSegment() const 129 { 130 return first_byte_in_segment_ == FIRST_BYTE_IN_SEGMENT_VALUE; 131 } 132 GetAllocatorType()133 AllocatorType GetAllocatorType() const 134 { 135 return allocator_type_; 136 } 137 GetAllocatorAddr()138 const void *GetAllocatorAddr() const 139 { 140 return allocator_addr_; 141 } 142 GetSpaceType()143 SpaceType GetSpaceType() const 144 { 145 return space_type_; 146 } 147 148 private: 149 bool first_byte_in_segment_ {FIRST_BYTE_IN_SEGMENT_VALUE}; 150 AllocatorType allocator_type_ {AllocatorType::UNDEFINED}; 151 SpaceType space_type_ {SpaceType::SPACE_TYPE_UNDEFINED}; 152 const void *allocator_addr_ = nullptr; 153 }; 154 AddrToMapNum(const void * addr)155 static size_t AddrToMapNum(const void *addr) 156 { 157 size_t map_num = ToUintPtr(addr) / POOL_MAP_GRANULARITY; 158 ASSERT(map_num < POOL_MAP_SIZE); 159 return map_num; 160 } 161 MapNumToAddr(size_t map_num)162 static void *MapNumToAddr(size_t map_num) 163 { 164 // Checking overflow 165 ASSERT(static_cast<uint64_t>(map_num) * POOL_MAP_GRANULARITY == map_num * POOL_MAP_GRANULARITY); 166 return ToVoidPtr(map_num * POOL_MAP_GRANULARITY); 167 } 168 169 void *GetFirstByteInSegment(const void *addr) const; 170 171 std::array<PoolInfo, POOL_MAP_SIZE> pool_map_; 172 173 friend class PoolMapTest; 174 }; 175 176 } // namespace panda 177 178 WEAK_FOR_LTO_END 179 180 #endif // LIBPANDABASE_MEM_POOL_MAP_H 181