Include <sys/types.h> on darwin before <sys/mman.h>, this is a bug fix for
[cacao.git] / src / mm / memory.c
1 /* toolbox/memory.c - 
2
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
5    M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
6    P. Tomsich, J. Wenninger
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    $Id: memory.c 1499 2004-11-12 15:52:35Z twisti $
30
31 */
32
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <assert.h>
37 #include <string.h>
38
39 #if defined(__DARWIN__)
40 /* If we compile with -ansi on darwin, <sys/types.h> is not included. So      */
41 /* let's do it here.                                                          */
42 # include <sys/types.h>
43 #endif
44
45 #include <sys/mman.h>
46 #include <unistd.h>
47
48 #include "exceptions.h"
49 #include "global.h"
50 #include "native.h"
51 #include "options.h"
52 #include "statistics.h"
53 #include "threads/nativethread.h"
54 #include "toolbox/logging.h"
55 #include "toolbox/memory.h"
56
57
58 /********* general types, variables and auxiliary functions *********/
59
60 static int mmapcodesize = 0;
61 static void *mmapcodeptr = NULL;
62
63
64 /*******************************************************************************
65
66     This structure is used for dump memory allocation if cacao runs without
67     threads.
68
69 *******************************************************************************/
70
71 #if !defined(USE_THREADS)
72 static dumpinfo nothreads_dumpinfo;
73 #endif
74
75
76 void *mem_mmap(int size)
77 {
78         void *m;
79
80         size = ALIGN(size, ALIGNSIZE);
81
82         if (size > mmapcodesize) {
83                 mmapcodesize = 0x10000;
84
85                 if (size > mmapcodesize)
86                         mmapcodesize = size;
87
88                 mmapcodesize = ALIGN(mmapcodesize, getpagesize());
89                 mmapcodeptr = mmap(NULL,
90                                                    (size_t) mmapcodesize,
91                                                    PROT_READ | PROT_WRITE | PROT_EXEC,
92                                                    MAP_PRIVATE |
93 #if defined(HAVE_MAP_ANONYMOUS)
94                                                    MAP_ANONYMOUS,
95 #elif defined(HAVE_MAP_ANON)
96                                                    MAP_ANON,
97 #else
98                                                    0,
99 #endif
100                                                    -1,
101                                                    (off_t) 0);
102
103                 if (mmapcodeptr == MAP_FAILED)
104                         throw_cacao_exception_exit(string_java_lang_InternalError,
105                                                                            "Out of memory");
106         }
107
108         m = mmapcodeptr;
109         mmapcodeptr = (void *) ((char *) mmapcodeptr + size);
110         mmapcodesize -= size;
111
112         return m;
113 }
114
115
116 static void *checked_alloc(int size)
117 {
118         /* always allocate memory zeroed out */
119         void *m = calloc(size, 1);
120
121         if (!m)
122                 throw_cacao_exception_exit(string_java_lang_InternalError,
123                                                                    "Out of memory");
124
125         return m;
126 }
127
128
129 void *mem_alloc(int size)
130 {
131         if (size == 0)
132                 return NULL;
133
134         if (opt_stat) {
135                 memoryusage += size;
136
137                 if (memoryusage > maxmemusage)
138                         maxmemusage = memoryusage;
139         }
140         
141         return checked_alloc(size);
142 }
143
144
145 void *mem_realloc(void *src, int len1, int len2)
146 {
147         void *dst;
148
149         if (!src) {
150                 if (len1 != 0)
151                         panic("reallocating memoryblock with address NULL, length != 0");
152         }
153
154         if (opt_stat)
155                 memoryusage = (memoryusage - len1) + len2;
156
157         dst = realloc(src, len2);
158
159         if (!dst)
160                 throw_cacao_exception_exit(string_java_lang_InternalError,
161                                                                    "Out of memory");
162
163         return dst;
164 }
165
166
167 void mem_free(void *m, int size)
168 {
169         if (!m) {
170                 if (size == 0)
171                         return;
172                 panic("returned memoryblock with address NULL, length != 0");
173         }
174
175         if (opt_stat)
176                 memoryusage -= size;
177
178         free(m);
179 }
180
181
182 void *dump_alloc(int size)
183 {
184         void *m;
185         dumpinfo *di;
186
187         /* If no threads are used, the dumpinfo structure is a static structure   */
188         /* defined at the top of this file.                                       */
189 #if defined(USE_THREADS)
190         di = &((threadobject *) THREADOBJECT)->dumpinfo;
191 #else
192         di = &nothreads_dumpinfo;
193 #endif
194
195         if (size == 0)
196                 return NULL;
197
198         size = ALIGN(size, ALIGNSIZE);
199
200         if (di->useddumpsize + size > di->allocateddumpsize) {
201                 dumpblock *newdumpblock;
202                 s4 newdumpblocksize;
203
204                 /* allocate a new dumplist structure */
205                 newdumpblock = checked_alloc(sizeof(dumpblock));
206
207                 /* If requested size is greater than the default, make the new dump   */
208                 /* block as big as the size requested. Else use the default size.     */
209                 if (size > DUMPBLOCKSIZE) {
210                         newdumpblocksize = size;
211
212                 } else {
213                         newdumpblocksize = DUMPBLOCKSIZE;
214                 }
215
216                 /* allocate dumpblock memory */
217                 /*printf("new dumpblock: %d\n", newdumpblocksize);*/
218                 newdumpblock->dumpmem = checked_alloc(newdumpblocksize);
219
220                 newdumpblock->prev = di->currentdumpblock;
221                 newdumpblock->size = newdumpblocksize;
222                 di->currentdumpblock = newdumpblock;
223
224                 /* Used dump size is previously allocated dump size, because the      */
225                 /* remaining free memory of the previous dump block cannot be used.   */
226                 /*printf("unused memory: %d\n", allocateddumpsize - useddumpsize);*/
227                 di->useddumpsize = di->allocateddumpsize;
228
229                 /* increase the allocated dump size by the size of the new dump block */
230                 di->allocateddumpsize += newdumpblocksize;
231
232                 /* the amount of globally allocated dump memory (thread save)         */
233                 if (opt_stat)
234                         globalallocateddumpsize += newdumpblocksize;
235         }
236
237         /* current dump block base address + the size of the current dump block - */
238         /* the size of the unused memory = new start address                      */
239         m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
240                 (di->allocateddumpsize - di->useddumpsize);
241
242         /* increase used dump size by the allocated memory size                   */
243         di->useddumpsize += size;
244
245         if (opt_stat) {
246                 if (di->useddumpsize > maxdumpsize) {
247                         maxdumpsize = di->useddumpsize;
248                 }
249         }
250                 
251         return m;
252 }   
253
254
255 void *dump_realloc(void *src, int len1, int len2)
256 {
257         void *dst = dump_alloc(len2);
258
259         memcpy(dst, src, len1);
260
261         return dst;
262 }
263
264
265 void dump_release(int size)
266 {
267         dumpinfo *di;
268
269         /* If no threads are used, the dumpinfo structure is a static structure   */
270         /* defined at the top of this file.                                       */
271 #if defined(USE_THREADS)
272         di = &((threadobject *) THREADOBJECT)->dumpinfo;
273 #else
274         di = &nothreads_dumpinfo;
275 #endif
276
277         if (size < 0 || size > di->useddumpsize)
278                 throw_cacao_exception_exit(string_java_lang_InternalError,
279                                                                    "Illegal dump release size %d", size);
280
281         /* reset the used dump size to the size specified                         */
282         di->useddumpsize = size;
283
284         while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
285                 dumpblock *tmp = di->currentdumpblock;
286
287 #if 0
288                 /* XXX TWISTI: can someone explain this to me? */
289 #ifdef TRACECALLARGS
290                 /* Keep the first dumpblock if we don't free memory. Otherwise
291                  * a new dumpblock is allocated each time and we run out of
292                  * memory.
293                  */
294                 if (!oldtop->prev) break;
295 #endif
296 #endif
297
298                 di->allocateddumpsize -= tmp->size;
299                 di->currentdumpblock = tmp->prev;
300
301                 /* the amount of globally allocated dump memory (thread save)         */
302                 if (opt_stat)
303                         globalallocateddumpsize -= tmp->size;
304
305                 /* release the dump memory and the dumpinfo structure                 */
306                 free(tmp->dumpmem);
307                 free(tmp);
308         }
309 }
310
311
312 long dump_size()
313 {
314         dumpinfo *di;
315
316         /* If no threads are used, the dumpinfo structure is a static structure   */
317         /* defined at the top of this file.                                       */
318 #if defined(USE_THREADS)
319         di = &((threadobject *) THREADOBJECT)->dumpinfo;
320 #else
321         di = &nothreads_dumpinfo;
322 #endif
323
324         return di->useddumpsize;
325 }
326
327
328 /*
329  * These are local overrides for various environment variables in Emacs.
330  * Please do not remove this and leave it at the end of the file, where
331  * Emacs will automagically detect them.
332  * ---------------------------------------------------------------------
333  * Local variables:
334  * mode: c
335  * indent-tabs-mode: t
336  * c-basic-offset: 4
337  * tab-width: 4
338  * End:
339  */