blitz_gc_rc.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. #include "blitz.h"
  2. #ifdef BB_GC_RC
  3. //#define DEBUG_GC
  4. #ifdef _WIN32
  5. #include <windows.h>
  6. #endif
  7. #define SIZEALIGN 16
  8. #define ALIGNMASK (SIZEALIGN-1)
  9. #define BUF_GROW 1024
  10. #define BBGC_ZERO 0x80000000
  11. #define PAGE_BITS 12
  12. #define PAGE_SIZE (1<<PAGE_BITS)
  13. #define PAGE_MASK ((PAGE_SIZE/4)-1)
  14. static int gc_mode=BBGC_AUTOMATIC;
  15. static int gc_debug=BBGC_NODEBUG;
  16. static int gc_suspended=0;
  17. static int gc_millisecs,gc_memfreed,gc_objsfreed;
  18. static void **buf_base,**buf_put,**buf_end;
  19. static int max_buflen;
  20. static int *pages[1<<(25-PAGE_BITS)];
  21. static int pagesAlloced;
  22. static void **live;
  23. static int live_len;
  24. #define MAXSIZE 256
  25. #define MAXFREEBUFSIZE 65536
  26. static char* freebuf;
  27. static int freebufsize,freebuf_alloced;
  28. static char* freelists[MAXSIZE/SIZEALIGN];
  29. static int gc_alloced;
  30. #ifdef DEBUG_GC
  31. #define DEBUG_COUNT 16384 //4096
  32. #define DEBUG_MASK (DEBUG_COUNT-1)
  33. #define DEBUG_OBJECT(X,Y) debugObject((X),(Y))
  34. typedef struct GCDebugInfo{
  35. void *object;
  36. void *typename;
  37. const char *msg;
  38. }GCDebugInfo;
  39. static int dbIndex;
  40. static GCDebugInfo dbInfos[DEBUG_COUNT];
  41. static void dumpDebugInfo();
  42. static int debugAtExit;
  43. static const char *typeName( void *p ){
  44. BBObject *o=(BBObject*)p;
  45. BBClass *c=o->clas;
  46. BBDebugScope *d=c->debug_scope;
  47. if( d ) return d->name;
  48. return "?";
  49. }
  50. static void debugObject( void *p,const char *msg ){
  51. GCDebugInfo *db=dbInfos+(dbIndex & DEBUG_MASK);
  52. db->object=p;
  53. db->typename=typeName( p );
  54. db->msg=msg;
  55. ++dbIndex;
  56. if( debugAtExit ) return;
  57. atexit( dumpDebugInfo );
  58. debugAtExit=1;
  59. }
  60. static void dumpDebugInfo(){
  61. int i;
  62. printf( "GC Debug info:\n" );
  63. for( i=0;i<DEBUG_COUNT;++i ){
  64. GCDebugInfo *db=dbInfos+((dbIndex+i) & DEBUG_MASK);
  65. if( !db->object ) continue;
  66. printf( "%s %s @ $%p\n",db->msg,db->typename,db->object );
  67. }
  68. fflush( stdout );
  69. }
  70. #else
  71. #define DEBUG_OBJECT(X,Y)
  72. #endif
  73. static void gcError( void *p,const char *msg ){
  74. #ifdef DEBUG_GC
  75. printf( "GC ERROR: %s, object=$%p\n",msg,p );
  76. fflush( stdout );
  77. #endif
  78. bbExThrowCString( msg );
  79. }
  80. static int setMemBit( void *p ){
  81. int page;
  82. int offset;
  83. int mask;
  84. page=(unsigned)p>>(PAGE_BITS+7);
  85. if( !pages[page] ){
  86. ++pagesAlloced;
  87. pages[page]=malloc( PAGE_SIZE );
  88. memset( pages[page],0,PAGE_SIZE );
  89. }
  90. offset=((unsigned)p>>9) & PAGE_MASK;
  91. mask=1<<( ((unsigned)p>>4) & 31 );
  92. if( pages[page][offset] & mask ) gcError( p,"setMemBit error: membit already set" );
  93. pages[page][offset]|=mask;
  94. DEBUG_OBJECT( p,"setMemBit" );
  95. }
  96. static void clrMemBit( void *p ){
  97. int page;
  98. int offset;
  99. int mask;
  100. page=(unsigned)p>>(PAGE_BITS+7);
  101. if( !pages[page] ) gcError( p,"clrMemBit error: mempage does not exist" );
  102. offset=((unsigned)p>>9) & PAGE_MASK;
  103. mask=1<<( ((unsigned)p>>4) & 31 );
  104. if( !(pages[page][offset] & mask) ) gcError( p,"clrMemBit error: membit not set" );
  105. pages[page][offset]&=~mask;
  106. DEBUG_OBJECT( p,"clrMemBit" );
  107. }
  108. static int tstMemBit( void *p ){
  109. int page;
  110. int offset;
  111. int mask;
  112. if( (int)p & 15 ) return 0;
  113. page=(unsigned)p>>(PAGE_BITS+7);
  114. if( !pages[page] ){
  115. return 0;
  116. }
  117. offset=((unsigned)p>>9) & PAGE_MASK;
  118. mask=1<<( ((unsigned)p>>4) & 31 );
  119. return pages[page][offset] & mask;
  120. }
  121. static int collectMem( int dummy ){
  122. int i,n;
  123. BBObject *p;
  124. void **sp,**spBase,**tsp;
  125. void *rootRegs[BBGC_NUM_ROOTREGS];
  126. if( gc_suspended || !bbGCStackTop ) return 0;
  127. ++gc_suspended;
  128. gc_memfreed=bbGCMemAlloced();
  129. if( gc_debug ){
  130. gc_millisecs=-1;
  131. #if _WIN32
  132. gc_millisecs=timeGetTime();
  133. #endif
  134. }
  135. spBase=bbGCRootRegs( rootRegs );
  136. n=bbGCStackTop-spBase+BBGC_NUM_ROOTREGS;
  137. if( n>live_len ){
  138. void **t=live;
  139. int new_len=live_len+1000;
  140. if( n>new_len ) new_len=n;
  141. live=(void**)malloc( new_len*4 );
  142. if( t ) free( t );
  143. live_len=new_len;
  144. }
  145. tsp=live;
  146. sp=spBase;
  147. while( sp!=bbGCStackTop ){
  148. p=*sp++;
  149. if( tstMemBit( p ) ) *tsp++=p;
  150. }
  151. sp=rootRegs;
  152. for( n=0;n<BBGC_NUM_ROOTREGS;++n ){
  153. p=*sp++;
  154. if( tstMemBit( p ) ) *tsp++=p;
  155. }
  156. sp=live;
  157. while( sp!=tsp ){
  158. p=*sp++;
  159. ++p->refs;
  160. }
  161. i=0;
  162. gc_objsfreed=0;
  163. while( i!=(buf_put-buf_base) ){
  164. p=buf_base[i++];
  165. if( p->refs>=0 ){
  166. printf( "bad refs:obj=$%x refs=$%x\n",(unsigned)p,(unsigned)p->refs );
  167. if( p->clas==&bbStringClass ){
  168. printf( "String:%s\n",bbStringToCString( (BBString*)p ) );
  169. }
  170. fflush( stdout );
  171. }
  172. if( p->refs&=~BBGC_ZERO ) continue;
  173. p->clas->free( p );
  174. ++gc_objsfreed;
  175. }
  176. buf_put=buf_base;
  177. sp=live;
  178. while( sp!=tsp ){
  179. p=*sp++;
  180. if( !--p->refs ) bbGCFree( p );
  181. }
  182. gc_memfreed-=bbGCMemAlloced();
  183. if( gc_debug ){
  184. #if _WIN32
  185. gc_millisecs=timeGetTime()-gc_millisecs;
  186. #endif
  187. printf( "GC collectMem: memFreed=%i, time=%ims, objsFreed=%i, objsScanned=%i, objsLive=%i\n",
  188. gc_memfreed,
  189. gc_millisecs,
  190. gc_objsfreed,
  191. bbGCStackTop-spBase,
  192. tsp-live );
  193. fflush( stdout );
  194. }
  195. --gc_suspended;
  196. return gc_memfreed;
  197. }
  198. //***** GC INTERFACE *****//
  199. void bbGCStartup(){
  200. }
  201. void bbGCSetMode( int mode ){
  202. gc_mode=mode;
  203. }
  204. void bbGCSetDebug( int debug ){
  205. gc_debug=debug;
  206. }
  207. BBObject *bbGCAllocObject( int size,BBClass *clas,int flags ){
  208. BBObject *p;
  209. if( gc_mode==BBGC_AUTOMATIC && !gc_suspended ){
  210. static int alloced;
  211. static int rate=500;
  212. alloced+=size;
  213. if( alloced>(1024*1024) || buf_put-buf_base>rate ){
  214. collectMem(0);
  215. rate+=500-gc_objsfreed;
  216. alloced=0;
  217. }
  218. }else if( gc_mode==BBGC_AGGRESSIVE ){
  219. collectMem(0);
  220. }
  221. if( size<=0 ) return 0;
  222. if( size>(MAXSIZE-SIZEALIGN) ){
  223. p=bbMemAlloc( size );
  224. }else{
  225. int n=(size+ALIGNMASK)/SIZEALIGN;
  226. p=freelists[n];
  227. if( p ){
  228. freelists[n]=*(char**)p;
  229. }else if( size<=freebufsize ){
  230. p=freebuf;
  231. n*=SIZEALIGN;
  232. freebuf+=n;
  233. freebufsize-=n;
  234. }else{
  235. if( freebufsize ){
  236. int n=(freebufsize+ALIGNMASK)/SIZEALIGN;
  237. *(char**)freebuf=freelists[n];
  238. freelists[n]=freebuf;
  239. }
  240. p=bbMemAlloc( MAXFREEBUFSIZE );
  241. n*=SIZEALIGN;
  242. freebuf=(char*)p+n;
  243. freebufsize=MAXFREEBUFSIZE-n;
  244. }
  245. }
  246. setMemBit( p );
  247. gc_alloced+=size;
  248. p->clas=clas;
  249. p->refs=0;
  250. bbGCFree( p );
  251. return p;
  252. }
  253. int bbGCValidate( void *p ){
  254. return tstMemBit( p ) ? 1 : 0;
  255. }
  256. int bbGCMemAlloced(){
  257. return gc_alloced;
  258. }
  259. int bbGCCollect(){
  260. return collectMem(0);
  261. }
  262. void bbGCSuspend(){
  263. ++gc_suspended;
  264. }
  265. void bbGCResume(){
  266. --gc_suspended;
  267. }
  268. void bbGCRetain( BBObject *p ){
  269. BBINCREFS( p );
  270. }
  271. void bbGCRelease( BBObject *p ){
  272. BBDECREFS( p );
  273. }
  274. //***** Ref counter specific *****//
  275. void bbGCFree( BBObject *p ){
  276. if( p->refs ){
  277. bbExThrowCString( "GC bbGCFree: mem has non-0 refs" );
  278. }
  279. if( buf_put==buf_end ){
  280. int len=buf_put-buf_base,new_len=len+BUF_GROW;
  281. buf_base=(void**)bbMemExtend( buf_base,len*4,new_len*4 );
  282. buf_end=buf_base+new_len;
  283. buf_put=buf_base+len;
  284. if( new_len>max_buflen ) max_buflen=new_len;
  285. }
  286. p->refs=BBGC_ZERO;
  287. *buf_put++=p;
  288. }
  289. void bbGCDeallocObject( BBObject *p,int size ){
  290. if( !p ) return;
  291. clrMemBit( p );
  292. if( size>(MAXSIZE-SIZEALIGN) ){
  293. bbMemFree( p );
  294. }else{
  295. int n=(size+ALIGNMASK)/SIZEALIGN;
  296. *(char**)p=freelists[n];
  297. freelists[n]=(char*)p;
  298. }
  299. gc_alloced-=size;
  300. }
  301. #endif