implemented Setup.hs to build boehm cpp libs and install them;
[hs-boehmgc.git] / gc-7.2 / include / new_gc_alloc.h
1 /*
2  * Copyright (c) 1996-1998 by Silicon Graphics.  All rights reserved.
3  *
4  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
6  *
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.
12  */
13
14 //
15 // This is a revision of gc_alloc.h for SGI STL versions > 3.0
16 // Unlike earlier versions, it supplements the standard "alloc.h"
17 // instead of replacing it.
18 //
19 // This is sloppy about variable names used in header files.
20 // It also doesn't yet understand the new header file names or
21 // namespaces.
22 //
23 // This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE.
24 // The user should also consider -DREDIRECT_MALLOC=GC_uncollectable_malloc,
25 // to ensure that object allocated through malloc are traced.
26 //
27 // Some of this could be faster in the explicit deallocation case.
28 // In particular, we spend too much time clearing objects on the
29 // free lists.  That could be avoided.
30 //
31 // This uses template classes with static members, and hence does not work
32 // with g++ 2.7.2 and earlier.
33 //
34 // Unlike its predecessor, this one simply defines
35 //      gc_alloc
36 //      single_client_gc_alloc
37 //      traceable_alloc
38 //      single_client_traceable_alloc
39 //
40 // It does not redefine alloc.  Nor does it change the default allocator,
41 // though the user may wish to do so.  (The argument against changing
42 // the default allocator is that it may introduce subtle link compatibility
43 // problems.  The argument for changing it is that the usual default
44 // allocator is usually a very bad choice for a garbage collected environment.)
45 //
46 // This code assumes that the collector itself has been compiled with a
47 // compiler that defines __STDC__ .
48 //
49
50 #ifndef GC_ALLOC_H
51
52 #include "gc.h"
53
54 #if (__GNUC__ < 3)
55 # include <stack>  // A more portable way to get stl_alloc.h .
56 #else
57 # include <bits/stl_alloc.h>
58 # ifndef __STL_BEGIN_NAMESPACE
59 # define __STL_BEGIN_NAMESPACE namespace std {
60 # define __STL_END_NAMESPACE };
61 # endif
62 #ifndef __STL_USE_STD_ALLOCATORS
63 #define __STL_USE_STD_ALLOCATORS
64 #endif
65 #endif
66
67 /* A hack to deal with gcc 3.1.  If you are using gcc3.1 and later,     */
68 /* you should probably really use gc_allocator.h instead.               */
69 #if defined (__GNUC__) && \
70     (__GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ >= 1)))
71 # define simple_alloc __simple_alloc
72 #endif
73
74 #define GC_ALLOC_H
75
76 #include <stddef.h>
77 #include <string.h>
78
79 // The following need to match collector data structures.
80 // We can't include gc_priv.h, since that pulls in way too much stuff.
81 // This should eventually be factored out into another include file.
82
83 extern "C" {
84     GC_API void ** const GC_objfreelist_ptr;
85     GC_API void ** const GC_aobjfreelist_ptr;
86     GC_API void ** const GC_uobjfreelist_ptr;
87     GC_API void ** const GC_auobjfreelist_ptr;
88
89     GC_API void GC_CALL GC_incr_bytes_allocd(size_t bytes);
90     GC_API void GC_CALL GC_incr_bytes_freed(size_t bytes);
91
92     GC_API char * GC_CALL GC_generic_malloc_words_small(size_t word, int kind);
93                 /* FIXME: Doesn't exist anymore.        */
94 }
95
96 // Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
97 // AUNCOLLECTABLE in gc_priv.h.
98
99 enum { GC_PTRFREE = 0, GC_NORMAL = 1, GC_UNCOLLECTABLE = 2,
100        GC_AUNCOLLECTABLE = 3 };
101
102 enum { GC_max_fast_bytes = 255 };
103
104 enum { GC_bytes_per_word = sizeof(char *) };
105
106 enum { GC_byte_alignment = 8 };
107
108 enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
109
110 inline void * &GC_obj_link(void * p)
111 {   return *reinterpret_cast<void **>(p);  }
112
113 // Compute a number of words >= n+1 bytes.
114 // The +1 allows for pointers one past the end.
115 inline size_t GC_round_up(size_t n)
116 {
117     return ((n + GC_byte_alignment)/GC_byte_alignment)*GC_word_alignment;
118 }
119
120 // The same but don't allow for extra byte.
121 inline size_t GC_round_up_uncollectable(size_t n)
122 {
123     return ((n + GC_byte_alignment - 1)/GC_byte_alignment)*GC_word_alignment;
124 }
125
126 template <int dummy>
127 class GC_aux_template {
128 public:
129   // File local count of allocated words.  Occasionally this is
130   // added into the global count.  A separate count is necessary since the
131   // real one must be updated with a procedure call.
132   static size_t GC_bytes_recently_allocd;
133
134   // Same for uncollectable memory.  Not yet reflected in either
135   // GC_bytes_recently_allocd or GC_non_gc_bytes.
136   static size_t GC_uncollectable_bytes_recently_allocd;
137
138   // Similar counter for explicitly deallocated memory.
139   static size_t GC_bytes_recently_freed;
140
141   // Again for uncollectable memory.
142   static size_t GC_uncollectable_bytes_recently_freed;
143
144   static void * GC_out_of_line_malloc(size_t nwords, int kind);
145 };
146
147 template <int dummy>
148 size_t GC_aux_template<dummy>::GC_bytes_recently_allocd = 0;
149
150 template <int dummy>
151 size_t GC_aux_template<dummy>::GC_uncollectable_bytes_recently_allocd = 0;
152
153 template <int dummy>
154 size_t GC_aux_template<dummy>::GC_bytes_recently_freed = 0;
155
156 template <int dummy>
157 size_t GC_aux_template<dummy>::GC_uncollectable_bytes_recently_freed = 0;
158
159 template <int dummy>
160 void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
161 {
162     GC_bytes_recently_allocd += GC_uncollectable_bytes_recently_allocd;
163     GC_non_gc_bytes +=
164                 GC_uncollectable_bytes_recently_allocd;
165     GC_uncollectable_bytes_recently_allocd = 0;
166
167     GC_bytes_recently_freed += GC_uncollectable_bytes_recently_freed;
168     GC_non_gc_bytes -= GC_uncollectable_bytes_recently_freed;
169     GC_uncollectable_bytes_recently_freed = 0;
170
171     GC_incr_bytes_allocd(GC_bytes_recently_allocd);
172     GC_bytes_recently_allocd = 0;
173
174     GC_incr_bytes_freed(GC_bytes_recently_freed);
175     GC_bytes_recently_freed = 0;
176
177     return GC_generic_malloc_words_small(nwords, kind);
178 }
179
180 typedef GC_aux_template<0> GC_aux;
181
182 // A fast, single-threaded, garbage-collected allocator
183 // We assume the first word will be immediately overwritten.
184 // In this version, deallocation is not a no-op, and explicit
185 // deallocation is likely to help performance.
186 template <int dummy>
187 class single_client_gc_alloc_template {
188     public:
189         static void * allocate(size_t n)
190         {
191             size_t nwords = GC_round_up(n);
192             void ** flh;
193             void * op;
194
195             if (n > GC_max_fast_bytes) return GC_malloc(n);
196             flh = GC_objfreelist_ptr + nwords;
197             if (0 == (op = *flh)) {
198                 return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
199             }
200             *flh = GC_obj_link(op);
201             GC_aux::GC_bytes_recently_allocd += nwords * GC_bytes_per_word;
202             return op;
203         }
204         static void * ptr_free_allocate(size_t n)
205         {
206             size_t nwords = GC_round_up(n);
207             void ** flh;
208             void * op;
209
210             if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
211             flh = GC_aobjfreelist_ptr + nwords;
212             if (0 == (op = *flh)) {
213                 return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
214             }
215             *flh = GC_obj_link(op);
216             GC_aux::GC_bytes_recently_allocd += nwords * GC_bytes_per_word;
217             return op;
218         }
219         static void deallocate(void *p, size_t n)
220         {
221             size_t nwords = GC_round_up(n);
222             void ** flh;
223
224             if (n > GC_max_fast_bytes)  {
225                 GC_free(p);
226             } else {
227                 flh = GC_objfreelist_ptr + nwords;
228                 GC_obj_link(p) = *flh;
229                 memset(reinterpret_cast<char *>(p) + GC_bytes_per_word, 0,
230                        GC_bytes_per_word * (nwords - 1));
231                 *flh = p;
232                 GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
233             }
234         }
235         static void ptr_free_deallocate(void *p, size_t n)
236         {
237             size_t nwords = GC_round_up(n);
238             void ** flh;
239
240             if (n > GC_max_fast_bytes) {
241                 GC_free(p);
242             } else {
243                 flh = GC_aobjfreelist_ptr + nwords;
244                 GC_obj_link(p) = *flh;
245                 *flh = p;
246                 GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
247             }
248         }
249 };
250
251 typedef single_client_gc_alloc_template<0> single_client_gc_alloc;
252
253 // Once more, for uncollectable objects.
254 template <int dummy>
255 class single_client_traceable_alloc_template {
256     public:
257         static void * allocate(size_t n)
258         {
259             size_t nwords = GC_round_up_uncollectable(n);
260             void ** flh;
261             void * op;
262
263             if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
264             flh = GC_uobjfreelist_ptr + nwords;
265             if (0 == (op = *flh)) {
266                 return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
267             }
268             *flh = GC_obj_link(op);
269             GC_aux::GC_uncollectable_bytes_recently_allocd +=
270                                         nwords * GC_bytes_per_word;
271             return op;
272         }
273         static void * ptr_free_allocate(size_t n)
274         {
275             size_t nwords = GC_round_up_uncollectable(n);
276             void ** flh;
277             void * op;
278
279             if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
280             flh = GC_auobjfreelist_ptr + nwords;
281             if (0 == (op = *flh)) {
282                 return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
283             }
284             *flh = GC_obj_link(op);
285             GC_aux::GC_uncollectable_bytes_recently_allocd +=
286                                         nwords * GC_bytes_per_word;
287             return op;
288         }
289         static void deallocate(void *p, size_t n)
290         {
291             size_t nwords = GC_round_up_uncollectable(n);
292             void ** flh;
293
294             if (n > GC_max_fast_bytes)  {
295                 GC_free(p);
296             } else {
297                 flh = GC_uobjfreelist_ptr + nwords;
298                 GC_obj_link(p) = *flh;
299                 *flh = p;
300                 GC_aux::GC_uncollectable_bytes_recently_freed +=
301                                 nwords * GC_bytes_per_word;
302             }
303         }
304         static void ptr_free_deallocate(void *p, size_t n)
305         {
306             size_t nwords = GC_round_up_uncollectable(n);
307             void ** flh;
308
309             if (n > GC_max_fast_bytes) {
310                 GC_free(p);
311             } else {
312                 flh = GC_auobjfreelist_ptr + nwords;
313                 GC_obj_link(p) = *flh;
314                 *flh = p;
315                 GC_aux::GC_uncollectable_bytes_recently_freed +=
316                                 nwords * GC_bytes_per_word;
317             }
318         }
319 };
320
321 typedef single_client_traceable_alloc_template<0> single_client_traceable_alloc;
322
323 template < int dummy >
324 class gc_alloc_template {
325     public:
326         static void * allocate(size_t n) { return GC_malloc(n); }
327         static void * ptr_free_allocate(size_t n)
328                 { return GC_malloc_atomic(n); }
329         static void deallocate(void *, size_t) { }
330         static void ptr_free_deallocate(void *, size_t) { }
331 };
332
333 typedef gc_alloc_template < 0 > gc_alloc;
334
335 template < int dummy >
336 class traceable_alloc_template {
337     public:
338         static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
339         static void * ptr_free_allocate(size_t n)
340                 { return GC_malloc_atomic_uncollectable(n); }
341         static void deallocate(void *p, size_t) { GC_free(p); }
342         static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
343 };
344
345 typedef traceable_alloc_template < 0 > traceable_alloc;
346
347 // We want to specialize simple_alloc so that it does the right thing
348 // for all pointer-free types.  At the moment there is no portable way to
349 // even approximate that.  The following approximation should work for
350 // SGI compilers, and recent versions of g++.
351
352 // GC_SPECIALIZE() is used internally.
353 #define GC_SPECIALIZE(T,alloc) \
354   class simple_alloc<T, alloc> { \
355   public: \
356     static T *allocate(size_t n) \
357         { return 0 == n? 0 : \
358             reinterpret_cast<T*>(alloc::ptr_free_allocate(n * sizeof(T))); } \
359     static T *allocate(void) \
360         { return reinterpret_cast<T*>(alloc::ptr_free_allocate(sizeof(T))); } \
361     static void deallocate(T *p, size_t n) \
362         { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof(T)); } \
363     static void deallocate(T *p) \
364         { alloc::ptr_free_deallocate(p, sizeof(T)); } \
365   };
366
367 __STL_BEGIN_NAMESPACE
368
369 GC_SPECIALIZE(char, gc_alloc)
370 GC_SPECIALIZE(int, gc_alloc)
371 GC_SPECIALIZE(unsigned, gc_alloc)
372 GC_SPECIALIZE(float, gc_alloc)
373 GC_SPECIALIZE(double, gc_alloc)
374
375 GC_SPECIALIZE(char, traceable_alloc)
376 GC_SPECIALIZE(int, traceable_alloc)
377 GC_SPECIALIZE(unsigned, traceable_alloc)
378 GC_SPECIALIZE(float, traceable_alloc)
379 GC_SPECIALIZE(double, traceable_alloc)
380
381 GC_SPECIALIZE(char, single_client_gc_alloc)
382 GC_SPECIALIZE(int, single_client_gc_alloc)
383 GC_SPECIALIZE(unsigned, single_client_gc_alloc)
384 GC_SPECIALIZE(float, single_client_gc_alloc)
385 GC_SPECIALIZE(double, single_client_gc_alloc)
386
387 GC_SPECIALIZE(char, single_client_traceable_alloc)
388 GC_SPECIALIZE(int, single_client_traceable_alloc)
389 GC_SPECIALIZE(unsigned, single_client_traceable_alloc)
390 GC_SPECIALIZE(float, single_client_traceable_alloc)
391 GC_SPECIALIZE(double, single_client_traceable_alloc)
392
393 __STL_END_NAMESPACE
394
395 #ifdef __STL_USE_STD_ALLOCATORS
396
397 __STL_BEGIN_NAMESPACE
398
399 template <class _Tp>
400 struct _Alloc_traits<_Tp, gc_alloc >
401 {
402   static const bool _S_instanceless = true;
403   typedef simple_alloc<_Tp, gc_alloc > _Alloc_type;
404   typedef __allocator<_Tp, gc_alloc > allocator_type;
405 };
406
407 inline bool operator==(const gc_alloc&,
408                        const gc_alloc&)
409 {
410   return true;
411 }
412
413 inline bool operator!=(const gc_alloc&,
414                        const gc_alloc&)
415 {
416   return false;
417 }
418
419 template <class _Tp>
420 struct _Alloc_traits<_Tp, single_client_gc_alloc >
421 {
422   static const bool _S_instanceless = true;
423   typedef simple_alloc<_Tp, single_client_gc_alloc > _Alloc_type;
424   typedef __allocator<_Tp, single_client_gc_alloc > allocator_type;
425 };
426
427 inline bool operator==(const single_client_gc_alloc&,
428                        const single_client_gc_alloc&)
429 {
430   return true;
431 }
432
433 inline bool operator!=(const single_client_gc_alloc&,
434                        const single_client_gc_alloc&)
435 {
436   return false;
437 }
438
439 template <class _Tp>
440 struct _Alloc_traits<_Tp, traceable_alloc >
441 {
442   static const bool _S_instanceless = true;
443   typedef simple_alloc<_Tp, traceable_alloc > _Alloc_type;
444   typedef __allocator<_Tp, traceable_alloc > allocator_type;
445 };
446
447 inline bool operator==(const traceable_alloc&,
448                        const traceable_alloc&)
449 {
450   return true;
451 }
452
453 inline bool operator!=(const traceable_alloc&,
454                        const traceable_alloc&)
455 {
456   return false;
457 }
458
459 template <class _Tp>
460 struct _Alloc_traits<_Tp, single_client_traceable_alloc >
461 {
462   static const bool _S_instanceless = true;
463   typedef simple_alloc<_Tp, single_client_traceable_alloc > _Alloc_type;
464   typedef __allocator<_Tp, single_client_traceable_alloc > allocator_type;
465 };
466
467 inline bool operator==(const single_client_traceable_alloc&,
468                        const single_client_traceable_alloc&)
469 {
470   return true;
471 }
472
473 inline bool operator!=(const single_client_traceable_alloc&,
474                        const single_client_traceable_alloc&)
475 {
476   return false;
477 }
478
479 __STL_END_NAMESPACE
480
481 #endif /* __STL_USE_STD_ALLOCATORS */
482
483 #endif /* GC_ALLOC_H */