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