a2296193536e5c8c6b23eefdc89155ba3d729ea0
[cacao.git] / mm / heap2.c
1 #include <stddef.h>
2 #include <unistd.h>             /* getpagesize, mmap, ... */
3 #include <sys/mman.h>
4 #ifndef MAP_FAILED
5 #define MAP_FAILED ((void*) -1)
6 #endif
7 #include <sys/types.h>
8 #include <stdio.h>
9 #include "../asmpart.h"
10 #include "../callargs.h"
11 #include "../threads/thread.h"
12 #include "../threads/locks.h"
13 #include <assert.h>
14
15 #include "mm.h"
16
17 #define PAGESIZE_MINUS_ONE      (getpagesize() - 1)
18
19 #undef ALIGN
20 #undef OFFSET
21
22 #define false 0
23 #define true 1
24
25 #include "allocator.h" /* rev. 1 allocator */
26 #include "bitmap2.h"   /* rev. 2 bitmap management */
27
28 bool collectverbose;
29
30 void gc_call (void);
31
32 /* --- macros */
33
34 #define align_size(size)        ((size) & ~((1 << ALIGN) - 1))
35 #define MAP_ADDRESS                     (void*) 0x10000000
36
37 #define VERBOSITY_MESSAGE       1
38 #define VERBOSITY_DEBUG         2
39 #define VERBOSITY_MISTRUST      3
40 #define VERBOSITY_TRACE         4
41 #define VERBOSITY_PARANOIA      5
42 #define VERBOSITY_LIFESPAN      6
43
44 //#define VERBOSITY                     VERBOSITY_MESSAGE
45 //#define VERBOSITY                     VERBOSITY_PARANOIA
46 #define VERBOSITY                       VERBOSITY_LIFESPAN
47
48 /* --- file-wide variables */
49
50 static void*    heap_base = NULL;
51 static SIZE             heap_size = 0;
52 static void*    heap_top = NULL;
53 static void*    heap_limit = NULL;
54 static void*    heap_next_collection = NULL;
55
56 static bitmap_t* start_bitmap = NULL;
57 static BITBLOCK* start_bits = NULL;
58 static bitmap_t* reference_bitmap = NULL;
59 static BITBLOCK* reference_bits = NULL;
60 static bitmap_t* mark_bitmap = NULL;
61 static BITBLOCK* mark_bits = NULL;
62
63 static void**   stackbottom = NULL;
64
65 typedef struct address_list_node {
66         void* address;
67         struct address_list_node* next;
68 } address_list_node;
69
70 static address_list_node* references = NULL;
71 static address_list_node* finalizers = NULL;
72
73 /* --- implementation */
74
75 void 
76 heap_init (SIZE size, 
77                    SIZE startsize, /* when should we collect for the first time ? */
78                    void **in_stackbottom)
79 {
80 #if VERBOSITY == VERBOSITY_MESSAGE
81         fprintf(stderr, "The heap is verbose.\n");
82 #elif VERBOSITY == VERBOSITY_DEBUG
83         fprintf(stderr, "The heap is in debug mode.\n");
84 #elif VERBOSITY == VERBOSITY_MISTRUST
85         fprintf(stderr, "The heap is mistrusting us.\n");
86 #elif VERBOSITY == VERBOSITY_TRACE
87         fprintf(stderr, "The heap is outputting trace information.\n");
88 #elif VERBOSITY == VERBOSITY_PARANOIA
89         fprintf(stderr, "The heap is paranoid.\n");
90 #elif VERBOSITY == VERBOSITY_LIFESPAN
91         fprintf(stderr, "The heap is collecting lifespan information.\n");
92 #endif
93
94         /* 1. Initialise the freelists & reset the allocator's state */
95         allocator_init(); 
96
97         /* 2. Allocate at least (alignment!) size bytes of memory for the heap */
98         heap_size = align_size(size + ((1 << ALIGN) - 1));
99
100 #if 1
101         /* For now, we'll try to map in the stack at a fixed address...
102            ...this will change soon. -- phil. */
103         heap_base = (void*) mmap (MAP_ADDRESS, 
104                                                           ((size_t)heap_size + PAGESIZE_MINUS_ONE) & ~PAGESIZE_MINUS_ONE,
105                                                           PROT_READ | PROT_WRITE, 
106                                                           MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 
107                                                           -1, 
108                                                           (off_t) 0);
109 #else
110         heap_base = malloc(heap_size);
111 #endif
112
113         if (heap_base == MAP_FAILED) {
114                 /* unable to allocate the requested amount of memory */
115                 fprintf(stderr, "The queen, mylord, is dead!\n");
116                 exit(-1);
117         }
118
119         /* 3. Allocate the bitmaps */
120         start_bitmap = bitmap_allocate(heap_base, heap_size);
121         reference_bitmap = bitmap_allocate(heap_base, heap_size);
122         mark_bitmap = bitmap_allocate(heap_base, heap_size);
123
124         start_bits = start_bitmap->bitmap;
125     reference_bits = reference_bitmap->bitmap;
126     mark_bits = mark_bitmap->bitmap;
127
128         /* 4. Mark the first free-area as an object-start */
129         bitmap_setbit(start_bits, heap_base);
130
131         /* 5. Initialise the heap's state (heap_top, etc.) */
132         stackbottom = in_stackbottom; /* copy the stackbottom */
133
134         heap_top = heap_base; /* the current end of the heap (just behind the last allocated object) */
135         heap_limit = heap_base + heap_size; /* points just behind the last accessible block of the heap */
136
137         /* 6. calculate a useful first collection limit */
138         /* This is extremly primitive at this point... 
139            we should replace it with something more useful -- phil. */
140         heap_next_collection = heap_base + (heap_size / 8);
141
142         /* 7. Init the global reference lists & finalizer addresses */
143         references = NULL;
144         finalizers = NULL;
145 }
146
147 void 
148 heap_close (void)
149 {
150         /* 1. Clean up on the heap... finalize all remaining objects */
151 #if 0
152         address_list_node* curr = finalizers;
153         while (curr) {
154                 address_list_node* prev = curr;
155
156                 if (bitmap_testbit(start_bits, curr->address))
157                         asm_calljavamethod(((java_objectheader*)(curr->address))->vftbl->class->finalizer, curr->address, NULL, NULL, NULL);
158
159                 curr = curr->next;
160                 free(prev);
161         }
162 #endif
163
164         /* 2. Release the bitmaps */
165         bitmap_release(start_bitmap);
166         bitmap_release(reference_bitmap);
167         bitmap_release(mark_bitmap);
168
169         /* 3. Release the memory allocated to the heap */
170         if (heap_base)
171                 munmap(heap_base, heap_size);
172 }
173
174 static
175 inline
176 void
177 heap_add_address_to_address_list(address_list_node** list, void* address)
178 {
179         /* Note: address lists are kept sorted to simplify finalization */
180
181         address_list_node* new_node = malloc(sizeof(address_list_node));
182         new_node->address = address;
183         new_node->next = NULL;
184
185         while (*list && (*list)->next) {
186 #if VERBOSITY >= VERBOSITY_PARANOIA
187                 if ((*list)->address == address)
188                         fprintf(stderr,
189                                         "Attempt to add a duplicate adress to an adress list.\n");
190 #endif
191
192                 if ((*list)->next->address < address)
193                         list = &(*list)->next;
194                 else {
195                         new_node->next = *list;
196                         *list = new_node;
197                         return;
198                 }                       
199         }
200
201         new_node->next = *list;
202         *list = new_node;
203 }
204
205 static
206 inline
207 void
208 heap_add_finalizer_for_object_at(void* addr)
209 {
210         /* Finalizers seem to be very rare... for this reason, I keep a linked
211            list of object addresses, which have a finalizer attached. This list
212            is kept in ascending order according to the order garbage is freed.
213            This list is currently kept separate from the heap, but should be 
214            moved onto it, but some JIT-marker code to handle these special
215            objects will need to be added first. -- phil. */
216
217         heap_add_address_to_address_list(&finalizers, addr);
218 }
219
220 void* 
221 heap_allocate (SIZE               in_length, 
222                            bool           references, 
223                            methodinfo *finalizer)
224 {
225         SIZE    length = align_size(in_length + ((1 << ALIGN) - 1)); 
226         void*   free_chunk = NULL;
227
228 #if VERBOSITY >= VERBOSITY_MISTRUST && 0
229         /* check for misaligned in_length parameter */
230         if (length != in_length)
231                 fprintf(stderr,
232                                 "heap2.c: heap_allocate was passed unaligned in_length parameter: %ld, \n         aligned to %ld. (mistrust)\n",
233                                 in_length, length);
234 #endif
235
236         // fprintf(stderr, "heap_allocate: 0x%lx (%ld) requested, 0x%lx (%ld) aligned\n", in_length, in_length, length, length);
237
238         if (finalizer)
239                 fprintf(stderr, "finalizer detected\n");
240
241 #if VERBOSITY >= VERBOSITY_LIFESPAN 
242         /* perform garbage collection to collect data for lifespan analysis */
243         if (heap_top > heap_base)
244                 gc_call();
245 #endif
246
247         intsDisable();
248
249  retry:
250         /* 1. attempt to get a free block with size >= length from the freelists */
251         free_chunk = allocator_alloc(length);
252
253         /* 2. if unsuccessful, try alternative allocation strategies */
254         if (!free_chunk) {
255                 /* 2.a if the collection threshold would be exceeded, collect the heap */
256                 if (heap_top + length > heap_next_collection) {
257                         /* 2.a.1. collect if the next_collection threshold would be exceeded */
258                         gc_call();
259
260                         /* 2.a.2. we just ran a collection, recheck the freelists */
261                         free_chunk = allocator_alloc(length);
262                         if (free_chunk)
263                                 goto success;
264
265                         /* 2.a.3. we can't satisfy the request from the freelists, check
266                                   against the heap_limit whether growing the heap is possible */
267                         if (heap_top + length > heap_limit)
268                                 goto failure;
269                 }
270
271                 /* 2.b. grow the heap */
272                 free_chunk = heap_top;
273                 heap_top += length;
274         }
275
276  success:
277         /* 3.a. mark all necessary bits, store the finalizer & return the newly allocate block */
278 #if 0
279         /* I don't mark the object-start anymore, as it always is at the beginning of a free-block,
280            which already is marked (Note: The first free-block gets marked in heap_init). -- phil. */
281         bitmap_setbit(start_bits, free_chunk); /* mark the new object */
282 #endif
283         bitmap_setbit(start_bits, free_chunk + length); /* mark the freespace behind the new object */
284         if (references)
285                 bitmap_setbit(reference_bits, free_chunk);
286         else 
287                 bitmap_clearbit(reference_bits, free_chunk);
288
289 #if 1
290         /* store a hint, that there's a finalizer */
291         if (finalizer)
292                 heap_add_finalizer_for_object_at(free_chunk);
293 #else
294 #   warning "finalizers disabled."
295 #endif
296
297 #if VERBOSITY >= VERBOSITY_TRACE
298         fprintf(stderr, "heap_allocate: returning free block of 0x%lx bytes at 0x%lx\n", length, free_chunk);
299 #endif
300 #if VERBOSITY >= VERBOSITY_PARANOIA && 0
301         fprintf(stderr, "heap_allocate: reporting heap state variables:\n");
302         fprintf(stderr, "\theap top              0x%lx\n", heap_top);
303         fprintf(stderr, "\theap size             0x%lx (%ld)\n", heap_size, heap_size);
304         fprintf(stderr, "\theap_limit            0x%lx\n", heap_limit);
305         fprintf(stderr, "\theap next collection  0x%lx\n", heap_next_collection);
306 #endif
307
308         return free_chunk;
309         
310  failure:
311         /* 3.b. failure to allocate enough memory... fail gracefully */
312 #if VERBOSITY >= VERBOSITY_MESSAGE
313         fprintf(stderr, 
314                         "heap2.c: heap_allocate was unable to allocate 0x%lx bytes on the VM heap.\n",
315                         length);
316 #endif
317
318 #if VERBOSITY >= VERBOSITY_TRACE
319         fprintf(stderr, "heap_allocate: returning NULL\n");
320 #endif
321
322         return NULL;
323
324         intsRestore();
325 }
326
327 void 
328 heap_addreference (void **reflocation)
329 {
330         /* I currently use a separate linked list (as in the original code) to hold
331            the global reference locations, but I'll change this to allocate these
332            in blocks on the heap; we'll have to add JIT-Marker code for those Java
333            objects then. -- phil. */
334
335         heap_add_address_to_address_list(&references, reflocation);
336 }
337
338 static
339 inline
340 void gc_finalize (void)
341 {
342         /* This will have to be slightly rewritten as soon the JIT-marked heap-based lists are used. -- phil. */
343
344         address_list_node*  curr = finalizers;
345         address_list_node*  prev;
346
347 #if 0
348         while (curr) {
349                 if (!bitmap_testbit(mark_bits, curr->address)) {
350                         /* I need a way to save derefs. Any suggestions? -- phil. */
351                         asm_calljavamethod(((java_objectheader*)curr->address)->vftbl->class->finalizer, 
352                                                            curr->address, NULL, NULL, NULL);
353
354                         prev->next = curr->next;                        
355                         free(curr);
356                 } else {
357                         prev = curr;
358                         curr = curr->next;
359                 }
360         }
361 #else
362         while (curr) {
363                 if (curr->address) {
364                         if (!bitmap_testbit(mark_bits, curr->address)) {
365                                 fprintf(stderr, "executing finalizer\n");
366                                 asm_calljavamethod(((java_objectheader*)curr->address)->vftbl->class->finalizer, 
367                                                                    curr->address, NULL, NULL, NULL);
368                                 curr->address = 0;
369                         }
370                 }
371
372                 curr = curr->next;
373         }
374 #endif
375 }
376
377 static 
378 inline 
379 void gc_reclaim (void)
380 {
381         void* free_start;
382         void* free_end = heap_base;
383         BITBLOCK* temp_bits;
384         bitmap_t* temp_bitmap;
385
386         /* 1. reset the freelists */
387         allocator_reset();
388
389         /* 2. reclaim unmarked objects */
390 #if 0 && SIZE_FROM_CLASSINFO
391         free_start = bitmap_find_next_combination_set_unset(start_bitmap,
392                                                                                                                 mark_bitmap,
393                                                                                                                 free_end);
394         while (free_start < heap_top) {
395                 if (!bitmap_testbit(start_bits, free_start) || 
396                         bitmap_testbit(mark_bits, free_start)) {
397                         fprintf(stderr, "gc_reclaim: inconsistent bit info for 0x%lx\n", free_start);
398                 }
399
400                 free_end = free_start;
401                 while((free_end < heap_top) && 
402                           (!bitmap_testbit(mark_bits, free_end)) {
403                         free_end += 
404                 }
405
406
407
408 bitmap_find_next_setbit(mark_bitmap, free_start + 8); /* FIXME: constant used */
409
410                         //                      fprintf(stderr, "%lx -- %lx\n", free_start, free_end);
411                         
412                         if (free_end < heap_top) {
413                                 allocator_free(free_start, free_end - free_start);
414
415                                 //                              fprintf(stderr, "gc_reclaim: freed 0x%lx bytes at 0x%lx\n", free_end - free_start, free_start);
416
417 #if !defined(JIT_MARKER_SUPPORT)
418                                 /* might make trouble with JIT-Marker support. The Marker for unused blocks 
419                                    might be called, leading to a bad dereference. -- phil. */
420                                 bitmap_setbit(mark_bits, free_start);
421 #endif
422                         }
423                 } else {
424                         //                      fprintf(stderr, "hmmm... found freeable area of 0 bytes at heaptop ?!\n");
425                         free_end = heap_top;
426                 }                       
427         }
428 #else
429         while (free_end < heap_top) {
430                 free_start = bitmap_find_next_combination_set_unset(start_bitmap,
431                                                                                                                         mark_bitmap,
432                                                                                                                         free_end);
433
434                 if (!bitmap_testbit(start_bits, free_start) || 
435                         bitmap_testbit(mark_bits, free_start))
436                         fprintf(stderr, "gc_reclaim: inconsistent bit info for 0x%lx\n", free_start);
437
438                 if (free_start < heap_top) {
439                         free_end   = bitmap_find_next_setbit(mark_bitmap, free_start + 8); /* FIXME: constant used */
440
441                         //                      fprintf(stderr, "%lx -- %lx\n", free_start, free_end);
442                         
443                         if (free_end < heap_top) {
444                                 allocator_free(free_start, free_end - free_start);
445
446                                 //                              fprintf(stderr, "gc_reclaim: freed 0x%lx bytes at 0x%lx\n", free_end - free_start, free_start);
447
448 #if !defined(JIT_MARKER_SUPPORT)
449                                 /* might make trouble with JIT-Marker support. The Marker for unused blocks 
450                                    might be called, leading to a bad dereference. -- phil. */
451                                 bitmap_setbit(mark_bits, free_start);
452 #endif
453                         }
454                 } else {
455                         //                      fprintf(stderr, "hmmm... found freeable area of 0 bytes at heaptop ?!\n");
456                         free_end = heap_top;
457                 }                       
458         }
459 #endif
460
461         /* 3.1. swap mark & start bitmaps */
462         temp_bits = mark_bits;
463         mark_bits = start_bits;
464         start_bits = temp_bits;
465
466         temp_bitmap = mark_bitmap;
467         mark_bitmap = start_bitmap;
468         start_bitmap = temp_bitmap;
469
470         /* 3.2. mask reference bitmap */
471 #warning "bitmap masking unimplemented --- references will not be cleared"
472
473         /* 3.3. update heap_top */
474         if (free_start < heap_top)
475                 heap_top = free_start;
476
477         if (heap_top < heap_limit)
478                 bitmap_setbit(start_bits, heap_top);
479
480         /* 4. adjust the collection threshold */
481         heap_next_collection = heap_top + (heap_limit - heap_top) / 8;
482         if (heap_next_collection > heap_limit)
483                 heap_next_collection = heap_limit;
484
485 #if VERBOSITY >= VERBOSITY_PARANOIA && 0
486         fprintf(stderr, "gc_reclaim: reporting heap state variables:\n");
487         fprintf(stderr, "\theap top              0x%lx\n", heap_top);
488         fprintf(stderr, "\theap size             0x%lx (%ld)\n", heap_size, heap_size);
489         fprintf(stderr, "\theap_limit            0x%lx\n", heap_limit);
490         fprintf(stderr, "\theap next collection  0x%lx\n", heap_next_collection);
491
492         allocator_dump();
493 #endif
494 }
495
496 static
497 inline 
498 void 
499 gc_mark_object_at (void** addr)
500 {
501 #if 0
502         //      fprintf(stderr, "gc_mark_object_at: called for address 0x%lx\n", addr);
503
504         if (!((void*)addr >= heap_base && 
505                   (void*)addr < heap_top)) {
506                 //              fprintf(stderr, "not an address on the heap.\n");
507         } else {
508                 if (!bitmap_testbit(start_bits, (void*)addr)) {
509                         //                      fprintf(stderr, "not an object.\n");
510                 }
511                 else {
512                         if (bitmap_testbit(mark_bits, (void*)addr)) {
513                                 //                              fprintf(stderr, "gc_mark_object_at: called for address 0x%lx: ", addr);
514                                 //                              fprintf(stderr, "already marked.\n");
515                         }
516                 }
517         }
518 #endif
519
520         /* 1. is the addr aligned, on the heap && the start of an object */
521         if (!((long)addr & ((1 << ALIGN) - 1)) &&
522                 (void*)addr >= heap_base && 
523                 (void*)addr < heap_top && 
524                 bitmap_testbit(start_bits, (void*)addr) &&
525                 !bitmap_testbit(mark_bits, (void*)addr)) {
526                 bitmap_setbit(mark_bits, (void*)addr); 
527
528                 //              fprintf(stderr, "gc_mark_object_at: called for address 0x%lx: ", addr);
529                 //              fprintf(stderr, "marking object.\n");
530
531 #ifdef JIT_MARKER_SUPPORT
532                 /* 1.a. invoke the JIT-marker method */
533                 asm_calljavamethod(addr->vftbl->class->marker, addr, NULL, NULL, NULL);
534 #else
535                 /* 1.b. mark the references contained */
536                 if (bitmap_testbit(reference_bits, addr)) {
537                         void** end;
538 #ifdef SIZE_FROM_CLASSINFO
539                         void** old_end;
540
541                         if (((java_objectheader*)addr)->vftbl == class_array->vftbl) {
542                                 end = (void**)((long)addr + (long)((java_arrayheader*)addr)->alignedsize); 
543 //                              fprintf(stderr, "size found for array at 0x%lx: 0x%lx\n", addr, ((java_arrayheader*)addr)->alignedsize);
544                         }
545                         else {
546                                 end = (void**)((long)addr + (long)((java_objectheader*)addr)->vftbl->class->alignedsize);                                                          
547 //                              fprintf(stderr, "size found for 0x%lx: 0x%lx\n", addr, ((java_objectheader*)addr)->vftbl->class->alignedsize);
548                         }
549
550                         old_end = (void**)bitmap_find_next_setbit(start_bitmap, (void*)addr + 8);
551                         if (end != old_end) {
552                                 fprintf(stderr, "inconsistent object length for object at 0x%lx:", addr);
553                                 fprintf(stderr, " old = 0x%lx ; new = 0x%lx\n", old_end, end);
554                         }
555 #else
556                         end = (void**)bitmap_find_next_setbit(start_bitmap, addr + 8); /* points just behind the object */
557 #endif
558
559                         while (addr < end)
560                                 gc_mark_object_at(*(addr++));
561                 }
562 #endif  
563         }
564
565         return;
566 }
567
568 static
569 inline 
570 void gc_mark_references (void)
571 {
572         address_list_node* curr = references;
573
574         //      fprintf(stderr, "gc_mark_references\n");
575
576         while (curr) {
577                 gc_mark_object_at(*((void**)(curr->address)));
578                 curr = curr->next;
579         }
580 }
581
582 static
583 inline
584 void 
585 markreferences(void** start, void** end)
586 {
587         while (start < end)
588                 gc_mark_object_at(*(start++));
589 }
590
591 static
592 inline 
593 void gc_mark_stack (void)
594 {
595         void *dummy;
596
597 #ifdef USE_THREADS 
598     thread *aThread;
599         
600         if (currentThread == NULL) {
601                 void **top_of_stack = &dummy;
602                 
603                 if (top_of_stack > stackbottom)
604                         markreferences(stackbottom, top_of_stack);
605                 else
606                         markreferences(top_of_stack, stackbottom);
607         }
608         else {
609                 for (aThread = liveThreads; aThread != 0;
610                          aThread = CONTEXT(aThread).nextlive) {
611                         mark_object_at((void*)aThread);
612                         if (aThread == currentThread) {
613                                 void **top_of_stack = &dummy;
614                                 
615                                 if (top_of_stack > (void**)CONTEXT(aThread).stackEnd)
616                                         markreferences((void**)CONTEXT(aThread).stackEnd, top_of_stack);
617                                 else    
618                                         markreferences(top_of_stack, (void**)CONTEXT(aThread).stackEnd);
619                         }
620                         else {
621                                 if (CONTEXT(aThread).usedStackTop > CONTEXT(aThread).stackEnd)
622                                         markreferences((void**)CONTEXT(aThread).stackEnd,
623                                                                    (void**)CONTEXT(aThread).usedStackTop);
624                                 else    
625                                         markreferences((void**)CONTEXT(aThread).usedStackTop,
626                                                                    (void**)CONTEXT(aThread).stackEnd);
627                         }
628             }
629
630                 markreferences((void**)&threadQhead[0],
631                                            (void**)&threadQhead[MAX_THREAD_PRIO]);
632         }
633 #else
634     void **top_of_stack = &dummy;
635
636         //      fprintf(stderr, "gc_mark_stack\n");
637         
638     if (top_of_stack > stackbottom) {
639                 //              fprintf(stderr, "stack growing upward\n");
640         markreferences(stackbottom, top_of_stack);
641         } else {
642                 //              fprintf(stderr, "stack growing downward\n");
643         markreferences(top_of_stack, stackbottom);
644         }
645 #endif
646 }
647
648
649 static 
650 void gc_run (void)
651 {
652         static int armageddon_is_near = 0;
653
654         if (armageddon_is_near) {
655                 /* armageddon_is_here! */
656                 fprintf(stderr, "Oops, seems like there's a slight problem here: gc_run() called while still running?!\n");
657                 return;
658         }
659
660         armageddon_is_near = true;
661         heap_next_collection = heap_limit;  /* try to avoid finalizer-induced collections */
662
663         bitmap_clear(mark_bitmap);
664
665         asm_dumpregistersandcall(gc_mark_stack);
666         gc_mark_references();
667         gc_finalize();
668         gc_reclaim();
669
670         armageddon_is_near = false;
671 }
672
673
674 /************************* Function: gc_init **********************************
675
676   Initializes anything that must be initialized to call the gc on the right
677   stack.
678
679 ******************************************************************************/
680
681 void
682 gc_init (void)
683 {
684 }
685
686 /************************** Function: gc_call ********************************
687
688   Calls the garbage collector. The garbage collector should always be called
689   using this function since it ensures that enough stack space is available.
690
691 ******************************************************************************/
692
693 void
694 gc_call (void)
695 {
696 #ifdef USE_THREADS
697         assert(blockInts == 0);
698
699         intsDisable();
700         if (currentThread == NULL || currentThread == mainThread)
701                 gc_run();
702         else
703                 asm_switchstackandcall(CONTEXT(mainThread).usedStackTop, gc_run);
704         intsRestore();
705 #else
706         gc_run();
707 #endif
708 }
709
710
711
712 /*
713  * These are local overrides for various environment variables in Emacs.
714  * Please do not remove this and leave it at the end of the file, where
715  * Emacs will automagically detect them.
716  * ---------------------------------------------------------------------
717  * Local variables:
718  * mode: c
719  * indent-tabs-mode: t
720  * c-basic-offset: 4
721  * tab-width: 4
722  * End:
723  */