blitz_gc_ms.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. #include "blitz.h"
  2. #ifdef BB_GC_MS
  3. //#define DEBUG_GC
  4. #define SIZEALIGN 16
  5. #define ALIGNMASK (SIZEALIGN-1)
  6. #define BBGC_MARKED 4
  7. #define BBGC_LOCKED 8
  8. #define PAGE_BITS 12
  9. #define PAGE_SIZE (1<<PAGE_BITS)
  10. #define PAGE_MASK ((PAGE_SIZE/4)-1)
  11. typedef struct GCBlock GCBlock;
  12. struct GCBlock{
  13. GCBlock *succ;
  14. int flags; //low 4 bits - rest is size
  15. char data[0];
  16. };
  17. static int *pages[1<<(25-PAGE_BITS)];
  18. static int pagesAlloced;
  19. static GCBlock *usedBlocks;
  20. static GCBlock *finalizedBlocks;
  21. static char *freeBuf;
  22. static int freeBufSize;
  23. static GCBlock *freeBlocks[256];
  24. static int gc_mode=BBGC_AUTOMATIC;
  25. static int gc_debug;
  26. static int gc_alloced;
  27. static int gc_suspended;
  28. static int n_global_vars;
  29. static void ***global_vars;
  30. static int n_alloced;
  31. #ifdef _WIN32
  32. extern void *_bss_start__;
  33. extern void *_bss_end__;
  34. extern void *_data_start__;
  35. extern void *_data_end__;
  36. extern void *_start_data__;
  37. extern void *_stop_data__;
  38. extern void *_end__;
  39. #endif
  40. #ifdef __linux
  41. extern void *__data_start;
  42. extern void *__bss_start;
  43. extern void *_end;
  44. #endif
  45. static void **DATA_START;
  46. static void **DATA_END;
  47. static const char *typeName( void *p ){
  48. BBObject *o=(BBObject*)p;
  49. BBClass *c=o->clas;
  50. BBDebugScope *d=c->debug_scope;
  51. if( d ) return d->name;
  52. return "?";
  53. }
  54. /*
  55. static void *getTIB(){
  56. void *tib;
  57. __asm__( "movl %%fs:0x18,%0":"=r"(tib) );
  58. return tib;
  59. }
  60. static int atomic_add( volatile int *p,int incr ){
  61. int result;
  62. __asm__ __volatile__ ("lock; xaddl %0, %1" :
  63. "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
  64. : "memory");
  65. return result;
  66. }
  67. static int compare_and_swap( volatile int *addr,int old,int new_val ){
  68. char result;
  69. __asm__ __volatile__("lock; cmpxchgl %3, %0; setz %1"
  70. : "=m"(*addr), "=q"(result)
  71. : "m"(*addr), "r" (new_val), "a"(old) : "memory");
  72. return (int) result;
  73. }
  74. */
  75. static void gcError( void *p,const char *msg ){
  76. printf( "GC ERROR: %s, object=$%p\n",msg,p );
  77. fflush( stdout );
  78. bbExThrowCString( msg );
  79. }
  80. static int setMemBit( void *p ){
  81. unsigned page;
  82. unsigned offset;
  83. unsigned 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. }
  95. static void clrMemBit( void *p ){
  96. unsigned page;
  97. unsigned offset;
  98. unsigned mask;
  99. page=(unsigned)p>>(PAGE_BITS+7);
  100. if( !pages[page] ) gcError( p,"clrMemBit error: mempage does not exist" );
  101. offset=((unsigned)p>>9) & PAGE_MASK;
  102. mask=1<<( ((unsigned)p>>4) & 31 );
  103. if( !(pages[page][offset] & mask) ) gcError( p,"clrMemBit error: membit not set" );
  104. pages[page][offset]&=~mask;
  105. }
  106. static int tstMemBit( void *p ){
  107. unsigned page;
  108. unsigned offset;
  109. unsigned mask;
  110. if( (unsigned)p & 15 ) return 0;
  111. page=(unsigned)p>>(PAGE_BITS+7);
  112. if( !pages[page] )return 0;
  113. offset=((unsigned)p>>9) & PAGE_MASK;
  114. mask=1<<( ((unsigned)p>>4) & 31 );
  115. return pages[page][offset] & mask;
  116. }
  117. static void collectMem( int );
  118. static int heap_alloced,heap_size;
  119. static void *heapAlloc( int size ){
  120. void *p,*q;
  121. size+=SIZEALIGN+4;
  122. p=malloc( size );
  123. if( !p ){
  124. bbGCCollect();
  125. p=malloc( size );
  126. if( !p ) return 0;
  127. }
  128. heap_alloced+=size;
  129. if( heap_alloced>heap_size ){
  130. heap_size=heap_alloced;
  131. #ifdef DEBUG_GC
  132. printf( "heap_size=%i\n",heap_size );fflush( stdout );
  133. #endif
  134. }
  135. q=(void*)( ((unsigned)p+ALIGNMASK+4) & ~ALIGNMASK );
  136. *((void**)q-1)=p;
  137. return q;
  138. }
  139. static void heapFree( void *p,int size ){
  140. heap_alloced-=size;
  141. free( *((void**)p-1) );
  142. }
  143. static void *allocMem( int size,int flags ){
  144. size=(size + sizeof(GCBlock) + 15) & ~15;
  145. int i=size/16;
  146. GCBlock *t;
  147. if( i<256 && (t=freeBlocks[i]) ){
  148. freeBlocks[i]=t->succ;
  149. }else{
  150. static int alloced;
  151. if( gc_mode==BBGC_AUTOMATIC && (gc_alloced-alloced)>heap_size/3 ){
  152. collectMem(0);
  153. alloced=gc_alloced;
  154. }
  155. if( i>255 ){
  156. t=heapAlloc( size );
  157. setMemBit( t );
  158. }else if( t=freeBlocks[i] ){
  159. freeBlocks[i]=t->succ;
  160. }else{
  161. if( size>freeBufSize ){
  162. if( freeBufSize ){
  163. int i=freeBufSize/16;
  164. GCBlock *t=freeBuf;
  165. t->flags=BBGC_MARKED;
  166. t->succ=freeBlocks[i];
  167. freeBlocks[i]=t;
  168. setMemBit( t );
  169. }
  170. freeBufSize=65536;
  171. freeBuf=heapAlloc( freeBufSize );
  172. }
  173. t=freeBuf;
  174. freeBuf+=size;
  175. freeBufSize-=size;
  176. setMemBit( t );
  177. }
  178. }
  179. t->succ=usedBlocks;
  180. t->flags=size|flags;
  181. usedBlocks=t;
  182. gc_alloced+=size;
  183. return t->data;
  184. }
  185. static GCBlock *getBlock( void *p ){
  186. GCBlock *q=(GCBlock*)p-1;
  187. if( tstMemBit( q ) ) return q;
  188. return 0;
  189. }
  190. static void freeBlock( GCBlock *t ){
  191. int flags=t->flags;
  192. int size=flags & ~15;
  193. int i=size/16;
  194. if( i>255 ){
  195. clrMemBit( t );
  196. heapFree( t,size );
  197. }else{
  198. t->flags=BBGC_MARKED;
  199. t->succ=freeBlocks[i];
  200. freeBlocks[i]=t;
  201. }
  202. gc_alloced-=size;
  203. }
  204. static void mark( void *p ){
  205. GCBlock *t=getBlock( p );
  206. if( !t ) return;
  207. if( t->flags & BBGC_MARKED ) return;
  208. t->flags|=BBGC_MARKED;
  209. if( t->flags & BBGC_ATOMIC ) return;
  210. int size=t->flags & ~15,i;
  211. for( i=sizeof(GCBlock);i<size;i+=4 ){
  212. void **r=(char*)t+i;
  213. mark( *r );
  214. }
  215. }
  216. static void finalize( GCBlock *t ){
  217. }
  218. void collectMem( int dummy ){
  219. int i;
  220. void **r;
  221. static int recurs;
  222. if( recurs ){
  223. // printf( "RECURSIVE GC!\n" );fflush( stdout );
  224. return;
  225. }
  226. recurs=1;
  227. #ifdef DEBUG_GC
  228. int ms=bbMilliSecs();
  229. #endif
  230. BBThread *thread;
  231. BBThread *curThread=bbThreadGetCurrent();
  232. BBThread *lockedThreads=_bbThreadLockThreads();
  233. for( thread=lockedThreads;thread;thread=thread->succ ){
  234. for( i=0;i<32;++i ){
  235. mark( thread->data[i] );
  236. }
  237. if( thread==curThread ){
  238. void *regs[BBGC_NUM_ROOTREGS];
  239. void **sp=bbGCRootRegs( regs );
  240. for( i=0;i<BBGC_NUM_ROOTREGS;++i ){
  241. mark( regs[i] );
  242. }
  243. for( r=sp;r!=thread->stackTop;++r ){
  244. mark( *r );
  245. }
  246. }else{
  247. for( i=0;i<BB_THREADREGS;++i ){
  248. mark( (void*)thread->locked_regs[i] );
  249. }
  250. for( r=(void**)thread->locked_sp;r!=thread->stackTop;++r ){
  251. mark( *r );
  252. }
  253. }
  254. }
  255. for( i=0;i<n_global_vars;++i ){
  256. mark( *global_vars[i] );
  257. }
  258. #ifdef DEBUG_GC
  259. int mark_ms=bbMilliSecs();
  260. #endif
  261. GCBlock *t;
  262. //mark locked blocks
  263. for( t=usedBlocks;t;t=t->succ ){
  264. if( t->flags & BBGC_LOCKED ) mark( t->data );
  265. }
  266. //resurrect or free finalized blocks
  267. while( t=finalizedBlocks ){
  268. finalizedBlocks=t->succ;
  269. if( t->flags & BBGC_MARKED ){
  270. //resurrect me!
  271. t->succ=usedBlocks;
  272. usedBlocks=t;
  273. if( t->flags & BBGC_FINALIZE ){
  274. t->flags&=~BBGC_FINALIZE;
  275. #ifdef DEBUG_GC
  276. BBObject *q=(BBObject*)t->data;
  277. printf( "GC resurrected:%s @%p\n",typeName( q ),q );fflush( stdout );
  278. #endif
  279. }
  280. }else{
  281. freeBlock( t );
  282. }
  283. }
  284. GCBlock **p=&usedBlocks;
  285. int n_finalized=0;
  286. while( t=*p ){
  287. if( t->flags & BBGC_MARKED ){
  288. p=&t->succ;
  289. t->flags&=~BBGC_MARKED;
  290. }else{
  291. *p=t->succ;
  292. if( t->flags & BBGC_FINALIZE ){
  293. ++n_finalized;
  294. BBObject *q=(BBObject*)t->data;
  295. // printf( "GC finalizing:%s\n",typeName( q ) );fflush( stdout );
  296. BBClass *c=q->clas;
  297. c->free( q );
  298. q->clas=c;
  299. }
  300. t->succ=finalizedBlocks;
  301. finalizedBlocks=t;
  302. }
  303. }
  304. if( !n_finalized ){
  305. //
  306. //No finalizers were run, so it's OK to free blocks NOW.
  307. //
  308. while( t=finalizedBlocks ){
  309. finalizedBlocks=t->succ;
  310. freeBlock( t );
  311. }
  312. }
  313. _bbThreadUnlockThreads();
  314. #ifdef DEBUG_GC
  315. int end_ms=bbMilliSecs();
  316. printf( "gc ms=%i, marked=%i, marked_ms=%i, freed=%i, freed_ms=%i\n",end_ms-ms,n_marked,mark_ms-ms,n_freed,end_ms-mark_ms );fflush( stdout );
  317. #endif
  318. recurs=0;
  319. }
  320. //***** GC Interface *****//
  321. static int isGlobalVar( int *p ){
  322. if( p==&bbNullObject ) return 1;
  323. if( p==&bbEmptyString ) return 1;
  324. if( p==&bbEmptyArray ) return 1;
  325. if( ( p>=DATA_START && p<DATA_END-1 ) &&
  326. ( *(void**)p==&bbStringClass ) &&
  327. ( *(int**)(p+1)==0x7fffffff ) ) return 1;
  328. return 0;
  329. }
  330. void bbGCStartup(){
  331. #ifdef _WIN32
  332. /*
  333. printf( "_bss_start__=%p\n",&_bss_start__ );
  334. printf( "_bss_end__=%p\n",&_bss_end__ );
  335. printf( "_data_start__=%p\n",&_data_start__ );
  336. printf( "_data_end__=%p\n",&_data_end__ );
  337. printf( "_end__=%p\n",&_end__ );
  338. fflush( stdout );
  339. */
  340. DATA_START=&_data_start__;
  341. DATA_END=&_bss_end__;
  342. #endif
  343. #ifdef __APPLE__
  344. int *seg=getsegbyname( "__DATA" );
  345. DATA_START=(void**)seg[6];
  346. DATA_END=(void**)(seg[6]+seg[7]);
  347. #endif
  348. #ifdef __linux
  349. DATA_START=&__data_start;
  350. DATA_END=&_end;
  351. #endif
  352. #ifdef DEBUG_GC
  353. printf( "DATA_START=%p, DATA_END=%p\n",DATA_START,DATA_END );fflush( stdout );
  354. #endif
  355. void **r;
  356. n_global_vars=0;
  357. for( r=DATA_START;r!=DATA_END;++r ){
  358. void *p=*r;
  359. if( isGlobalVar( p ) ){
  360. ++n_global_vars;
  361. }
  362. }
  363. #ifdef DEBUG_GC
  364. printf( "Found %i global vars\n",n_global_vars );fflush( stdout );
  365. #endif
  366. global_vars=(void***)malloc( n_global_vars*4 );
  367. int i=0;
  368. for( r=DATA_START;r!=DATA_END;++r ){
  369. void *p=*r;
  370. if( isGlobalVar( p ) ){
  371. global_vars[i++]=r;
  372. }
  373. }
  374. }
  375. void bbGCSetMode( int mode ){
  376. gc_mode=mode;
  377. }
  378. void bbGCSetDebug( int debug ){
  379. gc_debug=debug;
  380. }
  381. void *bbGCMalloc( int size,int flags ){
  382. if( size<=0 ) return 0;
  383. void *p;
  384. BB_LOCK
  385. p=allocMem( size,flags & BBGC_ATOMIC );
  386. BB_UNLOCK
  387. return p;
  388. }
  389. BBObject *bbGCAllocObject( int size,BBClass *clas,int flags ){
  390. BBObject *q;
  391. BB_LOCK
  392. q=(BBObject*)allocMem( size,flags );
  393. q->clas=clas;
  394. q->refs=0;
  395. BB_UNLOCK
  396. // if( clas!=&bbStringClass ){
  397. // printf( "%s = %p\n",typeName(q),q );fflush( stdout );
  398. // }
  399. return q;
  400. }
  401. int bbGCValidate( void *p ){
  402. int r;
  403. BB_LOCK
  404. r=getBlock( p ) ? 1 : 0;
  405. BB_UNLOCK
  406. return r;
  407. }
  408. int bbGCMemAlloced(){
  409. return gc_alloced;
  410. }
  411. int bbGCCollect(){
  412. int t;
  413. if( gc_suspended ) return 0;
  414. BB_LOCK
  415. t=gc_alloced;
  416. collectMem( 0 );
  417. t-=gc_alloced;
  418. BB_UNLOCK
  419. return t;
  420. }
  421. void bbGCSuspend(){
  422. BB_LOCK
  423. ++gc_suspended;
  424. BB_UNLOCK
  425. }
  426. void bbGCResume(){
  427. BB_LOCK
  428. --gc_suspended;
  429. BB_UNLOCK
  430. }
  431. void bbGCRetain( BBObject *p ){
  432. BB_LOCK
  433. GCBlock *t=getBlock( p );
  434. if( t ){
  435. if( !p->refs++ ) t->flags|=BBGC_LOCKED;
  436. }
  437. BB_UNLOCK
  438. }
  439. void bbGCRelease( BBObject *p ){
  440. BB_LOCK
  441. GCBlock *t=getBlock( p );
  442. if( t ){
  443. if( !--p->refs ) t->flags&=~BBGC_LOCKED;
  444. }
  445. BB_UNLOCK
  446. }
  447. #endif