1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team 1998-2008
5 * MegaBlock Allocator Interface. This file contains all the dirty
6 * architecture-dependent hackery required to get a chunk of aligned
7 * memory from the operating system.
9 * ---------------------------------------------------------------------------*/
11 #include "PosixSource.h"
15 #include "BlockAlloc.h"
21 lnat peak_mblocks_allocated = 0;
22 lnat mblocks_allocated = 0;
25 /* -----------------------------------------------------------------------------
26 The MBlock Map: provides our implementation of HEAP_ALLOCED()
27 -------------------------------------------------------------------------- */
29 #if SIZEOF_VOID_P == 4
30 StgWord8 mblock_map[MBLOCK_MAP_SIZE]; // initially all zeros
33 setHeapAlloced(void *p, StgWord8 i)
35 mblock_map[MBLOCK_MAP_ENTRY(p)] = i;
38 #elif SIZEOF_VOID_P == 8
40 MBlockMap **mblock_maps = NULL;
42 nat mblock_map_count = 0;
44 MbcCacheLine mblock_cache[MBC_ENTRIES];
47 findMBlockMap(void *p)
50 StgWord32 hi = (StgWord32) (((StgWord)p) >> 32);
51 for( i = 0; i < mblock_map_count; i++ )
53 if(mblock_maps[i]->addrHigh32 == hi)
55 return mblock_maps[i];
61 StgBool HEAP_ALLOCED_miss(StgWord mblock, void *p)
67 entry_no = mblock & (MBC_ENTRIES-1);
69 map = findMBlockMap(p);
73 value = map->lines[MBLOCK_MAP_LINE(p)];
74 mblock_cache[entry_no] = (mblock<<1) | value;
79 mblock_cache[entry_no] = (mblock<<1);
85 setHeapAlloced(void *p, StgWord8 i)
87 MBlockMap *map = findMBlockMap(p);
91 mblock_maps = realloc(mblock_maps,
92 sizeof(MBlockMap*) * mblock_map_count);
93 map = mblock_maps[mblock_map_count-1] =
94 stgMallocBytes(sizeof(MBlockMap),"markHeapAlloced");
95 memset(map,0,sizeof(MBlockMap));
96 map->addrHigh32 = (StgWord32) (((StgWord)p) >> 32);
99 map->lines[MBLOCK_MAP_LINE(p)] = i;
105 mblock = (StgWord)p >> MBLOCK_SHIFT;
106 entry_no = mblock & (MBC_ENTRIES-1);
107 mblock_cache[entry_no] = (mblock << 1) + i;
113 markHeapAlloced(void *p)
115 setHeapAlloced(p, 1);
119 markHeapUnalloced(void *p)
121 setHeapAlloced(p, 0);
124 #if SIZEOF_VOID_P == 4
127 void * mapEntryToMBlock(nat i)
129 return (void *)((StgWord)i << MBLOCK_SHIFT);
132 void * getFirstMBlock(void)
136 for (i = 0; i < MBLOCK_MAP_SIZE; i++) {
137 if (mblock_map[i]) return mapEntryToMBlock(i);
142 void * getNextMBlock(void *mblock)
146 for (i = MBLOCK_MAP_ENTRY(mblock) + 1; i < MBLOCK_MAP_SIZE; i++) {
147 if (mblock_map[i]) return mapEntryToMBlock(i);
152 #elif SIZEOF_VOID_P == 8
154 void * getNextMBlock(void *p)
161 for (j = 0; j < mblock_map_count; j++) {
162 map = mblock_maps[j];
163 if (map->addrHigh32 == (StgWord)p >> 32) break;
165 if (j == mblock_map_count) return NULL;
167 for (; j < mblock_map_count; j++) {
168 map = mblock_maps[j];
169 if (map->addrHigh32 == (StgWord)p >> 32) {
170 line_no = MBLOCK_MAP_LINE(p);
171 off = (((StgWord)p >> MBLOCK_SHIFT) & (MBC_LINE_SIZE-1)) + 1;
172 // + 1 because we want the *next* mblock
174 line_no = 0; off = 0;
176 for (; line_no < MBLOCK_MAP_ENTRIES; line_no++) {
177 line = map->lines[line_no];
178 for (; off < MBC_LINE_SIZE; off++) {
179 if (line & (1<<off)) {
180 return (void*)(((StgWord)map->addrHigh32 << 32) +
181 line_no * MBC_LINE_SIZE * MBLOCK_SIZE +
191 void * getFirstMBlock(void)
193 MBlockMap *map = mblock_maps[0];
197 for (line_no = 0; line_no < MBLOCK_MAP_ENTRIES; line_no++) {
198 line = map->lines[line_no];
200 for (off = 0; off < MBC_LINE_SIZE; off++) {
201 if (line & (1<<off)) {
202 return (void*)(((StgWord)map->addrHigh32 << 32) +
203 line_no * MBC_LINE_SIZE * MBLOCK_SIZE +
212 #endif // SIZEOF_VOID_P
214 /* -----------------------------------------------------------------------------
215 Allocate new mblock(s)
216 -------------------------------------------------------------------------- */
221 return getMBlocks(1);
224 // The external interface: allocate 'n' mblocks, and return the
233 ret = osGetMBlocks(n);
235 debugTrace(DEBUG_gc, "allocated %d megablock(s) at %p",n,ret);
238 for (i = 0; i < n; i++) {
239 markHeapAlloced( (StgWord8*)ret + i * MBLOCK_SIZE );
242 mblocks_allocated += n;
243 peak_mblocks_allocated = stg_max(peak_mblocks_allocated, mblocks_allocated);
249 freeMBlocks(void *addr, nat n)
253 debugTrace(DEBUG_gc, "freeing %d megablock(s) at %p",n,addr);
255 mblocks_allocated -= n;
257 for (i = 0; i < n; i++) {
258 markHeapUnalloced( (StgWord8*)addr + i * MBLOCK_SIZE );
261 osFreeMBlocks(addr, n);
267 debugTrace(DEBUG_gc, "freeing all megablocks");
275 #if SIZEOF_VOID_P == 8
276 memset(mblock_cache,0xff,sizeof(mblock_cache));