diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 28a7104d..f02d1518 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -1313,7 +1313,7 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) continue; bool needsTypeData = (needsTypeList) || ((type->IsObject()) && (needsObjectTypeData)); - bool needsVData = (type->IsObject()) && (typeInst->mHasBeenInstantiated); + bool needsVData = (type->IsObject()) && (typeInst->HasBeenInstantiated()); bool forceReflectFields = false; @@ -2764,7 +2764,7 @@ void BfCompiler::GenerateSlotNums() if ((typeInstance->mSlotNum <= 0) || (!isHotCompile)) { if ((mContext->mReferencedIFaceSlots.Contains(typeInstance)) || - (typeInstance->mHasBeenInstantiated) || (typeInstance->mIncludeAllMethods)) + (typeInstance->mHasBeenInstantiated) || (typeInstance->IncludeAllMethods())) { if (typeInstance->mSlotNum == -2) typeInstance->mSlotNum = -1; @@ -5437,7 +5437,7 @@ void BfCompiler::PopulateReified() } // Only check virtual stuff if we have been instantiated - if (typeInst->mHasBeenInstantiated) + if (typeInst->HasBeenInstantiated()) { // If we have any virtual methods overrides that are unreified but the declaring virtual method is reified then we also need to reify for (auto&& vEntry : typeInst->mVirtualMethodTable) @@ -5468,7 +5468,7 @@ void BfCompiler::PopulateReified() auto checkType = typeInst; while (checkType != NULL) { - if ((checkType != typeInst) && (checkType->mHasBeenInstantiated)) + if ((checkType != typeInst) && (checkType->HasBeenInstantiated())) { // We will already check this type here in its own loop break; @@ -8854,7 +8854,7 @@ BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetTypeInfo(BfCompiler* bfCompiler, { if (typeInst->mIsReified) outString += " Reified"; - if (typeInst->mHasBeenInstantiated) + if (typeInst->HasBeenInstantiated()) outString += " Instantiated"; if (typeInst->mTypeFailed) outString += " TypeFailed"; diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index 8f1c1241..ccec118e 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -58,7 +58,8 @@ public: CompileState_None, CompileState_Normal, CompileState_Unreified, - CompileState_VData + CompileState_VData, + CompileState_Cleanup }; struct Stats diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index 3154eab9..d83cd5a2 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -2778,6 +2778,26 @@ void BfContext::Cleanup() // Can't clean up LLVM types, they are allocated with a bump allocator RemoveInvalidFailTypes(); + mCompiler->mCompileState = BfCompiler::CompileState_Cleanup; + + // We can't remove the local methods if they still may be referenced by a BfMethodRefType used to specialize a method + if (mMethodWorkList.empty()) + { + Array survivingLocalMethods; + + for (auto localMethod : mLocalMethodGraveyard) + { + if ((localMethod->mMethodInstanceGroup != NULL) && (localMethod->mMethodInstanceGroup->mRefCount > 0)) + { + localMethod->Dispose(); + survivingLocalMethods.push_back(localMethod); + } + else + delete localMethod; + } + mLocalMethodGraveyard = survivingLocalMethods; + } + // Clean up deleted BfTypes // These need to get deleted before the modules because we access mModule in the MethodInstance dtors for (auto type : mTypeGraveyard) @@ -2803,22 +2823,7 @@ void BfContext::Cleanup() for (auto typeDef : mTypeDefGraveyard) delete typeDef; - mTypeDefGraveyard.Clear(); - - // We can't remove the local methods if they still may be referenced by a BfMethodRefType used to specialize a method - if (mMethodWorkList.empty()) - { - Array survivingLocalMethods; - - for (auto localMethod : mLocalMethodGraveyard) - { - if ((localMethod->mMethodInstanceGroup != NULL) && (localMethod->mMethodInstanceGroup->mRefCount > 0)) - survivingLocalMethods.push_back(localMethod); - else - delete localMethod; - } - mLocalMethodGraveyard = survivingLocalMethods; - } + mTypeDefGraveyard.Clear(); mScratchModule->Cleanup(); mUnreifiedModule->Cleanup(); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 9d5fdbf0..cbb67811 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -82,11 +82,25 @@ BfLocalMethod::~BfLocalMethod() mSource->mRefCount--; BF_ASSERT(mSource->mRefCount >= 0); } - + delete mMethodInstanceGroup; delete mMethodDef; } +void BfLocalMethod::Dispose() +{ + if (mMethodInstanceGroup == NULL) + return; + if (mMethodInstanceGroup->mDefault != NULL) + mMethodInstanceGroup->mDefault->Dispose(); + + if (mMethodInstanceGroup->mMethodSpecializationMap != NULL) + { + for (auto& kv : *mMethodInstanceGroup->mMethodSpecializationMap) + kv.mValue->Dispose(); + } +} + void BfDeferredLocalAssignData::ExtendFrom(BfDeferredLocalAssignData* outerLocalAssignData, bool doChain) { mIsChained = doChain; @@ -1185,6 +1199,12 @@ void BfModule::StartNewRevision(RebuildKind rebuildKind, bool force) // causes other types rebuild BEFORE they get deleted, which is okay (though wasteful) //BF_ASSERT((mProject == NULL) || (!mProject->mDisabled)); + if (mCompiler->mCompileState == BfCompiler::CompileState_Cleanup) + { + // Cleaning up local methods may cause some necessary NewRevisions + force = true; + } + // Already on new revision? if ((mRevision == mCompiler->mRevision) && (!force)) return; @@ -1887,7 +1907,7 @@ void BfModule::AddStackAlloc(BfTypedValue val, BfIRValue arraySize, BfAstNode* r return; auto checkBaseType = val.mType->ToTypeInstance(); - if ((checkBaseType != NULL) && (checkBaseType->IsObject())) + if ((checkBaseType != NULL) && (checkBaseType->IsObject()) && (!arraySize)) { bool hadDtorCall = false; while (checkBaseType != NULL) @@ -8571,7 +8591,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget auto loadedPtr = _CreateDynAlloc(sizeValue, arrayType->mAlign); auto typedVal = BfTypedValue(mBfIRBuilder->CreateBitCast(loadedPtr, mBfIRBuilder->MapType(arrayType)), arrayType); if (!noDtorCall) - AddStackAlloc(typedVal, arraySize, NULL, scopeData, false, true); + AddStackAlloc(typedVal, BfIRValue(), NULL, scopeData, false, true); InitTypeInst(typedVal, scopeData, zeroMemory, sizeValue); return typedVal.mValue; } @@ -8610,7 +8630,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget auto typedVal = BfTypedValue(mBfIRBuilder->CreateBitCast(allocaInst, mBfIRBuilder->MapType(arrayType)), arrayType); mBfIRBuilder->ClearDebugLocation_Last(); if (!noDtorCall) - AddStackAlloc(typedVal, arraySize, NULL, scopeData, false, true); + AddStackAlloc(typedVal, BfIRValue(), NULL, scopeData, false, true); InitTypeInst(typedVal, scopeData, zeroMemory, sizeValue); return typedVal.mValue; } @@ -11118,13 +11138,13 @@ void BfModule::ProcessTypeInstCustomAttributes(bool& isPacked, bool& isUnion, bo { auto constant = mCurTypeInstance->mConstHolder->GetConstant(setProp.mParam.mValue); if ((constant != NULL) && (constant->mBool)) - mCurTypeInstance->mHasBeenInstantiated = true; + mCurTypeInstance->mAlwaysIncludeFlags = (BfAlwaysIncludeFlags)(mCurTypeInstance->mAlwaysIncludeFlags | BfAlwaysIncludeFlag_AssumeInstantiated); } else if (propertyDef->mName == "IncludeAllMethods") { auto constant = mCurTypeInstance->mConstHolder->GetConstant(setProp.mParam.mValue); if ((constant != NULL) && (constant->mBool)) - mCurTypeInstance->mIncludeAllMethods = true; + mCurTypeInstance->mAlwaysIncludeFlags = (BfAlwaysIncludeFlags)(mCurTypeInstance->mAlwaysIncludeFlags | BfAlwaysIncludeFlag_IncludeAllMethods); } } } @@ -11149,6 +11169,12 @@ void BfModule::ProcessTypeInstCustomAttributes(bool& isPacked, bool& isUnion, bo } } } + + if (customAttribute.mType->mAttributeData == NULL) + PopulateType(customAttribute.mType); + BF_ASSERT(customAttribute.mType->mAttributeData != NULL); + if ((customAttribute.mType->mAttributeData != NULL) && ((customAttribute.mType->mAttributeData->mAlwaysIncludeUser & BfAlwaysIncludeFlag_AssumeInstantiated) != 0)) + mCurTypeInstance->mAlwaysIncludeFlags = (BfAlwaysIncludeFlags)(mCurTypeInstance->mAlwaysIncludeFlags | customAttribute.mType->mAttributeData->mAlwaysIncludeUser); } } } @@ -11205,6 +11231,12 @@ void BfModule::ProcessCustomAttributeData() if (constant != NULL) attributeData->mAttributeTargets = (BfAttributeTargets)constant->mInt32; } + else if (propDef->mName == "AlwaysIncludeUser") + { + auto constant = mCurTypeInstance->mConstHolder->GetConstant(setProp.mParam.mValue); + if (constant != NULL) + attributeData->mAlwaysIncludeUser = (BfAlwaysIncludeFlags)constant->mInt32; + } } hasCustomAttribute = true; @@ -11217,6 +11249,7 @@ void BfModule::ProcessCustomAttributeData() attributeData->mAttributeTargets = mCurTypeInstance->mBaseType->mAttributeData->mAttributeTargets; attributeData->mInherited = mCurTypeInstance->mBaseType->mAttributeData->mInherited; attributeData->mAllowMultiple = mCurTypeInstance->mBaseType->mAttributeData->mAllowMultiple; + attributeData->mAlwaysIncludeUser = mCurTypeInstance->mBaseType->mAttributeData->mAlwaysIncludeUser; } mCurTypeInstance->mAttributeData = attributeData; diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index e208afbd..7c83fcef 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -247,6 +247,7 @@ public: mNextWithSameName = NULL; } ~BfLocalMethod(); + void Dispose(); }; class BfDeferredCapture diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 7d36f2b0..40667319 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -2279,7 +2279,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy return; } - if ((!mCompiler->mIsResolveOnly) && (!typeInstance->mHasBeenInstantiated)) + if ((!mCompiler->mIsResolveOnly) && (!typeInstance->HasBeenInstantiated())) { for (auto& dep : typeInstance->mDependencyMap) { @@ -2814,7 +2814,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy auto typeOptions = mSystem->GetTypeOptions(typeInstance->mTypeOptionsIdx); if (typeOptions != NULL) { - typeInstance->mHasBeenInstantiated = typeOptions->Apply(typeInstance->mHasBeenInstantiated, BfOptionFlags_ReflectAssumeInstantiated); + typeInstance->mHasBeenInstantiated = typeOptions->Apply(typeInstance->HasBeenInstantiated(), BfOptionFlags_ReflectAssumeInstantiated); } } @@ -4352,7 +4352,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) implRequired = true; declRequired = true; } - if (typeInstance->mIncludeAllMethods) + if (typeInstance->IncludeAllMethods()) implRequired = true; if ((typeOptionsIncludeAll) && (ApplyTypeOptionMethodFilters(true, methodDef, typeOptions))) @@ -4471,6 +4471,15 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) continue; if ((constant->mInt8 & BfCustomAttributeFlags_AlwaysIncludeTarget) != 0) forceMethodImpl = true; + + if (attrTypeInst->mAttributeData == NULL) + PopulateType(attrTypeInst); + BF_ASSERT(attrTypeInst->mAttributeData != NULL); + if (attrTypeInst->mAttributeData != NULL) + { + if ((attrTypeInst->mAttributeData->mAlwaysIncludeUser & BfAlwaysIncludeFlag_IncludeAllMethods) != 0) + forceMethodImpl = true; + } } } } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 79d8b7f1..d1473bc4 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -535,21 +535,7 @@ BfMethodInfoEx::~BfMethodInfoEx() BfMethodInstance::~BfMethodInstance() { - if (mMethodInstanceGroup != NULL) - { - BfLogSys(GetOwner()->mModule->mSystem, "BfMethodInstance::~BfMethodInstance %p Local:%d InCEMachine:%d\n", this, mMethodDef->mIsLocalMethod, mInCEMachine); - } - else - { - BF_ASSERT(!mMethodDef->mIsLocalMethod); - } - - if (mInCEMachine) - { - auto module = GetOwner()->mModule; - if (module->mCompiler->mCEMachine != NULL) - module->mCompiler->mCEMachine->RemoveMethod(this); - } + Dispose(true); if (mHasMethodRefType) { @@ -561,19 +547,42 @@ BfMethodInstance::~BfMethodInstance() } } + delete mMethodInfoEx; +} + +void BfMethodInstance::Dispose(bool isDeleting) +{ + if (mIsDisposed) + return; + mIsDisposed = true; + + if (mMethodInstanceGroup != NULL) + { + BfLogSys(GetOwner()->mModule->mSystem, "BfMethodInstance::~BfMethodInstance %p Local:%d InCEMachine:%d Deleting:%d\n", this, mMethodDef->mIsLocalMethod, mInCEMachine, isDeleting); + } + else + { + BF_ASSERT(!mMethodDef->mIsLocalMethod); + } + + if (mInCEMachine) + { + auto module = GetOwner()->mModule; + if (module->mCompiler->mCEMachine != NULL) + module->mCompiler->mCEMachine->RemoveMethod(this); + } + if (mMethodProcessRequest != NULL) { BF_ASSERT(mMethodProcessRequest->mMethodInstance == this); mMethodProcessRequest->mMethodInstance = NULL; } - + if (mHotMethod != NULL) - { + { mHotMethod->mFlags = (BfHotDepDataFlags)(mHotMethod->mFlags & ~BfHotDepDataFlag_IsBound); mHotMethod->Deref(); - } - - delete mMethodInfoEx; + } } void BfMethodInstance::CopyFrom(BfMethodInstance* methodInstance) @@ -2205,6 +2214,8 @@ bool BfTypeInstance::IsAlwaysInclude() auto typeOptions = mModule->mSystem->GetTypeOptions(mTypeOptionsIdx); typeOptions->Apply(alwaysInclude, BfOptionFlags_ReflectAlwaysIncludeType); } + if ((mAlwaysIncludeFlags & BfAlwaysIncludeFlag_Type) != 0) + alwaysInclude = true; return alwaysInclude; } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 7cab9dc4..6c63e97a 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -822,6 +822,7 @@ public: bool mDisallowCalling:1; bool mIsInnerOverride:1; bool mInCEMachine:1; + bool mIsDisposed:1; BfMethodChainType mChainType; BfCallingConvention mCallingConvention; BfMethodInstanceGroup* mMethodInstanceGroup; @@ -859,6 +860,7 @@ public: mDisallowCalling = false; mIsInnerOverride = false; mInCEMachine = false; + mIsDisposed = false; mChainType = BfMethodChainType_None; mCallingConvention = BfCallingConvention_Unspecified; mMethodInstanceGroup = NULL; @@ -874,6 +876,7 @@ public: } ~BfMethodInstance(); + void Dispose(bool isDeleting = false); void CopyFrom(BfMethodInstance* methodInstance); @@ -1545,6 +1548,7 @@ class BfAttributeData { public: BfAttributeTargets mAttributeTargets; + BfAlwaysIncludeFlags mAlwaysIncludeUser; bool mInherited; bool mAllowMultiple; @@ -1552,6 +1556,7 @@ public: BfAttributeData() { mAttributeTargets = BfAttributeTargets_All; + mAlwaysIncludeUser = BfAlwaysIncludeFlag_None; mInherited = true; mAllowMultiple = false; } @@ -1794,8 +1799,8 @@ public: int mInstSize; int16 mInheritDepth; int16 mSlotNum; + BfAlwaysIncludeFlags mAlwaysIncludeFlags; bool mHasBeenInstantiated; - bool mIncludeAllMethods; bool mIsReified; bool mIsTypedPrimitive; bool mIsCRepr; @@ -1861,9 +1866,9 @@ public: mBaseTypeMayBeIncomplete = false; mIsFinishingType = false; mResolvingConstField = false; - mHasPackingHoles = false; - mHasBeenInstantiated = false; - mIncludeAllMethods = false; + mHasPackingHoles = false; + mAlwaysIncludeFlags = BfAlwaysIncludeFlag_None; + mHasBeenInstantiated = false; mWantsGCMarking = false; mHasParameterizedBase = false; mHasDeclError = false; @@ -1952,7 +1957,10 @@ public: bool GetResultInfo(BfType*& valueType, int& okTagId); BfGenericTypeInfo::GenericParamsVector* GetGenericParamsVector(BfTypeDef* declaringTypeDef); void GenerateProjectsReferenced(); - bool IsAlwaysInclude(); + bool IsAlwaysInclude(); + bool HasBeenInstantiated() { return mHasBeenInstantiated || ((mAlwaysIncludeFlags & BfAlwaysIncludeFlag_AssumeInstantiated) != 0); } + bool IncludeAllMethods() { return ((mAlwaysIncludeFlags & BfAlwaysIncludeFlag_IncludeAllMethods) != 0); } + virtual void ReportMemory(MemReporter* memReporter) override; }; diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 3a736c0e..2702338e 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -200,7 +200,7 @@ enum BfObjectFlags : uint8 BfObjectFlag_StackDeleted = 0x80 // We remove StackAlloc so it doesn't get scanned }; -enum BfCustomAttributeFlags +enum BfCustomAttributeFlags : uint8 { BfCustomAttributeFlags_None, BfCustomAttributeFlags_DisallowAllowMultiple = 1, @@ -209,6 +209,15 @@ enum BfCustomAttributeFlags BfCustomAttributeFlags_AlwaysIncludeTarget = 8 }; +enum BfAlwaysIncludeFlags : uint8 +{ + BfAlwaysIncludeFlag_None = 0, + BfAlwaysIncludeFlag_Type = 1, + BfAlwaysIncludeFlag_IncludeAllMethods = 2, + BfAlwaysIncludeFlag_AssumeInstantiated = 4, + BfAlwaysIncludeFlag_All = BfAlwaysIncludeFlag_Type | BfAlwaysIncludeFlag_IncludeAllMethods | BfAlwaysIncludeFlag_AssumeInstantiated +}; + enum BfPlatformType { BfPlatformType_Unknown,