void FUObjectArray::AllocateUObjectIndex(UObjectBase* Object, bool bMergingThreads /*= false*/) { int32 Index = INDEX_NONE; check(Object->InternalIndex == INDEX_NONE || bMergingThreads); // Special non- garbage collectable range. if (OpenForDisregardForGC && DisregardForGCEnabled()) { // Disregard from GC pool is only available from the game thread, at least for now check(IsInGameThread()); Index = ++ObjLastNonGCIndex; // Check if we're not out of bounds, unless there hasn't been any gc objects yet UE_CLOG(ObjLastNonGCIndex >= MaxObjectsNotConsideredByGC && ObjFirstGCIndex >= 0, LogUObjectArray, Fatal, TEXT("Unable to add more objects to disregard for GC pool (Max: %d)"), MaxObjectsNotConsideredByGC); // If we haven't added any GC objects yet, it's fine to keep growing the disregard pool past its initial size. if (ObjLastNonGCIndex >= MaxObjectsNotConsideredByGC) { Index = ObjObjects.AddSingle(); check(Index == ObjLastNonGCIndex); } MaxObjectsNotConsideredByGC = FMath::Max(MaxObjectsNotConsideredByGC, ObjLastNonGCIndex + 1); } // Regular pool/ range. else { int32* AvailableIndex = ObjAvailableList.Pop(); if (AvailableIndex) { #if UE_GC_TRACK_OBJ_AVAILABLE const int32 AvailableCount = ObjAvailableCount.Decrement(); checkSlow(AvailableCount >= 0); #endif Index = (int32)(uintptr_t)AvailableIndex; check(ObjObjects[Index].Object==nullptr); } else { // Make sure ObjFirstGCIndex is valid, otherwise we didn't close the disregard for GC set check(ObjFirstGCIndex >= 0); #if THREADSAFE_UOBJECTS FScopeLock ObjObjectsLock(&ObjObjectsCritical); #else check(IsInGameThread()); #endif Index = ObjObjects.AddSingle(); } check(Index >= ObjFirstGCIndex && Index > ObjLastNonGCIndex); } // Add to global table. if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&ObjObjects[Index].Object, Object, NULL) != NULL) // we use an atomic operation to check for unexpected concurrency, verify alignment, etc { UE_LOG(LogUObjectArray, Fatal, TEXT("Unexpected concurency while adding new object")); } IndexToObject(Index)->ResetSerialNumberAndFlags(); Object->InternalIndex = Index; // @todo: threading: lock UObjectCreateListeners for (int32 ListenerIndex = 0; ListenerIndex < UObjectCreateListeners.Num(); ListenerIndex++) { UObjectCreateListeners[ListenerIndex]->NotifyUObjectCreated(Object,Index); } }
void FUObjectArray::AllocateUObjectIndex(UObjectBase* Object, bool bMergingThreads /*= false*/) { int32 Index = INDEX_NONE; check(Object->InternalIndex == INDEX_NONE || bMergingThreads); // Special non- garbage collectable range. if (OpenForDisregardForGC && DisregardForGCEnabled()) { // Disregard from GC pool is only available from the game thread, at least for now check(IsInGameThread()); Index = ObjObjects.AddZeroed(1); ObjLastNonGCIndex = Index; ObjFirstGCIndex = FMath::Max(ObjFirstGCIndex, Index + 1); } // Regular pool/ range. else { int32* AvailableIndex = ObjAvailableList.Pop(); if (AvailableIndex) { #if WITH_EDITOR ObjAvailableCount.Decrement(); checkSlow(ObjAvailableCount.GetValue() >= 0); #endif Index = (int32)(uintptr_t)AvailableIndex; check(ObjObjects[Index]==nullptr); } else { #if THREADSAFE_UOBJECTS FScopeLock ObjObjectsLock(&ObjObjectsCritical); #else check(IsInGameThread()); #endif Index = ObjObjects.AddZeroed(1); } check(Index >= ObjFirstGCIndex); } // Add to global table. if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&ObjObjects[Index], Object, NULL) != NULL) // we use an atomic operation to check for unexpected concurrency, verify alignment, etc { UE_LOG(LogUObjectArray, Fatal, TEXT("Unexpected concurency while adding new object")); } Object->InternalIndex = Index; // @todo: threading: lock UObjectCreateListeners for (int32 ListenerIndex = 0; ListenerIndex < UObjectCreateListeners.Num(); ListenerIndex++) { UObjectCreateListeners[ListenerIndex]->NotifyUObjectCreated(Object,Index); } }