Automatic date update in version.in
[binutils-gdb.git] / gprofng / src / HeapMap.cc
blob8e6c009bf48e648e70d7f5a38a72562730230fe9
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2 Contributed by Oracle.
4 This file is part of GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
21 #include "config.h"
22 #include "util.h"
23 #include "HeapMap.h"
25 #define HEAPCHUNKSZ 1024 // number of HeapObj's in a chunk
26 #define HEAPCHAINS 9192 // number of address-based chains
27 #define hash(x) (((x) >> 6) % HEAPCHAINS)
29 typedef struct HeapObj
31 uint64_t addr;
32 uint64_t size;
33 long val;
34 HeapObj *next;
35 } HeapObj;
37 typedef struct HeapChunk
39 void *addr;
40 HeapChunk *next;
41 } HeapChunk;
43 HeapMap::HeapMap ()
45 chunks = NULL;
46 empty = NULL;
47 chain = new HeapObj*[HEAPCHAINS];
48 for (int i = 0; i < HEAPCHAINS; i++)
49 chain[i] = NULL;
51 mmaps = new HeapObj;
52 mmaps->addr = (uint64_t) 0;
53 mmaps->size = (uint64_t) 0;
54 mmaps->val = -1;
55 mmaps->next = NULL;
58 HeapMap::~HeapMap ()
60 // free up all the chunks
61 HeapChunk *c = chunks;
62 while (c != NULL)
64 HeapChunk *next = c->next;
65 delete c;
66 c = next;
68 delete[] chain;
69 delete mmaps;
72 void
73 HeapMap::allocate (uint64_t addr, long val)
75 // get a HeapObj, and set it up for the allocated block
76 HeapObj *incoming = getHeapObj ();
77 incoming->addr = addr;
78 incoming->val = val;
79 incoming->next = NULL;
81 // determine which chain the block belongs on
82 int ichain = (int) hash (addr);
84 // if this is the first, just set it up and return
85 if (chain[ichain] == NULL)
87 chain[ichain] = incoming;
88 return;
90 // chain is non-empty -- find the slot for this one
91 // chain is maintained in reverse address order
92 HeapObj *prev = NULL;
93 HeapObj *next = chain[ichain];
95 for (;;)
97 if ((next == NULL) || (next->addr < incoming->addr))
99 // we've found the spot
100 incoming->next = next;
101 if (prev == NULL)
102 chain[ichain] = incoming;
103 else
104 prev->next = incoming;
105 return;
107 if (next->addr == incoming->addr)
109 // error -- two blocks with same address active
110 // ignore the new one
111 releaseHeapObj (incoming);
112 return;
114 // not yet, keep looking
115 prev = next;
116 next = next->next;
120 long
121 HeapMap::deallocate (uint64_t addr)
123 int ichain = (int) hash (addr);
124 HeapObj *cur = chain[ichain];
125 HeapObj *prev = NULL;
126 while (cur != NULL)
128 if (cur->addr == addr)
130 // we've found the block
131 long val = cur->val;
133 // delete the block from the chain
134 if (prev == NULL)
135 chain[ichain] = cur->next;
136 else
137 prev->next = cur->next;
138 releaseHeapObj (cur);
139 return val;
141 prev = cur;
142 cur = cur->next;
145 // block not found
146 return 0;
149 void
150 HeapMap::allocateChunk ()
152 // allocate the memory
153 HeapChunk *c = new HeapChunk;
154 HeapObj *newc = new HeapObj[HEAPCHUNKSZ];
156 // set up the chunk, and queue it for destructor's use
157 c->addr = (void *) newc;
158 c->next = chunks;
159 chunks = c;
161 // Initialize the HeapObj's in the chunk to one chain
162 // last entry is left NULL, terminating the chain
163 for (int i = 0; i < (HEAPCHUNKSZ - 1); i++)
164 newc[i].next = newc + i + 1;
165 newc[HEAPCHUNKSZ - 1].next = NULL;
167 // put that chain on the empty queue
168 empty = newc;
171 HeapObj *
172 HeapMap::getHeapObj ()
174 if (empty == NULL)
175 allocateChunk ();
176 HeapObj *ret = empty;
177 empty = ret->next;
178 return ret;
181 void
182 HeapMap::releaseHeapObj (HeapObj *obj)
184 obj->next = empty;
185 empty = obj;
188 UnmapChunk*
189 HeapMap::mmap (uint64_t addr, int64_t size, long val)
191 HeapObj *incoming = getHeapObj ();
192 incoming->addr = addr;
193 incoming->size = size;
194 incoming->val = val;
195 incoming->next = NULL;
196 UnmapChunk* list = process (incoming, addr, size);
197 return list;
200 UnmapChunk*
201 HeapMap::munmap (uint64_t addr, int64_t size)
203 UnmapChunk* list = process (NULL, addr, size);
204 return list;
207 UnmapChunk*
208 HeapMap::process (HeapObj *obj, uint64_t addr, int64_t size)
210 // Some graphics are used to clarify the alignment of mmap regions
211 // obj, shown as consecutive pages: "NNNNNN"
212 // cur, shown as consecutive pages: "CCCCCC"
214 // Find the first overlap, start of N is before end of C. Examples:
215 // CCCCC
216 // NNNNN
217 // or
218 // CCCCC
219 // NNN
220 // or
221 // CCCCC
222 // NNNNN
223 // or
224 // CCCCC
225 // NNNNNNN
226 HeapObj *prev = mmaps;
227 HeapObj *cur = prev->next;
228 while (cur)
230 if (addr < cur->addr + cur->size)
231 break;
232 prev = cur;
233 cur = prev->next;
236 // None found
237 if (cur == NULL)
239 prev->next = obj;
240 return NULL;
243 UnmapChunk* list = NULL;
244 if (addr > cur->addr)
246 if (cur->addr + cur->size <= addr + size)
248 // Process overlap on the left (low side) of new allocation
249 // New range: N-start to C-end (gets freed below)
250 prev = cur;
251 cur = getHeapObj ();
252 cur->addr = addr;
253 cur->size = prev->addr + prev->size - addr;
254 cur->val = prev->val;
255 cur->next = prev->next;
257 // Truncate range: C-start to N-start
258 prev->size = addr - prev->addr;
260 else
262 // Process new allocation that fits completely within old allocation
263 // New range: N-start to N-end (freed below)
264 int64_t c_end = cur->addr + cur->size;
265 prev = cur;
266 cur = getHeapObj ();
267 cur->addr = addr;
268 cur->size = size;
269 cur->val = prev->val;
270 cur->next = prev->next;
272 // Truncate range: C-start to N-start
273 prev->size = addr - prev->addr;
275 // New range: N-end to C-end.
276 HeapObj *next = getHeapObj ();
277 next->addr = addr + size;
278 next->size = c_end - next->addr;
279 next->val = cur->val;
280 next->next = cur->next;
281 cur->next = next;
285 // Process all full overlaps.
286 // Copy details of cur to UnmapChunk list, remove cur from mmaps
287 while (cur && cur->addr + cur->size <= addr + size)
290 UnmapChunk* uc = new UnmapChunk;
291 uc->val = cur->val;
292 uc->size = cur->size;
293 uc->next = list;
294 list = uc;
296 HeapObj *t = cur;
297 cur = cur->next;
298 releaseHeapObj (t);
301 if (cur && cur->addr < addr + size)
303 // Process the last overlap (right side of new allocation)
304 // Copy details of cur to UnmapChunk list
305 UnmapChunk* uc = new UnmapChunk;
306 uc->val = cur->val;
307 uc->size = addr + size - cur->addr;
308 uc->next = list;
309 list = uc;
311 // Truncate left side of cur
312 cur->size -= uc->size;
313 cur->addr = addr + size;
316 // Insert new allocation
317 if (obj)
319 prev->next = obj;
320 obj->next = cur;
322 else
323 prev->next = cur;
324 return list;