// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "UObject/UObjectHierarchyFwd.h" class FLinkerPlaceholderBase; struct FObjectImport; template class TLinkerImportPlaceholder; /******************************************************************************* * TLinkerImportPlaceholder<> ******************************************************************************/ //------------------------------------------------------------------------------ template int32 TLinkerImportPlaceholder::ResolveAllPlaceholderReferences(UObject* ReplacementObj) { if (UObjectRedirector* ReplacementRedirector = Cast(ReplacementObj)) { if (FLinkerLoad* ReplacementLinker = ReplacementRedirector->GetLinker()) { if (!ReplacementRedirector->HasAnyFlags(RF_LoadCompleted)) { // we're in the midst of serializing this redirector // somewhere up the stack, in some scenario like this: // // - ClassA and ClassC both depend on ClassB // - ClassB has a redirector to ClassB_2 // - ClassB_2 depends on ClassC // // if ClassA is loaded first, it then goes to load ClassB, which // seeks to serialize in its UObjectRedirector; before that's // set it loads ClassB_2 and subsequently ClassC; ClassC ends up // here, needing to use the ClassB redirector, but we haven't // returned up the stack for it to be set yet... here we force // it to finish preloading (like we do in VerifyImport): check(!GEventDrivenLoaderEnabled || !EVENT_DRIVEN_ASYNC_LOAD_ACTIVE_AT_RUNTIME); ReplacementRedirector->SetFlags(RF_NeedLoad); ReplacementLinker->Preload(ReplacementRedirector); } } ReplacementObj = ReplacementRedirector->DestinationObject; } PlaceholderType* TypeCheckedReplacement = CastChecked(ReplacementObj, ECastCheckedType::NullAllowed); int32 ReplacementCount = ResolvePropertyReferences(TypeCheckedReplacement); ReplacementCount += ResolveScriptReferences(TypeCheckedReplacement); #if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS ReplacementCount += ChildObjects.Num(); ChildObjects.Empty(); #endif//USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS ReplacementCount += DerivedFunctions.Num(); for (auto Entry : DerivedFunctions) { Entry->SetSuperStruct(TypeCheckedReplacement); } DerivedFunctions.Empty(); ReplacementCount += FLinkerPlaceholderBase::ResolveAllPlaceholderReferences(ReplacementObj); return ReplacementCount; } //------------------------------------------------------------------------------ template bool TLinkerImportPlaceholder::HasKnownReferences() const { return FLinkerPlaceholderBase::HasKnownReferences() || (ReferencingProperties.Num() > 0) || (ReferencingScriptExpressions.Num() > 0) || #if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS ChildObjects.Num() > 0 || #endif //USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS DerivedFunctions.Num() > 0; } //------------------------------------------------------------------------------ template void TLinkerImportPlaceholder::AddReferencingProperty(FFieldVariant ReferencingProperty) { #if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS UObject* ThisAsObject = GetPlaceholderAsUObject(); check(ThisAsObject != nullptr); FObjectImport* PlaceholderImport = nullptr; if (FLinkerLoad* PropertyLinker = ReferencingProperty->GetLinker()) { for (FObjectImport& Import : PropertyLinker->ImportMap) { if (Import.XObject == ThisAsObject) { PlaceholderImport = &Import; break; } } check(ThisAsObject->GetOutermost() == PropertyLinker->LinkerRoot); check(PropertyLinker->LoadFlags & LOAD_DeferDependencyLoads); } // if this check hits, then we're adding dependencies after we've // already resolved the placeholder (it won't be resolved again) check(!IsMarkedResolved()); #endif // USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS ReferencingProperties.Add(ReferencingProperty); } #if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS //------------------------------------------------------------------------------ template void TLinkerImportPlaceholder::AddChildObject(UObject* Child) { ChildObjects.Push(Child); } #endif //USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS //------------------------------------------------------------------------------ template void TLinkerImportPlaceholder::AddDerivedFunction(UStruct* DerivedFunctionType) { DerivedFunctions.Add(DerivedFunctionType); } //------------------------------------------------------------------------------ template void TLinkerImportPlaceholder::RemoveReferencingProperty(FFieldVariant ReferencingProperty) { ReferencingProperties.Remove(ReferencingProperty); } //------------------------------------------------------------------------------ template void TLinkerImportPlaceholder::AddReferencingScriptExpr(PlaceholderType** ExpressionPtr) { #if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS check(*ExpressionPtr == GetPlaceholderAsUObject()); #endif // USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS ReferencingScriptExpressions.Add(ExpressionPtr); } //------------------------------------------------------------------------------ template int32 TLinkerImportPlaceholder::ResolvePropertyReferences(PlaceholderType* ReplacementObj) { #if !CHECK_PUREVIRTUALS // requires template specialization (technically not "pure virtual"): PURE_VIRTUAL(TLinkerImportPlaceholder::ResolvePropertyReferences, return 0;) #endif } //------------------------------------------------------------------------------ template int32 TLinkerImportPlaceholder::ResolveScriptReferences(PlaceholderType* ReplacementObj) { int32 ReplacementCount = 0; PlaceholderType* PlaceholderObj = CastChecked(GetPlaceholderAsUObject()); for (PlaceholderType** ScriptRefPtr : ReferencingScriptExpressions) { PlaceholderType*& ScriptRef = *ScriptRefPtr; if (ScriptRef == PlaceholderObj) { ScriptRef = ReplacementObj; ++ReplacementCount; } } ReferencingScriptExpressions.Empty(); return ReplacementCount; }