gc.cpp 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784
  1. //#define BF_GC_DISABLED
  2. //#define BF_GC_LOG_ENABLED
  3. #define _WIN32_WINNT _WIN32_WINNT_WIN8
  4. // This spits out interesting stats periodically to the console
  5. #define BF_GC_PRINTSTATS
  6. //TEMPORARY
  7. //#define BF_GC_DEBUGSWEEP
  8. //#define BF_GC_EMPTYSCAN
  9. // Disable efficient new mass-freeing in TCMalloc
  10. //#define BF_GC_USE_OLD_FREE
  11. #ifdef BF_DEBUG
  12. // Useful for tracing down memory corruption -- memory isn't returned to TCMalloc, it's just marked as freed. You'll run out eventually
  13. //#define BF_NO_FREE_MEMORY
  14. // Old and not too useful
  15. //#define BG_GC_TRACKPTRS
  16. #endif
  17. #if defined BF_OBJECT_TRACK_ALLOCNUM && defined BF_NO_FREE_MEMORY
  18. //#define BF_GC_VERIFY_SWEEP_IDS
  19. #endif
  20. //#define BF_SECTION_NURSERY
  21. #ifdef BF_PLATFORM_WINDOWS
  22. #include <direct.h>
  23. #endif
  24. #include "gc.h"
  25. #ifdef BF_GC_SUPPORTED
  26. #include <fstream>
  27. #include "BeefySysLib/Common.h"
  28. #include "BeefySysLib/BFApp.h"
  29. #include "BeefySysLib/util/CritSect.h"
  30. #include "BeefySysLib/util/BeefPerf.h"
  31. #include "BeefySysLib/util/HashSet.h"
  32. #include "BeefySysLib/util/Dictionary.h"
  33. #include <unordered_set>
  34. #include "../rt/BfObjects.h"
  35. #include "../rt/Thread.h"
  36. #ifdef BF_PLATFORM_WINDOWS
  37. #include <psapi.h>
  38. #endif
  39. #ifndef BF_TCMALLOC_DISABLED
  40. #define TCMALLOC_NO_MALLOCGUARD
  41. #define TCMALLOC_NAMESPACE tcmalloc_obj
  42. #define TCMALLOC_EXTERN static
  43. #include "gperftools/src/tcmalloc.cc"
  44. #else
  45. #define tc_malloc malloc
  46. #define tc_free free
  47. #endif
  48. USING_NS_BF;
  49. //System::Threading::Thread* gMainThread;
  50. #include "BeefySysLib/util/PerfTimer.h"
  51. /*#include "BeefyRtCPP/MonitorManager.h"
  52. #include "BeefyRtCPP/InternalThread.h"
  53. #include "BeefyRtCPP/ReflectionData.h"
  54. #include "BeefyRtCPP/RtCommon_inl.h"
  55. #include "BeefyRtCPP/BFArray.h"
  56. #include "BeefyRtCPP/Reflection.h"*/
  57. extern "C" GCDbgData gGCDbgData = { 0 };
  58. void BfLog(const char* fmt ...)
  59. {
  60. static int lineNum = 0;
  61. lineNum++;
  62. static FILE* fp = fopen("dbg_bf.txt", "wb");
  63. va_list argList;
  64. va_start(argList, fmt);
  65. String aResult = vformat(fmt, argList);
  66. va_end(argList);
  67. aResult = StrFormat("%d ", lineNum) + aResult;
  68. fwrite(aResult.c_str(), 1, aResult.length(), fp);
  69. fflush(fp);
  70. }
  71. //////////////////////////////////////////////////////////////////////////
  72. using Beefy::CritSect;
  73. BF_TLS_DECLSPEC BFGC::ThreadInfo* BFGC::ThreadInfo::sCurThreadInfo;
  74. HANDLE gGCHeap = 0;
  75. #ifdef _DEBUG
  76. bool gGCGetAllocStats = true;
  77. #else
  78. bool gGCGetAllocStats = false;
  79. #endif
  80. #ifdef BF_GC_VERIFY_SWEEP_IDS
  81. static std::set<int> allocIdSet;
  82. static int maxAllocNum = 0;
  83. #endif
  84. int gGCAllocCount = 0;
  85. int gGCAllocBytes = 0;
  86. std::vector<int> gGCAllocCountMap;
  87. std::vector<int> gGCAllocSizeMap;
  88. struct TCMallocRecord
  89. {
  90. void* mPtr;
  91. int mSize;
  92. };
  93. static std::vector<TCMallocRecord> gTCMallocRecords;
  94. void TCMalloc_RecordAlloc(void* ptr, int size)
  95. {
  96. TCMallocRecord mallocRecord = { ptr, size };
  97. gTCMallocRecords.push_back(mallocRecord);
  98. }
  99. static void TCMalloc_FreeAllocs()
  100. {
  101. for (auto& record : gTCMallocRecords)
  102. {
  103. ::VirtualFree(record.mPtr, 0, MEM_RELEASE);
  104. }
  105. gTCMallocRecords.clear();
  106. }
  107. void PatchWindowsFunctions()
  108. {
  109. // For TCMalloc, don't really patch
  110. }
  111. #ifdef BG_GC_TRACKPTRS
  112. boost::unordered_set<void*> gTrackPtr;
  113. #endif
  114. void BFMarkThreadPoolJobs()
  115. {
  116. }
  117. #ifndef BF_MONOTOUCH
  118. void BFMarkCOMObjects()
  119. {
  120. }
  121. void BFIMarkStackData(BFIThreadData* bfiThreadData)
  122. {
  123. }
  124. #endif
  125. /*void* sDbgPtr0 = NULL;
  126. void* sDbgPtr1 = NULL;
  127. void* sDbgPtr2 = NULL;*/
  128. void BFGC::MarkMembers(bf::System::Object* obj)
  129. {
  130. //BP_ZONE("MarkMembers");
  131. /*if ((obj == sDbgPtr0) || (obj == sDbgPtr1) || (obj == sDbgPtr2))
  132. {
  133. int a = 0;
  134. }*/
  135. if (((obj->mObjectFlags & BF_OBJECTFLAG_DELETED) != 0) && (!mMarkingDeleted))
  136. {
  137. mMarkingDeleted = true;
  138. gBfRtDbgCallbacks.Object_GCMarkMembers(obj);
  139. mMarkingDeleted = false;
  140. }
  141. else
  142. {
  143. gBfRtDbgCallbacks.Object_GCMarkMembers(obj);
  144. }
  145. }
  146. static void MarkObject(bf::System::Object* obj)
  147. {
  148. if ((obj != NULL) && ((obj->mObjectFlags & (BF_OBJECTFLAG_MARK_ID_MASK)) != BFGC::sCurMarkId))
  149. gBFGC.MarkFromGCThread(obj);
  150. }
  151. //////////////////////////////////////////////////////////////////////////
  152. //AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures;
  153. namespace tcmalloc
  154. {
  155. extern "C" int RunningOnValgrind(void)
  156. {
  157. return 0;
  158. }
  159. }
  160. ////////////////////////////////////////////
  161. BFGC::ThreadInfo::~ThreadInfo()
  162. {
  163. if (mThreadHandle != NULL)
  164. BfpThread_Release(mThreadHandle);
  165. }
  166. //////////////////////////////////////////////////////////////////////////
  167. #ifdef BF_GC_LOG_ENABLED
  168. class GCLog
  169. {
  170. public:
  171. enum
  172. {
  173. EVENT_ALLOC,
  174. EVENT_GC_START, // cycle#
  175. EVENT_GC_UNFREEZE, // cycle#
  176. EVENT_MARK,
  177. EVENT_WB_MARK,
  178. EVENT_THREAD_STARTED,
  179. EVENT_THREAD_DONE,
  180. EVENT_SCAN_THREAD,
  181. EVENT_CONSERVATIVE_SCAN,
  182. EVENT_FOUND_TARGET,
  183. EVENT_FINALIZE_LIST,
  184. EVENT_LEAK,
  185. EVENT_DELETE,
  186. EVENT_FREE,
  187. EVENT_WB_MOVE,
  188. EVENT_WEAK_REF,
  189. EVENT_STRONG_REF,
  190. EVENT_WEAKREF_MARKED,
  191. EVENT_WEAK,
  192. EVENT_RESURRECT,
  193. EVENT_WAS_RESURRECT,
  194. EVENT_GC_DONE
  195. };
  196. class Entry
  197. {
  198. public:
  199. int mEvent;
  200. intptr mParam1;
  201. intptr mParam2;
  202. intptr mParam3;
  203. };
  204. Beefy::CritSect mCritSect;
  205. static const int BUFFSIZE = 1024*1024;
  206. static const int BUFFSIZE_MASK = BUFFSIZE-1;
  207. Entry mBuffer[BUFFSIZE];
  208. volatile int mHead;
  209. volatile int mTail;
  210. volatile bool mWriting;
  211. public:
  212. GCLog()
  213. {
  214. mWriting = false;
  215. }
  216. void Log(int event, intptr param1 = 0, intptr param2 = 0, intptr param3 = 0)
  217. {
  218. if (mWriting)
  219. {
  220. // Not a strict guarantee, but should keep us from only messing up
  221. // more than a single element of the log while we're writing it
  222. Beefy::AutoCrit autoCrit(mCritSect);
  223. return;
  224. }
  225. BF_FULL_MEMORY_FENCE();
  226. Entry entry = {event, param1, param2, param3};
  227. int prevHead;
  228. int nextHead;
  229. while (true)
  230. {
  231. prevHead = mHead;
  232. nextHead = (mHead + 1) & BUFFSIZE_MASK;
  233. if (nextHead == mTail)
  234. {
  235. int prevTail = mTail;
  236. int nextTail = (mTail + 1) & BUFFSIZE_MASK;
  237. if (::InterlockedCompareExchange((uint32*)&mTail, nextTail, prevTail) != prevTail)
  238. continue; // Try again
  239. }
  240. if (::InterlockedCompareExchange((uint32*)&mHead, nextHead, prevHead) == prevHead)
  241. break;
  242. }
  243. mBuffer[prevHead] = entry;
  244. }
  245. const char* GetNameStr(bf::System::Type* type)
  246. {
  247. static Beefy::String str;
  248. if (type == NULL)
  249. return "NULL";
  250. try
  251. {
  252. bf::System::Type* bfTypeRoot = (bf::System::Type*)type;
  253. str = type->GetFullName();
  254. return str.c_str();
  255. }
  256. catch (...)
  257. {
  258. return "<invalid>";
  259. }
  260. }
  261. #pragma warning(disable:4477)
  262. void Write()
  263. {
  264. Beefy::AutoCrit autoCrit(mCritSect);
  265. wchar_t str[MAX_PATH];
  266. GetCurrentDirectoryW(MAX_PATH, str);
  267. FILE* fp = fopen("c:\\temp\\gclog.txt", "w");
  268. mWriting = true;
  269. int sampleHead = mHead;
  270. BF_FULL_MEMORY_FENCE();
  271. int sampleTail = mTail;
  272. BF_FULL_MEMORY_FENCE();
  273. int pos = sampleTail;
  274. while (pos != sampleHead)
  275. {
  276. Entry ent = mBuffer[pos];
  277. switch (ent.mEvent)
  278. {
  279. case EVENT_ALLOC:
  280. fprintf(fp, "Alloc:%p Type:%s\n", ent.mParam1, GetNameStr((bf::System::Type*)ent.mParam2));
  281. break;
  282. case EVENT_GC_START:
  283. fprintf(fp, "GCStart MarkId:%d Tick:%d\n", ent.mParam1, ent.mParam2);
  284. break;
  285. case EVENT_GC_UNFREEZE:
  286. fprintf(fp, "GCUnfreeze MarkId:%d Tick:%d\n", ent.mParam1, ent.mParam2);
  287. break;
  288. case EVENT_MARK:
  289. fprintf(fp, "GCMark Obj:%p Flags:%X Parent:%p\n", ent.mParam1, ent.mParam2, ent.mParam3);
  290. break;
  291. case EVENT_WB_MARK:
  292. fprintf(fp, "WriteBarrierMark Obj:%p Type:%s Thread:%p\n", ent.mParam1, GetNameStr((bf::System::Type*)ent.mParam2), ent.mParam3);
  293. break;
  294. case EVENT_WB_MOVE:
  295. fprintf(fp, "WriteBarrier Entry Move Obj:%p Type:%s Thread:%p\n", ent.mParam1, GetNameStr((bf::System::Type*) ent.mParam2), ent.mParam3);
  296. break;
  297. case EVENT_FOUND_TARGET:
  298. fprintf(fp, "Heap Scan Found Target:%p Type:%s Flags:%d\n", ent.mParam1, GetNameStr((bf::System::Type*)ent.mParam2), ent.mParam3);
  299. break;
  300. case EVENT_FINALIZE_LIST:
  301. fprintf(fp, "On Finalize List:%p\n", ent.mParam1);
  302. break;
  303. case EVENT_LEAK:
  304. fprintf(fp, "Leak Detected:%p Type:%s\n", ent.mParam1, GetNameStr((bf::System::Type*)ent.mParam2));
  305. break;
  306. case EVENT_FREE:
  307. fprintf(fp, "Free Obj:%p\n", ent.mParam1);
  308. break;
  309. case EVENT_DELETE:
  310. fprintf(fp, "Delete Obj:%p\n", ent.mParam1);
  311. break;
  312. case EVENT_THREAD_STARTED:
  313. fprintf(fp, "ThreadStarted:%p TID:%d\n", ent.mParam1, ent.mParam2);
  314. break;
  315. case EVENT_THREAD_DONE:
  316. fprintf(fp, "ThreadDone:%p\n", ent.mParam1);
  317. break;
  318. case EVENT_SCAN_THREAD:
  319. fprintf(fp, "ScanThread:%p Id:%d\n", ent.mParam1, ent.mParam2);
  320. break;
  321. case EVENT_CONSERVATIVE_SCAN:
  322. fprintf(fp, "ConservativeScan:%p to %p\n", ent.mParam1, ent.mParam2);
  323. break;
  324. case EVENT_GC_DONE:
  325. fprintf(fp, "GCDone\n");
  326. break;
  327. default:
  328. BF_FATAL("Unknown event");
  329. break;
  330. }
  331. pos = (pos + 1) & BUFFSIZE_MASK;
  332. }
  333. fclose(fp);
  334. mWriting = false;
  335. }
  336. };
  337. GCLog gGCLog;
  338. void BFGCLogWrite()
  339. {
  340. gGCLog.Write();
  341. }
  342. #define BFLOG(cmd) gGCLog.Log(cmd)
  343. #define BFLOG1(cmd, param1) gGCLog.Log(cmd, param1)
  344. #define BFLOG2(cmd, param1, param2) gGCLog.Log(cmd, param1, param2)
  345. #define BFLOG3(cmd, param1, param2, param3) gGCLog.Log(cmd, param1, param2, param3)
  346. #else
  347. #define BFLOG(cmd)
  348. #define BFLOG1(cmd, param1)
  349. #define BFLOG2(cmd, param1, param2)
  350. #define BFLOG3(cmd, param1, param2, param3)
  351. void BFGCLogWrite() {}
  352. #endif
  353. void BFGCLogAlloc(bf::System::Object* obj, bf::System::Type* objType, int allocNum)
  354. {
  355. BFLOG3(GCLog::EVENT_ALLOC, (intptr)obj, (intptr)objType, allocNum);
  356. }
  357. BfDbgInternalThread* GetCurrentInternalThread()
  358. {
  359. return NULL;
  360. }
  361. ////////////////////////////////////////////
  362. static void CheckTcIntegrity()
  363. {
  364. auto pageHeap = Static::pageheap();
  365. if (pageHeap == NULL)
  366. return;
  367. #ifdef BF64
  368. //BP_ZONE("CheckTcIntegrity");
  369. Beefy::HashSet<tcmalloc_obj::Span*> spanSet;
  370. int interiorLen = PageHeap::PageMap::INTERIOR_LENGTH;
  371. int leafLen = PageHeap::PageMap::LEAF_LENGTH;
  372. for (int pageIdx1 = 0; pageIdx1 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx1++)
  373. {
  374. PageHeap::PageMap::Node* node1 = Static::pageheap()->pagemap_.root_->ptrs[pageIdx1];
  375. if (node1 == NULL)
  376. continue;
  377. for (int pageIdx2 = 0; pageIdx2 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx2++)
  378. {
  379. PageHeap::PageMap::Node* node2 = node1->ptrs[pageIdx2];
  380. if (node2 == NULL)
  381. continue;
  382. for (int pageIdx3 = 0; pageIdx3 < PageHeap::PageMap::LEAF_LENGTH; pageIdx3++)
  383. {
  384. tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)node2->ptrs[pageIdx3];
  385. if (span != NULL)
  386. {
  387. int expectedStartPage = ((pageIdx1 * PageHeap::PageMap::INTERIOR_LENGTH) + pageIdx2) * PageHeap::PageMap::LEAF_LENGTH + pageIdx3;
  388. if (span->start == expectedStartPage)
  389. {
  390. auto result = spanSet.Add(span);
  391. BF_ASSERT(result);
  392. }
  393. }
  394. }
  395. }
  396. }
  397. int spansFound = spanSet.size();
  398. #endif
  399. }
  400. ////////////////////////////////////////////
  401. void BFCheckSuspended()
  402. {
  403. BfInternalThread* internalThread = (BfInternalThread*)GetCurrentInternalThread();
  404. if ((internalThread != NULL) && (internalThread->mIsSuspended))
  405. {
  406. internalThread = (BfInternalThread*)GetCurrentInternalThread();
  407. printf("IsSuspended\n");
  408. }
  409. BF_ASSERT((internalThread == NULL) || (!internalThread->mIsSuspended));
  410. }
  411. void* BfObjectAllocate(intptr size, bf::System::Type* objType)
  412. {
  413. bf::System::Object* obj = (bf::System::Object*)tc_malloc(size);
  414. BFLOG2(GCLog::EVENT_ALLOC, (intptr)obj, (intptr)objType);
  415. //CheckTcIntegrity();
  416. gBFGC.mBytesRequested += size;
  417. // #ifdef BF_GC_PRINTSTATS
  418. // ::InterlockedIncrement((volatile uint32*)&gBFGC.mTotalAllocs);
  419. // #endif
  420. #ifdef BG_GC_TRACKPTRS
  421. {
  422. Beefy::AutoCrit autoCrit(gBFGC.mCritSect);
  423. BF_LOGASSERT(gTrackPtr.find(obj) == gTrackPtr.end());
  424. gTrackPtr.insert(obj);
  425. }
  426. #endif
  427. #ifdef _DEBUG
  428. BF_LOGASSERT((obj->mAllocCheckPtr == 0) || (size > kMaxSize));
  429. #endif
  430. //memset((void*)obj, 0, size);
  431. #ifdef BF_OBJECT_TRACK_ALLOCNUM
  432. obj->mAllocNum = (int)::InterlockedIncrement((volatile uint32*) &BfObject::sCurAllocNum);
  433. #endif
  434. #ifdef BF_SECTION_NURSERY
  435. BfInternalThread* internalThread = (BfInternalThread*)bf::System::Threading::Thread::CurrentInternalThread_internal();
  436. if ((internalThread != NULL) && (internalThread->mSectionDepth == 1))
  437. internalThread->mSectionNursery.PushUnsafe(obj);
  438. #endif
  439. gBFGC.mAllocSinceLastGC += size;
  440. /*if ((uint32)gBFGC.mAllocSinceLastGC > (uint32)gBFGC.mAllocGCTrigger)
  441. gBFGC.TriggerCollection();*/
  442. //BfLog("AllocId %d ptr: %p Thread:%d\n", gBFGC.mTotalAllocs, obj, GetCurrentThreadId());
  443. //gBFGC.TriggerCollection(true);
  444. return obj;
  445. }
  446. //////////////////////////////////////////////////////////////////////////
  447. #define BF_GC_MAX_PENDING_OBJECT_COUNT 16*1024
  448. ///
  449. ///
  450. class BFFinalizeData
  451. {
  452. public:
  453. int mFinalizeCount;
  454. bool mInFinalizeList;
  455. public:
  456. BFFinalizeData()
  457. {
  458. mFinalizeCount = 1;
  459. mInFinalizeList = false;
  460. }
  461. };
  462. ///
  463. BFGC gBFGC;
  464. int volatile BFGC::sCurMarkId = 1;
  465. int volatile BFGC::sAllocFlags = 1;
  466. int gBFCRTAllocSize = 0;
  467. BFGC::BFGC()
  468. {
  469. mRunning = false;
  470. mExiting = false;
  471. mPaused = false;
  472. mShutdown = false;
  473. mForceDecommit = false;
  474. mLastCollectFrame = 0;
  475. mSkipMark = false;
  476. mGracelessShutdown = false;
  477. mMainThreadTLSPtr = NULL;
  478. mCollectIdx = 0;
  479. mStackScanIdx = 0;
  480. mMarkDepthCount = 0;
  481. mMarkingDeleted = false;
  482. mCurMutatorMarkCount = 0;
  483. mCurGCMarkCount = 0;
  484. mCurFreedBytes = 0;
  485. sCurMarkId = 1;
  486. mQueueMarkObjects = false;
  487. //mEphemeronTombstone = NULL;
  488. mWaitingForGC = false;
  489. mCollectRequested = false;
  490. mAllocSinceLastGC = 0;
  491. mFullGCTriggered = false;
  492. mDebugDumpState = 0;
  493. mCurScanIdx = 1;
  494. mTotalAllocs = 0;
  495. mTotalFrees = 0;
  496. mLastFreeCount = 0;
  497. mBytesFreed = 0;
  498. mBytesRequested = 0;
  499. mRequestedSizesInvalid = false;
  500. mDisplayFreedObjects = false;
  501. mHadRootError = false;
  502. mCurLiveObjectCount = 0;
  503. mFreeSinceLastGC = 0;
  504. // Default to just over two 60Hz frames
  505. // This keeps stack scanning from adding excessive costs to a 30Hz app, or
  506. // from impacting two successive frames in a triple-buffered 60Hz app where
  507. // only one slow frame could be absorbed
  508. mMultiStackScanWait = 35;
  509. // By default we collect after freeing 64MB
  510. mFreeTrigger = 64*1024*1024;
  511. mMaxPausePercentage = 20;
  512. mMaxRawDeferredObjectFreePercentage = 30;
  513. // Zero means to run continuously. -1 means don't trigger on a time base
  514. // Defaults to collecting every 2 seconds
  515. mFullGCPeriod = 2000;
  516. mGCThread = NULL;
  517. gGCDbgData.mDbgFlags = gBfRtDbgFlags;
  518. ThreadCache::InitTSD();
  519. if (UNLIKELY(Static::pageheap() == NULL)) ThreadCache::InitModule();
  520. gGCDbgData.mObjRootPtr = Static::pageheap()->pagemap_.root_;
  521. for (int i = 0; i < kNumClasses; i++)
  522. gGCDbgData.mSizeClasses[i] = Static::sizemap()->ByteSizeForClass(i);
  523. RawInit();
  524. }
  525. BFGC::~BFGC()
  526. {
  527. //::HeapDestroy(gGCHeap);
  528. //gGCHeap = NULL;
  529. Beefy::AutoCrit autoCrit(mCritSect);
  530. for (auto thread : mThreadList)
  531. {
  532. delete thread;
  533. }
  534. }
  535. /*inline T BFWB(typename BFToType<T>::type::BFBaseObjectInObject obj)
  536. {
  537. if ((obj != NULL) && ((obj->mBFMonitorPtrAndObjFlags & (BF_OBJECTFLAG_MARK_ID_MASK)) != BFGC::sCurMarkId))
  538. gBFGC.MarkFromMutator(obj, 0);
  539. return (T) obj;
  540. }*/
  541. /*void BFGC::RegisterRoot(bf::System::Object* obj)
  542. {
  543. Beefy::AutoCrit autoCrit(mCritSect);
  544. mExplicitRoots.push_back(obj);
  545. if (mRunning)
  546. BFWB(obj);
  547. }*/
  548. #ifdef BF32
  549. static tcmalloc_obj::Span* TCGetSpanAt(void* addr)
  550. {
  551. int checkPageId = (int)((uintptr)addr >> kPageShift);
  552. int checkRootIdx = checkPageId >> PageHeap::PageMap::LEAF_BITS;
  553. int checkLeafIdx = checkPageId & (PageHeap::PageMap::LEAF_LENGTH - 1);
  554. PageHeap::PageMap::Leaf* rootLeaf = Static::pageheap()->pagemap_.root_[checkRootIdx];
  555. if (rootLeaf == NULL)
  556. return NULL;
  557. auto span = (tcmalloc_obj::Span*)rootLeaf->values[checkLeafIdx];
  558. intptr pageSize = (intptr)1 << kPageShift;
  559. int spanSize = pageSize * span->length;
  560. void* spanStart = (void*)((intptr)span->start << kPageShift);
  561. void* spanEnd = (void*)((intptr)spanStart + spanSize);
  562. if ((addr >= spanStart) && (addr < spanEnd))
  563. return span;
  564. return span;
  565. }
  566. #else
  567. static tcmalloc_obj::Span* TCGetSpanAt(void* addr)
  568. {
  569. int64 checkPageId = (int64)((uintptr)addr >> kPageShift);
  570. int pageIdx1 = (int)(checkPageId >> (PageHeap::PageMap::LEAF_BITS + PageHeap::PageMap::INTERIOR_BITS));
  571. int pageIdx2 = (int)((checkPageId >> PageHeap::PageMap::LEAF_BITS) & (PageHeap::PageMap::INTERIOR_LENGTH-1));
  572. int pageIdx3 = (int)(checkPageId & (PageHeap::PageMap::LEAF_LENGTH-1));
  573. PageHeap::PageMap::Node* node1 = Static::pageheap()->pagemap_.root_->ptrs[pageIdx1];
  574. if (node1 == NULL)
  575. return NULL;
  576. PageHeap::PageMap::Node* node2 = node1->ptrs[pageIdx2];
  577. if (node2 == NULL)
  578. return NULL;
  579. auto span = (tcmalloc_obj::Span*)node2->ptrs[pageIdx3];
  580. return span;
  581. // if (span == NULL)
  582. // return NULL;
  583. // intptr pageSize = (intptr)1 << kPageShift;
  584. // int spanSize = pageSize * span->length;
  585. // void* spanStart = (void*)((intptr)span->start << kPageShift);
  586. // void* spanEnd = (void*)((intptr)spanStart + spanSize);
  587. // if ((addr >= spanStart) && (addr < spanEnd))
  588. // return span;
  589. // return NULL;
  590. }
  591. #endif
  592. int gTargetFoundCount = 0;
  593. int gMarkTargetCount = 0;
  594. int gMarkTargetMutatorCount = 0;
  595. int BFGetObjectSize(bf::System::Object* obj)
  596. {
  597. // auto span = TCGetSpanAt(obj);
  598. // int elementSize = Static::sizemap()->ByteSizeForClass(span->sizeclass);
  599. // if (elementSize != 0)
  600. // return elementSize;
  601. // intptr pageSize = (intptr)1 << kPageShift;
  602. // int spanSize = pageSize * span->length;
  603. // return spanSize;
  604. const PageID p = reinterpret_cast<uintptr_t>(obj) >> kPageShift;
  605. size_t cl = Static::pageheap()->GetSizeClassIfCached(p);
  606. int allocSize = 0;
  607. if (cl == 0)
  608. {
  609. auto span = Static::pageheap()->GetDescriptor(p);
  610. if (span != NULL)
  611. {
  612. cl = span->sizeclass;
  613. if (cl == 0)
  614. {
  615. allocSize = span->length << kPageShift;
  616. }
  617. }
  618. }
  619. if (cl != 0)
  620. allocSize = Static::sizemap()->class_to_size(cl);
  621. return allocSize;
  622. }
  623. void BFCheckObjectSize(bf::System::Object* obj, int size)
  624. {
  625. if (gBFGC.mRunning)
  626. {
  627. BF_ASSERT(BFGetObjectSize(obj) == size);
  628. }
  629. }
  630. void BFGC::ConservativeScan(void* startAddr, int length)
  631. {
  632. if ((gBfRtDbgFlags & BfRtFlags_ObjectHasDebugFlags) == 0)
  633. return;
  634. BFLOG2(GCLog::EVENT_CONSERVATIVE_SCAN, (intptr)startAddr, (intptr)startAddr + length);
  635. void* ptr = (void*)((intptr)startAddr & ~((sizeof(intptr)-1)));
  636. void* endAddr = (uint8*)startAddr + length;
  637. while (ptr < endAddr)
  638. {
  639. void* addr = *(void**)ptr;
  640. MarkFromGCThread((bf::System::Object*)addr);
  641. ptr = (uint8*)ptr + sizeof(intptr);
  642. }
  643. }
  644. static tcmalloc_obj::Span* gLastSpan = NULL;
  645. bool BFGC::IsHeapObject(bf::System::Object* obj)
  646. {
  647. //BP_ZONE("IsHeapObject");
  648. if ((obj >= tcmalloc_obj::PageHeap::sAddressStart) && (obj < tcmalloc_obj::PageHeap::sAddressEnd))
  649. {
  650. tcmalloc_obj::Span* span = TCGetSpanAt(obj);
  651. gLastSpan = span;
  652. return span != NULL;
  653. }
  654. return false;
  655. }
  656. /*void BFGC::MarkTypeStatics(BFTypeRoot* checkType)
  657. {
  658. BFTypeRoot* innerCheckType = (BFTypeRoot*)checkType->mFirstNestedType;
  659. while (innerCheckType != NULL)
  660. {
  661. MarkTypeStatics(innerCheckType);
  662. innerCheckType = (BFTypeRoot*)innerCheckType->mNextSibling;
  663. }
  664. if (checkType->mTypeRootData->mTypeFlags & BF_TYPEFLAG_GENERIC_DEF_TYPE)
  665. return;
  666. if (checkType->mTypeRootData->mBFMarkStatics != NULL)
  667. checkType->mTypeRootData->mBFMarkStatics();
  668. }
  669. void BFGC::MarkStatics()
  670. {
  671. BFMark(bf::System::Object::sTypeLockObject);
  672. BFAppDomain* bfDomain = BFAppDomain::GetAppDomain();
  673. for (int assemblyIdx = 0; assemblyIdx < (int) bfDomain->mBFAssemblyVector.size(); assemblyIdx++)
  674. {
  675. BFAssembly* assembly = bfDomain->mBFAssemblyVector[assemblyIdx];
  676. BFTypeRoot* outerCheckType = (BFTypeRoot*)assembly->mFirstType;
  677. while (outerCheckType != NULL)
  678. {
  679. MarkTypeStatics(outerCheckType);
  680. outerCheckType = (BFTypeRoot*)outerCheckType->mNextSibling;
  681. }
  682. }
  683. BFType::BFMarkStatics();
  684. }*/
  685. void BFGC::MarkStatics()
  686. {
  687. bf::System::GC::DoMarkAllStaticMembers();
  688. //MarkObject(gMainThread);
  689. }
  690. void BFGC::ObjectDeleteRequested(bf::System::Object* obj)
  691. {
  692. if (mFreeTrigger >= 0)
  693. {
  694. int objSize = BFGetObjectSize(obj);
  695. if (BfpSystem_InterlockedExchangeAdd32((uint32*)&mFreeSinceLastGC, (uint32)objSize) + objSize >= mFreeTrigger)
  696. {
  697. mFreeSinceLastGC = 0;
  698. Collect(true);
  699. }
  700. BFLOG1(GCLog::EVENT_DELETE, (intptr)obj);
  701. }
  702. }
  703. bool BFGC::HandlePendingGCData(Beefy::Array<bf::System::Object*>* pendingGCData)
  704. {
  705. int count = 0;
  706. while (!pendingGCData->IsEmpty())
  707. {
  708. bf::System::Object* obj = pendingGCData->back();
  709. pendingGCData->pop_back();
  710. MarkMembers(obj);
  711. count++;
  712. }
  713. return count > 0;
  714. }
  715. bool BFGC::HandlePendingGCData()
  716. {
  717. bool didMark = false;
  718. didMark = HandlePendingGCData(&mPendingGCData);
  719. return didMark;
  720. }
  721. void BFGC::SweepSpan(tcmalloc_obj::Span* span, int expectedStartPage)
  722. {
  723. if ((gBfRtDbgFlags & BfRtFlags_ObjectHasDebugFlags) == 0)
  724. return;
  725. if (span->location != tcmalloc_obj::Span::IN_USE)
  726. return;
  727. if (span->start != expectedStartPage)
  728. {
  729. // This check covers when a new multi-page span is being put into place
  730. // and we catch after the first block, and it also catches the case
  731. // when the allocator splits a span and the pagemap can hold a reference
  732. // to a span that no longer covers that location.
  733. // For both of these cases we ignore the span. Remember, the worst case
  734. // here is that we'll miss a sweep of an object, which would just delay it's
  735. // cleanup until next GC cycle. Because the GC is the sole freer of spans,
  736. // there can never be a case where we find a valid span and then the span
  737. // changes sizeclass or location before we can scan the memory it points to.
  738. //
  739. // This also covers the case where a page spans over a radix map section and
  740. // we catch it on an outer loop again
  741. return;
  742. }
  743. intptr pageSize = (intptr)1<<kPageShift;
  744. int spanSize = pageSize * span->length;
  745. void* spanStart = (void*)((intptr)span->start << kPageShift);
  746. void* spanEnd = (void*)((intptr)spanStart + spanSize);
  747. void* spanPtr = spanStart;
  748. BF_LOGASSERT((spanStart >= tcmalloc_obj::PageHeap::sAddressStart) && (spanEnd <= tcmalloc_obj::PageHeap::sAddressEnd));
  749. int elementSize = Static::sizemap()->ByteSizeForClass(span->sizeclass);
  750. if (elementSize == 0)
  751. elementSize = spanSize;
  752. BF_LOGASSERT(elementSize >= sizeof(bf::System::Object));
  753. while (spanPtr <= (uint8*)spanEnd - elementSize)
  754. {
  755. //objCheckCount++;
  756. bf::System::Object* obj = (bf::System::Object*)spanPtr;
  757. #ifdef TARGET_TYPE
  758. if ((obj->mAllocCheckPtr != 0) && (obj->mBFVData->mType == TARGET_TYPE))
  759. {
  760. //sweepFoundCount++;
  761. }
  762. #endif
  763. // Mark 0 means 'just allocated'. 'deleteMarkId' is the last one. 'invalidMarkId' should be impossible because we'd either be deleted or marked as leaked before
  764. int deleteMarkId = mCurMarkId - 1;
  765. if (deleteMarkId == 0)
  766. deleteMarkId = 3;
  767. int invalidMarkId = deleteMarkId - 1;
  768. if (invalidMarkId == 0)
  769. invalidMarkId = 3;
  770. bool showAllAsLeaks = !mRunning;
  771. if (obj->mAllocCheckPtr != 0)
  772. {
  773. #ifdef BF_GC_VERIFY_SWEEP_IDS
  774. BF_LOGASSERT(obj->mAllocNum != 0);
  775. BF_LOGASSERT(allocIdSet.find(obj->mAllocNum) == allocIdSet.end());
  776. allocIdSet.insert(obj->mAllocNum);
  777. #endif
  778. mCurSweepFoundCount++;
  779. int objectFlags = obj->mObjectFlags;
  780. if (objectFlags == 0)
  781. mCurSweepFoundPermanentCount++;
  782. int markId = objectFlags & BF_OBJECTFLAG_MARK_ID_MASK;
  783. BF_ASSERT(markId != invalidMarkId);
  784. if (markId == 0)
  785. {
  786. // Newly-allocated! Set mark flag now...
  787. //obj->mObjectFlags = (BfObjectFlags)(obj->mObjectFlags | mCurMarkId);
  788. // Newly-allocated! Ignore, it will have its mark set soon (rare race condition)
  789. }
  790. else if ((markId == deleteMarkId) || (mSweepInfo.mShowAllAsLeaks))
  791. {
  792. if ((objectFlags & BF_OBJECTFLAG_DELETED) == 0)
  793. {
  794. if (!mSweepInfo.mEmptyScan)
  795. {
  796. // We set this to cause an error like:
  797. // Deleting an object that was detected as leaked (internal error)
  798. obj->mObjectFlags = (BfObjectFlags)(objectFlags | BF_OBJECTFLAG_STACK_ALLOC);
  799. if (!mHadRootError)
  800. {
  801. mSweepInfo.mLeakCount++;
  802. if (mSweepInfo.mLeakCount <= 1024 * 1024) // Have SOME limit
  803. {
  804. mSweepInfo.mLeakObjects.push_back(obj);
  805. }
  806. BFLOG2(GCLog::EVENT_LEAK, (intptr)obj, (intptr)obj->_GetType());
  807. #ifdef BF_GC_LOG_ENABLED
  808. gGCLog.Write();
  809. #endif
  810. }
  811. }
  812. }
  813. else
  814. {
  815. if (!mSweepInfo.mEmptyScan)
  816. {
  817. BFLOG1(GCLog::EVENT_FINALIZE_LIST, (intptr)obj);
  818. //obj->mObjectFlags = (BfObjectFlags) (obj->mObjectFlags & ~BF_OBJECTFLAG_FINALIZE_MAP);
  819. mFinalizeList.push_back(obj);
  820. }
  821. }
  822. }
  823. else
  824. mCurLiveObjectCount++;
  825. }
  826. spanPtr = (void*)((intptr)spanPtr + elementSize);
  827. }
  828. }
  829. void BFGC::Sweep()
  830. {
  831. BP_ZONE("Sweep");
  832. mCurLiveObjectCount = 0;
  833. auto pageHeap = Static::pageheap();
  834. if (pageHeap == NULL)
  835. return;
  836. #ifdef BF_GC_VERIFY_SWEEP_IDS
  837. maxAllocNum = bf::System::Object::sCurAllocNum;
  838. allocIdSet.clear();
  839. #endif
  840. int leafCheckCount = 0;
  841. int bits = kAddressBits;
  842. int leafLen = PageHeap::PageMap::LEAF_LENGTH;
  843. #ifdef BF32
  844. for (int rootIdx = 0; rootIdx < PageHeap::PageMap::ROOT_LENGTH; rootIdx++)
  845. {
  846. PageHeap::PageMap::Leaf* rootLeaf = Static::pageheap()->pagemap_.root_[rootIdx];
  847. if (rootLeaf == NULL)
  848. continue;
  849. for (int leafIdx = 0; leafIdx < PageHeap::PageMap::LEAF_LENGTH; leafIdx++)
  850. {
  851. leafCheckCount++;
  852. tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)rootLeaf->values[leafIdx];
  853. if (span != NULL)
  854. {
  855. int expectedStartPage = (rootIdx * PageHeap::PageMap::LEAF_LENGTH) + leafIdx;
  856. SweepSpan(span, expectedStartPage);
  857. // We may be tempted to advance by span->length here, BUT
  858. // let us just scan all leafs becuause span data is
  859. // sometimes invalid and a long invalid span can cause
  860. // us to skip over an actual valid span
  861. }
  862. }
  863. }
  864. #else
  865. int interiorLen = PageHeap::PageMap::INTERIOR_LENGTH;
  866. for (int pageIdx1 = 0; pageIdx1 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx1++)
  867. {
  868. PageHeap::PageMap::Node* node1 = Static::pageheap()->pagemap_.root_->ptrs[pageIdx1];
  869. if (node1 == NULL)
  870. continue;
  871. for (int pageIdx2 = 0; pageIdx2 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx2++)
  872. {
  873. PageHeap::PageMap::Node* node2 = node1->ptrs[pageIdx2];
  874. if (node2 == NULL)
  875. continue;
  876. for (int pageIdx3 = 0; pageIdx3 < PageHeap::PageMap::LEAF_LENGTH; pageIdx3++)
  877. {
  878. leafCheckCount++;
  879. tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)node2->ptrs[pageIdx3];
  880. if (span != NULL)
  881. {
  882. int expectedStartPage = ((pageIdx1 * PageHeap::PageMap::INTERIOR_LENGTH) + pageIdx2) * PageHeap::PageMap::LEAF_LENGTH + pageIdx3;
  883. SweepSpan(span, expectedStartPage);
  884. // We may be tempted to advance by span->length here, BUT
  885. // let us just scan all leafs becuause span data is
  886. // sometimes invalid and a long invalid span can cause
  887. // us to skip over an actual valid span
  888. }
  889. }
  890. }
  891. }
  892. #endif
  893. #ifdef BF_GC_VERIFY_SWEEP_IDS
  894. for (int allocNum = 1; allocNum < maxAllocNum; allocNum++)
  895. {
  896. BF_LOGASSERT(allocIdSet.find(allocNum) != allocIdSet.end());
  897. }
  898. #endif
  899. }
  900. extern Beefy::StringT<0> gDbgErrorString;
  901. void BFGC::ProcessSweepInfo()
  902. {
  903. if (mSweepInfo.mLeakCount > 0)
  904. {
  905. if (mSweepInfo.mShowAllAsLeaks)
  906. {
  907. // We aren't certain of the mark flags, so force the issue
  908. mCurMarkId = 0;
  909. for (auto obj : mSweepInfo.mLeakObjects)
  910. {
  911. obj->mObjectFlags = (BfObjectFlags)((obj->mObjectFlags & ~BF_OBJECTFLAG_MARK_ID_MASK) | mCurMarkId);
  912. }
  913. mCurMarkId = 1;
  914. }
  915. for (auto obj : mSweepInfo.mLeakObjects)
  916. {
  917. MarkMembers(obj);
  918. }
  919. //::MessageBoxA(NULL, "Leak", "Leak", MB_OK);
  920. //#if 0
  921. Beefy::String errorStr = StrFormat("%d object memory leak%s detected, details in Output panel.",
  922. mSweepInfo.mLeakCount, (mSweepInfo.mLeakCount != 1) ? "s" : "");
  923. gDbgErrorString = errorStr;
  924. gDbgErrorString += "\n";
  925. #ifdef BF_GC_DEBUGSWEEP
  926. Sleep(100);
  927. #endif
  928. for (int pass = 0; pass < 2; pass++)
  929. {
  930. int passLeakCount = 0;
  931. for (auto obj : mSweepInfo.mLeakObjects)
  932. {
  933. bool wantsNoRefs = pass == 0;
  934. bool hasNoRefs = (obj->mObjectFlags & BF_OBJECTFLAG_MARK_ID_MASK) != mCurMarkId;
  935. if (hasNoRefs != wantsNoRefs)
  936. continue;
  937. Beefy::String typeName = obj->GetTypeName();
  938. if (passLeakCount == 0)
  939. {
  940. Beefy::String header = (pass == 0) ? " Unreferenced:\n" : " Referenced by other leaked objects:\n";
  941. errorStr += "\x1";
  942. errorStr += "TEXT\t";
  943. errorStr += header;
  944. gDbgErrorString += header;
  945. }
  946. if (passLeakCount == 20000) // Only display so many...
  947. break;
  948. errorStr += "\x1";
  949. errorStr += StrFormat("LEAK\t(System.Object)0x%@\n", obj);
  950. errorStr += StrFormat(" (%s)0x%@\n", typeName.c_str(), obj);
  951. if (gDbgErrorString.length() < 256)
  952. gDbgErrorString += StrFormat(" (%s)0x%@\n", typeName.c_str(), obj);
  953. passLeakCount++;
  954. }
  955. }
  956. //TODO: Testing!
  957. //OutputDebugStrF(gDbgErrorString.c_str());
  958. gBfRtDbgCallbacks.SetErrorString(gDbgErrorString.c_str());
  959. gBfRtDbgCallbacks.DebugMessageData_SetupError(errorStr.c_str(), 1);
  960. BF_DEBUG_BREAK();
  961. }
  962. mSweepInfo.Clear();
  963. }
  964. void BFGC::ReleasePendingSpanObjects(Span* span)
  965. {
  966. if (span->freeingObjects != NULL)
  967. {
  968. Static::central_cache()[span->sizeclass].ReleasePendingSpanObjects(span);
  969. span->freeingObjects = NULL;
  970. span->freeingObjectsTail = NULL;
  971. }
  972. }
  973. void BFGC::ReleasePendingObjects()
  974. {
  975. BP_ZONE("ReleasePendingObjects");
  976. auto pageHeap = Static::pageheap();
  977. if (pageHeap == NULL)
  978. return;
  979. #ifdef BF_GC_VERIFY_SWEEP_IDS
  980. maxAllocNum = bf::System::Object::sCurAllocNum;
  981. allocIdSet.clear();
  982. #endif
  983. int leafCheckCount = 0;
  984. #ifdef BF32
  985. for (int rootIdx = 0; rootIdx < PageHeap::PageMap::ROOT_LENGTH; rootIdx++)
  986. {
  987. PageHeap::PageMap::Leaf* rootLeaf = Static::pageheap()->pagemap_.root_[rootIdx];
  988. if (rootLeaf == NULL)
  989. continue;
  990. for (int leafIdx = 0; leafIdx < PageHeap::PageMap::LEAF_LENGTH; leafIdx++)
  991. {
  992. tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)rootLeaf->values[leafIdx];
  993. if (span != NULL)
  994. ReleasePendingSpanObjects(span);
  995. }
  996. }
  997. #else
  998. for (int pageIdx1 = 0; pageIdx1 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx1++)
  999. {
  1000. PageHeap::PageMap::Node* node1 = Static::pageheap()->pagemap_.root_->ptrs[pageIdx1];
  1001. if (node1 == NULL)
  1002. continue;
  1003. for (int pageIdx2 = 0; pageIdx2 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx2++)
  1004. {
  1005. PageHeap::PageMap::Node* node2 = node1->ptrs[pageIdx2];
  1006. if (node2 == NULL)
  1007. continue;
  1008. for (int pageIdx3 = 0; pageIdx3 < PageHeap::PageMap::LEAF_LENGTH; pageIdx3++)
  1009. {
  1010. tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)node2->ptrs[pageIdx3];
  1011. if (span != NULL)
  1012. ReleasePendingSpanObjects(span);
  1013. }
  1014. }
  1015. }
  1016. #endif
  1017. #ifdef BF_GC_VERIFY_SWEEP_IDS
  1018. for (int allocNum = 1; allocNum < maxAllocNum; allocNum++)
  1019. {
  1020. BF_LOGASSERT(allocIdSet.find(allocNum) != allocIdSet.end());
  1021. }
  1022. #endif
  1023. }
  1024. typedef struct _TEB {
  1025. PVOID Reserved1[11];
  1026. void* ThreadLocalStorage;
  1027. void* ProcessEnvironmentBlock;
  1028. PVOID Reserved2[399];
  1029. BYTE Reserved3[1952];
  1030. PVOID TlsSlots[64];
  1031. BYTE Reserved4[8];
  1032. PVOID Reserved5[26];
  1033. PVOID ReservedForOle;
  1034. PVOID Reserved6[4];
  1035. PVOID TlsExpansionSlots;
  1036. } TEB, *PTEB;
  1037. typedef LONG NTSTATUS;
  1038. typedef DWORD KPRIORITY;
  1039. typedef WORD UWORD;
  1040. typedef struct _CLIENT_ID
  1041. {
  1042. PVOID UniqueProcess;
  1043. PVOID UniqueThread;
  1044. } CLIENT_ID, *PCLIENT_ID;
  1045. typedef struct _THREAD_BASIC_INFORMATION
  1046. {
  1047. NTSTATUS ExitStatus;
  1048. PVOID TebBaseAddress;
  1049. CLIENT_ID ClientId;
  1050. KAFFINITY AffinityMask;
  1051. KPRIORITY Priority;
  1052. KPRIORITY BasePriority;
  1053. } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
  1054. enum THREADINFOCLASS
  1055. {
  1056. ThreadBasicInformation,
  1057. };
  1058. static _TEB* GetTEB(HANDLE hThread)
  1059. {
  1060. bool loadedManually = false;
  1061. HMODULE module = GetModuleHandleA("ntdll.dll");
  1062. if (!module)
  1063. {
  1064. module = LoadLibraryA("ntdll.dll");
  1065. loadedManually = true;
  1066. }
  1067. NTSTATUS(__stdcall *NtQueryInformationThread)(HANDLE ThreadHandle, THREADINFOCLASS ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength);
  1068. NtQueryInformationThread = reinterpret_cast<decltype(NtQueryInformationThread)>(GetProcAddress(module, "NtQueryInformationThread"));
  1069. if (NtQueryInformationThread)
  1070. {
  1071. NT_TIB tib = { 0 };
  1072. THREAD_BASIC_INFORMATION tbi = { 0 };
  1073. NTSTATUS status = NtQueryInformationThread(hThread, ThreadBasicInformation, &tbi, sizeof(tbi), nullptr);
  1074. if (status >= 0)
  1075. {
  1076. _TEB* teb = (_TEB*)tbi.TebBaseAddress;
  1077. return teb;
  1078. }
  1079. }
  1080. if (loadedManually)
  1081. {
  1082. FreeLibrary(module);
  1083. }
  1084. return NULL;
  1085. }
  1086. static void** GetThreadLocalAddressMap(HANDLE hThread)
  1087. {
  1088. _TEB* teb = GetTEB(hThread);
  1089. if (teb == NULL)
  1090. return NULL;
  1091. return (void**)teb->ThreadLocalStorage;
  1092. }
  1093. void BFGC::AdjustStackPtr(intptr& addr, int& size)
  1094. {
  1095. int pageSize = 4096;
  1096. // There's a race condition where RSP can be adjusted into a guard page region before the
  1097. // guard page is actually removed. The guard page is a fire-once error so we can't just
  1098. // ignore it or else we rob that read of it's ability to expand (crash)
  1099. while (size > 0)
  1100. {
  1101. MEMORY_BASIC_INFORMATION memoryInfo;
  1102. int returnSize = ::VirtualQuery((void*)addr, &memoryInfo, sizeof(memoryInfo));
  1103. if ((returnSize > 0) && ((memoryInfo.Protect & (PAGE_GUARD | PAGE_NOACCESS)) == 0))
  1104. return;
  1105. addr += pageSize;
  1106. size -= pageSize;
  1107. }
  1108. }
  1109. bool BFGC::ScanThreads()
  1110. {
  1111. BP_ZONE("BFGC::ScanThreads");
  1112. mUsingThreadUnlocked = true;
  1113. BF_FULL_MEMORY_FENCE();
  1114. //BP_ZONE("ScanThreads");
  1115. bool didWork = false;
  1116. mStackScanIdx++;
  1117. mDoStackDeepMark = true;
  1118. int threadIdx = 0;
  1119. while (true)
  1120. {
  1121. ThreadInfo* thread = NULL;
  1122. {
  1123. AutoCrit autoCrit(mCritSect);
  1124. if (threadIdx >= mThreadList.size())
  1125. break;
  1126. thread = mThreadList[threadIdx++];
  1127. }
  1128. if (!thread->mRunning)
  1129. {
  1130. AutoCrit autoCrit(mCritSect);
  1131. BF_ASSERT(mThreadList[threadIdx - 1] == thread);
  1132. delete thread;
  1133. mThreadList.RemoveAt(threadIdx - 1);
  1134. continue;
  1135. }
  1136. BP_ZONE("ThreadCollect");
  1137. //Beefy::DebugTimeGuard suspendTimeGuard(10, "ThreadSuspend");
  1138. DWORD result = 0;
  1139. //BFMark(thread);
  1140. //MarkObject(thread->mThread);
  1141. // If (thread->mLastGCScanIdx == mCurScanIdx), that means this is the second cycle of running through here,
  1142. // which could happen if we added another thread while scanning so we need another pass tSuspendThreadhrough to
  1143. // catch the new one
  1144. if (((mGCThread != NULL) && (thread->mThreadHandle == mGCThread)) ||
  1145. (!thread->mRunning) /*|| (thread->mLastGCScanIdx == mCurScanIdx)*/)
  1146. {
  1147. continue;
  1148. }
  1149. #ifdef BF_GC_LOG_ENABLED
  1150. // If we're writing the log from another thread then wait for it -- we'll deadlock if we pause that thread and then try to log
  1151. while (gGCLog.mWriting)
  1152. {
  1153. Sleep(20);
  1154. }
  1155. #endif
  1156. //printf("Processing Thread:%p Handle:%p\n", thread, thread->mThreadHandle);
  1157. //suspendTimeGuard.Start();
  1158. //DWORD lastError = GetLastError();
  1159. BF_LOGASSERT(result == 0);
  1160. didWork = true;
  1161. BFLOG2(GCLog::EVENT_SCAN_THREAD, (intptr)thread, (intptr)thread->mThreadId);
  1162. for (auto obj : thread->mStackMarkableObjects)
  1163. {
  1164. MarkMembers(obj);
  1165. }
  1166. intptr regVals[64];
  1167. intptr stackPtr = 0;
  1168. BfpThreadResult threadResult;
  1169. int regValCount = 64;
  1170. BfpThread_GetIntRegisters(thread->mThreadHandle, &stackPtr, regVals, &regValCount, &threadResult);
  1171. BF_ASSERT(threadResult == BfpThreadResult_Ok);
  1172. void** threadLoadAddressMap = (void**)((_TEB*)thread->mTEB)->ThreadLocalStorage;
  1173. for (auto& tlsMember : mTLSMembers)
  1174. {
  1175. void* threadLoadAddress = threadLoadAddressMap[tlsMember.mTLSIndex];
  1176. typedef void(*MarkFunc)(void*);
  1177. MarkFunc markFunc = *(MarkFunc*)&tlsMember.mMarkFunc;
  1178. markFunc((uint8*)threadLoadAddress + tlsMember.mTLSOffset);
  1179. }
  1180. mQueueMarkObjects = true;
  1181. ConservativeScan(regVals, regValCount * sizeof(intptr));
  1182. int length = thread->mStackStart - stackPtr;
  1183. AdjustStackPtr(stackPtr, length);
  1184. ConservativeScan((void*)stackPtr, length);
  1185. mQueueMarkObjects = false;
  1186. if (mDoStackDeepMark)
  1187. {
  1188. HandlePendingGCData();
  1189. }
  1190. //suspendTimeGuard.Stop();
  1191. BF_LOGASSERT(result != -1);
  1192. if (!mPendingGCData.IsEmpty())
  1193. {
  1194. BP_ZONE("HandlePendingGCData(Thread)");
  1195. HandlePendingGCData();
  1196. }
  1197. }
  1198. // This can be write barrier objects be from dead threads
  1199. HandlePendingGCData();
  1200. BF_FULL_MEMORY_FENCE();
  1201. mUsingThreadUnlocked = false;
  1202. return didWork;
  1203. }
  1204. int gAddedTypeCount = 0;
  1205. int gGCTypeCounts = 0;
  1206. int gGCAssemblyCount = 0;
  1207. static void GCObjFree(void* ptr)
  1208. {
  1209. Span* span = TCGetSpanAt(ptr);
  1210. if (span == NULL)
  1211. {
  1212. BF_DBG_FATAL("Bad");
  1213. tc_free(ptr);
  1214. return;
  1215. }
  1216. if (span->sizeclass == 0)
  1217. {
  1218. // Clear out all memory
  1219. intptr pageSize = (intptr)1 << kPageShift;
  1220. int spanSize = pageSize * span->length;
  1221. void* spanStart = (void*)((intptr)span->start << kPageShift);
  1222. memset(spanStart, 0, spanSize);
  1223. tc_free(ptr);
  1224. return;
  1225. }
  1226. int size = Static::sizemap()->class_to_size(span->sizeclass);
  1227. int dataOffset = (int)(sizeof(intptr) * 2);
  1228. memset((uint8*)ptr + dataOffset, 0, size - dataOffset);
  1229. // const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
  1230. // size_t cl = Static::pageheap()->GetSizeClassIfCached(p);
  1231. // if (cl == 0)
  1232. // {
  1233. // tc_free(ptr);
  1234. // return;
  1235. // }
  1236. //
  1237. // Span* span = TCGetSpanAt(ptr);
  1238. if (span->freeingObjectsTail == NULL)
  1239. {
  1240. span->freeingObjectsTail = ptr;
  1241. *((intptr*)span->freeingObjectsTail) = 1;
  1242. }
  1243. else
  1244. {
  1245. // Increment pending size
  1246. (*((intptr*)span->freeingObjectsTail))++;
  1247. *(reinterpret_cast<void**>(ptr)) = span->freeingObjects;
  1248. }
  1249. span->freeingObjects = ptr;
  1250. }
  1251. void BFGC::DoCollect(bool doingFullGC)
  1252. {
  1253. BP_ZONE("Collect");
  1254. mThreadId = BfpThread_GetCurrentId();
  1255. mStage = 0;
  1256. gTargetFoundCount = 0;
  1257. gMarkTargetCount = 0;
  1258. gMarkTargetMutatorCount = 0;
  1259. mCurGCMarkCount = 0;
  1260. mCurMutatorMarkCount = 0;
  1261. mCurGCObjectQueuedCount = 0;
  1262. mCurMutatorObjectQueuedCount = 0;
  1263. mCurObjectDeleteCount = 0;
  1264. mCurFinalizersCalled = 0;
  1265. mCurSweepFoundCount = 0;
  1266. mCurSweepFoundPermanentCount = 0;
  1267. mCurFreedBytes = 0;
  1268. if (doingFullGC)
  1269. {
  1270. int nextMark = sCurMarkId + 1;
  1271. if (nextMark == 4)
  1272. nextMark = 1;
  1273. mCurMarkId = nextMark;
  1274. sCurMarkId = nextMark;
  1275. sAllocFlags = sCurMarkId;
  1276. }
  1277. mStage = 1;
  1278. BFLOG2(GCLog::EVENT_GC_START, sCurMarkId, BfpSystem_TickCount());
  1279. gGCTypeCounts = 0;
  1280. if (!mSkipMark)
  1281. {
  1282. BP_ZONE("MarkStatics");
  1283. MarkStatics();
  1284. RawMarkAll();
  1285. bool success = bf::System::GC::DoCallRootCallbacks();
  1286. if ((!success) && (!mHadRootError))
  1287. {
  1288. OutputDebugStringA("WARNING: GC leak detection disabled, a GC root callback disabled it\n");
  1289. mHadRootError = true;
  1290. }
  1291. }
  1292. if (!mSkipMark)
  1293. {
  1294. Beefy::AutoCrit autoCrit(mCritSect);
  1295. BP_ZONE("ExplicitRootsMark");
  1296. mQueueMarkObjects = true;
  1297. for (int i = 0; i < (int)mExplicitRoots.size(); i++)
  1298. MarkObject(mExplicitRoots[i]);
  1299. mQueueMarkObjects = false;
  1300. }
  1301. if ((doingFullGC) && (!mSkipMark))
  1302. {
  1303. //MarkObject(mGCThread);
  1304. BFMarkThreadPoolJobs();
  1305. BFMarkCOMObjects();
  1306. }
  1307. int threadIdx = 0;
  1308. // We need to turn roots black, otherwise the mutator could move a member
  1309. // of a gray root to the stack after the stack scan and we'd miss it
  1310. {
  1311. BP_ZONE("Collect - HandlePendingGCData(Roots)");
  1312. HandlePendingGCData();
  1313. }
  1314. mStage = 2;
  1315. mCurScanIdx++;
  1316. int passes = 0;
  1317. if (doingFullGC)
  1318. {
  1319. if (!mSkipMark)
  1320. {
  1321. ScanThreads();
  1322. HandlePendingGCData();
  1323. }
  1324. }
  1325. BF_ASSERT(mPendingGCData.IsEmpty());
  1326. }
  1327. void BFGC::FinishCollect()
  1328. {
  1329. //OutputDebugStrF("Collected %d objects\n", mFinalizeList.size());
  1330. if ((gBfRtDbgFlags & BfRtFlags_ObjectHasDebugFlags) == 0)
  1331. return;
  1332. mLastFreeCount = 0;
  1333. mStage = 3;
  1334. typedef std::unordered_set<bf::System::Object*> BfObjectSet;
  1335. {
  1336. // Handle any pending data from strong GCHandle references
  1337. HandlePendingGCData();
  1338. }
  1339. int finalizeDataCountFound = 0;
  1340. if (mDebugDumpState == DEBUGDUMPSTATE_WAITING_FOR_GC)
  1341. {
  1342. WriteDebugDumpState();
  1343. mDebugDumpState = DEBUGDUMPSTATE_NONE;
  1344. }
  1345. {
  1346. BP_ZONE("FreeingObjects");
  1347. void* lastPtr = NULL;
  1348. for (int i = 0; i < mFinalizeList.size(); i++)
  1349. {
  1350. bf::System::Object* obj = mFinalizeList[i];
  1351. if (obj == NULL)
  1352. continue;
  1353. BF_LOGASSERT((obj->mObjectFlags & (/*BF_OBJECTFLAG_FREED |*/ BF_OBJECTFLAG_ALLOCATED)) == BF_OBJECTFLAG_ALLOCATED);
  1354. //BF_LOGASSERT(obj > lastPtr);
  1355. lastPtr = obj;
  1356. }
  1357. {
  1358. BP_ZONE("ReleaseAtLeastNPages");
  1359. SpinLockHolder h(tcmalloc_obj::Static::pageheap_lock());
  1360. Static::pageheap()->ReleaseAtLeastNPages(256);
  1361. }
  1362. {
  1363. BP_ZONE("DecommitFromReleasedList");
  1364. Static::pageheap()->DecommitFromReleasedList(mForceDecommit);
  1365. mForceDecommit = false;
  1366. }
  1367. Dictionary<bf::System::Type*, int> sizeMap;
  1368. int objFreeSize = 0;
  1369. for (int i = 0; i < mFinalizeList.size(); i++)
  1370. {
  1371. bf::System::Object* obj = mFinalizeList[i];
  1372. if (obj == NULL)
  1373. continue;
  1374. // Removed from list already?
  1375. if ((obj->mObjectFlags & BF_OBJECTFLAG_MARK_ID_MASK) == mCurMarkId)
  1376. continue;
  1377. #ifdef BF_DEBUG
  1378. if ((obj->mObjectFlags & (/*BF_OBJECTFLAG_FREED |*/ BF_OBJECTFLAG_ALLOCATED)) != BF_OBJECTFLAG_ALLOCATED)
  1379. {
  1380. tcmalloc_obj::Span* span = TCGetSpanAt(obj);
  1381. BF_FATAL("Object corrupted");
  1382. }
  1383. #ifdef TARGET_TYPE
  1384. if (obj->mBFVData->mType == TARGET_TYPE)
  1385. {
  1386. printf("Finalizing target %p\n", obj);
  1387. }
  1388. #endif
  1389. #endif
  1390. BFLOG1(GCLog::EVENT_FREE, (intptr)obj);
  1391. // BYE!
  1392. #ifdef BF_NO_FREE_MEMORY
  1393. //obj->mObjectFlags |= BF_OBJECTFLAG_FREED;
  1394. #else
  1395. #ifdef BG_GC_TRACKPTRS
  1396. {
  1397. Beefy::AutoCrit autoCrit(gBFGC.mCritSect);
  1398. gTrackPtr.erase(gTrackPtr.find(obj));
  1399. }
  1400. #endif
  1401. int objSize = BFGetObjectSize(obj);
  1402. objFreeSize += objSize;
  1403. if (mDisplayFreedObjects)
  1404. {
  1405. // Temporarily remove object flags so GetType() won't fail
  1406. obj->mObjectFlags = BfObjectFlag_None;
  1407. bf::System::Type* type = obj->_GetType();
  1408. //auto pairVal = sizeMap.insert(std::make_pair(type, 0));
  1409. //int newSize = pairVal.first->second + objSize;
  1410. int* sizePtr = NULL;
  1411. sizeMap.TryAdd(type, NULL, &sizePtr);
  1412. *sizePtr += objSize;
  1413. //pairVal.first->second = newSize;
  1414. }
  1415. //obj->mObjectFlags = BfObjectFlag_None;
  1416. obj->mAllocCheckPtr = 0;
  1417. mLastFreeCount++;
  1418. #ifdef BF_GC_USE_OLD_FREE
  1419. tc_free(obj);
  1420. #else
  1421. GCObjFree(obj);
  1422. #endif
  1423. #ifdef BF_GC_PRINTSTATS
  1424. ::InterlockedIncrement((volatile uint32*) &gBFGC.mTotalFrees);
  1425. #endif
  1426. #endif
  1427. mCurObjectDeleteCount++;
  1428. }
  1429. if (!sizeMap.IsEmpty())
  1430. {
  1431. std::multimap<int, bf::System::Type*> orderedSizeMap;
  1432. int totalSize = 0;
  1433. for (auto& pair : sizeMap)
  1434. {
  1435. totalSize += pair.mValue;
  1436. orderedSizeMap.insert(std::make_pair(-pair.mValue, pair.mKey));
  1437. }
  1438. Beefy::String msg;
  1439. msg += Beefy::StrFormat("GC Live Count : %d\n", mCurLiveObjectCount);
  1440. msg += Beefy::StrFormat("GC Freed Count : %d\n", mLastFreeCount);
  1441. msg += Beefy::StrFormat("GC Freed Size : %dk\n", (int)(objFreeSize / 1024));
  1442. msg += "GC Objects\n";
  1443. for (auto& pair : orderedSizeMap)
  1444. {
  1445. bf::System::Type* typeName = pair.second;
  1446. msg += StrFormat(" %-37s : %dk\n", typeName->GetFullName().c_str(), (-pair.first + 1023) / 1024);
  1447. }
  1448. Beefy::OutputDebugStr(msg.c_str());
  1449. }
  1450. mBytesFreed += objFreeSize;
  1451. mBytesRequested -= objFreeSize;
  1452. mCurFreedBytes += objFreeSize;
  1453. }
  1454. #ifdef BF_GC_USE_OLD_FREE
  1455. {
  1456. BP_ZONE("TCScavenge");
  1457. tcmalloc_obj::ThreadCache::GetCacheWhichMustBePresent()->ForceScavenge();
  1458. }
  1459. #else
  1460. {
  1461. //Beefy::DebugTimeGuard suspendTimeGuard(10, "BFGC::ReleasePendingObjects");
  1462. ReleasePendingObjects();
  1463. }
  1464. #endif
  1465. mFinalizeList.Clear();
  1466. mStage = 4;
  1467. }
  1468. void BFGC::Run()
  1469. {
  1470. BfpThread_SetName(BfpThread_GetCurrent(), "BFGC", NULL);
  1471. uint32 lastGCTick = BFTickCount();
  1472. while (!mExiting)
  1473. {
  1474. float fullGCPeriod = mFullGCPeriod;
  1475. if ((fullGCPeriod != -1) && (mMaxPausePercentage > 0) && (!mCollectReports.IsEmpty()))
  1476. {
  1477. // When we are debugging, we can have a very long update when stepping through code,
  1478. // but otherwise try to pick an update period that keeps our pause time down
  1479. float maxExpandPeriod = BF_MAX(mFullGCPeriod, 2000);
  1480. auto& collectReport = mCollectReports.back();
  1481. fullGCPeriod = BF_MAX(fullGCPeriod, collectReport.mPausedMS * 100 / mMaxPausePercentage);
  1482. fullGCPeriod = BF_MIN(fullGCPeriod, maxExpandPeriod);
  1483. }
  1484. int waitPeriod = fullGCPeriod;
  1485. if (waitPeriod == 0)
  1486. waitPeriod = -1;
  1487. mCollectEvent.WaitFor(waitPeriod);
  1488. uint32 tickNow = BFTickCount();
  1489. if ((fullGCPeriod >= 0) && (tickNow - lastGCTick >= fullGCPeriod))
  1490. mCollectRequested = true;
  1491. if ((mFreeTrigger >= 0) && (mFreeSinceLastGC >= mFreeTrigger))
  1492. mCollectRequested = true;
  1493. if (!mCollectRequested)
  1494. continue;
  1495. lastGCTick = tickNow;
  1496. mCollectRequested = false;
  1497. mPerformingCollection = true;
  1498. BF_FULL_MEMORY_FENCE();
  1499. PerformCollection();
  1500. BF_FULL_MEMORY_FENCE();
  1501. mPerformingCollection = false;
  1502. BF_FULL_MEMORY_FENCE();
  1503. mCollectDoneEvent.Set(true);
  1504. }
  1505. mRunning = false;
  1506. }
  1507. void BFGC::RunStub(void* gc)
  1508. {
  1509. ((BFGC*)gc)->Run();
  1510. }
  1511. void BFGC::ThreadStarted(BfDbgInternalThread* thread)
  1512. {
  1513. Beefy::AutoCrit autoCrit(mCritSect);
  1514. //thread->mTCMallocObjThreadCache = tcmalloc_obj::ThreadCache::GetCache();
  1515. //mThreadList.push_back(thread);
  1516. BFLOG2(GCLog::EVENT_THREAD_STARTED, (intptr)thread, (intptr)BfpThread_GetCurrentId());
  1517. //printf("ThreadStarted: %p intern:%p TID:%d\n", thread->mThread, thread, ::GetCurrentThreadId());
  1518. }
  1519. void BFGC::ThreadStopped(BfDbgInternalThread* thread)
  1520. {
  1521. Beefy::AutoCrit autoCrit(mCritSect);
  1522. // Keep sync to avoid having the thread exit while the GC is trying to pause it,
  1523. // but do the actual cleanup from the GC's thread
  1524. //thread->mDone = true;
  1525. //printf("ThreadStopped: %p intern:%p TID:%d\n", thread->mThread, thread, ::GetCurrentThreadId());
  1526. }
  1527. void BFGC::ThreadStarted()
  1528. {
  1529. Beefy::AutoCrit autoCrit(mCritSect);
  1530. ThreadInfo* thread = new ThreadInfo();
  1531. thread->mRunning = true;
  1532. thread->mThreadHandle = BfpThread_GetCurrent();
  1533. thread->mThreadId = BfpThread_GetCurrentId();
  1534. thread->mTEB = GetTEB((HANDLE)thread->mThreadHandle);
  1535. intptr stackBase;
  1536. int stackLimit;
  1537. BfpThread_GetStackInfo(thread->mThreadHandle, &stackBase, &stackLimit, NULL);
  1538. thread->mStackStart = stackBase;
  1539. mThreadList.Add(thread);
  1540. ThreadInfo::sCurThreadInfo = thread;
  1541. }
  1542. void BFGC::ThreadStopped()
  1543. {
  1544. auto thread = ThreadInfo::sCurThreadInfo;
  1545. if (thread != NULL)
  1546. {
  1547. Beefy::AutoCrit autoCrit(mCritSect);
  1548. BF_ASSERT(thread->mStackMarkableObjects.IsEmpty());
  1549. if (!mUsingThreadUnlocked)
  1550. {
  1551. // Just delete it
  1552. mThreadList.Remove(thread);
  1553. delete thread;
  1554. }
  1555. else
  1556. {
  1557. thread->mRunning = false;
  1558. }
  1559. }
  1560. }
  1561. void BFGC::Init()
  1562. {
  1563. //ThreadStarted();
  1564. Start();
  1565. }
  1566. void BFGC::Start()
  1567. {
  1568. #ifndef BF_GC_DISABLED
  1569. //mEphemeronTombstone = Object::BFCreate();
  1570. //RegisterRoot(mEphemeronTombstone);
  1571. mRunning = true;
  1572. #ifdef BF_DEBUG
  1573. // More stack space is needed in debug version
  1574. //::CreateThread(NULL, 64*1024, (LPTHREAD_START_ROUTINE)&RunStub, (void*)this, 0, (DWORD*)&mThreadId);
  1575. mGCThread = BfpThread_Create(RunStub, (void*)this, 256*1024, (BfpThreadCreateFlags)(BfpThreadCreateFlag_Suspended | BfpThreadCreateFlag_StackSizeReserve), &mThreadId);
  1576. #else
  1577. mGCThread = BfpThread_Create(RunStub, (void*)this, 64 * 1024, (BfpThreadCreateFlags)(BfpThreadCreateFlag_Suspended | BfpThreadCreateFlag_StackSizeReserve), &mThreadId);
  1578. #endif
  1579. BfpThread_Resume(mGCThread, NULL);
  1580. #endif
  1581. }
  1582. void BFGC::StopCollecting()
  1583. {
  1584. if (!mRunning)
  1585. return;
  1586. mExiting = true;
  1587. while (mRunning)
  1588. {
  1589. if (BfpThread_WaitFor(mGCThread, 0))
  1590. {
  1591. OutputDebugStr("BeefDbgRT not shut down gracefully!\n");
  1592. mGracelessShutdown = true;
  1593. mRunning = false;
  1594. break;
  1595. }
  1596. //BFRtLock bfLock(mEphemeronTombstone);
  1597. mWaitingForGC = true;
  1598. // Wait for current collection to finish
  1599. mCollectEvent.Set();
  1600. //Monitor::Monitor_wait(mEphemeronTombstone, 20);
  1601. mWaitingForGC = false;
  1602. }
  1603. }
  1604. void BFGC::AddStackMarkableObject(bf::System::Object* obj)
  1605. {
  1606. auto threadInfo = ThreadInfo::sCurThreadInfo;
  1607. Beefy::AutoCrit autoCrit(threadInfo->mCritSect);
  1608. threadInfo->mStackMarkableObjects.Add(obj);
  1609. }
  1610. void BFGC::RemoveStackMarkableObject(bf::System::Object* obj)
  1611. {
  1612. auto threadInfo = ThreadInfo::sCurThreadInfo;
  1613. Beefy::AutoCrit autoCrit(threadInfo->mCritSect);
  1614. int stackIdx = threadInfo->mStackMarkableObjects.LastIndexOf(obj);
  1615. BF_ASSERT(stackIdx != -1);
  1616. if (stackIdx != -1)
  1617. threadInfo->mStackMarkableObjects.RemoveAtFast(stackIdx);
  1618. }
  1619. void BFGC::Shutdown()
  1620. {
  1621. if (mShutdown)
  1622. return;
  1623. mShutdown = true;
  1624. StopCollecting();
  1625. Beefy::AutoCrit autoCrit(mCritSect);
  1626. if (mGracelessShutdown)
  1627. return;
  1628. // Report any objects that aren't deleted
  1629. mSweepInfo.mShowAllAsLeaks = true;
  1630. Sweep();
  1631. ProcessSweepInfo();
  1632. RawShutdown();
  1633. TCMalloc_FreeAllocs();
  1634. mFinalizeList.Dispose();
  1635. mPendingGCData.Dispose();
  1636. for (auto thread : mThreadList)
  1637. thread->mStackMarkableObjects.Dispose();
  1638. }
  1639. void BFGC::InitDebugDump()
  1640. {
  1641. mDebugDumpState = DEBUGDUMPSTATE_WAITING_FOR_PREV;
  1642. mCollectEvent.Set();
  1643. while (mDebugDumpState < DEBUGDUMPSTATE_WAITING_FOR_MUTATOR)
  1644. {
  1645. //BFRtLock bfLock(mEphemeronTombstone);
  1646. //Monitor::Monitor_wait(mEphemeronTombstone, 20);
  1647. }
  1648. }
  1649. void BFGC::EndDebugDump()
  1650. {
  1651. mDebugDumpState = DEBUGDUMPSTATE_WAITING_FOR_GC;
  1652. }
  1653. intptr gFindAddrVal = 0;
  1654. void BFGC::DebugDumpLeaks()
  1655. {
  1656. CheckTcIntegrity();
  1657. BP_ZONE("DebugDump");
  1658. if (mExiting)
  1659. return;
  1660. mSkipMark = true;
  1661. Collect(false);
  1662. }
  1663. void BFGC::ObjReportHandleSpan(tcmalloc_obj::Span* span, int expectedStartPage, int& objectCount, intptr& freeSize, Beefy::Dictionary<bf::System::Type*, AllocInfo>& sizeMap)
  1664. {
  1665. if (span->location != tcmalloc_obj::Span::IN_USE)
  1666. return;
  1667. if (span->start != expectedStartPage)
  1668. {
  1669. return;
  1670. }
  1671. intptr pageSize = (intptr)1<<kPageShift;
  1672. int spanSize = pageSize * span->length;
  1673. void* spanStart = (void*)((intptr)span->start << kPageShift);
  1674. void* spanEnd = (void*)((intptr)spanStart + spanSize);
  1675. void* spanPtr = spanStart;
  1676. BF_LOGASSERT((spanStart >= tcmalloc_obj::PageHeap::sAddressStart) && (spanEnd <= tcmalloc_obj::PageHeap::sAddressEnd));
  1677. int elementSize = Static::sizemap()->ByteSizeForClass(span->sizeclass);
  1678. if (elementSize == 0)
  1679. elementSize = spanSize;
  1680. BF_LOGASSERT(elementSize >= sizeof(bf::System::Object));
  1681. while (spanPtr <= (uint8*)spanEnd - elementSize)
  1682. {
  1683. bf::System::Object* obj = (bf::System::Object*)spanPtr;
  1684. if (obj->mAllocCheckPtr != 0)
  1685. {
  1686. int objectFlags = obj->mObjectFlags;
  1687. if ((objectFlags & BF_OBJECTFLAG_DELETED) == 0)
  1688. {
  1689. bf::System::Type* type = obj->_GetType();
  1690. //auto pairVal = sizeMap.insert(std::make_pair(type, 0));
  1691. //int newSize = pairVal.first->second + elementSize;
  1692. //pairVal.first->second = newSize;
  1693. AllocInfo* sizePtr = NULL;
  1694. sizeMap.TryAdd(type, NULL, &sizePtr);
  1695. sizePtr->mCount++;
  1696. sizePtr->mSize += elementSize;
  1697. objectCount++;
  1698. }
  1699. }
  1700. else
  1701. freeSize += elementSize;
  1702. spanPtr = (void*)((intptr)spanPtr + elementSize);
  1703. }
  1704. }
  1705. void BFGC::ObjReportScan(int& objectCount, intptr& freeSize, Beefy::Dictionary<bf::System::Type*, AllocInfo>& sizeMap)
  1706. {
  1707. auto pageHeap = Static::pageheap();
  1708. if (pageHeap == NULL)
  1709. return;
  1710. #ifdef BF32
  1711. int checkPageId = (int)((uintptr)gFindAddrVal >> kPageShift);
  1712. int checkRootIdx = checkPageId >> PageHeap::PageMap::LEAF_BITS;
  1713. int checkLeafIdx = checkPageId & (PageHeap::PageMap::LEAF_LENGTH - 1);
  1714. for (int rootIdx = 0; rootIdx < PageHeap::PageMap::ROOT_LENGTH; rootIdx++)
  1715. {
  1716. PageHeap::PageMap::Leaf* rootLeaf = Static::pageheap()->pagemap_.root_[rootIdx];
  1717. if (rootLeaf == NULL)
  1718. continue;
  1719. for (int leafIdx = 0; leafIdx < PageHeap::PageMap::LEAF_LENGTH; leafIdx++)
  1720. {
  1721. tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)rootLeaf->values[leafIdx];
  1722. if (span != NULL)
  1723. {
  1724. int expectedStartPage = (rootIdx * PageHeap::PageMap::LEAF_LENGTH) + leafIdx;
  1725. ObjReportHandleSpan(span, expectedStartPage, objectCount, freeSize, sizeMap);
  1726. // We may be tempted to advance by span->length here, BUT
  1727. // let us just scan all leafs becuause span data is
  1728. // sometimes invalid and a long invalid span can cause
  1729. // us to skip over an actual valid span
  1730. }
  1731. }
  1732. }
  1733. #else
  1734. for (int pageIdx1 = 0; pageIdx1 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx1++)
  1735. {
  1736. PageHeap::PageMap::Node* node1 = Static::pageheap()->pagemap_.root_->ptrs[pageIdx1];
  1737. if (node1 == NULL)
  1738. continue;
  1739. for (int pageIdx2 = 0; pageIdx2 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx2++)
  1740. {
  1741. PageHeap::PageMap::Node* node2 = node1->ptrs[pageIdx2];
  1742. if (node2 == NULL)
  1743. continue;
  1744. for (int pageIdx3 = 0; pageIdx3 < PageHeap::PageMap::LEAF_LENGTH; pageIdx3++)
  1745. {
  1746. tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)node2->ptrs[pageIdx3];
  1747. if (span != NULL)
  1748. {
  1749. int expectedStartPage = ((pageIdx1 * PageHeap::PageMap::INTERIOR_LENGTH) + pageIdx2) * PageHeap::PageMap::LEAF_LENGTH + pageIdx3;
  1750. ObjReportHandleSpan(span, expectedStartPage, objectCount, freeSize, sizeMap);
  1751. // We may be tempted to advance by span->length here, BUT
  1752. // let us just scan all leafs because span data is
  1753. // sometimes invalid and a long invalid span can cause
  1754. // us to skip over an actual valid span
  1755. }
  1756. }
  1757. }
  1758. }
  1759. #endif
  1760. }
  1761. void BFGC::Report()
  1762. {
  1763. AutoCrit autoCrit(mCritSect);
  1764. CheckTcIntegrity();
  1765. BP_ZONE("Report");
  1766. Beefy::String msg;
  1767. int objectCount = 0;
  1768. #ifdef BF_GC_VERIFY_SWEEP_IDS
  1769. maxAllocNum = bf::System::Object::sCurAllocNum;
  1770. allocIdSet.clear();
  1771. #endif
  1772. int leafCheckCount = 0;
  1773. bool overflowed = false;
  1774. Dictionary<bf::System::Type*, AllocInfo> sizeMap;
  1775. intptr objFreeSize = 0;
  1776. ObjReportScan(objectCount, objFreeSize, sizeMap);
  1777. std::multimap<AllocInfo, bf::System::Type*> orderedSizeMap;
  1778. intptr totalSize = 0;
  1779. for (auto& pair : sizeMap)
  1780. {
  1781. orderedSizeMap.insert(std::make_pair(pair.mValue, pair.mKey));
  1782. }
  1783. msg += "Overall GC Summary\n";
  1784. //msg += Beefy::StrFormat(" TotalAllocs %d\n", mTotalAllocs);
  1785. //msg += Beefy::StrFormat(" TotalAllocs - TotalFrees %d\n", mTotalAllocs - mTotalFrees);
  1786. msg += Beefy::StrFormat(" System Memory Taken %dk\n", (int)(TCMalloc_SystemTaken / 1024));
  1787. //msg += Beefy::StrFormat(" BytesRequested %dk\n", (int)(mBytesRequested / 1024));
  1788. msg += Beefy::StrFormat(" Live Objects %d\n", objectCount);
  1789. msg += Beefy::StrFormat(" Last Object Freed Count %d\n", mLastFreeCount);
  1790. intptr reportedCount = 0;
  1791. intptr rawFreeSize = 0;
  1792. gBFGC.RawReport(msg, rawFreeSize, orderedSizeMap);
  1793. for (auto& pair : orderedSizeMap)
  1794. {
  1795. totalSize += pair.first.mSize;
  1796. reportedCount += pair.first.mCount;
  1797. }
  1798. msg += Beefy::StrFormat(" Scanned Alloc Count %d\n", (int)(reportedCount));
  1799. msg += Beefy::StrFormat(" Used Memory %dk\n", (int)(totalSize / 1024));
  1800. msg += Beefy::StrFormat(" Object Unusued Memory %dk\n", (int)(objFreeSize / 1024));
  1801. msg += Beefy::StrFormat(" Raw Unusued Memory %dk\n", (int)(rawFreeSize / 1024));
  1802. if (!mCollectReports.IsEmpty())
  1803. {
  1804. for (int reportIdx = 0; reportIdx < (int)mCollectReports.size(); reportIdx++)
  1805. {
  1806. auto& report = mCollectReports[reportIdx];
  1807. msg += Beefy::StrFormat(" Collection %d Total: %dms Paused: %dms CollectCount: %d", report.mCollectIdx, report.mTotalMS, report.mPausedMS, report.mCollectCount);
  1808. if (reportIdx > 0)
  1809. {
  1810. msg += Beefy::StrFormat(" SinceLast: %dms", report.mStartTick - mCollectReports[reportIdx - 1].mStartTick);
  1811. }
  1812. msg += "\n";
  1813. }
  1814. msg += Beefy::StrFormat(" Average Time Between Collections %dms\n", BFTickCount() / mCollectIdx);
  1815. }
  1816. msg += "Types Size Count\n";
  1817. for (auto& pair : orderedSizeMap)
  1818. {
  1819. bf::System::Type* type = pair.second;
  1820. Beefy::String typeName;
  1821. if (type == NULL)
  1822. typeName = "NULL";
  1823. else
  1824. typeName = type->GetFullName();
  1825. msg += StrFormat(" %-62s %7dk %7d\n", typeName.c_str(), (pair.first.mSize + 1023) / 1024, pair.first.mCount);
  1826. }
  1827. Beefy::OutputDebugStr(msg.c_str());
  1828. BFGCLogWrite();
  1829. }
  1830. void BFGC::ReportTLSMember(int tlsIndex, void* ptr, void* markFunc)
  1831. {
  1832. if (mMainThreadTLSPtr == NULL)
  1833. {
  1834. _TEB* teb = NtCurrentTeb();
  1835. mMainThreadTLSPtr = teb->ThreadLocalStorage;
  1836. }
  1837. TLSMember tlsMember;
  1838. tlsMember.mTLSOffset = (uint8*)ptr - ((uint8**)mMainThreadTLSPtr)[tlsIndex];
  1839. tlsMember.mMarkFunc = markFunc;
  1840. tlsMember.mTLSIndex = tlsIndex;
  1841. mTLSMembers.Add(tlsMember);
  1842. }
  1843. void BFGC::SuspendThreads()
  1844. {
  1845. BP_ZONE("TriggerCollection - SuspendThreads");
  1846. auto curThreadId = GetCurrentThreadId();
  1847. for (auto thread : mThreadList)
  1848. {
  1849. if ((thread->mThreadId != curThreadId) && (thread->mRunning))
  1850. {
  1851. // We must lock this before suspending so we can access mStackMarkableObjects
  1852. // Otherwise we could deadlock
  1853. thread->mCritSect.Lock();
  1854. BfpThreadResult result;
  1855. BfpThread_Suspend(thread->mThreadHandle, &result);
  1856. ASSERT(result == BfpThreadResult_Ok);
  1857. }
  1858. }
  1859. }
  1860. void BFGC::ResumeThreads()
  1861. {
  1862. BP_ZONE("TriggerCollection - ResumeThreads");
  1863. auto curThreadId = GetCurrentThreadId();
  1864. for (auto thread : mThreadList)
  1865. {
  1866. if ((thread->mThreadId != curThreadId) && (thread->mRunning))
  1867. {
  1868. // Previously locked in SuspendThreads
  1869. thread->mCritSect.Unlock();
  1870. BfpThread_Resume(thread->mThreadHandle, NULL);
  1871. }
  1872. }
  1873. }
  1874. void BFGC::PerformCollection()
  1875. {
  1876. BP_ZONE("TriggerCollection");
  1877. DWORD startTick = BFTickCount();
  1878. CollectReport collectReport;
  1879. collectReport.mCollectIdx = mCollectIdx;
  1880. collectReport.mStartTick = startTick;
  1881. #ifndef BF_MINGW
  1882. //_CrtCheckMemory();
  1883. #endif
  1884. #ifdef BF_GC_INCREMENTAL
  1885. mFullGCTriggered = true;
  1886. mForceDecommit |= forceDecommit;
  1887. gBFGC.mCollectEvent.Set();
  1888. #else
  1889. Beefy::AutoCrit autoCrit(mCritSect);
  1890. mAllocSinceLastGC = 0;
  1891. // This was old "emergency" debugging code to make sure we weren't doing a malloc in the GC code,
  1892. // but it's a multi-threaded race condition
  1893. /*uint8* mallocAddr = (uint8*)&malloc;
  1894. DWORD oldProtect = 0;
  1895. BOOL worked = ::VirtualProtect(mallocAddr, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
  1896. uint8 oldCode = *mallocAddr;
  1897. *mallocAddr = 0xCC;*/
  1898. mPendingGCData.Reserve(BF_GC_MAX_PENDING_OBJECT_COUNT);
  1899. uint32 suspendStartTick = BFTickCount();
  1900. SuspendThreads();
  1901. #ifndef BF_MINGW
  1902. //_CrtCheckMemory();
  1903. #endif
  1904. DoCollect(true);
  1905. #ifndef BF_MINGW
  1906. //_CrtCheckMemory();
  1907. #endif
  1908. //*mallocAddr = oldCode;
  1909. #ifdef BF_GC_EMPTYSCAN
  1910. {
  1911. mSweepInfo.mEmptyScan = true;
  1912. Sweep();
  1913. mSweepInfo.mEmptyScan = false;
  1914. }
  1915. #endif
  1916. mFreeSinceLastGC = 0;
  1917. BFLOG2(GCLog::EVENT_GC_UNFREEZE, sCurMarkId, BfpSystem_TickCount());
  1918. #ifndef BF_GC_DEBUGSWEEP
  1919. ResumeThreads();
  1920. #endif
  1921. collectReport.mPausedMS = BFTickCount() - suspendStartTick;
  1922. //BFGCLogWrite();
  1923. mFinalizeList.Clear();
  1924. Sweep();
  1925. #ifdef BF_GC_DEBUGSWEEP
  1926. ResumeThreads();
  1927. #endif
  1928. collectReport.mCollectCount = (int)mFinalizeList.size();
  1929. FinishCollect();
  1930. ReleasePendingObjects();
  1931. ProcessSweepInfo();
  1932. BFLOG2(GCLog::EVENT_GC_DONE, sCurMarkId, BfpSystem_TickCount());
  1933. collectReport.mTotalMS = BFTickCount() - startTick;
  1934. // while (mCollectReports.size() > 4)
  1935. // mCollectReports.RemoveAt(0);
  1936. while (mCollectReports.size() > 10)
  1937. mCollectReports.RemoveAt(0);
  1938. mCollectReports.Add(collectReport);
  1939. mCollectIdx++;
  1940. #endif
  1941. }
  1942. void BFGC::Collect(bool async)
  1943. {
  1944. mCollectRequested = true;
  1945. BF_FULL_MEMORY_FENCE();
  1946. if (async)
  1947. {
  1948. mCollectEvent.Set();
  1949. }
  1950. else
  1951. {
  1952. if (mPerformingCollection)
  1953. mCollectDoneEvent.WaitFor(0); // Wait for previous to finish
  1954. mCollectDoneEvent.Reset();
  1955. mCollectEvent.Set();
  1956. mCollectDoneEvent.WaitFor();
  1957. }
  1958. }
  1959. void BFGC::WriteDebugDumpState()
  1960. {
  1961. struct DebugInfo
  1962. {
  1963. bf::System::Type* mType;
  1964. int mCount;
  1965. int mSize;
  1966. int mAllocSize;
  1967. DebugInfo()
  1968. {
  1969. mType = NULL;
  1970. mCount = 0;
  1971. mSize = 0;
  1972. mAllocSize = 0;
  1973. }
  1974. };
  1975. std::vector<DebugInfo> debugInfoVector;
  1976. for (int i = 0; i < (int)mFinalizeList.size(); i++)
  1977. {
  1978. bf::System::Object* obj = (bf::System::Object*) mFinalizeList[i];
  1979. if ((bf::System::Type*)obj->GetTypeSafe() != NULL)
  1980. {
  1981. if ((uintptr)obj->GetTypeSafe() <= 1024U*1024U)
  1982. {
  1983. while ((int) debugInfoVector.size() <= 0)
  1984. debugInfoVector.push_back(DebugInfo());
  1985. DebugInfo* debugInfo = &debugInfoVector[0];
  1986. debugInfo->mType = NULL;
  1987. debugInfo->mCount++;
  1988. int objSize = BFGetObjectSize(obj);
  1989. debugInfo->mSize += objSize;
  1990. debugInfo->mAllocSize += objSize;
  1991. //debugInfo->mAllocSize += MallocExtension::instance()->GetEstimatedAllocatedSize(objSize);
  1992. }
  1993. else
  1994. {
  1995. //const bf::System::Type* bfTypeRootData = ((bf::System::Type*)obj->GetTypeSafe())->mTypeRootData;
  1996. bf::System::Type* bfType = obj->GetTypeSafe();
  1997. while ((int) debugInfoVector.size() <= bfType->mTypeId)
  1998. debugInfoVector.push_back(DebugInfo());
  1999. DebugInfo* debugInfo = &debugInfoVector[bfType->mTypeId];
  2000. debugInfo->mType = obj->GetTypeSafe();
  2001. debugInfo->mCount++;
  2002. int objSize = BFGetObjectSize(obj);
  2003. debugInfo->mSize += objSize;
  2004. debugInfo->mAllocSize += objSize;
  2005. //debugInfo->mAllocSize += MallocExtension::instance()->GetEstimatedAllocatedSize(objSize);
  2006. }
  2007. }
  2008. }
  2009. typedef std::multimap<int, DebugInfo*> DebugInfoMap;
  2010. DebugInfoMap debugInfoMap;
  2011. for (int i = 0; i < (int) debugInfoVector.size(); i++)
  2012. {
  2013. DebugInfo* debugInfo = &debugInfoVector[i];
  2014. if (debugInfo->mCount > 0)
  2015. debugInfoMap.insert(DebugInfoMap::value_type(-debugInfo->mSize, debugInfo));
  2016. }
  2017. Beefy::String dbgStr = "\n\nBeefyRT GC DebugDump:\n";
  2018. int countTotal = 0;
  2019. int sizeTotal = 0;
  2020. int allocSizeTotal = 0;
  2021. DebugInfoMap::iterator itr = debugInfoMap.begin();
  2022. while (itr != debugInfoMap.end())
  2023. {
  2024. DebugInfo* debugInfo = itr->second;
  2025. Beefy::String lineStr = StrFormat("%8d %8dk %8dk ", debugInfo->mCount, (debugInfo->mSize + 1023) / 1024, (debugInfo->mAllocSize + 1023) / 1024);
  2026. Beefy::String typeName;
  2027. if (debugInfo->mType != NULL)
  2028. typeName = debugInfo->mType->GetFullName();
  2029. else
  2030. typeName = "???";
  2031. lineStr += typeName;
  2032. dbgStr += lineStr += "\n";
  2033. countTotal += debugInfo->mCount;
  2034. sizeTotal += debugInfo->mSize;
  2035. allocSizeTotal += debugInfo->mAllocSize;
  2036. ++itr;
  2037. }
  2038. dbgStr += StrFormat("%8d %8dk %8dk TOTAL", countTotal, (sizeTotal + 1023)/1024, (allocSizeTotal + 1023)/1024);
  2039. OutputDebugStrF(dbgStr.c_str());
  2040. }
  2041. #ifdef BF_DEBUG
  2042. //#define NO_QUEUE_OBJECTS
  2043. #endif
  2044. #ifdef BF_GC_LOG_ENABLED
  2045. static bf::System::Object* gMarkingObject[8192];
  2046. #endif
  2047. void BFGC::MarkFromGCThread(bf::System::Object* obj)
  2048. {
  2049. if (obj == NULL)
  2050. return;
  2051. //BP_ZONE("MarkFromGCThread");
  2052. void* addr = obj;
  2053. if ((addr < tcmalloc_obj::PageHeap::sAddressStart) || (addr >= tcmalloc_obj::PageHeap::sAddressEnd))
  2054. return;
  2055. tcmalloc_obj::Span* span = TCGetSpanAt(obj);
  2056. if (span == NULL)
  2057. return;
  2058. if (span->location != tcmalloc_obj::Span::IN_USE)
  2059. return;
  2060. intptr pageSize = (intptr) 1 << kPageShift;
  2061. int spanSize = pageSize * span->length;
  2062. void* spanStart = (void*)((intptr)span->start << kPageShift);
  2063. void* spanEnd = (void*)((intptr)spanStart + spanSize);
  2064. if ((addr < spanStart) || (addr > (uint8*)spanEnd - sizeof(bf::System::Object)))
  2065. return;
  2066. // Is it already marked? Ignore.
  2067. if ((obj->mObjectFlags & BF_OBJECTFLAG_MARK_ID_MASK) == mCurMarkId)
  2068. return;
  2069. // Don't do any processing of non-allocated objects (like string literals), or append allocs
  2070. if ((obj->mObjectFlags & BF_OBJECTFLAG_ALLOCATED) == 0)
  2071. return;
  2072. if (obj->mAllocCheckPtr == 0) // It IS in the heap but not allocated
  2073. return;
  2074. bool curIsDeleted = false;
  2075. if (mMarkingDeleted)
  2076. {
  2077. if ((obj->mObjectFlags & BF_OBJECTFLAG_DELETED) == 0)
  2078. {
  2079. // Don't allow a deleted object to mark a non-deleted object-
  2080. // That should be handled as a LEAK if there aren't any non-deleted objects referencing it
  2081. return;
  2082. }
  2083. }
  2084. int elementSize = Static::sizemap()->ByteSizeForClass(span->sizeclass);
  2085. // Large alloc
  2086. if (elementSize == 0)
  2087. {
  2088. if (obj != (bf::System::Object*)spanStart)
  2089. return;
  2090. }
  2091. else
  2092. {
  2093. void* maskedAddr = addr;
  2094. maskedAddr = (uint8*)spanStart + (((uint8*)maskedAddr - (uint8*)spanStart) / elementSize * elementSize);
  2095. if (obj != (bf::System::Object*)maskedAddr)
  2096. return;
  2097. }
  2098. #ifndef BF_GC_DISABLED
  2099. BF_LOGASSERT(mThreadId == BfpThread_GetCurrentId());
  2100. BF_LOGASSERT(obj->mClassVData != 0);
  2101. #ifdef TARGET_TYPE
  2102. if (obj->mBFVData->mType == TARGET_TYPE)
  2103. {
  2104. gMarkTargetCount++;
  2105. printf("Marking target %p\n", obj);
  2106. }
  2107. #endif
  2108. #ifdef BF_GC_LOG_ENABLED
  2109. bf::System::Object* parentObj = NULL;
  2110. if (mMarkDepthCount > 0)
  2111. parentObj = gMarkingObject[mMarkDepthCount-1];
  2112. BFLOG3(GCLog::EVENT_MARK, (intptr)obj, obj->mObjectFlags, (intptr)parentObj);
  2113. #endif
  2114. int maxMarkDepth = 256;
  2115. //int maxMarkDepth = 1;
  2116. obj->mObjectFlags = (BfObjectFlags)((obj->mObjectFlags & ~BF_OBJECTFLAG_MARK_ID_MASK) | mCurMarkId);
  2117. mCurGCMarkCount++;
  2118. //if (obj->mBFVData->BFMarkMembers != NULL)
  2119. {
  2120. mCurGCObjectQueuedCount++;
  2121. #ifdef NO_QUEUE_OBJECTS
  2122. Beefy::AutoCrit autoCrit(mCritSect);
  2123. BFVCALL(obj, BFMarkMembers)();
  2124. #else
  2125. bool allowQueue = true;
  2126. //if ((!mQueueMarkObjects) && (mMarkDepthCount < maxMarkDepth))
  2127. if (mMarkDepthCount < maxMarkDepth)
  2128. {
  2129. #ifdef BF_GC_LOG_ENABLED
  2130. gMarkingObject[mMarkDepthCount] = obj;
  2131. #endif
  2132. mMarkDepthCount++;
  2133. // Try to clear off the list first
  2134. while (!mPendingGCData.IsEmpty())
  2135. {
  2136. bf::System::Object* queuedObj = mPendingGCData.back();
  2137. mPendingGCData.pop_back();
  2138. MarkMembers(queuedObj);
  2139. }
  2140. MarkMembers(obj);
  2141. mMarkDepthCount--;
  2142. }
  2143. else
  2144. {
  2145. if (mPendingGCData.GetFreeCount() > 0)
  2146. {
  2147. mPendingGCData.Add(obj);
  2148. }
  2149. else
  2150. {
  2151. // No more room left -- we can't queue...
  2152. MarkMembers(obj);
  2153. }
  2154. }
  2155. #endif
  2156. }
  2157. #endif
  2158. }
  2159. void BFGC::SetAutoCollectPeriod(int periodMS)
  2160. {
  2161. mFullGCPeriod = periodMS;
  2162. mCollectEvent.Set();
  2163. }
  2164. void BFGC::SetCollectFreeThreshold(int freeBytes)
  2165. {
  2166. mFreeTrigger = freeBytes;
  2167. mCollectEvent.Set();
  2168. }
  2169. void BFGC::SetMaxPausePercentage(int maxPausePercentage)
  2170. {
  2171. mMaxPausePercentage = maxPausePercentage;
  2172. mCollectEvent.Set();
  2173. }
  2174. void BFGC::SetMaxRawDeferredObjectFreePercentage(intptr maxPercentage)
  2175. {
  2176. mMaxRawDeferredObjectFreePercentage = maxPercentage;
  2177. }
  2178. using namespace bf::System;
  2179. void GC::Run()
  2180. {
  2181. #ifdef BF_GC_INCREMENTAL
  2182. gBFGC.Run();
  2183. #endif
  2184. }
  2185. void GC::Init()
  2186. {
  2187. gBFGC.Init();
  2188. }
  2189. void GC::ReportTLSMember(intptr tlsIndex, void* ptr, void* markFunc)
  2190. {
  2191. gBFGC.ReportTLSMember((int)tlsIndex, ptr, markFunc);
  2192. }
  2193. void GC::StopCollecting()
  2194. {
  2195. gBFGC.StopCollecting();
  2196. }
  2197. void GC::AddStackMarkableObject(Object* obj)
  2198. {
  2199. gBFGC.AddStackMarkableObject(obj);
  2200. }
  2201. void GC::RemoveStackMarkableObject(Object* obj)
  2202. {
  2203. gBFGC.RemoveStackMarkableObject(obj);
  2204. }
  2205. void GC::Shutdown()
  2206. {
  2207. gBFGC.Shutdown();
  2208. }
  2209. void GC::Collect(bool async)
  2210. {
  2211. gBFGC.Collect(async);
  2212. }
  2213. void GC::Report()
  2214. {
  2215. gBFGC.Report();
  2216. }
  2217. void GC::Mark(Object* obj)
  2218. {
  2219. gBFGC.MarkFromGCThread(obj);
  2220. }
  2221. void GC::Mark(void* ptr, intptr size)
  2222. {
  2223. gBFGC.ConservativeScan(ptr, (int)size);
  2224. }
  2225. void GC::DebugDumpLeaks()
  2226. {
  2227. gBFGC.DebugDumpLeaks();
  2228. }
  2229. void GC::SetAutoCollectPeriod(intptr periodMS)
  2230. {
  2231. gBFGC.SetAutoCollectPeriod((int)periodMS);
  2232. }
  2233. void GC::SetCollectFreeThreshold(intptr freeBytes)
  2234. {
  2235. gBFGC.SetCollectFreeThreshold((int)freeBytes);
  2236. }
  2237. BFRT_EXPORT void bf::System::GC::SetMaxPausePercentage(intptr maxPausePercentage)
  2238. {
  2239. gBFGC.SetMaxPausePercentage(maxPausePercentage);
  2240. }
  2241. BFRT_EXPORT void bf::System::GC::SetMaxRawDeferredObjectFreePercentage(intptr maxPercentage)
  2242. {
  2243. gBFGC.SetMaxRawDeferredObjectFreePercentage(maxPercentage);
  2244. }
  2245. #else // BF_GC_SUPPORTED
  2246. void* BfObjectAllocate(intptr size, bf::System::Type* type)
  2247. {
  2248. BF_FATAL("Not supported");
  2249. return NULL;
  2250. }
  2251. using namespace bf::System;
  2252. void GC::Run()
  2253. {
  2254. #ifdef BF_GC_INCREMENTAL
  2255. gBFGC.Run();
  2256. #endif
  2257. }
  2258. void GC::Init()
  2259. {
  2260. }
  2261. void GC::ReportTLSMember(intptr tlsIndex, void* ptr, void* markFunc)
  2262. {
  2263. }
  2264. void GC::Shutdown()
  2265. {
  2266. }
  2267. void GC::Collect(bool async)
  2268. {
  2269. }
  2270. void GC::Report()
  2271. {
  2272. }
  2273. void GC::Mark(Object* obj)
  2274. {
  2275. }
  2276. void GC::Mark(void* ptr, intptr size)
  2277. {
  2278. }
  2279. void GC::DebugDumpLeaks()
  2280. {
  2281. }
  2282. void GC::SetAutoCollectPeriod(intptr periodMS)
  2283. {
  2284. }
  2285. void GC::SetCollectFreeThreshold(intptr freeBytes)
  2286. {
  2287. }
  2288. #endif