Major file restructuring.
[cacao.git] / src / mm / memory.c
1 /* toolbox/memory.c - 
2
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
5    M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
6    P. Tomsich, J. Wenninger
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Reinhard Grafl
28
29    $Id: memory.c 557 2003-11-02 22:51:59Z twisti $
30
31 */
32
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <assert.h>
37 #include <string.h>
38 #include <sys/mman.h>
39 #include <unistd.h>
40
41 #include "global.h"
42 #include "loging.h"
43 #include "memory.h"
44
45
46 /********* general types, variables and auxiliary functions *********/
47
48 #define DUMPBLOCKSIZE  (2<<21)
49 #define ALIGNSIZE           8
50
51 typedef struct dumplist {
52         struct dumplist *prev;
53         char *dumpmem;
54 } dumplist;
55
56
57
58 long int memoryusage = 0;
59
60 long int dumpsize = 0;
61 long int dumpspace = 0;
62 dumplist *topdumpblock = NULL;
63
64 long int maxmemusage = 0;
65 long int maxdumpsize = 0;
66
67 #define TRACECALLARGS
68
69 #ifdef TRACECALLARGS
70 static char *nomallocmem = NULL;
71 static char *nomalloctop;
72 static char *nomallocptr;
73
74
75 static void *lit_checked_alloc (int length)
76 {
77         void *m;
78
79         if (!nomallocmem) {
80                 nomallocmem = malloc(16777216); 
81                 nomalloctop = nomallocmem + 16777216;
82                 nomallocptr = nomallocmem;
83         }
84
85         nomallocptr = (void*) ALIGN ((long) nomallocptr, ALIGNSIZE);
86         
87         m = nomallocptr;
88         nomallocptr += length;
89         if (nomallocptr > nomalloctop) panic ("Out of memory");
90         return m;
91 }
92
93 #else
94
95 static void *lit_checked_alloc (int length)
96 {
97         void *m = malloc(length);
98         if (!m) panic ("Out of memory");
99         return m;
100 }
101
102 #endif
103
104
105 static void *checked_alloc (int length)
106 {
107         void *m = malloc(length);
108         if (!m) panic ("Out of memory");
109         return m;
110 }
111
112
113 static int mmapcodesize = 0;
114 static void *mmapcodeptr = NULL;
115
116
117 void *mem_mmap(int length)
118 {
119         void *retptr;
120
121         length = (ALIGN(length,ALIGNSIZE));
122         if (length > mmapcodesize) {
123                 mmapcodesize = 0x10000;
124                 if (length > mmapcodesize)
125                         mmapcodesize = length;
126                 mmapcodesize = (ALIGN(mmapcodesize, getpagesize()));
127                 mmapcodeptr = mmap (NULL, (size_t) mmapcodesize,
128                                                         PROT_READ | PROT_WRITE | PROT_EXEC,
129                                                         MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t) 0);
130                 if (mmapcodeptr == (void*) -1)
131                         panic ("Out of memory");
132         }
133         retptr = mmapcodeptr;
134         mmapcodeptr = (void*) ((char*) mmapcodeptr + length);
135         mmapcodesize -= length;
136         return retptr;
137 }
138
139
140 #ifdef DEBUG
141
142 /************ Memory manager, safe version **************/
143
144
145 typedef struct memblock {
146         struct memblock *prev,*next;
147         int length;
148 } memblock;
149
150 #define BLOCKOFFSET    (ALIGN(sizeof(memblock),ALIGNSIZE))
151
152 struct memblock *firstmemblock;
153
154
155
156 void *mem_alloc(int length)
157 {
158         memblock *mb;
159
160         if (length==0) return NULL;
161         mb = checked_alloc (length + BLOCKOFFSET);
162
163         mb -> prev = NULL;
164         mb -> next = firstmemblock;     
165         mb -> length = length;
166
167         if (firstmemblock) firstmemblock -> prev = mb;
168         firstmemblock = mb;
169
170         memoryusage += length;
171         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
172
173         return ((char*) mb) + BLOCKOFFSET;
174 }
175
176
177 void *lit_mem_alloc(int length)
178 {
179         memblock *mb;
180
181         if (length==0) return NULL;
182         mb = lit_checked_alloc (length + BLOCKOFFSET);
183
184         mb -> prev = NULL;
185         mb -> next = firstmemblock;     
186         mb -> length = length;
187
188         if (firstmemblock) firstmemblock -> prev = mb;
189         firstmemblock = mb;
190
191         memoryusage += length;
192         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
193
194         return ((char*) mb) + BLOCKOFFSET;
195 }
196
197
198 void mem_free(void *m, int length)
199 {
200         memblock *mb;
201         if (!m) {
202                 if (length==0) return;
203                 panic ("returned memoryblock with address NULL, length != 0");
204         }
205
206         mb = (memblock*) (((char*) m) - BLOCKOFFSET);
207         
208         if (mb->length != length) {
209                 sprintf (logtext, 
210                                  "Memory block of size %d has been return as size %d",
211                          mb->length, length);
212                 error();
213         }
214                 
215         if (mb->prev) mb->prev->next = mb->next;
216         else firstmemblock = mb->next;
217         if (mb->next) mb->next->prev = mb->prev;
218
219         free (mb);
220
221         memoryusage -= length;
222 }
223
224
225 void lit_mem_free(void *m, int length)
226 {
227         memblock *mb;
228         if (!m) {
229                 if (length==0) return;
230                 panic ("returned memoryblock with address NULL, length != 0");
231         }
232
233         mb = (memblock*) (((char*) m) - BLOCKOFFSET);
234         
235         if (mb->length != length) {
236                 sprintf (logtext, 
237                                  "Memory block of size %d has been return as size %d",
238                          mb->length, length);
239                 error();
240         }
241                 
242         if (mb->prev) mb->prev->next = mb->next;
243         else firstmemblock = mb->next;
244         if (mb->next) mb->next->prev = mb->prev;
245
246 #ifdef TRACECALLARGS
247 #else
248         free (mb);
249 #endif
250
251         memoryusage -= length;
252 }
253
254
255 void *mem_realloc (void *m1, int len1, int len2)
256 {
257         void *m2;
258         
259         m2 = mem_alloc (len2);
260         memcpy (m2, m1, len1);
261         mem_free (m1, len1);
262
263         return m2;
264 }
265
266
267
268
269 static void mem_characterlog (unsigned char *m, int len)
270 {
271 #       define LINESIZE 16
272         int z,i;
273         
274         for (z=0; z<len; z+=LINESIZE) {
275                 sprintf (logtext, "   ");
276                         
277                 for (i=z; i<(z+LINESIZE) && i<len; i++) {
278                         sprintf (logtext+strlen(logtext), "%2x ", m[i]);
279                 }
280                 for (; i<(z+LINESIZE); i++) {
281                         sprintf (logtext+strlen(logtext), "   ");
282                 }
283                                         
284                 sprintf (logtext+strlen(logtext),"   ");
285                 for (i=z; i<(z+LINESIZE) && i<len; i++) {
286                         sprintf (logtext+strlen(logtext),
287                                          "%c", (m[i]>=' ' && m[i]<=127) ? m[i] : '.');
288                 }
289                         
290                 dolog();
291         }
292 }
293
294 #else
295 /******* Memory manager, fast version ******/
296
297
298 void *mem_alloc(int length)
299 {
300         if (length==0) return NULL;
301
302         memoryusage += length;
303         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
304         
305         return checked_alloc (length);
306 }
307
308
309 void *lit_mem_alloc(int length)
310 {
311         if (length==0) return NULL;
312
313         memoryusage += length;
314         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
315         
316         return lit_checked_alloc (length);
317 }
318
319
320 void mem_free(void *m, int length)
321 {
322         if (!m) {
323                 if (length==0) return;
324                 panic ("returned memoryblock with address NULL, length != 0");
325         }
326
327         memoryusage -= length;
328
329         free (m);
330 }
331
332
333 void lit_mem_free(void *m, int length)
334 {
335         if (!m) {
336                 if (length==0) return;
337                 panic ("returned memoryblock with address NULL, length != 0");
338         }
339
340         memoryusage -= length;
341
342 #ifdef TRACECALLARGS
343 #else
344         free (m);
345 #endif
346 }
347
348
349 void *mem_realloc (void *m1, int len1, int len2)
350 {
351         void *m2;
352
353         if (!m1) {
354                 if (len1!=0) 
355                         panic ("reallocating memoryblock with address NULL, length != 0");
356         }
357                 
358         memoryusage = (memoryusage - len1) + len2;
359
360         m2 = realloc (m1, len2);
361         if (!m2) panic ("Out of memory");
362         return m2;
363 }
364
365
366 #endif
367
368 /******* common memory manager parts ******/
369
370 long int mem_usage()
371 {
372         return memoryusage;
373 }
374
375
376 void *dump_alloc(int length)
377 {
378         void *m;
379
380         if (length == 0) return NULL;
381         
382         length = ALIGN(length, ALIGNSIZE);
383
384         assert(length <= DUMPBLOCKSIZE);
385         assert(length > 0);
386
387         if (dumpsize + length > dumpspace) {
388                 dumplist *newdumpblock = checked_alloc(sizeof(dumplist));
389
390                 newdumpblock->prev = topdumpblock;
391                 topdumpblock = newdumpblock;
392
393                 newdumpblock->dumpmem = checked_alloc(DUMPBLOCKSIZE);
394
395                 dumpsize = dumpspace;
396                 dumpspace += DUMPBLOCKSIZE;             
397         }
398         
399         m = topdumpblock->dumpmem + DUMPBLOCKSIZE - (dumpspace - dumpsize);
400         dumpsize += length;
401         
402         if (dumpsize > maxdumpsize) {
403                 maxdumpsize = dumpsize;
404         }
405                 
406         return m;
407 }   
408
409
410 void *dump_realloc(void *ptr, int len1, int len2)
411 {
412         void *p2 = dump_alloc(len2);
413         memcpy(p2, ptr, len1);  
414         return p2;
415 }
416
417
418 long int dump_size()
419 {
420         return dumpsize;
421 }
422
423
424 void dump_release(long int size)
425 {
426         assert(size >= 0 && size <= dumpsize);
427
428         dumpsize = size;
429         
430         while (dumpspace > dumpsize + DUMPBLOCKSIZE) {
431                 dumplist *oldtop = topdumpblock;
432                 
433                 topdumpblock = oldtop->prev;
434                 dumpspace -= DUMPBLOCKSIZE;
435                 
436 #ifdef TRACECALLARGS
437 #else
438                 free(oldtop->dumpmem);
439                 free(oldtop);
440 #endif
441         }               
442 }
443
444
445 void mem_usagelog (int givewarnings)
446 {
447         if ((memoryusage!=0) && givewarnings) {
448                 sprintf (logtext, "Allocated memory not returned: %d",
449                                  (int)memoryusage);
450                 dolog();
451
452 #ifdef DEBUG
453                 { 
454                         memblock *mb = firstmemblock;
455                         while (mb) {
456                                 sprintf (logtext, "   Memory block size: %d", 
457                                                  (int)(mb->length) );
458                                 dolog();
459                                 mem_characterlog ( ((unsigned char*)mb) + BLOCKOFFSET, mb->length);
460                                 mb = mb->next;
461                         }
462                 }
463 #endif
464                         
465         }
466
467         if ((dumpsize!=0) && givewarnings) {
468                 sprintf (logtext, "Dump memory not returned: %d",(int)dumpsize);
469                 dolog();
470         }
471
472
473         sprintf(logtext, "Random/Dump - memory usage: %dK/%dK", 
474                         (int)((maxmemusage+1023)/1024), 
475                         (int)((maxdumpsize+1023)/1024) );
476         dolog();
477         
478 }
479
480
481 /*
482  * These are local overrides for various environment variables in Emacs.
483  * Please do not remove this and leave it at the end of the file, where
484  * Emacs will automagically detect them.
485  * ---------------------------------------------------------------------
486  * Local variables:
487  * mode: c
488  * indent-tabs-mode: t
489  * c-basic-offset: 4
490  * tab-width: 4
491  * End:
492  */