* src/vm/vm.c, src/vm/vm.h: Moved to .cpp.
[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 */
26
27
28 #include "config.h"
29 #include "vm/types.h"
30
31 #include "threads/lock-common.h"
32
33 #include "gc.h"
34 #include "final.h"
35 #include "heap.h"
36 #include "mark.h"
37 #include "region.h"
38 #include "mm/memory.h"
39 #include "native/include/java_lang_String.h"
40 #include "native/llni.h"
41 #include "toolbox/logging.h"
42 #include "vm/global.h"
43 #include "vm/stringlocal.h"
44 #include "vm/vm.hpp"
45 #include "vmcore/options.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_object_t *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_object_t  *o;
90         java_object_t  *ref;
91         java_object_t **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].ref;
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_object_t *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_object_t *heap_alloc_intern(u4 bytelength, regioninfo_t *region, bool collect)
234 {
235         java_object_t *p;
236
237         /* only a quick sanity check */
238         GC_ASSERT(region);
239         GC_ASSERT(bytelength >= sizeof(java_object_t));
240
241 #if !defined(NDEBUG) && defined(ENABLE_THREADS)
242         /* check the current VM state for sanity */
243         GC_ASSERT(!THREADOBJECT->gc_critical);
244         GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
245 #endif
246
247         /* align objects in memory */
248         bytelength = GC_ALIGN(bytelength, GC_ALIGN_SIZE);
249
250         /* lock the region */
251         LOCK_MONITOR_ENTER(region);
252
253 #if !defined(NDEBUG)
254         /* heavy stress test */
255         if (opt_GCStress && collect)
256                 gc_collect(0);
257 #endif
258
259         /* check for sufficient free space */
260         if (bytelength > region->free) {
261                 dolog("GC: Region out of memory! (collect=%d)", collect);
262
263                 if (collect) {
264                         gc_collect(0);
265 #if 0
266                         GC_ASSERT(region->free >= bytelength);
267 #else
268                         if (region->free < bytelength) {
269                                 dolog("GC: OOM OOM OOM OOM OOM OOM OOM OOM OOM OOM");
270                                 exceptions_throw_outofmemoryerror();
271                                 return NULL;
272                         }
273 #endif
274                 } else
275                         return NULL;
276         }
277
278         /* allocate the object in this region */
279         p = (java_object_t *) region->ptr;
280         region->ptr += bytelength;
281         region->free -= bytelength;
282
283         /* unlock the region */
284         LOCK_MONITOR_EXIT(region);
285
286         /* clear allocated memory region */
287         GC_ASSERT(p);
288         MSET(p, 0, u1, bytelength);
289
290         /* set the header information */
291         heap_init_objectheader(p, bytelength);
292
293         return p;
294 }
295
296
297 /* heap_alloc ******************************************************************
298
299    Allocates memory on the Java heap.
300
301 *******************************************************************************/
302
303 void *heap_alloc(u4 size, u4 references, methodinfo *finalizer, bool collect)
304 {
305         java_object_t *p;
306         java_handle_t *h;
307 #if defined(ENABLE_RT_TIMING)
308         struct timespec time_start, time_end;
309 #endif
310
311         RT_TIMING_GET_TIME(time_start);
312
313         p = heap_alloc_intern(size, heap_region_main, collect);
314
315         if (p == NULL)
316                 return NULL;
317
318 #if defined(GCCONF_HDRFLAG_REFERENCING)
319         /* We can't use a bool here for references, as it's passed as a
320            bitmask in builtin_new.  Thus we check for != 0. */
321         if (references != 0) {
322                 GC_SET_FLAGS(p, HDRFLAG_REFERENCING);
323         }
324 #endif
325
326         /* register the finalizer for this object */
327         if (finalizer != NULL) {
328                 final_register(p, finalizer);
329         }
330
331         h = LLNI_WRAP(p);
332
333         RT_TIMING_GET_TIME(time_end);
334         RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_GC_ALLOC);
335
336         return h;
337 }
338
339
340 void *heap_alloc_uncollectable(u4 size)
341 {
342         java_object_t *p;
343
344         /* loader.c does this a lot for classes with fieldscount equal zero */
345         if (size == 0)
346                 return NULL;
347
348         p = heap_alloc_intern(size, heap_region_sys, false);
349
350         if (p == NULL)
351                 return NULL;
352
353         /* TODO: can this be overwritten by cloning??? */
354         /* remember this object as uncollectable */
355         GC_SET_FLAGS(p, HDRFLAG_UNCOLLECTABLE);
356
357         return p;
358 }
359
360
361 void heap_free(void *p)
362 {
363         GC_LOG( dolog("GC: Free %p", p); );
364         GC_ASSERT(0);
365 }
366
367
368 /* Debugging ******************************************************************/
369
370 #if !defined(NDEBUG)
371 void heap_println_usage()
372 {
373         printf("Current Heap Usage: Size=%d Free=%d\n",
374                         heap_current_size, heap_region_main->free);
375
376         GC_ASSERT(heap_current_size == heap_region_main->size);
377 }
378 #endif
379
380
381 #if !defined(NDEBUG)
382 void heap_print_object_flags(java_object_t *o)
383 {
384         printf("0x%02x [%s%s%s%s]",
385                 GC_GET_SIZE(o),
386                 GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED) ? "A" : " ",
387                 GC_TEST_FLAGS(o, HDRFLAG_HASH_TAKEN)    ? "T" : " ",
388                 GC_TEST_FLAGS(o, HDRFLAG_UNCOLLECTABLE) ? "U" : " ",
389                 GC_TEST_FLAGS(o, GC_FLAG_MARKED)        ? "M" : " ");
390 }
391 #endif
392
393
394 #if !defined(NDEBUG)
395 void heap_print_object(java_object_t *o)
396 {
397         java_array_t *a;
398         classinfo    *c;
399
400         /* check for null pointers */
401         if (o == NULL) {
402                 printf("(NULL)");
403                 return;
404         }
405
406         /* print general information */
407 #if SIZEOF_VOID_P == 8
408         printf("0x%016llx: ", (unsigned long long) o);
409 #else
410         printf("0x%08lx: ", (unsigned long) o);
411 #endif
412
413         /* check for invalid heap references */
414         if (!POINTS_INTO(o, heap_region_main->base, heap_region_main->end) &&
415                 !POINTS_INTO(o, heap_region_sys->base, heap_region_sys->end))
416         {
417                 printf("<<< No Heap Reference >>>");
418                 return;
419         }
420
421         /* print object flags */
422         heap_print_object_flags(o);
423         printf(" ");
424
425         GC_ASSERT(o->vftbl);
426
427         /* TODO */
428         /* maybe this is not really an object */
429         if (/*IS_CLASS*/ o->vftbl->class == class_java_lang_Class) {
430
431                 /* get the class information */
432                 c = (classinfo *) o;
433
434                 /* print the class information */
435                 printf("CLS ");
436                 class_print(c);
437
438         } else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
439
440                 /* get the array information */
441                 a = (java_array_t *) o;
442                 c = o->vftbl->class;
443
444                 /* print the array information */
445                 printf("ARR ");
446                 /*class_print(c);*/
447                 utf_display_printable_ascii_classname(c->name);
448                 printf(" (size=%d)", a->size);
449
450         } else /*IS_OBJECT*/ {
451
452                 /* get the object class */
453                 c = o->vftbl->class;
454
455                 /* print the object information */
456                 printf("OBJ ");
457                 /*class_print(c);*/
458                 utf_display_printable_ascii_classname(c->name);
459                 if (c == class_java_lang_String) {
460                         printf(" (string=\"");
461                         utf_display_printable_ascii(
462                                         javastring_toutf((java_lang_String *) o, false));
463                         printf("\")");
464                 }
465
466         }
467 }
468 #endif
469
470 #if !defined(NDEBUG)
471 void heap_dump_region(regioninfo_t *region, bool marked_only)
472 {
473         java_object_t *o;
474         u4             o_size;
475
476         /* some basic sanity checks */
477         GC_ASSERT(region->base <= region->ptr);
478
479         printf("Heap-Dump:\n");
480
481         /* walk the region in a linear style */
482         o = (java_object_t *) region->base;
483         while (o < region->ptr) {
484
485                 if (!marked_only || GC_IS_MARKED(o)) {
486                         printf("\t");
487                         heap_print_object(o);
488                         printf("\n");
489                 }
490
491                 /* get size of object */
492                 o_size = get_object_size(o);
493
494                 /* walk to next object */
495                 GC_ASSERT(o_size != 0);
496                 o = ((u1 *) o) + o_size;
497         }
498
499         printf("Heap-Dump finished.\n");
500 }
501 #endif
502
503
504 s4 get_object_size(java_object_t *o)
505 {
506         java_array_t *a;
507         classinfo    *c;
508         s4            o_size;
509
510         /* we can assume someone initialized the header */
511         GC_ASSERT(o->hdrflags != 0);
512
513         /* get the wordcount from the header */
514         o_size = GC_GET_SIZE(o);
515
516         /* maybe we need to calculate the size by hand */
517         if (o_size != GC_SIZE_DUMMY) {
518                 GC_ASSERT(o_size != 0);
519                 o_size = o_size << 2;
520         } else {
521
522                 /* TODO */
523                 /* maybe this is not really an object */
524                 if (/*IS_CLASS*/ o->vftbl->class == class_java_lang_Class) {
525                         /* we know the size of a classinfo */
526                         o_size = sizeof(classinfo);
527
528                 } else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
529                         /* compute size of this array */
530                         a = (java_array_t *) o;
531                         c = o->vftbl->class;
532                         o_size = c->vftbl->arraydesc->dataoffset +
533                                         a->size * c->vftbl->arraydesc->componentsize;
534
535                 } else /*IS_OBJECT*/ {
536                         /* get the object size */
537                         c = o->vftbl->class;
538                         o_size = c->instancesize;
539                         GC_LOG( dolog("Got size (from Class): %d bytes", o_size); );
540                 }
541         
542         }
543
544         /* align the size */
545         o_size = GC_ALIGN(o_size, GC_ALIGN_SIZE);
546
547         /* the hashcode attached to this object might increase the size */
548         if (GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED))
549                 o_size += SIZEOF_VOID_P;
550
551         return o_size;
552 }
553
554
555 /*
556  * These are local overrides for various environment variables in Emacs.
557  * Please do not remove this and leave it at the end of the file, where
558  * Emacs will automagically detect them.
559  * ---------------------------------------------------------------------
560  * Local variables:
561  * mode: c
562  * indent-tabs-mode: t
563  * c-basic-offset: 4
564  * tab-width: 4
565  * End:
566  * vim:noexpandtab:sw=4:ts=4:
567  */