OSDN Git Service

PR driver/40144
[pf3gnuchains/gcc-fork.git] / boehm-gc / stubborn.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 /* 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
22 extern 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
32 GC_PTR * GC_changing_list_start;
33
34 void 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
48 GC_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
54 void 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.                                            */
82 GC_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
128 void GC_change_stubborn(p)
129 GC_PTR p;
130 {
131     DCL_LOCK_STATE;
132     
133     DISABLE_SIGNALS();
134     LOCK();
135     ADD_CHANGING(p);
136     UNLOCK();
137     ENABLE_SIGNALS();
138 }
139
140 void GC_end_stubborn_change(p)
141 GC_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 {
199 register ptr_t op;
200 register ptr_t *opp;
201 register word lw;
202 ptr_t result;
203 DCL_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    }
229 record:
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.         */
241 void 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
261 GC_bool GC_page_was_changed(h)
262 struct 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.              */
271 void 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*/
311 void GC_end_stubborn_change(p)
312 GC_PTR p;
313 {
314 }
315
316 /*ARGSUSED*/
317 void GC_change_stubborn(p)
318 GC_PTR p;
319 {
320 }
321
322 void GC_push_stubborn_structures GC_PROTO((void))
323 {
324 }
325
326 #endif