* memory_cnew: Added.
[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 3479 2005-10-21 13:08:19Z 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 static void *checked_alloc(s4 size)
93 {
94         /* always allocate memory zeroed out */
95
96         void *m = calloc(size, 1);
97
98         if (!m)
99                 throw_cacao_exception_exit(string_java_lang_InternalError,
100                                                                    "Out of memory");
101
102         return m;
103 }
104
105
106 /* memory_cnew *****************************************************************
107
108    Allocates memory from the heap, aligns it to architecutres PAGESIZE
109    and make the memory read-, write-, and executeable.
110
111 *******************************************************************************/
112
113 void *memory_cnew(s4 size)
114 {
115         void *p;
116         int   pagesize;
117
118         /* get the pagesize of this architecture */
119
120         pagesize = getpagesize();
121
122         /* allocate normal heap memory */
123
124         if ((p = mem_alloc(size + pagesize - 1)) == NULL)
125                 return NULL;
126
127         /* align the memory allocated to a multiple of PAGESIZE, mprotect
128            requires this */
129
130         p = (void *) (((ptrint) p + pagesize - 1) & ~(pagesize - 1));
131
132         /* make the memory read-, write-, and executeable */
133
134         if (mprotect(p, size, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
135                 throw_cacao_exception_exit(string_java_lang_InternalError,
136                                                                    strerror(errno));
137
138         return p;
139 }
140
141
142 void *mem_alloc(s4 size)
143 {
144         if (size == 0)
145                 return NULL;
146
147 #if defined(STATISTICS)
148         if (opt_stat) {
149                 memoryusage += size;
150
151                 if (memoryusage > maxmemusage)
152                         maxmemusage = memoryusage;
153         }
154 #endif
155
156         return checked_alloc(size);
157 }
158
159
160 void *mem_realloc(void *src, s4 len1, s4 len2)
161 {
162         void *dst;
163
164         if (!src) {
165                 if (len1 != 0) {
166                         log_text("reallocating memoryblock with address NULL, length != 0");
167                         assert(0);
168                 }
169         }
170
171 #if defined(STATISTICS)
172         if (opt_stat)
173                 memoryusage = (memoryusage - len1) + len2;
174 #endif
175
176         dst = realloc(src, len2);
177
178         if (!dst)
179                 throw_cacao_exception_exit(string_java_lang_InternalError,
180                                                                    "Out of memory");
181
182         return dst;
183 }
184
185
186 void mem_free(void *m, s4 size)
187 {
188         if (!m) {
189                 if (size == 0)
190                         return;
191
192                 log_text("returned memoryblock with address NULL, length != 0");
193                 assert(0);
194         }
195
196 #if defined(STATISTICS)
197         if (opt_stat)
198                 memoryusage -= size;
199 #endif
200
201         free(m);
202 }
203
204
205 /* dump_alloc ******************************************************************
206
207    XXX
208
209 *******************************************************************************/
210
211 void *dump_alloc(s4 size)
212 {
213 #if defined(DISABLE_DUMP)
214         /* use malloc memory for dump memory (for debugging only!) */
215
216         return mem_alloc(size);
217 #else
218         void     *m;
219         dumpinfo *di;
220
221         /* If no threads are used, the dumpinfo structure is a static structure   */
222         /* defined at the top of this file.                                       */
223
224         di = DUMPINFO;
225
226         if (size == 0)
227                 return NULL;
228
229         size = ALIGN(size, ALIGNSIZE);
230
231         if (di->useddumpsize + size > di->allocateddumpsize) {
232                 dumpblock *newdumpblock;
233                 s4         newdumpblocksize;
234
235                 /* allocate a new dumplist structure */
236
237                 newdumpblock = checked_alloc(sizeof(dumpblock));
238
239                 /* If requested size is greater than the default, make the new dump   */
240                 /* block as big as the size requested. Else use the default size.     */
241
242                 if (size > DUMPBLOCKSIZE) {
243                         newdumpblocksize = size;
244
245                 } else {
246                         newdumpblocksize = DUMPBLOCKSIZE;
247                 }
248
249                 /* allocate dumpblock memory */
250
251                 newdumpblock->dumpmem = checked_alloc(newdumpblocksize);
252
253                 newdumpblock->prev = di->currentdumpblock;
254                 newdumpblock->size = newdumpblocksize;
255                 di->currentdumpblock = newdumpblock;
256
257                 /* Used dump size is previously allocated dump size, because the      */
258                 /* remaining free memory of the previous dump block cannot be used.   */
259
260                 di->useddumpsize = di->allocateddumpsize;
261
262                 /* increase the allocated dump size by the size of the new dump block */
263
264                 di->allocateddumpsize += newdumpblocksize;
265
266 #if defined(STATISTICS)
267                 /* the amount of globally allocated dump memory (thread save) */
268
269                 if (opt_stat)
270                         globalallocateddumpsize += newdumpblocksize;
271 #endif
272         }
273
274         /* current dump block base address + the size of the current dump block - */
275         /* the size of the unused memory = new start address                      */
276
277         m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
278                 (di->allocateddumpsize - di->useddumpsize);
279
280         /* increase used dump size by the allocated memory size */
281
282         di->useddumpsize += size;
283
284 #if defined(STATISTICS)
285         if (opt_stat)
286                 if (di->useddumpsize > maxdumpsize)
287                         maxdumpsize = di->useddumpsize;
288 #endif
289                 
290         return m;
291 #endif /* defined(DISABLE_DUMP) */
292 }
293
294
295 /* dump_realloc ****************************************************************
296
297    XXX
298
299 *******************************************************************************/
300
301 void *dump_realloc(void *src, s4 len1, s4 len2)
302 {
303 #if defined(DISABLE_DUMP)
304         /* use malloc memory for dump memory (for debugging only!) */
305
306         return mem_realloc(src, len1, len2);
307 #else
308         void *dst = dump_alloc(len2);
309
310         memcpy(dst, src, len1);
311
312         return dst;
313 #endif
314 }
315
316
317 /* dump_release ****************************************************************
318
319    XXX
320
321 *******************************************************************************/
322
323 void dump_release(s4 size)
324 {
325 #if defined(DISABLE_DUMP)
326         /* use malloc memory for dump memory (for debugging only!) */
327
328         /* do nothing */
329 #else
330         dumpinfo *di;
331
332         /* If no threads are used, the dumpinfo structure is a static structure   */
333         /* defined at the top of this file.                                       */
334
335         di = DUMPINFO;
336
337         if (size < 0 || size > di->useddumpsize)
338                 throw_cacao_exception_exit(string_java_lang_InternalError,
339                                                                    "Illegal dump release size %d", size);
340
341         /* reset the used dump size to the size specified */
342
343         di->useddumpsize = size;
344
345         while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
346                 dumpblock *tmp = di->currentdumpblock;
347
348 #if 0
349                 /* XXX TWISTI: can someone explain this to me? */
350 #ifdef TRACECALLARGS
351                 /* Keep the first dumpblock if we don't free memory. Otherwise
352                  * a new dumpblock is allocated each time and we run out of
353                  * memory.
354                  */
355                 if (!oldtop->prev) break;
356 #endif
357 #endif
358
359                 di->allocateddumpsize -= tmp->size;
360                 di->currentdumpblock = tmp->prev;
361
362 #if defined(STATISTICS)
363                 /* the amount of globally allocated dump memory (thread save) */
364
365                 if (opt_stat)
366                         globalallocateddumpsize -= tmp->size;
367 #endif
368
369                 /* release the dump memory and the dumpinfo structure */
370
371                 free(tmp->dumpmem);
372                 free(tmp);
373         }
374 #endif /* defined(DISABLE_DUMP) */
375 }
376
377
378 /* dump_size *******************************************************************
379
380    XXX
381
382 *******************************************************************************/
383
384 s4 dump_size(void)
385 {
386 #if defined(DISABLE_DUMP)
387         /* use malloc memory for dump memory (for debugging only!) */
388
389         return 0;
390 #else
391         dumpinfo *di;
392
393         /* If no threads are used, the dumpinfo structure is a static structure   */
394         /* defined at the top of this file.                                       */
395
396         di = DUMPINFO;
397
398         if (!di)
399                 return 0;
400
401         return di->useddumpsize;
402 #endif /* defined(DISABLE_DUMP) */
403 }
404
405
406 /*
407  * These are local overrides for various environment variables in Emacs.
408  * Please do not remove this and leave it at the end of the file, where
409  * Emacs will automagically detect them.
410  * ---------------------------------------------------------------------
411  * Local variables:
412  * mode: c
413  * indent-tabs-mode: t
414  * c-basic-offset: 4
415  * tab-width: 4
416  * End:
417  */