2 * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3 * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
5 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
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.
14 /* Boehm, October 9, 1995 1:06 pm PDT */
18 /* Data structure for list of root sets. */
19 /* We keep a hash table, so that we can filter out duplicate additions. */
20 /* Under Win32, we need to do a better job of filtering overlaps, so */
21 /* we resort to sequential search, and pay the price. */
22 /* This is really declared in gc_priv.h:
27 struct roots * r_next;
30 -- Delete before registering new dynamic libraries
33 struct roots GC_static_roots[MAX_ROOT_SETS];
36 static int n_root_sets
= 0;
38 /* GC_static_roots[0..n_root_sets) contains the valid root sets. */
40 # if !defined(NO_DEBUGGING)
42 void GC_print_static_roots()
47 for (i
= 0; i
< n_root_sets
; i
++) {
48 GC_printf2("From 0x%lx to 0x%lx ",
49 (unsigned long) GC_static_roots
[i
].r_start
,
50 (unsigned long) GC_static_roots
[i
].r_end
);
51 if (GC_static_roots
[i
].r_tmp
) {
52 GC_printf0(" (temporary)\n");
56 total
+= GC_static_roots
[i
].r_end
- GC_static_roots
[i
].r_start
;
58 GC_printf1("Total size: %ld\n", (unsigned long) total
);
59 if (GC_root_size
!= total
) {
60 GC_printf1("GC_root_size incorrect: %ld!!\n",
61 (unsigned long) GC_root_size
);
64 # endif /* NO_DEBUGGING */
66 /* Primarily for debugging support: */
67 /* Is the address p in one of the registered static */
69 GC_bool
GC_is_static_root(p
)
72 static int last_root_set
= 0;
76 if (p
>= GC_static_roots
[last_root_set
].r_start
77 && p
< GC_static_roots
[last_root_set
].r_end
) return(TRUE
);
78 for (i
= 0; i
< n_root_sets
; i
++) {
79 if (p
>= GC_static_roots
[i
].r_start
80 && p
< GC_static_roots
[i
].r_end
) {
90 # define LOG_RT_SIZE 6
91 # define RT_SIZE (1 << LOG_RT_SIZE) -- Power of 2, may be != MAX_ROOT_SETS
93 struct roots * GC_root_index[RT_SIZE];
94 -- Hash table header. Used only to check whether a range is
96 -- really defined in gc_priv.h
99 static int rt_hash(addr
)
102 word result
= (word
) addr
;
103 # if CPP_WORDSZ > 8*LOG_RT_SIZE
104 result
^= result
>> 8*LOG_RT_SIZE
;
106 # if CPP_WORDSZ > 4*LOG_RT_SIZE
107 result
^= result
>> 4*LOG_RT_SIZE
;
109 result
^= result
>> 2*LOG_RT_SIZE
;
110 result
^= result
>> LOG_RT_SIZE
;
111 result
&= (RT_SIZE
-1);
115 /* Is a range starting at b already in the table? If so return a */
116 /* pointer to it, else NIL. */
117 struct roots
* GC_roots_present(b
)
120 register int h
= rt_hash(b
);
121 register struct roots
*p
= GC_root_index
[h
];
124 if (p
-> r_start
== (ptr_t
)b
) return(p
);
130 /* Add the given root structure to the index. */
131 static void add_roots_to_index(p
)
134 register int h
= rt_hash(p
-> r_start
);
136 p
-> r_next
= GC_root_index
[h
];
137 GC_root_index
[h
] = p
;
142 # define add_roots_to_index(p)
149 word GC_root_size
= 0;
151 void GC_add_roots(b
, e
)
158 GC_add_roots_inner(b
, e
, FALSE
);
164 /* Add [b,e) to the root set. Adding the same interval a second time */
165 /* is a moderately fast noop, and hence benign. We do not handle */
166 /* different but overlapping intervals efficiently. (We do handle */
167 /* them correctly.) */
168 /* Tmp specifies that the interval may be deleted before */
169 /* reregistering dynamic libraries. */
170 void GC_add_roots_inner(b
, e
, tmp
)
177 /* Spend the time to ensure that there are no overlapping */
178 /* or adjacent intervals. */
179 /* This could be done faster with e.g. a */
180 /* balanced tree. But the execution time here is */
181 /* virtually guaranteed to be dominated by the time it */
182 /* takes to scan the roots. */
186 for (i
= 0; i
< n_root_sets
; i
++) {
187 old
= GC_static_roots
+ i
;
188 if ((ptr_t
)b
<= old
-> r_end
&& (ptr_t
)e
>= old
-> r_start
) {
189 if ((ptr_t
)b
< old
-> r_start
) {
190 old
-> r_start
= (ptr_t
)b
;
191 GC_root_size
+= (old
-> r_start
- (ptr_t
)b
);
193 if ((ptr_t
)e
> old
-> r_end
) {
194 old
-> r_end
= (ptr_t
)e
;
195 GC_root_size
+= ((ptr_t
)e
- old
-> r_end
);
201 if (i
< n_root_sets
) {
202 /* merge other overlapping intervals */
205 for (i
++; i
< n_root_sets
; i
++) {
206 other
= GC_static_roots
+ i
;
207 b
= (char *)(other
-> r_start
);
208 e
= (char *)(other
-> r_end
);
209 if ((ptr_t
)b
<= old
-> r_end
&& (ptr_t
)e
>= old
-> r_start
) {
210 if ((ptr_t
)b
< old
-> r_start
) {
211 old
-> r_start
= (ptr_t
)b
;
212 GC_root_size
+= (old
-> r_start
- (ptr_t
)b
);
214 if ((ptr_t
)e
> old
-> r_end
) {
215 old
-> r_end
= (ptr_t
)e
;
216 GC_root_size
+= ((ptr_t
)e
- old
-> r_end
);
218 old
-> r_tmp
&= other
-> r_tmp
;
219 /* Delete this entry. */
220 GC_root_size
-= (other
-> r_end
- other
-> r_start
);
221 other
-> r_start
= GC_static_roots
[n_root_sets
-1].r_start
;
222 other
-> r_end
= GC_static_roots
[n_root_sets
-1].r_end
;
230 old
= GC_roots_present(b
);
232 if ((ptr_t
)e
<= old
-> r_end
) /* already there */ return;
234 GC_root_size
+= (ptr_t
)e
- old
-> r_end
;
235 old
-> r_end
= (ptr_t
)e
;
239 if (n_root_sets
== MAX_ROOT_SETS
) {
240 ABORT("Too many root sets\n");
242 GC_static_roots
[n_root_sets
].r_start
= (ptr_t
)b
;
243 GC_static_roots
[n_root_sets
].r_end
= (ptr_t
)e
;
244 GC_static_roots
[n_root_sets
].r_tmp
= tmp
;
246 GC_static_roots
[n_root_sets
].r_next
= 0;
248 add_roots_to_index(GC_static_roots
+ n_root_sets
);
249 GC_root_size
+= (ptr_t
)e
- (ptr_t
)b
;
253 void GC_clear_roots
GC_PROTO((void))
265 for (i
= 0; i
< RT_SIZE
; i
++) GC_root_index
[i
] = 0;
272 /* Internal use only; lock held. */
273 void GC_remove_tmp_roots()
277 for (i
= 0; i
< n_root_sets
; ) {
278 if (GC_static_roots
[i
].r_tmp
) {
280 (GC_static_roots
[i
].r_end
- GC_static_roots
[i
].r_start
);
281 GC_static_roots
[i
].r_start
= GC_static_roots
[n_root_sets
-1].r_start
;
282 GC_static_roots
[i
].r_end
= GC_static_roots
[n_root_sets
-1].r_end
;
283 GC_static_roots
[i
].r_tmp
= GC_static_roots
[n_root_sets
-1].r_tmp
;
293 for (i
= 0; i
< RT_SIZE
; i
++) GC_root_index
[i
] = 0;
294 for (i
= 0; i
< n_root_sets
; i
++)
295 add_roots_to_index(GC_static_roots
+ i
);
305 return((ptr_t
)(&dummy
));
309 * Data structure for excluded static roots.
310 * Real declaration is in gc_priv.h.
317 struct exclusion GC_excl_table[MAX_EXCLUSIONS];
318 -- Array of exclusions, ascending
322 size_t GC_excl_table_entries
= 0; /* Number of entries in use. */
324 /* Return the first exclusion range that includes an address >= start_addr */
325 /* Assumes the exclusion table contains at least one entry (namely the */
326 /* GC data structures). */
327 struct exclusion
* GC_next_exclusion(start_addr
)
331 size_t high
= GC_excl_table_entries
- 1;
335 mid
= (low
+ high
) >> 1;
336 /* low <= mid < high */
337 if ((word
) GC_excl_table
[mid
].e_end
<= (word
) start_addr
) {
343 if ((word
) GC_excl_table
[low
].e_end
<= (word
) start_addr
) return 0;
344 return GC_excl_table
+ low
;
347 void GC_exclude_static_roots(start
, finish
)
351 struct exclusion
* next
;
352 size_t next_index
, i
;
354 if (0 == GC_excl_table_entries
) {
357 next
= GC_next_exclusion(start
);
360 if ((word
)(next
-> e_start
) < (word
) finish
) {
361 /* incomplete error check. */
362 ABORT("exclusion ranges overlap");
364 if ((word
)(next
-> e_start
) == (word
) finish
) {
365 /* extend old range backwards */
366 next
-> e_start
= (ptr_t
)start
;
369 next_index
= next
- GC_excl_table
;
370 for (i
= GC_excl_table_entries
; i
> next_index
; --i
) {
371 GC_excl_table
[i
] = GC_excl_table
[i
-1];
374 next_index
= GC_excl_table_entries
;
376 if (GC_excl_table_entries
== MAX_EXCLUSIONS
) ABORT("Too many exclusions");
377 GC_excl_table
[next_index
].e_start
= (ptr_t
)start
;
378 GC_excl_table
[next_index
].e_end
= (ptr_t
)finish
;
379 ++GC_excl_table_entries
;
382 /* Invoke push_conditional on ranges that are not excluded. */
383 void GC_push_conditional_with_exclusions(bottom
, top
, all
)
388 struct exclusion
* next
;
391 while (bottom
< top
) {
392 next
= GC_next_exclusion(bottom
);
393 if (0 == next
|| (excl_start
= next
-> e_start
) >= top
) {
394 GC_push_conditional(bottom
, top
, all
);
397 if (excl_start
> bottom
) GC_push_conditional(bottom
, excl_start
, all
);
398 bottom
= next
-> e_end
;
403 * In the absence of threads, push the stack contents.
404 * In the presence of threads, push enough of the current stack
405 * to ensure that callee-save registers saved in collector frames have been
408 void GC_push_current_stack(cold_gc_frame
)
411 # if defined(THREADS)
412 if (0 == cold_gc_frame
) return;
413 # ifdef STACK_GROWS_DOWN
414 GC_push_all_eager(GC_approx_sp(), cold_gc_frame
);
419 GC_push_all_eager( cold_gc_frame
, GC_approx_sp() );
422 # ifdef STACK_GROWS_DOWN
423 GC_push_all_stack_partially_eager( GC_approx_sp(), GC_stackbottom
,
426 /* We also need to push the register stack backing store. */
427 /* This should really be done in the same way as the */
428 /* regular stack. For now we fudge it a bit. */
429 /* Note that the backing store grows up, so we can't use */
430 /* GC_push_all_stack_partially_eager. */
432 extern word GC_save_regs_ret_val
;
433 /* Previously set to backing store pointer. */
434 ptr_t bsp
= (ptr_t
) GC_save_regs_ret_val
;
435 ptr_t cold_gc_bs_pointer
;
436 # ifdef ALL_INTERIOR_POINTERS
437 cold_gc_bs_pointer
= bsp
- 2048;
438 if (cold_gc_bs_pointer
< BACKING_STORE_BASE
) {
439 cold_gc_bs_pointer
= BACKING_STORE_BASE
;
441 GC_push_all(BACKING_STORE_BASE
, cold_gc_bs_pointer
);
443 cold_gc_bs_pointer
= BACKING_STORE_BASE
;
445 GC_push_all_eager(cold_gc_bs_pointer
, bsp
);
446 /* All values should be sufficiently aligned that we */
447 /* dont have to worry about the boundary. */
451 GC_push_all_stack_partially_eager( GC_stackbottom
, GC_approx_sp(),
454 # endif /* !THREADS */
458 * Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional
459 * on groups of pointers) on every top level accessible pointer.
460 * If all is FALSE, arrange to push only possibly altered values.
461 * Cold_gc_frame is an address inside a GC frame that
462 * remains valid until all marking is complete.
463 * A zero value indicates that it's OK to miss some
466 void GC_push_roots(all
, cold_gc_frame
)
473 * push registers - i.e., call GC_push_one(r) for each
474 * register contents r.
476 # ifdef USE_GENERIC_PUSH_REGS
477 GC_generic_push_regs(cold_gc_frame
);
479 GC_push_regs(); /* usually defined in machine_dep.c */
483 * Next push static data. This must happen early on, since it's
484 * not robust against mark stack overflow.
486 /* Reregister dynamic libraries, in case one got added. */
487 # if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(PCR)) \
489 GC_remove_tmp_roots();
490 GC_register_dynamic_libraries();
492 /* Mark everything in static data areas */
493 for (i
= 0; i
< n_root_sets
; i
++) {
494 GC_push_conditional_with_exclusions(
495 GC_static_roots
[i
].r_start
,
496 GC_static_roots
[i
].r_end
, all
);
500 * Now traverse stacks.
502 # if !defined(USE_GENERIC_PUSH_REGS)
503 GC_push_current_stack(cold_gc_frame
);
504 /* IN the threads case, this only pushes collector frames. */
505 /* In the USE_GENERIC_PUSH_REGS case, this is done inside */
506 /* GC_push_regs, so that we catch callee-save registers saved */
507 /* inside the GC_push_regs frame. */
509 if (GC_push_other_roots
!= 0) (*GC_push_other_roots
)();
510 /* In the threads case, this also pushes thread stacks. */