* src/mm/cacao-gc/heap.c: Fixed includes.
[cacao.git] / src / mm / cacao-gc / heap.c
1 /* mm/cacao-gc/heap.c - GC module for heap management
2
3    Copyright (C) 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: Michael Starzinger
28
29    $Id$
30
31 */
32
33
34 #include "config.h"
35 #include "vm/types.h"
36
37 #if defined(ENABLE_THREADS)
38 # include "threads/native/lock.h"
39 #else
40 # include "threads/none/lock.h"
41 #endif
42
43 #include "gc.h"
44 #include "heap.h"
45 #include "mark.h"
46 #include "region.h"
47 #include "mm/memory.h"
48 #include "src/native/include/java_lang_String.h" /* TODO: fix me! */
49 #include "toolbox/logging.h"
50 #include "vm/global.h"
51 #include "vmcore/rt-timing.h"
52
53
54 /* Global Variables ***********************************************************/
55
56 s4 heap_current_size;  /* current size of the heap */
57 s4 heap_maximal_size;  /* maximal size of the heap */
58 regioninfo_t *heap_region_sys;
59 regioninfo_t *heap_region_main;
60
61
62 /* Helper Macros **************************************************************/
63
64 #define GC_ALIGN_SIZE SIZEOF_VOID_P
65 #define GC_ALIGN(length,size) ((((length) + (size) - 1) / (size)) * (size))
66
67
68
69 void heap_init_objectheader(java_objectheader *o, u4 bytelength)
70 {
71         u4 wordcount;
72
73         /* initialize the header flags */
74         o->hdrflags = 0;
75
76         /* align the size */
77         /* TODO */
78
79         /* calculate the wordcount as stored in the header */
80     /* TODO: improve this to save wordcount and without header bytes */
81     if ((bytelength & 0x03) == 0) {
82         GC_ASSERT((bytelength & 0x03) == 0);
83         wordcount = (bytelength >> 2);
84         GC_ASSERT(wordcount != 0);
85     } else {
86         wordcount = GC_SIZE_DUMMY;
87     }
88
89         /* set the wordcount in the header */
90     if (wordcount >= GC_SIZE_DUMMY) {
91         GC_SET_SIZE(o, GC_SIZE_DUMMY);
92     } else {
93         GC_SET_SIZE(o, wordcount);
94     }
95
96 }
97
98
99 s4 heap_increase_size() {
100         void *p;
101         s4    increasesize;
102         s4    newsize;
103
104         /* TODO: locking for threads!!! */
105
106         /* only a quick sanity check */
107         GC_ASSERT(heap_current_size <= heap_maximal_size);
108
109         /* check if we are allowed to enlarge the heap */
110         if (heap_current_size == heap_maximal_size)
111                 exceptions_throw_outofmemory_exit();
112
113         /* TODO: find out how much to increase the heap??? */
114         increasesize = heap_maximal_size - heap_current_size;
115         GC_LOG( dolog("GC: Increasing Heap Size by %d", increasesize); );
116
117         /* allocate new heap from the system */
118         newsize = heap_current_size + increasesize;
119         p = malloc(newsize);
120
121         /* check if the newly allocated heap exists */
122         if (p == NULL)
123                 exceptions_throw_outofmemory_exit(); 
124
125         /* TODO: copy the old content to the new heap */
126         /* TODO: find a complete rootset and update it to the new position */
127         /* TODO: free the old heap */
128
129         /* set the new values */
130         /*heap_ptr = p + (heap_ptr - heap_base);
131         heap_base = p;*/
132         heap_current_size = newsize;
133
134         GC_LOG( dolog("GC: Increasing Heap Size was successful");
135                         heap_println_usage(); );
136
137         /* only a quick sanity check */
138         GC_ASSERT(heap_current_size <= heap_maximal_size);
139
140         return increasesize;
141 }
142
143
144 s4 heap_get_hashcode(java_objectheader *o)
145 {
146         s4 hashcode;
147
148         if (!o)
149                 return 0;
150
151         /* TODO: we need to lock the object here i think!!! */
152
153         /* check if there is a hash attached to this object */
154         if (GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED)) {
155
156                 hashcode = *( (s4 *) ( ((u1 *) o) + get_object_size(o) - SIZEOF_VOID_P ) ); /* TODO: clean this up!!! */
157                 GC_LOG2( dolog("GC: Hash re-taken: %d (0x%08x)", hashcode, hashcode); );
158
159         } else {
160
161                 GC_SET_FLAGS(o, HDRFLAG_HASH_TAKEN);
162
163                 hashcode = (s4) (ptrint) o;
164                 GC_LOG2( dolog("GC: Hash taken: %d (0x%08x)", hashcode, hashcode); );
165
166         }
167
168         return hashcode;
169 }
170
171
172 static java_objectheader *heap_alloc_intern(u4 bytelength, regioninfo_t *region)
173 {
174         java_objectheader *p;
175
176         /* only a quick sanity check */
177         GC_ASSERT(region);
178         GC_ASSERT(bytelength >= sizeof(java_objectheader));
179
180         /* align objects in memory */
181         bytelength = GC_ALIGN(bytelength, GC_ALIGN_SIZE);
182
183         /* lock the region */
184         LOCK_MONITOR_ENTER(region);
185
186         /* check for sufficient free space */
187         if (bytelength > region->free) {
188                 dolog("GC: Region out of memory!");
189                 gc_collect();
190                 return NULL;
191         }
192
193         /* allocate the object in this region */
194         p = (java_objectheader *) region->ptr;
195         region->ptr += bytelength;
196         region->free -= bytelength;
197
198         /* unlock the region */
199         LOCK_MONITOR_EXIT(region);
200         GC_LOG( region = NULL; );
201
202         /* clear allocated memory region */
203         GC_ASSERT(p);
204         MSET(p, 0, u1, bytelength);
205
206         /* set the header information */
207         heap_init_objectheader(p, bytelength);
208
209         return p;
210 }
211
212
213 /* heap_allocate ***************************************************************
214
215    Allocates memory on the Java heap.
216
217 *******************************************************************************/
218
219 void *heap_allocate(u4 bytelength, u4 references, methodinfo *finalizer)
220 {
221         java_objectheader *p;
222 #if defined(ENABLE_RT_TIMING)
223         struct timespec time_start, time_end;
224 #endif
225
226         RT_TIMING_GET_TIME(time_start);
227
228         p = heap_alloc_intern(bytelength, heap_region_main);
229
230         if (p == NULL)
231                 return NULL;
232
233 #if defined(GCCONF_HDRFLAG_REFERENCING)
234         /* We can't use a bool here for references, as it's passed as a
235            bitmask in builtin_new.  Thus we check for != 0. */
236         if (references != 0) {
237                 GC_SET_FLAGS(p, HDRFLAG_REFERENCING);
238         }
239 #endif
240
241         /* take care of finalization stuff */
242         if (finalizer != NULL) {
243
244                 /* set the header bit */
245                 /* TODO: do we really need this??? */
246                 /* TODO: can this be overwritten by cloning??? */
247                 GC_SET_FLAGS(p, GC_FLAG_FINALIZER);
248
249                 /* register the finalizer for this object */
250                 final_register(p, finalizer);
251         }
252
253         RT_TIMING_GET_TIME(time_end);
254         RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_GC_ALLOC);
255
256         return p;
257 }
258
259
260 void *heap_alloc_uncollectable(u4 bytelength)
261 {
262         java_objectheader *p;
263
264         /* loader.c does this a lot for classes with fieldscount equal zero */
265         if (bytelength == 0)
266                 return NULL;
267
268         p = heap_alloc_intern(bytelength, heap_region_sys);
269
270         if (p == NULL)
271                 return NULL;
272
273         /* TODO: can this be overwritten by cloning??? */
274         /* remember this object as uncollectable */
275         GC_SET_FLAGS(p, HDRFLAG_UNCOLLECTABLE);
276
277         return p;
278 }
279
280
281 void heap_free(void *p)
282 {
283         GC_LOG( dolog("GC: Free %p", p); );
284         GC_ASSERT(0);
285 }
286
287
288 /* Debugging ******************************************************************/
289
290 #if !defined(NDEBUG)
291 void heap_println_usage()
292 {
293         printf("Current Heap Usage: Size=%d Free=%d\n",
294                         heap_current_size, heap_region_main->free);
295
296         GC_ASSERT(heap_current_size == heap_region_main->size);
297 }
298 #endif
299
300
301 #if !defined(NDEBUG)
302 void heap_print_object_flags(java_objectheader *o)
303 {
304         printf("0x%02x [%s%s%s%s%s]",
305                 GC_GET_SIZE(o),
306                 GC_TEST_FLAGS(o, GC_FLAG_FINALIZER)     ? "F" : " ",
307                 GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED) ? "A" : " ",
308                 GC_TEST_FLAGS(o, HDRFLAG_HASH_TAKEN)    ? "T" : " ",
309                 GC_TEST_FLAGS(o, HDRFLAG_UNCOLLECTABLE) ? "U" : " ",
310                 GC_TEST_FLAGS(o, GC_FLAG_MARKED)        ? "M" : " ");
311 }
312 #endif
313
314
315 #if !defined(NDEBUG)
316 void heap_print_object(java_objectheader *o)
317 {
318         java_arrayheader  *a;
319         classinfo         *c;
320
321         /* check for null pointers */
322         if (o == NULL) {
323                 printf("(NULL)");
324                 return;
325         }
326
327         /* print general information */
328 #if SIZEOF_VOID_P == 8
329         assert(0);
330 #else
331         printf("0x%08x: ", (void *) o);
332 #endif
333         heap_print_object_flags(o);
334         printf(" ");
335
336         /* TODO */
337         /* maybe this is not really an object */
338         if (/*IS_CLASS*/ o->vftbl->class == class_java_lang_Class) {
339
340                 /* get the class information */
341                 c = (classinfo *) o;
342
343                 /* print the class information */
344                 printf("CLS ");
345                 class_print(c);
346
347         } else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
348
349                 /* get the array information */
350                 a = (java_arrayheader *) o;
351                 c = o->vftbl->class;
352
353                 /* print the array information */
354                 printf("ARR ");
355                 /*class_print(c);*/
356                 utf_display_printable_ascii_classname(c->name);
357                 printf(" (size=%d)", a->size);
358
359         } else /*IS_OBJECT*/ {
360
361                 /* get the object class */
362                 c = o->vftbl->class;
363
364                 /* print the object information */
365                 printf("OBJ ");
366                 /*class_print(c);*/
367                 utf_display_printable_ascii_classname(c->name);
368                 if (c == class_java_lang_String) {
369                         printf(" (string=\"");
370                         utf_display_printable_ascii(
371                                         javastring_toutf((java_lang_String *) o, false));
372                         printf("\")");
373                 }
374
375         }
376 }
377 #endif
378
379 #if !defined(NDEBUG)
380 void heap_dump_region(regioninfo_t *region, bool marked_only)
381 {
382         java_objectheader *o;
383         u4                 o_size;
384
385         /* some basic sanity checks */
386         GC_ASSERT(region->base < region->ptr);
387
388         printf("Heap-Dump:\n");
389
390         /* walk the region in a linear style */
391         o = (java_objectheader *) region->base;
392         while (o < region->ptr) {
393
394                 if (!marked_only || GC_IS_MARKED(o)) {
395                         printf("\t");
396                         heap_print_object(o);
397                         printf("\n");
398                 }
399
400                 /* get size of object */
401                 o_size = get_object_size(o);
402
403                 /* walk to next object */
404                 GC_ASSERT(o_size != 0);
405                 o = ((u1 *) o) + o_size;
406         }
407
408         printf("Heap-Dump finished.\n");
409 }
410 #endif
411
412
413 s4 get_object_size(java_objectheader *o)
414 {
415         java_arrayheader *a;
416         classinfo        *c;
417         s4                o_size;
418
419         /* we can assume someone initialized the header */
420         GC_ASSERT(o->hdrflags != 0);
421
422         /* get the wordcount from the header */
423         o_size = GC_GET_SIZE(o);
424
425         /* maybe we need to calculate the size by hand */
426         if (o_size != GC_SIZE_DUMMY) {
427                 GC_ASSERT(o_size != 0);
428                 o_size = o_size << 2;
429         } else {
430
431                 /* TODO */
432                 /* maybe this is not really an object */
433                 if (/*IS_CLASS*/ o->vftbl->class == class_java_lang_Class) {
434                         /* we know the size of a classinfo */
435                         o_size = sizeof(classinfo);
436
437                 } else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
438                         /* compute size of this array */
439                         a = (java_arrayheader *) o;
440                         c = o->vftbl->class;
441                         o_size = c->vftbl->arraydesc->dataoffset +
442                                         a->size * c->vftbl->arraydesc->componentsize;
443
444                 } else /*IS_OBJECT*/ {
445                         /* get the object size */
446                         c = o->vftbl->class;
447                         o_size = c->instancesize;
448                         GC_LOG( dolog("Got size (from Class): %d bytes", o_size); );
449                 }
450         
451         }
452
453         /* align the size */
454         o_size = GC_ALIGN(o_size, GC_ALIGN_SIZE);
455
456         /* the hashcode attached to this object might increase the size */
457         if (GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED))
458                 o_size += SIZEOF_VOID_P;
459
460         return o_size;
461 }
462
463
464 /*
465  * These are local overrides for various environment variables in Emacs.
466  * Please do not remove this and leave it at the end of the file, where
467  * Emacs will automagically detect them.
468  * ---------------------------------------------------------------------
469  * Local variables:
470  * mode: c
471  * indent-tabs-mode: t
472  * c-basic-offset: 4
473  * tab-width: 4
474  * End:
475  * vim:noexpandtab:sw=4:ts=4:
476  */