4 * Copyright (c) 1998 A. Krall, R. Grafl, M. Gschwind, M. Probst, P. Tomsich
5 * See file COPYRIGHT for information on usage and disclaimer of warranties
7 * Authors: Philipp Tomsich EMAIL: cacao@complang.tuwien.ac.at
9 * $Id: bitmap2.c 37 1998-11-04 12:39:19Z phil $
13 * This file contains the new bitmap management; it's used within the garbage
14 * collector and allocator to maintain and access the objectstart-, marker-
15 * and reference-bitmaps.
18 * 1. For efficencies sake, the memory used for the bitmap is never accessed
19 * directly using a heap-offset, but through a pointer offset at bitmap
20 * creation; this saves all the subtractions and additions necessary to
21 * convert between an address on the heap and an offset into the heap.
23 * 2. I finally added a bitmap_t structure to encapsulate some state
24 * information. It contains everything necessary to access the bitmap,
25 * caches a few precomputable values and allows for freeing the bitmap.
27 * 3. There's no checks whatsoever to determine whether an address passed is
28 * valid or not. These were removed, in order to allow passing the offset
29 * address of the bitmap instead of the bitmap structure.
30 * I.e., checking addresses to determine whether they are pointing onto
31 * the heap must be done before passing them to the bitmap management
34 * 4. Just added exceptions to note 3: Now we have new functions checking the
35 * validity of the address to aid in debugging. They are named
36 * bitmap_checking_{set|clear|test}bit and will cause an assertion to fail
37 * if the addr argument is out of range.
40 #include <assert.h> /* assert */
41 #include <stdio.h> /* printf, fprintf */
42 #include <stdlib.h> /* malloc, free */
43 #include <string.h> /* memset */
44 #include <unistd.h> /* exit */
48 #warning "bitmap2.c untested in 32-bit mode -- phil."
50 /* FIXME: I haven't decided, whether to keep these macro definitions here or
51 * move them to the header file; they are implementation details, so
52 * they should stay here, but moving them would make the SETBIT,
53 * TESTBIT and CLEARBIT macros available to the general public. --phil.
56 /* FIXME: HEAPBLOCK_SIZE is an alias for POINTER_ALIGNMENT and should be
60 /* Please note: All values are log2 */
62 #define POINTER_ALIGNMENT 3 /* alignment of pointers onto the
63 heap == heapblocksize */
64 #define BITBLOCK_SIZE 3 /* bytes/BITBLOCK */
66 #define POINTER_ALIGNMENT 2
67 #define BITBLOCK_SIZE 2
70 #define HEAPBLOCK_SIZE POINTER_ALIGNMENT
71 #define BITS_PER_BYTE 3 /* actually quite self-explanatory */
72 #define HEAPBLOCKS_PER_BITBLOCK (BITBLOCK_SIZE + BITS_PER_BYTE)
74 #define ADDR_TO_BLOCK(addr) ((OFFSET_T)(addr) >> (HEAPBLOCKS_PER_BITBLOCK + POINTER_ALIGNMENT))
75 #define ADDR_TO_OFFSET(addr) (((OFFSET_T)(addr) & ((1 << (HEAPBLOCKS_PER_BITBLOCK + POINTER_ALIGNMENT)) - 1)) >> HEAPBLOCK_SIZE)
76 #define BLOCK_TO_ADDR(block) ((block) << (HEAPBLOCKS_PER_BITBLOCK + POINTER_ALIGNMENT))
77 #define OFFSET_TO_ADDR(offset) ((offset) << HEAPBLOCK_SIZE)
78 #define CALC_BITMAP_SIZE(size) (((size) + ((1 << (POINTER_ALIGNMENT + HEAPBLOCK_SIZE)) - 1)) >> BITS_PER_BYTE)
80 #define CHECK_ADDR_ALIGNMENT(addr) { assert(!((OFFSET_T)addr & ((1 << POINTER_ALIGNMENT) - 1))); }
81 #define CALC_ZERO_OFFSET(zero) (((OFFSET_T)(zero) >> (HEAPBLOCK_SIZE + BITS_PER_BYTE)))
83 #define BIT_AT_OFFSET(offset) ((BITBLOCK)1 << (offset))
84 #define BIT_FOR_ADDR(addr) BIT_AT_OFFSET(ADDR_TO_OFFSET((addr)))
86 #define SETBIT(bitmap, addr) { bitmap[ADDR_TO_BLOCK(addr)] |= BIT_FOR_ADDR(addr); }
87 #define CLEARBIT(bitmap, addr) { bitmap[ADDR_TO_BLOCK(addr)] &= ~BIT_FOR_ADDR(addr); }
88 #define TESTBIT(bitmap, addr) ( (bitmap[ADDR_TO_BLOCK(addr)] & BIT_FOR_ADDR(addr)) != 0 )
91 /* Operations per macro (relative cost):
93 * Macro | & | &= | |= | ~ | >> | << | + | dereference |
94 * -----------------+---+----+----+---+----+----+---+-------------+
95 * ADDR_TO_BLOCK | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
96 * ADDR_TO_OFFSET | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
97 * BLOCK_TO_ADDR | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
98 * OFFSET_TO_ADDR | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
99 * CALC_BITMAP_SIZE | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
100 * CALC_ZERO_OFFSET | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
101 * -----------------+---+----+----+---+----+----+---+-------------+
102 * BIT_AT_OFFSET | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
103 * BIT_FOR_ADDR | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
104 * -----------------+---+----+----+---+----+----+---+-------------+
105 * SETBIT | 1 | 0 | 1 | 0 | 2 | 1 | 0 | 1 |
106 * CLEARBIT | 1 | 1 | 0 | 1 | 2 | 1 | 0 | 1 |
107 * TESTBIT | 2 | 0 | 0 | 0 | 2 | 1 | 0 | 1 |
112 void bitmap_setbit(BITBLOCK* bitmap,
115 SETBIT(bitmap, addr);
119 void bitmap_clearbit(BITBLOCK* bitmap,
122 CLEARBIT(bitmap, addr);
126 bool bitmap_testbit(BITBLOCK* bitmap,
129 return TESTBIT(bitmap, addr);
134 void bitmap_boundscheck(bitmap_t* bitmap,
137 /* check the lower bound */
138 assert((void*)&bitmap->bitmap[ADDR_TO_BLOCK(addr)] >= bitmap->bitmap_memory);
139 /* check the upper bound */
140 assert(&bitmap->bitmap[
142 <= &bitmap->bitmap[bitmap->bitmap_top_block]);
143 assert(addr < bitmap->bitmap_beyond_addr); /* a stricter way to check the upper bound */
147 void bitmap_checking_setbit(bitmap_t* bitmap,
150 bitmap_boundscheck(bitmap, addr);
151 bitmap_setbit(bitmap->bitmap, addr);
155 void bitmap_checking_clearbit(bitmap_t* bitmap,
158 bitmap_boundscheck(bitmap, addr);
159 bitmap_clearbit(bitmap->bitmap, addr);
163 bool bitmap_checking_testbit(bitmap_t* bitmap,
166 bitmap_boundscheck(bitmap, addr);
167 return bitmap_testbit(bitmap->bitmap, addr);
171 void bitmap_clear(bitmap_t* bitmap)
173 memset(bitmap->bitmap_memory, 0, bitmap->bytesize);
177 bitmap_t* bitmap_allocate(void* zero_addr,
182 unsigned long bytesize = CALC_BITMAP_SIZE(size); /* align */
183 bitmap = (bitmap_t*)malloc(sizeof(bitmap_t));
185 CHECK_ADDR_ALIGNMENT(zero_addr); /* ensure correct alignment for zero_addr */
187 bitmap->bytesize = bytesize;
188 bitmap->bitmap_memory = malloc(bytesize);
189 bitmap->bitmap = bitmap->bitmap_memory - CALC_ZERO_OFFSET(zero_addr); /* offset for fast access */
191 bitmap->bitmap_beyond_addr = zero_addr + size;
192 bitmap->bitmap_top_block = ADDR_TO_BLOCK(bitmap->bitmap_beyond_addr - sizeof(BITBLOCK));
194 if (!bitmap->bitmap_memory) {
195 /* handle error -- unable to allocate enough memory */
196 fprintf(stderr, "bitmap2.c: Failed to allocate memory for a bitmap.\n");
197 exit(-1); /* FIXME: I should probably call some sort of cacao-wide "panic" function ?! -- phil. */
200 bitmap_clear(bitmap);
206 void bitmap_release(bitmap_t* bitmap)
209 if (bitmap->bitmap_memory)
210 free(bitmap->bitmap_memory);
218 int offset_for_lowest(BITBLOCK i)
220 /* Maintainer, don't despair!
222 * The OFFSET_TO_ADDR adjusts an argument according to the size of heap-allocation blocks,
223 * so that the resulting value can be used as an offset to a pointer.
224 * I.e.: addr + OFFSET_TO_ADDR(i) is equivalent to addr + (sizeof(heap_block) * i)
226 * The definition of lowest just looks inefficient, everything should be expanded at
227 * compile-time, though. -- phil.
230 static signed char lowest[256] = {
231 OFFSET_TO_ADDR(0), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
232 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
233 OFFSET_TO_ADDR(4), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
234 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
235 OFFSET_TO_ADDR(5), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
236 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
237 OFFSET_TO_ADDR(4), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
238 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
239 OFFSET_TO_ADDR(6), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
240 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
241 OFFSET_TO_ADDR(4), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
242 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
243 OFFSET_TO_ADDR(5), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
244 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
245 OFFSET_TO_ADDR(4), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
246 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
247 OFFSET_TO_ADDR(7), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
248 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
249 OFFSET_TO_ADDR(4), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
250 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
251 OFFSET_TO_ADDR(5), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
252 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
253 OFFSET_TO_ADDR(4), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
254 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
255 OFFSET_TO_ADDR(6), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
256 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
257 OFFSET_TO_ADDR(4), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
258 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
259 OFFSET_TO_ADDR(5), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
260 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
261 OFFSET_TO_ADDR(4), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
262 OFFSET_TO_ADDR(3), 0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
266 if (i & 0xffffffffffULL)
270 return OFFSET_TO_ADDR(0) + lowest[(unsigned char)i];
272 return OFFSET_TO_ADDR(8) + lowest[(unsigned char)(i>>8)];
275 return OFFSET_TO_ADDR(16) + lowest[(unsigned char)(i>>16)];
277 return OFFSET_TO_ADDR(24) + lowest[(unsigned char)(i>>24)];
280 if (i & 0xffff00000000ULL)
281 if (i & 0xff00000000ULL)
282 return OFFSET_TO_ADDR(32) + lowest[(unsigned char)(i>>32)];
284 return OFFSET_TO_ADDR(40) + lowest[(unsigned char)(i>>40)];
286 if (i & 0xff000000000000ULL)
287 return OFFSET_TO_ADDR(48) + lowest[(unsigned char)(i>>48)];
289 return OFFSET_TO_ADDR(56) + lowest[(unsigned char)(i>>56)];
295 bitmap_find_next_setbit(bitmap_t* bitmap,
298 OFFSET_T block = ADDR_TO_BLOCK(addr);
299 OFFSET_T offset = ADDR_TO_OFFSET(addr);
302 bitmap_boundscheck(bitmap, addr);
304 /* 1. check the current block, starting from the bit indicated by addr */
305 pattern = bitmap->bitmap[block] >> offset;
307 return (void*)(addr + offset_for_lowest(pattern));
309 /* 2. iteratively check block by block until the end of the bitmap */
310 while (block < bitmap->bitmap_top_block) {
311 pattern = bitmap->bitmap[++block];
314 return (void*)(BLOCK_TO_ADDR(block) + offset_for_lowest(pattern));
317 /* 3. failed to find a set bit... */
318 return bitmap->bitmap_beyond_addr;
323 bitmap_find_next_combination_set_unset(bitmap_t* bitmap,
324 bitmap_t* invertedmap,
327 OFFSET_T block = ADDR_TO_BLOCK(addr);
328 OFFSET_T offset = ADDR_TO_OFFSET(addr);
331 bitmap_boundscheck(bitmap, addr);
333 /* 1. check the current block, starting from the bit indicated by addr */
334 pattern = (bitmap->bitmap[block] & ~invertedmap->bitmap[block]) >> offset;
336 return (void*)(addr + offset_for_lowest(pattern));
338 /* 2. iteratively check block by block until the end of the bitmap */
339 while (block < bitmap->bitmap_top_block) {
340 pattern = bitmap->bitmap[++block] & ~invertedmap->bitmap[block];
343 return (void*)(BLOCK_TO_ADDR(block) + offset_for_lowest(pattern));
346 /* 3. failed to find a combination... */
347 return bitmap->bitmap_beyond_addr;
351 * These are local overrides for various environment variables in Emacs.
352 * Please do not remove this and leave it at the end of the file, where
353 * Emacs will automagically detect them.
354 * ---------------------------------------------------------------------
357 * indent-tabs-mode: t