bbgc.cpp 5.7 KB

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