2
0

bbgc.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. #include "bbgc.h"
  2. namespace bbDB{
  3. void stop();
  4. void stopped();
  5. void error( bbString err );
  6. }
  7. namespace bbGC{
  8. int memused;
  9. int malloced;
  10. size_t trigger=4*1024*1024;
  11. int suspended=1;
  12. int markedBit;
  13. int unmarkedBit;
  14. bbGCNode *markQueue;
  15. bbGCNode *markedList;
  16. bbGCNode *unmarkedList;
  17. bbGCRoot *roots;
  18. bbGCFiber *fibers;
  19. bbGCFiber *currentFiber;
  20. bbGCTmp *freeTmps;
  21. bbGCTmp *retained;
  22. bbGCNode markLists[2];
  23. bbGCNode freeList;
  24. size_t markedBytes;
  25. size_t unmarkedBytes;
  26. size_t allocedBytes;
  27. void *pools[32];
  28. unsigned char *poolBuf;
  29. size_t poolBufSize;
  30. bool inited;
  31. void init(){
  32. if( inited ) return;
  33. inited=true;
  34. markedBit=1;
  35. markedList=&markLists[0];
  36. markedList->succ=markedList->pred=markedList;
  37. unmarkedBit=2;
  38. unmarkedList=&markLists[1];
  39. unmarkedList->succ=unmarkedList->pred=unmarkedList;
  40. freeList.succ=freeList.pred=&freeList;
  41. fibers=new bbGCFiber;
  42. currentFiber=fibers;
  43. suspended=0;
  44. }
  45. void setTrigger( size_t size ){
  46. trigger=size;
  47. }
  48. void suspend(){
  49. ++suspended;
  50. }
  51. void resume(){
  52. --suspended;
  53. }
  54. void reclaim( size_t size=0x7fffffff ){
  55. size_t freed=0;
  56. while( freeList.succ!=&freeList && freed<size ){
  57. bbGCNode *p=freeList.succ;
  58. freed+=mallocSize( p );
  59. remove( p );
  60. if( p->flags & 1 ){
  61. //printf( "finalizing: %s %p\n",p->typeName(),p );fflush( stdout );
  62. ++suspended;
  63. p->state=unmarkedBit;
  64. p->gcFinalize();
  65. if( p->state==markedBit ) bbRuntimeError( "Object resurrected in finalizer" );
  66. --suspended;
  67. }
  68. p->~bbGCNode();
  69. bbGC::free( p );
  70. }
  71. }
  72. void markQueued( size_t tomark=0x7fffffff ){
  73. while( markQueue && markedBytes<tomark ){
  74. bbGCNode *p=markQueue;
  75. markQueue=p->succ;
  76. insert( p,markedList );
  77. markedBytes+=mallocSize( p );
  78. p->gcMark();
  79. }
  80. }
  81. void markRoots(){
  82. for( bbGCRoot *root=roots;root;root=root->succ ){
  83. root->gcMark();
  84. }
  85. }
  86. void markRetained(){
  87. for( bbGCTmp *tmp=retained;tmp;tmp=tmp->succ ){
  88. enqueue( tmp->node );
  89. }
  90. }
  91. void markFibers(){
  92. bbGCFiber *fiber=fibers;
  93. for(;;){
  94. bbGCMark( fiber->entry );
  95. for( bbGCFrame *frame=fiber->frames;frame;frame=frame->succ ){
  96. frame->gcMark();
  97. }
  98. for( bbGCNode *node=fiber->ctoring;node;node=node->succ ){
  99. node->gcMark();
  100. }
  101. for( bbGCTmp *tmp=fiber->tmps;tmp;tmp=tmp->succ ){
  102. enqueue( tmp->node );
  103. }
  104. fiber=fiber->succ;
  105. if( fiber==fibers ) break;
  106. }
  107. }
  108. void sweep(){
  109. markRetained();
  110. markFibers();
  111. markQueued();
  112. if( unmarkedList->succ!=unmarkedList ){
  113. //append unmarked to end of free queue
  114. unmarkedList->succ->pred=freeList.pred;
  115. unmarkedList->pred->succ=&freeList;
  116. freeList.pred->succ=unmarkedList->succ;
  117. freeList.pred=unmarkedList->pred;
  118. //clear unmarked
  119. unmarkedList->succ=unmarkedList->pred=unmarkedList;
  120. }
  121. //swap mark/unmarked lists
  122. auto tmp1=markedList;markedList=unmarkedList;unmarkedList=tmp1;
  123. auto tmp2=markedBit;markedBit=unmarkedBit;unmarkedBit=tmp2;
  124. unmarkedBytes=markedBytes;
  125. markedBytes=0;
  126. //start new sweep phase
  127. allocedBytes=0;
  128. markRoots();
  129. }
  130. void retain( bbGCNode *node ){
  131. BBGC_VALIDATE( node );
  132. if( !node ) return;
  133. bbGCTmp *tmp=freeTmps;
  134. if( !tmp ) tmp=new bbGCTmp;
  135. tmp->node=node;
  136. tmp->succ=retained;
  137. retained=tmp;
  138. }
  139. void release( bbGCNode *node ){
  140. if( !node ) return;
  141. bbGCTmp **p=&retained;
  142. while( bbGCTmp *tmp=*p ){
  143. if( tmp->node==node ){
  144. *p=tmp->succ;
  145. tmp->succ=freeTmps;
  146. freeTmps=tmp;
  147. return;
  148. }
  149. p=&tmp->succ;
  150. }
  151. printf( "Warning! bbGC::release() - node not found!\n" );
  152. }
  153. void *malloc( size_t size ){
  154. size=(size+8+7) & ~7;
  155. memused+=size;
  156. if( !suspended ){
  157. if( allocedBytes+size>=trigger ){
  158. sweep();
  159. }else{
  160. markQueued( double( allocedBytes+size ) / double( trigger ) * double( unmarkedBytes + trigger ) );
  161. }
  162. reclaim( size );
  163. }
  164. void *p;
  165. if( size<256 ){
  166. if( pools[size>>3] ){
  167. p=pools[size>>3];
  168. pools[size>>3]=*(void**)p;
  169. }else{
  170. if( size>poolBufSize ){
  171. if( poolBufSize ){
  172. *(void**)poolBuf=pools[poolBufSize>>3];
  173. pools[poolBufSize>>3]=poolBuf;
  174. }
  175. poolBufSize=65536;
  176. poolBuf=(unsigned char*)::malloc( poolBufSize );
  177. malloced+=poolBufSize;
  178. }
  179. p=poolBuf;
  180. poolBuf+=size;
  181. poolBufSize-=size;
  182. }
  183. }else{
  184. p=::malloc( size );
  185. malloced+=size;
  186. }
  187. allocedBytes+=size;
  188. size_t *q=(size_t*)p;
  189. if( sizeof(size_t)==4 ) ++q;
  190. *q++=size;
  191. return q;
  192. }
  193. size_t mallocSize( void *p ){
  194. if( p ) return *((size_t*)p-1);
  195. return 0;
  196. }
  197. void free( void *p ){
  198. if( !p ) return;
  199. size_t *q=(size_t*)p;
  200. size_t size=*--q;
  201. if( sizeof(size_t)==4 ) --q;
  202. #ifndef NDEBUG
  203. memset( q,0xa5,size );
  204. #endif
  205. memused-=size;
  206. if( size<256 ){
  207. *(void**)q=pools[size>>3];
  208. pools[size>>3]=q;
  209. }else{
  210. malloced-=size;
  211. ::free( q );
  212. }
  213. }
  214. /*
  215. bbGCNode *alloc( size_t size ){
  216. bbGCNode *p=(bbGCNode*)bbGC::malloc( size );
  217. *((void**)p)=(void*)0xcafebabe;
  218. p->state=0;
  219. p->flags=0;
  220. return p;
  221. }
  222. */
  223. void collect(){
  224. if( !inited ) return;
  225. static size_t maxused;
  226. sweep();
  227. reclaim();
  228. if( memused>maxused ) maxused=memused;
  229. // printf( "Collect complete: memused=%i max memused=%i\n",memused,maxused );fflush( stdout );
  230. }
  231. }