new_gc_alloc.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  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. // This is a revision of gc_alloc.h for SGI STL versions > 3.0
  15. // Unlike earlier versions, it supplements the standard "alloc.h"
  16. // instead of replacing it.
  17. //
  18. // This is sloppy about variable names used in header files.
  19. // It also doesn't yet understand the new header file names or
  20. // namespaces.
  21. //
  22. // This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE.
  23. // The user should also consider -DREDIRECT_MALLOC=GC_uncollectable_malloc,
  24. // to ensure that object allocated through malloc are traced.
  25. //
  26. // Some of this could be faster in the explicit deallocation case.
  27. // In particular, we spend too much time clearing objects on the
  28. // free lists. That could be avoided.
  29. //
  30. // This uses template classes with static members, and hence does not work
  31. // with g++ 2.7.2 and earlier.
  32. //
  33. // Unlike its predecessor, this one simply defines
  34. // gc_alloc
  35. // single_client_gc_alloc
  36. // traceable_alloc
  37. // single_client_traceable_alloc
  38. //
  39. // It does not redefine alloc. Nor does it change the default allocator,
  40. // though the user may wish to do so. (The argument against changing
  41. // the default allocator is that it may introduce subtle link compatibility
  42. // problems. The argument for changing it is that the usual default
  43. // allocator is usually a very bad choice for a garbage collected environment.)
  44. //
  45. #ifndef GC_ALLOC_H
  46. #include "gc.h"
  47. #if (__GNUC__ < 3)
  48. # include <stack> // A more portable way to get stl_alloc.h .
  49. #else
  50. # include <bits/stl_alloc.h>
  51. # ifndef __STL_BEGIN_NAMESPACE
  52. # define __STL_BEGIN_NAMESPACE namespace std {
  53. # define __STL_END_NAMESPACE };
  54. # endif
  55. #ifndef __STL_USE_STD_ALLOCATORS
  56. #define __STL_USE_STD_ALLOCATORS
  57. #endif
  58. #endif
  59. /* A hack to deal with gcc 3.1. If you are using gcc3.1 and later, */
  60. /* you should probably really use gc_allocator.h instead. */
  61. #if defined (__GNUC__) && \
  62. (__GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ >= 1)))
  63. # define simple_alloc __simple_alloc
  64. #endif
  65. #define GC_ALLOC_H
  66. #include <stddef.h>
  67. #include <string.h>
  68. // The following need to match collector data structures.
  69. // We can't include gc_priv.h, since that pulls in way too much stuff.
  70. // This should eventually be factored out into another include file.
  71. extern "C" {
  72. GC_API void ** const GC_objfreelist_ptr;
  73. GC_API void ** const GC_aobjfreelist_ptr;
  74. GC_API void ** const GC_uobjfreelist_ptr;
  75. GC_API void ** const GC_auobjfreelist_ptr;
  76. GC_API void GC_CALL GC_incr_bytes_allocd(size_t bytes);
  77. GC_API void GC_CALL GC_incr_bytes_freed(size_t bytes);
  78. GC_API char * GC_CALL GC_generic_malloc_words_small(size_t word, int kind);
  79. /* FIXME: Doesn't exist anymore. */
  80. }
  81. // Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
  82. // AUNCOLLECTABLE in gc_priv.h.
  83. enum { GC_PTRFREE = 0, GC_NORMAL = 1, GC_UNCOLLECTABLE = 2,
  84. GC_AUNCOLLECTABLE = 3 };
  85. enum { GC_max_fast_bytes = 255 };
  86. enum { GC_bytes_per_word = sizeof(char *) };
  87. enum { GC_byte_alignment = 8 };
  88. enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
  89. inline void * &GC_obj_link(void * p)
  90. { return *reinterpret_cast<void **>(p); }
  91. // Compute a number of words >= n+1 bytes.
  92. // The +1 allows for pointers one past the end.
  93. inline size_t GC_round_up(size_t n)
  94. {
  95. return ((n + GC_byte_alignment)/GC_byte_alignment)*GC_word_alignment;
  96. }
  97. // The same but don't allow for extra byte.
  98. inline size_t GC_round_up_uncollectable(size_t n)
  99. {
  100. return ((n + GC_byte_alignment - 1)/GC_byte_alignment)*GC_word_alignment;
  101. }
  102. template <int dummy>
  103. class GC_aux_template {
  104. public:
  105. // File local count of allocated words. Occasionally this is
  106. // added into the global count. A separate count is necessary since the
  107. // real one must be updated with a procedure call.
  108. static size_t GC_bytes_recently_allocd;
  109. // Same for uncollectible memory. Not yet reflected in either
  110. // GC_bytes_recently_allocd or GC_non_gc_bytes.
  111. static size_t GC_uncollectable_bytes_recently_allocd;
  112. // Similar counter for explicitly deallocated memory.
  113. static size_t GC_bytes_recently_freed;
  114. // Again for uncollectible memory.
  115. static size_t GC_uncollectable_bytes_recently_freed;
  116. static void * GC_out_of_line_malloc(size_t nwords, int kind);
  117. };
  118. template <int dummy>
  119. size_t GC_aux_template<dummy>::GC_bytes_recently_allocd = 0;
  120. template <int dummy>
  121. size_t GC_aux_template<dummy>::GC_uncollectable_bytes_recently_allocd = 0;
  122. template <int dummy>
  123. size_t GC_aux_template<dummy>::GC_bytes_recently_freed = 0;
  124. template <int dummy>
  125. size_t GC_aux_template<dummy>::GC_uncollectable_bytes_recently_freed = 0;
  126. template <int dummy>
  127. void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
  128. {
  129. GC_bytes_recently_allocd += GC_uncollectable_bytes_recently_allocd;
  130. GC_non_gc_bytes +=
  131. GC_uncollectable_bytes_recently_allocd;
  132. GC_uncollectable_bytes_recently_allocd = 0;
  133. GC_bytes_recently_freed += GC_uncollectable_bytes_recently_freed;
  134. GC_non_gc_bytes -= GC_uncollectable_bytes_recently_freed;
  135. GC_uncollectable_bytes_recently_freed = 0;
  136. GC_incr_bytes_allocd(GC_bytes_recently_allocd);
  137. GC_bytes_recently_allocd = 0;
  138. GC_incr_bytes_freed(GC_bytes_recently_freed);
  139. GC_bytes_recently_freed = 0;
  140. return GC_generic_malloc_words_small(nwords, kind);
  141. }
  142. typedef GC_aux_template<0> GC_aux;
  143. // A fast, single-threaded, garbage-collected allocator
  144. // We assume the first word will be immediately overwritten.
  145. // In this version, deallocation is not a no-op, and explicit
  146. // deallocation is likely to help performance.
  147. template <int dummy>
  148. class single_client_gc_alloc_template {
  149. public:
  150. static void * allocate(size_t n)
  151. {
  152. size_t nwords = GC_round_up(n);
  153. void ** flh;
  154. void * op;
  155. if (n > GC_max_fast_bytes) return GC_malloc(n);
  156. flh = GC_objfreelist_ptr + nwords;
  157. if (0 == (op = *flh)) {
  158. return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
  159. }
  160. *flh = GC_obj_link(op);
  161. GC_aux::GC_bytes_recently_allocd += nwords * GC_bytes_per_word;
  162. return op;
  163. }
  164. static void * ptr_free_allocate(size_t n)
  165. {
  166. size_t nwords = GC_round_up(n);
  167. void ** flh;
  168. void * op;
  169. if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
  170. flh = GC_aobjfreelist_ptr + nwords;
  171. if (0 == (op = *flh)) {
  172. return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
  173. }
  174. *flh = GC_obj_link(op);
  175. GC_aux::GC_bytes_recently_allocd += nwords * GC_bytes_per_word;
  176. return op;
  177. }
  178. static void deallocate(void *p, size_t n)
  179. {
  180. size_t nwords = GC_round_up(n);
  181. void ** flh;
  182. if (n > GC_max_fast_bytes) {
  183. GC_free(p);
  184. } else {
  185. flh = GC_objfreelist_ptr + nwords;
  186. GC_obj_link(p) = *flh;
  187. memset(reinterpret_cast<char *>(p) + GC_bytes_per_word, 0,
  188. GC_bytes_per_word * (nwords - 1));
  189. *flh = p;
  190. GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
  191. }
  192. }
  193. static void ptr_free_deallocate(void *p, size_t n)
  194. {
  195. size_t nwords = GC_round_up(n);
  196. void ** flh;
  197. if (n > GC_max_fast_bytes) {
  198. GC_free(p);
  199. } else {
  200. flh = GC_aobjfreelist_ptr + nwords;
  201. GC_obj_link(p) = *flh;
  202. *flh = p;
  203. GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
  204. }
  205. }
  206. };
  207. typedef single_client_gc_alloc_template<0> single_client_gc_alloc;
  208. // Once more, for uncollectible objects.
  209. template <int dummy>
  210. class single_client_traceable_alloc_template {
  211. public:
  212. static void * allocate(size_t n)
  213. {
  214. size_t nwords = GC_round_up_uncollectable(n);
  215. void ** flh;
  216. void * op;
  217. if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
  218. flh = GC_uobjfreelist_ptr + nwords;
  219. if (0 == (op = *flh)) {
  220. return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
  221. }
  222. *flh = GC_obj_link(op);
  223. GC_aux::GC_uncollectable_bytes_recently_allocd +=
  224. nwords * GC_bytes_per_word;
  225. return op;
  226. }
  227. static void * ptr_free_allocate(size_t n)
  228. {
  229. size_t nwords = GC_round_up_uncollectable(n);
  230. void ** flh;
  231. void * op;
  232. if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
  233. flh = GC_auobjfreelist_ptr + nwords;
  234. if (0 == (op = *flh)) {
  235. return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
  236. }
  237. *flh = GC_obj_link(op);
  238. GC_aux::GC_uncollectable_bytes_recently_allocd +=
  239. nwords * GC_bytes_per_word;
  240. return op;
  241. }
  242. static void deallocate(void *p, size_t n)
  243. {
  244. size_t nwords = GC_round_up_uncollectable(n);
  245. void ** flh;
  246. if (n > GC_max_fast_bytes) {
  247. GC_free(p);
  248. } else {
  249. flh = GC_uobjfreelist_ptr + nwords;
  250. GC_obj_link(p) = *flh;
  251. *flh = p;
  252. GC_aux::GC_uncollectable_bytes_recently_freed +=
  253. nwords * GC_bytes_per_word;
  254. }
  255. }
  256. static void ptr_free_deallocate(void *p, size_t n)
  257. {
  258. size_t nwords = GC_round_up_uncollectable(n);
  259. void ** flh;
  260. if (n > GC_max_fast_bytes) {
  261. GC_free(p);
  262. } else {
  263. flh = GC_auobjfreelist_ptr + nwords;
  264. GC_obj_link(p) = *flh;
  265. *flh = p;
  266. GC_aux::GC_uncollectable_bytes_recently_freed +=
  267. nwords * GC_bytes_per_word;
  268. }
  269. }
  270. };
  271. typedef single_client_traceable_alloc_template<0> single_client_traceable_alloc;
  272. template < int dummy >
  273. class gc_alloc_template {
  274. public:
  275. static void * allocate(size_t n) { return GC_malloc(n); }
  276. static void * ptr_free_allocate(size_t n)
  277. { return GC_malloc_atomic(n); }
  278. static void deallocate(void *, size_t) { }
  279. static void ptr_free_deallocate(void *, size_t) { }
  280. };
  281. typedef gc_alloc_template < 0 > gc_alloc;
  282. template < int dummy >
  283. class traceable_alloc_template {
  284. public:
  285. static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
  286. static void * ptr_free_allocate(size_t n)
  287. { return GC_malloc_atomic_uncollectable(n); }
  288. static void deallocate(void *p, size_t) { GC_free(p); }
  289. static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
  290. };
  291. typedef traceable_alloc_template < 0 > traceable_alloc;
  292. // We want to specialize simple_alloc so that it does the right thing
  293. // for all pointer-free types. At the moment there is no portable way to
  294. // even approximate that. The following approximation should work for
  295. // SGI compilers, and recent versions of g++.
  296. // GC_SPECIALIZE() is used internally.
  297. #define GC_SPECIALIZE(T,alloc) \
  298. class simple_alloc<T, alloc> { \
  299. public: \
  300. static T *allocate(size_t n) \
  301. { return 0 == n? 0 : \
  302. reinterpret_cast<T*>(alloc::ptr_free_allocate(n * sizeof(T))); } \
  303. static T *allocate(void) \
  304. { return reinterpret_cast<T*>(alloc::ptr_free_allocate(sizeof(T))); } \
  305. static void deallocate(T *p, size_t n) \
  306. { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof(T)); } \
  307. static void deallocate(T *p) \
  308. { alloc::ptr_free_deallocate(p, sizeof(T)); } \
  309. };
  310. __STL_BEGIN_NAMESPACE
  311. GC_SPECIALIZE(char, gc_alloc)
  312. GC_SPECIALIZE(int, gc_alloc)
  313. GC_SPECIALIZE(unsigned, gc_alloc)
  314. GC_SPECIALIZE(float, gc_alloc)
  315. GC_SPECIALIZE(double, gc_alloc)
  316. GC_SPECIALIZE(char, traceable_alloc)
  317. GC_SPECIALIZE(int, traceable_alloc)
  318. GC_SPECIALIZE(unsigned, traceable_alloc)
  319. GC_SPECIALIZE(float, traceable_alloc)
  320. GC_SPECIALIZE(double, traceable_alloc)
  321. GC_SPECIALIZE(char, single_client_gc_alloc)
  322. GC_SPECIALIZE(int, single_client_gc_alloc)
  323. GC_SPECIALIZE(unsigned, single_client_gc_alloc)
  324. GC_SPECIALIZE(float, single_client_gc_alloc)
  325. GC_SPECIALIZE(double, single_client_gc_alloc)
  326. GC_SPECIALIZE(char, single_client_traceable_alloc)
  327. GC_SPECIALIZE(int, single_client_traceable_alloc)
  328. GC_SPECIALIZE(unsigned, single_client_traceable_alloc)
  329. GC_SPECIALIZE(float, single_client_traceable_alloc)
  330. GC_SPECIALIZE(double, single_client_traceable_alloc)
  331. __STL_END_NAMESPACE
  332. #ifdef __STL_USE_STD_ALLOCATORS
  333. __STL_BEGIN_NAMESPACE
  334. template <class _Tp>
  335. struct _Alloc_traits<_Tp, gc_alloc >
  336. {
  337. static const bool _S_instanceless = true;
  338. typedef simple_alloc<_Tp, gc_alloc > _Alloc_type;
  339. typedef __allocator<_Tp, gc_alloc > allocator_type;
  340. };
  341. inline bool operator==(const gc_alloc&,
  342. const gc_alloc&)
  343. {
  344. return true;
  345. }
  346. inline bool operator!=(const gc_alloc&,
  347. const gc_alloc&)
  348. {
  349. return false;
  350. }
  351. template <class _Tp>
  352. struct _Alloc_traits<_Tp, single_client_gc_alloc >
  353. {
  354. static const bool _S_instanceless = true;
  355. typedef simple_alloc<_Tp, single_client_gc_alloc > _Alloc_type;
  356. typedef __allocator<_Tp, single_client_gc_alloc > allocator_type;
  357. };
  358. inline bool operator==(const single_client_gc_alloc&,
  359. const single_client_gc_alloc&)
  360. {
  361. return true;
  362. }
  363. inline bool operator!=(const single_client_gc_alloc&,
  364. const single_client_gc_alloc&)
  365. {
  366. return false;
  367. }
  368. template <class _Tp>
  369. struct _Alloc_traits<_Tp, traceable_alloc >
  370. {
  371. static const bool _S_instanceless = true;
  372. typedef simple_alloc<_Tp, traceable_alloc > _Alloc_type;
  373. typedef __allocator<_Tp, traceable_alloc > allocator_type;
  374. };
  375. inline bool operator==(const traceable_alloc&,
  376. const traceable_alloc&)
  377. {
  378. return true;
  379. }
  380. inline bool operator!=(const traceable_alloc&,
  381. const traceable_alloc&)
  382. {
  383. return false;
  384. }
  385. template <class _Tp>
  386. struct _Alloc_traits<_Tp, single_client_traceable_alloc >
  387. {
  388. static const bool _S_instanceless = true;
  389. typedef simple_alloc<_Tp, single_client_traceable_alloc > _Alloc_type;
  390. typedef __allocator<_Tp, single_client_traceable_alloc > allocator_type;
  391. };
  392. inline bool operator==(const single_client_traceable_alloc&,
  393. const single_client_traceable_alloc&)
  394. {
  395. return true;
  396. }
  397. inline bool operator!=(const single_client_traceable_alloc&,
  398. const single_client_traceable_alloc&)
  399. {
  400. return false;
  401. }
  402. __STL_END_NAMESPACE
  403. #endif /* __STL_USE_STD_ALLOCATORS */
  404. #endif /* GC_ALLOC_H */