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 C++ header file that is intended to replace the SGI STL
|
---|
16 | // alloc.h. This assumes SGI STL version < 3.0.
|
---|
17 | //
|
---|
18 | // This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE
|
---|
19 | // and -DALL_INTERIOR_POINTERS. We also recommend
|
---|
20 | // -DREDIRECT_MALLOC=GC_uncollectable_malloc.
|
---|
21 | //
|
---|
22 | // Some of this could be faster in the explicit deallocation case. In particular,
|
---|
23 | // we spend too much time clearing objects on the free lists. That could be avoided.
|
---|
24 | //
|
---|
25 | // This uses template classes with static members, and hence does not work
|
---|
26 | // with g++ 2.7.2 and earlier.
|
---|
27 | //
|
---|
28 | // This code assumes that the collector itself has been compiled with a
|
---|
29 | // compiler that defines __STDC__ .
|
---|
30 | //
|
---|
31 |
|
---|
32 | #include "gc.h"
|
---|
33 |
|
---|
34 | #ifndef GC_ALLOC_H
|
---|
35 |
|
---|
36 | #define GC_ALLOC_H
|
---|
37 | #define __ALLOC_H // Prevent inclusion of the default version. Ugly.
|
---|
38 | #define __SGI_STL_ALLOC_H
|
---|
39 | #define __SGI_STL_INTERNAL_ALLOC_H
|
---|
40 |
|
---|
41 | #ifndef __ALLOC
|
---|
42 | # define __ALLOC alloc
|
---|
43 | #endif
|
---|
44 |
|
---|
45 | #include <stddef.h>
|
---|
46 | #include <string.h>
|
---|
47 |
|
---|
48 | // The following is just replicated from the conventional SGI alloc.h:
|
---|
49 |
|
---|
50 | template<class T, class alloc>
|
---|
51 | class simple_alloc {
|
---|
52 |
|
---|
53 | public:
|
---|
54 | static T *allocate(size_t n)
|
---|
55 | { return 0 == n? 0 : (T*) alloc::allocate(n * sizeof (T)); }
|
---|
56 | static T *allocate(void)
|
---|
57 | { return (T*) alloc::allocate(sizeof (T)); }
|
---|
58 | static void deallocate(T *p, size_t n)
|
---|
59 | { if (0 != n) alloc::deallocate(p, n * sizeof (T)); }
|
---|
60 | static void deallocate(T *p)
|
---|
61 | { alloc::deallocate(p, sizeof (T)); }
|
---|
62 | };
|
---|
63 |
|
---|
64 | #include "gc.h"
|
---|
65 |
|
---|
66 | // The following need to match collector data structures.
|
---|
67 | // We can't include gc_priv.h, since that pulls in way too much stuff.
|
---|
68 | // This should eventually be factored out into another include file.
|
---|
69 |
|
---|
70 | extern "C" {
|
---|
71 | extern void ** const GC_objfreelist_ptr;
|
---|
72 | extern void ** const GC_aobjfreelist_ptr;
|
---|
73 | extern void ** const GC_uobjfreelist_ptr;
|
---|
74 | extern void ** const GC_auobjfreelist_ptr;
|
---|
75 |
|
---|
76 | extern void GC_incr_words_allocd(size_t words);
|
---|
77 | extern void GC_incr_mem_freed(size_t words);
|
---|
78 |
|
---|
79 | extern char * GC_generic_malloc_words_small(size_t word, int kind);
|
---|
80 | }
|
---|
81 |
|
---|
82 | // Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
|
---|
83 | // AUNCOLLECTABLE in gc_priv.h.
|
---|
84 |
|
---|
85 | enum { GC_PTRFREE = 0, GC_NORMAL = 1, GC_UNCOLLECTABLE = 2,
|
---|
86 | GC_AUNCOLLECTABLE = 3 };
|
---|
87 |
|
---|
88 | enum { GC_max_fast_bytes = 255 };
|
---|
89 |
|
---|
90 | enum { GC_bytes_per_word = sizeof(char *) };
|
---|
91 |
|
---|
92 | enum { GC_byte_alignment = 8 };
|
---|
93 |
|
---|
94 | enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
|
---|
95 |
|
---|
96 | inline void * &GC_obj_link(void * p)
|
---|
97 | { return *(void **)p; }
|
---|
98 |
|
---|
99 | // Compute a number of words >= n+1 bytes.
|
---|
100 | // The +1 allows for pointers one past the end.
|
---|
101 | inline size_t GC_round_up(size_t n)
|
---|
102 | {
|
---|
103 | return ((n + GC_byte_alignment)/GC_byte_alignment)*GC_word_alignment;
|
---|
104 | }
|
---|
105 |
|
---|
106 | // The same but don't allow for extra byte.
|
---|
107 | inline size_t GC_round_up_uncollectable(size_t n)
|
---|
108 | {
|
---|
109 | return ((n + GC_byte_alignment - 1)/GC_byte_alignment)*GC_word_alignment;
|
---|
110 | }
|
---|
111 |
|
---|
112 | template <int dummy>
|
---|
113 | class GC_aux_template {
|
---|
114 | public:
|
---|
115 | // File local count of allocated words. Occasionally this is
|
---|
116 | // added into the global count. A separate count is necessary since the
|
---|
117 | // real one must be updated with a procedure call.
|
---|
118 | static size_t GC_words_recently_allocd;
|
---|
119 |
|
---|
120 | // Same for uncollectable mmory. Not yet reflected in either
|
---|
121 | // GC_words_recently_allocd or GC_non_gc_bytes.
|
---|
122 | static size_t GC_uncollectable_words_recently_allocd;
|
---|
123 |
|
---|
124 | // Similar counter for explicitly deallocated memory.
|
---|
125 | static size_t GC_mem_recently_freed;
|
---|
126 |
|
---|
127 | // Again for uncollectable memory.
|
---|
128 | static size_t GC_uncollectable_mem_recently_freed;
|
---|
129 |
|
---|
130 | static void * GC_out_of_line_malloc(size_t nwords, int kind);
|
---|
131 | };
|
---|
132 |
|
---|
133 | template <int dummy>
|
---|
134 | size_t GC_aux_template<dummy>::GC_words_recently_allocd = 0;
|
---|
135 |
|
---|
136 | template <int dummy>
|
---|
137 | size_t GC_aux_template<dummy>::GC_uncollectable_words_recently_allocd = 0;
|
---|
138 |
|
---|
139 | template <int dummy>
|
---|
140 | size_t GC_aux_template<dummy>::GC_mem_recently_freed = 0;
|
---|
141 |
|
---|
142 | template <int dummy>
|
---|
143 | size_t GC_aux_template<dummy>::GC_uncollectable_mem_recently_freed = 0;
|
---|
144 |
|
---|
145 | template <int dummy>
|
---|
146 | void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
|
---|
147 | {
|
---|
148 | GC_words_recently_allocd += GC_uncollectable_words_recently_allocd;
|
---|
149 | GC_non_gc_bytes +=
|
---|
150 | GC_bytes_per_word * GC_uncollectable_words_recently_allocd;
|
---|
151 | GC_uncollectable_words_recently_allocd = 0;
|
---|
152 |
|
---|
153 | GC_mem_recently_freed += GC_uncollectable_mem_recently_freed;
|
---|
154 | GC_non_gc_bytes -=
|
---|
155 | GC_bytes_per_word * GC_uncollectable_mem_recently_freed;
|
---|
156 | GC_uncollectable_mem_recently_freed = 0;
|
---|
157 |
|
---|
158 | GC_incr_words_allocd(GC_words_recently_allocd);
|
---|
159 | GC_words_recently_allocd = 0;
|
---|
160 |
|
---|
161 | GC_incr_mem_freed(GC_mem_recently_freed);
|
---|
162 | GC_mem_recently_freed = 0;
|
---|
163 |
|
---|
164 | return GC_generic_malloc_words_small(nwords, kind);
|
---|
165 | }
|
---|
166 |
|
---|
167 | typedef GC_aux_template<0> GC_aux;
|
---|
168 |
|
---|
169 | // A fast, single-threaded, garbage-collected allocator
|
---|
170 | // We assume the first word will be immediately overwritten.
|
---|
171 | // In this version, deallocation is not a noop, and explicit
|
---|
172 | // deallocation is likely to help performance.
|
---|
173 | template <int dummy>
|
---|
174 | class single_client_gc_alloc_template {
|
---|
175 | public:
|
---|
176 | static void * allocate(size_t n)
|
---|
177 | {
|
---|
178 | size_t nwords = GC_round_up(n);
|
---|
179 | void ** flh;
|
---|
180 | void * op;
|
---|
181 |
|
---|
182 | if (n > GC_max_fast_bytes) return GC_malloc(n);
|
---|
183 | flh = GC_objfreelist_ptr + nwords;
|
---|
184 | if (0 == (op = *flh)) {
|
---|
185 | return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
|
---|
186 | }
|
---|
187 | *flh = GC_obj_link(op);
|
---|
188 | GC_aux::GC_words_recently_allocd += nwords;
|
---|
189 | return op;
|
---|
190 | }
|
---|
191 | static void * ptr_free_allocate(size_t n)
|
---|
192 | {
|
---|
193 | size_t nwords = GC_round_up(n);
|
---|
194 | void ** flh;
|
---|
195 | void * op;
|
---|
196 |
|
---|
197 | if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
|
---|
198 | flh = GC_aobjfreelist_ptr + nwords;
|
---|
199 | if (0 == (op = *flh)) {
|
---|
200 | return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
|
---|
201 | }
|
---|
202 | *flh = GC_obj_link(op);
|
---|
203 | GC_aux::GC_words_recently_allocd += nwords;
|
---|
204 | return op;
|
---|
205 | }
|
---|
206 | static void deallocate(void *p, size_t n)
|
---|
207 | {
|
---|
208 | size_t nwords = GC_round_up(n);
|
---|
209 | void ** flh;
|
---|
210 |
|
---|
211 | if (n > GC_max_fast_bytes) {
|
---|
212 | GC_free(p);
|
---|
213 | } else {
|
---|
214 | flh = GC_objfreelist_ptr + nwords;
|
---|
215 | GC_obj_link(p) = *flh;
|
---|
216 | memset((char *)p + GC_bytes_per_word, 0,
|
---|
217 | GC_bytes_per_word * (nwords - 1));
|
---|
218 | *flh = p;
|
---|
219 | GC_aux::GC_mem_recently_freed += nwords;
|
---|
220 | }
|
---|
221 | }
|
---|
222 | static void ptr_free_deallocate(void *p, size_t n)
|
---|
223 | {
|
---|
224 | size_t nwords = GC_round_up(n);
|
---|
225 | void ** flh;
|
---|
226 |
|
---|
227 | if (n > GC_max_fast_bytes) {
|
---|
228 | GC_free(p);
|
---|
229 | } else {
|
---|
230 | flh = GC_aobjfreelist_ptr + nwords;
|
---|
231 | GC_obj_link(p) = *flh;
|
---|
232 | *flh = p;
|
---|
233 | GC_aux::GC_mem_recently_freed += nwords;
|
---|
234 | }
|
---|
235 | }
|
---|
236 | };
|
---|
237 |
|
---|
238 | typedef single_client_gc_alloc_template<0> single_client_gc_alloc;
|
---|
239 |
|
---|
240 | // Once more, for uncollectable objects.
|
---|
241 | template <int dummy>
|
---|
242 | class single_client_alloc_template {
|
---|
243 | public:
|
---|
244 | static void * allocate(size_t n)
|
---|
245 | {
|
---|
246 | size_t nwords = GC_round_up_uncollectable(n);
|
---|
247 | void ** flh;
|
---|
248 | void * op;
|
---|
249 |
|
---|
250 | if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
|
---|
251 | flh = GC_uobjfreelist_ptr + nwords;
|
---|
252 | if (0 == (op = *flh)) {
|
---|
253 | return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
|
---|
254 | }
|
---|
255 | *flh = GC_obj_link(op);
|
---|
256 | GC_aux::GC_uncollectable_words_recently_allocd += nwords;
|
---|
257 | return op;
|
---|
258 | }
|
---|
259 | static void * ptr_free_allocate(size_t n)
|
---|
260 | {
|
---|
261 | size_t nwords = GC_round_up_uncollectable(n);
|
---|
262 | void ** flh;
|
---|
263 | void * op;
|
---|
264 |
|
---|
265 | if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
|
---|
266 | flh = GC_auobjfreelist_ptr + nwords;
|
---|
267 | if (0 == (op = *flh)) {
|
---|
268 | return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
|
---|
269 | }
|
---|
270 | *flh = GC_obj_link(op);
|
---|
271 | GC_aux::GC_uncollectable_words_recently_allocd += nwords;
|
---|
272 | return op;
|
---|
273 | }
|
---|
274 | static void deallocate(void *p, size_t n)
|
---|
275 | {
|
---|
276 | size_t nwords = GC_round_up_uncollectable(n);
|
---|
277 | void ** flh;
|
---|
278 |
|
---|
279 | if (n > GC_max_fast_bytes) {
|
---|
280 | GC_free(p);
|
---|
281 | } else {
|
---|
282 | flh = GC_uobjfreelist_ptr + nwords;
|
---|
283 | GC_obj_link(p) = *flh;
|
---|
284 | *flh = p;
|
---|
285 | GC_aux::GC_uncollectable_mem_recently_freed += nwords;
|
---|
286 | }
|
---|
287 | }
|
---|
288 | static void ptr_free_deallocate(void *p, size_t n)
|
---|
289 | {
|
---|
290 | size_t nwords = GC_round_up_uncollectable(n);
|
---|
291 | void ** flh;
|
---|
292 |
|
---|
293 | if (n > GC_max_fast_bytes) {
|
---|
294 | GC_free(p);
|
---|
295 | } else {
|
---|
296 | flh = GC_auobjfreelist_ptr + nwords;
|
---|
297 | GC_obj_link(p) = *flh;
|
---|
298 | *flh = p;
|
---|
299 | GC_aux::GC_uncollectable_mem_recently_freed += nwords;
|
---|
300 | }
|
---|
301 | }
|
---|
302 | };
|
---|
303 |
|
---|
304 | typedef single_client_alloc_template<0> single_client_alloc;
|
---|
305 |
|
---|
306 | template < int dummy >
|
---|
307 | class gc_alloc_template {
|
---|
308 | public:
|
---|
309 | static void * allocate(size_t n) { return GC_malloc(n); }
|
---|
310 | static void * ptr_free_allocate(size_t n)
|
---|
311 | { return GC_malloc_atomic(n); }
|
---|
312 | static void deallocate(void *, size_t) { }
|
---|
313 | static void ptr_free_deallocate(void *, size_t) { }
|
---|
314 | };
|
---|
315 |
|
---|
316 | typedef gc_alloc_template < 0 > gc_alloc;
|
---|
317 |
|
---|
318 | template < int dummy >
|
---|
319 | class alloc_template {
|
---|
320 | public:
|
---|
321 | static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
|
---|
322 | static void * ptr_free_allocate(size_t n)
|
---|
323 | { return GC_malloc_atomic_uncollectable(n); }
|
---|
324 | static void deallocate(void *p, size_t) { GC_free(p); }
|
---|
325 | static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
|
---|
326 | };
|
---|
327 |
|
---|
328 | typedef alloc_template < 0 > alloc;
|
---|
329 |
|
---|
330 | #ifdef _SGI_SOURCE
|
---|
331 |
|
---|
332 | // We want to specialize simple_alloc so that it does the right thing
|
---|
333 | // for all pointerfree types. At the moment there is no portable way to
|
---|
334 | // even approximate that. The following approximation should work for
|
---|
335 | // SGI compilers, and perhaps some others.
|
---|
336 |
|
---|
337 | # define __GC_SPECIALIZE(T,alloc) \
|
---|
338 | class simple_alloc<T, alloc> { \
|
---|
339 | public: \
|
---|
340 | static T *allocate(size_t n) \
|
---|
341 | { return 0 == n? 0 : \
|
---|
342 | (T*) alloc::ptr_free_allocate(n * sizeof (T)); } \
|
---|
343 | static T *allocate(void) \
|
---|
344 | { return (T*) alloc::ptr_free_allocate(sizeof (T)); } \
|
---|
345 | static void deallocate(T *p, size_t n) \
|
---|
346 | { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
|
---|
347 | static void deallocate(T *p) \
|
---|
348 | { alloc::ptr_free_deallocate(p, sizeof (T)); } \
|
---|
349 | };
|
---|
350 |
|
---|
351 | __GC_SPECIALIZE(char, gc_alloc)
|
---|
352 | __GC_SPECIALIZE(int, gc_alloc)
|
---|
353 | __GC_SPECIALIZE(unsigned, gc_alloc)
|
---|
354 | __GC_SPECIALIZE(float, gc_alloc)
|
---|
355 | __GC_SPECIALIZE(double, gc_alloc)
|
---|
356 |
|
---|
357 | __GC_SPECIALIZE(char, alloc)
|
---|
358 | __GC_SPECIALIZE(int, alloc)
|
---|
359 | __GC_SPECIALIZE(unsigned, alloc)
|
---|
360 | __GC_SPECIALIZE(float, alloc)
|
---|
361 | __GC_SPECIALIZE(double, alloc)
|
---|
362 |
|
---|
363 | __GC_SPECIALIZE(char, single_client_gc_alloc)
|
---|
364 | __GC_SPECIALIZE(int, single_client_gc_alloc)
|
---|
365 | __GC_SPECIALIZE(unsigned, single_client_gc_alloc)
|
---|
366 | __GC_SPECIALIZE(float, single_client_gc_alloc)
|
---|
367 | __GC_SPECIALIZE(double, single_client_gc_alloc)
|
---|
368 |
|
---|
369 | __GC_SPECIALIZE(char, single_client_alloc)
|
---|
370 | __GC_SPECIALIZE(int, single_client_alloc)
|
---|
371 | __GC_SPECIALIZE(unsigned, single_client_alloc)
|
---|
372 | __GC_SPECIALIZE(float, single_client_alloc)
|
---|
373 | __GC_SPECIALIZE(double, single_client_alloc)
|
---|
374 |
|
---|
375 | #ifdef __STL_USE_STD_ALLOCATORS
|
---|
376 |
|
---|
377 | ???copy stuff from stl_alloc.h or remove it to a different file ???
|
---|
378 |
|
---|
379 | #endif /* __STL_USE_STD_ALLOCATORS */
|
---|
380 |
|
---|
381 | #endif /* _SGI_SOURCE */
|
---|
382 |
|
---|
383 | #endif /* GC_ALLOC_H */
|
---|