• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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