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
73 // The following need to match collector data structures.
74 // We can't include gc_priv.h, since that pulls in way too much stuff.
75 // This should eventually be factored out into another include file.
78 extern void ** const GC_objfreelist_ptr
;
79 extern void ** const GC_aobjfreelist_ptr
;
80 extern void ** const GC_uobjfreelist_ptr
;
81 extern void ** const GC_auobjfreelist_ptr
;
83 extern void GC_incr_words_allocd(size_t words
);
84 extern void GC_incr_mem_freed(size_t words
);
86 extern char * GC_generic_malloc_words_small(size_t word
, int kind
);
89 // Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
90 // AUNCOLLECTABLE in gc_priv.h.
92 enum { GC_PTRFREE
= 0, GC_NORMAL
= 1, GC_UNCOLLECTABLE
= 2,
93 GC_AUNCOLLECTABLE
= 3 };
95 enum { GC_max_fast_bytes
= 255 };
97 enum { GC_bytes_per_word
= sizeof(char *) };
99 enum { GC_byte_alignment
= 8 };
101 enum { GC_word_alignment
= GC_byte_alignment
/GC_bytes_per_word
};
103 inline void * &GC_obj_link(void * p
)
104 { return *(void **)p
; }
106 // Compute a number of words >= n+1 bytes.
107 // The +1 allows for pointers one past the end.
108 inline size_t GC_round_up(size_t n
)
110 return ((n
+ GC_byte_alignment
)/GC_byte_alignment
)*GC_word_alignment
;
113 // The same but don't allow for extra byte.
114 inline size_t GC_round_up_uncollectable(size_t n
)
116 return ((n
+ GC_byte_alignment
- 1)/GC_byte_alignment
)*GC_word_alignment
;
120 class GC_aux_template
{
122 // File local count of allocated words. Occasionally this is
123 // added into the global count. A separate count is necessary since the
124 // real one must be updated with a procedure call.
125 static size_t GC_words_recently_allocd
;
127 // Same for uncollectable mmory. Not yet reflected in either
128 // GC_words_recently_allocd or GC_non_gc_bytes.
129 static size_t GC_uncollectable_words_recently_allocd
;
131 // Similar counter for explicitly deallocated memory.
132 static size_t GC_mem_recently_freed
;
134 // Again for uncollectable memory.
135 static size_t GC_uncollectable_mem_recently_freed
;
137 static void * GC_out_of_line_malloc(size_t nwords
, int kind
);
141 size_t GC_aux_template
<dummy
>::GC_words_recently_allocd
= 0;
144 size_t GC_aux_template
<dummy
>::GC_uncollectable_words_recently_allocd
= 0;
147 size_t GC_aux_template
<dummy
>::GC_mem_recently_freed
= 0;
150 size_t GC_aux_template
<dummy
>::GC_uncollectable_mem_recently_freed
= 0;
153 void * GC_aux_template
<dummy
>::GC_out_of_line_malloc(size_t nwords
, int kind
)
155 GC_words_recently_allocd
+= GC_uncollectable_words_recently_allocd
;
157 GC_bytes_per_word
* GC_uncollectable_words_recently_allocd
;
158 GC_uncollectable_words_recently_allocd
= 0;
160 GC_mem_recently_freed
+= GC_uncollectable_mem_recently_freed
;
162 GC_bytes_per_word
* GC_uncollectable_mem_recently_freed
;
163 GC_uncollectable_mem_recently_freed
= 0;
165 GC_incr_words_allocd(GC_words_recently_allocd
);
166 GC_words_recently_allocd
= 0;
168 GC_incr_mem_freed(GC_mem_recently_freed
);
169 GC_mem_recently_freed
= 0;
171 return GC_generic_malloc_words_small(nwords
, kind
);
174 typedef GC_aux_template
<0> GC_aux
;
176 // A fast, single-threaded, garbage-collected allocator
177 // We assume the first word will be immediately overwritten.
178 // In this version, deallocation is not a noop, and explicit
179 // deallocation is likely to help performance.
181 class single_client_gc_alloc_template
{
183 static void * allocate(size_t n
)
185 size_t nwords
= GC_round_up(n
);
189 if (n
> GC_max_fast_bytes
) return GC_malloc(n
);
190 flh
= GC_objfreelist_ptr
+ nwords
;
191 if (0 == (op
= *flh
)) {
192 return GC_aux::GC_out_of_line_malloc(nwords
, GC_NORMAL
);
194 *flh
= GC_obj_link(op
);
195 GC_aux::GC_words_recently_allocd
+= nwords
;
198 static void * ptr_free_allocate(size_t n
)
200 size_t nwords
= GC_round_up(n
);
204 if (n
> GC_max_fast_bytes
) return GC_malloc_atomic(n
);
205 flh
= GC_aobjfreelist_ptr
+ nwords
;
206 if (0 == (op
= *flh
)) {
207 return GC_aux::GC_out_of_line_malloc(nwords
, GC_PTRFREE
);
209 *flh
= GC_obj_link(op
);
210 GC_aux::GC_words_recently_allocd
+= nwords
;
213 static void deallocate(void *p
, size_t n
)
215 size_t nwords
= GC_round_up(n
);
218 if (n
> GC_max_fast_bytes
) {
221 flh
= GC_objfreelist_ptr
+ nwords
;
222 GC_obj_link(p
) = *flh
;
223 memset((char *)p
+ GC_bytes_per_word
, 0,
224 GC_bytes_per_word
* (nwords
- 1));
226 GC_aux::GC_mem_recently_freed
+= nwords
;
229 static void ptr_free_deallocate(void *p
, size_t n
)
231 size_t nwords
= GC_round_up(n
);
234 if (n
> GC_max_fast_bytes
) {
237 flh
= GC_aobjfreelist_ptr
+ nwords
;
238 GC_obj_link(p
) = *flh
;
240 GC_aux::GC_mem_recently_freed
+= nwords
;
245 typedef single_client_gc_alloc_template
<0> single_client_gc_alloc
;
247 // Once more, for uncollectable objects.
249 class single_client_traceable_alloc_template
{
251 static void * allocate(size_t n
)
253 size_t nwords
= GC_round_up_uncollectable(n
);
257 if (n
> GC_max_fast_bytes
) return GC_malloc_uncollectable(n
);
258 flh
= GC_uobjfreelist_ptr
+ nwords
;
259 if (0 == (op
= *flh
)) {
260 return GC_aux::GC_out_of_line_malloc(nwords
, GC_UNCOLLECTABLE
);
262 *flh
= GC_obj_link(op
);
263 GC_aux::GC_uncollectable_words_recently_allocd
+= nwords
;
266 static void * ptr_free_allocate(size_t n
)
268 size_t nwords
= GC_round_up_uncollectable(n
);
272 if (n
> GC_max_fast_bytes
) return GC_malloc_atomic_uncollectable(n
);
273 flh
= GC_auobjfreelist_ptr
+ nwords
;
274 if (0 == (op
= *flh
)) {
275 return GC_aux::GC_out_of_line_malloc(nwords
, GC_AUNCOLLECTABLE
);
277 *flh
= GC_obj_link(op
);
278 GC_aux::GC_uncollectable_words_recently_allocd
+= nwords
;
281 static void deallocate(void *p
, size_t n
)
283 size_t nwords
= GC_round_up_uncollectable(n
);
286 if (n
> GC_max_fast_bytes
) {
289 flh
= GC_uobjfreelist_ptr
+ nwords
;
290 GC_obj_link(p
) = *flh
;
292 GC_aux::GC_uncollectable_mem_recently_freed
+= nwords
;
295 static void ptr_free_deallocate(void *p
, size_t n
)
297 size_t nwords
= GC_round_up_uncollectable(n
);
300 if (n
> GC_max_fast_bytes
) {
303 flh
= GC_auobjfreelist_ptr
+ nwords
;
304 GC_obj_link(p
) = *flh
;
306 GC_aux::GC_uncollectable_mem_recently_freed
+= nwords
;
311 typedef single_client_traceable_alloc_template
<0> single_client_traceable_alloc
;
313 template < int dummy
>
314 class gc_alloc_template
{
316 static void * allocate(size_t n
) { return GC_malloc(n
); }
317 static void * ptr_free_allocate(size_t n
)
318 { return GC_malloc_atomic(n
); }
319 static void deallocate(void *, size_t) { }
320 static void ptr_free_deallocate(void *, size_t) { }
323 typedef gc_alloc_template
< 0 > gc_alloc
;
325 template < int dummy
>
326 class traceable_alloc_template
{
328 static void * allocate(size_t n
) { return GC_malloc_uncollectable(n
); }
329 static void * ptr_free_allocate(size_t n
)
330 { return GC_malloc_atomic_uncollectable(n
); }
331 static void deallocate(void *p
, size_t) { GC_free(p
); }
332 static void ptr_free_deallocate(void *p
, size_t) { GC_free(p
); }
335 typedef traceable_alloc_template
< 0 > traceable_alloc
;
337 // We want to specialize simple_alloc so that it does the right thing
338 // for all pointerfree types. At the moment there is no portable way to
339 // even approximate that. The following approximation should work for
340 // SGI compilers, and recent versions of g++.
342 # define __GC_SPECIALIZE(T,alloc) \
343 class simple_alloc<T, alloc> { \
345 static T *allocate(size_t n) \
346 { return 0 == n? 0 : \
347 (T*) alloc::ptr_free_allocate(n * sizeof (T)); } \
348 static T *allocate(void) \
349 { return (T*) alloc::ptr_free_allocate(sizeof (T)); } \
350 static void deallocate(T *p, size_t n) \
351 { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
352 static void deallocate(T *p) \
353 { alloc::ptr_free_deallocate(p, sizeof (T)); } \
356 __STL_BEGIN_NAMESPACE
358 __GC_SPECIALIZE(char, gc_alloc
)
359 __GC_SPECIALIZE(int, gc_alloc
)
360 __GC_SPECIALIZE(unsigned, gc_alloc
)
361 __GC_SPECIALIZE(float, gc_alloc
)
362 __GC_SPECIALIZE(double, gc_alloc
)
364 __GC_SPECIALIZE(char, traceable_alloc
)
365 __GC_SPECIALIZE(int, traceable_alloc
)
366 __GC_SPECIALIZE(unsigned, traceable_alloc
)
367 __GC_SPECIALIZE(float, traceable_alloc
)
368 __GC_SPECIALIZE(double, traceable_alloc
)
370 __GC_SPECIALIZE(char, single_client_gc_alloc
)
371 __GC_SPECIALIZE(int, single_client_gc_alloc
)
372 __GC_SPECIALIZE(unsigned, single_client_gc_alloc
)
373 __GC_SPECIALIZE(float, single_client_gc_alloc
)
374 __GC_SPECIALIZE(double, single_client_gc_alloc
)
376 __GC_SPECIALIZE(char, single_client_traceable_alloc
)
377 __GC_SPECIALIZE(int, single_client_traceable_alloc
)
378 __GC_SPECIALIZE(unsigned, single_client_traceable_alloc
)
379 __GC_SPECIALIZE(float, single_client_traceable_alloc
)
380 __GC_SPECIALIZE(double, single_client_traceable_alloc
)
384 #ifdef __STL_USE_STD_ALLOCATORS
386 __STL_BEGIN_NAMESPACE
389 struct _Alloc_traits
<_T
, gc_alloc
>
391 static const bool _S_instanceless
= true;
392 typedef simple_alloc
<_T
, gc_alloc
> _Alloc_type
;
393 typedef __allocator
<_T
, gc_alloc
> allocator_type
;
396 inline bool operator==(const gc_alloc
&,
402 inline bool operator!=(const gc_alloc
&,
409 struct _Alloc_traits
<_T
, single_client_gc_alloc
>
411 static const bool _S_instanceless
= true;
412 typedef simple_alloc
<_T
, single_client_gc_alloc
> _Alloc_type
;
413 typedef __allocator
<_T
, single_client_gc_alloc
> allocator_type
;
416 inline bool operator==(const single_client_gc_alloc
&,
417 const single_client_gc_alloc
&)
422 inline bool operator!=(const single_client_gc_alloc
&,
423 const single_client_gc_alloc
&)
429 struct _Alloc_traits
<_T
, traceable_alloc
>
431 static const bool _S_instanceless
= true;
432 typedef simple_alloc
<_T
, traceable_alloc
> _Alloc_type
;
433 typedef __allocator
<_T
, traceable_alloc
> allocator_type
;
436 inline bool operator==(const traceable_alloc
&,
437 const traceable_alloc
&)
442 inline bool operator!=(const traceable_alloc
&,
443 const traceable_alloc
&)
449 struct _Alloc_traits
<_T
, single_client_traceable_alloc
>
451 static const bool _S_instanceless
= true;
452 typedef simple_alloc
<_T
, single_client_traceable_alloc
> _Alloc_type
;
453 typedef __allocator
<_T
, single_client_traceable_alloc
> allocator_type
;
456 inline bool operator==(const single_client_traceable_alloc
&,
457 const single_client_traceable_alloc
&)
462 inline bool operator!=(const single_client_traceable_alloc
&,
463 const single_client_traceable_alloc
&)
470 #endif /* __STL_USE_STD_ALLOCATORS */
472 #endif /* GC_ALLOC_H */