int asCGarbageCollector::DestroyNewGarbage() { for(;;) { switch( destroyNewState ) { case destroyGarbage_init: { // If there are no objects to be freed then don't start if( gcNewObjects.GetLength() == 0 ) return 0; destroyNewIdx = (asUINT)-1; destroyNewState = destroyGarbage_loop; } break; case destroyGarbage_loop: case destroyGarbage_haveMore: { // If the refCount has reached 1, then only the GC still holds a // reference to the object, thus we don't need to worry about the // application touching the objects during collection. // Destroy all objects that have refCount == 1. If any objects are // destroyed, go over the list again, because it may have made more // objects reach refCount == 1. if( ++destroyNewIdx < gcNewObjects.GetLength() ) { asSObjTypePair gcObj = GetNewObjectAtIdx(destroyNewIdx); if( engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount) == 1 ) { // Release the object immediately // Make sure the refCount is really 0, because the // destructor may have increased the refCount again. bool addRef = false; if( gcObj.type->flags & asOBJ_SCRIPT_OBJECT ) { // Script objects may actually be resurrected in the destructor int refCount = ((asCScriptObject*)gcObj.obj)->Release(); if( refCount > 0 ) addRef = true; } else engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release); // Was the object really destroyed? if( !addRef ) { numDestroyed++; numNewDestroyed++; RemoveNewObjectAtIdx(destroyNewIdx); destroyNewIdx--; } else { // Since the object was resurrected in the // destructor, we must add our reference again engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref); } destroyNewState = destroyGarbage_haveMore; } else if( gcObj.count == 3 ) { // We've already verified this object multiple times. It is likely // to live for quite a long time so we'll move it to the list if old objects MoveObjectToOldList(destroyNewIdx); destroyNewIdx--; } else { // Increase the counter for the number of times the object has been verified IncreaseCounterForNewObject(destroyNewIdx); } // Allow the application to work a little return 1; } else { if( destroyNewState == destroyGarbage_haveMore ) { // Restart the cycle destroyNewState = destroyGarbage_init; } else { // Restart the cycle destroyNewState = destroyGarbage_init; // Return 0 to tell the application that there // is no more garbage to destroy at the moment return 0; } } } break; } } // Shouldn't reach this point UNREACHABLE_RETURN; }
int asCGarbageCollector::DestroyNewGarbage() { // This function will only be called within the critical section gcCollecting asASSERT(isProcessing); for(;;) { switch( destroyNewState ) { case destroyGarbage_init: { // If there are no objects to be freed then don't start if( gcNewObjects.GetLength() == 0 ) return 0; // Update the seqAtSweepStart which is used to determine when // to move an object from the new set to the old set seqAtSweepStart[0] = seqAtSweepStart[1]; seqAtSweepStart[1] = seqAtSweepStart[2]; seqAtSweepStart[2] = numAdded; destroyNewIdx = (asUINT)-1; destroyNewState = destroyGarbage_loop; } break; case destroyGarbage_loop: case destroyGarbage_haveMore: { // If the refCount has reached 1, then only the GC still holds a // reference to the object, thus we don't need to worry about the // application touching the objects during collection. // Destroy all objects that have refCount == 1. If any objects are // destroyed, go over the list again, because it may have made more // objects reach refCount == 1. if( ++destroyNewIdx < gcNewObjects.GetLength() ) { asSObjTypePair gcObj = GetNewObjectAtIdx(destroyNewIdx); if( engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount) == 1 ) { // Release the object immediately // Make sure the refCount is really 0, because the // destructor may have increased the refCount again. bool addRef = false; if( gcObj.type->flags & asOBJ_SCRIPT_OBJECT ) { // Script objects may actually be resurrected in the destructor int refCount = ((asCScriptObject*)gcObj.obj)->Release(); if( refCount > 0 ) addRef = true; } else engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release); // Was the object really destroyed? if( !addRef ) { numDestroyed++; numNewDestroyed++; RemoveNewObjectAtIdx(destroyNewIdx); destroyNewIdx--; } else { // Since the object was resurrected in the // destructor, we must add our reference again engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref); } destroyNewState = destroyGarbage_haveMore; } // Check if this object has been inspected 3 times already, and if so move it to the // set of old objects that are less likely to become garbage in a short time // TODO: Is 3 really a good value? Should the number of times be dynamic? else if( gcObj.seqNbr < seqAtSweepStart[0] ) { // We've already verified this object multiple times. It is likely // to live for quite a long time so we'll move it to the list if old objects MoveObjectToOldList(destroyNewIdx); destroyNewIdx--; } // Allow the application to work a little return 1; } else { if( destroyNewState == destroyGarbage_haveMore ) { // Restart the cycle destroyNewState = destroyGarbage_init; } else { // Restart the cycle destroyNewState = destroyGarbage_init; // Return 0 to tell the application that there // is no more garbage to destroy at the moment return 0; } } } break; } } // Shouldn't reach this point UNREACHABLE_RETURN; }