* src/vm/jit/replace.c (replace_find_replacement_point): Fixed assertion.
[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
206         /* clear allocated memory region */
207         GC_ASSERT(p);
208         MSET(p, 0, u1, bytelength);
209
210         /* set the header information */
211         heap_init_objectheader(p, bytelength);
212
213         return p;
214 }
215
216
217 /* heap_alloc ******************************************************************
218
219    Allocates memory on the Java heap.
220
221 *******************************************************************************/
222
223 void *heap_alloc(u4 size, u4 references, methodinfo *finalizer, bool collect)
224 {
225         java_objectheader *p;
226 #if defined(ENABLE_RT_TIMING)
227         struct timespec time_start, time_end;
228 #endif
229
230         RT_TIMING_GET_TIME(time_start);
231
232         p = heap_alloc_intern(size, heap_region_main, collect);
233
234         if (p == NULL)
235                 return NULL;
236
237 #if defined(GCCONF_HDRFLAG_REFERENCING)
238         /* We can't use a bool here for references, as it's passed as a
239            bitmask in builtin_new.  Thus we check for != 0. */
240         if (references != 0) {
241                 GC_SET_FLAGS(p, HDRFLAG_REFERENCING);
242         }
243 #endif
244
245         /* register the finalizer for this object */
246         if (finalizer != NULL) {
247                 final_register(p, finalizer);
248         }
249
250         RT_TIMING_GET_TIME(time_end);
251         RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_GC_ALLOC);
252
253         return p;
254 }
255
256
257 void *heap_alloc_uncollectable(u4 size)
258 {
259         java_objectheader *p;
260
261         /* loader.c does this a lot for classes with fieldscount equal zero */
262         if (size == 0)
263                 return NULL;
264
265         p = heap_alloc_intern(size, heap_region_sys, false);
266
267         if (p == NULL)
268                 return NULL;
269
270         /* TODO: can this be overwritten by cloning??? */
271         /* remember this object as uncollectable */
272         GC_SET_FLAGS(p, HDRFLAG_UNCOLLECTABLE);
273
274         return p;
275 }
276
277
278 void heap_free(void *p)
279 {
280         GC_LOG( dolog("GC: Free %p", p); );
281         GC_ASSERT(0);
282 }
283
284
285 /* Debugging ******************************************************************/
286
287 #if !defined(NDEBUG)
288 void heap_println_usage()
289 {
290         printf("Current Heap Usage: Size=%d Free=%d\n",
291                         heap_current_size, heap_region_main->free);
292
293         GC_ASSERT(heap_current_size == heap_region_main->size);
294 }
295 #endif
296
297
298 #if !defined(NDEBUG)
299 void heap_print_object_flags(java_objectheader *o)
300 {
301         printf("0x%02x [%s%s%s%s]",
302                 GC_GET_SIZE(o),
303                 GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED) ? "A" : " ",
304                 GC_TEST_FLAGS(o, HDRFLAG_HASH_TAKEN)    ? "T" : " ",
305                 GC_TEST_FLAGS(o, HDRFLAG_UNCOLLECTABLE) ? "U" : " ",
306                 GC_TEST_FLAGS(o, GC_FLAG_MARKED)        ? "M" : " ");
307 }
308 #endif
309
310
311 #if !defined(NDEBUG)
312 void heap_print_object(java_objectheader *o)
313 {
314         java_arrayheader  *a;
315         classinfo         *c;
316
317         /* check for null pointers */
318         if (o == NULL) {
319                 printf("(NULL)");
320                 return;
321         }
322
323         /* print general information */
324 #if SIZEOF_VOID_P == 8
325         printf("0x%016llx: ", (unsigned long long) o);
326 #else
327         printf("0x%08lx: ", (unsigned long) o);
328 #endif
329
330         /* check for invalid heap references */
331         if (!POINTS_INTO(o, heap_region_main->base, heap_region_main->end) &&
332                 !POINTS_INTO(o, heap_region_sys->base, heap_region_sys->end))
333         {
334                 printf("<<< No Heap Reference >>>");
335                 return;
336         }
337
338         /* print object flags */
339         heap_print_object_flags(o);
340         printf(" ");
341
342         GC_ASSERT(o->vftbl);
343
344         /* TODO */
345         /* maybe this is not really an object */
346         if (/*IS_CLASS*/ o->vftbl->class == class_java_lang_Class) {
347
348                 /* get the class information */
349                 c = (classinfo *) o;
350
351                 /* print the class information */
352                 printf("CLS ");
353                 class_print(c);
354
355         } else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
356
357                 /* get the array information */
358                 a = (java_arrayheader *) o;
359                 c = o->vftbl->class;
360
361                 /* print the array information */
362                 printf("ARR ");
363                 /*class_print(c);*/
364                 utf_display_printable_ascii_classname(c->name);
365                 printf(" (size=%d)", a->size);
366
367         } else /*IS_OBJECT*/ {
368
369                 /* get the object class */
370                 c = o->vftbl->class;
371
372                 /* print the object information */
373                 printf("OBJ ");
374                 /*class_print(c);*/
375                 utf_display_printable_ascii_classname(c->name);
376                 if (c == class_java_lang_String) {
377                         printf(" (string=\"");
378                         utf_display_printable_ascii(
379                                         javastring_toutf((java_lang_String *) o, false));
380                         printf("\")");
381                 }
382
383         }
384 }
385 #endif
386
387 #if !defined(NDEBUG)
388 void heap_dump_region(regioninfo_t *region, bool marked_only)
389 {
390         java_objectheader *o;
391         u4                 o_size;
392
393         /* some basic sanity checks */
394         GC_ASSERT(region->base <= region->ptr);
395
396         printf("Heap-Dump:\n");
397
398         /* walk the region in a linear style */
399         o = (java_objectheader *) region->base;
400         while (o < region->ptr) {
401
402                 if (!marked_only || GC_IS_MARKED(o)) {
403                         printf("\t");
404                         heap_print_object(o);
405                         printf("\n");
406                 }
407
408                 /* get size of object */
409                 o_size = get_object_size(o);
410
411                 /* walk to next object */
412                 GC_ASSERT(o_size != 0);
413                 o = ((u1 *) o) + o_size;
414         }
415
416         printf("Heap-Dump finished.\n");
417 }
418 #endif
419
420
421 s4 get_object_size(java_objectheader *o)
422 {
423         java_arrayheader *a;
424         classinfo        *c;
425         s4                o_size;
426
427         /* we can assume someone initialized the header */
428         GC_ASSERT(o->hdrflags != 0);
429
430         /* get the wordcount from the header */
431         o_size = GC_GET_SIZE(o);
432
433         /* maybe we need to calculate the size by hand */
434         if (o_size != GC_SIZE_DUMMY) {
435                 GC_ASSERT(o_size != 0);
436                 o_size = o_size << 2;
437         } else {
438
439                 /* TODO */
440                 /* maybe this is not really an object */
441                 if (/*IS_CLASS*/ o->vftbl->class == class_java_lang_Class) {
442                         /* we know the size of a classinfo */
443                         o_size = sizeof(classinfo);
444
445                 } else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
446                         /* compute size of this array */
447                         a = (java_arrayheader *) o;
448                         c = o->vftbl->class;
449                         o_size = c->vftbl->arraydesc->dataoffset +
450                                         a->size * c->vftbl->arraydesc->componentsize;
451
452                 } else /*IS_OBJECT*/ {
453                         /* get the object size */
454                         c = o->vftbl->class;
455                         o_size = c->instancesize;
456                         GC_LOG( dolog("Got size (from Class): %d bytes", o_size); );
457                 }
458         
459         }
460
461         /* align the size */
462         o_size = GC_ALIGN(o_size, GC_ALIGN_SIZE);
463
464         /* the hashcode attached to this object might increase the size */
465         if (GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED))
466                 o_size += SIZEOF_VOID_P;
467
468         return o_size;
469 }
470
471
472 /*
473  * These are local overrides for various environment variables in Emacs.
474  * Please do not remove this and leave it at the end of the file, where
475  * Emacs will automagically detect them.
476  * ---------------------------------------------------------------------
477  * Local variables:
478  * mode: c
479  * indent-tabs-mode: t
480  * c-basic-offset: 4
481  * tab-width: 4
482  * End:
483  * vim:noexpandtab:sw=4:ts=4:
484  */