| 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 | /* Boehm, August 9, 1995 6:09 pm PDT */
|
|---|
| 15 | # include "private/gc_priv.h"
|
|---|
| 16 |
|
|---|
| 17 | /*
|
|---|
| 18 | * We maintain several hash tables of hblks that have had false hits.
|
|---|
| 19 | * Each contains one bit per hash bucket; If any page in the bucket
|
|---|
| 20 | * has had a false hit, we assume that all of them have.
|
|---|
| 21 | * See the definition of page_hash_table in gc_private.h.
|
|---|
| 22 | * False hits from the stack(s) are much more dangerous than false hits
|
|---|
| 23 | * from elsewhere, since the former can pin a large object that spans the
|
|---|
| 24 | * block, eventhough it does not start on the dangerous block.
|
|---|
| 25 | */
|
|---|
| 26 |
|
|---|
| 27 | /*
|
|---|
| 28 | * Externally callable routines are:
|
|---|
| 29 |
|
|---|
| 30 | * GC_add_to_black_list_normal
|
|---|
| 31 | * GC_add_to_black_list_stack
|
|---|
| 32 | * GC_promote_black_lists
|
|---|
| 33 | * GC_is_black_listed
|
|---|
| 34 | *
|
|---|
| 35 | * All require that the allocator lock is held.
|
|---|
| 36 | */
|
|---|
| 37 |
|
|---|
| 38 | /* Pointers to individual tables. We replace one table by another by */
|
|---|
| 39 | /* switching these pointers. */
|
|---|
| 40 | word * GC_old_normal_bl;
|
|---|
| 41 | /* Nonstack false references seen at last full */
|
|---|
| 42 | /* collection. */
|
|---|
| 43 | word * GC_incomplete_normal_bl;
|
|---|
| 44 | /* Nonstack false references seen since last */
|
|---|
| 45 | /* full collection. */
|
|---|
| 46 | word * GC_old_stack_bl;
|
|---|
| 47 | word * GC_incomplete_stack_bl;
|
|---|
| 48 |
|
|---|
| 49 | word GC_total_stack_black_listed;
|
|---|
| 50 |
|
|---|
| 51 | word GC_black_list_spacing = MINHINCR*HBLKSIZE; /* Initial rough guess */
|
|---|
| 52 |
|
|---|
| 53 | void GC_clear_bl();
|
|---|
| 54 |
|
|---|
| 55 | # if defined(__STDC__) || defined(__cplusplus)
|
|---|
| 56 | void GC_default_print_heap_obj_proc(ptr_t p)
|
|---|
| 57 | # else
|
|---|
| 58 | void GC_default_print_heap_obj_proc(p)
|
|---|
| 59 | ptr_t p;
|
|---|
| 60 | # endif
|
|---|
| 61 | {
|
|---|
| 62 | ptr_t base = GC_base(p);
|
|---|
| 63 |
|
|---|
| 64 | GC_err_printf2("start: 0x%lx, appr. length: %ld", base, GC_size(base));
|
|---|
| 65 | }
|
|---|
| 66 |
|
|---|
| 67 | void (*GC_print_heap_obj) GC_PROTO((ptr_t p)) =
|
|---|
| 68 | GC_default_print_heap_obj_proc;
|
|---|
| 69 |
|
|---|
| 70 | void GC_print_source_ptr(p)
|
|---|
| 71 | ptr_t p;
|
|---|
| 72 | {
|
|---|
| 73 | ptr_t base = GC_base(p);
|
|---|
| 74 | if (0 == base) {
|
|---|
| 75 | if (0 == p) {
|
|---|
| 76 | GC_err_printf0("in register");
|
|---|
| 77 | } else {
|
|---|
| 78 | GC_err_printf0("in root set");
|
|---|
| 79 | }
|
|---|
| 80 | } else {
|
|---|
| 81 | GC_err_printf0("in object at ");
|
|---|
| 82 | (*GC_print_heap_obj)(base);
|
|---|
| 83 | }
|
|---|
| 84 | }
|
|---|
| 85 |
|
|---|
| 86 | void GC_bl_init()
|
|---|
| 87 | {
|
|---|
| 88 | if (!GC_all_interior_pointers) {
|
|---|
| 89 | GC_old_normal_bl = (word *)
|
|---|
| 90 | GC_scratch_alloc((word)(sizeof (page_hash_table)));
|
|---|
| 91 | GC_incomplete_normal_bl = (word *)GC_scratch_alloc
|
|---|
| 92 | ((word)(sizeof(page_hash_table)));
|
|---|
| 93 | if (GC_old_normal_bl == 0 || GC_incomplete_normal_bl == 0) {
|
|---|
| 94 | GC_err_printf0("Insufficient memory for black list\n");
|
|---|
| 95 | EXIT();
|
|---|
| 96 | }
|
|---|
| 97 | GC_clear_bl(GC_old_normal_bl);
|
|---|
| 98 | GC_clear_bl(GC_incomplete_normal_bl);
|
|---|
| 99 | }
|
|---|
| 100 | GC_old_stack_bl = (word *)GC_scratch_alloc((word)(sizeof(page_hash_table)));
|
|---|
| 101 | GC_incomplete_stack_bl = (word *)GC_scratch_alloc
|
|---|
| 102 | ((word)(sizeof(page_hash_table)));
|
|---|
| 103 | if (GC_old_stack_bl == 0 || GC_incomplete_stack_bl == 0) {
|
|---|
| 104 | GC_err_printf0("Insufficient memory for black list\n");
|
|---|
| 105 | EXIT();
|
|---|
| 106 | }
|
|---|
| 107 | GC_clear_bl(GC_old_stack_bl);
|
|---|
| 108 | GC_clear_bl(GC_incomplete_stack_bl);
|
|---|
| 109 | }
|
|---|
| 110 |
|
|---|
| 111 | void GC_clear_bl(doomed)
|
|---|
| 112 | word *doomed;
|
|---|
| 113 | {
|
|---|
| 114 | BZERO(doomed, sizeof(page_hash_table));
|
|---|
| 115 | }
|
|---|
| 116 |
|
|---|
| 117 | void GC_copy_bl(old, new)
|
|---|
| 118 | word *new, *old;
|
|---|
| 119 | {
|
|---|
| 120 | BCOPY(old, new, sizeof(page_hash_table));
|
|---|
| 121 | }
|
|---|
| 122 |
|
|---|
| 123 | static word total_stack_black_listed();
|
|---|
| 124 |
|
|---|
| 125 | /* Signal the completion of a collection. Turn the incomplete black */
|
|---|
| 126 | /* lists into new black lists, etc. */
|
|---|
| 127 | void GC_promote_black_lists()
|
|---|
| 128 | {
|
|---|
| 129 | word * very_old_normal_bl = GC_old_normal_bl;
|
|---|
| 130 | word * very_old_stack_bl = GC_old_stack_bl;
|
|---|
| 131 |
|
|---|
| 132 | GC_old_normal_bl = GC_incomplete_normal_bl;
|
|---|
| 133 | GC_old_stack_bl = GC_incomplete_stack_bl;
|
|---|
| 134 | if (!GC_all_interior_pointers) {
|
|---|
| 135 | GC_clear_bl(very_old_normal_bl);
|
|---|
| 136 | }
|
|---|
| 137 | GC_clear_bl(very_old_stack_bl);
|
|---|
| 138 | GC_incomplete_normal_bl = very_old_normal_bl;
|
|---|
| 139 | GC_incomplete_stack_bl = very_old_stack_bl;
|
|---|
| 140 | GC_total_stack_black_listed = total_stack_black_listed();
|
|---|
| 141 | # ifdef PRINTSTATS
|
|---|
| 142 | GC_printf1("%ld bytes in heap blacklisted for interior pointers\n",
|
|---|
| 143 | (unsigned long)GC_total_stack_black_listed);
|
|---|
| 144 | # endif
|
|---|
| 145 | if (GC_total_stack_black_listed != 0) {
|
|---|
| 146 | GC_black_list_spacing =
|
|---|
| 147 | HBLKSIZE*(GC_heapsize/GC_total_stack_black_listed);
|
|---|
| 148 | }
|
|---|
| 149 | if (GC_black_list_spacing < 3 * HBLKSIZE) {
|
|---|
| 150 | GC_black_list_spacing = 3 * HBLKSIZE;
|
|---|
| 151 | }
|
|---|
| 152 | if (GC_black_list_spacing > MAXHINCR * HBLKSIZE) {
|
|---|
| 153 | GC_black_list_spacing = MAXHINCR * HBLKSIZE;
|
|---|
| 154 | /* Makes it easier to allocate really huge blocks, which otherwise */
|
|---|
| 155 | /* may have problems with nonuniform blacklist distributions. */
|
|---|
| 156 | /* This way we should always succeed immediately after growing the */
|
|---|
| 157 | /* heap. */
|
|---|
| 158 | }
|
|---|
| 159 | }
|
|---|
| 160 |
|
|---|
| 161 | void GC_unpromote_black_lists()
|
|---|
| 162 | {
|
|---|
| 163 | if (!GC_all_interior_pointers) {
|
|---|
| 164 | GC_copy_bl(GC_old_normal_bl, GC_incomplete_normal_bl);
|
|---|
| 165 | }
|
|---|
| 166 | GC_copy_bl(GC_old_stack_bl, GC_incomplete_stack_bl);
|
|---|
| 167 | }
|
|---|
| 168 |
|
|---|
| 169 | /* P is not a valid pointer reference, but it falls inside */
|
|---|
| 170 | /* the plausible heap bounds. */
|
|---|
| 171 | /* Add it to the normal incomplete black list if appropriate. */
|
|---|
| 172 | #ifdef PRINT_BLACK_LIST
|
|---|
| 173 | void GC_add_to_black_list_normal(p, source)
|
|---|
| 174 | ptr_t source;
|
|---|
| 175 | #else
|
|---|
| 176 | void GC_add_to_black_list_normal(p)
|
|---|
| 177 | #endif
|
|---|
| 178 | word p;
|
|---|
| 179 | {
|
|---|
| 180 | if (!(GC_modws_valid_offsets[p & (sizeof(word)-1)])) return;
|
|---|
| 181 | {
|
|---|
| 182 | register int index = PHT_HASH(p);
|
|---|
| 183 |
|
|---|
| 184 | if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_normal_bl, index)) {
|
|---|
| 185 | # ifdef PRINT_BLACK_LIST
|
|---|
| 186 | if (!get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
|
|---|
| 187 | GC_err_printf2(
|
|---|
| 188 | "Black listing (normal) 0x%lx referenced from 0x%lx ",
|
|---|
| 189 | (unsigned long) p, (unsigned long) source);
|
|---|
| 190 | GC_print_source_ptr(source);
|
|---|
| 191 | GC_err_puts("\n");
|
|---|
| 192 | }
|
|---|
| 193 | # endif
|
|---|
| 194 | set_pht_entry_from_index(GC_incomplete_normal_bl, index);
|
|---|
| 195 | } /* else this is probably just an interior pointer to an allocated */
|
|---|
| 196 | /* object, and isn't worth black listing. */
|
|---|
| 197 | }
|
|---|
| 198 | }
|
|---|
| 199 |
|
|---|
| 200 | /* And the same for false pointers from the stack. */
|
|---|
| 201 | #ifdef PRINT_BLACK_LIST
|
|---|
| 202 | void GC_add_to_black_list_stack(p, source)
|
|---|
| 203 | ptr_t source;
|
|---|
| 204 | #else
|
|---|
| 205 | void GC_add_to_black_list_stack(p)
|
|---|
| 206 | #endif
|
|---|
| 207 | word p;
|
|---|
| 208 | {
|
|---|
| 209 | register int index = PHT_HASH(p);
|
|---|
| 210 |
|
|---|
| 211 | if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_stack_bl, index)) {
|
|---|
| 212 | # ifdef PRINT_BLACK_LIST
|
|---|
|
|---|