void Grid::PrintChildren(int NumofNode) { node* ptr = ReturnNode(NumofNode); if (ptr != NULL) { cout << "Node = " << ptr->NumofNode << endl; ptr->Left == NULL ? cout << "Left Child = Null\n": cout << "Left Child = " << ptr->Left->NumofNode << endl; ptr->Right == NULL ? cout << "Right Child = Null\n" : cout << "Right Child = " << ptr->Right->NumofNode << endl; } else { cout << "Node is not in the tree\n"; } }
int asCGarbageCollector::IdentifyGarbageWithCyclicRefs() { for(;;) { switch( detectState ) { case clearCounters_init: detectState = clearCounters_loop; break; case clearCounters_loop: { // Decrease reference counter for all objects removed from the map asSMapNode<void*, asSIntTypePair> *cursor = 0; gcMap.MoveFirst(&cursor); if( cursor ) { void *obj = gcMap.GetKey(cursor); asSIntTypePair it = gcMap.GetValue(cursor); engine->CallObjectMethod(obj, it.type->beh.release); ReturnNode(gcMap.Remove(cursor)); return 1; } detectState = buildMap_init; } break; case buildMap_init: detectIdx = 0; detectState = buildMap_loop; break; case buildMap_loop: { // Build a map of objects that will be checked, the map will // hold the object pointer as key, and the gcCount and the // object's type as value. As objects are added to the map the // gcFlag must be set in the objects, so we can be verify if // the object is accessed during the GC cycle. // If an object is removed from the gcObjects list during the // iteration of this step, it is possible that an object won't // be used during the analyzing for cyclic references. This // isn't a problem, as the next time the GC cycle starts the // object will be verified. if( detectIdx < gcOldObjects.GetLength() ) { // Add the gc count for this object asSObjTypePair gcObj = GetOldObjectAtIdx(detectIdx); int refCount = 0; if( gcObj.type->beh.gcGetRefCount ) refCount = engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount); if( refCount > 1 ) { asSIntTypePair it = {refCount-1, gcObj.type}; gcMap.Insert(GetNode(gcObj.obj, it)); // Increment the object's reference counter when putting it in the map engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref); // Mark the object so that we can // see if it has changed since read engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.gcSetFlag); } detectIdx++; // Let the application work a little return 1; } else detectState = countReferences_init; } break; case countReferences_init: { gcMap.MoveFirst(&gcMapCursor); detectState = countReferences_loop; } break; case countReferences_loop: { // Call EnumReferences on all objects in the map to count the number // of references reachable from between objects in the map. If all // references for an object in the map is reachable from other objects // in the map, then we know that no outside references are held for // this object, thus it is a potential dead object in a circular reference. // If the gcFlag is cleared for an object we consider the object alive // and referenced from outside the GC, thus we don't enumerate its references. // Any new objects created after this step in the GC cycle won't be // in the map, and is thus automatically considered alive. if( gcMapCursor ) { void *obj = gcMap.GetKey(gcMapCursor); asCObjectType *type = gcMap.GetValue(gcMapCursor).type; gcMap.MoveNext(&gcMapCursor, gcMapCursor); if( engine->CallObjectMethodRetBool(obj, type->beh.gcGetFlag) ) { engine->CallObjectMethod(obj, engine, type->beh.gcEnumReferences); } // Allow the application to work a little return 1; } else detectState = detectGarbage_init; } break; case detectGarbage_init: { gcMap.MoveFirst(&gcMapCursor); liveObjects.SetLength(0); detectState = detectGarbage_loop1; } break; case detectGarbage_loop1: { // All objects that are known not to be dead must be removed from the map, // along with all objects they reference. What remains in the map after // this pass is sure to be dead objects in circular references. // An object is considered alive if its gcFlag is cleared, or all the // references were not found in the map. // Add all alive objects from the map to the liveObjects array if( gcMapCursor ) { asSMapNode<void*, asSIntTypePair> *cursor = gcMapCursor; gcMap.MoveNext(&gcMapCursor, gcMapCursor); void *obj = gcMap.GetKey(cursor); asSIntTypePair it = gcMap.GetValue(cursor); bool gcFlag = engine->CallObjectMethodRetBool(obj, it.type->beh.gcGetFlag); if( !gcFlag || it.i > 0 ) { liveObjects.PushLast(obj); } // Allow the application to work a little return 1; } else detectState = detectGarbage_loop2; } break; case detectGarbage_loop2: { // In this step we are actually removing the alive objects from the map. // As the object is removed, all the objects it references are added to the // liveObjects list, by calling EnumReferences. Only objects still in the map // will be added to the liveObjects list. if( liveObjects.GetLength() ) { void *gcObj = liveObjects.PopLast(); asCObjectType *type = 0; // Remove the object from the map to mark it as alive asSMapNode<void*, asSIntTypePair> *cursor = 0; if( gcMap.MoveTo(&cursor, gcObj) ) { type = gcMap.GetValue(cursor).type; ReturnNode(gcMap.Remove(cursor)); // We need to decrease the reference count again as we remove the object from the map engine->CallObjectMethod(gcObj, type->beh.release); // Enumerate all the object's references so that they too can be marked as alive engine->CallObjectMethod(gcObj, engine, type->beh.gcEnumReferences); } // Allow the application to work a little return 1; } else detectState = verifyUnmarked_init; } break; case verifyUnmarked_init: gcMap.MoveFirst(&gcMapCursor); detectState = verifyUnmarked_loop; break; case verifyUnmarked_loop: { // In this step we must make sure that none of the objects still in the map // has been touched by the application. If they have then we must run the // detectGarbage loop once more. if( gcMapCursor ) { void *gcObj = gcMap.GetKey(gcMapCursor); asCObjectType *type = gcMap.GetValue(gcMapCursor).type; bool gcFlag = engine->CallObjectMethodRetBool(gcObj, type->beh.gcGetFlag); if( !gcFlag ) { // The unmarked object was touched, rerun the detectGarbage loop detectState = detectGarbage_init; } else gcMap.MoveNext(&gcMapCursor, gcMapCursor); // Allow the application to work a little return 1; } else { // No unmarked object was touched, we can now be sure // that objects that have gcCount == 0 really is garbage detectState = breakCircles_init; } } break; case breakCircles_init: { gcMap.MoveFirst(&gcMapCursor); detectState = breakCircles_loop; } break; case breakCircles_loop: case breakCircles_haveGarbage: { // All objects in the map are now known to be dead objects // kept alive through circular references. To be able to free // these objects we need to force the breaking of the circle // by having the objects release their references. if( gcMapCursor ) { numDetected++; void *gcObj = gcMap.GetKey(gcMapCursor); asCObjectType *type = gcMap.GetValue(gcMapCursor).type; engine->CallObjectMethod(gcObj, engine, type->beh.gcReleaseAllReferences); gcMap.MoveNext(&gcMapCursor, gcMapCursor); detectState = breakCircles_haveGarbage; // Allow the application to work a little return 1; } else { // If no garbage was detected we can finish now if( detectState != breakCircles_haveGarbage ) { // Restart the GC detectState = clearCounters_init; return 0; } else { // Restart the GC detectState = clearCounters_init; return 1; } } } } // switch } // Shouldn't reach this point UNREACHABLE_RETURN; }