int __cdecl main(int argc, char* argv[]) { // // Initialize system info // if (!GCToOSInterface::Initialize()) { return -1; } // // Initialize free object methodtable. The GC uses a special array-like methodtable as placeholder // for collected free space. // static MethodTable freeObjectMT; freeObjectMT.InitializeFreeObject(); g_pFreeObjectMethodTable = &freeObjectMT; // // Initialize GC heap // GcDacVars dacVars; IGCHeap *pGCHeap; IGCHandleManager *pGCHandleManager; if (!InitializeGarbageCollector(nullptr, &pGCHeap, &pGCHandleManager, &dacVars)) { return -1; } if (FAILED(pGCHeap->Initialize())) return -1; // // Initialize handle manager // if (!pGCHandleManager->Initialize()) return -1; // // Initialize current thread // ThreadStore::AttachCurrentThread(); // // Create a Methodtable with GCDesc // class My : Object { public: Object * m_pOther1; int dummy_inbetween; Object * m_pOther2; }; static struct My_MethodTable { // GCDesc CGCDescSeries m_series[2]; size_t m_numSeries; // The actual methodtable MethodTable m_MT; } My_MethodTable; // 'My' contains the MethodTable* uint32_t baseSize = sizeof(My); // GC expects the size of ObjHeader (extra void*) to be included in the size. baseSize = baseSize + sizeof(ObjHeader); // Add padding as necessary. GC requires the object size to be at least MIN_OBJECT_SIZE. My_MethodTable.m_MT.m_baseSize = max(baseSize, MIN_OBJECT_SIZE); My_MethodTable.m_MT.m_componentSize = 0; // Array component size My_MethodTable.m_MT.m_flags = MTFlag_ContainsPointers; My_MethodTable.m_numSeries = 2; // The GC walks the series backwards. It expects the offsets to be sorted in descending order. My_MethodTable.m_series[0].SetSeriesOffset(offsetof(My, m_pOther2)); My_MethodTable.m_series[0].SetSeriesCount(1); My_MethodTable.m_series[0].seriessize -= My_MethodTable.m_MT.m_baseSize; My_MethodTable.m_series[1].SetSeriesOffset(offsetof(My, m_pOther1)); My_MethodTable.m_series[1].SetSeriesCount(1); My_MethodTable.m_series[1].seriessize -= My_MethodTable.m_MT.m_baseSize; MethodTable * pMyMethodTable = &My_MethodTable.m_MT; // Allocate instance of MyObject Object * pObj = AllocateObject(pMyMethodTable); if (pObj == NULL) return -1; // Create strong handle and store the object into it OBJECTHANDLE oh = HndCreateHandle(g_HandleTableMap.pBuckets[0]->pTable[GetCurrentThreadHomeHeapNumber()], HNDTYPE_DEFAULT, pObj); if (oh == NULL) return -1; for (int i = 0; i < 1000000; i++) { Object * pBefore = ((My *)HndFetchHandle(oh))->m_pOther1; // Allocate more instances of the same object Object * p = AllocateObject(pMyMethodTable); if (p == NULL) return -1; Object * pAfter = ((My *)HndFetchHandle(oh))->m_pOther1; // Uncomment this assert to see how GC triggered inside AllocateObject moved objects around // assert(pBefore == pAfter); // Store the newly allocated object into a field using WriteBarrier WriteBarrier(&(((My *)HndFetchHandle(oh))->m_pOther1), p); } // Create weak handle that points to our object OBJECTHANDLE ohWeak = HndCreateHandle(g_HandleTableMap.pBuckets[0]->pTable[GetCurrentThreadHomeHeapNumber()], HNDTYPE_WEAK_DEFAULT, HndFetchHandle(oh)); if (ohWeak == NULL) return -1; // Destroy the strong handle so that nothing will be keeping out object alive HndDestroyHandle(HndGetHandleTable(oh), HNDTYPE_DEFAULT, oh); // Explicitly trigger full GC pGCHeap->GarbageCollect(); // Verify that the weak handle got cleared by the GC assert(HndFetchHandle(ohWeak) == NULL); printf("Done\n"); return 0; }
int __cdecl main(int argc, char* argv[]) { // // Initialize system info // if (!GCToOSInterface::Initialize()) { return -1; } // // Initialize free object methodtable. The GC uses a special array-like methodtable as placeholder // for collected free space. // static MethodTable freeObjectMT; freeObjectMT.InitializeFreeObject(); g_pFreeObjectMethodTable = &freeObjectMT; // // Initialize handle table // if (!Ref_Initialize()) return -1; // // Initialize GC heap // GCHeap *pGCHeap = GCHeap::CreateGCHeap(); if (!pGCHeap) return -1; if (FAILED(pGCHeap->Initialize())) return -1; // // Initialize current thread // ThreadStore::AttachCurrentThread(); // // Create a Methodtable with GCDesc // class My : Object { public: Object * m_pOther1; int dummy_inbetween; Object * m_pOther2; }; static struct My_MethodTable { // GCDesc CGCDescSeries m_series[2]; size_t m_numSeries; // The actual methodtable MethodTable m_MT; } My_MethodTable; // 'My' contains the MethodTable* uint32_t baseSize = sizeof(My); // GC expects the size of ObjHeader (extra void*) to be included in the size. baseSize = baseSize + sizeof(ObjHeader); // Add padding as necessary. GC requires the object size to be at least MIN_OBJECT_SIZE. My_MethodTable.m_MT.m_baseSize = max(baseSize, MIN_OBJECT_SIZE); My_MethodTable.m_MT.m_componentSize = 0; // Array component size My_MethodTable.m_MT.m_flags = MTFlag_ContainsPointers; My_MethodTable.m_numSeries = 2; // The GC walks the series backwards. It expects the offsets to be sorted in descending order. My_MethodTable.m_series[0].SetSeriesOffset(offsetof(My, m_pOther2)); My_MethodTable.m_series[0].SetSeriesCount(1); My_MethodTable.m_series[0].seriessize -= My_MethodTable.m_MT.m_baseSize; My_MethodTable.m_series[1].SetSeriesOffset(offsetof(My, m_pOther1)); My_MethodTable.m_series[1].SetSeriesCount(1); My_MethodTable.m_series[1].seriessize -= My_MethodTable.m_MT.m_baseSize; MethodTable * pMyMethodTable = &My_MethodTable.m_MT; // Allocate instance of MyObject Object * pObj = AllocateObject(pMyMethodTable); if (pObj == NULL) return -1; // Create strong handle and store the object into it OBJECTHANDLE oh = CreateGlobalHandle(pObj); if (oh == NULL) return -1; for (int i = 0; i < 1000000; i++) { Object * pBefore = ((My *)ObjectFromHandle(oh))->m_pOther1; // Allocate more instances of the same object Object * p = AllocateObject(pMyMethodTable); if (p == NULL) return -1; Object * pAfter = ((My *)ObjectFromHandle(oh))->m_pOther1; // Uncomment this assert to see how GC triggered inside AllocateObject moved objects around // assert(pBefore == pAfter); if (pBefore != pAfter) { printf("%8i) pBefore = 0x%08x, pAfter = 0x%08x, diff = 0x%08x (%i)\n", i, pBefore, pAfter, pBefore - pAfter, pBefore - pAfter); PrintGCStats(pGCHeap); } // Store the newly allocated object into a field using WriteBarrier WriteBarrier(&(((My *)ObjectFromHandle(oh))->m_pOther1), p); } // Create weak handle that points to our object OBJECTHANDLE ohWeak = CreateGlobalWeakHandle(ObjectFromHandle(oh)); if (ohWeak == NULL) return -1; // Destroy the strong handle so that nothing will be keeping out object alive DestroyGlobalHandle(oh); // Verify that the weak handle has not yet been cleared (i.e. before the GC has run) assert(ObjectFromHandle(ohWeak) != NULL); printf("\nBEFORE Final Call to pGCHeap->GarbageCollect()"); PrintGCStats(pGCHeap); // Explicitly trigger full GC pGCHeap->GarbageCollect(); printf("\nAFTER Final Call to pGCHeap->GarbageCollect()"); PrintGCStats(pGCHeap); // Verify that the weak handle got cleared by the GC assert(ObjectFromHandle(ohWeak) == NULL); printf("Done\n"); return 0; }