// // gmGCRoot.cpp // #include "gmGCRoot.h" // Init statics and constants gmGCRootManager* gmGCRootManager::s_staticInstance; gmGCRootManager::gmGCRootManager() { m_machineHolderSet.Init(0, 4); } gmGCRootManager::~gmGCRootManager() { DestroyAllMachines(); } void gmGCRootManager::Init() { GM_ASSERT( !s_staticInstance ); if( !s_staticInstance ) { s_staticInstance = new gmGCRootManager; } } void gmGCRootManager::Destroy() { if( s_staticInstance ) { delete s_staticInstance; s_staticInstance = NULL; } } gmgcrHolder* gmGCRootManager::FindOrAdd(gmObject* a_object, gmMachine* a_machine) { GM_ASSERT(a_object); GM_ASSERT(a_machine); if( !a_object || !a_machine ) { return NULL; } MachineHolders* machineSet = FindOrAddMachine(a_machine); gmgcrHolder* holder = NULL; if( !machineSet->m_mapPtrToHolder.GetAt(a_object, holder) ) { // Add new holder = m_memHolder.Alloc(); holder->Init(a_object, a_machine); machineSet->m_mapPtrToHolder.SetAt(a_object, holder); a_machine->AddCPPOwnedGMObject(a_object); // Add to GC roots } return holder; } void gmGCRootManager::RemoveObject(gmObject* a_object, gmMachine* a_machine) { if( a_object && a_machine ) { a_machine->RemoveCPPOwnedGMObject(a_object); // Remove from GC roots gmGCRootManager::MachineHolders* machineSet = FindOrAddMachine(a_machine); machineSet->m_mapPtrToHolder.RemoveAt(a_object); } } void gmGCRootManager::FreeHolder(const gmgcrHolder* a_holder) { if( a_holder ) { m_memHolder.Free( const_cast(a_holder) ); } } void gmGCRootManager::DestroyMachine(gmMachine* a_machine) { int foundIndex = -1; // Find existing set for(int mIndex=0; mIndex < m_machineHolderSet.GetSize(); ++mIndex) { if( m_machineHolderSet[mIndex].m_machine == a_machine ) { foundIndex = mIndex; break; } } if( foundIndex >= 0 ) { MachineHolders* destroySet = &m_machineHolderSet[foundIndex]; // Cleanup all internal pointers gmgcrMap::Iterator it; // Iterate carefully as we are deleting while iterating destroySet->m_mapPtrToHolder.GetFirst(it); while( !destroySet->m_mapPtrToHolder.IsNull(it) ) { gmgcrHolder* toDelete = NULL; if( destroySet->m_mapPtrToHolder.GetValue(it, toDelete) ) { // NOTE: Delete this found value after incrementing iterator } destroySet->m_mapPtrToHolder.GetNext(it); if( toDelete ) { toDelete->Destroy(); } } // Remove machine set m_machineHolderSet.RemoveAt(foundIndex); } } gmGCRootManager::MachineHolders* gmGCRootManager::FindOrAddMachine(gmMachine* a_machine) { // NOTE: Expect very small number of machines. If this is not so, accelerate search. GM_ASSERT( a_machine ); // Find existing set for(int mIndex=0; mIndex < m_machineHolderSet.GetSize(); ++mIndex) { if( m_machineHolderSet[mIndex].m_machine == a_machine ) { return &m_machineHolderSet[mIndex]; } } // Create new set int newIndex = m_machineHolderSet.AddEmpty(); MachineHolders* newSet = &m_machineHolderSet[newIndex]; newSet->m_machine = a_machine; return newSet; } void gmGCRootManager::DestroyAllMachines() { while( m_machineHolderSet.GetSize() ) { DestroyMachine( m_machineHolderSet[m_machineHolderSet.GetLastIndex()].m_machine ); } } #if 0 // Test the gmGCRoot system void TestGMGCRoot() { gmGCRootManager::Init(); // Init system { gmMachine machine1; gmGCRoot ptr1; gmStringObject* stringObj1 = machine1.AllocStringObject("hello"); ptr1.Set(stringObj1, &machine1); // Initialize via func gmStringObject* nat1 = ptr1; // Assign pointer gmGCRoot ptr2; ptr2 = ptr1; ptr1 = NULL; // Assign to null ptr2 = NULL; //ptr2 = nat1; // ERROR gmStringObject* stringObj2 = machine1.AllocStringObject("apple"); gmGCRoot ptr3(stringObj2, &machine1); // Initialize via constructor gmGCRoot ptr4(stringObj2, &machine1); // Duplicate without copy gmGCRoot ptr5; { gmMachine machine2; gmStringObject* stringObj3 = machine2.AllocStringObject("bannana"); ptr5.Set(stringObj3, &machine2); gmGCRootManager::Get()->DestroyMachine(&machine2); // Null associated pointers } if( ptr5 ) { int i=1; // Won't get here } } gmGCRootManager::Destroy(); } #endif