* Use DUMPINFO macro to get non-/threaded dumpinfo.
[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 3205 2005-09-19 09:02:55Z 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 "config.h"
48 #include "arch.h"
49
50 #if USE_CODEMMAP
51 # include <sys/mman.h>
52 # include <unistd.h>
53 #endif
54
55 #include "mm/memory.h"
56 #include "native/native.h"
57
58 #if defined(USE_THREADS)
59 # if defined(NATIVE_THREADS)
60 #  include "threads/native/threads.h"
61 # else
62 #  include "threads/green/threads.h"
63 # endif
64 #endif
65
66 #include "toolbox/logging.h"
67 #include "vm/exceptions.h"
68 #include "vm/global.h"
69 #include "vm/options.h"
70 #include "vm/statistics.h"
71 #include "vm/stringlocal.h"
72
73
74 /********* general types, variables and auxiliary functions *********/
75
76 #if USE_CODEMMAP
77 static int mmapcodesize = 0;
78 static void *mmapcodeptr = NULL;
79 #endif
80
81
82 /*******************************************************************************
83
84     This structure is used for dump memory allocation if cacao runs
85     without threads.
86
87 *******************************************************************************/
88
89 #if !defined(USE_THREADS) || (defined(USE_THREADS) && !defined(NATIVE_THREADS))
90 static dumpinfo _no_threads_dumpinfo;
91 #endif
92
93 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
94 #define DUMPINFO    &((threadobject *) THREADOBJECT)->dumpinfo
95 #else
96 #define DUMPINFO    &_no_threads_dumpinfo
97 #endif
98
99
100 #if USE_CODEMMAP
101 void *mem_mmap(s4 size)
102 {
103         void *m;
104
105         size = ALIGN(size, ALIGNSIZE);
106
107         if (size > mmapcodesize) {
108                 mmapcodesize = 0x10000;
109
110                 if (size > mmapcodesize)
111                         mmapcodesize = size;
112
113                 mmapcodesize = ALIGN(mmapcodesize, getpagesize());
114                 mmapcodeptr = mmap(NULL,
115                                                    (size_t) mmapcodesize,
116                                                    PROT_READ | PROT_WRITE | PROT_EXEC,
117                                                    MAP_PRIVATE |
118 #if defined(HAVE_MAP_ANONYMOUS)
119                                                    MAP_ANONYMOUS,
120 #elif defined(HAVE_MAP_ANON)
121                                                    MAP_ANON,
122 #else
123                                                    0,
124 #endif
125                                                    -1,
126                                                    (off_t) 0);
127
128                 if (mmapcodeptr == MAP_FAILED)
129                         throw_cacao_exception_exit(string_java_lang_InternalError,
130                                                                            "Out of memory");
131         }
132
133         m = mmapcodeptr;
134         mmapcodeptr = (void *) ((char *) mmapcodeptr + size);
135         mmapcodesize -= size;
136
137         return m;
138 }
139 #endif
140
141
142 static void *checked_alloc(s4 size)
143 {
144         /* always allocate memory zeroed out */
145         void *m = calloc(size, 1);
146
147         if (!m)
148                 throw_cacao_exception_exit(string_java_lang_InternalError,
149                                                                    "Out of memory");
150
151         return m;
152 }
153
154
155 void *mem_alloc(s4 size)
156 {
157         if (size == 0)
158                 return NULL;
159
160 #if defined(STATISTICS)
161         if (opt_stat) {
162                 memoryusage += size;
163
164                 if (memoryusage > maxmemusage)
165                         maxmemusage = memoryusage;
166         }
167 #endif
168
169         return checked_alloc(size);
170 }
171
172
173 void *mem_realloc(void *src, s4 len1, s4 len2)
174 {
175         void *dst;
176
177         if (!src) {
178                 if (len1 != 0) {
179                         log_text("reallocating memoryblock with address NULL, length != 0");
180                         assert(0);
181                 }
182         }
183
184 #if defined(STATISTICS)
185         if (opt_stat)
186                 memoryusage = (memoryusage - len1) + len2;
187 #endif
188
189         dst = realloc(src, len2);
190
191         if (!dst)
192                 throw_cacao_exception_exit(string_java_lang_InternalError,
193                                                                    "Out of memory");
194
195         return dst;
196 }
197
198
199 void mem_free(void *m, s4 size)
200 {
201         if (!m) {
202                 if (size == 0)
203                         return;
204
205                 log_text("returned memoryblock with address NULL, length != 0");
206                 assert(0);
207         }
208
209 #if defined(STATISTICS)
210         if (opt_stat)
211                 memoryusage -= size;
212 #endif
213
214         free(m);
215 }
216
217
218 /* dump_alloc ******************************************************************
219
220    XXX
221
222 *******************************************************************************/
223
224 void *dump_alloc(s4 size)
225 {
226 #if defined(DISABLE_DUMP)
227         /* use malloc memory for dump memory (for debugging only!) */
228
229         return mem_alloc(size);
230 #else
231         void     *m;
232         dumpinfo *di;
233
234         /* If no threads are used, the dumpinfo structure is a static structure   */
235         /* defined at the top of this file.                                       */
236
237         di = DUMPINFO;
238
239         if (size == 0)
240                 return NULL;
241
242         size = ALIGN(size, ALIGNSIZE);
243
244         if (di->useddumpsize + size > di->allocateddumpsize) {
245                 dumpblock *newdumpblock;
246                 s4         newdumpblocksize;
247
248                 /* allocate a new dumplist structure */
249
250                 newdumpblock = checked_alloc(sizeof(dumpblock));
251
252                 /* If requested size is greater than the default, make the new dump   */
253                 /* block as big as the size requested. Else use the default size.     */
254
255                 if (size > DUMPBLOCKSIZE) {
256                         newdumpblocksize = size;
257
258                 } else {
259                         newdumpblocksize = DUMPBLOCKSIZE;
260                 }
261
262                 /* allocate dumpblock memory */
263
264                 newdumpblock->dumpmem = checked_alloc(newdumpblocksize);
265
266                 newdumpblock->prev = di->currentdumpblock;
267                 newdumpblock->size = newdumpblocksize;
268                 di->currentdumpblock = newdumpblock;
269
270                 /* Used dump size is previously allocated dump size, because the      */
271                 /* remaining free memory of the previous dump block cannot be used.   */
272
273                 di->useddumpsize = di->allocateddumpsize;
274
275                 /* increase the allocated dump size by the size of the new dump block */
276
277                 di->allocateddumpsize += newdumpblocksize;
278
279 #if defined(STATISTICS)
280                 /* the amount of globally allocated dump memory (thread save) */
281
282                 if (opt_stat)
283                         globalallocateddumpsize += newdumpblocksize;
284 #endif
285         }
286
287         /* current dump block base address + the size of the current dump block - */
288         /* the size of the unused memory = new start address                      */
289
290         m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
291                 (di->allocateddumpsize - di->useddumpsize);
292
293         /* increase used dump size by the allocated memory size */
294
295         di->useddumpsize += size;
296
297 #if defined(STATISTICS)
298         if (opt_stat)
299                 if (di->useddumpsize > maxdumpsize)
300                         maxdumpsize = di->useddumpsize;
301 #endif
302                 
303         return m;
304 #endif /* defined(DISABLE_DUMP) */
305 }
306
307
308 /* dump_realloc ****************************************************************
309
310    XXX
311
312 *******************************************************************************/
313
314 void *dump_realloc(void *src, s4 len1, s4 len2)
315 {
316 #if defined(DISABLE_DUMP)
317         /* use malloc memory for dump memory (for debugging only!) */
318
319         return mem_realloc(src, len1, len2);
320 #else
321         void *dst = dump_alloc(len2);
322
323         memcpy(dst, src, len1);
324
325         return dst;
326 #endif
327 }
328
329
330 /* dump_release ****************************************************************
331
332    XXX
333
334 *******************************************************************************/
335
336 void dump_release(s4 size)
337 {
338 #if defined(DISABLE_DUMP)
339         /* use malloc memory for dump memory (for debugging only!) */
340
341         /* do nothing */
342 #else
343         dumpinfo *di;
344
345         /* If no threads are used, the dumpinfo structure is a static structure   */
346         /* defined at the top of this file.                                       */
347
348         di = DUMPINFO;
349
350         if (size < 0 || size > di->useddumpsize)
351                 throw_cacao_exception_exit(string_java_lang_InternalError,
352                                                                    "Illegal dump release size %d", size);
353
354         /* reset the used dump size to the size specified */
355
356         di->useddumpsize = size;
357
358         while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
359                 dumpblock *tmp = di->currentdumpblock;
360
361 #if 0
362                 /* XXX TWISTI: can someone explain this to me? */
363 #ifdef TRACECALLARGS
364                 /* Keep the first dumpblock if we don't free memory. Otherwise
365                  * a new dumpblock is allocated each time and we run out of
366                  * memory.
367                  */
368                 if (!oldtop->prev) break;
369 #endif
370 #endif
371
372                 di->allocateddumpsize -= tmp->size;
373                 di->currentdumpblock = tmp->prev;
374
375 #if defined(STATISTICS)
376                 /* the amount of globally allocated dump memory (thread save) */
377
378                 if (opt_stat)
379                         globalallocateddumpsize -= tmp->size;
380 #endif
381
382                 /* release the dump memory and the dumpinfo structure */
383
384                 free(tmp->dumpmem);
385                 free(tmp);
386         }
387 #endif /* defined(DISABLE_DUMP) */
388 }
389
390
391 /* dump_size *******************************************************************
392
393    XXX
394
395 *******************************************************************************/
396
397 s4 dump_size(void)
398 {
399 #if defined(DISABLE_DUMP)
400         /* use malloc memory for dump memory (for debugging only!) */
401
402         return 0;
403 #else
404         dumpinfo *di;
405
406         /* If no threads are used, the dumpinfo structure is a static structure   */
407         /* defined at the top of this file.                                       */
408
409         di = DUMPINFO;
410
411         if (!di)
412                 return 0;
413
414         return di->useddumpsize;
415 #endif /* defined(DISABLE_DUMP) */
416 }
417
418
419 /*
420  * These are local overrides for various environment variables in Emacs.
421  * Please do not remove this and leave it at the end of the file, where
422  * Emacs will automagically detect them.
423  * ---------------------------------------------------------------------
424  * Local variables:
425  * mode: c
426  * indent-tabs-mode: t
427  * c-basic-offset: 4
428  * tab-width: 4
429  * End:
430  */