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