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