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