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.)
52 # include <stack> // A more portable way to get stl_alloc.h .
54 # include <bits/stl_alloc.h>
55 # ifndef __STL_BEGIN_NAMESPACE
56 # define __STL_BEGIN_NAMESPACE namespace std {
57 # define __STL_END_NAMESPACE };
59 #ifndef __STL_USE_STD_ALLOCATORS
60 #define __STL_USE_STD_ALLOCATORS
64 /* A hack to deal with gcc 3.1. If you are using gcc3.1 and later, */
65 /* you should probably really use gc_allocator.h instead. */
66 #if defined (__GNUC__) && \
67 (__GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ >= 1)))
68 # define simple_alloc __simple_alloc
76 // The following need to match collector data structures.
77 // We can't include gc_priv.h, since that pulls in way too much stuff.
78 // This should eventually be factored out into another include file.
81 GC_API
void ** const GC_objfreelist_ptr
;
82 GC_API
void ** const GC_aobjfreelist_ptr
;
83 GC_API
void ** const GC_uobjfreelist_ptr
;
84 GC_API
void ** const GC_auobjfreelist_ptr
;
86 GC_API
void GC_CALL
GC_incr_bytes_allocd(size_t bytes
);
87 GC_API
void GC_CALL
GC_incr_bytes_freed(size_t bytes
);
89 GC_API
char * GC_CALL
GC_generic_malloc_words_small(size_t word
, int kind
);
90 /* FIXME: Doesn't exist anymore. */
93 // Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
94 // AUNCOLLECTABLE in gc_priv.h.
96 enum { GC_PTRFREE
= 0, GC_NORMAL
= 1, GC_UNCOLLECTABLE
= 2,
97 GC_AUNCOLLECTABLE
= 3 };
99 enum { GC_max_fast_bytes
= 255 };
101 enum { GC_bytes_per_word
= sizeof(char *) };
103 enum { GC_byte_alignment
= 8 };
105 enum { GC_word_alignment
= GC_byte_alignment
/GC_bytes_per_word
};
107 inline void * &GC_obj_link(void * p
)
108 { return *reinterpret_cast<void **>(p
); }
110 // Compute a number of words >= n+1 bytes.
111 // The +1 allows for pointers one past the end.
112 inline size_t GC_round_up(size_t n
)
114 return ((n
+ GC_byte_alignment
)/GC_byte_alignment
)*GC_word_alignment
;
117 // The same but don't allow for extra byte.
118 inline size_t GC_round_up_uncollectable(size_t n
)
120 return ((n
+ GC_byte_alignment
- 1)/GC_byte_alignment
)*GC_word_alignment
;
124 class GC_aux_template
{
126 // File local count of allocated words. Occasionally this is
127 // added into the global count. A separate count is necessary since the
128 // real one must be updated with a procedure call.
129 static size_t GC_bytes_recently_allocd
;
131 // Same for uncollectable memory. Not yet reflected in either
132 // GC_bytes_recently_allocd or GC_non_gc_bytes.
133 static size_t GC_uncollectable_bytes_recently_allocd
;
135 // Similar counter for explicitly deallocated memory.
136 static size_t GC_bytes_recently_freed
;
138 // Again for uncollectable memory.
139 static size_t GC_uncollectable_bytes_recently_freed
;
141 static void * GC_out_of_line_malloc(size_t nwords
, int kind
);
145 size_t GC_aux_template
<dummy
>::GC_bytes_recently_allocd
= 0;
148 size_t GC_aux_template
<dummy
>::GC_uncollectable_bytes_recently_allocd
= 0;
151 size_t GC_aux_template
<dummy
>::GC_bytes_recently_freed
= 0;
154 size_t GC_aux_template
<dummy
>::GC_uncollectable_bytes_recently_freed
= 0;
157 void * GC_aux_template
<dummy
>::GC_out_of_line_malloc(size_t nwords
, int kind
)
159 GC_bytes_recently_allocd
+= GC_uncollectable_bytes_recently_allocd
;
161 GC_uncollectable_bytes_recently_allocd
;
162 GC_uncollectable_bytes_recently_allocd
= 0;
164 GC_bytes_recently_freed
+= GC_uncollectable_bytes_recently_freed
;
165 GC_non_gc_bytes
-= GC_uncollectable_bytes_recently_freed
;
166 GC_uncollectable_bytes_recently_freed
= 0;
168 GC_incr_bytes_allocd(GC_bytes_recently_allocd
);
169 GC_bytes_recently_allocd
= 0;
171 GC_incr_bytes_freed(GC_bytes_recently_freed
);
172 GC_bytes_recently_freed
= 0;
174 return GC_generic_malloc_words_small(nwords
, kind
);
177 typedef GC_aux_template
<0> GC_aux
;
179 // A fast, single-threaded, garbage-collected allocator
180 // We assume the first word will be immediately overwritten.
181 // In this version, deallocation is not a no-op, and explicit
182 // deallocation is likely to help performance.
184 class single_client_gc_alloc_template
{
186 static void * allocate(size_t n
)
188 size_t nwords
= GC_round_up(n
);
192 if (n
> GC_max_fast_bytes
) return GC_malloc(n
);
193 flh
= GC_objfreelist_ptr
+ nwords
;
194 if (0 == (op
= *flh
)) {
195 return GC_aux::GC_out_of_line_malloc(nwords
, GC_NORMAL
);
197 *flh
= GC_obj_link(op
);
198 GC_aux::GC_bytes_recently_allocd
+= nwords
* GC_bytes_per_word
;
201 static void * ptr_free_allocate(size_t n
)
203 size_t nwords
= GC_round_up(n
);
207 if (n
> GC_max_fast_bytes
) return GC_malloc_atomic(n
);
208 flh
= GC_aobjfreelist_ptr
+ nwords
;
209 if (0 == (op
= *flh
)) {
210 return GC_aux::GC_out_of_line_malloc(nwords
, GC_PTRFREE
);
212 *flh
= GC_obj_link(op
);
213 GC_aux::GC_bytes_recently_allocd
+= nwords
* GC_bytes_per_word
;
216 static void deallocate(void *p
, size_t n
)
218 size_t nwords
= GC_round_up(n
);
221 if (n
> GC_max_fast_bytes
) {
224 flh
= GC_objfreelist_ptr
+ nwords
;
225 GC_obj_link(p
) = *flh
;
226 memset(reinterpret_cast<char *>(p
) + GC_bytes_per_word
, 0,
227 GC_bytes_per_word
* (nwords
- 1));
229 GC_aux::GC_bytes_recently_freed
+= nwords
* GC_bytes_per_word
;
232 static void ptr_free_deallocate(void *p
, size_t n
)
234 size_t nwords
= GC_round_up(n
);
237 if (n
> GC_max_fast_bytes
) {
240 flh
= GC_aobjfreelist_ptr
+ nwords
;
241 GC_obj_link(p
) = *flh
;
243 GC_aux::GC_bytes_recently_freed
+= nwords
* GC_bytes_per_word
;
248 typedef single_client_gc_alloc_template
<0> single_client_gc_alloc
;
250 // Once more, for uncollectable objects.
252 class single_client_traceable_alloc_template
{
254 static void * allocate(size_t n
)
256 size_t nwords
= GC_round_up_uncollectable(n
);
260 if (n
> GC_max_fast_bytes
) return GC_malloc_uncollectable(n
);
261 flh
= GC_uobjfreelist_ptr
+ nwords
;
262 if (0 == (op
= *flh
)) {
263 return GC_aux::GC_out_of_line_malloc(nwords
, GC_UNCOLLECTABLE
);
265 *flh
= GC_obj_link(op
);
266 GC_aux::GC_uncollectable_bytes_recently_allocd
+=
267 nwords
* GC_bytes_per_word
;
270 static void * ptr_free_allocate(size_t n
)
272 size_t nwords
= GC_round_up_uncollectable(n
);
276 if (n
> GC_max_fast_bytes
) return GC_malloc_atomic_uncollectable(n
);
277 flh
= GC_auobjfreelist_ptr
+ nwords
;
278 if (0 == (op
= *flh
)) {
279 return GC_aux::GC_out_of_line_malloc(nwords
, GC_AUNCOLLECTABLE
);
281 *flh
= GC_obj_link(op
);
282 GC_aux::GC_uncollectable_bytes_recently_allocd
+=
283 nwords
* GC_bytes_per_word
;
286 static void deallocate(void *p
, size_t n
)
288 size_t nwords
= GC_round_up_uncollectable(n
);
291 if (n
> GC_max_fast_bytes
) {
294 flh
= GC_uobjfreelist_ptr
+ nwords
;
295 GC_obj_link(p
) = *flh
;
297 GC_aux::GC_uncollectable_bytes_recently_freed
+=
298 nwords
* GC_bytes_per_word
;
301 static void ptr_free_deallocate(void *p
, size_t n
)
303 size_t nwords
= GC_round_up_uncollectable(n
);
306 if (n
> GC_max_fast_bytes
) {
309 flh
= GC_auobjfreelist_ptr
+ nwords
;
310 GC_obj_link(p
) = *flh
;
312 GC_aux::GC_uncollectable_bytes_recently_freed
+=
313 nwords
* GC_bytes_per_word
;
318 typedef single_client_traceable_alloc_template
<0> single_client_traceable_alloc
;
320 template < int dummy
>
321 class gc_alloc_template
{
323 static void * allocate(size_t n
) { return GC_malloc(n
); }
324 static void * ptr_free_allocate(size_t n
)
325 { return GC_malloc_atomic(n
); }
326 static void deallocate(void *, size_t) { }
327 static void ptr_free_deallocate(void *, size_t) { }
330 typedef gc_alloc_template
< 0 > gc_alloc
;
332 template < int dummy
>
333 class traceable_alloc_template
{
335 static void * allocate(size_t n
) { return GC_malloc_uncollectable(n
); }
336 static void * ptr_free_allocate(size_t n
)
337 { return GC_malloc_atomic_uncollectable(n
); }
338 static void deallocate(void *p
, size_t) { GC_free(p
); }
339 static void ptr_free_deallocate(void *p
, size_t) { GC_free(p
); }
342 typedef traceable_alloc_template
< 0 > traceable_alloc
;
344 // We want to specialize simple_alloc so that it does the right thing
345 // for all pointer-free types. At the moment there is no portable way to
346 // even approximate that. The following approximation should work for
347 // SGI compilers, and recent versions of g++.
349 // GC_SPECIALIZE() is used internally.
350 #define GC_SPECIALIZE(T,alloc) \
351 class simple_alloc<T, alloc> { \
353 static T *allocate(size_t n) \
354 { return 0 == n? 0 : \
355 reinterpret_cast<T*>(alloc::ptr_free_allocate(n * sizeof(T))); } \
356 static T *allocate(void) \
357 { return reinterpret_cast<T*>(alloc::ptr_free_allocate(sizeof(T))); } \
358 static void deallocate(T *p, size_t n) \
359 { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof(T)); } \
360 static void deallocate(T *p) \
361 { alloc::ptr_free_deallocate(p, sizeof(T)); } \
364 __STL_BEGIN_NAMESPACE
366 GC_SPECIALIZE(char, gc_alloc
)
367 GC_SPECIALIZE(int, gc_alloc
)
368 GC_SPECIALIZE(unsigned, gc_alloc
)
369 GC_SPECIALIZE(float, gc_alloc
)
370 GC_SPECIALIZE(double, gc_alloc
)
372 GC_SPECIALIZE(char, traceable_alloc
)
373 GC_SPECIALIZE(int, traceable_alloc
)
374 GC_SPECIALIZE(unsigned, traceable_alloc
)
375 GC_SPECIALIZE(float, traceable_alloc
)
376 GC_SPECIALIZE(double, traceable_alloc
)
378 GC_SPECIALIZE(char, single_client_gc_alloc
)
379 GC_SPECIALIZE(int, single_client_gc_alloc
)
380 GC_SPECIALIZE(unsigned, single_client_gc_alloc
)
381 GC_SPECIALIZE(float, single_client_gc_alloc
)
382 GC_SPECIALIZE(double, single_client_gc_alloc
)
384 GC_SPECIALIZE(char, single_client_traceable_alloc
)
385 GC_SPECIALIZE(int, single_client_traceable_alloc
)
386 GC_SPECIALIZE(unsigned, single_client_traceable_alloc
)
387 GC_SPECIALIZE(float, single_client_traceable_alloc
)
388 GC_SPECIALIZE(double, single_client_traceable_alloc
)
392 #ifdef __STL_USE_STD_ALLOCATORS
394 __STL_BEGIN_NAMESPACE
397 struct _Alloc_traits
<_Tp
, gc_alloc
>
399 static const bool _S_instanceless
= true;
400 typedef simple_alloc
<_Tp
, gc_alloc
> _Alloc_type
;
401 typedef __allocator
<_Tp
, gc_alloc
> allocator_type
;
404 inline bool operator==(const gc_alloc
&,
410 inline bool operator!=(const gc_alloc
&,
417 struct _Alloc_traits
<_Tp
, single_client_gc_alloc
>
419 static const bool _S_instanceless
= true;
420 typedef simple_alloc
<_Tp
, single_client_gc_alloc
> _Alloc_type
;
421 typedef __allocator
<_Tp
, single_client_gc_alloc
> allocator_type
;
424 inline bool operator==(const single_client_gc_alloc
&,
425 const single_client_gc_alloc
&)
430 inline bool operator!=(const single_client_gc_alloc
&,
431 const single_client_gc_alloc
&)
437 struct _Alloc_traits
<_Tp
, traceable_alloc
>
439 static const bool _S_instanceless
= true;
440 typedef simple_alloc
<_Tp
, traceable_alloc
> _Alloc_type
;
441 typedef __allocator
<_Tp
, traceable_alloc
> allocator_type
;
444 inline bool operator==(const traceable_alloc
&,
445 const traceable_alloc
&)
450 inline bool operator!=(const traceable_alloc
&,
451 const traceable_alloc
&)
457 struct _Alloc_traits
<_Tp
, single_client_traceable_alloc
>
459 static const bool _S_instanceless
= true;
460 typedef simple_alloc
<_Tp
, single_client_traceable_alloc
> _Alloc_type
;
461 typedef __allocator
<_Tp
, single_client_traceable_alloc
> allocator_type
;
464 inline bool operator==(const single_client_traceable_alloc
&,
465 const single_client_traceable_alloc
&)
470 inline bool operator!=(const single_client_traceable_alloc
&,
471 const single_client_traceable_alloc
&)
478 #endif /* __STL_USE_STD_ALLOCATORS */
480 #endif /* GC_ALLOC_H */