• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 
17 #ifndef MEMORY_MANAGER_H
18 #define MEMORY_MANAGER_H
19 #include <algorithm>
20 
21 #include "jsvm_util.h"
22 
23 template<size_t elementSize, size_t sizePerChunk = 8, size_t threshold = 10>
24 class MemoryChunkList {
25 private:
26     union ElementMemory {
ElementMemory()27         constexpr ElementMemory() : next(nullptr) {}
28 
~ElementMemory()29         ~ElementMemory() {}
30 
31         ElementMemory* next;
32         char ele[elementSize];
33     };
34 
35     struct MemoryChunk;
36 
37     struct ElementContainer {
38         uintptr_t header;
39         ElementMemory memory;
40 
GetMemoryChunkElementContainer41         static MemoryChunk* GetMemoryChunk(const ElementMemory* mem)
42         {
43             uintptr_t headerPtr = reinterpret_cast<uintptr_t>(mem) - sizeof(header);
44             return reinterpret_cast<MemoryChunk*>(*reinterpret_cast<uintptr_t*>(headerPtr));
45         }
46     };
47 
48     struct MemoryChunk {
49         MemoryChunk* prev;
50         MemoryChunk* next;
51         size_t freeCount;
52         ElementContainer elements[sizePerChunk];
53 
MemoryChunkMemoryChunk54         MemoryChunk() : prev(nullptr), next(nullptr), freeCount(sizePerChunk)
55         {
56             for (size_t i = 0; i < sizePerChunk - 1; ++i) {
57                 elements[i].header = reinterpret_cast<uintptr_t>(this);
58                 elements[i].memory.next = &(elements[i + 1].memory);
59             }
60             elements[sizePerChunk - 1].header = reinterpret_cast<uintptr_t>(this);
61             elements[sizePerChunk - 1].memory.next = nullptr;
62         }
63 
IncMemoryChunk64         void Inc()
65         {
66             ++freeCount;
67         }
68 
DecMemoryChunk69         void Dec()
70         {
71             --freeCount;
72         }
73 
CanBeFreeMemoryChunk74         bool CanBeFree()
75         {
76             return freeCount == sizePerChunk;
77         }
78     };
79 
80 public:
MemoryChunkList()81     MemoryChunkList() : head(nullptr), freeList(nullptr)
82     {
83         AllocateChunk();
84     }
85 
~MemoryChunkList()86     ~MemoryChunkList()
87     {
88         auto* ptr = head;
89         while (ptr) {
90             auto* next = ptr->next;
91             if (UNLIKELY(!ptr->CanBeFree())) {
92                 LOG(Error) << "Memory is in use when free " << std::hex << reinterpret_cast<uintptr_t>(ptr);
93                 DCHECK(false && "MemoryChunk can not free");
94             }
95 
96             delete ptr;
97             ptr = next;
98         }
99     }
100 
101     template<typename Element, typename... Args>
New(Args &&...args)102     Element* New(Args&&... args)
103     {
104         static_assert(elementSize >= sizeof(Element));
105         return new (GetMemory()) Element(std::forward<Args>(args)...);
106     }
107 
108     template<typename Element>
Delete(Element * element)109     void Delete(Element* element)
110     {
111         element->~Element();
112         auto* memory = reinterpret_cast<ElementMemory*>(element);
113         auto* chunk = ElementContainer::GetMemoryChunk(memory);
114         chunk->Inc();
115 
116         if (UNLIKELY(chunkNumber > threshold && chunk->CanBeFree())) {
117             FreeChunk(chunk);
118             return;
119         }
120 
121         memory->next = freeList;
122         freeList = memory;
123     }
124 
125 private:
GetMemory()126     void* GetMemory()
127     {
128         if (UNLIKELY(!freeList)) {
129             AllocateChunk();
130         }
131 
132         auto* memory = freeList;
133         ElementContainer::GetMemoryChunk(memory)->Dec();
134         freeList = memory->next;
135 
136         return reinterpret_cast<void*>(memory);
137     }
138 
AllocateChunk()139     void AllocateChunk()
140     {
141         DCHECK(freeList == nullptr);
142         auto* newChunk = new MemoryChunk();
143         if (head) {
144             newChunk->next = head;
145             head->prev = newChunk;
146         }
147         head = newChunk;
148         ++chunkNumber;
149 
150         freeList = &(newChunk->elements[0].memory);
151     }
152 
FreeChunk(MemoryChunk * chunk)153     void FreeChunk(MemoryChunk* chunk)
154     {
155         // Rebuild freeList
156         size_t count = 0;
157         auto* newFreeList = freeList;
158         ElementMemory* prev = nullptr;
159         for (auto* current = freeList; count < sizePerChunk - 1 && current; current = current->next) {
160             if (ElementContainer::GetMemoryChunk(current) == chunk) {
161                 if (prev) {
162                     prev->next = current->next;
163                 } else {
164                     newFreeList = current->next;
165                 }
166                 ++count;
167             } else {
168                 prev = current;
169             }
170         }
171         DCHECK(count == sizePerChunk - 1);
172         freeList = newFreeList;
173 
174         // Rebuild chunk list
175         if (chunk->next) {
176             chunk->next->prev = chunk->prev;
177         }
178         if (chunk->prev) {
179             chunk->prev->next = chunk->next;
180         } else {
181             // chunk is head
182             DCHECK(chunk == head);
183             head = chunk->next;
184         }
185         --chunkNumber;
186 
187         // Delete chunk
188         delete chunk;
189     }
190 
191 private:
192     MemoryChunk* head;
193     size_t chunkNumber;
194     ElementMemory* freeList;
195 };
196 
197 #endif