source: trunk/gcc/boehm-gc/stubborn.c@ 2446

Last change on this file since 2446 was 2, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 8.8 KB
Line 
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, July 31, 1995 5:02 pm PDT */
15
16
17#include "private/gc_priv.h"
18
19# ifdef STUBBORN_ALLOC
20/* Stubborn object (hard to change, nearly immutable) allocation. */
21
22extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
23
24#define GENERAL_MALLOC(lb,k) \
25 (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
26
27/* Data structure representing immutable objects that */
28/* are still being initialized. */
29/* This is a bit baroque in order to avoid acquiring */
30/* the lock twice for a typical allocation. */
31
32GC_PTR * GC_changing_list_start;
33
34void GC_push_stubborn_structures GC_PROTO((void))
35{
36 GC_push_all((ptr_t)(&GC_changing_list_start),
37 (ptr_t)(&GC_changing_list_start) + sizeof(GC_PTR *));
38}
39
40# ifdef THREADS
41 VOLATILE GC_PTR * VOLATILE GC_changing_list_current;
42# else
43 GC_PTR * GC_changing_list_current;
44# endif
45 /* Points at last added element. Also (ab)used for */
46 /* synchronization. Updates and reads are assumed atomic. */
47
48GC_PTR * GC_changing_list_limit;
49 /* Points at the last word of the buffer, which is always 0 */
50 /* All entries in (GC_changing_list_current, */
51 /* GC_changing_list_limit] are 0 */
52
53
54void GC_stubborn_init()
55{
56# define INIT_SIZE 10
57
58 GC_changing_list_start = (GC_PTR *)
59 GC_INTERNAL_MALLOC(
60 (word)(INIT_SIZE * sizeof(GC_PTR)),
61 PTRFREE);
62 BZERO(GC_changing_list_start,
63 INIT_SIZE * sizeof(GC_PTR));
64 if (GC_changing_list_start == 0) {
65 GC_err_printf0("Insufficient space to start up\n");
66 ABORT("GC_stubborn_init: put of space");
67 }
68 GC_changing_list_current = GC_changing_list_start;
69 GC_changing_list_limit = GC_changing_list_start + INIT_SIZE - 1;
70 * GC_changing_list_limit = 0;
71}
72
73/* Compact and possibly grow GC_uninit_list. The old copy is */
74/* left alone. Lock must be held. */
75/* When called GC_changing_list_current == GC_changing_list_limit */
76/* which is one past the current element. */
77/* When we finish GC_changing_list_current again points one past last */
78/* element. */
79/* Invariant while this is running: GC_changing_list_current */
80/* points at a word containing 0. */
81/* Returns FALSE on failure. */
82GC_bool GC_compact_changing_list()
83{
84 register GC_PTR *p, *q;
85 register word count = 0;
86 word old_size = (char **)GC_changing_list_limit
87 - (char **)GC_changing_list_start+1;
88 /* The casts are needed as a workaround for an Amiga bug */
89 register word new_size = old_size;
90 GC_PTR * new_list;
91
92 for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
93 if (*p != 0) count++;
94 }
95 if (2 * count > old_size) new_size = 2 * count;
96 new_list = (GC_PTR *)
97 GC_INTERNAL_MALLOC(
98 new_size * sizeof(GC_PTR), PTRFREE);
99 /* PTRFREE is a lie. But we don't want the collector to */
100 /* consider these. We do want the list itself to be */
101 /* collectable. */
102 if (new_list == 0) return(FALSE);
103 BZERO(new_list, new_size * sizeof(GC_PTR));
104 q = new_list;
105 for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
106 if (*p != 0) *q++ = *p;
107 }
108 GC_changing_list_start = new_list;
109 GC_changing_list_limit = new_list + new_size - 1;
110 GC_changing_list_current = q;
111 return(TRUE);
112}
113
114/* Add p to changing list. Clear p on failure. */
115# define ADD_CHANGING(p) \
116 { \
117 register struct hblk * h = HBLKPTR(p); \
118 register word index = PHT_HASH(h); \
119 \
120 set_pht_entry_from_index(GC_changed_pages, index); \
121 } \
122 if (*GC_changing_list_current != 0 \
123 && ++GC_changing_list_current == GC_changing_list_limit) { \
124 if (!GC_compact_changing_list()) (p) = 0; \
125 } \
126 *GC_changing_list_current = p;
127
128void GC_change_stubborn(p)
129GC_PTR p;
130{
131 DCL_LOCK_STATE;
132
133 DISABLE_SIGNALS();
134 LOCK();
135 ADD_CHANGING(p);
136 UNLOCK();
137 ENABLE_SIGNALS();
138}
139
140void GC_end_stubborn_change(p)
141GC_PTR p;
142{
143# ifdef THREADS
144 register VOLATILE GC_PTR * my_current = GC_changing_list_current;
145# else
146 register GC_PTR * my_current = GC_changing_list_current;
147# endif
148 register GC_bool tried_quick;
149 DCL_LOCK_STATE;
150
151 if (*my_current == p) {
152 /* Hopefully the normal case. */
153 /* Compaction could not have been running when we started. */
154 *my_current = 0;
155# ifdef THREADS
156 if (my_current == GC_changing_list_current) {
157 /* Compaction can't have run in the interim. */
158 /* We got away with the quick and dirty approach. */
159 return;
160 }
161 tried_quick = TRUE;
162# else
163 return;
164# endif
165 } else {
166 tried_quick = FALSE;
167 }
168 DISABLE_SIGNALS();
169 LOCK();
170 my_current = GC_changing_list_current;
171 for (; my_current >= GC_changing_list_start; my_current--) {
172 if (*my_current == p) {
173 *my_current = 0;
174 UNLOCK();
175 ENABLE_SIGNALS();
176 return;
177 }
178 }
179 if (!tried_quick) {
180 GC_err_printf1("Bad arg to GC_end_stubborn_change: 0x%lx\n",
181 (unsigned long)p);
182 ABORT("Bad arg to GC_end_stubborn_change");
183 }
184 UNLOCK();
185 ENABLE_SIGNALS();
186}
187
188/* Allocate lb bytes of composite (pointerful) data */
189/* No pointer fields may be changed after a call to */
190/* GC_end_stubborn_change(p) where p is the value */
191/* returned by GC_malloc_stubborn. */
192# ifdef __STDC__
193 GC_PTR GC_malloc_stubborn(size_t lb)
194# else
195 GC_PTR GC_malloc_stubborn(lb)
196 size_t lb;
197# endif
198{
199register ptr_t op;
200register ptr_t *opp;
201register word lw;
202ptr_t result;
203DCL_LOCK_STATE;
204
205 if( SMALL_OBJ(lb) ) {
206# ifdef MERGE_SIZES
207 lw = GC_size_map[lb];
208# else
209 lw = ALIGNED_WORDS(lb);
210# endif
211 opp = &(GC_sobjfreelist[lw]);
212 FASTLOCK();
213 if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
214 FASTUNLOCK();
215 result = GC_generic_malloc((word)lb, STUBBORN);
216 goto record;
217 }
218 *opp = obj_link(op);
219 obj_link(op) = 0;
220 GC_words_allocd += lw;
221 result = (GC_PTR) op;
222 ADD_CHANGING(result);
223 FASTUNLOCK();
224 return((GC_PTR)result);
225 } else {
226 result = (GC_PTR)
227 GC_generic_malloc((word)lb, STUBBORN);
228 }
229record:
230 DISABLE_SIGNALS();
231 LOCK();
232 ADD_CHANGING(result);
233 UNLOCK();
234 ENABLE_SIGNALS();
235 return((GC_PTR)GC_clear_stack(result));
236}
237
238
239/* Functions analogous to GC_read_dirty and GC_page_was_dirty. */
240/* Report pages on which stubborn objects were changed. */
241void GC_read_changed()
242{
243 register GC_PTR * p = GC_changing_list_start;
244 register GC_PTR q;
245 register struct hblk * h;
246 register word index;
247
248 if (p == 0) /* initializing */ return;
249 BCOPY(GC_changed_pages, GC_prev_changed_pages,
250 (sizeof GC_changed_pages));
251 BZERO(GC_changed_pages, (sizeof GC_changed_pages));
252 for (; p <= GC_changing_list_current; p++) {
253 if ((q = *p) != 0) {
254 h = HBLKPTR(q);
255 index = PHT_HASH(h);
256 set_pht_entry_from_index(GC_changed_pages, index);
257 }
258 }
259}
260
261GC_bool GC_page_was_changed(h)
262struct hblk * h;
263{
264 register word index = PHT_HASH(h);
265
266 return(get_pht_entry_from_index(GC_prev_changed_pages, index));
267}
268
269/* Remove unreachable entries from changed list. Should only be */
270/* called with mark bits consistent and lock held. */
271void GC_clean_changing_list()
272{
273 register GC_PTR * p = GC_changing_list_start;
274 register GC_PTR q;
275 register ptr_t r;
276 register unsigned long count = 0;
277 register unsigned long dropped_count = 0;
278
279 if (p == 0) /* initializing */ return;
280 for (; p <= GC_changing_list_current; p++) {
281 if ((q = *p) != 0) {
282 count++;
283 r = (ptr_t)GC_base(q);
284 if (r == 0 || !GC_is_marked(r)) {
285 *p = 0;
286 dropped_count++;
287 }
288 }
289 }
290# ifdef PRINTSTATS
291 if (count > 0) {
292 GC_printf2("%lu entries in changing list: reclaimed %lu\n",
293 (unsigned long)count, (unsigned long)dropped_count);
294 }
295# endif
296}
297
298#else /* !STUBBORN_ALLOC */
299
300# ifdef __STDC__
301 GC_PTR GC_malloc_stubborn(size_t lb)
302# else
303 GC_PTR GC_malloc_stubborn(lb)
304 size_t lb;
305# endif
306{
307 return(GC_malloc(lb));
308}
309
310/*ARGSUSED*/
311void GC_end_stubborn_change(p)
312GC_PTR p;
313{
314}
315
316/*ARGSUSED*/
317void GC_change_stubborn(p)
318GC_PTR p;
319{
320}
321
322void GC_push_stubborn_structures GC_PROTO((void))
323{
324}
325
326#endif
Note: See TracBrowser for help on using the repository browser.