RTS tidyup sweep, first phase
[ghc-hetmet.git] / rts / sm / MBlock.c
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team 1998-2008
4  *
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.
8  *
9  * ---------------------------------------------------------------------------*/
10
11 #include "PosixSource.h"
12 #include "Rts.h"
13
14 #include "RtsUtils.h"
15 #include "BlockAlloc.h"
16 #include "Trace.h"
17 #include "OSMem.h"
18
19 #include <string.h>
20
21 lnat mblocks_allocated = 0;
22 lnat mpc_misses = 0;
23
24 /* -----------------------------------------------------------------------------
25    The MBlock Map: provides our implementation of HEAP_ALLOCED()
26    -------------------------------------------------------------------------- */
27
28 #if SIZEOF_VOID_P == 4
29 StgWord8 mblock_map[MBLOCK_MAP_SIZE]; // initially all zeros
30
31 static void
32 markHeapAlloced(void *p)
33 {
34     mblock_map[MBLOCK_MAP_ENTRY(p)] = 1;
35 }
36
37 #elif SIZEOF_VOID_P == 8
38
39 MBlockMap **mblock_maps = NULL;
40
41 nat mblock_map_count = 0;
42
43 MbcCacheLine mblock_cache[MBC_ENTRIES];
44
45 static MBlockMap *
46 findMBlockMap(void *p)
47 {
48     nat i;
49     StgWord32 hi = (StgWord32) (((StgWord)p) >> 32);
50     for( i = 0; i < mblock_map_count; i++ )
51     {
52         if(mblock_maps[i]->addrHigh32 == hi)
53         {
54             return mblock_maps[i];
55         }
56     }
57     return NULL;
58 }
59
60 StgBool HEAP_ALLOCED_miss(StgWord mblock, void *p)
61 {
62     MBlockMap *map;
63     MBlockMapLine value;
64     nat entry_no;
65     
66     entry_no = mblock & (MBC_ENTRIES-1);
67
68     map = findMBlockMap(p);
69     if (map)
70     {
71         mpc_misses++;
72         value = map->lines[MBLOCK_MAP_LINE(p)];
73         mblock_cache[entry_no] = (mblock<<1) | value;
74         return value;
75     }
76     else
77     {
78         mblock_cache[entry_no] = (mblock<<1);
79         return 0;
80     }
81 }
82
83 static void
84 markHeapAlloced(void *p)
85 {
86     MBlockMap *map = findMBlockMap(p);
87     if(map == NULL)
88     {
89         mblock_map_count++;
90         mblock_maps = realloc(mblock_maps,
91                               sizeof(MBlockMap*) * mblock_map_count);
92         map = mblock_maps[mblock_map_count-1] = 
93             stgMallocBytes(sizeof(MBlockMap),"markHeapAlloced");
94         memset(map,0,sizeof(MBlockMap));
95         map->addrHigh32 = (StgWord32) (((StgWord)p) >> 32);
96     }
97
98     map->lines[MBLOCK_MAP_LINE(p)] = 1;
99
100     {
101         StgWord mblock;
102         nat entry_no;
103         
104         mblock   = (StgWord)p >> MBLOCK_SHIFT;
105         entry_no = mblock & (MBC_ENTRIES-1);
106         mblock_cache[entry_no] = (mblock << 1) + 1;
107     }
108 }
109 #endif
110
111 /* ----------------------------------------------------------------------------
112    Debugging code for traversing the allocated MBlocks
113    
114    This is used for searching for lost blocks when a memory leak is
115    detected; see Blocks.c:findUnmarkedBlock().
116    ------------------------------------------------------------------------ */
117
118 #ifdef DEBUG
119
120 #if SIZEOF_VOID_P == 4
121
122 STATIC_INLINE
123 void * mapEntryToMBlock(nat i)
124 {
125     return (void *)((StgWord)i << MBLOCK_SHIFT);
126 }
127
128 void * getFirstMBlock(void)
129 {
130     nat i;
131
132     for (i = 0; i < MBLOCK_MAP_SIZE; i++) {
133         if (mblock_map[i]) return mapEntryToMBlock(i);
134     }
135     return NULL;
136 }
137
138 void * getNextMBlock(void *mblock)
139 {
140     nat i;
141
142     for (i = MBLOCK_MAP_ENTRY(mblock) + 1; i < MBLOCK_MAP_SIZE; i++) {
143         if (mblock_map[i]) return mapEntryToMBlock(i);
144     }
145     return NULL;
146 }
147
148 #elif SIZEOF_VOID_P == 8
149
150 void * getNextMBlock(void *p)
151 {
152     MBlockMap *map;
153     nat off, j;
154     nat line_no;
155     MBlockMapLine line;
156
157     for (j = 0; j < mblock_map_count; j++)  {
158         map = mblock_maps[j];
159         if (map->addrHigh32 == (StgWord)p >> 32) break;
160     }
161     if (j == mblock_map_count) return NULL;
162
163     for (; j < mblock_map_count; j++) {
164         map = mblock_maps[j];
165         if (map->addrHigh32 == (StgWord)p >> 32) {
166             line_no = MBLOCK_MAP_LINE(p);
167             off  = (((StgWord)p >> MBLOCK_SHIFT) & (MBC_LINE_SIZE-1)) + 1;
168             // + 1 because we want the *next* mblock
169         } else {
170             line_no = 0; off = 0;
171         }
172         for (; line_no < MBLOCK_MAP_ENTRIES; line_no++) {
173             line = map->lines[line_no];
174             for (; off < MBC_LINE_SIZE; off++) {
175                 if (line & (1<<off)) {
176                     return (void*)(((StgWord)map->addrHigh32 << 32) + 
177                                    line_no * MBC_LINE_SIZE * MBLOCK_SIZE +
178                                    off * MBLOCK_SIZE);
179                 }
180             }
181             off = 0;
182         }
183     }
184     return NULL;
185 }
186
187 void * getFirstMBlock(void)
188 {
189     MBlockMap *map = mblock_maps[0];
190     nat line_no, off;
191     MbcCacheLine line;
192
193     for (line_no = 0; line_no < MBLOCK_MAP_ENTRIES; line_no++) {
194         line = map->lines[line_no];
195         if (line) {
196             for (off = 0; off < MBC_LINE_SIZE; off++) {
197                 if (line & (1<<off)) {
198                     return (void*)(((StgWord)map->addrHigh32 << 32) + 
199                                    line_no * MBC_LINE_SIZE * MBLOCK_SIZE +
200                                    off * MBLOCK_SIZE);
201                 }
202             }
203         }
204     }
205     return NULL;
206 }
207
208 #endif // SIZEOF_VOID_P
209
210 #endif // DEBUG
211
212 /* -----------------------------------------------------------------------------
213    Allocate new mblock(s)
214    -------------------------------------------------------------------------- */
215
216 void *
217 getMBlock(void)
218 {
219   return getMBlocks(1);
220 }
221
222 // The external interface: allocate 'n' mblocks, and return the
223 // address.
224
225 void *
226 getMBlocks(nat n)
227 {
228     nat i;
229     void *ret;
230
231     ret = osGetMBlocks(n);
232
233     debugTrace(DEBUG_gc, "allocated %d megablock(s) at %p",n,ret);
234     
235     // fill in the table
236     for (i = 0; i < n; i++) {
237         markHeapAlloced( (StgWord8*)ret + i * MBLOCK_SIZE );
238     }
239     
240     mblocks_allocated += n;
241
242     return ret;
243 }
244
245 void
246 freeAllMBlocks(void)
247 {
248     osFreeAllMBlocks();
249 }
250
251 void
252 initMBlocks(void)
253 {
254     osMemInit();
255 #if SIZEOF_VOID_P == 8
256     memset(mblock_cache,0xff,sizeof(mblock_cache));
257 #endif
258 }