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