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