1 /* Copyright (C) 2021-2023 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