* src/mm/memory.c (memory_mmap_anon): Fixed indentation and a debug
[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             Christian Thalinger
29             Edwin Steiner
30
31    $Id: memory.c 6256 2006-12-28 12:30:09Z twisti $
32
33 */
34
35
36 #include "config.h"
37
38 #include <assert.h>
39 #include <errno.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <sys/mman.h>
45
46 #if defined(__DARWIN__)
47 /* If we compile with -ansi on darwin, <sys/types.h> is not
48    included. So let's do it here. */
49 # include <sys/types.h>
50 #endif
51
52 #include "vm/types.h"
53
54 #include "arch.h"
55
56 #include "mm/memory.h"
57 #include "native/native.h"
58
59 #if defined(ENABLE_THREADS)
60 # include "threads/native/lock.h"
61 # include "threads/native/threads.h"
62 #else
63 # include "threads/none/lock.h"
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 #include "vm/vm.h"
73
74
75 /* constants for ENABLE_MEMCHECK **********************************************/
76
77 #if defined(ENABLE_MEMCHECK)
78 #define MEMORY_CANARY_SIZE          16
79 #define MEMORY_CANARY_FIRST_BYTE    0xca
80 #define MEMORY_CLEAR_BYTE           0xa5
81 #endif /* defined(ENABLE_MEMCHECK) */
82
83
84 /*******************************************************************************
85
86   This structure is used for dump memory allocation if cacao
87   runs without threads.
88
89 *******************************************************************************/
90
91 #if !defined(ENABLE_THREADS)
92 static dumpinfo_t _no_threads_dumpinfo;
93 #endif
94
95 #if defined(ENABLE_THREADS)
96 #define DUMPINFO    &((threadobject *) THREADOBJECT)->dumpinfo
97 #else
98 #define DUMPINFO    &_no_threads_dumpinfo
99 #endif
100
101
102 /* global code memory variables ***********************************************/
103
104 #define DEFAULT_CODE_MEMORY_SIZE    128 * 1024 /* defaulting to 128kB         */
105
106 #if defined(ENABLE_THREADS)
107 static java_objectheader *lock_code_memory = NULL;
108 #endif
109 static void              *code_memory      = NULL;
110 static int                code_memory_size = 0;
111 static int                pagesize         = 0;
112
113
114 /* memory_init *****************************************************************
115
116    Initialize the memory subsystem.
117
118 *******************************************************************************/
119
120 bool memory_init(void)
121 {
122 #if defined(ENABLE_THREADS)
123         lock_code_memory = NEW(java_objectheader);
124
125         lock_init_object_lock(lock_code_memory);
126 #endif
127
128         /* get the pagesize of this architecture */
129
130         pagesize = getpagesize();
131
132         /* everything's ok */
133
134         return true;
135 }
136
137
138 /* memory_mmap_anon ************************************************************
139
140    Maps anonymous memory, even on systems not defining
141    MAP_ANON(YMOUS).
142
143 *******************************************************************************/
144
145 void *memory_mmap_anon(void *addr, size_t len, int prot, int flags)
146 {
147         void *p;
148
149 #if defined(MAP_ANON) || defined(MAP_ANONYMOUS)
150         p = mmap(addr, len, prot,
151 # if defined(MAP_ANON)
152                          MAP_ANON | flags,
153 # else
154                          MAP_ANONYMOUS | flags,
155 # endif
156                          -1, 0);
157 #else
158         int fd;
159
160         fd = open("/dev/zero", O_RDONLY, 0);
161
162         if (fd == -1)
163                 vm_abort("memory_mmap_anon: open failed: %s", strerror(errno));
164
165         p = mmap(addr, len, prot, flags, fd, 0);
166 #endif
167
168 #if defined(MAP_FAILED)
169         if (p == MAP_FAILED)
170 #else
171         if (p == (void *) -1)
172 #endif
173                 vm_abort("memory_mmap_anon: mmap failed: %s", strerror(errno));
174
175         return p;
176 }
177
178
179 /* memory_checked_alloc ********************************************************
180
181    Allocated zeroed-out memory and does an OOM check.
182
183    ERROR HANDLING:
184       XXX If no memory could be allocated, this function justs *exists*.
185
186 *******************************************************************************/
187
188 static void *memory_checked_alloc(s4 size)
189 {
190         /* always allocate memory zeroed out */
191
192         void *p = calloc(size, 1);
193
194         if (p == NULL)
195                 exceptions_throw_outofmemory_exit();
196
197         return p;
198 }
199
200
201 /* memory_cnew *****************************************************************
202
203    Allocates memory from the heap via mmap and make the memory read-,
204    write-, and executeable.
205
206 *******************************************************************************/
207
208 void *memory_cnew(s4 size)
209 {
210         void *p;
211
212         LOCK_MONITOR_ENTER(lock_code_memory);
213
214         size = MEMORY_ALIGN(size, ALIGNSIZE);
215
216         /* check if enough memory is available */
217
218         if (size > code_memory_size) {
219                 /* set default code size */
220
221                 code_memory_size = DEFAULT_CODE_MEMORY_SIZE;
222
223                 /* do we need more? */
224
225                 if (size > code_memory_size)
226                         code_memory_size = size;
227
228                 /* align the size of the memory to be allocated */
229
230                 code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize);
231
232 #if defined(ENABLE_STATISTICS)
233                 if (opt_stat) {
234                         codememusage += code_memory_size;
235
236                         if (codememusage > maxcodememusage)
237                                 maxcodememusage = codememusage;
238                 }
239 #endif
240
241                 /* allocate the memory */
242
243                 p = memory_mmap_anon(NULL, code_memory_size,
244                                                          PROT_READ | PROT_WRITE | PROT_EXEC,
245                                                          MAP_PRIVATE);
246
247                 /* set global code memory pointer */
248
249                 code_memory = p;
250         }
251
252         /* get a memory chunk of the allocated memory */
253
254         p = code_memory;
255
256         code_memory       = (void *) ((ptrint) code_memory + size);
257         code_memory_size -= size;
258
259         LOCK_MONITOR_EXIT(lock_code_memory);
260
261         return p;
262 }
263
264
265 /* memory_cfree ****************************************************************
266
267    Frees the code memory pointed to.
268
269    ATTENTION: This function currently does NOTHING!  Because we don't
270    have a memory management for code memory.
271
272 *******************************************************************************/
273
274 void memory_cfree(void *p, s4 size)
275 {
276         /* do nothing */
277 }
278
279
280 void *mem_alloc(s4 size)
281 {
282         void *m;
283
284         if (size == 0)
285                 return NULL;
286
287 #if defined(ENABLE_STATISTICS)
288         if (opt_stat) {
289                 memoryusage += size;
290
291                 if (memoryusage > maxmemusage)
292                         maxmemusage = memoryusage;
293         }
294 #endif
295
296         m = memory_checked_alloc(size);
297
298 #if defined(ENABLE_MEMCHECK)
299         /* XXX we would like to poison the memory, but callers rely on */
300         /* the zeroing. This should change sooner or later.            */
301         /* memset(m, MEMORY_CLEAR_BYTE, size); */
302 #endif
303
304         return m;
305 }
306
307
308 void *mem_realloc(void *src, s4 len1, s4 len2)
309 {
310         void *dst;
311
312         if (!src) {
313                 if (len1 != 0) {
314                         log_text("reallocating memoryblock with address NULL, length != 0");
315                         assert(0);
316                 }
317         }
318
319 #if defined(ENABLE_STATISTICS)
320         if (opt_stat)
321                 memoryusage = (memoryusage - len1) + len2;
322 #endif
323
324 #if defined(ENABLE_MEMCHECK)
325         if (len2 < len1)
326                 memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
327 #endif
328
329         dst = realloc(src, len2);
330
331         if (dst == NULL)
332                 exceptions_throw_outofmemory_exit();
333
334 #if defined(ENABLE_MEMCHECK)
335         if (len2 > len1)
336                 memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, len2 - len1);
337 #endif
338
339         return dst;
340 }
341
342
343 void mem_free(void *m, s4 size)
344 {
345         if (!m) {
346                 if (size == 0)
347                         return;
348
349                 log_text("returned memoryblock with address NULL, length != 0");
350                 assert(0);
351         }
352
353 #if defined(ENABLE_STATISTICS)
354         if (opt_stat)
355                 memoryusage -= size;
356 #endif
357
358 #if defined(ENABLE_MEMCHECK)
359         /* destroy the contents */
360         memset(m, MEMORY_CLEAR_BYTE, size);
361 #endif
362
363         free(m);
364 }
365
366
367 /* dump_check_canaries *********************************************************
368
369    Check canaries in dump memory.
370
371    IN:
372       di...........dumpinfo_t * of the dump area to check
373           bottomsize...dump size down to which the dump area should be checked
374                        (specify 0 to check the whole dump area)
375
376    ERROR HANDLING:
377       If any canary has been changed, this function aborts the VM with
378           an error message.
379
380 *******************************************************************************/
381
382 #if defined(ENABLE_MEMCHECK)
383 void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
384 {
385         dump_allocation_t *da;
386         u1 *pm;
387         s4 i, j;
388
389         /* iterate over all dump memory allocations above bottomsize */
390
391         da = di->allocations;
392         while (da && da->useddumpsize >= bottomsize) {
393                 /* check canaries */
394
395                 pm = da->mem - MEMORY_CANARY_SIZE;
396                 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
397                         if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
398                                 fprintf(stderr, "canary bytes:");
399                                 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
400                                         fprintf(stderr, " %02x", pm[j]);
401                                 fprintf(stderr,"\n");
402                                 vm_abort("error: dump memory bottom canary killed: "
403                                                  "%p (%d bytes allocated at %p)\n",
404                                                 pm + i, da->size, da->mem);
405                         }
406
407                 pm = da->mem + da->size;
408                 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
409                         if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
410                                 fprintf(stderr, "canary bytes:");
411                                 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
412                                         fprintf(stderr, " %02x", pm[j]);
413                                 fprintf(stderr,"\n");
414                                 vm_abort("error: dump memory top canary killed: "
415                                                  "%p (%d bytes allocated at %p)\n",
416                                                 pm + i, da->size, da->mem);
417                         }
418
419                 da = da->next;
420         }
421 }
422 #endif /* defined(ENABLE_MEMCHECK) */
423
424
425 /* dump_alloc ******************************************************************
426
427    Allocate memory in the dump area.
428
429    IN:
430       size.........size of block to allocate, in bytes
431                                    may be zero, in which case NULL is returned
432
433    RETURN VALUE:
434       pointer to allocated memory, or
435           NULL iff `size` was zero
436
437    ERROR HANDLING:
438       XXX This function uses `memory_checked_alloc`, which *exits* if no 
439           memory could be allocated.
440
441    THREADS:
442       dump_alloc is thread safe. Each thread has its own dump memory area.
443
444    dump_alloc is a fast allocator suitable for scratch memory that can be
445    collectively freed when the current activity (eg. compiling) is done.
446
447    You cannot selectively free dump memory. Before you start allocating it, 
448    you remember the current size returned by `dump_size`. Later, when you no 
449    longer need the memory, call `dump_release` with the remembered size and
450    all dump memory allocated since the call to `dump_size` will be freed.
451
452 *******************************************************************************/
453
454 void *dump_alloc(s4 size)
455 {
456 #if defined(DISABLE_DUMP)
457
458         /* use malloc memory for dump memory (for debugging only!) */
459
460         return mem_alloc(size);
461
462 #else /* !defined(DISABLE_DUMP) */
463
464         void       *m;
465         dumpinfo_t *di;
466 #if defined(ENABLE_MEMCHECK)
467         s4          origsize = size; /* needed for the canary system */
468 #endif
469
470         /* If no threads are used, the dumpinfo structure is a static structure   */
471         /* defined at the top of this file.                                       */
472
473         di = DUMPINFO;
474
475         if (size == 0)
476                 return NULL;
477
478 #if defined(ENABLE_MEMCHECK)
479         size += 2*MEMORY_CANARY_SIZE;
480 #endif
481
482         size = MEMORY_ALIGN(size, ALIGNSIZE);
483
484         if (di->useddumpsize + size > di->allocateddumpsize) {
485                 dumpblock_t *newdumpblock;
486                 s4         newdumpblocksize;
487
488                 /* allocate a new dumplist structure */
489
490                 newdumpblock = memory_checked_alloc(sizeof(dumpblock_t));
491
492                 /* If requested size is greater than the default, make the new dump   */
493                 /* block as big as the size requested. Else use the default size.     */
494
495                 if (size > DUMPBLOCKSIZE) {
496                         newdumpblocksize = size;
497
498                 } else {
499                         newdumpblocksize = DUMPBLOCKSIZE;
500                 }
501
502                 /* allocate dumpblock memory */
503
504                 newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
505
506                 newdumpblock->prev = di->currentdumpblock;
507                 newdumpblock->size = newdumpblocksize;
508                 di->currentdumpblock = newdumpblock;
509
510                 /* Used dump size is previously allocated dump size, because the      */
511                 /* remaining free memory of the previous dump block cannot be used.   */
512
513                 di->useddumpsize = di->allocateddumpsize;
514
515                 /* increase the allocated dump size by the size of the new dump block */
516
517                 di->allocateddumpsize += newdumpblocksize;
518
519 #if defined(ENABLE_STATISTICS)
520                 /* the amount of globally allocated dump memory (thread save) */
521
522                 if (opt_stat)
523                         globalallocateddumpsize += newdumpblocksize;
524 #endif
525         }
526
527         /* current dump block base address + the size of the current dump block - */
528         /* the size of the unused memory = new start address                      */
529
530         m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
531                 (di->allocateddumpsize - di->useddumpsize);
532
533 #if defined(ENABLE_MEMCHECK)
534         {
535                 dump_allocation_t *da = NEW(dump_allocation_t);
536                 s4 i;
537                 u1 *pm;
538
539                 /* add the allocation to our linked list of allocations */
540
541                 da->next = di->allocations;
542                 da->mem = (u1*) m + MEMORY_CANARY_SIZE;
543                 da->size = origsize;
544                 da->useddumpsize = di->useddumpsize;
545
546                 di->allocations = da;
547
548                 /* write the canaries */
549
550                 pm = (u1*)m;
551                 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
552                         pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
553                 pm = da->mem + da->size;
554                 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
555                         pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
556
557                 /* make m point after the bottom canary */
558
559                 m = (u1*)m + MEMORY_CANARY_SIZE;
560
561                 /* clear the memory */
562
563                 memset(m, MEMORY_CLEAR_BYTE, da->size);
564         }
565 #endif /* defined(ENABLE_MEMCHECK) */
566
567         /* increase used dump size by the allocated memory size */
568
569         di->useddumpsize += size;
570
571 #if defined(ENABLE_STATISTICS)
572         if (opt_stat)
573                 if (di->useddumpsize > maxdumpsize)
574                         maxdumpsize = di->useddumpsize;
575 #endif
576
577         return m;
578
579 #endif /* defined(DISABLE_DUMP) */
580 }
581
582
583 /* dump_realloc ****************************************************************
584
585    Stupid realloc implementation for dump memory. Avoid, if possible.
586
587 *******************************************************************************/
588
589 void *dump_realloc(void *src, s4 len1, s4 len2)
590 {
591 #if defined(DISABLE_DUMP)
592         /* use malloc memory for dump memory (for debugging only!) */
593
594         return mem_realloc(src, len1, len2);
595 #else
596         void *dst = dump_alloc(len2);
597
598         memcpy(dst, src, len1);
599
600 #if defined(ENABLE_MEMCHECK)
601         /* destroy the source */
602         memset(src, MEMORY_CLEAR_BYTE, len1);
603 #endif
604
605         return dst;
606 #endif
607 }
608
609
610 /* dump_release ****************************************************************
611
612    Release dump memory above the given size.
613
614    IN:
615        size........All dump memory above this mark will be freed. Usually
616                        `size` will be the return value of a `dump_size` call
617                                    made earlier.
618
619         ERROR HANDLING:
620            XXX If the given size is invalid, this function *exits* with an
621                error message.
622                                    
623         See `dump_alloc`.
624
625 *******************************************************************************/
626
627 void dump_release(s4 size)
628 {
629 #if defined(DISABLE_DUMP)
630
631         /* use malloc memory for dump memory (for debugging only!) */
632
633         /* do nothing */
634
635 #else /* !defined(DISABLE_DUMP) */
636
637         dumpinfo_t *di;
638
639         /* If no threads are used, the dumpinfo structure is a static structure   */
640         /* defined at the top of this file.                                       */
641
642         di = DUMPINFO;
643
644         if ((size < 0) || (size > di->useddumpsize))
645                 vm_abort("Illegal dump release size: %d", size);
646
647 #if defined(ENABLE_MEMCHECK)
648         {
649                 dump_allocation_t *da, *next;
650
651                 /* check canaries */
652
653                 dump_check_canaries(di, size);
654
655                 /* iterate over all dump memory allocations about to be released */
656
657                 da = di->allocations;
658                 while (da && da->useddumpsize >= size) {
659                         next = da->next;
660
661                         /* invalidate the freed memory */
662
663                         memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
664
665                         FREE(da, dump_allocation_t);
666
667                         da = next;
668                 }
669                 di->allocations = da;
670         }
671 #endif /* defined(ENABLE_MEMCHECK) */
672
673         /* reset the used dump size to the size specified */
674
675         di->useddumpsize = size;
676
677         while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
678                 dumpblock_t *tmp = di->currentdumpblock;
679
680                 di->allocateddumpsize -= tmp->size;
681                 di->currentdumpblock = tmp->prev;
682
683 #if defined(ENABLE_STATISTICS)
684                 /* the amount of globally allocated dump memory (thread save) */
685
686                 if (opt_stat)
687                         globalallocateddumpsize -= tmp->size;
688 #endif
689
690                 /* release the dump memory and the dumpinfo structure */
691
692                 free(tmp->dumpmem);
693                 free(tmp);
694         }
695
696 #endif /* defined(DISABLE_DUMP) */
697 }
698
699
700 /* dump_size *******************************************************************
701
702    Return the current size of the dump memory area. See `dump_alloc`.
703
704 *******************************************************************************/
705
706 s4 dump_size(void)
707 {
708 #if defined(DISABLE_DUMP)
709         /* use malloc memory for dump memory (for debugging only!) */
710
711         return 0;
712
713 #else /* !defined(DISABLE_DUMP) */
714
715         dumpinfo_t *di;
716
717         /* If no threads are used, the dumpinfo structure is a static structure   */
718         /* defined at the top of this file.                                       */
719
720         di = DUMPINFO;
721
722         if (di == NULL)
723                 return 0;
724
725         return di->useddumpsize;
726
727 #endif /* defined(DISABLE_DUMP) */
728 }
729
730
731 /*
732  * These are local overrides for various environment variables in Emacs.
733  * Please do not remove this and leave it at the end of the file, where
734  * Emacs will automagically detect them.
735  * ---------------------------------------------------------------------
736  * Local variables:
737  * mode: c
738  * indent-tabs-mode: t
739  * c-basic-offset: 4
740  * tab-width: 4
741  * End:
742  * vim:noexpandtab:sw=4:ts=4:
743  */