OSDN Git Service

Imported version version 5.0alpha6.
[pf3gnuchains/gcc-fork.git] / boehm-gc / malloc.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, February 7, 1996 4:32 pm PST */
15  
16 #include <stdio.h>
17 #include "gc_priv.h"
18
19 extern ptr_t GC_clear_stack();  /* in misc.c, behaves like identity */
20 void GC_extend_size_map();      /* in misc.c. */
21
22 /* Allocate reclaim list for kind:      */
23 /* Return TRUE on success               */
24 GC_bool GC_alloc_reclaim_list(kind)
25 register struct obj_kind * kind;
26 {
27     struct hblk ** result = (struct hblk **)
28                 GC_scratch_alloc((MAXOBJSZ+1) * sizeof(struct hblk *));
29     if (result == 0) return(FALSE);
30     BZERO(result, (MAXOBJSZ+1)*sizeof(struct hblk *));
31     kind -> ok_reclaim_list = result;
32     return(TRUE);
33 }
34
35 /* allocate lb bytes for an object of kind.     */
36 /* Should not be used to directly to allocate   */
37 /* objects such as STUBBORN objects that        */
38 /* require special handling on allocation.      */
39 /* First a version that assumes we already      */
40 /* hold lock:                                   */
41 ptr_t GC_generic_malloc_inner(lb, k)
42 register word lb;
43 register int k;
44 {
45 register word lw;
46 register ptr_t op;
47 register ptr_t *opp;
48
49     if( SMALL_OBJ(lb) ) {
50         register struct obj_kind * kind = GC_obj_kinds + k;
51 #       ifdef MERGE_SIZES
52           lw = GC_size_map[lb];
53 #       else
54           lw = ALIGNED_WORDS(lb);
55           if (lw == 0) lw = 1;
56 #       endif
57         opp = &(kind -> ok_freelist[lw]);
58         if( (op = *opp) == 0 ) {
59 #           ifdef MERGE_SIZES
60               if (GC_size_map[lb] == 0) {
61                 if (!GC_is_initialized)  GC_init_inner();
62                 if (GC_size_map[lb] == 0) GC_extend_size_map(lb);
63                 return(GC_generic_malloc_inner(lb, k));
64               }
65 #           else
66               if (!GC_is_initialized) {
67                 GC_init_inner();
68                 return(GC_generic_malloc_inner(lb, k));
69               }
70 #           endif
71             if (kind -> ok_reclaim_list == 0) {
72                 if (!GC_alloc_reclaim_list(kind)) goto out;
73             }
74             op = GC_allocobj(lw, k);
75             if (op == 0) goto out;
76         }
77         /* Here everything is in a consistent state.    */
78         /* We assume the following assignment is        */
79         /* atomic.  If we get aborted                   */
80         /* after the assignment, we lose an object,     */
81         /* but that's benign.                           */
82         /* Volatile declarations may need to be added   */
83         /* to prevent the compiler from breaking things.*/
84         /* If we only execute the second of the         */
85         /* following assignments, we lose the free      */
86         /* list, but that should still be OK, at least  */
87         /* for garbage collected memory.                */
88         *opp = obj_link(op);
89         obj_link(op) = 0;
90     } else {
91         register struct hblk * h;
92         register word n_blocks = divHBLKSZ(ADD_SLOP(lb)
93                                            + HDR_BYTES + HBLKSIZE-1);
94         
95         if (!GC_is_initialized) GC_init_inner();
96         /* Do our share of marking work */
97           if(GC_incremental && !GC_dont_gc)
98                 GC_collect_a_little_inner((int)n_blocks);
99         lw = ROUNDED_UP_WORDS(lb);
100         h = GC_allochblk(lw, k, 0);
101 #       ifdef USE_MUNMAP
102           if (0 == h) {
103             GC_merge_unmapped();
104             h = GC_allochblk(lw, k, 0);
105           }
106 #       endif
107         while (0 == h && GC_collect_or_expand(n_blocks, FALSE)) {
108           h = GC_allochblk(lw, k, 0);
109         }
110         if (h == 0) {
111             op = 0;
112         } else {
113             op = (ptr_t) (h -> hb_body);
114             GC_words_wasted += BYTES_TO_WORDS(n_blocks * HBLKSIZE) - lw;
115         }
116     }
117     GC_words_allocd += lw;
118     
119 out:
120     return((ptr_t)op);
121 }
122
123 ptr_t GC_generic_malloc(lb, k)
124 register word lb;
125 register int k;
126 {
127     ptr_t result;
128     DCL_LOCK_STATE;
129
130     GC_INVOKE_FINALIZERS();
131     DISABLE_SIGNALS();
132     LOCK();
133     result = GC_generic_malloc_inner(lb, k);
134     UNLOCK();
135     ENABLE_SIGNALS();
136     if (0 == result) {
137         return((*GC_oom_fn)(lb));
138     } else {
139         return(result);
140     }
141 }   
142
143
144 #define GENERAL_MALLOC(lb,k) \
145     (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
146 /* We make the GC_clear_stack_call a tail call, hoping to get more of   */
147 /* the stack.                                                           */
148
149 /* Allocate lb bytes of atomic (pointerfree) data */
150 # ifdef __STDC__
151     GC_PTR GC_malloc_atomic(size_t lb)
152 # else
153     GC_PTR GC_malloc_atomic(lb)
154     size_t lb;
155 # endif
156 {
157 register ptr_t op;
158 register ptr_t * opp;
159 register word lw;
160 DCL_LOCK_STATE;
161
162     if( SMALL_OBJ(lb) ) {
163 #       ifdef MERGE_SIZES
164           lw = GC_size_map[lb];
165 #       else
166           lw = ALIGNED_WORDS(lb);
167 #       endif
168         opp = &(GC_aobjfreelist[lw]);
169         FASTLOCK();
170         if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
171             FASTUNLOCK();
172             return(GENERAL_MALLOC((word)lb, PTRFREE));
173         }
174         /* See above comment on signals.        */
175         *opp = obj_link(op);
176         GC_words_allocd += lw;
177         FASTUNLOCK();
178         return((GC_PTR) op);
179    } else {
180        return(GENERAL_MALLOC((word)lb, PTRFREE));
181    }
182 }
183
184 /* Allocate lb bytes of composite (pointerful) data */
185 # ifdef __STDC__
186     GC_PTR GC_malloc(size_t lb)
187 # else
188     GC_PTR GC_malloc(lb)
189     size_t lb;
190 # endif
191 {
192 register ptr_t op;
193 register ptr_t *opp;
194 register word lw;
195 DCL_LOCK_STATE;
196
197     if( SMALL_OBJ(lb) ) {
198 #       ifdef MERGE_SIZES
199           lw = GC_size_map[lb];
200 #       else
201           lw = ALIGNED_WORDS(lb);
202 #       endif
203         opp = &(GC_objfreelist[lw]);
204         FASTLOCK();
205         if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
206             FASTUNLOCK();
207             return(GENERAL_MALLOC((word)lb, NORMAL));
208         }
209         /* See above comment on signals.        */
210         *opp = obj_link(op);
211         obj_link(op) = 0;
212         GC_words_allocd += lw;
213         FASTUNLOCK();
214         return((GC_PTR) op);
215    } else {
216        return(GENERAL_MALLOC((word)lb, NORMAL));
217    }
218 }
219
220 # ifdef REDIRECT_MALLOC
221 # ifdef __STDC__
222     GC_PTR malloc(size_t lb)
223 # else
224     GC_PTR malloc(lb)
225     size_t lb;
226 # endif
227   {
228     /* It might help to manually inline the GC_malloc call here.        */
229     /* But any decent compiler should reduce the extra procedure call   */
230     /* to at most a jump instruction in this case.                      */
231 #   if defined(I386) && defined(SOLARIS_THREADS)
232       /*
233        * Thread initialisation can call malloc before
234        * we're ready for it.
235        * It's not clear that this is enough to help matters.
236        * The thread implementation may well call malloc at other
237        * inopportune times.
238        */
239       if (!GC_is_initialized) return sbrk(lb);
240 #   endif /* I386 && SOLARIS_THREADS */
241     return(REDIRECT_MALLOC(lb));
242   }
243
244 # ifdef __STDC__
245     GC_PTR calloc(size_t n, size_t lb)
246 # else
247     GC_PTR calloc(n, lb)
248     size_t n, lb;
249 # endif
250   {
251     return(REDIRECT_MALLOC(n*lb));
252   }
253 # endif /* REDIRECT_MALLOC */
254
255 GC_PTR GC_generic_or_special_malloc(lb,knd)
256 word lb;
257 int knd;
258 {
259     switch(knd) {
260 #     ifdef STUBBORN_ALLOC
261         case STUBBORN:
262             return(GC_malloc_stubborn((size_t)lb));
263 #     endif
264         case PTRFREE:
265             return(GC_malloc_atomic((size_t)lb));
266         case NORMAL:
267             return(GC_malloc((size_t)lb));
268         case UNCOLLECTABLE:
269             return(GC_malloc_uncollectable((size_t)lb));
270 #       ifdef ATOMIC_UNCOLLECTABLE
271           case AUNCOLLECTABLE:
272             return(GC_malloc_atomic_uncollectable((size_t)lb));
273 #       endif /* ATOMIC_UNCOLLECTABLE */
274         default:
275             return(GC_generic_malloc(lb,knd));
276     }
277 }
278
279
280 /* Change the size of the block pointed to by p to contain at least   */
281 /* lb bytes.  The object may be (and quite likely will be) moved.     */
282 /* The kind (e.g. atomic) is the same as that of the old.             */
283 /* Shrinking of large blocks is not implemented well.                 */
284 # ifdef __STDC__
285     GC_PTR GC_realloc(GC_PTR p, size_t lb)
286 # else
287     GC_PTR GC_realloc(p,lb)
288     GC_PTR p;
289     size_t lb;
290 # endif
291 {
292 register struct hblk * h;
293 register hdr * hhdr;
294 register word sz;        /* Current size in bytes       */
295 register word orig_sz;   /* Original sz in bytes        */
296 int obj_kind;
297
298     if (p == 0) return(GC_malloc(lb));  /* Required by ANSI */
299     h = HBLKPTR(p);
300     hhdr = HDR(h);
301     sz = hhdr -> hb_sz;
302     obj_kind = hhdr -> hb_obj_kind;
303     sz = WORDS_TO_BYTES(sz);
304     orig_sz = sz;
305
306     if (sz > WORDS_TO_BYTES(MAXOBJSZ)) {
307         /* Round it up to the next whole heap block */
308           register word descr;
309           
310           sz = (sz+HDR_BYTES+HBLKSIZE-1)
311                 & (~HBLKMASK);
312           sz -= HDR_BYTES;
313           hhdr -> hb_sz = BYTES_TO_WORDS(sz);
314           descr = GC_obj_kinds[obj_kind].ok_descriptor;
315           if (GC_obj_kinds[obj_kind].ok_relocate_descr) descr += sz;
316           hhdr -> hb_descr = descr;
317           if (IS_UNCOLLECTABLE(obj_kind)) GC_non_gc_bytes += (sz - orig_sz);
318           /* Extra area is already cleared by allochblk. */
319     }
320     if (ADD_SLOP(lb) <= sz) {
321         if (lb >= (sz >> 1)) {
322 #           ifdef STUBBORN_ALLOC
323                 if (obj_kind == STUBBORN) GC_change_stubborn(p);
324 #           endif
325             if (orig_sz > lb) {
326               /* Clear unneeded part of object to avoid bogus pointer */
327               /* tracing.                                             */
328               /* Safe for stubborn objects.                           */
329                 BZERO(((ptr_t)p) + lb, orig_sz - lb);
330             }
331             return(p);
332         } else {
333             /* shrink */
334               GC_PTR result =
335                         GC_generic_or_special_malloc((word)lb, obj_kind);
336
337               if (result == 0) return(0);
338                   /* Could also return original object.  But this       */
339                   /* gives the client warning of imminent disaster.     */
340               BCOPY(p, result, lb);
341 #             ifndef IGNORE_FREE
342                 GC_free(p);
343 #             endif
344               return(result);
345         }
346     } else {
347         /* grow */
348           GC_PTR result =
349                 GC_generic_or_special_malloc((word)lb, obj_kind);
350
351           if (result == 0) return(0);
352           BCOPY(p, result, sz);
353 #         ifndef IGNORE_FREE
354             GC_free(p);
355 #         endif
356           return(result);
357     }
358 }
359
360 # ifdef REDIRECT_MALLOC
361 # ifdef __STDC__
362     GC_PTR realloc(GC_PTR p, size_t lb)
363 # else
364     GC_PTR realloc(p,lb)
365     GC_PTR p;
366     size_t lb;
367 # endif
368   {
369     return(GC_realloc(p, lb));
370   }
371 # endif /* REDIRECT_MALLOC */
372
373 /* Explicitly deallocate an object p.                           */
374 # ifdef __STDC__
375     void GC_free(GC_PTR p)
376 # else
377     void GC_free(p)
378     GC_PTR p;
379 # endif
380 {
381     register struct hblk *h;
382     register hdr *hhdr;
383     register signed_word sz;
384     register ptr_t * flh;
385     register int knd;
386     register struct obj_kind * ok;
387     DCL_LOCK_STATE;
388
389     if (p == 0) return;
390         /* Required by ANSI.  It's not my fault ...     */
391     h = HBLKPTR(p);
392     hhdr = HDR(h);
393 #   if defined(REDIRECT_MALLOC) && \
394         (defined(SOLARIS_THREADS) || defined(LINUX_THREADS))
395         /* We have to redirect malloc calls during initialization.      */
396         /* Don't try to deallocate that memory.                         */
397         if (0 == hhdr) return;
398 #   endif
399     knd = hhdr -> hb_obj_kind;
400     sz = hhdr -> hb_sz;
401     ok = &GC_obj_kinds[knd];
402     if (sz <= MAXOBJSZ) {
403 #       ifdef THREADS
404             DISABLE_SIGNALS();
405             LOCK();
406 #       endif
407         GC_mem_freed += sz;
408         /* A signal here can make GC_mem_freed and GC_non_gc_bytes      */
409         /* inconsistent.  We claim this is benign.                      */
410         if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
411                 /* Its unnecessary to clear the mark bit.  If the       */
412                 /* object is reallocated, it doesn't matter.  O.w. the  */
413                 /* collector will do it, since it's on a free list.     */
414         if (ok -> ok_init) {
415             BZERO((word *)p + 1, WORDS_TO_BYTES(sz-1));
416         }
417         flh = &(ok -> ok_freelist[sz]);
418         obj_link(p) = *flh;
419         *flh = (ptr_t)p;
420 #       ifdef THREADS
421             UNLOCK();
422             ENABLE_SIGNALS();
423 #       endif
424     } else {
425         DISABLE_SIGNALS();
426         LOCK();
427         GC_mem_freed += sz;
428         if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
429         GC_freehblk(h);
430         UNLOCK();
431         ENABLE_SIGNALS();
432     }
433 }
434
435 # ifdef REDIRECT_MALLOC
436 #   ifdef __STDC__
437       void free(GC_PTR p)
438 #   else
439       void free(p)
440       GC_PTR p;
441 #   endif
442   {
443 #   ifndef IGNORE_FREE
444       GC_free(p);
445 #   endif
446   }
447 # endif  /* REDIRECT_MALLOC */