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