2000-02-17 Zack Weinberg <zack@wolery.cumb.org>
[official-gcc.git] / boehm-gc / nursery.c
blobab83afbaaf2f58e38d4a15de2ecba66f3c011683
1 /*
2 * Copyright (c) 1999 by Silicon Graphics. All rights reserved.
4 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
7 * Permission is hereby granted to use or copy this program
8 * for any purpose, provided the above notices are retained on all copies.
9 * Permission to modify the code and to distribute modified code is granted,
10 * provided the above notices are retained, and a notice that the code was
11 * modified is included with the above copyright notice.
14 #ifdef NURSERY
15 ??? This implementation is incomplete. If you are trying to
16 ??? compile this you are doing something wrong.
18 #include "nursery.h"
20 #define SCAN_STATICS_FOR_NURSERY
21 /* If this is not defined, the collector will not see */
22 /* references from static data areas to the nursery. */
24 struct copy_obj {
25 ptr_t forward; /* Forwarding link for copied objects. */
26 GC_copy_descriptor descr; /* Object descriptor */
27 word data[1];
30 ptr_t GC_nursery_start; /* Start of nursery area. */
31 /* Must be NURSERY_BLOCK_SIZE */
32 /* aligned. */
33 ptr_t GC_nursery_end; /* End of nursery area. */
34 unsigned char * GC_nursery_map;
35 /* GC_nursery_map[i] != 0 if an object */
36 /* starts on the ith 64-bit "word" of */
37 /* nursery. This simple structure has */
38 /* the advantage that */
39 /* allocation is cheap. Lookup is */
40 /* cheap for pointers to the head of */
41 /* an object, which should be the */
42 /* usual case. */
43 # define NURSERY_MAP_NOT_START 0 /* Not start of object. */
44 # define NURSERY_MAP_START 1 /* Start of object. */
45 # define NURSERY_MAP_PINNED 2 /* Start of pinned obj. */
47 # ifdef ALIGN_DOUBLE
48 # define NURSERY_WORD_SIZE (2 * sizeof(word))
49 # else
50 # define NURSERY_WORD_SIZE sizeof(word)
51 # endif
53 # define NURSERY_BLOCK_SIZE (HBLKSIZE/2)
54 /* HBLKSIZE must be a multiple of NURSERY_BLOCK_SIZE */
55 # define NURSERY_SIZE (1024 * NURSERY_BLOCK_SIZE)
57 size_t GC_nursery_size = NURSERY_SIZE;
58 /* Must be multiple of NURSERY_BLOCK_SIZE */
60 size_t GC_nursery_blocks; /* Number of blocks in the nursery. */
62 unsigned GC_next_nursery_block; /* index of next block we will attempt */
63 /* allocate from during this cycle. */
64 /* If it is pinned, we won't actually */
65 /* use it. */
67 unsigned short *GC_pinned; /* Number of pinned objects in ith */
68 /* nursery block. */
69 /* GC_pinned[i] != 0 if the ith nursery */
70 /* block is pinned, and thus not used */
71 /* for allocation. */
73 GC_copy_alloc_state global_alloc_state = (ptr_t)(-1); /* will overflow. */
75 /* Array of known rescuing pointers from the heap to the nursery. */
76 ptr_t ** nursery_rescuers;
77 /* Pointer to one past the last slot in rescuer table */
78 ptr_t ** nursery_rescuers_end;
79 /* Maximum number of known rescuing pointers. */
80 # define MAX_NURSERY_RESCUERS 32*1024
81 /* Add a rescuer to the list */
82 # define ADD_NURSERY_RESCUER(p) \
83 if (nursery_rescuers_end >= nursery_rescuers + MAX_NURSERY_RESCUERS) { \
84 ABORT("Nursery recuers overflow"); /* Fix later !!! */ \
85 } else { \
86 *nursery_rescuers_end++ = p; \
88 /* Remove rescuer at the given position in the table */
89 # define REMOVE_RESCUER(p) \
90 *p = *--nursery_rescuers_end
92 /* Should be called with allocator lock held. */
93 GC_nursery_init() {
94 GC_nursery_start = GET_MEM(GC_nursery_size);
95 GC_nursery_end = GC_nursery_start + GC_nursery_size;
96 GC_next_nursery_block = 0;
97 if (GC_nursery_start < GC_least_plausible_heap_addr) {
98 GC_least_plausible_heap_addr = GC_nursery_start;
100 if (GC_nursery_end > GC_greatest_plausible_heap_addr) {
101 GC_greatest_plausible_heap_addr = GC_nursery_end;
103 if (GC_nursery_start & (NURSERY_BLOCK_SIZE-1)) {
104 GC_err_printf1("Nursery area is misaligned!!");
105 /* This should be impossible, since GET_MEM returns HBLKSIZE */
106 /* aligned chunks, and that should be a multiple of */
107 /* NURSERY_BLOCK_SIZE */
108 ABORT("misaligned nursery");
110 GC_nursery_map = GET_MEM(GC_nursery_size/NURSERY_WORD_SIZE);
111 /* Map is cleared a block at a time when we allocate from the block. */
112 /* BZERO(GC_nursery_map, GC_nursery_size/NURSERY_WORD_SIZE); */
113 GC_nursery_blocks = GC_nursery_size/NURSERY_BLOCK_SIZE;
114 GC_pinned = GC_scratch_alloc(GC_nursery_blocks * sizeof(unsigned short));
115 BZERO(GC_pinned, GC_nursery_blocks);
116 nursery_rescuers = GET_MEM(MAX_NURSERY_RESCUERS * sizeof(ptr_t *));
117 nursery_rescuers_end = nursery_rescuers;
118 if (0 == GC_nursery_start || 0 == GC_nursery_map || 0 == nursery_rescuers)
119 ABORT("Insufficient memory for nursery");
122 #define PIN_OBJ(p) \
123 if (p >= GC_nursery_start && p < GC_nursery_end) { GC_pin_obj_checked(p); }
125 /* Pin the object at p, if it's in the nursery. */
126 void GC_pin_obj(ptr_t p) {
127 PIN_OBJ(p);
130 void (*GC_push_proc)(ptr_t) = 0;
132 /* Pin the object at p, which is known to be in the nursery. */
133 void GC_pin_obj_checked(ptr_t p) {
134 unsigned offset = p - GC_nursery_start;
135 unsigned word_offset = BYTES_TO_WORDS(offset);
136 unsigned blockno = (current - GC_nursery_start)/NURSERY_BLOCK_SIZE;
137 while (GC_nursery_map[word_offset] == NURSERY_MAP_NOT_START) {
138 --word_offset;
140 if (GC_nursery_map[word_offset] != NURSERY_MAP_PINNED) {
141 GC_nursery_map[word_offset] = NURSERY_MAP_PINNED;
142 ++GC_pinned[blockno];
143 ??Push object at GC_nursery_start + WORDS_TO_BYTES(word_offset)
144 ??onto mark stack.
148 void GC_scan_region_for_nursery(ptr_t low, ptr_t high) {
149 # if CPP_WORDSZ/8 != ALIGNMENT
150 --> fix this
151 # endif
152 word * l = (word *)((word)low + ALIGNMENT - 1 & ~(ALIGNMENT - 1));
153 word * h = (word *)((word)high & ~(ALIGNMENT - 1));
154 word * p;
155 for (p = l; p < h; ++p) {
156 PIN_OBJ(p);
160 /* Invoke GC_scan_region_for_nursery on ranges that are not excluded. */
161 void GC_scan_region_for_nursery_with_exclusions(ptr_t bottom, ptr_t top)
163 struct exclusion * next;
164 ptr_t excl_start;
166 while (bottom < top) {
167 next = GC_next_exclusion(bottom);
168 if (0 == next || (excl_start = next -> e_start) >= top) {
169 GC_scan_region_for_nursery(bottom, top);
170 return;
172 if (excl_start > bottom)
173 GC_scan_region_for_nursery(bottom, excl_start);
174 bottom = next -> e_end;
179 void GC_scan_stacks_for_nursery(void) {
180 # ifdef THREADS
181 --> fix this
182 # endif
183 # ifdef STACK_GROWS_DOWN
184 ptr_t stack_low = GC_approx_sp();
185 ptr_t stack_high = GC_stackbottom;
186 # else
187 ptr_t stack_low = GC_stackbottom;
188 ptr_t stack_high = GC_approx_sp();
189 # endif
190 GC_scan_region_for_nursery(stack_low, stack_high);
191 # ifdef IA64
192 GC_scan_region_for_nursery(BACKING_STORE_BASE,
193 (ptr_t) GC_save_regs_ret_val);
194 # endif
197 void GC_scan_roots_for_nursery(void) {
198 /* Scan registers. */
199 /* Direct GC_push_one to call GC_pin_obj instead of marking */
200 /* and pushing objects. */
201 /* This is a bit ugly, but we don't have to touch the */
202 /* platform-dependent code. */
204 void (*old_push_proc)(ptr_t) = GC_push_proc;
205 GC_push_proc = GC_pin_obj;
206 GC_push_regs();
207 GC_push_proc = old_push_proc;
208 GC_scan_stacks_for_nursery();
209 # ifdef SCAN_STATICS_FOR_NURSERY
210 # if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(PCR)) \
211 && !defined(SRC_M3)
212 GC_remove_tmp_roots();
213 GC_register_dynamic_libraries();
214 # endif
215 /* Mark everything in static data areas */
216 for (i = 0; i < n_root_sets; i++) {
217 GC_scan_region_for_nursery_with_exclusions (
218 GC_static_roots[i].r_start,
219 GC_static_roots[i].r_end);
221 # endif
224 /* Array of known rescuing pointers from the heap to the nursery. */
225 ptr_t ** nursery_rescuers;
227 /* Caller holds allocation lock. */
228 void GC_collect_nursery(void) {
229 int i;
230 ptr_t scan_ptr = 0;
231 STOP_WORLD;
232 for (i = 0; i < GC_nursery_blocks; ++i) GC_pinned[i] = 0;
233 GC_scan_roots_for_nursery();
234 /* All objects referenced by roots are now pinned. */
235 /* Their contents are described by */
236 /* mark stack entries. */
238 /* Pin blocks corresponding to valid allocation states. */
239 /* that probably happens automagically if the allocation */
240 /* states are kept where we can see them. */
241 /* It will take work if static roots are not scanned. */
242 /* We want to do this both for correctness and to avoid */
243 /* promoting very young objects. */
245 /* Somehow capture dirty bits. Update rescuers array to */
246 /* reflect newly valid and invalid references from dirty */
247 /* pages. Other references should remain valid, since the */
248 /* referents should have been pinned. */
250 /* Traverse the old object heap. Pin objects in the */
251 /* nursery that are ambiguously referenced, copy those */
252 /* that are unambiguously referenced. */
254 /* Traverse objects in mark stack. */
255 /* If referenced object is in pinned block, add contents */
256 /* to mark stack. If referenced object is forwarded, */
257 /* update pointer. Otherwise reallocate the object in the */
258 /* old heap, copy its contents, and then enqueue its */
259 /* contents in the mark stack. */
260 START_WORLD;
263 /* Initialize an allocation state so that it can be used for */
264 /* allocation. This implicitly reserves a small section of the */
265 /* nursery for use with this allocator. */
266 /* Also called to replenish an allocator that has been */
267 /* exhausted. */
268 void GC_init_copy_alloc_state(GC_copy_alloc_state *)
269 unsigned next_block;
270 ptr_t block_addr;
271 LOCK();
272 next_block = GC_next_nursery_block;
273 while(is_pinned[next_block] && next_block < GC_nursery_blocks) {
274 ++next_block;
276 if (next_block < GC_nursery_blocks) {
277 block_addr = GC_nursery_start + NURSERY_BLOCK_SIZE * next_block;
278 GC_next_nursery_block = next_block + 1;
279 BZERO(GC_nursery_map + next_block *
280 (NURSERY_BLOCK_SIZE/NURSERY_WORD_SIZE),
281 NURSERY_BLOCK_SIZE/NURSERY_WORD_SIZE);
282 *GC_copy_alloc_state = block_addr;
283 UNLOCK();
284 } else {
285 GC_collect_nursery();
286 GC_next_nursery_block = 0;
287 UNLOCK();
288 get_new_block(s);
292 GC_PTR GC_copying_malloc2(GC_copy_descriptor *d, GC_copy_alloc_state *s) {
293 size_t sz = GC_SIZE_FROM_DESCRIPTOR(d);
294 ptrdiff_t offset;
295 ptr_t result = *s;
296 ptr_t new = result + sz;
297 if (new & COPY_BLOCK_MASK <= result & COPY_BLOCK_MASK> {
298 GC_init_copy_alloc_state(s);
299 result = *s;
300 new = result + sz;
301 GC_ASSERT(new & COPY_BLOCK_MASK > result & COPY_BLOCK_MASK>
303 (struct copy_obj *)result -> descr = d;
304 (struct copy_obj *)result -> forward = 0;
305 offset = (result - GC_nursery_start)/NURSERY_WORD_SIZE;
306 GC_nursery_map[offset] = NURSERY_MAP_NOT_START;
309 GC_PTR GC_copying_malloc(GC_copy_descriptor *d) {
312 #endif /* NURSERY */