1 /* Copyright (C) 2021 Free Software Foundation, Inc.
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)
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. */
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
37 typedef struct HeapChunk
47 chain = new HeapObj*[HEAPCHAINS];
48 for (int i = 0; i < HEAPCHAINS; i++)
52 mmaps->addr = (uint64_t) 0;
53 mmaps->size = (uint64_t) 0;
60 // free up all the chunks
61 HeapChunk *c = chunks;
64 HeapChunk *next = c->next;
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;
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;
90 // chain is non-empty -- find the slot for this one
91 // chain is maintained in reverse address order
93 HeapObj *next = chain[ichain];
97 if ((next == NULL) || (next->addr < incoming->addr))
99 // we've found the spot
100 incoming->next = next;
102 chain[ichain] = incoming;
104 prev->next = incoming;
107 if (next->addr == incoming->addr)
109 // error -- two blocks with same address active
110 // ignore the new one
111 releaseHeapObj (incoming);
114 // not yet, keep looking
121 HeapMap::deallocate (uint64_t addr)
123 int ichain = (int) hash (addr);
124 HeapObj *cur = chain[ichain];
125 HeapObj *prev = NULL;
128 if (cur->addr == addr)
130 // we've found the block
133 // delete the block from the chain
135 chain[ichain] = cur->next;
137 prev->next = cur->next;
138 releaseHeapObj (cur);
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;
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
172 HeapMap::getHeapObj ()
176 HeapObj *ret = empty;
182 HeapMap::releaseHeapObj (HeapObj *obj)
189 HeapMap::mmap (uint64_t addr, int64_t size, long val)
191 HeapObj *incoming = getHeapObj ();
192 incoming->addr = addr;
193 incoming->size = size;
195 incoming->next = NULL;
196 UnmapChunk* list = process (incoming, addr, size);
201 HeapMap::munmap (uint64_t addr, int64_t size)
203 UnmapChunk* list = process (NULL, addr, size);
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:
226 HeapObj *prev = mmaps;
227 HeapObj *cur = prev->next;
230 if (addr < cur->addr + cur->size)
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)
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;
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;
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;
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;
292 uc->size = cur->size;
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;
307 uc->size = addr + size - cur->addr;
311 // Truncate left side of cur
312 cur->size -= uc->size;
313 cur->addr = addr + size;
316 // Insert new allocation