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