12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912 |
- //#define BF_GC_DISABLED
- //#define BF_GC_LOG_ENABLED
- #define _WIN32_WINNT _WIN32_WINNT_WIN8
- // This spits out interesting stats periodically to the console
- #define BF_GC_PRINTSTATS
- //TEMPORARY
- //#define BF_GC_DEBUGSWEEP
- //#define BF_GC_EMPTYSCAN
- // Disable efficient new mass-freeing in TCMalloc
- //#define BF_GC_USE_OLD_FREE
- #ifdef BF_DEBUG
- // Useful for tracing down memory corruption -- memory isn't returned to TCMalloc, it's just marked as freed. You'll run out eventually
- //#define BF_NO_FREE_MEMORY
- // Old and not too useful
- //#define BG_GC_TRACKPTRS
- #endif
- #if defined BF_OBJECT_TRACK_ALLOCNUM && defined BF_NO_FREE_MEMORY
- //#define BF_GC_VERIFY_SWEEP_IDS
- #endif
- //#define BF_SECTION_NURSERY
- #ifdef BF_PLATFORM_WINDOWS
- #include <direct.h>
- #endif
- #include "gc.h"
- #ifdef BF_GC_SUPPORTED
- #include <fstream>
- #include "BeefySysLib/Common.h"
- #include "BeefySysLib/BFApp.h"
- #include "BeefySysLib/util/CritSect.h"
- #include "BeefySysLib/util/BeefPerf.h"
- #include "BeefySysLib/util/HashSet.h"
- #include "BeefySysLib/util/Dictionary.h"
- #include "BeefySysLib/util/BinaryHeap.h"
- #include <unordered_set>
- #include "../rt/BfObjects.h"
- #include "../rt/Thread.h"
- #ifdef BF_PLATFORM_WINDOWS
- #include <psapi.h>
- #endif
- #ifndef BF_TCMALLOC_DISABLED
- #define TCMALLOC_NO_MALLOCGUARD
- #define TCMALLOC_NAMESPACE tcmalloc_obj
- #define TCMALLOC_EXTERN static
- #include "gperftools/src/tcmalloc.cc"
- #else
- #define tc_malloc malloc
- #define tc_free free
- #endif
- USING_NS_BF;
- //System::Threading::Thread* gMainThread;
- #include "BeefySysLib/util/PerfTimer.h"
- /*#include "BeefyRtCPP/MonitorManager.h"
- #include "BeefyRtCPP/InternalThread.h"
- #include "BeefyRtCPP/ReflectionData.h"
- #include "BeefyRtCPP/RtCommon_inl.h"
- #include "BeefyRtCPP/BFArray.h"
- #include "BeefyRtCPP/Reflection.h"*/
- extern "C" GCDbgData gGCDbgData = { 0 };
- void BfLog(const char* fmt ...)
- {
- static int lineNum = 0;
- lineNum++;
- static FILE* fp = fopen("dbg_bf.txt", "wb");
- va_list argList;
- va_start(argList, fmt);
- String aResult = vformat(fmt, argList);
- va_end(argList);
- aResult = StrFormat("%d ", lineNum) + aResult;
- fwrite(aResult.c_str(), 1, aResult.length(), fp);
- fflush(fp);
- }
- //////////////////////////////////////////////////////////////////////////
- using Beefy::CritSect;
- BF_TLS_DECLSPEC BFGC::ThreadInfo* BFGC::ThreadInfo::sCurThreadInfo;
- HANDLE gGCHeap = 0;
- #ifdef _DEBUG
- bool gGCGetAllocStats = true;
- #else
- bool gGCGetAllocStats = false;
- #endif
- #ifdef BF_GC_VERIFY_SWEEP_IDS
- static std::set<int> allocIdSet;
- static int maxAllocNum = 0;
- #endif
- int gGCAllocCount = 0;
- int gGCAllocBytes = 0;
- std::vector<int> gGCAllocCountMap;
- std::vector<int> gGCAllocSizeMap;
- struct TCMallocRecord
- {
- void* mPtr;
- int mSize;
- };
- static std::vector<TCMallocRecord> gTCMallocRecords;
- void TCMalloc_RecordAlloc(void* ptr, int size)
- {
- TCMallocRecord mallocRecord = { ptr, size };
- gTCMallocRecords.push_back(mallocRecord);
- }
- static void TCMalloc_FreeAllocs()
- {
- for (auto& record : gTCMallocRecords)
- {
- ::VirtualFree(record.mPtr, 0, MEM_RELEASE);
- }
- gTCMallocRecords.clear();
- }
- void PatchWindowsFunctions()
- {
- // For TCMalloc, don't really patch
- }
- #ifdef BG_GC_TRACKPTRS
- boost::unordered_set<void*> gTrackPtr;
- #endif
- void BFMarkThreadPoolJobs()
- {
- }
- #ifndef BF_MONOTOUCH
- void BFMarkCOMObjects()
- {
- }
- void BFIMarkStackData(BFIThreadData* bfiThreadData)
- {
- }
- #endif
- /*void* sDbgPtr0 = NULL;
- void* sDbgPtr1 = NULL;
- void* sDbgPtr2 = NULL;*/
- void BFGC::MarkMembers(bf::System::Object* obj)
- {
- //BP_ZONE("MarkMembers");
- /*if ((obj == sDbgPtr0) || (obj == sDbgPtr1) || (obj == sDbgPtr2))
- {
- int a = 0;
- }*/
- if (((obj->mObjectFlags & BF_OBJECTFLAG_DELETED) != 0) && (!mMarkingDeleted))
- {
- mMarkingDeleted = true;
- gBfRtDbgCallbacks.Object_GCMarkMembers(obj);
- mMarkingDeleted = false;
- }
- else
- {
- gBfRtDbgCallbacks.Object_GCMarkMembers(obj);
- }
- }
- static void MarkObject(bf::System::Object* obj)
- {
- if ((obj != NULL) && ((obj->mObjectFlags & (BF_OBJECTFLAG_MARK_ID_MASK)) != BFGC::sCurMarkId))
- gBFGC.MarkFromGCThread(obj);
- }
- //////////////////////////////////////////////////////////////////////////
- //AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures;
- namespace tcmalloc
- {
- extern "C" int RunningOnValgrind(void)
- {
- return 0;
- }
- }
- ////////////////////////////////////////////
- BFGC::ThreadInfo::~ThreadInfo()
- {
- if (mThreadHandle != NULL)
- BfpThread_Release(mThreadHandle);
- if (mThreadInfo != NULL)
- BfpThreadInfo_Release(mThreadInfo);
- }
- bool BFGC::ThreadInfo::WantsSuspend()
- {
- #ifndef BP_DISABLED
- BfpThreadId threadId = BpManager::Get()->mThreadId;
- return threadId != (BfpThreadId)mThreadId;
- #else
- return true;
- #endif
- }
- void BFGC::ThreadInfo::CalcStackStart()
- {
- intptr stackBase;
- int stackLimit;
- BfpThreadInfo_GetStackInfo(mThreadInfo, &stackBase, &stackLimit, BfpThreadInfoFlags_NoCache, NULL);
- mStackStart = stackBase;
- }
- //////////////////////////////////////////////////////////////////////////
- #ifdef BF_GC_LOG_ENABLED
- class GCLog
- {
- public:
- enum
- {
- EVENT_ALLOC,
- EVENT_GC_START, // cycle#
- EVENT_GC_UNFREEZE, // cycle#
- EVENT_MARK,
- EVENT_WB_MARK,
- EVENT_THREAD_STARTED,
- EVENT_THREAD_DONE,
- EVENT_SCAN_THREAD,
- EVENT_CONSERVATIVE_SCAN,
- EVENT_FOUND_TARGET,
- EVENT_FINALIZE_LIST,
- EVENT_LEAK,
- EVENT_DELETE,
- EVENT_FOUND,
- EVENT_FREE,
- EVENT_WB_MOVE,
- EVENT_WEAK_REF,
- EVENT_STRONG_REF,
- EVENT_WEAKREF_MARKED,
- EVENT_WEAK,
- EVENT_RESURRECT,
- EVENT_WAS_RESURRECT,
- EVENT_GC_DONE
- };
- class Entry
- {
- public:
- int mEvent;
- intptr mParam1;
- intptr mParam2;
- intptr mParam3;
- };
- Beefy::CritSect mCritSect;
- static const int BUFFSIZE = 4*1024*1024;
- static const int BUFFSIZE_MASK = BUFFSIZE-1;
- Entry mBuffer[BUFFSIZE];
- volatile int mHead;
- volatile int mTail;
- volatile bool mWriting;
- public:
- GCLog()
- {
- mWriting = false;
- }
- void Log(int event, intptr param1 = 0, intptr param2 = 0, intptr param3 = 0)
- {
- if (mWriting)
- {
- // Not a strict guarantee, but should keep us from only messing up
- // more than a single element of the log while we're writing it
- Beefy::AutoCrit autoCrit(mCritSect);
- return;
- }
- BF_FULL_MEMORY_FENCE();
- Entry entry = {event, param1, param2, param3};
-
- int prevHead;
- int nextHead;
- while (true)
- {
- prevHead = mHead;
- nextHead = (mHead + 1) & BUFFSIZE_MASK;
- if (nextHead == mTail)
- {
- int prevTail = mTail;
- int nextTail = (mTail + 1) & BUFFSIZE_MASK;
- if (::InterlockedCompareExchange((uint32*)&mTail, nextTail, prevTail) != prevTail)
- continue; // Try again
- }
- if (::InterlockedCompareExchange((uint32*)&mHead, nextHead, prevHead) == prevHead)
- break;
- }
-
- mBuffer[prevHead] = entry;
- }
- const char* GetNameStr(bf::System::Type* type)
- {
- static Beefy::String str;
- if (type == NULL)
- return "NULL";
- try
- {
- bf::System::Type* bfTypeRoot = (bf::System::Type*)type;
- str = type->GetFullName();
- return str.c_str();
- }
- catch (...)
- {
- return "<invalid>";
- }
- }
- #pragma warning(disable:4477)
- void Write()
- {
- Beefy::AutoCrit autoCrit(mCritSect);
- wchar_t str[MAX_PATH];
- GetCurrentDirectoryW(MAX_PATH, str);
- FILE* fp = fopen("c:\\temp\\gclog.txt", "w");
-
- mWriting = true;
- int sampleHead = mHead;
- BF_FULL_MEMORY_FENCE();
- int sampleTail = mTail;
- BF_FULL_MEMORY_FENCE();
- int pos = sampleTail;
- while (pos != sampleHead)
- {
- Entry ent = mBuffer[pos];
-
- switch (ent.mEvent)
- {
- case EVENT_ALLOC:
- fprintf(fp, "Alloc:%p Type:%s\n", ent.mParam1, GetNameStr((bf::System::Type*)ent.mParam2));
- break;
- case EVENT_GC_START:
- fprintf(fp, "GCStart MarkId:%d Tick:%d\n", ent.mParam1, ent.mParam2);
- break;
- case EVENT_GC_UNFREEZE:
- fprintf(fp, "GCUnfreeze MarkId:%d Tick:%d\n", ent.mParam1, ent.mParam2);
- break;
- case EVENT_MARK:
- fprintf(fp, "GCMark Obj:%p Flags:0x%X Parent:%p\n", ent.mParam1, ent.mParam2, ent.mParam3);
- break;
- case EVENT_WB_MARK:
- fprintf(fp, "WriteBarrierMark Obj:%p Type:%s Thread:%p\n", ent.mParam1, GetNameStr((bf::System::Type*)ent.mParam2), ent.mParam3);
- break;
- case EVENT_WB_MOVE:
- fprintf(fp, "WriteBarrier Entry Move Obj:%p Type:%s Thread:%p\n", ent.mParam1, GetNameStr((bf::System::Type*) ent.mParam2), ent.mParam3);
- break;
- case EVENT_FOUND_TARGET:
- fprintf(fp, "Heap Scan Found Target:%p Type:%s Flags:%d\n", ent.mParam1, GetNameStr((bf::System::Type*)ent.mParam2), ent.mParam3);
- break;
- case EVENT_FINALIZE_LIST:
- fprintf(fp, "On Finalize List:%p\n", ent.mParam1);
- break;
- case EVENT_LEAK:
- fprintf(fp, "Leak Detected:%p Type:%s\n", ent.mParam1, GetNameStr((bf::System::Type*)ent.mParam2));
- break;
- case EVENT_FOUND:
- fprintf(fp, "Found Obj:%p Flags:0x%X\n", ent.mParam1, ent.mParam2);
- break;
- case EVENT_FREE:
- fprintf(fp, "Free Obj:%p\n", ent.mParam1);
- break;
- case EVENT_DELETE:
- fprintf(fp, "Delete Obj:%p\n", ent.mParam1);
- break;
- case EVENT_THREAD_STARTED:
- fprintf(fp, "ThreadStarted:%p TID:%d\n", ent.mParam1, ent.mParam2);
- break;
- case EVENT_THREAD_DONE:
- fprintf(fp, "ThreadDone:%p\n", ent.mParam1);
- break;
- case EVENT_SCAN_THREAD:
- fprintf(fp, "ScanThread:%p Id:%d\n", ent.mParam1, ent.mParam2);
- break;
- case EVENT_CONSERVATIVE_SCAN:
- fprintf(fp, "ConservativeScan:%p to %p\n", ent.mParam1, ent.mParam2);
- break;
- case EVENT_GC_DONE:
- fprintf(fp, "GCDone MarkCount:%d HadOverflow:%d\n", ent.mParam1, ent.mParam2);
- break;
- default:
- BF_FATAL("Unknown event");
- break;
- }
-
- pos = (pos + 1) & BUFFSIZE_MASK;
- }
-
- fclose(fp);
- mWriting = false;
- }
- };
- GCLog gGCLog;
- void BFGCLogWrite()
- {
- gGCLog.Write();
- }
- #define BFLOG(cmd) gGCLog.Log(cmd)
- #define BFLOG1(cmd, param1) gGCLog.Log(cmd, param1)
- #define BFLOG2(cmd, param1, param2) gGCLog.Log(cmd, param1, param2)
- #define BFLOG3(cmd, param1, param2, param3) gGCLog.Log(cmd, param1, param2, param3)
- #else
- #define BFLOG(cmd)
- #define BFLOG1(cmd, param1)
- #define BFLOG2(cmd, param1, param2)
- #define BFLOG3(cmd, param1, param2, param3)
- void BFGCLogWrite() {}
- #endif
- void BFGCLogAlloc(bf::System::Object* obj, bf::System::Type* objType, int allocNum)
- {
- BFLOG3(GCLog::EVENT_ALLOC, (intptr)obj, (intptr)objType, allocNum);
- }
- BfDbgInternalThread* GetCurrentInternalThread()
- {
- return NULL;
- }
- ////////////////////////////////////////////
- static void CheckTcIntegrity()
- {
- auto pageHeap = Static::pageheap();
- if (pageHeap == NULL)
- return;
- #ifdef BF64
- //BP_ZONE("CheckTcIntegrity");
- Beefy::HashSet<tcmalloc_obj::Span*> spanSet;
- int interiorLen = PageHeap::PageMap::INTERIOR_LENGTH;
- int leafLen = PageHeap::PageMap::LEAF_LENGTH;
- for (int pageIdx1 = 0; pageIdx1 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx1++)
- {
- PageHeap::PageMap::Node* node1 = Static::pageheap()->pagemap_.root_->ptrs[pageIdx1];
- if (node1 == NULL)
- continue;
- for (int pageIdx2 = 0; pageIdx2 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx2++)
- {
- PageHeap::PageMap::Node* node2 = node1->ptrs[pageIdx2];
- if (node2 == NULL)
- continue;
- for (int pageIdx3 = 0; pageIdx3 < PageHeap::PageMap::LEAF_LENGTH; pageIdx3++)
- {
- tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)node2->ptrs[pageIdx3];
- if (span != NULL)
- {
- int expectedStartPage = ((pageIdx1 * PageHeap::PageMap::INTERIOR_LENGTH) + pageIdx2) * PageHeap::PageMap::LEAF_LENGTH + pageIdx3;
- if (span->start == expectedStartPage)
- {
- auto result = spanSet.Add(span);
- BF_ASSERT(result);
- }
- }
- }
- }
- }
- int spansFound = spanSet.size();
- #endif
- }
- ////////////////////////////////////////////
- void BFCheckSuspended()
- {
- BfInternalThread* internalThread = (BfInternalThread*)GetCurrentInternalThread();
- if ((internalThread != NULL) && (internalThread->mIsSuspended))
- {
- internalThread = (BfInternalThread*)GetCurrentInternalThread();
- printf("IsSuspended\n");
- }
- BF_ASSERT((internalThread == NULL) || (!internalThread->mIsSuspended));
- }
- void* BfObjectAllocate(intptr size, bf::System::Type* objType)
- {
- bf::System::Object* obj = (bf::System::Object*)tc_malloc(size);
- BFLOG2(GCLog::EVENT_ALLOC, (intptr)obj, (intptr)objType);
- //CheckTcIntegrity();
- gBFGC.mBytesRequested += size;
- // #ifdef BF_GC_PRINTSTATS
- // ::InterlockedIncrement((volatile uint32*)&gBFGC.mTotalAllocs);
- // #endif
-
- #ifdef BG_GC_TRACKPTRS
- {
- Beefy::AutoCrit autoCrit(gBFGC.mCritSect);
- BF_LOGASSERT(gTrackPtr.find(obj) == gTrackPtr.end());
- gTrackPtr.insert(obj);
- }
- #endif
-
- #ifdef _DEBUG
- BF_LOGASSERT((obj->mAllocCheckPtr == 0) || (size > kMaxSize));
- #endif
- //memset((void*)obj, 0, size);
- #ifdef BF_OBJECT_TRACK_ALLOCNUM
- obj->mAllocNum = (int)::InterlockedIncrement((volatile uint32*) &BfObject::sCurAllocNum);
- #endif
-
- #ifdef BF_SECTION_NURSERY
- BfInternalThread* internalThread = (BfInternalThread*)bf::System::Threading::Thread::CurrentInternalThread_internal();
- if ((internalThread != NULL) && (internalThread->mSectionDepth == 1))
- internalThread->mSectionNursery.PushUnsafe(obj);
- #endif
-
- gBFGC.mAllocSinceLastGC += size;
-
- return obj;
- }
- //////////////////////////////////////////////////////////////////////////
- #define BF_GC_MAX_PENDING_OBJECT_COUNT 16*1024
- ///
- ///
- class BFFinalizeData
- {
- public:
- int mFinalizeCount;
- bool mInFinalizeList;
- public:
- BFFinalizeData()
- {
- mFinalizeCount = 1;
- mInFinalizeList = false;
- }
- };
- ///
- BFGC gBFGC;
- int volatile BFGC::sCurMarkId = 1;
- int volatile BFGC::sAllocFlags = 1;
- int gBFCRTAllocSize = 0;
- BFGC::BFGC()
- {
- mRunning = false;
- mExiting = false;
- mPaused = false;
- mShutdown = false;
- mForceDecommit = false;
- mCollectFailed = false;
- mLastCollectFrame = 0;
- mSkipMark = false;
- mGracelessShutdown = false;
- mMainThreadTLSPtr = NULL;
- mHadPendingGCDataOverflow = false;
- mCurPendingGCSize = 0;
- mMaxPendingGCSize = 0;
-
- mCollectIdx = 0;
- mStackScanIdx = 0;
- mMarkDepthCount = 0;
- mMarkingDeleted = false;
- mCurMutatorMarkCount = 0;
- mCurGCMarkCount = 0;
- mCurFreedBytes = 0;
- sCurMarkId = 1;
- mQueueMarkObjects = false;
- //mEphemeronTombstone = NULL;
- mWaitingForGC = false;
- mCollectRequested = false;
- mAllocSinceLastGC = 0;
- mFullGCTriggered = false;
- mDebugDumpState = 0;
- mCurScanIdx = 1;
- mTotalAllocs = 0;
- mTotalFrees = 0;
- mLastFreeCount = 0;
- mBytesFreed = 0;
- mBytesRequested = 0;
- mRequestedSizesInvalid = false;
- mDisplayFreedObjects = false;
- mHadRootError = false;
- mCurLiveObjectCount = 0;
- mFreeSinceLastGC = 0;
- // Default to just over two 60Hz frames
- // This keeps stack scanning from adding excessive costs to a 30Hz app, or
- // from impacting two successive frames in a triple-buffered 60Hz app where
- // only one slow frame could be absorbed
- mMultiStackScanWait = 35;
- // By default we collect after freeing 64MB
- mFreeTrigger = 64*1024*1024;
- mMaxPausePercentage = 20;
- mMaxRawDeferredObjectFreePercentage = 30;
-
- // Zero means to run continuously. -1 means don't trigger on a time base
- // Defaults to collecting every 2 seconds
- mFullGCPeriod = 2000;
- mGCThread = NULL;
- gGCDbgData.mDbgFlags = gBfRtDbgFlags;
- ThreadCache::InitTSD();
- if (UNLIKELY(Static::pageheap() == NULL)) ThreadCache::InitModule();
- gGCDbgData.mObjRootPtr = Static::pageheap()->pagemap_.root_;
- for (int i = 0; i < kNumClasses; i++)
- gGCDbgData.mSizeClasses[i] = Static::sizemap()->ByteSizeForClass(i);
- mStats = NULL;
- Beefy::String memName = StrFormat("BFGC_stats_%d", GetCurrentProcessId());
- auto* fileMapping = ::CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Stats), memName.c_str());
- if (fileMapping != NULL)
- {
- mStats = (Stats*)MapViewOfFile(fileMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(Stats));
- mStats->mHeapSize = 0;
- }
- RawInit();
- }
- BFGC::~BFGC()
- {
- //::HeapDestroy(gGCHeap);
- //gGCHeap = NULL;
- Beefy::AutoCrit autoCrit(mCritSect);
- for (auto thread : mThreadList)
- {
- delete thread;
- }
- }
- /*inline T BFWB(typename BFToType<T>::type::BFBaseObjectInObject obj)
- {
- if ((obj != NULL) && ((obj->mBFMonitorPtrAndObjFlags & (BF_OBJECTFLAG_MARK_ID_MASK)) != BFGC::sCurMarkId))
- gBFGC.MarkFromMutator(obj, 0);
- return (T) obj;
- }*/
- /*void BFGC::RegisterRoot(bf::System::Object* obj)
- {
- Beefy::AutoCrit autoCrit(mCritSect);
- mExplicitRoots.push_back(obj);
- if (mRunning)
- BFWB(obj);
- }*/
- #ifdef BF32
- static tcmalloc_obj::Span* TCGetSpanAt(void* addr)
- {
- int checkPageId = (int)((uintptr)addr >> kPageShift);
- int checkRootIdx = checkPageId >> PageHeap::PageMap::LEAF_BITS;
- int checkLeafIdx = checkPageId & (PageHeap::PageMap::LEAF_LENGTH - 1);
- PageHeap::PageMap::Leaf* rootLeaf = Static::pageheap()->pagemap_.root_[checkRootIdx];
- if (rootLeaf == NULL)
- return NULL;
- auto span = (tcmalloc_obj::Span*)rootLeaf->values[checkLeafIdx];
- // intptr pageSize = (intptr)1 << kPageShift;
- // int spanSize = pageSize * span->length;
- // void* spanStart = (void*)((intptr)span->start << kPageShift);
- // void* spanEnd = (void*)((intptr)spanStart + spanSize);
- // if ((addr >= spanStart) && (addr < spanEnd))
- // return span;
- return span;
- }
- #else
- static tcmalloc_obj::Span* TCGetSpanAt(void* addr)
- {
- int64 checkPageId = (int64)((uintptr)addr >> kPageShift);
- int pageIdx1 = (int)(checkPageId >> (PageHeap::PageMap::LEAF_BITS + PageHeap::PageMap::INTERIOR_BITS));
- int pageIdx2 = (int)((checkPageId >> PageHeap::PageMap::LEAF_BITS) & (PageHeap::PageMap::INTERIOR_LENGTH-1));
- int pageIdx3 = (int)(checkPageId & (PageHeap::PageMap::LEAF_LENGTH-1));
- PageHeap::PageMap::Node* node1 = Static::pageheap()->pagemap_.root_->ptrs[pageIdx1];
- if (node1 == NULL)
- return NULL;
- PageHeap::PageMap::Node* node2 = node1->ptrs[pageIdx2];
- if (node2 == NULL)
- return NULL;
- auto span = (tcmalloc_obj::Span*)node2->ptrs[pageIdx3];
- return span;
- // if (span == NULL)
- // return NULL;
- // intptr pageSize = (intptr)1 << kPageShift;
- // int spanSize = pageSize * span->length;
- // void* spanStart = (void*)((intptr)span->start << kPageShift);
- // void* spanEnd = (void*)((intptr)spanStart + spanSize);
- // if ((addr >= spanStart) && (addr < spanEnd))
- // return span;
- // return NULL;
- }
- #endif
- int gTargetFoundCount = 0;
- int gMarkTargetCount = 0;
- int gMarkTargetMutatorCount = 0;
- int BFGetObjectSize(bf::System::Object* obj)
- {
- // auto span = TCGetSpanAt(obj);
- // int elementSize = Static::sizemap()->ByteSizeForClass(span->sizeclass);
- // if (elementSize != 0)
- // return elementSize;
- // intptr pageSize = (intptr)1 << kPageShift;
- // int spanSize = pageSize * span->length;
- // return spanSize;
- const PageID p = reinterpret_cast<uintptr_t>(obj) >> kPageShift;
- size_t cl = Static::pageheap()->GetSizeClassIfCached(p);
- int allocSize = 0;
- if (cl == 0)
- {
- auto span = Static::pageheap()->GetDescriptor(p);
- if (span != NULL)
- {
- cl = span->sizeclass;
- if (cl == 0)
- {
- allocSize = span->length << kPageShift;
- }
- }
- }
- if (cl != 0)
- allocSize = Static::sizemap()->class_to_size(cl);
- return allocSize;
- }
- void BFCheckObjectSize(bf::System::Object* obj, int size)
- {
- if (gBFGC.mRunning)
- {
- BF_ASSERT(BFGetObjectSize(obj) == size);
- }
- }
- void BFGC::ConservativeScan(void* startAddr, int length)
- {
- if ((gBfRtDbgFlags & BfRtFlags_ObjectHasDebugFlags) == 0)
- return;
- BFLOG2(GCLog::EVENT_CONSERVATIVE_SCAN, (intptr)startAddr, (intptr)startAddr + length);
-
- void* ptr = (void*)((intptr)startAddr & ~((sizeof(intptr)-1)));
- void* endAddr = (uint8*)startAddr + length;
- __try
- {
- while (ptr < endAddr)
- {
- void* addr = *(void**)ptr;
- MarkFromGCThread((bf::System::Object*)addr);
- ptr = (uint8*)ptr + sizeof(intptr);
- }
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- }
- }
- static tcmalloc_obj::Span* gLastSpan = NULL;
- bool BFGC::IsHeapObject(bf::System::Object* obj)
- {
- //BP_ZONE("IsHeapObject");
- if ((obj >= tcmalloc_obj::PageHeap::sAddressStart) && (obj < tcmalloc_obj::PageHeap::sAddressEnd))
- {
- tcmalloc_obj::Span* span = TCGetSpanAt(obj);
- gLastSpan = span;
- return span != NULL;
- }
- return false;
- }
- /*void BFGC::MarkTypeStatics(BFTypeRoot* checkType)
- {
- BFTypeRoot* innerCheckType = (BFTypeRoot*)checkType->mFirstNestedType;
- while (innerCheckType != NULL)
- {
- MarkTypeStatics(innerCheckType);
- innerCheckType = (BFTypeRoot*)innerCheckType->mNextSibling;
- }
- if (checkType->mTypeRootData->mTypeFlags & BF_TYPEFLAG_GENERIC_DEF_TYPE)
- return;
- if (checkType->mTypeRootData->mBFMarkStatics != NULL)
- checkType->mTypeRootData->mBFMarkStatics();
- }
- void BFGC::MarkStatics()
- {
- BFMark(bf::System::Object::sTypeLockObject);
- BFAppDomain* bfDomain = BFAppDomain::GetAppDomain();
- for (int assemblyIdx = 0; assemblyIdx < (int) bfDomain->mBFAssemblyVector.size(); assemblyIdx++)
- {
- BFAssembly* assembly = bfDomain->mBFAssemblyVector[assemblyIdx];
- BFTypeRoot* outerCheckType = (BFTypeRoot*)assembly->mFirstType;
- while (outerCheckType != NULL)
- {
- MarkTypeStatics(outerCheckType);
- outerCheckType = (BFTypeRoot*)outerCheckType->mNextSibling;
- }
- }
- BFType::BFMarkStatics();
- }*/
- void BFGC::MarkStatics()
- {
- bf::System::GC::DoMarkAllStaticMembers();
- //MarkObject(gMainThread);
- }
- void BFGC::ObjectDeleteRequested(bf::System::Object* obj)
- {
- if (mFreeTrigger >= 0)
- {
- int objSize = BFGetObjectSize(obj);
- if (BfpSystem_InterlockedExchangeAdd32((uint32*)&mFreeSinceLastGC, (uint32)objSize) + objSize >= mFreeTrigger)
- {
- mFreeSinceLastGC = 0;
- Collect(true);
- }
- BFLOG1(GCLog::EVENT_DELETE, (intptr)obj);
- }
- }
- bool BFGC::HandlePendingGCData()
- {
- int count = 0;
-
- while (true)
- {
- if (mOrderedPendingGCData.IsEmpty())
- break;
-
- mCurPendingGCSize = 0;
- bf::System::Object* obj = mOrderedPendingGCData.Pop();
- MarkMembers(obj);
- count++;
- if (mCurPendingGCSize > mMaxPendingGCSize)
- mMaxPendingGCSize = mCurPendingGCSize;
- }
- return count > 0;
- }
- void BFGC::SweepSpan(tcmalloc_obj::Span* span, int expectedStartPage)
- {
- if ((gBfRtDbgFlags & BfRtFlags_ObjectHasDebugFlags) == 0)
- return;
- if (span->location != tcmalloc_obj::Span::IN_USE)
- return;
- if (span->start != expectedStartPage)
- {
- // This check covers when a new multi-page span is being put into place
- // and we catch after the first block, and it also catches the case
- // when the allocator splits a span and the pagemap can hold a reference
- // to a span that no longer covers that location.
- // For both of these cases we ignore the span. Remember, the worst case
- // here is that we'll miss a sweep of an object, which would just delay it's
- // cleanup until next GC cycle. Because the GC is the sole freer of spans,
- // there can never be a case where we find a valid span and then the span
- // changes sizeclass or location before we can scan the memory it points to.
- //
- // This also covers the case where a page spans over a radix map section and
- // we catch it on an outer loop again
- return;
- }
- intptr pageSize = (intptr)1<<kPageShift;
- intptr spanSize = pageSize * span->length;
- void* spanStart = (void*)((intptr)span->start << kPageShift);
- void* spanEnd = (void*)((intptr)spanStart + spanSize);
- void* spanPtr = spanStart;
- BF_LOGASSERT((spanStart >= tcmalloc_obj::PageHeap::sAddressStart) && (spanEnd <= tcmalloc_obj::PageHeap::sAddressEnd));
-
- intptr elementSize = Static::sizemap()->ByteSizeForClass(span->sizeclass);
- if (elementSize == 0)
- elementSize = spanSize;
- BF_LOGASSERT(elementSize >= sizeof(bf::System::Object));
-
- while (spanPtr <= (uint8*)spanEnd - elementSize)
- {
- //objCheckCount++;
- bf::System::Object* obj = (bf::System::Object*)spanPtr;
- #ifdef TARGET_TYPE
- if ((obj->mAllocCheckPtr != 0) && (obj->mBFVData->mType == TARGET_TYPE))
- {
- //sweepFoundCount++;
- }
- #endif
- // 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
- int deleteMarkId = mCurMarkId - 1;
- if (deleteMarkId == 0)
- deleteMarkId = 3;
-
- int invalidMarkId = deleteMarkId - 1;
- if (invalidMarkId == 0)
- invalidMarkId = 3;
- bool showAllAsLeaks = !mRunning;
- if (obj->mAllocCheckPtr != 0)
- {
- #ifdef BF_GC_VERIFY_SWEEP_IDS
- BF_LOGASSERT(obj->mAllocNum != 0);
- BF_LOGASSERT(allocIdSet.find(obj->mAllocNum) == allocIdSet.end());
- allocIdSet.insert(obj->mAllocNum);
- #endif
-
- mCurSweepFoundCount++;
- int objectFlags = obj->mObjectFlags;
- if (objectFlags == 0)
- mCurSweepFoundPermanentCount++;
-
- BFLOG2(GCLog::EVENT_FOUND, (intptr)obj, obj->mObjectFlags);
- int markId = objectFlags & BF_OBJECTFLAG_MARK_ID_MASK;
- if ((mCollectFailed) && (markId != mCurMarkId))
- {
- obj->mObjectFlags = (BfObjectFlags)((obj->mObjectFlags & ~BF_OBJECTFLAG_MARK_ID_MASK) | mCurMarkId);
- markId = mCurMarkId;
- }
- BF_ASSERT(markId != invalidMarkId);
- if (markId == 0)
- {
- // Newly-allocated! Set mark flag now...
- //obj->mObjectFlags = (BfObjectFlags)(obj->mObjectFlags | mCurMarkId);
- // Newly-allocated! Ignore, it will have its mark set soon (rare race condition)
- }
- else if ((markId == deleteMarkId) || (mSweepInfo.mShowAllAsLeaks))
- {
- if ((objectFlags & BF_OBJECTFLAG_DELETED) == 0)
- {
- if (!mSweepInfo.mEmptyScan)
- {
- // We set this to cause an error like:
- // Deleting an object that was detected as leaked (internal error)
- obj->mObjectFlags = (BfObjectFlags)(objectFlags | BF_OBJECTFLAG_STACK_ALLOC);
- if (!mHadRootError)
- {
- mSweepInfo.mLeakCount++;
- if (mSweepInfo.mLeakCount <= 1024 * 1024) // Have SOME limit
- {
- mSweepInfo.mLeakObjects.push_back(obj);
- }
- BFLOG2(GCLog::EVENT_LEAK, (intptr)obj, (intptr)obj->_GetType());
- #ifdef BF_GC_LOG_ENABLED
- gGCLog.Write();
- #endif
- }
- }
- }
- else
- {
- if (!mSweepInfo.mEmptyScan)
- {
- BFLOG1(GCLog::EVENT_FINALIZE_LIST, (intptr)obj);
- //obj->mObjectFlags = (BfObjectFlags) (obj->mObjectFlags & ~BF_OBJECTFLAG_FINALIZE_MAP);
- mFinalizeList.push_back(obj);
- }
- }
- }
- else
- mCurLiveObjectCount++;
- }
- spanPtr = (void*)((intptr)spanPtr + elementSize);
- }
- }
- void BFGC::Sweep()
- {
- BP_ZONE("Sweep");
- mCurLiveObjectCount = 0;
- auto pageHeap = Static::pageheap();
- if (pageHeap == NULL)
- return;
- #ifdef BF_GC_VERIFY_SWEEP_IDS
- maxAllocNum = bf::System::Object::sCurAllocNum;
- allocIdSet.clear();
- #endif
- int leafCheckCount = 0;
- int bits = kAddressBits;
- int leafLen = PageHeap::PageMap::LEAF_LENGTH;
- #ifdef BF32
- for (int rootIdx = 0; rootIdx < PageHeap::PageMap::ROOT_LENGTH; rootIdx++)
- {
- PageHeap::PageMap::Leaf* rootLeaf = Static::pageheap()->pagemap_.root_[rootIdx];
- if (rootLeaf == NULL)
- continue;
- for (int leafIdx = 0; leafIdx < PageHeap::PageMap::LEAF_LENGTH; leafIdx++)
- {
- leafCheckCount++;
- tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)rootLeaf->values[leafIdx];
- if (span != NULL)
- {
- int expectedStartPage = (rootIdx * PageHeap::PageMap::LEAF_LENGTH) + leafIdx;
- SweepSpan(span, expectedStartPage);
- // We may be tempted to advance by span->length here, BUT
- // let us just scan all leafs becuause span data is
- // sometimes invalid and a long invalid span can cause
- // us to skip over an actual valid span
- }
- }
- }
- #else
- int interiorLen = PageHeap::PageMap::INTERIOR_LENGTH;
- for (int pageIdx1 = 0; pageIdx1 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx1++)
- {
- PageHeap::PageMap::Node* node1 = Static::pageheap()->pagemap_.root_->ptrs[pageIdx1];
- if (node1 == NULL)
- continue;
- for (int pageIdx2 = 0; pageIdx2 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx2++)
- {
- PageHeap::PageMap::Node* node2 = node1->ptrs[pageIdx2];
- if (node2 == NULL)
- continue;
- for (int pageIdx3 = 0; pageIdx3 < PageHeap::PageMap::LEAF_LENGTH; pageIdx3++)
- {
- leafCheckCount++;
- tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)node2->ptrs[pageIdx3];
- if (span != NULL)
- {
- int expectedStartPage = ((pageIdx1 * PageHeap::PageMap::INTERIOR_LENGTH) + pageIdx2) * PageHeap::PageMap::LEAF_LENGTH + pageIdx3;
- SweepSpan(span, expectedStartPage);
- // We may be tempted to advance by span->length here, BUT
- // let us just scan all leafs becuause span data is
- // sometimes invalid and a long invalid span can cause
- // us to skip over an actual valid span
- }
- }
- }
- }
- #endif
- #ifdef BF_GC_VERIFY_SWEEP_IDS
- for (int allocNum = 1; allocNum < maxAllocNum; allocNum++)
- {
- BF_LOGASSERT(allocIdSet.find(allocNum) != allocIdSet.end());
- }
- #endif
- }
- extern Beefy::StringT<0> gDbgErrorString;
- void BFGC::ProcessSweepInfo()
- {
- if (mSweepInfo.mLeakCount > 0)
- {
- if (mSweepInfo.mShowAllAsLeaks)
- {
- // We aren't certain of the mark flags, so force the issue
- mCurMarkId = 0;
- for (auto obj : mSweepInfo.mLeakObjects)
- {
- obj->mObjectFlags = (BfObjectFlags)((obj->mObjectFlags & ~BF_OBJECTFLAG_MARK_ID_MASK) | mCurMarkId);
- }
- mCurMarkId = 1;
- }
- for (auto obj : mSweepInfo.mLeakObjects)
- {
- MarkMembers(obj);
- }
- //::MessageBoxA(NULL, "Leak", "Leak", MB_OK);
- //#if 0
- Beefy::StringT<1024> errorStr = StrFormat("%d object memory leak%s detected.\nMouse over an 'i' icon in the Output panel to view a leaked object and its allocation stack trace.",
- mSweepInfo.mLeakCount, (mSweepInfo.mLeakCount != 1) ? "s" : "");
- gDbgErrorString = errorStr;
- gDbgErrorString += "\n";
- #ifdef BF_GC_DEBUGSWEEP
- Sleep(100);
- #endif
- for (int pass = 0; pass < 2; pass++)
- {
- int passLeakCount = 0;
- for (auto obj : mSweepInfo.mLeakObjects)
- {
- bool wantsNoRefs = pass == 0;
- bool hasNoRefs = (obj->mObjectFlags & BF_OBJECTFLAG_MARK_ID_MASK) != mCurMarkId;
- if (hasNoRefs != wantsNoRefs)
- continue;
-
- Beefy::String typeName = obj->GetTypeName();
-
- if (passLeakCount == 0)
- {
- Beefy::String header = (pass == 0) ? " Unreferenced:\n" : " Referenced by other leaked objects:\n";
- errorStr += "\x1";
- errorStr += "TEXT\t";
- errorStr += header;
- gDbgErrorString += header;
- }
- if (passLeakCount == 20000) // Only display so many...
- break;
- errorStr += "\x1";
- errorStr += StrFormat("LEAK\t(System.Object)0x%@\n", obj);
- errorStr += StrFormat(" (%s)0x%@\n", typeName.c_str(), obj);
- if (gDbgErrorString.length() < 256)
- gDbgErrorString += StrFormat(" (%s)0x%@\n", typeName.c_str(), obj);
- passLeakCount++;
- }
- }
- //TODO: Testing!
- //OutputDebugStrF(gDbgErrorString.c_str());
- gBfRtDbgCallbacks.SetErrorString(gDbgErrorString.c_str());
- gBfRtDbgCallbacks.DebugMessageData_SetupError(errorStr.c_str(), 1);
-
- mCritSect.Unlock();
- BF_DEBUG_BREAK();
- mCritSect.Lock();
- for (auto obj : mSweepInfo.mLeakObjects)
- {
- // Allow continuing
- obj->mObjectFlags = (BfObjectFlags)((obj->mObjectFlags & ~BF_OBJECTFLAG_MARK_ID_MASK) | mCurMarkId);
- }
- }
- mSweepInfo.Clear();
- }
- void BFGC::ReleasePendingSpanObjects(Span* span)
- {
- if (span->freeingObjects != NULL)
- {
- Static::central_cache()[span->sizeclass].ReleasePendingSpanObjects(span);
- span->freeingObjects = NULL;
- span->freeingObjectsTail = NULL;
- }
- }
- void BFGC::ReleasePendingObjects()
- {
- BP_ZONE("ReleasePendingObjects");
-
- auto pageHeap = Static::pageheap();
- if (pageHeap == NULL)
- return;
- #ifdef BF_GC_VERIFY_SWEEP_IDS
- maxAllocNum = bf::System::Object::sCurAllocNum;
- allocIdSet.clear();
- #endif
-
- int leafCheckCount = 0;
-
- #ifdef BF32
- for (int rootIdx = 0; rootIdx < PageHeap::PageMap::ROOT_LENGTH; rootIdx++)
- {
- PageHeap::PageMap::Leaf* rootLeaf = Static::pageheap()->pagemap_.root_[rootIdx];
- if (rootLeaf == NULL)
- continue;
-
- for (int leafIdx = 0; leafIdx < PageHeap::PageMap::LEAF_LENGTH; leafIdx++)
- {
- tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)rootLeaf->values[leafIdx];
- if (span != NULL)
- ReleasePendingSpanObjects(span);
- }
- }
- #else
- for (int pageIdx1 = 0; pageIdx1 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx1++)
- {
- PageHeap::PageMap::Node* node1 = Static::pageheap()->pagemap_.root_->ptrs[pageIdx1];
- if (node1 == NULL)
- continue;
- for (int pageIdx2 = 0; pageIdx2 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx2++)
- {
- PageHeap::PageMap::Node* node2 = node1->ptrs[pageIdx2];
- if (node2 == NULL)
- continue;
- for (int pageIdx3 = 0; pageIdx3 < PageHeap::PageMap::LEAF_LENGTH; pageIdx3++)
- {
- tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)node2->ptrs[pageIdx3];
- if (span != NULL)
- ReleasePendingSpanObjects(span);
- }
- }
- }
- #endif
-
- #ifdef BF_GC_VERIFY_SWEEP_IDS
- for (int allocNum = 1; allocNum < maxAllocNum; allocNum++)
- {
- BF_LOGASSERT(allocIdSet.find(allocNum) != allocIdSet.end());
- }
- #endif
- }
- typedef struct _TEB {
- PVOID Reserved1[11];
- void* ThreadLocalStorage;
- void* ProcessEnvironmentBlock;
- PVOID Reserved2[399];
- BYTE Reserved3[1952];
- PVOID TlsSlots[64];
- BYTE Reserved4[8];
- PVOID Reserved5[26];
- PVOID ReservedForOle;
- PVOID Reserved6[4];
- PVOID TlsExpansionSlots;
- } TEB, *PTEB;
- typedef LONG NTSTATUS;
- typedef DWORD KPRIORITY;
- typedef WORD UWORD;
- typedef struct _CLIENT_ID
- {
- PVOID UniqueProcess;
- PVOID UniqueThread;
- } CLIENT_ID, *PCLIENT_ID;
- typedef struct _THREAD_BASIC_INFORMATION
- {
- NTSTATUS ExitStatus;
- PVOID TebBaseAddress;
- CLIENT_ID ClientId;
- KAFFINITY AffinityMask;
- KPRIORITY Priority;
- KPRIORITY BasePriority;
- } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
- enum THREADINFOCLASS
- {
- ThreadBasicInformation,
- };
- static _TEB* GetTEB(HANDLE hThread)
- {
- bool loadedManually = false;
- HMODULE module = GetModuleHandleA("ntdll.dll");
- if (!module)
- {
- module = LoadLibraryA("ntdll.dll");
- loadedManually = true;
- }
- NTSTATUS(__stdcall *NtQueryInformationThread)(HANDLE ThreadHandle, THREADINFOCLASS ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength);
- NtQueryInformationThread = reinterpret_cast<decltype(NtQueryInformationThread)>(GetProcAddress(module, "NtQueryInformationThread"));
- if (NtQueryInformationThread)
- {
- NT_TIB tib = { 0 };
- THREAD_BASIC_INFORMATION tbi = { 0 };
- NTSTATUS status = NtQueryInformationThread(hThread, ThreadBasicInformation, &tbi, sizeof(tbi), nullptr);
- if (status >= 0)
- {
- _TEB* teb = (_TEB*)tbi.TebBaseAddress;
- return teb;
- }
- }
- if (loadedManually)
- {
- FreeLibrary(module);
- }
- return NULL;
- }
- static void** GetThreadLocalAddressMap(HANDLE hThread)
- {
- _TEB* teb = GetTEB(hThread);
- if (teb == NULL)
- return NULL;
- return (void**)teb->ThreadLocalStorage;
- }
- void BFGC::AdjustStackPtr(intptr& addr, int& size)
- {
- int pageSize = 4096;
- // There's a race condition where RSP can be adjusted into a guard page region before the
- // guard page is actually removed. The guard page is a fire-once error so we can't just
- // ignore it or else we rob that read of it's ability to expand (crash)
- while (size > 0)
- {
- MEMORY_BASIC_INFORMATION memoryInfo;
- int returnSize = ::VirtualQuery((void*)addr, &memoryInfo, sizeof(memoryInfo));
- if ((returnSize > 0) && ((memoryInfo.Protect & (PAGE_GUARD | PAGE_NOACCESS)) == 0))
- return;
-
- addr += pageSize;
- size -= pageSize;
- }
- }
- bool BFGC::ScanThreads()
- {
- BP_ZONE("BFGC::ScanThreads");
-
- mUsingThreadUnlocked = true;
- BF_FULL_MEMORY_FENCE();
- //BP_ZONE("ScanThreads");
-
- bool didWork = false;
-
- mStackScanIdx++;
- mDoStackDeepMark = true;
-
- int threadIdx = 0;
- while (true)
- {
- ThreadInfo* thread = NULL;
-
- ///
- {
- AutoCrit autoCrit(mCritSect);
- for (auto& kv : mPendingThreads)
- {
- MarkFromGCThread(kv.mValue->mThread);
- }
- }
- ///
- {
- AutoCrit autoCrit(mCritSect);
- if (threadIdx >= mThreadList.size())
- break;
- thread = mThreadList[threadIdx++];
- }
- if (thread->mExcluded)
- continue;
- if (!thread->mRunning)
- {
- AutoCrit autoCrit(mCritSect);
- BF_ASSERT(mThreadList[threadIdx - 1] == thread);
- delete thread;
- mThreadList.RemoveAt(threadIdx - 1);
- continue;
- }
- BP_ZONE_F("ThreadCollect %d", thread->mThreadId);
- //Beefy::DebugTimeGuard suspendTimeGuard(10, "ThreadSuspend");
- DWORD result = 0;
-
- //BFMark(thread);
- //MarkObject(thread->mThread);
- // If (thread->mLastGCScanIdx == mCurScanIdx), that means this is the second cycle of running through here,
- // which could happen if we added another thread while scanning so we need another pass tSuspendThreadhrough to
- // catch the new one
- if (((mGCThread != NULL) && (thread->mThreadHandle == mGCThread)) ||
- (!thread->mRunning) /*|| (thread->mLastGCScanIdx == mCurScanIdx)*/)
- {
- continue;
- }
- #ifdef BF_GC_LOG_ENABLED
- // 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
- while (gGCLog.mWriting)
- {
- Sleep(20);
- }
- #endif
-
- //printf("Processing Thread:%p Handle:%p\n", thread, thread->mThreadHandle);
- //suspendTimeGuard.Start();
- //DWORD lastError = GetLastError();
- BF_LOGASSERT(result == 0);
-
- didWork = true;
- BFLOG2(GCLog::EVENT_SCAN_THREAD, (intptr)thread, (intptr)thread->mThreadId);
- //
- {
- BP_ZONE("StackMarkableObjects");
- for (auto obj : thread->mStackMarkableObjects)
- {
- MarkMembers(obj);
- }
- }
- intptr regVals[128];
- intptr stackPtr = 0;
- BfpThreadResult threadResult;
- int regValCount = 128;
- ///
- {
- BP_ZONE("BfpThread_GetIntRegisters");
- BfpThread_GetIntRegisters(thread->mThreadHandle, &stackPtr, regVals, ®ValCount, &threadResult);
- }
- if (threadResult != BfpThreadResult_Ok)
- {
- mCollectFailed = true;
- return false;
- }
- BF_ASSERT(threadResult == BfpThreadResult_Ok);
-
- if (thread->mTEB != NULL)
- {
- void** threadLoadAddressMap = (void**)((_TEB*)thread->mTEB)->ThreadLocalStorage;
- for (auto& tlsMember : mTLSMembers)
- {
- void* threadLoadAddress = threadLoadAddressMap[tlsMember.mTLSIndex];
- typedef void(*MarkFunc)(void*);
- MarkFunc markFunc = *(MarkFunc*)&tlsMember.mMarkFunc;
- markFunc((uint8*)threadLoadAddress + tlsMember.mTLSOffset);
- }
- }
-
- mQueueMarkObjects = true;
- ConservativeScan(regVals, regValCount * sizeof(intptr));
- intptr prevStackStart = thread->mStackStart;
- thread->CalcStackStart();
- thread->mLastStackPtr = stackPtr;
- int length = thread->mStackStart - stackPtr;
-
- AdjustStackPtr(stackPtr, length);
- {
- BP_ZONE("ConservativeScan stack");
- ConservativeScan((void*)stackPtr, length);
- }
- mQueueMarkObjects = false;
- if (mDoStackDeepMark)
- {
- HandlePendingGCData();
- }
- //suspendTimeGuard.Stop();
- BF_LOGASSERT(result != -1);
- if ((!mOrderedPendingGCData.IsEmpty()) || (!mOrderedPendingGCData.IsEmpty()))
- {
- BP_ZONE("HandlePendingGCData(Thread)");
- HandlePendingGCData();
- }
- }
- // This can be write barrier objects be from dead threads
- HandlePendingGCData();
- BF_FULL_MEMORY_FENCE();
- mUsingThreadUnlocked = false;
- return didWork;
- }
- int gAddedTypeCount = 0;
- int gGCTypeCounts = 0;
- int gGCAssemblyCount = 0;
- static void GCObjFree(void* ptr)
- {
- Span* span = TCGetSpanAt(ptr);
- if (span == NULL)
- {
- BF_DBG_FATAL("Bad");
- tc_free(ptr);
- return;
- }
- if (span->sizeclass == 0)
- {
- // Clear out all memory
- intptr pageSize = (intptr)1 << kPageShift;
- int spanSize = pageSize * span->length;
- void* spanStart = (void*)((intptr)span->start << kPageShift);
- memset(spanStart, 0, spanSize);
- tc_free(ptr);
- return;
- }
-
-
- int size = Static::sizemap()->class_to_size(span->sizeclass);
- int dataOffset = (int)(sizeof(intptr) * 2);
- memset((uint8*)ptr + dataOffset, 0, size - dataOffset);
- // const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
- // size_t cl = Static::pageheap()->GetSizeClassIfCached(p);
- // if (cl == 0)
- // {
- // tc_free(ptr);
- // return;
- // }
- //
- // Span* span = TCGetSpanAt(ptr);
- if (span->freeingObjectsTail == NULL)
- {
- span->freeingObjectsTail = ptr;
- *((intptr*)span->freeingObjectsTail) = 1;
- }
- else
- {
- // Increment pending size
- (*((intptr*)span->freeingObjectsTail))++;
- *(reinterpret_cast<void**>(ptr)) = span->freeingObjects;
- }
-
- span->freeingObjects = ptr;
- }
- void BFGC::DoCollect(bool doingFullGC)
- {
- BP_ZONE("Collect");
- mThreadId = BfpThread_GetCurrentId();
- mStage = 0;
- gTargetFoundCount = 0;
- gMarkTargetCount = 0;
- gMarkTargetMutatorCount = 0;
- mCurGCMarkCount = 0;
- mCurMutatorMarkCount = 0;
- mCurGCObjectQueuedCount = 0;
- mCurMutatorObjectQueuedCount = 0;
- mCurObjectDeleteCount = 0;
- mCurFinalizersCalled = 0;
- mCurSweepFoundCount = 0;
- mCurSweepFoundPermanentCount = 0;
- mCurFreedBytes = 0;
- if (doingFullGC)
- {
- int nextMark = sCurMarkId + 1;
- if (nextMark == 4)
- nextMark = 1;
- mCurMarkId = nextMark;
- sCurMarkId = nextMark;
- sAllocFlags = sCurMarkId;
- }
- mStage = 1;
- BFLOG2(GCLog::EVENT_GC_START, sCurMarkId, BfpSystem_TickCount());
- gGCTypeCounts = 0;
- if (!mSkipMark)
- {
- BP_ZONE("MarkStatics");
- MarkStatics();
- RawMarkAll();
- bool success = bf::System::GC::DoCallRootCallbacks();
- if ((!success) && (!mHadRootError))
- {
- OutputDebugStringA("WARNING: GC leak detection disabled, a GC root callback disabled it\n");
- mHadRootError = true;
- }
- }
-
- if (!mSkipMark)
- {
- Beefy::AutoCrit autoCrit(mCritSect);
- BP_ZONE("ExplicitRootsMark");
- mQueueMarkObjects = true;
- for (int i = 0; i < (int)mExplicitRoots.size(); i++)
- MarkObject(mExplicitRoots[i]);
- mQueueMarkObjects = false;
- }
- if ((doingFullGC) && (!mSkipMark))
- {
- //MarkObject(mGCThread);
- BFMarkThreadPoolJobs();
- BFMarkCOMObjects();
- }
- int threadIdx = 0;
-
- // We need to turn roots black, otherwise the mutator could move a member
- // of a gray root to the stack after the stack scan and we'd miss it
- {
- BP_ZONE("Collect - HandlePendingGCData(Roots)");
- HandlePendingGCData();
- }
- mStage = 2;
- mCurScanIdx++;
- int passes = 0;
-
- if (doingFullGC)
- {
- if (!mSkipMark)
- {
- ScanThreads();
- HandlePendingGCData();
- }
- }
- BF_ASSERT(mOrderedPendingGCData.IsEmpty());
- }
- void BFGC::FinishCollect()
- {
- //OutputDebugStrF("Collected %d objects\n", mFinalizeList.size());
- if ((gBfRtDbgFlags & BfRtFlags_ObjectHasDebugFlags) == 0)
- return;
- mLastFreeCount = 0;
- mStage = 3;
-
- typedef std::unordered_set<bf::System::Object*> BfObjectSet;
-
- {
-
- // Handle any pending data from strong GCHandle references
- HandlePendingGCData();
- }
- int finalizeDataCountFound = 0;
-
- if (mDebugDumpState == DEBUGDUMPSTATE_WAITING_FOR_GC)
- {
- WriteDebugDumpState();
- mDebugDumpState = DEBUGDUMPSTATE_NONE;
- }
-
- {
- BP_ZONE("FreeingObjects");
- void* lastPtr = NULL;
- for (int i = 0; i < mFinalizeList.size(); i++)
- {
- bf::System::Object* obj = mFinalizeList[i];
- if (obj == NULL)
- continue;
- BF_LOGASSERT((obj->mObjectFlags & (/*BF_OBJECTFLAG_FREED |*/ BF_OBJECTFLAG_ALLOCATED)) == BF_OBJECTFLAG_ALLOCATED);
- //BF_LOGASSERT(obj > lastPtr);
- lastPtr = obj;
- }
- {
- BP_ZONE("ReleaseAtLeastNPages");
- SpinLockHolder h(tcmalloc_obj::Static::pageheap_lock());
- Static::pageheap()->ReleaseAtLeastNPages(256);
- }
- {
- BP_ZONE("DecommitFromReleasedList");
- Static::pageheap()->DecommitFromReleasedList(mForceDecommit);
- mForceDecommit = false;
- }
- Dictionary<bf::System::Type*, int> sizeMap;
- int objFreeSize = 0;
- for (int i = 0; i < mFinalizeList.size(); i++)
- {
- bf::System::Object* obj = mFinalizeList[i];
- if (obj == NULL)
- continue;
- // Removed from list already?
- if ((obj->mObjectFlags & BF_OBJECTFLAG_MARK_ID_MASK) == mCurMarkId)
- continue;
- #ifdef BF_DEBUG
- if ((obj->mObjectFlags & (/*BF_OBJECTFLAG_FREED |*/ BF_OBJECTFLAG_ALLOCATED)) != BF_OBJECTFLAG_ALLOCATED)
- {
- tcmalloc_obj::Span* span = TCGetSpanAt(obj);
- BF_FATAL("Object corrupted");
- }
- #ifdef TARGET_TYPE
- if (obj->mBFVData->mType == TARGET_TYPE)
- {
- printf("Finalizing target %p\n", obj);
- }
- #endif
- #endif
- BFLOG1(GCLog::EVENT_FREE, (intptr)obj);
- // BYE!
- #ifdef BF_NO_FREE_MEMORY
- //obj->mObjectFlags |= BF_OBJECTFLAG_FREED;
- #else
-
- #ifdef BG_GC_TRACKPTRS
- {
- Beefy::AutoCrit autoCrit(gBFGC.mCritSect);
- gTrackPtr.erase(gTrackPtr.find(obj));
- }
- #endif
- int objSize = BFGetObjectSize(obj);
- objFreeSize += objSize;
- if (mDisplayFreedObjects)
- {
- // Temporarily remove object flags so GetType() won't fail
- obj->mObjectFlags = BfObjectFlag_None;
- bf::System::Type* type = obj->_GetType();
- //auto pairVal = sizeMap.insert(std::make_pair(type, 0));
- //int newSize = pairVal.first->second + objSize;
- int* sizePtr = NULL;
- sizeMap.TryAdd(type, NULL, &sizePtr);
- *sizePtr += objSize;
- //pairVal.first->second = newSize;
- }
- //obj->mObjectFlags = BfObjectFlag_None;
- obj->mAllocCheckPtr = 0;
- mLastFreeCount++;
- #ifdef BF_GC_USE_OLD_FREE
- tc_free(obj);
- #else
- GCObjFree(obj);
- #endif
-
- #ifdef BF_GC_PRINTSTATS
- ::InterlockedIncrement((volatile uint32*) &gBFGC.mTotalFrees);
- #endif
-
- #endif
- mCurObjectDeleteCount++;
- }
-
- if (!sizeMap.IsEmpty())
- {
- std::multimap<int, bf::System::Type*> orderedSizeMap;
- int totalSize = 0;
- for (auto& pair : sizeMap)
- {
- totalSize += pair.mValue;
- orderedSizeMap.insert(std::make_pair(-pair.mValue, pair.mKey));
- }
- Beefy::String msg;
- msg += Beefy::StrFormat("GC Live Count : %d\n", mCurLiveObjectCount);
- msg += Beefy::StrFormat("GC Freed Count : %d\n", mLastFreeCount);
- msg += Beefy::StrFormat("GC Freed Size : %dk\n", (int)(objFreeSize / 1024));
- msg += "GC Objects\n";
- for (auto& pair : orderedSizeMap)
- {
- bf::System::Type* typeName = pair.second;
- msg += StrFormat(" %-37s : %dk\n", typeName->GetFullName().c_str(), (-pair.first + 1023) / 1024);
- }
- Beefy::OutputDebugStr(msg.c_str());
- }
- mBytesFreed += objFreeSize;
- mBytesRequested -= objFreeSize;
- mCurFreedBytes += objFreeSize;
- }
- #ifdef BF_GC_USE_OLD_FREE
- {
- BP_ZONE("TCScavenge");
- tcmalloc_obj::ThreadCache::GetCacheWhichMustBePresent()->ForceScavenge();
- }
- #else
- {
- //Beefy::DebugTimeGuard suspendTimeGuard(10, "BFGC::ReleasePendingObjects");
- ReleasePendingObjects();
- }
- #endif
- mFinalizeList.Clear();
- mStage = 4;
- }
- void BFGC::UpdateStats()
- {
- if (mStats == NULL)
- return;
- mStats->mHeapSize = TCMalloc_SystemTaken;
- }
- void BFGC::Run()
- {
- BfpThread_SetName(BfpThread_GetCurrent(), "BFGC", NULL);
- uint32 lastGCTick = BFTickCount();
- while (!mExiting)
- {
- UpdateStats();
- float fullGCPeriod = mFullGCPeriod;
- if ((fullGCPeriod != -1) && (mMaxPausePercentage > 0) && (!mCollectReports.IsEmpty()))
- {
- // When we are debugging, we can have a very long update when stepping through code,
- // but otherwise try to pick an update period that keeps our pause time down
- float maxExpandPeriod = BF_MAX(mFullGCPeriod, 2000);
- auto& collectReport = mCollectReports.back();
- fullGCPeriod = BF_MAX(fullGCPeriod, collectReport.mPausedMS * 100 / mMaxPausePercentage);
- fullGCPeriod = BF_MIN(fullGCPeriod, maxExpandPeriod);
- }
- int waitPeriod = BF_MIN(fullGCPeriod, 100);
- if (waitPeriod == 0)
- waitPeriod = -1;
- mCollectEvent.WaitFor(waitPeriod);
-
- uint32 tickNow = BFTickCount();
- if ((fullGCPeriod >= 0) && (tickNow - lastGCTick >= fullGCPeriod))
- mCollectRequested = true;
- if ((mFreeTrigger >= 0) && (mFreeSinceLastGC >= mFreeTrigger))
- mCollectRequested = true;
- if (!mCollectRequested)
- continue;
- lastGCTick = tickNow;
- mCollectRequested = false;
- mPerformingCollection = true;
- BF_FULL_MEMORY_FENCE();
- while (true)
- {
- mHadPendingGCDataOverflow = false;
- mMaxPendingGCSize = 0;
- PerformCollection();
- if (!mHadPendingGCDataOverflow)
- break;
- mOrderedPendingGCData.Reserve(BF_MAX(mOrderedPendingGCData.mAllocSize + mOrderedPendingGCData.mAllocSize / 2, mMaxPendingGCSize + 256));
- }
-
- BF_FULL_MEMORY_FENCE();
- mPerformingCollection = false;
- BF_FULL_MEMORY_FENCE();
- mCollectDoneEvent.Set(true);
- }
-
- mRunning = false;
- }
- void BFGC::RunStub(void* gc)
- {
- ((BFGC*)gc)->Run();
- }
- void BFGC::ThreadStarted(BfDbgInternalThread* thread)
- {
- Beefy::AutoCrit autoCrit(mCritSect);
-
- //thread->mTCMallocObjThreadCache = tcmalloc_obj::ThreadCache::GetCache();
- //mThreadList.push_back(thread);
- BFLOG2(GCLog::EVENT_THREAD_STARTED, (intptr)thread, (intptr)BfpThread_GetCurrentId());
- //printf("ThreadStarted: %p intern:%p TID:%d\n", thread->mThread, thread, ::GetCurrentThreadId());
- }
- void BFGC::ThreadStopped(BfDbgInternalThread* thread)
- {
- Beefy::AutoCrit autoCrit(mCritSect);
- // Keep sync to avoid having the thread exit while the GC is trying to pause it,
- // but do the actual cleanup from the GC's thread
- //thread->mDone = true;
- //printf("ThreadStopped: %p intern:%p TID:%d\n", thread->mThread, thread, ::GetCurrentThreadId());
- }
- void BFGC::ThreadStarted()
- {
- Beefy::AutoCrit autoCrit(mCritSect);
-
- ThreadInfo* thread = new ThreadInfo();
- thread->mRunning = true;
- thread->mThreadHandle = BfpThread_GetCurrent();
- thread->mThreadId = BfpThread_GetCurrentId();
- thread->mTEB = GetTEB((HANDLE)thread->mThreadHandle);
- thread->mThreadInfo = BfpThreadInfo_Create();
- thread->CalcStackStart();
- mThreadList.Add(thread);
- mPendingThreads.Remove(thread->mThreadId);
- ThreadInfo::sCurThreadInfo = thread;
- }
- void BFGC::ThreadStopped()
- {
- auto thread = ThreadInfo::sCurThreadInfo;
- if (thread != NULL)
- {
- Beefy::AutoCrit autoCrit(mCritSect);
- BF_ASSERT(thread->mStackMarkableObjects.IsEmpty());
- if (!mUsingThreadUnlocked)
- {
- // Just delete it
- mThreadList.Remove(thread);
- delete thread;
- }
- else
- {
- thread->mRunning = false;
- }
- }
- }
- void BFGC::Init()
- {
- //ThreadStarted();
- Start();
- }
- void BFGC::Start()
- {
- #ifndef BF_GC_DISABLED
- mRunning = true;
- #ifdef BF_DEBUG
- // More stack space is needed in debug version
- mGCThread = BfpThread_Create(RunStub, (void*)this, 256 * 1024, (BfpThreadCreateFlags)(BfpThreadCreateFlag_Suspended | BfpThreadCreateFlag_StackSizeReserve), &mThreadId);
- #else
- mGCThread = BfpThread_Create(RunStub, (void*)this, 64 * 1024, (BfpThreadCreateFlags)(BfpThreadCreateFlag_Suspended | BfpThreadCreateFlag_StackSizeReserve), &mThreadId);
- #endif
-
- BfpThread_Resume(mGCThread, NULL);
- #endif
- }
- void BFGC::StopCollecting()
- {
- if (!mRunning)
- return;
- mExiting = true;
- while (mRunning)
- {
- if (BfpThread_WaitFor(mGCThread, 0))
- {
- OutputDebugStr("BeefDbgRT not shut down gracefully!\n");
- mGracelessShutdown = true;
- mRunning = false;
- break;
- }
- //BFRtLock bfLock(mEphemeronTombstone);
- mWaitingForGC = true;
- // Wait for current collection to finish
- mCollectEvent.Set();
- //Monitor::Monitor_wait(mEphemeronTombstone, 20);
- mWaitingForGC = false;
- }
- }
- void BFGC::AddStackMarkableObject(bf::System::Object* obj)
- {
- auto threadInfo = ThreadInfo::sCurThreadInfo;
- Beefy::AutoCrit autoCrit(threadInfo->mCritSect);
- threadInfo->mStackMarkableObjects.Add(obj);
- }
- void BFGC::RemoveStackMarkableObject(bf::System::Object* obj)
- {
- auto threadInfo = ThreadInfo::sCurThreadInfo;
- Beefy::AutoCrit autoCrit(threadInfo->mCritSect);
- int stackIdx = threadInfo->mStackMarkableObjects.LastIndexOf(obj);
- BF_ASSERT(stackIdx != -1);
- if (stackIdx != -1)
- threadInfo->mStackMarkableObjects.RemoveAtFast(stackIdx);
- }
- void BFGC::AddPendingThread(BfInternalThread* internalThread)
- {
- if (internalThread->mThread == 0)
- return;
- Beefy::AutoCrit autoCrit(mCritSect);
- mPendingThreads.TryAdd(internalThread->mThreadId, internalThread);
- }
- void BFGC::Shutdown()
- {
- if (mShutdown)
- return;
- mShutdown = true;
- StopCollecting();
- Beefy::AutoCrit autoCrit(mCritSect);
- if (mGracelessShutdown)
- return;
- // Report any objects that aren't deleted
- mSweepInfo.mShowAllAsLeaks = true;
- Sweep();
- ProcessSweepInfo();
- RawShutdown();
- TCMalloc_FreeAllocs();
-
- mFinalizeList.Dispose();
- mOrderedPendingGCData.Dispose();
- for (auto thread : mThreadList)
- thread->mStackMarkableObjects.Dispose();
- }
- void BFGC::InitDebugDump()
- {
- mDebugDumpState = DEBUGDUMPSTATE_WAITING_FOR_PREV;
- mCollectEvent.Set();
- while (mDebugDumpState < DEBUGDUMPSTATE_WAITING_FOR_MUTATOR)
- {
- //BFRtLock bfLock(mEphemeronTombstone);
- //Monitor::Monitor_wait(mEphemeronTombstone, 20);
- }
- }
- void BFGC::EndDebugDump()
- {
- mDebugDumpState = DEBUGDUMPSTATE_WAITING_FOR_GC;
- }
- intptr gFindAddrVal = 0;
- void BFGC::DebugDumpLeaks()
- {
- CheckTcIntegrity();
- BP_ZONE("DebugDump");
- if (mExiting)
- return;
- mSkipMark = true;
- Collect(false);
- }
- void BFGC::ObjReportHandleSpan(tcmalloc_obj::Span* span, int expectedStartPage, int& objectCount, intptr& freeSize, Beefy::Dictionary<bf::System::Type*, AllocInfo>& sizeMap)
- {
- if (span->location != tcmalloc_obj::Span::IN_USE)
- return;
- if (span->start != expectedStartPage)
- {
- return;
- }
- intptr pageSize = (intptr)1<<kPageShift;
- intptr spanSize = pageSize * span->length;
- void* spanStart = (void*)((intptr)span->start << kPageShift);
- void* spanEnd = (void*)((intptr)spanStart + spanSize);
- void* spanPtr = spanStart;
- BF_LOGASSERT((spanStart >= tcmalloc_obj::PageHeap::sAddressStart) && (spanEnd <= tcmalloc_obj::PageHeap::sAddressEnd));
- intptr elementSize = Static::sizemap()->ByteSizeForClass(span->sizeclass);
- if (elementSize == 0)
- elementSize = spanSize;
- BF_LOGASSERT(elementSize >= sizeof(bf::System::Object));
- while (spanPtr <= (uint8*)spanEnd - elementSize)
- {
- bf::System::Object* obj = (bf::System::Object*)spanPtr;
- if (obj->mAllocCheckPtr != 0)
- {
- int objectFlags = obj->mObjectFlags;
- if ((objectFlags & BF_OBJECTFLAG_DELETED) == 0)
- {
- bf::System::Type* type = obj->_GetType();
- //auto pairVal = sizeMap.insert(std::make_pair(type, 0));
- //int newSize = pairVal.first->second + elementSize;
- //pairVal.first->second = newSize;
- AllocInfo* sizePtr = NULL;
- sizeMap.TryAdd(type, NULL, &sizePtr);
- sizePtr->mObjCount++;
- sizePtr->mObjSize += elementSize;
- objectCount++;
- }
- }
- else
- freeSize += elementSize;
- spanPtr = (void*)((intptr)spanPtr + elementSize);
- }
- }
- void BFGC::ObjReportScan(int& objectCount, intptr& freeSize, Beefy::Dictionary<bf::System::Type*, AllocInfo>& sizeMap)
- {
- auto pageHeap = Static::pageheap();
- if (pageHeap == NULL)
- return;
- #ifdef BF32
- int checkPageId = (int)((uintptr)gFindAddrVal >> kPageShift);
- int checkRootIdx = checkPageId >> PageHeap::PageMap::LEAF_BITS;
- int checkLeafIdx = checkPageId & (PageHeap::PageMap::LEAF_LENGTH - 1);
- for (int rootIdx = 0; rootIdx < PageHeap::PageMap::ROOT_LENGTH; rootIdx++)
- {
- PageHeap::PageMap::Leaf* rootLeaf = Static::pageheap()->pagemap_.root_[rootIdx];
- if (rootLeaf == NULL)
- continue;
- for (int leafIdx = 0; leafIdx < PageHeap::PageMap::LEAF_LENGTH; leafIdx++)
- {
- tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)rootLeaf->values[leafIdx];
- if (span != NULL)
- {
- int expectedStartPage = (rootIdx * PageHeap::PageMap::LEAF_LENGTH) + leafIdx;
- ObjReportHandleSpan(span, expectedStartPage, objectCount, freeSize, sizeMap);
- // We may be tempted to advance by span->length here, BUT
- // let us just scan all leafs becuause span data is
- // sometimes invalid and a long invalid span can cause
- // us to skip over an actual valid span
- }
- }
- }
- #else
- for (int pageIdx1 = 0; pageIdx1 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx1++)
- {
- PageHeap::PageMap::Node* node1 = Static::pageheap()->pagemap_.root_->ptrs[pageIdx1];
- if (node1 == NULL)
- continue;
- for (int pageIdx2 = 0; pageIdx2 < PageHeap::PageMap::INTERIOR_LENGTH; pageIdx2++)
- {
- PageHeap::PageMap::Node* node2 = node1->ptrs[pageIdx2];
- if (node2 == NULL)
- continue;
- for (int pageIdx3 = 0; pageIdx3 < PageHeap::PageMap::LEAF_LENGTH; pageIdx3++)
- {
- tcmalloc_obj::Span* span = (tcmalloc_obj::Span*)node2->ptrs[pageIdx3];
- if (span != NULL)
- {
- int expectedStartPage = ((pageIdx1 * PageHeap::PageMap::INTERIOR_LENGTH) + pageIdx2) * PageHeap::PageMap::LEAF_LENGTH + pageIdx3;
- ObjReportHandleSpan(span, expectedStartPage, objectCount, freeSize, sizeMap);
- // We may be tempted to advance by span->length here, BUT
- // let us just scan all leafs because span data is
- // sometimes invalid and a long invalid span can cause
- // us to skip over an actual valid span
- }
- }
- }
- }
- #endif
- }
- void BFGC::Report()
- {
- AutoCrit autoCrit(mCritSect);
- CheckTcIntegrity();
- BP_ZONE("Report");
-
- Beefy::String msg;
- int objectCount = 0;
- #ifdef BF_GC_VERIFY_SWEEP_IDS
- maxAllocNum = bf::System::Object::sCurAllocNum;
- allocIdSet.clear();
- #endif
- int leafCheckCount = 0;
- bool overflowed = false;
- Dictionary<bf::System::Type*, AllocInfo> sizeMap;
- intptr objFreeSize = 0;
- ObjReportScan(objectCount, objFreeSize, sizeMap);
- std::multimap<AllocInfo, bf::System::Type*> orderedSizeMap;
- for (auto& pair : sizeMap)
- {
- orderedSizeMap.insert(std::make_pair(pair.mValue, pair.mKey));
- }
- msg += "Overall GC Summary\n";
- //msg += Beefy::StrFormat(" TotalAllocs %d\n", mTotalAllocs);
- //msg += Beefy::StrFormat(" TotalAllocs - TotalFrees %d\n", mTotalAllocs - mTotalFrees);
- msg += Beefy::StrFormat(" System Memory Taken %dk\n", (int)(TCMalloc_SystemTaken / 1024));
- //msg += Beefy::StrFormat(" BytesRequested %dk\n", (int)(mBytesRequested / 1024));
- msg += Beefy::StrFormat(" Live Objects %d\n", objectCount);
- msg += Beefy::StrFormat(" Last Object Freed Count %d\n", mLastFreeCount);
-
- intptr objReportedCount = 0;
- intptr rawReportedCount = 0;
- intptr rawFreeSize = 0;
- intptr objTotalSize = 0;
- intptr rawTotalSize = 0;
- gBFGC.RawReport(msg, rawFreeSize, orderedSizeMap);
- for (auto& pair : orderedSizeMap)
- {
- objTotalSize += pair.first.mObjSize;
- objReportedCount += pair.first.mObjCount;
- rawTotalSize += pair.first.mRawSize;
- rawReportedCount += pair.first.mRawCount;
- }
- msg += Beefy::StrFormat(" Obj Scanned Alloc Count %d\n", (int)(objReportedCount));
- msg += Beefy::StrFormat(" Raw Scanned Alloc Count %d\n", (int)(rawReportedCount));
- msg += Beefy::StrFormat(" Obj Used Memory %dk\n", (int)(objTotalSize / 1024));
- msg += Beefy::StrFormat(" Raw Used Memory %dk\n", (int)(rawTotalSize / 1024));
- msg += Beefy::StrFormat(" Obj Unusued Memory %dk\n", (int)(objFreeSize / 1024));
- msg += Beefy::StrFormat(" Raw Unusued Memory %dk\n", (int)(rawFreeSize / 1024));
-
- if (!mCollectReports.IsEmpty())
- {
- for (int reportIdx = 0; reportIdx < (int)mCollectReports.size(); reportIdx++)
- {
- auto& report = mCollectReports[reportIdx];
- msg += Beefy::StrFormat(" Collection %d Total: %dms Paused: %dms CollectCount: %d", report.mCollectIdx, report.mTotalMS, report.mPausedMS, report.mCollectCount);
- if (reportIdx > 0)
- {
- msg += Beefy::StrFormat(" SinceLast: %dms", report.mStartTick - mCollectReports[reportIdx - 1].mStartTick);
- }
- msg += "\n";
- }
-
- msg += Beefy::StrFormat(" Average Time Between Collections %dms\n", BFTickCount() / mCollectIdx);
- }
-
- msg += "Types Size Count\n";
- for (auto& pair : orderedSizeMap)
- {
- bf::System::Type* type = pair.second;
- Beefy::String typeName;
- if (type == NULL)
- typeName = "NULL";
- else
- typeName = type->GetFullName();
-
- if (pair.first.mObjCount > 0)
- msg += StrFormat("OBJ %-62s %7dk %7d\n", typeName.c_str(), (pair.first.mObjSize + 1023) / 1024, pair.first.mObjCount);
- if (pair.first.mRawCount > 0)
- msg += StrFormat("RAW %-62s %7dk %7d\n", typeName.c_str(), (pair.first.mRawSize + 1023) / 1024, pair.first.mRawCount);
- }
- Beefy::OutputDebugStr(msg.c_str());
- BFGCLogWrite();
- }
- void BFGC::ReportTLSMember(int tlsIndex, void* ptr, void* markFunc)
- {
- if (mMainThreadTLSPtr == NULL)
- {
- _TEB* teb = NtCurrentTeb();
- mMainThreadTLSPtr = teb->ThreadLocalStorage;
- }
- TLSMember tlsMember;
- tlsMember.mTLSOffset = (uint8*)ptr - ((uint8**)mMainThreadTLSPtr)[tlsIndex];
- tlsMember.mMarkFunc = markFunc;
- tlsMember.mTLSIndex = tlsIndex;
- mTLSMembers.Add(tlsMember);
- }
- void BFGC::SuspendThreads()
- {
- BP_ZONE("TriggerCollection - SuspendThreads");
- auto curThreadId = GetCurrentThreadId();
- for (auto thread : mThreadList)
- {
- if ((thread->mThreadId != curThreadId) && (!thread->mExcluded) && (thread->mRunning) && (thread->WantsSuspend()))
- {
- // We must lock this before suspending so we can access mStackMarkableObjects
- // Otherwise we could deadlock
- thread->mCritSect.Lock();
- thread->mSuspended = true;
- BfpThreadResult result;
- BfpThread_Suspend(thread->mThreadHandle, &result);
- ASSERT(result == BfpThreadResult_Ok);
- }
- }
- }
- void BFGC::ResumeThreads()
- {
- BP_ZONE("TriggerCollection - ResumeThreads");
- auto curThreadId = GetCurrentThreadId();
- for (auto thread : mThreadList)
- {
- if ((thread->mThreadId != curThreadId) && (thread->mSuspended) && (thread->mRunning) && (thread->WantsSuspend()))
- {
- // Previously locked in SuspendThreads
- thread->mCritSect.Unlock();
- thread->mSuspended = false;
- BfpThread_Resume(thread->mThreadHandle, NULL);
- }
- }
- }
- void BFGC::PerformCollection()
- {
- BP_ZONE("TriggerCollection");
-
- if (mCollectIdx == 0)
- {
- // 'Prime' register capture
- intptr regVals[128];
- intptr stackPtr = 0;
- BfpThreadResult threadResult;
- int regValCount = 128;
- BfpThread_GetIntRegisters(BfpThread_GetCurrent(), &stackPtr, regVals, ®ValCount, &threadResult);
- }
- int prevMarkId = mCurMarkId;
- DWORD startTick = BFTickCount();
- CollectReport collectReport;
- collectReport.mCollectIdx = mCollectIdx;
- collectReport.mStartTick = startTick;
- #ifndef BF_MINGW
- //_CrtCheckMemory();
- #endif
- #ifdef BF_GC_INCREMENTAL
- mFullGCTriggered = true;
- mForceDecommit |= forceDecommit;
- gBFGC.mCollectEvent.Set();
- #else
- Beefy::AutoCrit autoCrit(mCritSect);
- mAllocSinceLastGC = 0;
- mCollectFailed = false;
- // This was old "emergency" debugging code to make sure we weren't doing a malloc in the GC code,
- // but it's a multi-threaded race condition
- /*uint8* mallocAddr = (uint8*)&malloc;
- DWORD oldProtect = 0;
- BOOL worked = ::VirtualProtect(mallocAddr, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
- uint8 oldCode = *mallocAddr;
- *mallocAddr = 0xCC;*/
-
- mOrderedPendingGCData.Reserve(BF_GC_MAX_PENDING_OBJECT_COUNT);
- uint32 suspendStartTick = BFTickCount();
- SuspendThreads();
- #ifndef BF_MINGW
- //_CrtCheckMemory();
- #endif
- DoCollect(true);
- #ifndef BF_MINGW
- //_CrtCheckMemory();
- #endif
- //*mallocAddr = oldCode;
-
- #ifdef BF_GC_EMPTYSCAN
- {
- mSweepInfo.mEmptyScan = true;
- Sweep();
- mSweepInfo.mEmptyScan = false;
- }
- #endif
- mFreeSinceLastGC = 0;
- BFLOG2(GCLog::EVENT_GC_UNFREEZE, sCurMarkId, BfpSystem_TickCount());
- #ifndef BF_GC_DEBUGSWEEP
- ResumeThreads();
- #endif
- collectReport.mPausedMS = BFTickCount() - suspendStartTick;
-
- //BFGCLogWrite();
- mFinalizeList.Clear();
- Sweep();
- #ifdef BF_GC_DEBUGSWEEP
- ResumeThreads();
- #endif
- collectReport.mCollectCount = (int)mFinalizeList.size();
- FinishCollect();
- ReleasePendingObjects();
- ProcessSweepInfo();
- BFLOG2(GCLog::EVENT_GC_DONE, mCurGCMarkCount, mHadPendingGCDataOverflow ? 1 : 0);
-
- collectReport.mTotalMS = BFTickCount() - startTick;
- // while (mCollectReports.size() > 4)
- // mCollectReports.RemoveAt(0);
- while (mCollectReports.size() > 10)
- mCollectReports.RemoveAt(0);
- mCollectReports.Add(collectReport);
- mCollectIdx++;
- #endif
- }
- void BFGC::Collect(bool async)
- {
- mCollectRequested = true;
- BF_FULL_MEMORY_FENCE();
- if (async)
- {
- mCollectEvent.Set();
- }
- else
- {
- if (mPerformingCollection)
- mCollectDoneEvent.WaitFor(0); // Wait for previous to finish
- mCollectDoneEvent.Reset();
- mCollectEvent.Set();
- mCollectDoneEvent.WaitFor();
- }
- }
- void BFGC::WriteDebugDumpState()
- {
- struct DebugInfo
- {
- bf::System::Type* mType;
- int mCount;
- int mSize;
- int mAllocSize;
- DebugInfo()
- {
- mType = NULL;
- mCount = 0;
- mSize = 0;
- mAllocSize = 0;
- }
- };
- std::vector<DebugInfo> debugInfoVector;
- for (int i = 0; i < (int)mFinalizeList.size(); i++)
- {
- bf::System::Object* obj = (bf::System::Object*) mFinalizeList[i];
- if ((bf::System::Type*)obj->GetTypeSafe() != NULL)
- {
- if ((uintptr)obj->GetTypeSafe() <= 1024U*1024U)
- {
- while ((int) debugInfoVector.size() <= 0)
- debugInfoVector.push_back(DebugInfo());
- DebugInfo* debugInfo = &debugInfoVector[0];
- debugInfo->mType = NULL;
- debugInfo->mCount++;
- int objSize = BFGetObjectSize(obj);
- debugInfo->mSize += objSize;
- debugInfo->mAllocSize += objSize;
- //debugInfo->mAllocSize += MallocExtension::instance()->GetEstimatedAllocatedSize(objSize);
- }
- else
- {
- //const bf::System::Type* bfTypeRootData = ((bf::System::Type*)obj->GetTypeSafe())->mTypeRootData;
- bf::System::Type* bfType = obj->GetTypeSafe();
- while ((int) debugInfoVector.size() <= bfType->mTypeId)
- debugInfoVector.push_back(DebugInfo());
- DebugInfo* debugInfo = &debugInfoVector[bfType->mTypeId];
- debugInfo->mType = obj->GetTypeSafe();
- debugInfo->mCount++;
- int objSize = BFGetObjectSize(obj);
- debugInfo->mSize += objSize;
- debugInfo->mAllocSize += objSize;
- //debugInfo->mAllocSize += MallocExtension::instance()->GetEstimatedAllocatedSize(objSize);
- }
- }
- }
- typedef std::multimap<int, DebugInfo*> DebugInfoMap;
- DebugInfoMap debugInfoMap;
- for (int i = 0; i < (int) debugInfoVector.size(); i++)
- {
- DebugInfo* debugInfo = &debugInfoVector[i];
- if (debugInfo->mCount > 0)
- debugInfoMap.insert(DebugInfoMap::value_type(-debugInfo->mSize, debugInfo));
- }
- Beefy::String dbgStr = "\n\nBeefyRT GC DebugDump:\n";
- int countTotal = 0;
- int sizeTotal = 0;
- int allocSizeTotal = 0;
- DebugInfoMap::iterator itr = debugInfoMap.begin();
- while (itr != debugInfoMap.end())
- {
- DebugInfo* debugInfo = itr->second;
- Beefy::String lineStr = StrFormat("%8d %8dk %8dk ", debugInfo->mCount, (debugInfo->mSize + 1023) / 1024, (debugInfo->mAllocSize + 1023) / 1024);
- Beefy::String typeName;
- if (debugInfo->mType != NULL)
- typeName = debugInfo->mType->GetFullName();
- else
- typeName = "???";
-
- lineStr += typeName;
- dbgStr += lineStr += "\n";
- countTotal += debugInfo->mCount;
- sizeTotal += debugInfo->mSize;
- allocSizeTotal += debugInfo->mAllocSize;
- ++itr;
- }
- dbgStr += StrFormat("%8d %8dk %8dk TOTAL", countTotal, (sizeTotal + 1023)/1024, (allocSizeTotal + 1023)/1024);
- OutputDebugStrF(dbgStr.c_str());
- }
- #ifdef BF_DEBUG
- //#define NO_QUEUE_OBJECTS
- #endif
- #ifdef BF_GC_LOG_ENABLED
- static bf::System::Object* gMarkingObject[8192];
- #endif
- void BFGC::MarkFromGCThread(bf::System::Object* obj)
- {
- if (obj == NULL)
- return;
- //BP_ZONE("MarkFromGCThread");
-
- void* addr = obj;
- if ((addr < tcmalloc_obj::PageHeap::sAddressStart) || (addr >= tcmalloc_obj::PageHeap::sAddressEnd))
- return;
- tcmalloc_obj::Span* span = TCGetSpanAt(obj);
- if (span == NULL)
- return;
- if (span->location != tcmalloc_obj::Span::IN_USE)
- return;
-
- intptr pageSize = (intptr) 1 << kPageShift;
- intptr spanSize = pageSize * span->length;
- void* spanStart = (void*)((intptr)span->start << kPageShift);
- void* spanEnd = (void*)((intptr)spanStart + spanSize);
-
- if ((addr < spanStart) || (addr > (uint8*)spanEnd - sizeof(bf::System::Object)))
- return;
-
- // Is it already marked? Ignore.
- if ((obj->mObjectFlags & BF_OBJECTFLAG_MARK_ID_MASK) == mCurMarkId)
- return;
- // Don't do any processing of non-allocated objects (like string literals), or append allocs
- if ((obj->mObjectFlags & BF_OBJECTFLAG_ALLOCATED) == 0)
- return;
- if (obj->mAllocCheckPtr == 0) // It IS in the heap but not allocated
- return;
- bool curIsDeleted = false;
- if (mMarkingDeleted)
- {
- if ((obj->mObjectFlags & BF_OBJECTFLAG_DELETED) == 0)
- {
- // Don't allow a deleted object to mark a non-deleted object-
- // That should be handled as a LEAK if there aren't any non-deleted objects referencing it
- return;
- }
- }
- intptr elementSize = Static::sizemap()->ByteSizeForClass(span->sizeclass);
- // Large alloc
- if (elementSize == 0)
- {
- if (obj != (bf::System::Object*)spanStart)
- return;
- }
- else
- {
- void* maskedAddr = addr;
- maskedAddr = (uint8*)spanStart + (((uint8*)maskedAddr - (uint8*)spanStart) / elementSize * elementSize);
- if (obj != (bf::System::Object*)maskedAddr)
- return;
- }
-
- #ifndef BF_GC_DISABLED
- BF_LOGASSERT(mThreadId == BfpThread_GetCurrentId());
- BF_LOGASSERT(obj->mClassVData != 0);
- #ifdef TARGET_TYPE
- if (obj->mBFVData->mType == TARGET_TYPE)
- {
- gMarkTargetCount++;
- printf("Marking target %p\n", obj);
- }
- #endif
-
- #ifdef BF_GC_LOG_ENABLED
- bf::System::Object* parentObj = NULL;
- if (mMarkDepthCount > 0)
- parentObj = gMarkingObject[mMarkDepthCount-1];
- BFLOG3(GCLog::EVENT_MARK, (intptr)obj, obj->mObjectFlags, (intptr)parentObj);
- #endif
-
- obj->mObjectFlags = (BfObjectFlags)((obj->mObjectFlags & ~BF_OBJECTFLAG_MARK_ID_MASK) | mCurMarkId);
- mCurGCMarkCount++;
-
- mCurGCObjectQueuedCount++;
- mCurPendingGCSize++;
- bool allowQueue = true;
-
- if (mOrderedPendingGCData.GetFreeCount() > 0)
- {
- mOrderedPendingGCData.Add(obj);
- }
- else
- {
- // No more room left -- we can't queue...
- mHadPendingGCDataOverflow = true;
- mCollectFailed = true;
- }
- #endif
- }
- void BFGC::SetAutoCollectPeriod(int periodMS)
- {
- mFullGCPeriod = periodMS;
- mCollectEvent.Set();
- }
- void BFGC::SetCollectFreeThreshold(int freeBytes)
- {
- mFreeTrigger = freeBytes;
- mCollectEvent.Set();
- }
- void BFGC::SetMaxPausePercentage(int maxPausePercentage)
- {
- mMaxPausePercentage = maxPausePercentage;
- mCollectEvent.Set();
- }
- void BFGC::SetMaxRawDeferredObjectFreePercentage(intptr maxPercentage)
- {
- mMaxRawDeferredObjectFreePercentage = maxPercentage;
- }
- void BFGC::ExcludeThreadId(intptr threadId)
- {
- Beefy::AutoCrit autoCrit(mCritSect);
- for (auto thread : mThreadList)
- {
- if (thread->mThreadId == threadId)
- thread->mExcluded = true;
- }
- }
- using namespace bf::System;
- void GC::Run()
- {
- #ifdef BF_GC_INCREMENTAL
- gBFGC.Run();
- #endif
- }
- void GC::Init()
- {
- gBFGC.Init();
- }
- void GC::ReportTLSMember(intptr tlsIndex, void* ptr, void* markFunc)
- {
- gBFGC.ReportTLSMember((int)tlsIndex, ptr, markFunc);
- }
- void GC::StopCollecting()
- {
- gBFGC.StopCollecting();
- }
- void GC::AddStackMarkableObject(Object* obj)
- {
- gBFGC.AddStackMarkableObject(obj);
- }
- void GC::AddPendingThread(void* internalThreadInfo)
- {
- gBFGC.AddPendingThread((BfInternalThread*)internalThreadInfo);
- }
- void GC::RemoveStackMarkableObject(Object* obj)
- {
- gBFGC.RemoveStackMarkableObject(obj);
- }
- void GC::Shutdown()
- {
- gBFGC.Shutdown();
- }
- void GC::Collect(bool async)
- {
- gBFGC.Collect(async);
- }
- void GC::Report()
- {
- gBFGC.Report();
- }
- void GC::Mark(Object* obj)
- {
- gBFGC.MarkFromGCThread(obj);
- }
- void GC::Mark(void* ptr, intptr size)
- {
- gBFGC.ConservativeScan(ptr, (int)size);
- }
- void GC::DebugDumpLeaks()
- {
- gBFGC.DebugDumpLeaks();
- }
- void GC::SetAutoCollectPeriod(intptr periodMS)
- {
- gBFGC.SetAutoCollectPeriod((int)periodMS);
- }
- void GC::SetCollectFreeThreshold(intptr freeBytes)
- {
- gBFGC.SetCollectFreeThreshold((int)freeBytes);
- }
- BFRT_EXPORT void bf::System::GC::SetMaxPausePercentage(intptr maxPausePercentage)
- {
- gBFGC.SetMaxPausePercentage(maxPausePercentage);
- }
- BFRT_EXPORT void bf::System::GC::SetMaxRawDeferredObjectFreePercentage(intptr maxPercentage)
- {
- gBFGC.SetMaxRawDeferredObjectFreePercentage(maxPercentage);
- }
- BFRT_EXPORT void bf::System::GC::ExcludeThreadId(intptr threadId)
- {
- gBFGC.ExcludeThreadId(threadId);
- }
- #else // BF_GC_SUPPORTED
- void* BfObjectAllocate(intptr size, bf::System::Type* type)
- {
- BF_FATAL("Not supported");
- return NULL;
- }
- using namespace bf::System;
- void GC::Run()
- {
- #ifdef BF_GC_INCREMENTAL
- gBFGC.Run();
- #endif
- }
- void GC::Init()
- {
- }
- void GC::ReportTLSMember(intptr tlsIndex, void* ptr, void* markFunc)
- {
- }
- void GC::Shutdown()
- {
- }
- void GC::Collect(bool async)
- {
- }
- void GC::Report()
- {
- }
- /*void GC::Mark(Object* obj)
- {
- }*/
- void GC::Mark(void* ptr, intptr size)
- {
- }
- void GC::DebugDumpLeaks()
- {
- }
- void GC::SetAutoCollectPeriod(intptr periodMS)
- {
- }
- void GC::SetCollectFreeThreshold(intptr freeBytes)
- {
- }
- #endif
|