1 /* 2 * Copyright (c) 2025 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 COMMON_COMPONENTS_HEAP_COLLECTOR_COPY_DATA_MANAGER_H 17 #define COMMON_COMPONENTS_HEAP_COLLECTOR_COPY_DATA_MANAGER_H 18 19 #include "base/common.h" 20 #include "common_components/base/immortal_wrapper.h" 21 #include "common_components/heap/heap.h" 22 #if defined(__linux__) || defined(PANDA_TARGET_OHOS) || defined(__APPLE__) 23 #include <sys/mman.h> 24 #endif 25 26 #include "common_components/base/mem_utils.h" 27 #include "common_components/base/sys_call.h" 28 #include "common_components/heap/collector/region_bitmap.h" 29 #include "common_components/log/log.h" 30 31 #ifdef _WIN64 32 #include "common_components/base/atomic_spin_lock.h" 33 #include <errhandlingapi.h> 34 #include <handleapi.h> 35 #include <memoryapi.h> 36 #else 37 #include <sys/mman.h> 38 #endif 39 40 namespace common { 41 42 class HeapBitmapManager { 43 class Memory { 44 public: 45 struct Zone { 46 enum ZoneType : size_t { 47 BIT_MAP, 48 ZONE_TYPE_CNT, 49 }; 50 uintptr_t zoneStartAddress = 0; 51 std::atomic<uintptr_t> zonePosition; 52 }; 53 Memory() = default; InitializeMemory(uintptr_t start,size_t sz,size_t unitCount)54 void InitializeMemory(uintptr_t start, size_t sz, size_t unitCount) 55 { 56 startAddress_ = start; 57 size_ = sz; 58 InitZones(unitCount); 59 } InitZones(size_t unitCount)60 void InitZones(size_t unitCount) 61 { 62 uintptr_t start = startAddress_; 63 allocZone_[Zone::ZoneType::BIT_MAP].zoneStartAddress = start; 64 allocZone_[Zone::ZoneType::BIT_MAP].zonePosition = start; 65 #if defined(_WIN64) 66 lastCommitEndAddr[Zone::ZoneType::BIT_MAP].store(start); 67 #endif 68 } Allocate(Zone::ZoneType type,size_t sz)69 uintptr_t Allocate(Zone::ZoneType type, size_t sz) 70 { 71 #if defined(_WIN64) 72 allocSpinLock.Lock(); 73 uintptr_t startAddr = allocZone_[type].zonePosition.fetch_add(sz); 74 uintptr_t endAddr = startAddr + sz; 75 uintptr_t lastAddr = lastCommitEndAddr[type].load(std::memory_order_relaxed); 76 if (endAddr <= lastAddr) { 77 allocSpinLock.Unlock(); 78 return startAddr; 79 } 80 size_t pageSize = RoundUp(sz, COMMON_PAGE_SIZE); 81 LOGE_IF(UNLIKELY_CC(!VirtualAlloc(reinterpret_cast<void*>(lastAddr), pageSize, MEM_COMMIT, 82 PAGE_READWRITE))) << "VirtualAlloc commit failed in Allocate, errno: " << GetLastError(); 83 lastCommitEndAddr[type].store(lastAddr + pageSize); 84 allocSpinLock.Unlock(); 85 return startAddr; 86 #else 87 auto address = allocZone_[type].zonePosition.fetch_add(sz); 88 MemorySet(address, sz, 0, sz); 89 return address; 90 #endif 91 } ReleaseMemory()92 void ReleaseMemory() 93 { 94 #if defined(_WIN64) 95 LOGE_IF(UNLIKELY_CC(!VirtualFree(reinterpret_cast<void*>(startAddress_), size_, MEM_DECOMMIT))) << 96 "VirtualFree failed in ReturnPage, errno: " << GetLastError(); 97 #elif defined(__APPLE__) 98 (void)madvise(reinterpret_cast<void*>(startAddress_), size_, MADV_DONTNEED); 99 #else 100 DLOG(REGION, "clear copy-data @[%#zx+%zu, %#zx)", startAddress_, size_, startAddress_ + size_); 101 if (madvise(reinterpret_cast<void*>(startAddress_), size_, MADV_DONTNEED) == 0) { 102 DLOG(REGION, "release copy-data @[%#zx+%zu, %#zx)", startAddress_, size_, startAddress_ + size_); 103 } 104 #endif 105 for (size_t i = 0; i < Zone::ZoneType::ZONE_TYPE_CNT; ++i) { 106 allocZone_[i].zonePosition = allocZone_[i].zoneStartAddress; 107 #if defined(_WIN64) 108 lastCommitEndAddr[i].store(allocZone_[i].zoneStartAddress); 109 #endif 110 } 111 } 112 113 private: 114 Zone allocZone_[Zone::ZONE_TYPE_CNT]; 115 uintptr_t startAddress_ = 0; 116 size_t size_ = 0; 117 #if defined(_WIN64) 118 std::atomic<uintptr_t> lastCommitEndAddr[Zone::ZONE_TYPE_CNT]; 119 AtomicSpinLock allocSpinLock; 120 #endif 121 }; 122 123 public: 124 HeapBitmapManager() = default; ~HeapBitmapManager()125 ~HeapBitmapManager() 126 { 127 CHECK_CC(!initialized); 128 } 129 130 static HeapBitmapManager& GetHeapBitmapManager(); 131 132 void InitializeHeapBitmap(); 133 void DestroyHeapBitmap(); 134 ClearHeapBitmap()135 void ClearHeapBitmap() { heapBitmap_[0].ReleaseMemory(); } 136 AllocateRegionBitmap(size_t regionSize)137 RegionBitmap* AllocateRegionBitmap(size_t regionSize) 138 { 139 uintptr_t addr = 140 heapBitmap_[0].Allocate(Memory::Zone::ZoneType::BIT_MAP, RegionBitmap::GetRegionBitmapSize(regionSize)); 141 RegionBitmap* bitmap = reinterpret_cast<RegionBitmap*>(addr); 142 CHECK_CC(bitmap != nullptr); 143 new (bitmap) RegionBitmap(regionSize); 144 return bitmap; 145 } 146 147 private: GetHeapBitmapSize(size_t heapSize)148 size_t GetHeapBitmapSize(size_t heapSize) 149 { 150 const size_t REGION_UNIT_SIZE = COMMON_PAGE_SIZE; // must be equal to RegionDesc::UNIT_SIZE 151 heapSize = RoundUp<size_t>(heapSize, REGION_UNIT_SIZE); 152 size_t unitCnt = heapSize / REGION_UNIT_SIZE; 153 regionUnitCount_ = unitCnt; 154 // 64: 1 bit in bitmap marks 8bytes in region, i.e., 1 byte in bitmap marks 64 bytes in region. 155 constexpr uint8_t bitMarksSize = 64; 156 // 3 bitmaps for each region: markBitmap,resurrectBitmap, enqueueBitmap. 157 constexpr uint8_t nBitmapTypes = 3; 158 return unitCnt * (sizeof(RegionBitmap) + (REGION_UNIT_SIZE / bitMarksSize)) * nBitmapTypes; 159 } 160 161 Memory heapBitmap_[1]; 162 size_t regionUnitCount_ = 0; 163 uintptr_t heapBitmapStart_ = 0; 164 size_t allHeapBitmapSize_ = 0; 165 bool initialized = false; 166 }; 167 } // namespace common 168 #endif // COMMON_COMPONENTS_HEAP_COLLECTOR_COPY_DATA_MANAGER_H 169