~ubuntu-branches/ubuntu/intrepid/ecl/intrepid

« back to all changes in this revision

Viewing changes to src/gc/blacklst.c

  • Committer: Bazaar Package Importer
  • Author(s): Peter Van Eynde
  • Date: 2006-05-17 02:46:26 UTC
  • Revision ID: james.westby@ubuntu.com-20060517024626-lljr08ftv9g9vefl
Tags: upstream-0.9h-20060510
ImportĀ upstreamĀ versionĀ 0.9h-20060510

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
213
            if (!get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
 
214
                  GC_err_printf2(
 
215
                        "Black listing (stack) 0x%lx referenced from 0x%lx ",
 
216
                        (unsigned long)p, (unsigned long)source);
 
217
                  GC_print_source_ptr(source);
 
218
                  GC_err_puts("\n");
 
219
            }
 
220
#       endif
 
221
        set_pht_entry_from_index(GC_incomplete_stack_bl, index);
 
222
    }
 
223
}
 
224
 
 
225
/*
 
226
 * Is the block starting at h of size len bytes black listed?   If so,
 
227
 * return the address of the next plausible r such that (r, len) might not
 
228
 * be black listed.  (R may not actually be in the heap.  We guarantee only
 
229
 * that every smaller value of r after h is also black listed.)
 
230
 * If (h,len) is not black listed, return 0.
 
231
 * Knows about the structure of the black list hash tables.
 
232
 */
 
233
struct hblk * GC_is_black_listed(h, len)
 
234
struct hblk * h;
 
235
word len;
 
236
{
 
237
    register int index = PHT_HASH((word)h);
 
238
    register word i;
 
239
    word nblocks = divHBLKSZ(len);
 
240
 
 
241
    if (!GC_all_interior_pointers) {
 
242
      if (get_pht_entry_from_index(GC_old_normal_bl, index)
 
243
          || get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
 
244
        return(h+1);
 
245
      }
 
246
    }
 
247
    
 
248
    for (i = 0; ; ) {
 
249
        if (GC_old_stack_bl[divWORDSZ(index)] == 0
 
250
            && GC_incomplete_stack_bl[divWORDSZ(index)] == 0) {
 
251
            /* An easy case */
 
252
            i += WORDSZ - modWORDSZ(index);
 
253
        } else {
 
254
          if (get_pht_entry_from_index(GC_old_stack_bl, index)
 
255
              || get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
 
256
            return(h+i+1);
 
257
          }
 
258
          i++;
 
259
        }
 
260
        if (i >= nblocks) break;
 
261
        index = PHT_HASH((word)(h+i));
 
262
    }
 
263
    return(0);
 
264
}
 
265
 
 
266
 
 
267
/* Return the number of blacklisted blocks in a given range.    */
 
268
/* Used only for statistical purposes.                          */
 
269
/* Looks only at the GC_incomplete_stack_bl.                    */
 
270
word GC_number_stack_black_listed(start, endp1)
 
271
struct hblk *start, *endp1;
 
272
{
 
273
    register struct hblk * h;
 
274
    word result = 0;
 
275
    
 
276
    for (h = start; h < endp1; h++) {
 
277
        register int index = PHT_HASH((word)h);
 
278
        
 
279
        if (get_pht_entry_from_index(GC_old_stack_bl, index)) result++;
 
280
    }
 
281
    return(result);
 
282
}
 
283
 
 
284
 
 
285
/* Return the total number of (stack) black-listed bytes. */
 
286
static word total_stack_black_listed()
 
287
{
 
288
    register unsigned i;
 
289
    word total = 0;
 
290
    
 
291
    for (i = 0; i < GC_n_heap_sects; i++) {
 
292
        struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
 
293
        word len = (word) GC_heap_sects[i].hs_bytes;
 
294
        struct hblk * endp1 = start + len/HBLKSIZE;
 
295
        
 
296
        total += GC_number_stack_black_listed(start, endp1);
 
297
    }
 
298
    return(total * HBLKSIZE);
 
299
}
 
300