a873550a081199446365e9f6d16cd6327dab803b
[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 3552 2005-11-03 20:43:17Z 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                 throw_cacao_exception_exit(string_java_lang_InternalError,
139                                                                    "Out of memory");
140
141         return p;
142 }
143
144
145 /* memory_cnew *****************************************************************
146
147    Allocates memory from the heap, aligns it to architecutres PAGESIZE
148    and make the memory read-, write-, and executeable.
149
150 *******************************************************************************/
151
152 void *memory_cnew(s4 size)
153 {
154         void *p;
155         int   pagesize;
156
157 #if defined(USE_THREADS)
158         builtin_monitorenter(codememlock);
159 #endif
160
161         size = ALIGN(size, ALIGNSIZE);
162
163         /* check if enough memory is available */
164
165         if (size > codememsize) {
166                 /* set default code size */
167
168                 codememsize = DEFAULT_CODEMEM_SIZE;
169
170                 /* do we need more? */
171
172                 if (size > codememsize)
173                         codememsize = size;
174
175                 /* get the pagesize of this architecture */
176
177                 pagesize = getpagesize();
178
179                 /* allocate normal heap memory */
180
181                 if ((p = memory_checked_alloc(codememsize + pagesize - 1)) == NULL)
182                         return NULL;
183
184 #if defined(STATISTICS)
185                 if (opt_stat) {
186                         codememusage += codememsize + pagesize - 1;
187
188                         if (codememusage > maxcodememusage)
189                                 maxcodememusage = codememusage;
190                 }
191 #endif
192
193                 /* align the memory allocated to a multiple of PAGESIZE,
194                    mprotect requires this */
195
196                 p = (void *) (((ptrint) p + pagesize - 1) & ~(pagesize - 1));
197
198                 /* make the memory read-, write-, and executeable */
199
200                 if (mprotect(p, codememsize, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
201                         throw_cacao_exception_exit(string_java_lang_InternalError,
202                                                                            strerror(errno));
203
204                 /* set global code memory pointer */
205
206                 codememptr = p;
207         }
208
209         /* get a memory chunk of the allocated memory */
210
211         p = codememptr;
212         codememptr = (void *) ((ptrint) codememptr + size);
213         codememsize -= size;
214
215 #if defined(USE_THREADS)
216         builtin_monitorexit(codememlock);
217 #endif
218
219         return p;
220 }
221
222
223 void *mem_alloc(s4 size)
224 {
225         if (size == 0)
226                 return NULL;
227
228 #if defined(STATISTICS)
229         if (opt_stat) {
230                 memoryusage += size;
231
232                 if (memoryusage > maxmemusage)
233                         maxmemusage = memoryusage;
234         }
235 #endif
236
237         return memory_checked_alloc(size);
238 }
239
240
241 void *mem_realloc(void *src, s4 len1, s4 len2)
242 {
243         void *dst;
244
245         if (!src) {
246                 if (len1 != 0) {
247                         log_text("reallocating memoryblock with address NULL, length != 0");
248                         assert(0);
249                 }
250         }
251
252 #if defined(STATISTICS)
253         if (opt_stat)
254                 memoryusage = (memoryusage - len1) + len2;
255 #endif
256
257         dst = realloc(src, len2);
258
259         if (!dst)
260                 throw_cacao_exception_exit(string_java_lang_InternalError,
261                                                                    "Out of memory");
262
263         return dst;
264 }
265
266
267 void mem_free(void *m, s4 size)
268 {
269         if (!m) {
270                 if (size == 0)
271                         return;
272
273                 log_text("returned memoryblock with address NULL, length != 0");
274                 assert(0);
275         }
276
277 #if defined(STATISTICS)
278         if (opt_stat)
279                 memoryusage -= size;
280 #endif
281
282         free(m);
283 }
284
285
286 /* dump_alloc ******************************************************************
287
288    XXX
289
290 *******************************************************************************/
291
292 void *dump_alloc(s4 size)
293 {
294 #if defined(DISABLE_DUMP)
295         /* use malloc memory for dump memory (for debugging only!) */
296
297         return mem_alloc(size);
298 #else
299         void     *m;
300         dumpinfo *di;
301
302         /* If no threads are used, the dumpinfo structure is a static structure   */
303         /* defined at the top of this file.                                       */
304
305         di = DUMPINFO;
306
307         if (size == 0)
308                 return NULL;
309
310         size = ALIGN(size, ALIGNSIZE);
311
312         if (di->useddumpsize + size > di->allocateddumpsize) {
313                 dumpblock *newdumpblock;
314                 s4         newdumpblocksize;
315
316                 /* allocate a new dumplist structure */
317
318                 newdumpblock = memory_checked_alloc(sizeof(dumpblock));
319
320                 /* If requested size is greater than the default, make the new dump   */
321                 /* block as big as the size requested. Else use the default size.     */
322
323                 if (size > DUMPBLOCKSIZE) {
324                         newdumpblocksize = size;
325
326                 } else {
327                         newdumpblocksize = DUMPBLOCKSIZE;
328                 }
329
330                 /* allocate dumpblock memory */
331
332                 newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
333
334                 newdumpblock->prev = di->currentdumpblock;
335                 newdumpblock->size = newdumpblocksize;
336                 di->currentdumpblock = newdumpblock;
337
338                 /* Used dump size is previously allocated dump size, because the      */
339                 /* remaining free memory of the previous dump block cannot be used.   */
340
341                 di->useddumpsize = di->allocateddumpsize;
342
343                 /* increase the allocated dump size by the size of the new dump block */
344
345                 di->allocateddumpsize += newdumpblocksize;
346
347 #if defined(STATISTICS)
348                 /* the amount of globally allocated dump memory (thread save) */
349
350                 if (opt_stat)
351                         globalallocateddumpsize += newdumpblocksize;
352 #endif
353         }
354
355         /* current dump block base address + the size of the current dump block - */
356         /* the size of the unused memory = new start address                      */
357
358         m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
359                 (di->allocateddumpsize - di->useddumpsize);
360
361         /* increase used dump size by the allocated memory size */
362
363         di->useddumpsize += size;
364
365 #if defined(STATISTICS)
366         if (opt_stat)
367                 if (di->useddumpsize > maxdumpsize)
368                         maxdumpsize = di->useddumpsize;
369 #endif
370                 
371         return m;
372 #endif /* defined(DISABLE_DUMP) */
373 }
374
375
376 /* dump_realloc ****************************************************************
377
378    XXX
379
380 *******************************************************************************/
381
382 void *dump_realloc(void *src, s4 len1, s4 len2)
383 {
384 #if defined(DISABLE_DUMP)
385         /* use malloc memory for dump memory (for debugging only!) */
386
387         return mem_realloc(src, len1, len2);
388 #else
389         void *dst = dump_alloc(len2);
390
391         memcpy(dst, src, len1);
392
393         return dst;
394 #endif
395 }
396
397
398 /* dump_release ****************************************************************
399
400    XXX
401
402 *******************************************************************************/
403
404 void dump_release(s4 size)
405 {
406 #if defined(DISABLE_DUMP)
407         /* use malloc memory for dump memory (for debugging only!) */
408
409         /* do nothing */
410 #else
411         dumpinfo *di;
412
413         /* If no threads are used, the dumpinfo structure is a static structure   */
414         /* defined at the top of this file.                                       */
415
416         di = DUMPINFO;
417
418         if (size < 0 || size > di->useddumpsize)
419                 throw_cacao_exception_exit(string_java_lang_InternalError,
420                                                                    "Illegal dump release size %d", size);
421
422         /* reset the used dump size to the size specified */
423
424         di->useddumpsize = size;
425
426         while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
427                 dumpblock *tmp = di->currentdumpblock;
428
429 #if 0
430                 /* XXX TWISTI: can someone explain this to me? */
431 #ifdef TRACECALLARGS
432                 /* Keep the first dumpblock if we don't free memory. Otherwise
433                  * a new dumpblock is allocated each time and we run out of
434                  * memory.
435                  */
436                 if (!oldtop->prev) break;
437 #endif
438 #endif
439
440                 di->allocateddumpsize -= tmp->size;
441                 di->currentdumpblock = tmp->prev;
442
443 #if defined(STATISTICS)
444                 /* the amount of globally allocated dump memory (thread save) */
445
446                 if (opt_stat)
447                         globalallocateddumpsize -= tmp->size;
448 #endif
449
450                 /* release the dump memory and the dumpinfo structure */
451
452                 free(tmp->dumpmem);
453                 free(tmp);
454         }
455 #endif /* defined(DISABLE_DUMP) */
456 }
457
458
459 /* dump_size *******************************************************************
460
461    XXX
462
463 *******************************************************************************/
464
465 s4 dump_size(void)
466 {
467 #if defined(DISABLE_DUMP)
468         /* use malloc memory for dump memory (for debugging only!) */
469
470         return 0;
471 #else
472         dumpinfo *di;
473
474         /* If no threads are used, the dumpinfo structure is a static structure   */
475         /* defined at the top of this file.                                       */
476
477         di = DUMPINFO;
478
479         if (!di)
480                 return 0;
481
482         return di->useddumpsize;
483 #endif /* defined(DISABLE_DUMP) */
484 }
485
486
487 /*
488  * These are local overrides for various environment variables in Emacs.
489  * Please do not remove this and leave it at the end of the file, where
490  * Emacs will automagically detect them.
491  * ---------------------------------------------------------------------
492  * Local variables:
493  * mode: c
494  * indent-tabs-mode: t
495  * c-basic-offset: 4
496  * tab-width: 4
497  * End:
498  */