#ifdef's for MAP_ANONYMOUS, MAP_ANON and of none is available.
[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 1489 2004-11-12 11:31:47Z 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 "exceptions.h"
42 #include "global.h"
43 #include "native.h"
44 #include "options.h"
45 #include "statistics.h"
46 #include "threads/nativethread.h"
47 #include "toolbox/logging.h"
48 #include "toolbox/memory.h"
49
50
51 /********* general types, variables and auxiliary functions *********/
52
53 static int mmapcodesize = 0;
54 static void *mmapcodeptr = NULL;
55
56
57 /*******************************************************************************
58
59     This structure is used for dump memory allocation if cacao runs without
60     threads.
61
62 *******************************************************************************/
63
64 #if !defined(USE_THREADS)
65 static dumpinfo nothreads_dumpinfo;
66 #endif
67
68
69 void *mem_mmap(int size)
70 {
71         void *m;
72
73         size = ALIGN(size, ALIGNSIZE);
74
75         if (size > mmapcodesize) {
76                 mmapcodesize = 0x10000;
77
78                 if (size > mmapcodesize)
79                         mmapcodesize = size;
80
81                 mmapcodesize = ALIGN(mmapcodesize, getpagesize());
82                 mmapcodeptr = mmap(NULL,
83                                                    (size_t) mmapcodesize,
84                                                    PROT_READ | PROT_WRITE | PROT_EXEC,
85                                                    MAP_PRIVATE |
86 #if defined(HAVE_MAP_ANONYMOUS)
87                                                    MAP_ANONYMOUS,
88 #elif defined(HAVE_MAP_ANON)
89                                                    MAP_ANON,
90 #else
91                                                    0,
92 #endif
93                                                    -1,
94                                                    (off_t) 0);
95
96                 if (mmapcodeptr == MAP_FAILED)
97                         throw_cacao_exception_exit(string_java_lang_InternalError,
98                                                                            "Out of memory");
99         }
100
101         m = mmapcodeptr;
102         mmapcodeptr = (void *) ((char *) mmapcodeptr + size);
103         mmapcodesize -= size;
104
105         return m;
106 }
107
108
109 static void *checked_alloc(int size)
110 {
111         /* always allocate memory zeroed out */
112         void *m = calloc(size, 1);
113
114         if (!m)
115                 throw_cacao_exception_exit(string_java_lang_InternalError,
116                                                                    "Out of memory");
117
118         return m;
119 }
120
121
122 void *mem_alloc(int size)
123 {
124         if (size == 0)
125                 return NULL;
126
127         if (opt_stat) {
128                 memoryusage += size;
129
130                 if (memoryusage > maxmemusage)
131                         maxmemusage = memoryusage;
132         }
133         
134         return checked_alloc(size);
135 }
136
137
138 void *mem_realloc(void *src, int len1, int len2)
139 {
140         void *dst;
141
142         if (!src) {
143                 if (len1 != 0)
144                         panic("reallocating memoryblock with address NULL, length != 0");
145         }
146
147         if (opt_stat)
148                 memoryusage = (memoryusage - len1) + len2;
149
150         dst = realloc(src, len2);
151
152         if (!dst)
153                 throw_cacao_exception_exit(string_java_lang_InternalError,
154                                                                    "Out of memory");
155
156         return dst;
157 }
158
159
160 void mem_free(void *m, int size)
161 {
162         if (!m) {
163                 if (size == 0)
164                         return;
165                 panic("returned memoryblock with address NULL, length != 0");
166         }
167
168         if (opt_stat)
169                 memoryusage -= size;
170
171         free(m);
172 }
173
174
175 void *dump_alloc(int size)
176 {
177         void *m;
178         dumpinfo *di;
179
180         /* If no threads are used, the dumpinfo structure is a static structure   */
181         /* defined at the top of this file.                                       */
182 #if defined(USE_THREADS)
183         di = &((threadobject *) THREADOBJECT)->dumpinfo;
184 #else
185         di = &nothreads_dumpinfo;
186 #endif
187
188         if (size == 0)
189                 return NULL;
190
191         size = ALIGN(size, ALIGNSIZE);
192
193         if (di->useddumpsize + size > di->allocateddumpsize) {
194                 dumpblock *newdumpblock;
195                 s4 newdumpblocksize;
196
197                 /* allocate a new dumplist structure */
198                 newdumpblock = checked_alloc(sizeof(dumpblock));
199
200                 /* If requested size is greater than the default, make the new dump   */
201                 /* block as big as the size requested. Else use the default size.     */
202                 if (size > DUMPBLOCKSIZE) {
203                         newdumpblocksize = size;
204
205                 } else {
206                         newdumpblocksize = DUMPBLOCKSIZE;
207                 }
208
209                 /* allocate dumpblock memory */
210                 //printf("new dumpblock: %d\n", newdumpblocksize);
211                 newdumpblock->dumpmem = checked_alloc(newdumpblocksize);
212
213                 newdumpblock->prev = di->currentdumpblock;
214                 newdumpblock->size = newdumpblocksize;
215                 di->currentdumpblock = newdumpblock;
216
217                 /* Used dump size is previously allocated dump size, because the      */
218                 /* remaining free memory of the previous dump block cannot be used.   */
219                 //printf("unused memory: %d\n", allocateddumpsize - useddumpsize);
220                 di->useddumpsize = di->allocateddumpsize;
221
222                 /* increase the allocated dump size by the size of the new dump block */
223                 di->allocateddumpsize += newdumpblocksize;
224
225                 /* the amount of globally allocated dump memory (thread save)         */
226                 if (opt_stat)
227                         globalallocateddumpsize += newdumpblocksize;
228         }
229
230         /* current dump block base address + the size of the current dump block - */
231         /* the size of the unused memory = new start address                      */
232         m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
233                 (di->allocateddumpsize - di->useddumpsize);
234
235         /* increase used dump size by the allocated memory size                   */
236         di->useddumpsize += size;
237
238         if (opt_stat) {
239                 if (di->useddumpsize > maxdumpsize) {
240                         maxdumpsize = di->useddumpsize;
241                 }
242         }
243                 
244         return m;
245 }   
246
247
248 void *dump_realloc(void *src, int len1, int len2)
249 {
250         void *dst = dump_alloc(len2);
251
252         memcpy(dst, src, len1);
253
254         return dst;
255 }
256
257
258 void dump_release(int size)
259 {
260         dumpinfo *di;
261
262         /* If no threads are used, the dumpinfo structure is a static structure   */
263         /* defined at the top of this file.                                       */
264 #if defined(USE_THREADS)
265         di = &((threadobject *) THREADOBJECT)->dumpinfo;
266 #else
267         di = &nothreads_dumpinfo;
268 #endif
269
270         if (size < 0 || size > di->useddumpsize)
271                 throw_cacao_exception_exit(string_java_lang_InternalError,
272                                                                    "Illegal dump release size %d", size);
273
274         /* reset the used dump size to the size specified                         */
275         di->useddumpsize = size;
276
277         while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
278                 dumpblock *tmp = di->currentdumpblock;
279
280 #if 0
281                 /* XXX TWISTI: can someone explain this to me? */
282 #ifdef TRACECALLARGS
283                 /* Keep the first dumpblock if we don't free memory. Otherwise
284                  * a new dumpblock is allocated each time and we run out of
285                  * memory.
286                  */
287                 if (!oldtop->prev) break;
288 #endif
289 #endif
290
291                 di->allocateddumpsize -= tmp->size;
292                 di->currentdumpblock = tmp->prev;
293
294                 /* the amount of globally allocated dump memory (thread save)         */
295                 if (opt_stat)
296                         globalallocateddumpsize -= tmp->size;
297
298                 /* release the dump memory and the dumpinfo structure                 */
299                 free(tmp->dumpmem);
300                 free(tmp);
301         }
302 }
303
304
305 long dump_size()
306 {
307         dumpinfo *di;
308
309         /* If no threads are used, the dumpinfo structure is a static structure   */
310         /* defined at the top of this file.                                       */
311 #if defined(USE_THREADS)
312         di = &((threadobject *) THREADOBJECT)->dumpinfo;
313 #else
314         di = &nothreads_dumpinfo;
315 #endif
316
317         return di->useddumpsize;
318 }
319
320
321 /*
322  * These are local overrides for various environment variables in Emacs.
323  * Please do not remove this and leave it at the end of the file, where
324  * Emacs will automagically detect them.
325  * ---------------------------------------------------------------------
326  * Local variables:
327  * mode: c
328  * indent-tabs-mode: t
329  * c-basic-offset: 4
330  * tab-width: 4
331  * End:
332  */