2 * Copyright (c) 1996-1998 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.
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.
19 // This is sloppy about variable names used in header files.
20 // It also doesn't yet understand the new header file names or
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.
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.
31 // This uses template classes with static members, and hence does not work
32 // with g++ 2.7.2 and earlier.
34 // Unlike its predecessor, this one simply defines
36 // single_client_gc_alloc
38 // single_client_traceable_alloc
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.)
46 // This code assumes that the collector itself has been compiled with a
47 // compiler that defines __STDC__ .
55 # include <stack> // A more portable way to get stl_alloc.h .
57 # include <bits/stl_alloc.h>
58 # ifndef __STL_BEGIN_NAMESPACE
59 # define __STL_BEGIN_NAMESPACE namespace std {
60 # define __STL_END_NAMESPACE };
62 #ifndef __STL_USE_STD_ALLOCATORS
63 #define __STL_USE_STD_ALLOCATORS
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
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.
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;
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);
92 GC_API char * GC_CALL GC_generic_malloc_words_small(size_t word, int kind);
93 /* FIXME: Doesn't exist anymore. */
96 // Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
97 // AUNCOLLECTABLE in gc_priv.h.
99 enum { GC_PTRFREE = 0, GC_NORMAL = 1, GC_UNCOLLECTABLE = 2,
100 GC_AUNCOLLECTABLE = 3 };
102 enum { GC_max_fast_bytes = 255 };
104 enum { GC_bytes_per_word = sizeof(char *) };
106 enum { GC_byte_alignment = 8 };
108 enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
110 inline void * &GC_obj_link(void * p)
111 { return *reinterpret_cast<void **>(p); }
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)
117 return ((n + GC_byte_alignment)/GC_byte_alignment)*GC_word_alignment;
120 // The same but don't allow for extra byte.
121 inline size_t GC_round_up_uncollectable(size_t n)
123 return ((n + GC_byte_alignment - 1)/GC_byte_alignment)*GC_word_alignment;
127 class GC_aux_template {
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;
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;
138 // Similar counter for explicitly deallocated memory.
139 static size_t GC_bytes_recently_freed;
141 // Again for uncollectable memory.
142 static size_t GC_uncollectable_bytes_recently_freed;
144 static void * GC_out_of_line_malloc(size_t nwords, int kind);
148 size_t GC_aux_template<dummy>::GC_bytes_recently_allocd = 0;
151 size_t GC_aux_template<dummy>::GC_uncollectable_bytes_recently_allocd = 0;
154 size_t GC_aux_template<dummy>::GC_bytes_recently_freed = 0;
157 size_t GC_aux_template<dummy>::GC_uncollectable_bytes_recently_freed = 0;
160 void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
162 GC_bytes_recently_allocd += GC_uncollectable_bytes_recently_allocd;
164 GC_uncollectable_bytes_recently_allocd;
165 GC_uncollectable_bytes_recently_allocd = 0;
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;
171 GC_incr_bytes_allocd(GC_bytes_recently_allocd);
172 GC_bytes_recently_allocd = 0;
174 GC_incr_bytes_freed(GC_bytes_recently_freed);
175 GC_bytes_recently_freed = 0;
177 return GC_generic_malloc_words_small(nwords, kind);
180 typedef GC_aux_template<0> GC_aux;
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.
187 class single_client_gc_alloc_template {
189 static void * allocate(size_t n)
191 size_t nwords = GC_round_up(n);
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);
200 *flh = GC_obj_link(op);
201 GC_aux::GC_bytes_recently_allocd += nwords * GC_bytes_per_word;
204 static void * ptr_free_allocate(size_t n)
206 size_t nwords = GC_round_up(n);
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);
215 *flh = GC_obj_link(op);
216 GC_aux::GC_bytes_recently_allocd += nwords * GC_bytes_per_word;
219 static void deallocate(void *p, size_t n)
221 size_t nwords = GC_round_up(n);
224 if (n > GC_max_fast_bytes) {
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));
232 GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
235 static void ptr_free_deallocate(void *p, size_t n)
237 size_t nwords = GC_round_up(n);
240 if (n > GC_max_fast_bytes) {
243 flh = GC_aobjfreelist_ptr + nwords;
244 GC_obj_link(p) = *flh;
246 GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
251 typedef single_client_gc_alloc_template<0> single_client_gc_alloc;
253 // Once more, for uncollectable objects.
255 class single_client_traceable_alloc_template {
257 static void * allocate(size_t n)
259 size_t nwords = GC_round_up_uncollectable(n);
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);
268 *flh = GC_obj_link(op);
269 GC_aux::GC_uncollectable_bytes_recently_allocd +=
270 nwords * GC_bytes_per_word;
273 static void * ptr_free_allocate(size_t n)
275 size_t nwords = GC_round_up_uncollectable(n);
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);
284 *flh = GC_obj_link(op);
285 GC_aux::GC_uncollectable_bytes_recently_allocd +=
286 nwords * GC_bytes_per_word;
289 static void deallocate(void *p, size_t n)
291 size_t nwords = GC_round_up_uncollectable(n);
294 if (n > GC_max_fast_bytes) {
297 flh = GC_uobjfreelist_ptr + nwords;
298 GC_obj_link(p) = *flh;
300 GC_aux::GC_uncollectable_bytes_recently_freed +=
301 nwords * GC_bytes_per_word;
304 static void ptr_free_deallocate(void *p, size_t n)
306 size_t nwords = GC_round_up_uncollectable(n);
309 if (n > GC_max_fast_bytes) {
312 flh = GC_auobjfreelist_ptr + nwords;
313 GC_obj_link(p) = *flh;
315 GC_aux::GC_uncollectable_bytes_recently_freed +=
316 nwords * GC_bytes_per_word;
321 typedef single_client_traceable_alloc_template<0> single_client_traceable_alloc;
323 template < int dummy >
324 class gc_alloc_template {
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) { }
333 typedef gc_alloc_template < 0 > gc_alloc;
335 template < int dummy >
336 class traceable_alloc_template {
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); }
345 typedef traceable_alloc_template < 0 > traceable_alloc;
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++.
352 // GC_SPECIALIZE() is used internally.
353 #define GC_SPECIALIZE(T,alloc) \
354 class simple_alloc<T, alloc> { \
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)); } \
367 __STL_BEGIN_NAMESPACE
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)
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)
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)
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)
395 #ifdef __STL_USE_STD_ALLOCATORS
397 __STL_BEGIN_NAMESPACE
400 struct _Alloc_traits<_Tp, gc_alloc >
402 static const bool _S_instanceless = true;
403 typedef simple_alloc<_Tp, gc_alloc > _Alloc_type;
404 typedef __allocator<_Tp, gc_alloc > allocator_type;
407 inline bool operator==(const gc_alloc&,
413 inline bool operator!=(const gc_alloc&,
420 struct _Alloc_traits<_Tp, single_client_gc_alloc >
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;
427 inline bool operator==(const single_client_gc_alloc&,
428 const single_client_gc_alloc&)
433 inline bool operator!=(const single_client_gc_alloc&,
434 const single_client_gc_alloc&)
440 struct _Alloc_traits<_Tp, traceable_alloc >
442 static const bool _S_instanceless = true;
443 typedef simple_alloc<_Tp, traceable_alloc > _Alloc_type;
444 typedef __allocator<_Tp, traceable_alloc > allocator_type;
447 inline bool operator==(const traceable_alloc&,
448 const traceable_alloc&)
453 inline bool operator!=(const traceable_alloc&,
454 const traceable_alloc&)
460 struct _Alloc_traits<_Tp, single_client_traceable_alloc >
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;
467 inline bool operator==(const single_client_traceable_alloc&,
468 const single_client_traceable_alloc&)
473 inline bool operator!=(const single_client_traceable_alloc&,
474 const single_client_traceable_alloc&)
481 #endif /* __STL_USE_STD_ALLOCATORS */
483 #endif /* GC_ALLOC_H */