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