| 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 */
|
|---|