* src/mm/memory.c: fixed typo in _no_threads_dumpinfo definition
[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                         Edwin Steiner
31
32    $Id: memory.c 5807 2006-10-20 00:37:37Z ajordan $
33
34 */
35
36
37 #include "config.h"
38
39 #include <assert.h>
40 #include <errno.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <sys/mman.h>
46
47 #if defined(__DARWIN__)
48 /* If we compile with -ansi on darwin, <sys/types.h> is not included. So      */
49 /* let's do it here.                                                          */
50 # include <sys/types.h>
51 #endif
52
53 #include "vm/types.h"
54
55 #include "arch.h"
56
57 #include "mm/memory.h"
58 #include "native/native.h"
59
60 #if defined(ENABLE_THREADS)
61 # include "threads/native/lock.h"
62 # include "threads/native/threads.h"
63 #else
64 # include "threads/none/lock.h"
65 #endif
66
67 #include "toolbox/logging.h"
68 #include "vm/exceptions.h"
69 #include "vm/global.h"
70 #include "vm/options.h"
71 #include "vm/statistics.h"
72 #include "vm/stringlocal.h"
73 #include "vm/vm.h"
74
75
76 /*******************************************************************************
77
78   This structure is used for dump memory allocation if cacao
79   runs without threads.
80
81 *******************************************************************************/
82
83 #if !defined(ENABLE_THREADS)
84 static dumpinfo_t _no_threads_dumpinfo;
85 #endif
86
87 #if defined(ENABLE_THREADS)
88 #define DUMPINFO    &((threadobject *) THREADOBJECT)->dumpinfo
89 #else
90 #define DUMPINFO    &_no_threads_dumpinfo
91 #endif
92
93
94 /* global code memory variables ***********************************************/
95
96 #define DEFAULT_CODE_MEMORY_SIZE    128 * 1024 /* defaulting to 128kB         */
97
98 #if defined(ENABLE_THREADS)
99 static java_objectheader *lock_code_memory = NULL;
100 #endif
101 static void              *code_memory      = NULL;
102 static int                code_memory_size = 0;
103 static int                pagesize         = 0;
104
105
106 /* memory_init *****************************************************************
107
108    Initialize the memory subsystem.
109
110 *******************************************************************************/
111
112 bool memory_init(void)
113 {
114 #if defined(ENABLE_THREADS)
115         lock_code_memory = NEW(java_objectheader);
116
117         lock_init_object_lock(lock_code_memory);
118 #endif
119
120         /* get the pagesize of this architecture */
121
122         pagesize = getpagesize();
123
124         /* everything's ok */
125
126         return true;
127 }
128
129
130 /* memory_checked_alloc ********************************************************
131
132    Allocated zeroed-out memory and does an OOM check.
133
134    ERROR HANDLING:
135       XXX If no memory could be allocated, this function justs *exists*.
136
137 *******************************************************************************/
138
139 static void *memory_checked_alloc(s4 size)
140 {
141         /* always allocate memory zeroed out */
142
143         void *p = calloc(size, 1);
144
145         if (p == NULL)
146                 exceptions_throw_outofmemory_exit();
147
148         return p;
149 }
150
151
152 /* memory_cnew *****************************************************************
153
154    Allocates memory from the heap via mmap and make the memory read-,
155    write-, and executeable.
156
157 *******************************************************************************/
158
159 void *memory_cnew(s4 size)
160 {
161         void *p;
162
163         LOCK_MONITOR_ENTER(lock_code_memory);
164
165         size = ALIGN(size, ALIGNSIZE);
166
167         /* check if enough memory is available */
168
169         if (size > code_memory_size) {
170                 /* set default code size */
171
172                 code_memory_size = DEFAULT_CODE_MEMORY_SIZE;
173
174                 /* do we need more? */
175
176                 if (size > code_memory_size)
177                         code_memory_size = size;
178
179                 /* align the size of the memory to be allocated */
180
181                 code_memory_size = ALIGN(code_memory_size, pagesize);
182
183 #if defined(ENABLE_STATISTICS)
184                 if (opt_stat) {
185                         codememusage += code_memory_size;
186
187                         if (codememusage > maxcodememusage)
188                                 maxcodememusage = codememusage;
189                 }
190 #endif
191
192                 /* allocate the memory */
193
194 #if defined(MAP_ANONYMOUS) || defined(MAP_ANON)
195                 p = mmap(NULL,
196                                  (size_t) code_memory_size,
197                                  PROT_READ | PROT_WRITE | PROT_EXEC,
198                                  MAP_PRIVATE |
199 # if defined(MAP_ANONYMOUS)
200                                  MAP_ANONYMOUS,
201 # elif defined(MAP_ANON)
202                                  MAP_ANON,
203 # else
204                                  0,
205 # endif
206                                  -1,     
207                                  (off_t) 0);
208
209 # if defined(MAP_FAILED)
210                 if (p == MAP_FAILED)
211 # else
212                 if (p == (void *) -1)
213 # endif
214                         vm_abort("mmap failed: %s", strerror(errno));
215
216 #else
217                 /* This works a least on IRIX. */
218
219                 p = memory_checked_alloc(code_memory_size);
220 #endif
221
222                 /* set global code memory pointer */
223
224                 code_memory = p;
225         }
226
227         /* get a memory chunk of the allocated memory */
228
229         p = code_memory;
230
231         code_memory       = (void *) ((ptrint) code_memory + size);
232         code_memory_size -= size;
233
234         LOCK_MONITOR_EXIT(lock_code_memory);
235
236         return p;
237 }
238
239
240 /* memory_cfree ****************************************************************
241
242    Frees the code memory pointed to.
243
244    ATTENTION: This function currently does NOTHING!  Because we don't
245    have a memory management for code memory.
246
247 *******************************************************************************/
248
249 void memory_cfree(void *p, s4 size)
250 {
251         /* do nothing */
252 }
253
254
255 void *mem_alloc(s4 size)
256 {
257         if (size == 0)
258                 return NULL;
259
260 #if defined(ENABLE_STATISTICS)
261         if (opt_stat) {
262                 memoryusage += size;
263
264                 if (memoryusage > maxmemusage)
265                         maxmemusage = memoryusage;
266         }
267 #endif
268
269         return memory_checked_alloc(size);
270 }
271
272
273 void *mem_realloc(void *src, s4 len1, s4 len2)
274 {
275         void *dst;
276
277         if (!src) {
278                 if (len1 != 0) {
279                         log_text("reallocating memoryblock with address NULL, length != 0");
280                         assert(0);
281                 }
282         }
283
284 #if defined(ENABLE_STATISTICS)
285         if (opt_stat)
286                 memoryusage = (memoryusage - len1) + len2;
287 #endif
288
289         dst = realloc(src, len2);
290
291         if (dst == NULL)
292                 exceptions_throw_outofmemory_exit();
293
294         return dst;
295 }
296
297
298 void mem_free(void *m, s4 size)
299 {
300         if (!m) {
301                 if (size == 0)
302                         return;
303
304                 log_text("returned memoryblock with address NULL, length != 0");
305                 assert(0);
306         }
307
308 #if defined(ENABLE_STATISTICS)
309         if (opt_stat)
310                 memoryusage -= size;
311 #endif
312
313         free(m);
314 }
315
316
317 /* dump_alloc ******************************************************************
318
319    Allocate memory in the dump area.
320
321    IN:
322       size.........size of block to allocate, in bytes
323                                    may be zero, in which case NULL is returned
324
325    RETURN VALUE:
326       pointer to allocated memory, or
327           NULL iff `size` was zero
328
329    ERROR HANDLING:
330       XXX This function uses `memory_checked_alloc`, which *exits* if no 
331           memory could be allocated.
332
333    THREADS:
334       dump_alloc is thread safe. Each thread has its own dump memory area.
335
336    dump_alloc is a fast allocator suitable for scratch memory that can be
337    collectively freed when the current activity (eg. compiling) is done.
338
339    You cannot selectively free dump memory. Before you start allocating it, 
340    you remember the current size returned by `dump_size`. Later, when you no 
341    longer need the memory, call `dump_release` with the remembered size and
342    all dump memory allocated since the call to `dump_size` will be freed.
343
344 *******************************************************************************/
345
346 void *dump_alloc(s4 size)
347 {
348 #if defined(DISABLE_DUMP)
349
350         /* use malloc memory for dump memory (for debugging only!) */
351
352         return mem_alloc(size);
353
354 #else /* !defined(DISABLE_DUMP) */
355
356         void       *m;
357         dumpinfo_t *di;
358
359         /* If no threads are used, the dumpinfo structure is a static structure   */
360         /* defined at the top of this file.                                       */
361
362         di = DUMPINFO;
363
364         if (size == 0)
365                 return NULL;
366
367         size = ALIGN(size, ALIGNSIZE);
368
369         if (di->useddumpsize + size > di->allocateddumpsize) {
370                 dumpblock_t *newdumpblock;
371                 s4         newdumpblocksize;
372
373                 /* allocate a new dumplist structure */
374
375                 newdumpblock = memory_checked_alloc(sizeof(dumpblock_t));
376
377                 /* If requested size is greater than the default, make the new dump   */
378                 /* block as big as the size requested. Else use the default size.     */
379
380                 if (size > DUMPBLOCKSIZE) {
381                         newdumpblocksize = size;
382
383                 } else {
384                         newdumpblocksize = DUMPBLOCKSIZE;
385                 }
386
387                 /* allocate dumpblock memory */
388
389                 newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
390
391                 newdumpblock->prev = di->currentdumpblock;
392                 newdumpblock->size = newdumpblocksize;
393                 di->currentdumpblock = newdumpblock;
394
395                 /* Used dump size is previously allocated dump size, because the      */
396                 /* remaining free memory of the previous dump block cannot be used.   */
397
398                 di->useddumpsize = di->allocateddumpsize;
399
400                 /* increase the allocated dump size by the size of the new dump block */
401
402                 di->allocateddumpsize += newdumpblocksize;
403
404 #if defined(ENABLE_STATISTICS)
405                 /* the amount of globally allocated dump memory (thread save) */
406
407                 if (opt_stat)
408                         globalallocateddumpsize += newdumpblocksize;
409 #endif
410         }
411
412         /* current dump block base address + the size of the current dump block - */
413         /* the size of the unused memory = new start address                      */
414
415         m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
416                 (di->allocateddumpsize - di->useddumpsize);
417
418         /* increase used dump size by the allocated memory size */
419
420         di->useddumpsize += size;
421
422 #if defined(ENABLE_STATISTICS)
423         if (opt_stat)
424                 if (di->useddumpsize > maxdumpsize)
425                         maxdumpsize = di->useddumpsize;
426 #endif
427
428         return m;
429
430 #endif /* defined(DISABLE_DUMP) */
431 }
432
433
434 /* dump_realloc ****************************************************************
435
436    Stupid realloc implementation for dump memory. Avoid, if possible.
437
438 *******************************************************************************/
439
440 void *dump_realloc(void *src, s4 len1, s4 len2)
441 {
442 #if defined(DISABLE_DUMP)
443         /* use malloc memory for dump memory (for debugging only!) */
444
445         return mem_realloc(src, len1, len2);
446 #else
447         void *dst = dump_alloc(len2);
448
449         memcpy(dst, src, len1);
450
451         return dst;
452 #endif
453 }
454
455
456 /* dump_release ****************************************************************
457
458    Release dump memory above the given size.
459
460    IN:
461        size........All dump memory above this mark will be freed. Usually
462                        `size` will be the return value of a `dump_size` call
463                                    made earlier.
464
465         ERROR HANDLING:
466            XXX If the given size is invalid, this function *exits* with an
467                error message.
468                                    
469         See `dump_alloc`.
470
471 *******************************************************************************/
472
473 void dump_release(s4 size)
474 {
475 #if defined(DISABLE_DUMP)
476
477         /* use malloc memory for dump memory (for debugging only!) */
478
479         /* do nothing */
480
481 #else /* !defined(DISABLE_DUMP) */
482
483         dumpinfo_t *di;
484
485         /* If no threads are used, the dumpinfo structure is a static structure   */
486         /* defined at the top of this file.                                       */
487
488         di = DUMPINFO;
489
490         if ((size < 0) || (size > di->useddumpsize))
491                 vm_abort("Illegal dump release size: %d", size);
492
493         /* reset the used dump size to the size specified */
494
495         di->useddumpsize = size;
496
497         while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
498                 dumpblock_t *tmp = di->currentdumpblock;
499
500                 di->allocateddumpsize -= tmp->size;
501                 di->currentdumpblock = tmp->prev;
502
503 #if defined(ENABLE_STATISTICS)
504                 /* the amount of globally allocated dump memory (thread save) */
505
506                 if (opt_stat)
507                         globalallocateddumpsize -= tmp->size;
508 #endif
509
510                 /* release the dump memory and the dumpinfo structure */
511
512                 free(tmp->dumpmem);
513                 free(tmp);
514         }
515
516 #endif /* defined(DISABLE_DUMP) */
517 }
518
519
520 /* dump_size *******************************************************************
521
522    Return the current size of the dump memory area. See `dump_alloc`.
523
524 *******************************************************************************/
525
526 s4 dump_size(void)
527 {
528 #if defined(DISABLE_DUMP)
529         /* use malloc memory for dump memory (for debugging only!) */
530
531         return 0;
532
533 #else /* !defined(DISABLE_DUMP) */
534
535         dumpinfo_t *di;
536
537         /* If no threads are used, the dumpinfo structure is a static structure   */
538         /* defined at the top of this file.                                       */
539
540         di = DUMPINFO;
541
542         if (di == NULL)
543                 return 0;
544
545         return di->useddumpsize;
546
547 #endif /* defined(DISABLE_DUMP) */
548 }
549
550
551 /*
552  * These are local overrides for various environment variables in Emacs.
553  * Please do not remove this and leave it at the end of the file, where
554  * Emacs will automagically detect them.
555  * ---------------------------------------------------------------------
556  * Local variables:
557  * mode: c
558  * indent-tabs-mode: t
559  * c-basic-offset: 4
560  * tab-width: 4
561  * End:
562  * vim:noexpandtab:sw=4:ts=4:
563  */