* Updated header: Added 2006. Changed address of FSF. Changed email
[cacao.git] / src / mm / memory.c
1 /* src/mm/memory.c - 
2
3    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, 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., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Reinhard Grafl
28
29    Changes: Christian Thalinger
30
31    $Id: memory.c 4357 2006-01-22 23:33:38Z twisti $
32
33 */
34
35
36 #include <assert.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <sys/mman.h>
43
44 #if defined(__DARWIN__)
45 /* If we compile with -ansi on darwin, <sys/types.h> is not included. So      */
46 /* let's do it here.                                                          */
47 # include <sys/types.h>
48 #endif
49
50 #include "config.h"
51 #include "vm/types.h"
52
53 #include "arch.h"
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 /*******************************************************************************
75
76   This structure is used for dump memory allocation if cacao
77   runswithout threads.
78
79 *******************************************************************************/
80
81 #if !defined(USE_THREADS) || (defined(USE_THREADS) && !defined(NATIVE_THREADS))
82 static dumpinfo _no_threads_dumpinfo;
83 #endif
84
85 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
86 #define DUMPINFO    &((threadobject *) THREADOBJECT)->dumpinfo
87 #else
88 #define DUMPINFO    &_no_threads_dumpinfo
89 #endif
90
91
92 /* global code memory variables ***********************************************/
93
94 #define DEFAULT_CODEMEM_SIZE    128 * 1024  /* defaulting to 128kB            */
95
96 #if defined(USE_THREADS)
97 static java_objectheader *codememlock = NULL;
98 #endif
99 static int                codememsize = 0;
100 static void              *codememptr  = NULL;
101
102
103 /* memory_init *****************************************************************
104
105    Initialize the memory subsystem.
106
107 *******************************************************************************/
108
109 bool memory_init(void)
110 {
111 #if defined(USE_THREADS)
112         codememlock = NEW(java_objectheader);
113
114 # if defined(NATIVE_THREADS)
115         initObjectLock(codememlock);
116 # endif
117 #endif
118
119         /* everything's ok */
120
121         return true;
122 }
123
124
125 /* memory_checked_alloc ********************************************************
126
127    Allocated zeroed-out memory and does an OOM check.
128
129 *******************************************************************************/
130
131 static void *memory_checked_alloc(s4 size)
132 {
133         /* always allocate memory zeroed out */
134
135         void *p = calloc(size, 1);
136
137         if (!p)
138                 exceptions_throw_outofmemory_exit();
139
140         return p;
141 }
142
143
144 /* memory_cnew *****************************************************************
145
146    Allocates memory from the heap, aligns it to architecutres PAGESIZE
147    and make the memory read-, write-, and executeable.
148
149 *******************************************************************************/
150
151 void *memory_cnew(s4 size)
152 {
153         void *p;
154         int   pagesize;
155
156 #if defined(USE_THREADS)
157         builtin_monitorenter(codememlock);
158 #endif
159
160         size = ALIGN(size, ALIGNSIZE);
161
162         /* check if enough memory is available */
163
164         if (size > codememsize) {
165                 /* set default code size */
166
167                 codememsize = DEFAULT_CODEMEM_SIZE;
168
169                 /* do we need more? */
170
171                 if (size > codememsize)
172                         codememsize = size;
173
174                 /* get the pagesize of this architecture */
175
176                 pagesize = getpagesize();
177
178                 /* allocate normal heap memory */
179
180                 if ((p = memory_checked_alloc(codememsize + pagesize - 1)) == NULL)
181                         return NULL;
182
183 #if defined(ENABLE_STATISTICS)
184                 if (opt_stat) {
185                         codememusage += codememsize + pagesize - 1;
186
187                         if (codememusage > maxcodememusage)
188                                 maxcodememusage = codememusage;
189                 }
190 #endif
191
192                 /* align the memory allocated to a multiple of PAGESIZE,
193                    mprotect requires this */
194
195                 p = (void *) (((ptrint) p + pagesize - 1) & ~(pagesize - 1));
196
197                 /* make the memory read-, write-, and executeable */
198
199                 if (mprotect(p, codememsize, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
200                         throw_cacao_exception_exit(string_java_lang_InternalError,
201                                                                            strerror(errno));
202
203                 /* set global code memory pointer */
204
205                 codememptr = p;
206         }
207
208         /* get a memory chunk of the allocated memory */
209
210         p = codememptr;
211         codememptr = (void *) ((ptrint) codememptr + size);
212         codememsize -= size;
213
214 #if defined(USE_THREADS)
215         builtin_monitorexit(codememlock);
216 #endif
217
218         return p;
219 }
220
221
222 void *mem_alloc(s4 size)
223 {
224         if (size == 0)
225                 return NULL;
226
227 #if defined(ENABLE_STATISTICS)
228         if (opt_stat) {
229                 memoryusage += size;
230
231                 if (memoryusage > maxmemusage)
232                         maxmemusage = memoryusage;
233         }
234 #endif
235
236         return memory_checked_alloc(size);
237 }
238
239
240 void *mem_realloc(void *src, s4 len1, s4 len2)
241 {
242         void *dst;
243
244         if (!src) {
245                 if (len1 != 0) {
246                         log_text("reallocating memoryblock with address NULL, length != 0");
247                         assert(0);
248                 }
249         }
250
251 #if defined(ENABLE_STATISTICS)
252         if (opt_stat)
253                 memoryusage = (memoryusage - len1) + len2;
254 #endif
255
256         dst = realloc(src, len2);
257
258         if (!dst)
259                 exceptions_throw_outofmemory_exit();
260
261         return dst;
262 }
263
264
265 void mem_free(void *m, s4 size)
266 {
267         if (!m) {
268                 if (size == 0)
269                         return;
270
271                 log_text("returned memoryblock with address NULL, length != 0");
272                 assert(0);
273         }
274
275 #if defined(ENABLE_STATISTICS)
276         if (opt_stat)
277                 memoryusage -= size;
278 #endif
279
280         free(m);
281 }
282
283
284 /* dump_alloc ******************************************************************
285
286    XXX
287
288 *******************************************************************************/
289
290 void *dump_alloc(s4 size)
291 {
292 #if defined(DISABLE_DUMP)
293         /* use malloc memory for dump memory (for debugging only!) */
294
295         return mem_alloc(size);
296 #else
297         void     *m;
298         dumpinfo *di;
299
300         /* If no threads are used, the dumpinfo structure is a static structure   */
301         /* defined at the top of this file.                                       */
302
303         di = DUMPINFO;
304
305         if (size == 0)
306                 return NULL;
307
308         size = ALIGN(size, ALIGNSIZE);
309
310         if (di->useddumpsize + size > di->allocateddumpsize) {
311                 dumpblock *newdumpblock;
312                 s4         newdumpblocksize;
313
314                 /* allocate a new dumplist structure */
315
316                 newdumpblock = memory_checked_alloc(sizeof(dumpblock));
317
318                 /* If requested size is greater than the default, make the new dump   */
319                 /* block as big as the size requested. Else use the default size.     */
320
321                 if (size > DUMPBLOCKSIZE) {
322                         newdumpblocksize = size;
323
324                 } else {
325                         newdumpblocksize = DUMPBLOCKSIZE;
326                 }
327
328                 /* allocate dumpblock memory */
329
330                 newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
331
332                 newdumpblock->prev = di->currentdumpblock;
333                 newdumpblock->size = newdumpblocksize;
334                 di->currentdumpblock = newdumpblock;
335
336                 /* Used dump size is previously allocated dump size, because the      */
337                 /* remaining free memory of the previous dump block cannot be used.   */
338
339                 di->useddumpsize = di->allocateddumpsize;
340
341                 /* increase the allocated dump size by the size of the new dump block */
342
343                 di->allocateddumpsize += newdumpblocksize;
344
345 #if defined(ENABLE_STATISTICS)
346                 /* the amount of globally allocated dump memory (thread save) */
347
348                 if (opt_stat)
349                         globalallocateddumpsize += newdumpblocksize;
350 #endif
351         }
352
353         /* current dump block base address + the size of the current dump block - */
354         /* the size of the unused memory = new start address                      */
355
356         m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
357                 (di->allocateddumpsize - di->useddumpsize);
358
359         /* increase used dump size by the allocated memory size */
360
361         di->useddumpsize += size;
362
363 #if defined(ENABLE_STATISTICS)
364         if (opt_stat)
365                 if (di->useddumpsize > maxdumpsize)
366                         maxdumpsize = di->useddumpsize;
367 #endif
368                 
369         return m;
370 #endif /* defined(DISABLE_DUMP) */
371 }
372
373
374 /* dump_realloc ****************************************************************
375
376    XXX
377
378 *******************************************************************************/
379
380 void *dump_realloc(void *src, s4 len1, s4 len2)
381 {
382 #if defined(DISABLE_DUMP)
383         /* use malloc memory for dump memory (for debugging only!) */
384
385         return mem_realloc(src, len1, len2);
386 #else
387         void *dst = dump_alloc(len2);
388
389         memcpy(dst, src, len1);
390
391         return dst;
392 #endif
393 }
394
395
396 /* dump_release ****************************************************************
397
398    XXX
399
400 *******************************************************************************/
401
402 void dump_release(s4 size)
403 {
404 #if defined(DISABLE_DUMP)
405         /* use malloc memory for dump memory (for debugging only!) */
406
407         /* do nothing */
408 #else
409         dumpinfo *di;
410
411         /* If no threads are used, the dumpinfo structure is a static structure   */
412         /* defined at the top of this file.                                       */
413
414         di = DUMPINFO;
415
416         if (size < 0 || size > di->useddumpsize)
417                 throw_cacao_exception_exit(string_java_lang_InternalError,
418                                                                    "Illegal dump release size %d", size);
419
420         /* reset the used dump size to the size specified */
421
422         di->useddumpsize = size;
423
424         while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
425                 dumpblock *tmp = di->currentdumpblock;
426
427 #if 0
428                 /* XXX TWISTI: can someone explain this to me? */
429 #ifdef TRACECALLARGS
430                 /* Keep the first dumpblock if we don't free memory. Otherwise
431                  * a new dumpblock is allocated each time and we run out of
432                  * memory.
433                  */
434                 if (!oldtop->prev) break;
435 #endif
436 #endif
437
438                 di->allocateddumpsize -= tmp->size;
439                 di->currentdumpblock = tmp->prev;
440
441 #if defined(ENABLE_STATISTICS)
442                 /* the amount of globally allocated dump memory (thread save) */
443
444                 if (opt_stat)
445                         globalallocateddumpsize -= tmp->size;
446 #endif
447
448                 /* release the dump memory and the dumpinfo structure */
449
450                 free(tmp->dumpmem);
451                 free(tmp);
452         }
453 #endif /* defined(DISABLE_DUMP) */
454 }
455
456
457 /* dump_size *******************************************************************
458
459    XXX
460
461 *******************************************************************************/
462
463 s4 dump_size(void)
464 {
465 #if defined(DISABLE_DUMP)
466         /* use malloc memory for dump memory (for debugging only!) */
467
468         return 0;
469 #else
470         dumpinfo *di;
471
472         /* If no threads are used, the dumpinfo structure is a static structure   */
473         /* defined at the top of this file.                                       */
474
475         di = DUMPINFO;
476
477         if (!di)
478                 return 0;
479
480         return di->useddumpsize;
481 #endif /* defined(DISABLE_DUMP) */
482 }
483
484
485 /*
486  * These are local overrides for various environment variables in Emacs.
487  * Please do not remove this and leave it at the end of the file, where
488  * Emacs will automagically detect them.
489  * ---------------------------------------------------------------------
490  * Local variables:
491  * mode: c
492  * indent-tabs-mode: t
493  * c-basic-offset: 4
494  * tab-width: 4
495  * End:
496  */