4334496b8e50c935f1510c91c58a85fff4242fc7
[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 689 2003-12-05 18:03:47Z stefan $
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)
90                 panic("Out of memory");
91
92         return m;
93 }
94
95 #else
96
97 static void *lit_checked_alloc(int length)
98 {
99         void *m = malloc(length);
100         if (!m) panic ("Out of memory");
101         return m;
102 }
103
104 #endif
105
106
107 static void *checked_alloc(int length)
108 {
109         void *m = malloc(length);
110         if (!m) panic("Out of memory");
111         return m;
112 }
113
114
115 static int mmapcodesize = 0;
116 static void *mmapcodeptr = NULL;
117
118
119 void *mem_mmap(int length)
120 {
121         void *retptr;
122
123         length = (ALIGN(length,ALIGNSIZE));
124         if (length > mmapcodesize) {
125                 mmapcodesize = 0x10000;
126                 if (length > mmapcodesize)
127                         mmapcodesize = length;
128                 mmapcodesize = (ALIGN(mmapcodesize, getpagesize()));
129                 mmapcodeptr = mmap (NULL, (size_t) mmapcodesize,
130                                                         PROT_READ | PROT_WRITE | PROT_EXEC,
131                                                         MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t) 0);
132                 if (mmapcodeptr == (void*) -1)
133                         panic ("Out of memory");
134         }
135         retptr = mmapcodeptr;
136         mmapcodeptr = (void*) ((char*) mmapcodeptr + length);
137         mmapcodesize -= length;
138         return retptr;
139 }
140
141
142 #ifdef DEBUG
143
144 /************ Memory manager, safe version **************/
145
146
147 typedef struct memblock {
148         struct memblock *prev, *next;
149         int length;
150 } memblock;
151
152 #define BLOCKOFFSET    (ALIGN(sizeof(memblock),ALIGNSIZE))
153
154 struct memblock *firstmemblock;
155
156
157
158 void *mem_alloc(int length)
159 {
160         memblock *mb;
161
162         if (length == 0) return NULL;
163         mb = checked_alloc(length + BLOCKOFFSET);
164
165         mb->prev = NULL;
166         mb->next = firstmemblock;       
167         mb->length = length;
168
169         if (firstmemblock) firstmemblock->prev = mb;
170         firstmemblock = mb;
171
172         memoryusage += length;
173         if (memoryusage > maxmemusage)
174                 maxmemusage = memoryusage;
175
176         return ((char*) mb) + BLOCKOFFSET;
177 }
178
179
180 void *lit_mem_alloc(int length)
181 {
182         memblock *mb;
183
184         if (length == 0) return NULL;
185         mb = lit_checked_alloc(length + BLOCKOFFSET);
186
187         mb->prev = NULL;
188         mb->next = firstmemblock;       
189         mb->length = length;
190
191         if (firstmemblock) firstmemblock -> prev = mb;
192         firstmemblock = mb;
193
194         memoryusage += length;
195         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
196
197         return ((char*) mb) + BLOCKOFFSET;
198 }
199
200
201 void mem_free(void *m, int length)
202 {
203         memblock *mb;
204         if (!m) {
205                 if (length == 0) return;
206                 panic("returned memoryblock with address NULL, length != 0");
207         }
208
209         mb = (memblock*) (((char*) m) - BLOCKOFFSET);
210         
211         if (mb->length != length) {
212                 sprintf(logtext, 
213                                 "Memory block of size %d has been return as size %d",
214                                 mb->length, length);
215                 error();
216         }
217                 
218         if (mb->prev) mb->prev->next = mb->next;
219         else firstmemblock = mb->next;
220         if (mb->next) mb->next->prev = mb->prev;
221
222         free (mb);
223
224         memoryusage -= length;
225 }
226
227
228 void lit_mem_free(void *m, int length)
229 {
230         memblock *mb;
231         if (!m) {
232                 if (length==0) return;
233                 panic("returned memoryblock with address NULL, length != 0");
234         }
235
236         mb = (memblock*) (((char*) m) - BLOCKOFFSET);
237         
238         if (mb->length != length) {
239                 sprintf(logtext, 
240                                 "Memory block of size %d has been return as size %d",
241                                 mb->length, length);
242                 error();
243         }
244                 
245         if (mb->prev) mb->prev->next = mb->next;
246         else firstmemblock = mb->next;
247         if (mb->next) mb->next->prev = mb->prev;
248
249 #ifdef TRACECALLARGS
250 #else
251         free(mb);
252 #endif
253
254         memoryusage -= length;
255 }
256
257
258 void *mem_realloc(void *m1, int len1, int len2)
259 {
260         void *m2;
261         
262         m2 = mem_alloc(len2);
263         memcpy(m2, m1, len1);
264         mem_free(m1, len1);
265
266         return m2;
267 }
268
269
270
271
272 static void mem_characterlog(unsigned char *m, int len)
273 {
274 #       define LINESIZE 16
275         int z, i;
276         char logtext[MAXLOGTEXT];
277         
278         for (z = 0; z < len; z += LINESIZE) {
279                 sprintf(logtext, "   ");
280                         
281                 for (i = z; i < (z + LINESIZE) && i < len; i++) {
282                         sprintf(logtext + strlen(logtext), "%2x ", m[i]);
283                 }
284                 for (; i < (z + LINESIZE); i++) {
285                         sprintf(logtext + strlen(logtext), "   ");
286                 }
287                                         
288                 sprintf(logtext + strlen(logtext),"   ");
289                 for (i = z; i < (z + LINESIZE) && i < len; i++) {
290                         sprintf(logtext+strlen(logtext),
291                                         "%c", (m[i] >= ' ' && m[i] <= 127) ? m[i] : '.');
292                 }
293                         
294                 dolog(logtext);
295         }
296 }
297
298 #else
299 /******* Memory manager, fast version ******/
300
301
302 void *mem_alloc(int length)
303 {
304         if (length == 0) return NULL;
305
306         memoryusage += length;
307         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
308         
309         return checked_alloc(length);
310 }
311
312
313 void *lit_mem_alloc(int length)
314 {
315         if (length == 0) return NULL;
316
317         memoryusage += length;
318         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
319         
320         return lit_checked_alloc(length);
321 }
322
323
324 void mem_free(void *m, int length)
325 {
326         if (!m) {
327                 if (length == 0) return;
328                 panic("returned memoryblock with address NULL, length != 0");
329         }
330
331         memoryusage -= length;
332
333         free(m);
334 }
335
336
337 void lit_mem_free(void *m, int length)
338 {
339         if (!m) {
340                 if (length == 0) return;
341                 panic("returned memoryblock with address NULL, length != 0");
342         }
343
344         memoryusage -= length;
345
346 #ifdef TRACECALLARGS
347 #else
348         free(m);
349 #endif
350 }
351
352
353 void *mem_realloc (void *m1, int len1, int len2)
354 {
355         void *m2;
356
357         if (!m1) {
358                 if (len1!=0) 
359                         panic ("reallocating memoryblock with address NULL, length != 0");
360         }
361                 
362         memoryusage = (memoryusage - len1) + len2;
363
364         m2 = realloc (m1, len2);
365         if (!m2) panic ("Out of memory");
366         return m2;
367 }
368
369
370 #endif
371
372 /******* common memory manager parts ******/
373
374 long int mem_usage()
375 {
376         return memoryusage;
377 }
378
379
380 void *dump_alloc(int length)
381 {
382         void *m;
383
384         if (length == 0) return NULL;
385         
386         length = ALIGN(length, ALIGNSIZE);
387
388         assert(length <= DUMPBLOCKSIZE);
389         assert(length > 0);
390
391         if (dumpsize + length > dumpspace) {
392                 dumplist *newdumpblock = checked_alloc(sizeof(dumplist));
393
394                 newdumpblock->prev = topdumpblock;
395                 topdumpblock = newdumpblock;
396
397                 newdumpblock->dumpmem = checked_alloc(DUMPBLOCKSIZE);
398
399                 dumpsize = dumpspace;
400                 dumpspace += DUMPBLOCKSIZE;             
401         }
402         
403         m = topdumpblock->dumpmem + DUMPBLOCKSIZE - (dumpspace - dumpsize);
404         dumpsize += length;
405         
406         if (dumpsize > maxdumpsize) {
407                 maxdumpsize = dumpsize;
408         }
409                 
410         return m;
411 }   
412
413
414 void *dump_realloc(void *ptr, int len1, int len2)
415 {
416         void *p2 = dump_alloc(len2);
417         memcpy(p2, ptr, len1);  
418         return p2;
419 }
420
421
422 long int dump_size()
423 {
424         return dumpsize;
425 }
426
427
428 void dump_release(long int size)
429 {
430         assert(size >= 0 && size <= dumpsize);
431
432         dumpsize = size;
433         
434         while (dumpspace > dumpsize + DUMPBLOCKSIZE) {
435                 dumplist *oldtop = topdumpblock;
436                 
437                 topdumpblock = oldtop->prev;
438                 dumpspace -= DUMPBLOCKSIZE;
439                 
440 #ifdef TRACECALLARGS
441 #else
442                 free(oldtop->dumpmem);
443                 free(oldtop);
444 #endif
445         }               
446 }
447
448
449 void mem_usagelog (int givewarnings)
450 {
451         if ((memoryusage!=0) && givewarnings) {
452                 dolog ("Allocated memory not returned: %d",
453                                  (int)memoryusage);
454
455 #ifdef DEBUG
456                 { 
457                         memblock *mb = firstmemblock;
458                         while (mb) {
459                                 dolog ("   Memory block size: %d", 
460                                                  (int)(mb->length) );
461                                 mem_characterlog ( ((unsigned char*)mb) + BLOCKOFFSET, mb->length);
462                                 mb = mb->next;
463                         }
464                 }
465 #endif
466                         
467         }
468
469         if ((dumpsize!=0) && givewarnings) {
470                 dolog ("Dump memory not returned: %d",(int)dumpsize);
471         }
472
473
474         dolog("Random/Dump - memory usage: %dK/%dK", 
475                         (int)((maxmemusage+1023)/1024), 
476                         (int)((maxdumpsize+1023)/1024) );
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  */