Previous log message was mistaken
[cacao.git] / src / mm / memory.c
1 /************************* toolbox/memory.c ************************************
2
3         Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst
4
5         See file COPYRIGHT for information on usage and disclaimer of warranties
6
7         Not documented, see memory.h.
8
9         Authors: Reinhard Grafl      EMAIL: cacao@complang.tuwien.ac.at
10
11         Last Change: 1996/10/03
12
13 *******************************************************************************/
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <assert.h>
18 #include <string.h>
19 #include <sys/mman.h>
20 #include <unistd.h>
21
22 #include "global.h"
23 #include "callargs.h"
24 #include "loging.h"
25 #include "memory.h"
26
27
28         /********* general types, variables and auxiliary functions *********/
29
30 #define DUMPBLOCKSIZE  (2<<21)
31 #define ALIGNSIZE           8
32
33 typedef struct dumplist {
34         struct dumplist *prev;
35         char *dumpmem;
36 } dumplist;
37
38
39
40 long int memoryusage = 0;
41
42 long int dumpsize = 0;
43 long int dumpspace = 0;
44 dumplist *topdumpblock = NULL;
45
46 long int maxmemusage = 0;
47 long int maxdumpsize = 0;
48
49 /* #define TRACECALLARGS */
50
51 #ifdef TRACECALLARGS
52 static char *nomallocmem = NULL;
53 static char *nomalloctop;
54 static char *nomallocptr;
55
56 static void *lit_checked_alloc (int length)
57 {
58         void *m;
59
60         if (!nomallocmem) {
61                 nomallocmem = malloc(16777216);
62                 nomalloctop = nomallocmem + 16777216;
63                 nomallocptr = nomallocmem;
64         }
65
66         nomallocptr = (void*) ALIGN ((long) nomallocptr, ALIGNSIZE);
67         
68         m = nomallocptr;
69         nomallocptr += length;
70         if (nomallocptr > nomalloctop) panic ("Out of memory");
71         return m;
72 }
73
74 #else
75
76 static void *lit_checked_alloc (int length)
77 {
78         void *m = malloc(length);
79         if (!m) panic ("Out of memory");
80         return m;
81 }
82
83 #endif
84
85
86 static void *checked_alloc (int length)
87 {
88         void *m = malloc(length);
89         if (!m) panic ("Out of memory");
90         return m;
91 }
92
93 static int mmapcodesize = 0;
94 static void *mmapcodeptr = NULL;
95
96 void *mem_mmap(int length)
97 {
98         void *retptr;
99
100         length = (ALIGN(length,ALIGNSIZE));
101         if (length > mmapcodesize) {
102                 mmapcodesize = 0x10000;
103                 if (length > mmapcodesize)
104                         mmapcodesize = length;
105                 mmapcodesize = (ALIGN(mmapcodesize, getpagesize()));
106                 mmapcodeptr = mmap (NULL, (size_t) mmapcodesize,
107                               PROT_READ | PROT_WRITE | PROT_EXEC,
108                               MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t) 0);
109                 if (mmapcodeptr == (void*) -1)
110                         panic ("Out of memory");
111                 }
112         retptr = mmapcodeptr;
113         mmapcodeptr = (void*) ((char*) mmapcodeptr + length);
114         mmapcodesize -= length;
115         return retptr;
116 }
117
118
119 #ifdef DEBUG
120
121         /************ Memory manager, safe version **************/
122
123
124 typedef struct memblock {
125         struct memblock *prev,*next;
126         int length;
127 } memblock;
128
129 #define BLOCKOFFSET    (ALIGN(sizeof(memblock),ALIGNSIZE))
130
131 struct memblock *firstmemblock;
132
133
134
135 void *mem_alloc(int length)
136 {
137         memblock *mb;
138
139         if (length==0) return NULL;
140         mb = checked_alloc (length + BLOCKOFFSET);
141
142         mb -> prev = NULL;
143         mb -> next = firstmemblock;     
144         mb -> length = length;
145
146         if (firstmemblock) firstmemblock -> prev = mb;
147         firstmemblock = mb;
148
149         memoryusage += length;
150         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
151
152         return ((char*) mb) + BLOCKOFFSET;
153 }
154
155
156 void *lit_mem_alloc(int length)
157 {
158         memblock *mb;
159
160         if (length==0) return NULL;
161         mb = lit_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 mem_free(void *m, int length)
178 {
179         memblock *mb;
180         if (!m) {
181                 if (length==0) return;
182                 panic ("returned memoryblock with address NULL, length != 0");
183                 }
184
185         mb = (memblock*) (((char*) m) - BLOCKOFFSET);
186         
187         if (mb->length != length) {
188                 sprintf (logtext, 
189                         "Memory block of size %d has been return as size %d",
190                          mb->length, length);
191                 error();
192                 }
193                 
194         if (mb->prev) mb->prev->next = mb->next;
195                  else firstmemblock = mb->next;
196         if (mb->next) mb->next->prev = mb->prev;
197
198         free (mb);
199
200         memoryusage -= length;
201 }
202
203
204 void lit_mem_free(void *m, int length)
205 {
206         memblock *mb;
207         if (!m) {
208                 if (length==0) return;
209                 panic ("returned memoryblock with address NULL, length != 0");
210                 }
211
212         mb = (memblock*) (((char*) m) - BLOCKOFFSET);
213         
214         if (mb->length != length) {
215                 sprintf (logtext, 
216                         "Memory block of size %d has been return as size %d",
217                          mb->length, length);
218                 error();
219                 }
220                 
221         if (mb->prev) mb->prev->next = mb->next;
222                  else firstmemblock = mb->next;
223         if (mb->next) mb->next->prev = mb->prev;
224
225 #ifdef TRACECALLARGS
226 #else
227         free (mb);
228 #endif
229
230         memoryusage -= length;
231 }
232
233
234 void *mem_realloc (void *m1, int len1, int len2)
235 {
236         void *m2;
237         
238         m2 = mem_alloc (len2);
239         memcpy (m2, m1, len1);
240         mem_free (m1, len1);
241
242         return m2;
243 }
244
245
246
247
248 static void mem_characterlog (unsigned char *m, int len)
249 {
250 #       define LINESIZE 16
251         int z,i;
252         
253         for (z=0; z<len; z+=LINESIZE) {
254                 sprintf (logtext, "   ");
255                         
256                 for (i=z; i<(z+LINESIZE) && i<len; i++) {
257                         sprintf (logtext+strlen(logtext), "%2x ", m[i]);
258                         }
259                 for (; i<(z+LINESIZE); i++) {
260                         sprintf (logtext+strlen(logtext), "   ");
261                         }
262                                         
263                 sprintf (logtext+strlen(logtext),"   ");
264                 for (i=z; i<(z+LINESIZE) && i<len; i++) {
265                         sprintf (logtext+strlen(logtext),
266                              "%c", (m[i]>=' ' && m[i]<=127) ? m[i] : '.');
267                         }
268                         
269                 dolog();
270                 }
271 }
272
273 #else
274                 /******* Memory manager, fast version ******/
275
276
277 void *mem_alloc(int length)
278 {
279         if (length==0) return NULL;
280
281         memoryusage += length;
282         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
283         
284         return checked_alloc (length);
285 }
286
287
288 void *lit_mem_alloc(int length)
289 {
290         if (length==0) return NULL;
291
292         memoryusage += length;
293         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
294         
295         return lit_checked_alloc (length);
296 }
297
298
299 void mem_free(void *m, int length)
300 {
301         if (!m) {
302                 if (length==0) return;
303                 panic ("returned memoryblock with address NULL, length != 0");
304                 }
305
306         memoryusage -= length;
307
308         free (m);
309 }
310
311
312 void lit_mem_free(void *m, int length)
313 {
314         if (!m) {
315                 if (length==0) return;
316                 panic ("returned memoryblock with address NULL, length != 0");
317                 }
318
319         memoryusage -= length;
320
321 #ifdef TRACECALLARGS
322 #else
323         free (m);
324 #endif
325 }
326
327
328 void *mem_realloc (void *m1, int len1, int len2)
329 {
330         void *m2;
331
332         if (!m1) {
333                 if (len1!=0) 
334                   panic ("reallocating memoryblock with address NULL, length != 0");
335                 }
336                 
337         memoryusage = (memoryusage - len1) + len2;
338
339         m2 = realloc (m1, len2);
340         if (!m2) panic ("Out of memory");
341         return m2;
342 }
343
344
345 #endif
346
347                 /******* common memory manager parts ******/
348
349
350
351 long int mem_usage()
352 {
353         return memoryusage;
354 }
355
356
357
358
359
360 void *dump_alloc(int length)
361 {
362         void *m;
363
364         if (length==0) return NULL;
365         
366         length = ALIGN (length, ALIGNSIZE);
367
368         assert (length <= DUMPBLOCKSIZE);
369         assert (length > 0);
370
371         if (dumpsize + length > dumpspace) {
372                 dumplist *newdumpblock = checked_alloc (sizeof(dumplist));
373
374                 newdumpblock -> prev = topdumpblock;
375                 topdumpblock = newdumpblock;
376
377                 newdumpblock -> dumpmem = checked_alloc (DUMPBLOCKSIZE);
378
379                 dumpsize = dumpspace;
380                 dumpspace += DUMPBLOCKSIZE;             
381                 }
382         
383         m = topdumpblock -> dumpmem + DUMPBLOCKSIZE - (dumpspace - dumpsize);
384         dumpsize += length;
385         
386         if (dumpsize > maxdumpsize) {
387                 maxdumpsize = dumpsize;
388                 }
389                 
390         return m;
391 }   
392
393
394 void *dump_realloc(void *ptr, int len1, int len2)
395 {
396         void *p2 = dump_alloc (len2);
397         memcpy (p2, ptr, len1); 
398         return p2;
399 }
400
401
402 long int dump_size()
403 {
404         return dumpsize;
405 }
406
407
408 void dump_release(long int size)
409 {
410         assert (size >= 0 && size <= dumpsize);
411
412         dumpsize = size;
413         
414         while (dumpspace  >  dumpsize + DUMPBLOCKSIZE) {
415                 dumplist *oldtop = topdumpblock;
416                 
417                 topdumpblock = oldtop -> prev;
418                 dumpspace -= DUMPBLOCKSIZE;
419                 
420 #ifdef TRACECALLARGS
421 #else
422                 free (oldtop -> dumpmem);
423                 free (oldtop);
424 #endif
425                 }               
426 }
427
428
429
430
431 void mem_usagelog (int givewarnings)
432 {
433         if ((memoryusage!=0) && givewarnings) {
434                 sprintf (logtext, "Allocated memory not returned: %d",
435                       (int)memoryusage);
436                 dolog();
437
438 #ifdef DEBUG
439                 { 
440                 memblock *mb = firstmemblock;
441                 while (mb) {
442                         sprintf (logtext, "   Memory block size: %d", 
443                           (int)(mb->length) );
444                         dolog();
445                         mem_characterlog ( ((unsigned char*)mb) + BLOCKOFFSET, mb->length);
446                         mb = mb->next;
447                         }
448                 }
449 #endif
450                         
451                 }
452
453         if ((dumpsize!=0) && givewarnings) {
454                 sprintf (logtext, "Dump memory not returned: %d",(int)dumpsize);
455                 dolog();
456                 }
457
458
459         sprintf (logtext, "Random/Dump - memory usage: %dK/%dK", 
460               (int)((maxmemusage+1023)/1024), 
461               (int)((maxdumpsize+1023)/1024) );
462         dolog();
463         
464 }
465