Code 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 575 2003-11-09 17:26:53Z 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)
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         
277         for (z = 0; z < len; z += LINESIZE) {
278                 sprintf(logtext, "   ");
279                         
280                 for (i = z; i < (z + LINESIZE) && i < len; i++) {
281                         sprintf(logtext + strlen(logtext), "%2x ", m[i]);
282                 }
283                 for (; i < (z + LINESIZE); i++) {
284                         sprintf(logtext + strlen(logtext), "   ");
285                 }
286                                         
287                 sprintf(logtext + strlen(logtext),"   ");
288                 for (i = z; i < (z + LINESIZE) && i < len; i++) {
289                         sprintf(logtext+strlen(logtext),
290                                         "%c", (m[i] >= ' ' && m[i] <= 127) ? m[i] : '.');
291                 }
292                         
293                 dolog();
294         }
295 }
296
297 #else
298 /******* Memory manager, fast version ******/
299
300
301 void *mem_alloc(int length)
302 {
303         if (length == 0) return NULL;
304
305         memoryusage += length;
306         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
307         
308         return checked_alloc(length);
309 }
310
311
312 void *lit_mem_alloc(int length)
313 {
314         if (length == 0) return NULL;
315
316         memoryusage += length;
317         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
318         
319         return lit_checked_alloc(length);
320 }
321
322
323 void mem_free(void *m, int length)
324 {
325         if (!m) {
326                 if (length == 0) return;
327                 panic("returned memoryblock with address NULL, length != 0");
328         }
329
330         memoryusage -= length;
331
332         free(m);
333 }
334
335
336 void lit_mem_free(void *m, int length)
337 {
338         if (!m) {
339                 if (length == 0) return;
340                 panic("returned memoryblock with address NULL, length != 0");
341         }
342
343         memoryusage -= length;
344
345 #ifdef TRACECALLARGS
346 #else
347         free(m);
348 #endif
349 }
350
351
352 void *mem_realloc (void *m1, int len1, int len2)
353 {
354         void *m2;
355
356         if (!m1) {
357                 if (len1!=0) 
358                         panic ("reallocating memoryblock with address NULL, length != 0");
359         }
360                 
361         memoryusage = (memoryusage - len1) + len2;
362
363         m2 = realloc (m1, len2);
364         if (!m2) panic ("Out of memory");
365         return m2;
366 }
367
368
369 #endif
370
371 /******* common memory manager parts ******/
372
373 long int mem_usage()
374 {
375         return memoryusage;
376 }
377
378
379 void *dump_alloc(int length)
380 {
381         void *m;
382
383         if (length == 0) return NULL;
384         
385         length = ALIGN(length, ALIGNSIZE);
386
387         assert(length <= DUMPBLOCKSIZE);
388         assert(length > 0);
389
390         if (dumpsize + length > dumpspace) {
391                 dumplist *newdumpblock = checked_alloc(sizeof(dumplist));
392
393                 newdumpblock->prev = topdumpblock;
394                 topdumpblock = newdumpblock;
395
396                 newdumpblock->dumpmem = checked_alloc(DUMPBLOCKSIZE);
397
398                 dumpsize = dumpspace;
399                 dumpspace += DUMPBLOCKSIZE;             
400         }
401         
402         m = topdumpblock->dumpmem + DUMPBLOCKSIZE - (dumpspace - dumpsize);
403         dumpsize += length;
404         
405         if (dumpsize > maxdumpsize) {
406                 maxdumpsize = dumpsize;
407         }
408                 
409         return m;
410 }   
411
412
413 void *dump_realloc(void *ptr, int len1, int len2)
414 {
415         void *p2 = dump_alloc(len2);
416         memcpy(p2, ptr, len1);  
417         return p2;
418 }
419
420
421 long int dump_size()
422 {
423         return dumpsize;
424 }
425
426
427 void dump_release(long int size)
428 {
429         assert(size >= 0 && size <= dumpsize);
430
431         dumpsize = size;
432         
433         while (dumpspace > dumpsize + DUMPBLOCKSIZE) {
434                 dumplist *oldtop = topdumpblock;
435                 
436                 topdumpblock = oldtop->prev;
437                 dumpspace -= DUMPBLOCKSIZE;
438                 
439 #ifdef TRACECALLARGS
440 #else
441                 free(oldtop->dumpmem);
442                 free(oldtop);
443 #endif
444         }               
445 }
446
447
448 void mem_usagelog (int givewarnings)
449 {
450         if ((memoryusage!=0) && givewarnings) {
451                 sprintf (logtext, "Allocated memory not returned: %d",
452                                  (int)memoryusage);
453                 dolog();
454
455 #ifdef DEBUG
456                 { 
457                         memblock *mb = firstmemblock;
458                         while (mb) {
459                                 sprintf (logtext, "   Memory block size: %d", 
460                                                  (int)(mb->length) );
461                                 dolog();
462                                 mem_characterlog ( ((unsigned char*)mb) + BLOCKOFFSET, mb->length);
463                                 mb = mb->next;
464                         }
465                 }
466 #endif
467                         
468         }
469
470         if ((dumpsize!=0) && givewarnings) {
471                 sprintf (logtext, "Dump memory not returned: %d",(int)dumpsize);
472                 dolog();
473         }
474
475
476         sprintf(logtext, "Random/Dump - memory usage: %dK/%dK", 
477                         (int)((maxmemusage+1023)/1024), 
478                         (int)((maxdumpsize+1023)/1024) );
479         dolog();
480         
481 }
482
483
484 /*
485  * These are local overrides for various environment variables in Emacs.
486  * Please do not remove this and leave it at the end of the file, where
487  * Emacs will automagically detect them.
488  * ---------------------------------------------------------------------
489  * Local variables:
490  * mode: c
491  * indent-tabs-mode: t
492  * c-basic-offset: 4
493  * tab-width: 4
494  * End:
495  */