7cdaf37ab6baff73a10a9ca323fad2905c1c6c11
[cacao.git] / src / mm / boehm-gc / mark_rts.c
1 /* 
2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
4  *
5  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
7  *
8  * Permission is hereby granted to use or copy this program
9  * for any purpose,  provided the above notices are retained on all copies.
10  * Permission to modify the code and to distribute modified code is granted,
11  * provided the above notices are retained, and a notice that the code was
12  * modified is included with the above copyright notice.
13  */
14
15 #include "config.h"
16
17 # include <stdio.h>
18 # include "private/gc_priv.h"
19
20 /* Data structure for list of root sets.                                */
21 /* We keep a hash table, so that we can filter out duplicate additions. */
22 /* Under Win32, we need to do a better job of filtering overlaps, so    */
23 /* we resort to sequential search, and pay the price.                   */
24 /* This is really declared in gc_priv.h:
25 struct roots {
26         ptr_t r_start;
27         ptr_t r_end;
28  #      if !defined(MSWIN32) && !defined(MSWINCE)
29           struct roots * r_next;
30  #      endif
31         GC_bool r_tmp;
32                 -- Delete before registering new dynamic libraries
33 };
34
35 struct roots GC_static_roots[MAX_ROOT_SETS];
36 */
37
38 int GC_no_dls = 0;      /* Register dynamic library data segments.      */
39
40 static int n_root_sets = 0;
41
42         /* GC_static_roots[0..n_root_sets) contains the valid root sets. */
43
44 # if !defined(NO_DEBUGGING)
45 /* For debugging:       */
46 void GC_print_static_roots(void)
47 {
48     register int i;
49     size_t total = 0;
50     
51     for (i = 0; i < n_root_sets; i++) {
52         GC_printf("From %p to %p ",
53                   GC_static_roots[i].r_start,
54                   GC_static_roots[i].r_end);
55         if (GC_static_roots[i].r_tmp) {
56             GC_printf(" (temporary)\n");
57         } else {
58             GC_printf("\n");
59         }
60         total += GC_static_roots[i].r_end - GC_static_roots[i].r_start;
61     }
62     GC_printf("Total size: %ld\n", (unsigned long) total);
63     if (GC_root_size != total) {
64         GC_printf("GC_root_size incorrect: %ld!!\n",
65                   (unsigned long) GC_root_size);
66     }
67 }
68 # endif /* NO_DEBUGGING */
69
70 /* Primarily for debugging support:     */
71 /* Is the address p in one of the registered static                     */
72 /* root sections?                                                       */
73 GC_bool GC_is_static_root(ptr_t p)
74 {
75     static int last_root_set = MAX_ROOT_SETS;
76     register int i;
77     
78     
79     if (last_root_set < n_root_sets
80         && p >= GC_static_roots[last_root_set].r_start
81         && p < GC_static_roots[last_root_set].r_end) return(TRUE);
82     for (i = 0; i < n_root_sets; i++) {
83         if (p >= GC_static_roots[i].r_start
84             && p < GC_static_roots[i].r_end) {
85             last_root_set = i;
86             return(TRUE);
87         }
88     }
89     return(FALSE);
90 }
91
92 #if !defined(MSWIN32) && !defined(MSWINCE)
93 /* 
94 #   define LOG_RT_SIZE 6
95 #   define RT_SIZE (1 << LOG_RT_SIZE)  -- Power of 2, may be != MAX_ROOT_SETS
96
97     struct roots * GC_root_index[RT_SIZE];
98         -- Hash table header.  Used only to check whether a range is
99         -- already present.
100         -- really defined in gc_priv.h
101 */
102
103 static INLINE int rt_hash(ptr_t addr)
104 {
105     word result = (word) addr;
106 #   if CPP_WORDSZ > 8*LOG_RT_SIZE
107         result ^= result >> 8*LOG_RT_SIZE;
108 #   endif
109 #   if CPP_WORDSZ > 4*LOG_RT_SIZE
110         result ^= result >> 4*LOG_RT_SIZE;
111 #   endif
112     result ^= result >> 2*LOG_RT_SIZE;
113     result ^= result >> LOG_RT_SIZE;
114     result &= (RT_SIZE-1);
115     return(result);
116 }
117
118 /* Is a range starting at b already in the table? If so return a        */
119 /* pointer to it, else NIL.                                             */
120 struct roots * GC_roots_present(ptr_t b)
121 {
122     int h = rt_hash(b);
123     struct roots *p = GC_root_index[h];
124     
125     while (p != 0) {
126         if (p -> r_start == (ptr_t)b) return(p);
127         p = p -> r_next;
128     }
129     return(FALSE);
130 }
131
132 /* Add the given root structure to the index. */
133 static void add_roots_to_index(struct roots *p)
134 {
135     int h = rt_hash(p -> r_start);
136     
137     p -> r_next = GC_root_index[h];
138     GC_root_index[h] = p;
139 }
140
141 # else /* MSWIN32 || MSWINCE */
142
143 #   define add_roots_to_index(p)
144
145 # endif
146
147
148
149
150 word GC_root_size = 0;
151
152 void GC_add_roots(void *b, void *e)
153 {
154     DCL_LOCK_STATE;
155     
156     if (!GC_is_initialized) GC_init();
157     LOCK();
158     GC_add_roots_inner((ptr_t)b, (ptr_t)e, FALSE);
159     UNLOCK();
160 }
161
162
163 /* Add [b,e) to the root set.  Adding the same interval a second time   */
164 /* is a moderately fast noop, and hence benign.  We do not handle       */
165 /* different but overlapping intervals efficiently.  (We do handle      */
166 /* them correctly.)                                                     */
167 /* Tmp specifies that the interval may be deleted before                */
168 /* reregistering dynamic libraries.                                     */ 
169 void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp)
170 {
171     struct roots * old;
172     
173 #   if defined(MSWIN32) || defined(MSWINCE)
174       /* Spend the time to ensure that there are no overlapping */
175       /* or adjacent intervals.                                 */
176       /* This could be done faster with e.g. a                  */
177       /* balanced tree.  But the execution time here is         */
178       /* virtually guaranteed to be dominated by the time it    */
179       /* takes to scan the roots.                               */
180       {
181         register int i;
182         
183         for (i = 0; i < n_root_sets; i++) {
184             old = GC_static_roots + i;
185             if (b <= old -> r_end && e >= old -> r_start) {
186                 if (b < old -> r_start) {
187                     old -> r_start = b;
188                     GC_root_size += (old -> r_start - b);
189                 }
190                 if (e > old -> r_end) {
191                     old -> r_end = e;
192                     GC_root_size += (e - old -> r_end);
193                 }
194                 old -> r_tmp &= tmp;
195                 break;
196             }
197         }
198         if (i < n_root_sets) {
199           /* merge other overlapping intervals */
200             struct roots *other;
201             
202             for (i++; i < n_root_sets; i++) {
203               other = GC_static_roots + i;
204               b = other -> r_start;
205               e = other -> r_end;
206               if (b <= old -> r_end && e >= old -> r_start) {
207                 if (b < old -> r_start) {
208                     old -> r_start = b;
209                     GC_root_size += (old -> r_start - b);
210                 }
211                 if (e > old -> r_end) {
212                     old -> r_end = e;
213                     GC_root_size += (e - old -> r_end);
214                 }
215                 old -> r_tmp &= other -> r_tmp;
216                 /* Delete this entry. */
217                   GC_root_size -= (other -> r_end - other -> r_start);
218                   other -> r_start = GC_static_roots[n_root_sets-1].r_start;
219                   other -> r_end = GC_static_roots[n_root_sets-1].r_end;
220                   n_root_sets--;
221               }
222             }
223           return;
224         }
225       }
226 #   else
227       old = GC_roots_present(b);
228       if (old != 0) {
229         if (e <= old -> r_end) /* already there */ return;
230         /* else extend */
231         GC_root_size += e - old -> r_end;
232         old -> r_end = e;
233         return;
234       }
235 #   endif
236     if (n_root_sets == MAX_ROOT_SETS) {
237         ABORT("Too many root sets\n");
238     }
239     GC_static_roots[n_root_sets].r_start = (ptr_t)b;
240     GC_static_roots[n_root_sets].r_end = (ptr_t)e;
241     GC_static_roots[n_root_sets].r_tmp = tmp;
242 #   if !defined(MSWIN32) && !defined(MSWINCE)
243       GC_static_roots[n_root_sets].r_next = 0;
244 #   endif
245     add_roots_to_index(GC_static_roots + n_root_sets);
246     GC_root_size += e - b;
247     n_root_sets++;
248 }
249
250 static GC_bool roots_were_cleared = FALSE;
251
252 void GC_clear_roots (void)
253 {
254     DCL_LOCK_STATE;
255     
256     if (!GC_is_initialized) GC_init();
257     LOCK();
258     roots_were_cleared = TRUE;
259     n_root_sets = 0;
260     GC_root_size = 0;
261 #   if !defined(MSWIN32) && !defined(MSWINCE)
262     {
263         register int i;
264         
265         for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
266     }
267 #   endif
268     UNLOCK();
269 }
270
271 /* Internal use only; lock held.        */
272 static void GC_remove_root_at_pos(int i) 
273 {
274     GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
275     GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
276     GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
277     GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
278     n_root_sets--;
279 }
280
281 #if !defined(MSWIN32) && !defined(MSWINCE)
282 static void GC_rebuild_root_index(void)
283 {
284     int i;
285         
286     for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
287     for (i = 0; i < n_root_sets; i++)
288         add_roots_to_index(GC_static_roots + i);
289 }
290 #endif
291
292 /* Internal use only; lock held.        */
293 void GC_remove_tmp_roots(void)
294 {
295     int i;
296     
297     for (i = 0; i < n_root_sets; ) {
298         if (GC_static_roots[i].r_tmp) {
299             GC_remove_root_at_pos(i);
300         } else {
301             i++;
302         }
303     }
304     #if !defined(MSWIN32) && !defined(MSWINCE)
305     GC_rebuild_root_index();
306     #endif
307 }
308
309 #if !defined(MSWIN32) && !defined(MSWINCE)
310 void GC_remove_roots(void *b, void *e)
311 {
312     DCL_LOCK_STATE;
313     
314     LOCK();
315     GC_remove_roots_inner((ptr_t)b, (ptr_t)e);
316     UNLOCK();
317 }
318
319 /* Should only be called when the lock is held */
320 void GC_remove_roots_inner(ptr_t b, ptr_t e)
321 {
322     int i;
323     for (i = 0; i < n_root_sets; ) {
324         if (GC_static_roots[i].r_start >= b
325             && GC_static_roots[i].r_end <= e) {
326             GC_remove_root_at_pos(i);
327         } else {
328             i++;
329         }
330     }
331     GC_rebuild_root_index();
332 }
333 #endif /* !defined(MSWIN32) && !defined(MSWINCE) */
334
335 #if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
336 /* Workaround for the OS mapping and unmapping behind our back:         */
337 /* Is the address p in one of the temporary static root sections?       */
338 GC_bool GC_is_tmp_root(ptr_t p)
339 {
340     static int last_root_set = MAX_ROOT_SETS;
341     register int i;
342     
343     if (last_root_set < n_root_sets
344         && p >= GC_static_roots[last_root_set].r_start
345         && p < GC_static_roots[last_root_set].r_end)
346         return GC_static_roots[last_root_set].r_tmp;
347     for (i = 0; i < n_root_sets; i++) {
348         if (p >= GC_static_roots[i].r_start
349             && p < GC_static_roots[i].r_end) {
350             last_root_set = i;
351             return GC_static_roots[i].r_tmp;
352         }
353     }
354     return(FALSE);
355 }
356 #endif /* MSWIN32 || _WIN32_WCE_EMULATION */
357
358 ptr_t GC_approx_sp(void)
359 {
360     volatile word dummy;
361
362     dummy = 42; /* Force stack to grow if necessary.    Otherwise the   */
363                 /* later accesses might cause the kernel to think we're */
364                 /* doing something wrong.                               */
365 #   ifdef _MSC_VER
366 #     pragma warning(disable:4172)
367 #   endif
368     return((ptr_t)(&dummy));
369 #   ifdef _MSC_VER
370 #     pragma warning(default:4172)
371 #   endif
372 }
373
374 /*
375  * Data structure for excluded static roots.
376  * Real declaration is in gc_priv.h.
377
378 struct exclusion {
379     ptr_t e_start;
380     ptr_t e_end;
381 };
382
383 struct exclusion GC_excl_table[MAX_EXCLUSIONS];
384                                         -- Array of exclusions, ascending
385                                         -- address order.
386 */
387
388 size_t GC_excl_table_entries = 0;       /* Number of entries in use.      */
389
390 /* Return the first exclusion range that includes an address >= start_addr */
391 /* Assumes the exclusion table contains at least one entry (namely the     */
392 /* GC data structures).                                                    */
393 struct exclusion * GC_next_exclusion(ptr_t start_addr)
394 {
395     size_t low = 0;
396     size_t high = GC_excl_table_entries - 1;
397     size_t mid;
398
399     while (high > low) {
400         mid = (low + high) >> 1;
401         /* low <= mid < high    */
402         if ((word) GC_excl_table[mid].e_end <= (word) start_addr) {
403             low = mid + 1;
404         } else {
405             high = mid;
406         }
407     }
408     if ((word) GC_excl_table[low].e_end <= (word) start_addr) return 0;
409     return GC_excl_table + low;
410 }
411
412 void GC_exclude_static_roots(void *start, void *finish)
413 {
414     struct exclusion * next;
415     size_t next_index, i;
416
417     if (0 == GC_excl_table_entries) {
418         next = 0;
419     } else {
420         next = GC_next_exclusion(start);
421     }
422     if (0 != next) {
423       if ((word)(next -> e_start) < (word) finish) {
424         /* incomplete error check. */
425         ABORT("exclusion ranges overlap");
426       }  
427       if ((word)(next -> e_start) == (word) finish) {
428         /* extend old range backwards   */
429           next -> e_start = (ptr_t)start;
430           return;
431       }
432       next_index = next - GC_excl_table;
433       for (i = GC_excl_table_entries; i > next_index; --i) {
434         GC_excl_table[i] = GC_excl_table[i-1];
435       }
436     } else {
437       next_index = GC_excl_table_entries;
438     }
439     if (GC_excl_table_entries == MAX_EXCLUSIONS) ABORT("Too many exclusions");
440     GC_excl_table[next_index].e_start = (ptr_t)start;
441     GC_excl_table[next_index].e_end = (ptr_t)finish;
442     ++GC_excl_table_entries;
443 }
444
445 /* Invoke push_conditional on ranges that are not excluded. */
446 void GC_push_conditional_with_exclusions(ptr_t bottom, ptr_t top, GC_bool all)
447 {
448     struct exclusion * next;
449     ptr_t excl_start;
450
451     while (bottom < top) {
452         next = GC_next_exclusion(bottom);
453         if (0 == next || (excl_start = next -> e_start) >= top) {
454             GC_push_conditional(bottom, top, all);
455             return;
456         }
457         if (excl_start > bottom) GC_push_conditional(bottom, excl_start, all);
458         bottom = next -> e_end;
459     }
460 }
461
462 /*
463  * In the absence of threads, push the stack contents.
464  * In the presence of threads, push enough of the current stack
465  * to ensure that callee-save registers saved in collector frames have been
466  * seen.
467  * FIXME: Merge with per-thread stuff.
468  */
469 void GC_push_current_stack(ptr_t cold_gc_frame, void * context)
470 {
471 #   if defined(THREADS)
472         if (0 == cold_gc_frame) return;
473 #       ifdef STACK_GROWS_DOWN
474           GC_push_all_eager(GC_approx_sp(), cold_gc_frame);
475           /* For IA64, the register stack backing store is handled      */
476           /* in the thread-specific code.                               */
477 #       else
478           GC_push_all_eager( cold_gc_frame, GC_approx_sp() );
479 #       endif
480 #   else
481 #       ifdef STACK_GROWS_DOWN
482             GC_push_all_stack_partially_eager( GC_approx_sp(), GC_stackbottom,
483                                                cold_gc_frame );
484 #           ifdef IA64
485               /* We also need to push the register stack backing store. */
486               /* This should really be done in the same way as the      */
487               /* regular stack.  For now we fudge it a bit.             */
488               /* Note that the backing store grows up, so we can't use  */
489               /* GC_push_all_stack_partially_eager.                     */
490               {
491                 extern word GC_save_regs_ret_val;
492                         /* Previously set to backing store pointer.     */
493                 ptr_t bsp = (ptr_t) GC_save_regs_ret_val;
494                 ptr_t cold_gc_bs_pointer;
495                 if (GC_all_interior_pointers) {
496                   cold_gc_bs_pointer = bsp - 2048;
497                   if (cold_gc_bs_pointer < BACKING_STORE_BASE) {
498                     cold_gc_bs_pointer = BACKING_STORE_BASE;
499                   } else {
500                     GC_push_all_stack(BACKING_STORE_BASE, cold_gc_bs_pointer);
501                   }
502                 } else {
503                   cold_gc_bs_pointer = BACKING_STORE_BASE;
504                 }
505                 GC_push_all_eager(cold_gc_bs_pointer, bsp);
506                 /* All values should be sufficiently aligned that we    */
507                 /* dont have to worry about the boundary.               */
508               }
509 #           endif
510 #       else
511             GC_push_all_stack_partially_eager( GC_stackbottom, GC_approx_sp(),
512                                                cold_gc_frame );
513 #       endif
514 #   endif /* !THREADS */
515 }
516
517 void (*GC_push_typed_structures) (void) = NULL;
518
519 /*
520  * Push GC internal roots.  Only called if there is some reason to believe
521  * these would not otherwise get registered.
522  */
523 void GC_push_gc_structures(void)
524 {
525     GC_push_finalizer_structures();
526 #   if defined(THREADS)
527       GC_push_thread_structures();
528 #   endif
529     if( GC_push_typed_structures )
530       GC_push_typed_structures();
531 }
532
533 #ifdef THREAD_LOCAL_ALLOC
534   void GC_mark_thread_local_free_lists(void);
535 #endif
536
537 void GC_cond_register_dynamic_libraries(void)
538 {
539 # if defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
540      || defined(PCR)
541     GC_remove_tmp_roots();
542     if (!GC_no_dls) GC_register_dynamic_libraries();
543 # else
544     GC_no_dls = TRUE;
545 # endif
546 }
547
548 /*
549  * Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional
550  * on groups of pointers) on every top level accessible pointer.
551  * If all is FALSE, arrange to push only possibly altered values.
552  * Cold_gc_frame is an address inside a GC frame that
553  * remains valid until all marking is complete.
554  * A zero value indicates that it's OK to miss some
555  * register values.
556  */
557 void GC_push_roots(GC_bool all, ptr_t cold_gc_frame)
558 {
559     int i;
560     unsigned kind;
561
562     /*
563      * Next push static data.  This must happen early on, since it's
564      * not robust against mark stack overflow.
565      */
566      /* Reregister dynamic libraries, in case one got added.            */
567      /* There is some argument for doing this as late as possible,      */
568      /* especially on win32, where it can change asynchronously.        */
569      /* In those cases, we do it here.  But on other platforms, it's    */
570      /* not safe with the world stopped, so we do it earlier.           */
571 #      if !defined(REGISTER_LIBRARIES_EARLY)
572          GC_cond_register_dynamic_libraries();
573 #      endif
574
575      /* Mark everything in static data areas                             */
576        for (i = 0; i < n_root_sets; i++) {
577          GC_push_conditional_with_exclusions(
578                              GC_static_roots[i].r_start,
579                              GC_static_roots[i].r_end, all);
580        }
581
582      /* Mark all free list header blocks, if those were allocated from  */
583      /* the garbage collected heap.  This makes sure they don't         */
584      /* disappear if we are not marking from static data.  It also      */
585      /* saves us the trouble of scanning them, and possibly that of     */
586      /* marking the freelists.                                          */
587        for (kind = 0; kind < GC_n_kinds; kind++) {
588          void *base = GC_base(GC_obj_kinds[kind].ok_freelist);
589          if (0 != base) {
590            GC_set_mark_bit(base);
591          }
592        }
593        
594      /* Mark from GC internal roots if those might otherwise have       */
595      /* been excluded.                                                  */
596        if (GC_no_dls || roots_were_cleared) {
597            GC_push_gc_structures();
598        }
599
600      /* Mark thread local free lists, even if their mark        */
601      /* descriptor excludes the link field.                     */
602      /* If the world is not stopped, this is unsafe.  It is     */
603      /* also unnecessary, since we will do this again with the  */
604      /* world stopped.                                          */
605 #      if defined(THREAD_LOCAL_ALLOC)
606          if (GC_world_stopped) GC_mark_thread_local_free_lists();
607 #      endif
608
609     /*
610      * Now traverse stacks, and mark from register contents.
611      * These must be done last, since they can legitimately overflow
612      * the mark stack.
613      * This is usually done by saving the current context on the
614      * stack, and then just tracing from the stack.
615      */
616       GC_push_regs_and_stack(cold_gc_frame);
617
618     if (GC_push_other_roots != 0) (*GC_push_other_roots)();
619         /* In the threads case, this also pushes thread stacks. */
620         /* Note that without interior pointer recognition lots  */
621         /* of stuff may have been pushed already, and this      */
622         /* should be careful about mark stack overflows.        */
623 }
624