diff --git a/BeefLibs/corlib/src/Attribute.bf b/BeefLibs/corlib/src/Attribute.bf index 21358256..fa03996b 100644 --- a/BeefLibs/corlib/src/Attribute.bf +++ b/BeefLibs/corlib/src/Attribute.bf @@ -260,6 +260,12 @@ namespace System } + [AttributeUsage(.Method | .Invocation)] + public struct ConstEvalAttribute : Attribute + { + + } + [AttributeUsage(.Method /*2*/)] public struct IntrinsicAttribute : Attribute { diff --git a/BeefLibs/corlib/src/Compiler.bf b/BeefLibs/corlib/src/Compiler.bf index f40ab63a..b34bb38e 100644 --- a/BeefLibs/corlib/src/Compiler.bf +++ b/BeefLibs/corlib/src/Compiler.bf @@ -34,5 +34,21 @@ namespace System [LinkName("#IsConstEval")] public static extern bool IsConstEval; + + [LinkName("#IsBuilding")] + public static extern bool IsBuilding; + + [LinkName("#IsReified")] + public static extern bool IsReified; + + [LinkName("#CompileRev")] + public static extern int32 CompileRev; + + [ConstEval] + public static void Assert(bool cond) + { + if (!cond) + Runtime.FatalError("Assert failed"); + } } } diff --git a/BeefLibs/corlib/src/Reflection/FieldInfo.bf b/BeefLibs/corlib/src/Reflection/FieldInfo.bf index 31adddd2..fbef25ad 100644 --- a/BeefLibs/corlib/src/Reflection/FieldInfo.bf +++ b/BeefLibs/corlib/src/Reflection/FieldInfo.bf @@ -36,6 +36,30 @@ namespace System.Reflection } } + public bool IsConst + { + get + { + return mFieldData.mFlags.HasFlag(.Const); + } + } + + public bool IsStatic + { + get + { + return mFieldData.mFlags.HasFlag(.Static); + } + } + + public bool IsInstanceField + { + get + { + return !mFieldData.mFlags.HasFlag(.Static) && !mFieldData.mFlags.HasFlag(.Const); + } + } + public StringView Name { get @@ -520,6 +544,14 @@ namespace System.Reflection } } + public int32 Index + { + get + { + return mIdx; + } + } + public Result GetNext() mut { if (!MoveNext()) diff --git a/BeefLibs/corlib/src/Type.bf b/BeefLibs/corlib/src/Type.bf index 031c96c1..34d84bb1 100644 --- a/BeefLibs/corlib/src/Type.bf +++ b/BeefLibs/corlib/src/Type.bf @@ -454,14 +454,20 @@ namespace System { return (int32)mTypeId; } - + + static extern Type ConstEval_GetTypeById(int32 typeId); + protected static Type GetType(TypeId typeId) { + if (Compiler.IsConstEval) + return ConstEval_GetTypeById((.)typeId); return sTypes[(int32)typeId]; } protected static Type GetType_(int32 typeId) { + if (Compiler.IsConstEval) + return ConstEval_GetTypeById(typeId); return sTypes[typeId]; } diff --git a/BeefySysLib/util/PerfTimer.h b/BeefySysLib/util/PerfTimer.h index 18f69a1f..c8ed815c 100644 --- a/BeefySysLib/util/PerfTimer.h +++ b/BeefySysLib/util/PerfTimer.h @@ -148,6 +148,24 @@ public: ~AutoPerfRecordAndPrint(); }; +class AutoTimer +{ +public: + uint32 mStartTick; + int* mTimePtr; + +public: + AutoTimer(int& timeRef) + { + mTimePtr = &timeRef; + mStartTick = BFTickCount(); + } + + ~AutoTimer() + { + *mTimePtr += BFTickCount() - mStartTick; + } +}; class DebugTimeGuard { diff --git a/IDE/mintest/minlib/src/System/Attribute.bf b/IDE/mintest/minlib/src/System/Attribute.bf index 63b5be57..6318c556 100644 --- a/IDE/mintest/minlib/src/System/Attribute.bf +++ b/IDE/mintest/minlib/src/System/Attribute.bf @@ -231,6 +231,12 @@ namespace System } + [AttributeUsage(.Method | .Invocation)] + public struct ConstEvalAttribute : Attribute + { + + } + [AttributeUsage(.Method /*2*/)] public struct IntrinsicAttribute : Attribute { diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index aa492127..93715442 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -11781,6 +11781,9 @@ namespace IDE bool didClean = false; if (mWantsBeefClean) { + mBfBuildCompiler?.CancelBackground(); + mBfResolveCompiler?.CancelBackground(); + if ((!mBfBuildCompiler.HasQueuedCommands()) && ((mBfResolveCompiler == null) || (!mBfResolveCompiler.HasQueuedCommands()))) { @@ -11857,6 +11860,9 @@ namespace IDE if (mWantsClean) { + mBfBuildCompiler?.CancelBackground(); + mBfResolveCompiler?.CancelBackground(); + if ((!mBfBuildCompiler.HasQueuedCommands()) && (!mBfResolveCompiler.HasQueuedCommands()) #if IDE_C_SUPPORT && (!mDepClang.HasQueuedCommands()) && (!mResolveClang.HasQueuedCommands()) diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index bcd17036..641ab51d 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -1027,6 +1027,18 @@ namespace IDE.ui doBackground = true; } + // If there's a long-running const eval then cancel that first + if (!mDeferredResolveResults.IsEmpty) + { + for (var result in mDeferredResolveResults) + { + if (result.mResolveType == .ClassifyFullRefresh) + { + bfCompiler.RequestCancelBackground(); + } + } + } + if (mIsClang) { #if !IDE_C_SUPPORT diff --git a/IDE/src/ui/StatusBar.bf b/IDE/src/ui/StatusBar.bf index 29a97592..0ef7ed2e 100644 --- a/IDE/src/ui/StatusBar.bf +++ b/IDE/src/ui/StatusBar.bf @@ -26,6 +26,9 @@ namespace IDE.ui public int mDirtyDelay; public int mStatusBoxUpdateCnt = -1; + public int32 mResolveStuckTicks; + public float mResolveLastPct = -1; + public this() { mConfigComboBox = new DarkComboBox(); @@ -225,8 +228,19 @@ namespace IDE.ui #endif ) { + float completionPct = gApp.mBfResolveCompiler.GetCompletionPercentage(); + if (completionPct != mResolveLastPct) + { + mResolveStuckTicks = 0; + mResolveLastPct = completionPct; + } + else + mResolveStuckTicks++; + MarkDirtyEx(); } + else + mResolveStuckTicks = 0; } public override void Draw(Graphics g) @@ -380,6 +394,10 @@ namespace IDE.ui { DrawStatusBox("Custom Build Commands...", gApp.mBuildContext.mUpdateCnt); } + else if (mResolveStuckTicks > 300) + { + DrawStatusBox("Const Evaluation"); + } else mStatusBoxUpdateCnt = -1; diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index 2d04c34e..dc13e812 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -470,8 +470,8 @@ void BfAutoComplete::AddMethod(BfTypeInstance* typeInstance, BfMethodDef* method if (auto entryAdded = AddEntry(entry, filter)) { if (methodDecl != NULL) - { - if ((methodInstance != NULL) && (methodInstance->mMethodDef->mIsLocalMethod) && (GetCursorIdx(methodDecl) == methodDecl->mReturnType->mSrcEnd)) + { + if ((methodInstance != NULL) && (methodInstance->mMethodDef->mIsLocalMethod) && (methodDecl->mReturnType != NULL) && (GetCursorIdx(methodDecl) == methodDecl->mReturnType->mSrcEnd)) { // This isn't really a local method decl, it just looks like one return; diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index a953b335..364ca044 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -397,6 +397,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) mActionTypeDef = NULL; mEnumTypeDef = NULL; mFriendAttributeTypeDef = NULL; + mConstEvalAttributeTypeDef = NULL; mNoExtensionAttributeTypeDef = NULL; mCheckedAttributeTypeDef = NULL; mUncheckedAttributeTypeDef = NULL; @@ -406,7 +407,8 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) mGenericIEnumeratorTypeDef = NULL; mGenericIRefEnumeratorTypeDef = NULL; mInlineAttributeTypeDef = NULL; - mInternalTypeDef = NULL; + mThreadTypeDef = NULL; + mInternalTypeDef = NULL; mDiagnosticsDebugTypeDef = NULL; mIDisposableTypeDef = NULL; mIPrintableTypeDef = NULL; @@ -6596,6 +6598,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) mActionTypeDef = _GetRequiredType("System.Action"); mEnumTypeDef = _GetRequiredType("System.Enum"); mFriendAttributeTypeDef = _GetRequiredType("System.FriendAttribute"); + mConstEvalAttributeTypeDef = _GetRequiredType("System.ConstEvalAttribute"); mNoExtensionAttributeTypeDef = _GetRequiredType("System.NoExtensionAttribute"); mCheckedAttributeTypeDef = _GetRequiredType("System.CheckedAttribute"); mUncheckedAttributeTypeDef = _GetRequiredType("System.UncheckedAttribute"); @@ -6606,6 +6609,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) mGenericIEnumeratorTypeDef = _GetRequiredType("System.Collections.IEnumerator", 1); mGenericIRefEnumeratorTypeDef = _GetRequiredType("System.Collections.IRefEnumerator", 1); mInlineAttributeTypeDef = _GetRequiredType("System.InlineAttribute"); + mThreadTypeDef = _GetRequiredType("System.Threading.Thread"); mInternalTypeDef = _GetRequiredType("System.Internal"); mDiagnosticsDebugTypeDef = _GetRequiredType("System.Diagnostics.Debug"); mIDisposableTypeDef = _GetRequiredType("System.IDisposable"); @@ -7258,6 +7262,11 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) mPassInstance->OutputLine(StrFormat(":low %d module%s built, %d object file%s generated", numModulesWritten, (numModulesWritten != 1) ? "s" : "", numObjFilesWritten, (numObjFilesWritten != 1) ? "s" : "")); + + if ((mCEMachine != NULL) && (!mIsResolveOnly) && (mCEMachine->mRevisionExecuteTime > 0)) + { + mPassInstance->OutputLine(StrFormat(":med Const evaluation time: %0.2fs", mCEMachine->mRevisionExecuteTime / 1000.0f)); + } BpLeave(); mPassInstance->WriteErrorSummary(); diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index a6302347..dc9bb418 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -359,6 +359,7 @@ public: BfTypeDef* mGenericIEnumeratorTypeDef; BfTypeDef* mGenericIRefEnumeratorTypeDef; + BfTypeDef* mThreadTypeDef; BfTypeDef* mInternalTypeDef; BfTypeDef* mDiagnosticsDebugTypeDef; BfTypeDef* mIDisposableTypeDef; @@ -401,6 +402,7 @@ public: BfTypeDef* mDisableChecksAttributeTypeDef; BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef; BfTypeDef* mFriendAttributeTypeDef; + BfTypeDef* mConstEvalAttributeTypeDef; BfTypeDef* mNoExtensionAttributeTypeDef; BfTypeDef* mCheckedAttributeTypeDef; BfTypeDef* mUncheckedAttributeTypeDef; diff --git a/IDEHelper/Compiler/BfConstResolver.cpp b/IDEHelper/Compiler/BfConstResolver.cpp index c4a1ffde..171fb94d 100644 --- a/IDEHelper/Compiler/BfConstResolver.cpp +++ b/IDEHelper/Compiler/BfConstResolver.cpp @@ -36,7 +36,7 @@ BfConstResolver::BfConstResolver(BfModule* bfModule) : BfExprEvaluator(bfModule) BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfConstResolveFlags flags) { - mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstExpr); + mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstEval); // Handle the 'int[?] val = .(1, 2, 3)' case if ((flags & BfConstResolveFlag_ArrayInitSize) != 0) @@ -76,7 +76,7 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo } else { - mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(BfTypeCode_IntPtr), mModule->GetPrimitiveType(BfTypeCode_IntPtr)); + mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->GetPrimitiveType(BfTypeCode_IntPtr)), mModule->GetPrimitiveType(BfTypeCode_IntPtr)); return mResult; } } @@ -176,7 +176,7 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo BfTypedValue result; result.mKind = BfTypedValueKind_Value; result.mType = genericTypeConstraint; - result.mValue = mModule->mBfIRBuilder->GetUndefConstValue(primType->mTypeDef->mTypeCode); + result.mValue = mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->GetPrimitiveType(primType->mTypeDef->mTypeCode)); return result; } } diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index 21066146..7c7d0e95 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -821,6 +821,8 @@ void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef methodDef->mIsNoReturn = true; else if (typeRefName == "SkipCall") methodDef->mIsSkipCall = true; + else if (typeRefName == "ConstEval") + methodDef->mIsConstEval = true; else if (typeRefName == "NoShow") methodDef->mIsNoShow = true; else if (typeRefName == "NoDiscard") diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 27c67ce7..5ec674df 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -2630,14 +2630,14 @@ BfAutoComplete* BfExprEvaluator::GetAutoComplete() bool BfExprEvaluator::IsConstEval() { - return (mModule->mIsConstModule) || ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0); + return (mModule->mIsConstModule) || ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0); } bool BfExprEvaluator::IsConstEvalEntry() { if (mModule->mIsConstModule) return false; - return ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0); + return ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0); } int BfExprEvaluator::GetStructRetIdx(BfMethodInstance* methodInstance, bool forceStatic) @@ -3263,6 +3263,11 @@ void BfExprEvaluator::Visit(BfLiteralExpression* literalExpr) void BfExprEvaluator::Visit(BfStringInterpolationExpression* stringInterpolationExpression) { + if (IsConstEvalEntry()) + { + mModule->Fail("Const evaluation of string interpolation not allowed", stringInterpolationExpression); + } + if ((mBfEvalExprFlags & BfEvalExprFlags_StringInterpolateFormat) != 0) { BfVariant variant; @@ -4993,6 +4998,20 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* } } + if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0) + { + if (methodInstance->mReturnType->IsInstanceOf(mModule->mCompiler->mSpanTypeDef)) + { + if (mExpectingType->IsSizedArray()) + { + return BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(mExpectingType)), mExpectingType); + } + } + if (methodInstance->mReturnType->IsValuelessType()) + return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), methodInstance->mReturnType); + return BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(methodInstance->mReturnType)), methodInstance->mReturnType); + } + BfTypedValue result; if (sret != NULL) result = *sret; @@ -5009,15 +5028,15 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* { mModule->mCompiler->mCEMachine->QueueMethod(methodInstance, func); } - else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0) + else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0) { if (mFunctionBindResult != NULL) { forceBind = true; } - else if (mUsedAsStatement) + else if ((mBfEvalExprFlags & BfEvalExprFlags_InCascade) != 0) { - // Don't allow use in a cascade + mModule->Fail("Const evaluation not allowed with cascade operator", targetSrc); } else { @@ -5648,7 +5667,7 @@ void BfExprEvaluator::PushArg(BfTypedValue argVal, SizedArrayImpl& ir { if (argVal.mType->IsComposite()) { - if ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0) + if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0) { // Const eval entry - we want any incoming consts as they are } @@ -6121,7 +6140,24 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu if (methodDef->mMethodType == BfMethodType_Extension) numElements++; - if (wantType->IsArray()) + if (IsConstEvalEntry()) + { + if ((wantType->IsArray()) || (wantType->IsInstanceOf(mModule->mCompiler->mSpanTypeDef))) + { + auto genericTypeInst = wantType->ToGenericTypeInstance(); + expandedParamsElementType = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[0]; + + auto irSizedArrayType = mModule->mBfIRBuilder->GetSizedArrayType(mModule->mBfIRBuilder->MapType(expandedParamsElementType), numElements); + + Array values; + for (int i = 0; i < numElements; i++) + values.Add(mModule->mBfIRBuilder->GetFakeVal()); + expandedParamsArray = BfTypedValue(mModule->mBfIRBuilder->CreateConstAgg(irSizedArrayType, values), wantType); + + PushArg(expandedParamsArray, irArgs); + } + } + else if (wantType->IsArray()) { BfArrayType* arrayType = (BfArrayType*)wantType; mModule->PopulateType(arrayType, BfPopulateType_DataAndMethods); @@ -6152,9 +6188,9 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu PushArg(expandedParamsArray, irArgs); } - else + else if (wantType->IsInstanceOf(mModule->mCompiler->mSpanTypeDef)) { - auto genericTypeInst = wantType->ToGenericTypeInstance(); + auto genericTypeInst = wantType->ToGenericTypeInstance(); expandedParamsElementType = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[0]; expandedParamsArray = BfTypedValue(mModule->CreateAlloca(wantType), wantType, true); @@ -6538,7 +6574,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu { if (argValue) { - if (expandedParamAlloca) + if (IsConstEvalEntry()) + { + auto constant = mModule->mBfIRBuilder->GetConstant(expandedParamsArray.mValue); + BF_ASSERT(constant->mConstType == BfConstType_Agg); + auto constAgg = (BfConstantAgg*)constant; + constAgg->mValues[extendedParamIdx] = argValue.mValue; + } + else if (expandedParamAlloca) { argValue = mModule->LoadValue(argValue); auto addr = mModule->mBfIRBuilder->CreateInBoundsGEP(expandedParamAlloca, extendedParamIdx); @@ -7965,7 +8008,9 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp mResultLocalVar = NULL; mResultFieldInstance = NULL; mResultLocalVarRefNode = NULL; - MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, false); + auto result = MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, false); + if ((result) && (!result.mType->IsVoid())) + return result; mModule->ValidateAllocation(resolvedTypeInstance, targetSrc); mModule->AddDependency(resolvedTypeInstance, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_LocalUsage); @@ -8368,7 +8413,26 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp mModule->MethodToString(moduleMethodInstance.mMethodInstance).c_str(), mModule->MethodToString(mModule->mCurMethodInstance).c_str()), targetSrc); } - auto result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, bypassVirtual, argValues.mResolvedArgs, skipThis); + + BfTypedValue result; + + // + { + SetAndRestoreValue prevEvalExprFlag(mBfEvalExprFlags); + + if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) && (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mConstEvalAttributeTypeDef))) + { + mModule->mAttributeState->mUsed = true; + mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstEval); + } + else if (moduleMethodInstance.mMethodInstance->mMethodDef->mIsConstEval) + { + mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstEval); + } + + result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, bypassVirtual, argValues.mResolvedArgs, skipThis); + } + if (result) { if (result.mType->IsRef()) @@ -9474,7 +9538,7 @@ void BfExprEvaluator::DoTypeIntAttr(BfTypeReference* typeRef, BfToken token) // We do this so we know it's a constant but we can't assume anything about its value // We make the value an Int32 which doesn't match the IntPtr type, but it allows us to // assume it can be implicitly cased to int32 - mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(BfTypeCode_Int32), sizeType); + mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(sizeType)), sizeType); } else mResult = BfTypedValue(mModule->GetConstValue(attrVal, sizeType), sizeType); @@ -11918,7 +11982,7 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam mModule->mCurMethodState->mHotDataReferenceBuilder->mInnerMethods.Add(methodInstance->mHotMethod); methodState.Reset(); - + lambdaInstance = new BfLambdaInstance(); rootMethodState->mLambdaCache[cacheNodeList] = lambdaInstance; lambdaInstance->mDelegateTypeInstance = delegateTypeInstance; @@ -12022,6 +12086,8 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam mModule->mCurMethodState->mHotDataReferenceBuilder->mInnerMethods.Add(dtorMethodInstance->mHotMethod); lambdaInstance->mDtorMethodInstance = dtorMethodInstance; lambdaInstance->mDtorFunc = dtorFunc; + + dtorMethodInstance->mMethodInstanceGroup = NULL; } prevClosureState.Restore(); @@ -12043,7 +12109,7 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam if (processMethods) rootMethodState->mDeferredLambdaInstances.Add(lambdaInstance); - methodInstance->mMethodInstanceGroup = NULL; + methodInstance->mMethodInstanceGroup = NULL; return lambdaInstance; } @@ -13199,7 +13265,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs { allocValue = mModule->AllocFromType(resolvedTypeRef, allocTarget, appendSizeValue, BfIRValue(), 0, BfAllocFlags_None, allocAlign); } - if (((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0) && (mModule->mCompiler->mCEMachine != NULL)) + if (((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0) && (mModule->mCompiler->mCEMachine != NULL)) { mModule->mCompiler->mCEMachine->SetAppendAllocInfo(mModule, allocValue, appendSizeValue); } @@ -13250,7 +13316,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs { mModule->AssertErrorState(); } - else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) == 0) + else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) == 0) { SizedArray irArgs; irArgs.push_back(mResult.mValue); @@ -13328,7 +13394,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs } } - if (((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0) && (mModule->mCompiler->mCEMachine != NULL)) + if (((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0) && (mModule->mCompiler->mCEMachine != NULL)) { mModule->mCompiler->mCEMachine->ClearAppendAllocInfo(); } @@ -15362,6 +15428,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m int methodCount = 0; bool mayBeSkipCall = false; + bool mayBeConstEvalCall = false; if (thisValue.mType != NULL) { if (thisValue.mType->IsAllocType()) @@ -15379,6 +15446,8 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m { if (methodDef->mIsSkipCall) mayBeSkipCall = true; + if (methodDef->mIsConstEval) + mayBeConstEvalCall = true; methodDef = methodDef->mNextWithSameName; } } @@ -15404,7 +15473,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m BfResolveArgFlags resolveArgsFlags = (BfResolveArgFlags)(BfResolveArgFlag_DeferFixits | BfResolveArgFlag_AllowUnresolvedTypes); resolveArgsFlags = (BfResolveArgFlags)(resolveArgsFlags | BfResolveArgFlag_DeferParamEval); - if (mayBeSkipCall) + if ((mayBeSkipCall) || (mayBeConstEvalCall)) resolveArgsFlags = (BfResolveArgFlags)(resolveArgsFlags | BfResolveArgFlag_DeferParamValues); static int sCallIdx = 0; @@ -15430,10 +15499,13 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m } } - if ((isCascade) && (cascadeOperatorToken != NULL) && ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0)) + if ((isCascade) && (cascadeOperatorToken != NULL) && ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0)) mModule->Fail("Cascade operator cannot be used in const evaluation", cascadeOperatorToken); SetAndRestoreValue prevUsedAsStatement(mUsedAsStatement, mUsedAsStatement || isCascade); + SetAndRestoreValue prevEvalExprFlags(mBfEvalExprFlags); + if (isCascade) + mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_InCascade); ResolveArgValues(argValues, resolveArgsFlags); mResult = MatchMethod(methodNodeSrc, methodBoundExpr, thisValue, allowImplicitThis, bypassVirtual, targetFunctionName, argValues, methodGenericArguments, checkedKind); argValues.HandleFixits(mModule); @@ -15840,7 +15912,7 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp else { BF_ASSERT(mModule->mCurMethodInstance->mIsUnspecialized); - mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(BfTypeCode_IntPtr), mModule->GetPrimitiveType(BfTypeCode_IntPtr)); + mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->GetPrimitiveType(BfTypeCode_IntPtr)), mModule->GetPrimitiveType(BfTypeCode_IntPtr)); handled = true; } } @@ -17166,8 +17238,8 @@ void BfExprEvaluator::InitializedSizedArray(BfSizedArrayType* arrayType, BfToken { if (checkArrayType->mElementCount == -1) { - mModule->Fail("Initializers not supported for unknown-sized arrays", valueExprs[0]); - failedAt.Add(depth); +// mModule->Fail("Initializers not supported for unknown-sized arrays", valueExprs[0]); +// failedAt.Add(depth); } else if (initCountDiff > 0) { @@ -17453,6 +17525,10 @@ void BfExprEvaluator::InitializedSizedArray(BfSizedArrayType* arrayType, BfToken members.push_back(defaultVal.mValue); } + auto allocArrayType = checkArrayType; + if (checkArrayType->IsUndefSizedArray()) + allocArrayType = mModule->CreateSizedArrayType(checkArrayType->GetUnderlyingType(), (int)members.size()); + if (checkArrayType->mElementType->IsStruct()) { // This fixed cases where we have non-size-aligned initializers. Assume zero-initialized @@ -17629,19 +17705,63 @@ void BfExprEvaluator::Visit(BfTupleExpression* tupleExpr) mResult = *mReceivingValue; mReceivingValue = NULL; curTupleValue = mResult.mValue; - } + } else { + int valueIdx = -1; + bool isExactConst = true; + + for (int fieldIdx = 0; fieldIdx < (int)tupleType->mFieldInstances.size(); fieldIdx++) + { + BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx]; + if (fieldInstance->mDataIdx < 0) + continue; + ++valueIdx; + auto typedValue = typedValues[valueIdx]; + if (typedValue.mType != fieldInstance->mResolvedType) + { + isExactConst = false; + break; + } + if (!typedValue.mValue.IsConst()) + { + isExactConst = false; + break; + } + } + + if (isExactConst) + { + mModule->PopulateType(tupleType); + + Array irValues; + irValues.Resize(typedValues.mSize + 1); + irValues[0] = mModule->mBfIRBuilder->CreateConstStructZero(mModule->mBfIRBuilder->MapType(tupleType->mBaseType)); + + for (int fieldIdx = 0; fieldIdx < (int)tupleType->mFieldInstances.size(); fieldIdx++) + { + BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx]; + if (fieldInstance->mDataIdx < 0) + continue; + irValues[fieldInstance->mDataIdx] = typedValues[fieldIdx].mValue; + } + + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConstAgg(mModule->mBfIRBuilder->MapType(tupleType), irValues), tupleType); + return; + } + curTupleValue = mModule->CreateAlloca(tupleType); mResultIsTempComposite = true; - mResult = BfTypedValue(curTupleValue, tupleType, BfTypedValueKind_TempAddr); + mResult = BfTypedValue(curTupleValue, tupleType, BfTypedValueKind_TempAddr); } - for (int valueIdx = 0; valueIdx < (int)typedValues.size(); valueIdx++) + int valueIdx = -1; + for (int fieldIdx = 0; fieldIdx < (int)tupleType->mFieldInstances.size(); fieldIdx++) { - BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[valueIdx]; + BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx]; if (fieldInstance->mResolvedType->IsValuelessType()) continue; + ++valueIdx; auto typedVal = typedValues[valueIdx]; if (!typedVal) { @@ -20511,6 +20631,20 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (!handled) { + if ((leftValue.mType->IsUndefSizedArray()) || (rightValue.mType->IsUndefSizedArray())) + { + if ((leftValue.mType->IsSizedArray()) && (rightValue.mType->IsSizedArray() && + (leftValue.mType->GetUnderlyingType() == rightValue.mType->GetUnderlyingType()))) + { + if (BfBinOpEqualityCheck(binaryOp)) + { + auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean); + mResult = mModule->GetDefaultTypedValue(boolType, false, BfDefaultValueKind_Undef); + return; + } + } + } + mModule->Fail(StrFormat("Operator '%s' cannot be applied to operands of type '%s' and '%s'", BfGetOpName(binaryOp), mModule->TypeToString(leftValue.mType).c_str(), diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index 7c664494..cd9e6df6 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -175,9 +175,7 @@ USING_NS_BF; auto constRHS = GetConstantById(rhs.mId); \ if ((constLHS->mConstType == BfConstType_Undef) || (constRHS->mConstType == BfConstType_Undef)) \ { \ - if (((constLHS->mConstType == BfConstType_Undef) || (constLHS->mTypeCode < BfTypeCode_Length)) && \ - ((constRHS->mConstType == BfConstType_Undef) || (constRHS->mTypeCode < BfTypeCode_Length))) \ - return GetUndefConstValue(BfTypeCode_Boolean); \ + return GetUndefConstValue(MapType(mModule->GetPrimitiveType(BfTypeCode_Boolean))); \ } \ if ((constLHS->mTypeCode < BfTypeCode_Length) && (constRHS->mTypeCode < BfTypeCode_Length)) \ { \ @@ -654,6 +652,14 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f } return CreateConstAgg(constAgg->mType, copiedVals); } + else if (fromConst->mConstType == BfConstType_Undef) + { + auto constUndef = (BfConstantUndef*)fromConst; + BF_ASSERT(constUndef->mType.mKind != BfIRTypeData::TypeKind_Stream); + if (constUndef->mType.mKind == BfIRTypeData::TypeKind_Stream) + return GetUndefConstValue(BfIRValue()); + return GetUndefConstValue(constUndef->mType); + } else if ((IsInt(fromConst->mTypeCode)) || (fromConst->mTypeCode == BfTypeCode_Boolean) || (fromConst->mTypeCode == BfTypeCode_StringId)) { return CreateConst(fromConst->mTypeCode, fromConst->mUInt64); @@ -778,11 +784,11 @@ BfIRValue BfIRConstHolder::CreateTypeOf(BfType* type) return irValue; } -BfIRValue BfIRConstHolder::GetUndefConstValue(BfTypeCode typeCode) +BfIRValue BfIRConstHolder::GetUndefConstValue(BfIRType irType) { auto constUndef = mTempAlloc.Alloc(); constUndef->mConstType = BfConstType_Undef; - constUndef->mTypeCode = typeCode; + constUndef->mType = irType; BfIRValue undefVal(BfIRValueFlags_Const, mTempAlloc.GetChunkedId(constUndef)); #ifdef CHECK_CONSTHOLDER @@ -3461,12 +3467,11 @@ BfIRFunction BfIRBuilder::GetFakeFunction() } BfIRType BfIRBuilder::GetPrimitiveType(BfTypeCode typeCode) -{ - +{ FixTypeCode(typeCode); - BfIRType retType = WriteCmd(BfIRCmd_PrimitiveType, typeCode); - NEW_CMD_INSERTED_IRTYPE; - return retType; + BfIRType retType = WriteCmd(BfIRCmd_PrimitiveType, typeCode); + NEW_CMD_INSERTED_IRTYPE; + return retType; } BfIRType BfIRBuilder::CreateStructType(const StringImpl& name) @@ -3495,6 +3500,7 @@ BfIRType BfIRBuilder::MapType(BfType* type, BfIRPopulateType populateType) { PopulateType(type, populateType); } + BF_ASSERT(type->mTypeId > 0); BfIRType retType; retType.mKind = BfIRType::TypeKind_TypeId; retType.mId = type->mTypeId; diff --git a/IDEHelper/Compiler/BfIRBuilder.h b/IDEHelper/Compiler/BfIRBuilder.h index 2bdb3771..a3a2e15f 100644 --- a/IDEHelper/Compiler/BfIRBuilder.h +++ b/IDEHelper/Compiler/BfIRBuilder.h @@ -815,7 +815,7 @@ struct BfConstantSizedArrayType struct BfConstantUndef { BfConstType mConstType; - BfTypeCode mTypeCode; + BfIRType mType; }; struct BfConstantBitCast @@ -903,7 +903,7 @@ public: BfIRValue CreateConstArrayZero(BfIRType type, int count); BfIRValue CreateConstArrayZero(int count); BfIRValue CreateTypeOf(BfType* type); - BfIRValue GetUndefConstValue(BfTypeCode typeCode); + BfIRValue GetUndefConstValue(BfIRType type); }; enum BfIRPopulateType diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index b94c931c..1434c76b 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -83,8 +83,8 @@ BfLocalMethod::~BfLocalMethod() BF_ASSERT(mSource->mRefCount >= 0); } - delete mMethodDef; - delete mMethodInstanceGroup; + delete mMethodInstanceGroup; + delete mMethodDef; } void BfDeferredLocalAssignData::ExtendFrom(BfDeferredLocalAssignData* outerLocalAssignData, bool doChain) @@ -1134,7 +1134,7 @@ void BfModule::EnsureIRBuilder(bool dbgVerifyCodeGen) // code as we walk the AST //mBfIRBuilder->mDbgVerifyCodeGen = true; if ( - (mModuleName == "-") + (mModuleName == "System_StringView") //|| (mModuleName == "BeefTest2_ClearColorValue") //|| (mModuleName == "Tests_FuncRefs") ) @@ -1441,12 +1441,12 @@ BfTypedValue BfModule::GetDefaultTypedValue(BfType* type, bool allowRef, BfDefau if (defaultValueKind == BfDefaultValueKind_Undef) { - auto primType = type->ToPrimitiveType(); - if (primType != NULL) - { - return BfTypedValue(mBfIRBuilder->GetUndefConstValue(primType->mTypeDef->mTypeCode), type); - } - return BfTypedValue(mBfIRBuilder->CreateUndefValue(mBfIRBuilder->MapType(type)), type); +// auto primType = type->ToPrimitiveType(); +// if (primType != NULL) +// { +// return BfTypedValue(mBfIRBuilder->GetUndefConstValue( primType), type); +// } + return BfTypedValue(mBfIRBuilder->GetUndefConstValue(mBfIRBuilder->MapType(type)), type); } BfTypedValue typedValue; @@ -5390,7 +5390,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin } } - if ((!typeInstance->IsInterface()) && (typeInstance->mVirtualMethodTableSize > 0) && (needsVData)) + if ((!mIsConstModule) && (!typeInstance->IsInterface()) && (typeInstance->mVirtualMethodTableSize > 0) && (needsVData)) { int startTabIdx = (int)vData.size(); @@ -7925,7 +7925,7 @@ BfTypedValue BfModule::CreateValueFromExpression(BfExprEvaluator& exprEvaluator, BfTypedValue result; result.mKind = BfTypedValueKind_Value; result.mType = genericTypeConstraint; - result.mValue = mBfIRBuilder->GetUndefConstValue(primType->mTypeDef->mTypeCode); + result.mValue = mBfIRBuilder->GetUndefConstValue(mBfIRBuilder->MapType(primType)); typedVal = result; handled = true; } @@ -12064,6 +12064,11 @@ void BfModule::AddMethodReference(const BfMethodRef& methodRef, BfGetMethodInsta BfModuleMethodInstance BfModule::ReferenceExternalMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags) { + if (mIsConstModule) + { + NOP; + } + if ((flags & BfGetMethodInstanceFlag_ResultNotUsed) != 0) return BfModuleMethodInstance(methodInstance, BfIRValue()); @@ -12257,6 +12262,11 @@ BfModule* BfModule::GetOrCreateMethodModule(BfMethodInstance* methodInstance) BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfMethodDef* methodDef, const BfTypeVector& methodGenericArguments, BfGetMethodInstanceFlags flags, BfTypeInstance* foreignType) { + if (mIsConstModule) + { + NOP; + } + if (methodDef->mMethodType == BfMethodType_Init) return BfModuleMethodInstance(); @@ -12338,7 +12348,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mMethodInfoEx != NULL) && (mCurMethodInstance->mMethodInfoEx->mMinDependDepth >= 32)) flags = (BfGetMethodInstanceFlags)(flags | BfGetMethodInstanceFlag_DepthExceeded); - if ((!mIsReified) && (instModule->mIsReified)) + if ((!mIsConstModule) && (!mIsReified) && (instModule->mIsReified)) { BF_ASSERT(!mCompiler->mIsResolveOnly); // A resolve-only module is specializing a method from a type in a reified module, @@ -12351,7 +12361,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM } else { - if ((mIsReified) && (!instModule->mIsReified)) + if ((!mIsConstModule) && (mIsReified) && (!instModule->mIsReified)) { if (!typeInst->IsUnspecializedTypeVariation()) { @@ -13080,6 +13090,10 @@ void BfModule::SetupMethodIdHash(BfMethodInstance* methodInstance) } methodInstance->mIdHash = (int64)hashCtx.Finish64(); + if (methodInstance->mIdHash == 0x3400000029LL) + { + NOP; + } } BfIRValue BfModule::GetInterfaceSlotNum(BfTypeInstance* ifaceType) @@ -13134,6 +13148,18 @@ BfTypedValue BfModule::GetCompilerFieldValue(const StringImpl& str) { return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, mIsConstModule ? 1 : 0), GetPrimitiveType(BfTypeCode_Boolean)); } + if (str == "#IsBuilding") + { + return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, (!mCompiler->mIsResolveOnly) ? 1 : 0), GetPrimitiveType(BfTypeCode_Boolean)); + } + if (str == "#IsReified") + { + return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, mIsReified ? 1 : 0), GetPrimitiveType(BfTypeCode_Boolean)); + } + if (str == "#CompileRev") + { + return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Int32, mCompiler->mRevision), GetPrimitiveType(BfTypeCode_Int32)); + } if (str == "#ModuleName") { return BfTypedValue(GetStringObjectValue(mModuleName), ResolveTypeDef(mCompiler->mStringTypeDef)); @@ -14504,7 +14530,7 @@ void BfModule::CreateDelegateInvokeMethod() if (mCurMethodInstance->mReturnType->IsValueType()) mBfIRBuilder->PopulateType(mCurMethodInstance->mReturnType, BfIRPopulateType_Full); - if ((!mIsConstModule) && (mCurMethodInstance->GetStructRetIdx() != 0)) + if ((mIsConstModule) || (mCurMethodInstance->GetStructRetIdx() != 0)) memberFuncArgs.push_back(BfIRValue()); // Push 'target' int thisIdx = 0; @@ -17078,11 +17104,13 @@ void BfModule::ProcessMethod_ProcessDeferredLocals(int startIdx) BP_ZONE_F("ProcessMethod lambdaInstance %s", lambdaInstance->mMethodInstance->mMethodDef->mName.c_str()); lambdaInstance->mMethodInstance->mMethodInstanceGroup = &methodInstanceGroup; ProcessMethod(lambdaInstance->mMethodInstance); + lambdaInstance->mMethodInstance->mMethodInstanceGroup = NULL; if (lambdaInstance->mDtorMethodInstance != NULL) { lambdaInstance->mDtorMethodInstance->mMethodInstanceGroup = &methodInstanceGroup; ProcessMethod(lambdaInstance->mDtorMethodInstance); + lambdaInstance->mDtorMethodInstance->mMethodInstanceGroup = NULL; } } } @@ -17546,22 +17574,25 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) BF_ASSERT(methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_NotSet); - if ((methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_AlwaysInclude) && - (methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_Referenced)) + if (!mIsConstModule) { - methodInstance->mMethodInstanceGroup->mOnDemandKind = BfMethodOnDemandKind_Referenced; - - auto owningModule = methodInstance->GetOwner()->mModule; - - if (owningModule->mIsScratchModule) + if ((methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_AlwaysInclude) && + (methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_Referenced)) { - BF_ASSERT(owningModule->mOnDemandMethodCount == 0); - } - else - { - BF_ASSERT((owningModule->mOnDemandMethodCount > 0) || (!HasCompiledOutput()) || (owningModule->mExtensionCount > 0)); - if (owningModule->mOnDemandMethodCount > 0) - owningModule->mOnDemandMethodCount--; + methodInstance->mMethodInstanceGroup->mOnDemandKind = BfMethodOnDemandKind_Referenced; + + auto owningModule = methodInstance->GetOwner()->mModule; + + if (owningModule->mIsScratchModule) + { + BF_ASSERT(owningModule->mOnDemandMethodCount == 0); + } + else + { + BF_ASSERT((owningModule->mOnDemandMethodCount > 0) || (!HasCompiledOutput()) || (owningModule->mExtensionCount > 0)); + if (owningModule->mOnDemandMethodCount > 0) + owningModule->mOnDemandMethodCount--; + } } } diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 211a13b3..54d7fff7 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -69,7 +69,8 @@ enum BfEvalExprFlags BfEvalExprFlags_AllowNonConst = 0x10000, BfEvalExprFlags_StringInterpolateFormat = 0x20000, BfEvalExprFlags_NoLookupError = 0x40000, - BfEvalExprFlags_ConstExpr = 0x80000, + BfEvalExprFlags_ConstEval = 0x80000, + BfEvalExprFlags_InCascade = 0x100000, }; enum BfCastFlags @@ -904,13 +905,15 @@ public: ~BfLambdaInstance() { - delete mMethodInstance->mMethodDef; + auto methodDef = mMethodInstance->mMethodDef; delete mMethodInstance; + delete methodDef; if (mDtorMethodInstance != NULL) { - delete mDtorMethodInstance->mMethodDef; - delete mDtorMethodInstance; + auto methodDef = mDtorMethodInstance->mMethodDef; + delete mDtorMethodInstance; + delete methodDef; } } }; diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 08888804..493ed27f 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -10169,12 +10169,12 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp if (allowCast) { - if (ignoreWrites) + if ((ignoreWrites) && (!typedVal.mValue.IsConst())) return mBfIRBuilder->GetFakeVal(); return mBfIRBuilder->CreateBitCast(typedVal.mValue, mBfIRBuilder->MapType(toType)); } } - } + } // MethodRef -> Function if ((typedVal.mType->IsMethodRef()) && (toType->IsFunction())) @@ -10566,12 +10566,13 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp auto undefConst = (BfConstantUndef*)constant; - auto fakeVal = GetFakeTypedValue(GetPrimitiveType(undefConst->mTypeCode)); - // Why did we have this BfCastFlags_Explicit? It broke creating errors on things like "int16 val = TCount;" - //auto val = CastToValue(srcNode, fakeVal, toType, (BfCastFlags)(castFlags | BfCastFlags_Explicit)); + BF_ASSERT(undefConst->mType.mKind == BfIRTypeData::TypeKind_TypeId); + auto bfType = mContext->mTypes[undefConst->mType.mId]; + + auto fakeVal = GetFakeTypedValue(bfType); auto val = CastToValue(srcNode, fakeVal, toType, castFlags); if (val) - return val; + return mBfIRBuilder->GetUndefConstValue(mBfIRBuilder->MapType(toType)); } } } diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index fe12fe11..65545f51 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -5441,7 +5441,7 @@ BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool if (!onlyAllowIdentifier) { - BfExpression* expr = CreateExpressionAfter(attrib); + BfExpression* expr = CreateExpressionAfter(attrib, CreateExprFlags_EarlyExit); if (expr != NULL) { if (auto identifier = BfNodeDynCast(expr)) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 429f5f1d..6cddf002 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -535,6 +535,13 @@ 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; diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index b18ffbcf..c471d699 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -6438,10 +6438,15 @@ void BfModule::Visit(BfForEachStatement* forEachStmt) methodMatcher.CheckType(itrInterface, itr, false); methodMatcher.TryDevirtualizeCall(itr); exprEvaluator.mReceivingValue = &nextResult; - auto retVal = exprEvaluator.CreateCall(&methodMatcher, itr); + auto retVal = exprEvaluator.CreateCall(&methodMatcher, itr); if (exprEvaluator.mReceivingValue != NULL) { - AssertErrorState(); + if (mIsConstModule) + { + mBfIRBuilder->CreateStore(retVal.mValue, nextResult.mValue); + } + else + AssertErrorState(); } if ((retVal) && (!retVal.mType->IsVar())) { diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 1836bc81..d82235f3 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -733,6 +733,7 @@ public: bool mIsNoSplat; bool mIsNoReflect; bool mIsSkipCall; + bool mIsConstEval; bool mIsOperator; bool mIsExtern; bool mIsNoDiscard; @@ -761,6 +762,7 @@ public: mIsNoSplat = false; mIsNoReflect = false; mIsSkipCall = false; + mIsConstEval = false; mIsOperator = false; mIsExtern = false; mIsNoDiscard = false; diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index ab08326e..cda20a69 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -214,6 +214,13 @@ CeFunction::~CeFunction() ////////////////////////////////////////////////////////////////////////// +CeFunctionInfo::~CeFunctionInfo() +{ + delete mCeFunction; +} + +////////////////////////////////////////////////////////////////////////// + #define CE_GET(T) *((T*)(mPtr += sizeof(T)) - 1) void CeDumpContext::DumpOperandInfo(CeOperandInfoKind operandInfoKind) @@ -2151,6 +2158,10 @@ void CeBuilder::Build() break; } + else + { + mcAgg = GetOperand(castedInst->mAggVal); + } auto aggType = mcAgg.mType; int byteOffset = 0; @@ -2590,8 +2601,10 @@ CeMachine::CeMachine(BfCompiler* compiler) mCeModule = NULL; mRevision = 0; mExecuteId = 0; + mRevisionExecuteTime = 0; mCurTargetSrc = NULL; mCurModule = NULL; + mCurMethodInstance = NULL; mCurExpectingType = NULL; mHeap = NULL; mStringCharsOffset = -1; @@ -2613,7 +2626,7 @@ CeMachine::~CeMachine() BfError* CeMachine::Fail(const StringImpl& error) { - auto bfError = mCurModule->Fail("Unable to const-evaluate function", mCurTargetSrc); + auto bfError = mCurModule->Fail(StrFormat("Unable to const-evaluate %s", mCurModule->MethodToString(mCurMethodInstance).c_str()), mCurTargetSrc); if (bfError == NULL) return NULL; mCompiler->mPassInstance->MoreInfo(error); @@ -2622,7 +2635,7 @@ BfError* CeMachine::Fail(const StringImpl& error) BfError* CeMachine::Fail(const CeFrame& curFrame, const StringImpl& str) { - auto bfError = mCurModule->Fail("Unable to const-evaluate function", mCurTargetSrc); + auto bfError = mCurModule->Fail(StrFormat("Unable to const-evaluate %s", mCurModule->MethodToString(mCurMethodInstance).c_str()), mCurTargetSrc); if (bfError == NULL) return NULL; @@ -2696,7 +2709,11 @@ void CeMachine::Init() mCeModule->mIsSpecialModule = true; //mCeModule->mIsScratchModule = true; mCeModule->mIsConstModule = true; - mCeModule->mIsReified = true; + //mCeModule->mIsReified = true; + if (mCompiler->mIsResolveOnly) + mCeModule->mIsReified = true; + else + mCeModule->mIsReified = false; mCeModule->Init(); mCeModule->mBfIRBuilder = new BfIRBuilder(mCeModule); @@ -2731,6 +2748,28 @@ bool CeMachine::CeFree(addr_ce addr) #endif } +addr_ce CeMachine::CeAllocArray(BfArrayType* arrayType, int count, addr_ce& elemsAddr) +{ + mCeModule->PopulateType(arrayType); + + BfType* elemType = arrayType->GetUnderlyingType(); + auto countOffset = arrayType->mBaseType->mFieldInstances[0].mDataOffset; + auto elemOffset = arrayType->mFieldInstances[0].mDataOffset; + + int allocSize = elemOffset + elemType->GetStride() * count; + + uint8* mem = CeMalloc(allocSize); + + memset(mem, 0, allocSize); + + *(int32*)(mem) = arrayType->mTypeId; + *(int32*)(mem + countOffset) = count; + + elemsAddr = (addr_ce)(mem + elemOffset - mMemory.mVals); + + return (addr_ce)(mem - mMemory.mVals); +} + addr_ce CeMachine::GetConstantData(BeConstant* constant) { auto writeConstant = constant; @@ -2889,6 +2928,7 @@ BeModule* CeMachine::GetBeModule() void CeMachine::CompileStarted() { + mRevisionExecuteTime = 0; mRevision++; if (mCeModule != NULL) { @@ -2912,37 +2952,48 @@ void CeMachine::DerefMethodInfo(CeFunctionInfo* ceFunctionInfo) void CeMachine::RemoveMethod(BfMethodInstance* methodInstance) { + BfLogSys(methodInstance->GetOwner()->mModule->mSystem, "CeMachine::RemoveMethod %p\n", methodInstance); + auto itr = mFunctions.Find(methodInstance); auto ceFunctionInfo = itr->mValue; BF_ASSERT(itr != mFunctions.end()); if (itr != mFunctions.end()) - { - auto ceFunction = ceFunctionInfo->mCeFunction; - for (auto& callEntry : ceFunction->mCallTable) + { + if (ceFunctionInfo->mMethodInstance == methodInstance) { - if (callEntry.mFunctionInfo != NULL) - DerefMethodInfo(callEntry.mFunctionInfo); - } - delete ceFunction; - ceFunctionInfo->mCeFunction = NULL; - ceFunctionInfo->mMethodInstance = NULL; + auto ceFunction = ceFunctionInfo->mCeFunction; + for (auto& callEntry : ceFunction->mCallTable) + { + if (callEntry.mFunctionInfo != NULL) + DerefMethodInfo(callEntry.mFunctionInfo); + } + delete ceFunction; + ceFunctionInfo->mCeFunction = NULL; + ceFunctionInfo->mMethodInstance = NULL; - if (ceFunctionInfo->mRefCount > 1) - { - // Generate a methodref - ceFunctionInfo->mMethodRef = methodInstance; - } + if (methodInstance->mMethodDef->mIsLocalMethod) + { + // We can't rebuild these anyway + } + else if (ceFunctionInfo->mRefCount > 1) + { + // Generate a methodref + ceFunctionInfo->mMethodRef = methodInstance; + } - DerefMethodInfo(ceFunctionInfo); + DerefMethodInfo(ceFunctionInfo); + } mFunctions.Remove(itr); } + + CheckFunctions(); } //#define CE_GETC(T) *((T*)(addr += sizeof(T)) - 1) #define CE_GETC(T) *(T*)(mMemory.mVals + addr) -bool CeMachine::WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type) +bool CeMachine::WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type, bool isParams) { switch (constant->mTypeCode) { @@ -2987,8 +3038,56 @@ bool CeMachine::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta { return false; } - else + else if (type->IsArray()) { + auto elemType = type->GetUnderlyingType(); + + addr_ce elemsAddr = 0; + addr_ce arrayAddr = CeAllocArray((BfArrayType*)type, aggConstant->mValues.size(), elemsAddr); + + for (int i = 0; i < (int)aggConstant->mValues.size(); i++) + { + auto fieldConstant = module->mBfIRBuilder->GetConstant(aggConstant->mValues[i]); + if (fieldConstant == NULL) + return false; + WriteConstant(module, elemsAddr + i * elemType->GetStride(), fieldConstant, elemType); + } + + if (mCeModule->mSystem->mPtrSize == 4) + CE_GETC(int32) = arrayAddr; + else + CE_GETC(int64) = arrayAddr; + + return true; + } + else if ((type->IsInstanceOf(module->mCompiler->mSpanTypeDef)) && (isParams)) + { + auto elemType = type->GetUnderlyingType(); + addr_ce elemsAddr = CeMalloc(elemType->GetStride() * aggConstant->mValues.size()) - mMemory.mVals; + + for (int i = 0; i < (int)aggConstant->mValues.size(); i++) + { + auto fieldConstant = module->mBfIRBuilder->GetConstant(aggConstant->mValues[i]); + if (fieldConstant == NULL) + return false; + WriteConstant(module, elemsAddr + i * elemType->GetStride(), fieldConstant, elemType); + } + + if (mCeModule->mSystem->mPtrSize == 4) + { + CE_GETC(int32) = elemsAddr; + addr += 4; + CE_GETC(int32) = (int32)aggConstant->mValues.size(); + } + else + { + CE_GETC(int32) = elemsAddr; + addr += 8; + CE_GETC(int64) = (int32)aggConstant->mValues.size(); + } + } + else + { BF_ASSERT(type->IsStruct()); module->PopulateType(type); @@ -3087,7 +3186,40 @@ CeErrorKind CeMachine::WriteConstant(CeConstStructData& data, BeConstant* constV } if (globalVar->mInitializer == NULL) - return CeErrorKind_GlobalVariable; + { + auto ptr = data.mData.GrowUninitialized(mCeModule->mSystem->mPtrSize); + int64 addr64 = (addr_ce)0; + memcpy(ptr, &addr64, mCeModule->mSystem->mPtrSize); + return CeErrorKind_None; + + //TODO: Add this global variable in there and fixup + +// CeStaticFieldInfo* staticFieldInfoPtr = NULL; +// if (mCeMachine->mStaticFieldMap.TryGetValue(globalVar->mName, &staticFieldInfoPtr)) +// { +// CeStaticFieldInfo* staticFieldInfo = staticFieldInfoPtr; +// +// int* staticFieldTableIdxPtr = NULL; +// if (mStaticFieldMap.TryAdd(globalVar, NULL, &staticFieldTableIdxPtr)) +// { +// CeStaticFieldEntry staticFieldEntry; +// staticFieldEntry.mTypeId = staticFieldInfo->mFieldInstance->mOwner->mTypeId; +// staticFieldEntry.mName = globalVar->mName; +// staticFieldEntry.mSize = globalVar->mType->mSize; +// *staticFieldTableIdxPtr = (int)mCeFunction->mStaticFieldTable.size(); +// mCeFunction->mStaticFieldTable.Add(staticFieldEntry); +// } +// +// auto result = FrameAlloc(mCeMachine->GetBeContext()->GetPointerTo(globalVar->mType)); +// +// Emit(CeOp_GetStaticField); +// EmitFrameOffset(result); +// Emit((int32)*staticFieldTableIdxPtr); +// +// return result; +// } +// return CeErrorKind_GlobalVariable; + } BF_ASSERT(!data.mQueueFixups); @@ -3375,7 +3507,7 @@ BfIRValue CeMachine::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType if (typeInst->IsInstanceOf(mCeModule->mCompiler->mSpanTypeDef)) { - if ((outType != NULL) && (mCurExpectingType->IsSizedArray())) + if ((outType != NULL) && ((mCurExpectingType == NULL) || (mCurExpectingType->IsSizedArray()))) { module->PopulateType(typeInst); @@ -3402,6 +3534,9 @@ BfIRValue CeMachine::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType *outType = module->CreateSizedArrayType(elemType, lenVal); return instResult; } + + Fail(StrFormat("Span return type '%s' must be received by a sized array", module->TypeToString(typeInst).c_str())); + return BfIRValue(); } if (typeInst->IsObjectOrInterface()) @@ -3590,7 +3725,7 @@ BfIRValue CeMachine::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr) { - mExecuteId++; + mExecuteId++; CeFunction* ceFunction = startFunction; uint8* memStart = &mMemory[0]; @@ -3598,7 +3733,9 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* uint8* instPtr = (ceFunction->mCode.IsEmpty()) ? NULL : &ceFunction->mCode[0]; uint8* stackPtr = startStackPtr; uint8* framePtr = startFramePtr; - + + volatile bool* cancelPtr = &mCompiler->mCanceling; + auto _GetCurFrame = [&]() { CeFrame ceFrame; @@ -3659,32 +3796,6 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* handled = true; return true; } - else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite) - { - int32 ptrVal = *(int32*)((uint8*)stackPtr + 0); - auto size = *(int32*)(stackPtr + mCeModule->mSystem->mPtrSize); - CE_CHECKADDR(ptrVal, size); - char* strPtr = (char*)(ptrVal + memStart); - String str; - str.Insert(0, strPtr, size); - OutputDebugStr(str); - handled = true; - return true; - } - else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite_Int) - { - int32 intVal = *(int32*)((uint8*)stackPtr + 0); - OutputDebugStrF("Debug Val: %d\n", intVal); - handled = true; - return true; - } - else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectType) - { - int32 typeId = *(int32*)((uint8*)stackPtr + mCeModule->mSystem->mPtrSize); - auto reflectType = GetReflectType(typeId); - _FixVariables(); - *(addr_ce*)(stackPtr + 0) = reflectType; - } else if (checkFunction->mFunctionKind == CeFunctionKind_FatalError) { int32 strInstAddr = *(int32*)((uint8*)stackPtr + 0); @@ -3725,6 +3836,67 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* return false; } + else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite) + { + int32 ptrVal = *(int32*)((uint8*)stackPtr + 0); + auto size = *(int32*)(stackPtr + mCeModule->mSystem->mPtrSize); + CE_CHECKADDR(ptrVal, size); + char* strPtr = (char*)(ptrVal + memStart); + String str; + str.Insert(0, strPtr, size); + OutputDebugStr(str); + handled = true; + return true; + } + else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite_Int) + { + int32 intVal = *(int32*)((uint8*)stackPtr + 0); + OutputDebugStrF("Debug Val: %d\n", intVal); + handled = true; + return true; + } + else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectType) + { + addr_ce objAddr = *(addr_ce*)((uint8*)stackPtr + mCeModule->mSystem->mPtrSize); + CE_CHECKADDR(addr_ce, 4); + int32 typeId = *(int32*)(objAddr + memStart); + + auto reflectType = GetReflectType(typeId); + _FixVariables(); + *(addr_ce*)(stackPtr + 0) = reflectType; + handled = true; + return true; + } + else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectTypeById) + { + int32 typeId = *(int32*)((uint8*)stackPtr + mCeModule->mSystem->mPtrSize); + auto reflectType = GetReflectType(typeId); + _FixVariables(); + *(addr_ce*)(stackPtr + 0) = reflectType; + handled = true; + return true; + } + else if (checkFunction->mFunctionKind == CeFunctionKind_Sleep) + { + int32 sleepMS = *(int32*)((uint8*)stackPtr); + while (sleepMS > 0) + { + if (*cancelPtr) + break; + + if (sleepMS > 200) + { + Sleep(200); + sleepMS -= 200; + continue; + } + Sleep(sleepMS); + break; + } + + handled = true; + return true; + } else if (checkFunction->mFunctionKind == CeFunctionKind_Char32_ToLower) { int32& result = *(int32*)((uint8*)stackPtr + 0); @@ -3847,9 +4019,7 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* return false; if (handled) return true; - } - - volatile bool* cancelPtr = &mCompiler->mCanceling; + } int callCount = 0; int instIdx = 0; @@ -3858,7 +4028,7 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* { if (*cancelPtr) { - _Fail("Cancelled"); + _Fail("Compilation cancelled"); return false; } @@ -4989,6 +5159,8 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder) { + AutoTimer autoTimer(mRevisionExecuteTime); + if (mHeap == NULL) mHeap = new ContiguousHeap(); @@ -5007,6 +5179,13 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder ceFunction->mFunctionKind = CeFunctionKind_GetReflectType; } } + else if (owner->IsInstanceOf(mCeModule->mCompiler->mTypeTypeDef)) + { + if (methodDef->mName == "ConstEval_GetTypeById") + { + ceFunction->mFunctionKind = CeFunctionKind_GetReflectTypeById; + } + } else if (owner->IsInstanceOf(mCeModule->mCompiler->mDiagnosticsDebugTypeDef)) { if (methodDef->mName == "Write") @@ -5017,6 +5196,11 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder ceFunction->mFunctionKind = CeFunctionKind_DebugWrite; } } + else if (owner->IsInstanceOf(mCeModule->mCompiler->mThreadTypeDef)) + { + if (methodDef->mName == "SleepInternal") + ceFunction->mFunctionKind = CeFunctionKind_Sleep; + } else if (owner->IsInstanceOf(mCeModule->mCompiler->mInternalTypeDef)) { if (methodDef->mName == "ThrowIndexOutOfRange") @@ -5063,7 +5247,7 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder ceBuilder.mCeFunction = ceFunction; ceBuilder.Build(); - if (!ceFunction->mCode.IsEmpty()) + /*if (!ceFunction->mCode.IsEmpty()) { CeDumpContext dumpCtx; dumpCtx.mCeFunction = ceFunction; @@ -5073,6 +5257,14 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder dumpCtx.Dump(); OutputDebugStrF("Code for %s:\n%s\n", ceBuilder.mBeFunction->mName.c_str(), dumpCtx.mStr.c_str()); + }*/ +} + +void CeMachine::CheckFunctions() +{ + for (auto kv : mFunctions) + { + BF_ASSERT((((intptr)(void*)kv.mKey->mMethodDef) & 0xFF) != 0xDD); } } @@ -5084,6 +5276,8 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f return NULL; } + CheckFunctions(); + CeFunctionInfo** functionInfoPtr = NULL; CeFunctionInfo* ceFunctionInfo = NULL; CeFunction* ceFunction = NULL; @@ -5093,6 +5287,11 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f BF_ASSERT(ceFunctionInfo->mCeFunction != NULL); return ceFunctionInfo->mCeFunction; } + + BF_ASSERT(!methodInstance->mInCEMachine); + methodInstance->mInCEMachine = true; + + BfLogSys(mCeModule->mSystem, "CeMachine::GetFunction %p\n", methodInstance); if (!func) { @@ -5130,8 +5329,7 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f added = true; auto module = methodInstance->GetOwner()->mModule; - BF_ASSERT(!methodInstance->mInCEMachine); - methodInstance->mInCEMachine = true; + BF_ASSERT(ceFunctionInfo->mCeFunction == NULL); ceFunction = new CeFunction(); ceFunction->mCeFunctionInfo = ceFunctionInfo; @@ -5140,6 +5338,8 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f ceFunctionInfo->mMethodInstance = methodInstance; ceFunctionInfo->mCeFunction = ceFunction; } + + return ceFunction; } @@ -5188,14 +5388,24 @@ void CeMachine::ClearAppendAllocInfo() } BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray& args, CeEvalFlags flags, BfType* expectingType) -{ +{ + AutoTimer autoTimer(mRevisionExecuteTime); + // DISABLED - return BfTypedValue(); + //return BfTypedValue(); + + SetAndRestoreValue prevTargetSrc(mCurTargetSrc, targetSrc); + SetAndRestoreValue prevModule(mCurModule, module); + SetAndRestoreValue prevMethodInstance(mCurMethodInstance, methodInstance); + SetAndRestoreValue prevExpectingType(mCurExpectingType, expectingType); if (mAppendAllocInfo != NULL) { if ((mAppendAllocInfo->mAppendSizeValue) && (!mAppendAllocInfo->mAppendSizeValue.IsConst())) + { + Fail("Non-constant append alloc"); return BfTypedValue(); + } } int thisArgIdx = -1; @@ -5206,22 +5416,39 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns thisArgIdx = 0; if ((methodInstance->GetParamCount() >= 1) && (methodInstance->GetParamKind(0) == BfParamKind_AppendIdx)) appendAllocIdx = 1; - } + } - for (int argIdx = 0; argIdx < (int)args.size(); argIdx++) + int paramCompositeSize = 0; + int paramIdx = methodInstance->GetParamCount(); + for (int argIdx = (int)args.size() - 1; argIdx >= 0; argIdx--) { + BfType* paramType = NULL; + while (true) + { + paramIdx--; + paramType = methodInstance->GetParamType(paramIdx); + if (paramType->IsTypedPrimitive()) + paramType = paramType->GetUnderlyingType(); + if (!paramType->IsValuelessType()) + break; + } + if (paramType->IsComposite()) + { + auto paramTypeInst = paramType->ToTypeInstance(); + paramCompositeSize += paramTypeInst->mInstSize; + } + auto arg = args[argIdx]; if (!arg.IsConst()) { if ((argIdx != thisArgIdx) && (argIdx != appendAllocIdx)) + { + Fail(StrFormat("Non-constant argument for param '%s'", methodInstance->GetParamName(paramIdx).c_str())); return BfTypedValue(); + } } } - - SetAndRestoreValue prevTargetSrc(mCurTargetSrc, targetSrc); - SetAndRestoreValue prevModule(mCurModule, module); - SetAndRestoreValue prevExpectingType(mCurExpectingType, expectingType); - + BF_ASSERT(mCallStack.IsEmpty()); auto methodDef = methodInstance->mMethodDef; @@ -5285,28 +5512,9 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns memStart += memOffset; stackPtr += memOffset; }; - + addr_ce compositeStartAddr = stackPtr - memStart; - int paramIdx = methodInstance->GetParamCount(); - for (int argIdx = (int)args.size() - 1; argIdx >= 0; argIdx--) - { - BfType* paramType = NULL; - while (true) - { - paramIdx--; - paramType = methodInstance->GetParamType(paramIdx); - if (paramType->IsTypedPrimitive()) - paramType = paramType->GetUnderlyingType(); - if (!paramType->IsValuelessType()) - break; - } - if (paramType->IsComposite()) - { - auto paramTypeInst = paramType->ToTypeInstance(); - stackPtr -= paramTypeInst->mInstSize; - } - } - + stackPtr -= paramCompositeSize; addr_ce useCompositeAddr = compositeStartAddr; paramIdx = methodInstance->GetParamCount(); for (int argIdx = (int)args.size() - 1; argIdx >= 0; argIdx--) @@ -5322,6 +5530,7 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns break; } + bool isParams = methodInstance->GetParamKind(paramIdx) == BfParamKind_Params; auto arg = args[argIdx]; if (!arg.IsConst()) { @@ -5351,8 +5560,11 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns { auto paramTypeInst = paramType->ToTypeInstance(); useCompositeAddr -= paramTypeInst->mInstSize; - if (!WriteConstant(module, useCompositeAddr, constant, paramType)) + if (!WriteConstant(module, useCompositeAddr, constant, paramType, isParams)) + { + Fail(StrFormat("Failed to process argument for param '%s'", methodInstance->GetParamName(paramIdx).c_str())); return BfTypedValue(); + } _FixVariables(); stackPtr -= mCeModule->mSystem->mPtrSize; @@ -5362,8 +5574,11 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns else { stackPtr -= paramType->mSize; - if (!WriteConstant(module, stackPtr - memStart, constant, paramType)) + if (!WriteConstant(module, stackPtr - memStart, constant, paramType, isParams)) + { + Fail(StrFormat("Failed to process argument for param '%s'", methodInstance->GetParamName(paramIdx).c_str())); return BfTypedValue(); + } _FixVariables(); } } @@ -5405,6 +5620,10 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns BfIRValue constVal = CreateConstant(module, retPtr, returnType, &usedReturnType); if (constVal) returnValue = BfTypedValue(constVal, usedReturnType); + else + { + Fail("Failed to encode return argument"); + } } else { diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index d4f9c231..bf25bc6d 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -202,6 +202,8 @@ public: mCeFunction = NULL; mRefCount = 0; } + + ~CeFunctionInfo(); }; class CeCallEntry @@ -247,6 +249,8 @@ enum CeFunctionKind CeFunctionKind_DebugWrite, CeFunctionKind_DebugWrite_Int, CeFunctionKind_GetReflectType, + CeFunctionKind_GetReflectTypeById, + CeFunctionKind_Sleep, CeFunctionKind_Char32_ToLower, CeFunctionKind_Char32_ToUpper, CeFunctionKind_Char32_IsLower, @@ -595,7 +599,8 @@ public: BfCompiler* mCompiler; BfModule* mCeModule; int mRevision; - int mExecuteId; + int mRevisionExecuteTime; + int mExecuteId; // These are only valid for the current execution ContiguousHeap* mHeap; @@ -610,6 +615,7 @@ public: CeAppendAllocInfo* mAppendAllocInfo; BfAstNode* mCurTargetSrc; + BfMethodInstance* mCurMethodInstance; BfModule* mCurModule; BfType* mCurExpectingType; @@ -623,6 +629,7 @@ public: void Init(); uint8* CeMalloc(int size); bool CeFree(addr_ce addr); + addr_ce CeAllocArray(BfArrayType* arrayType, int count, addr_ce& elemsAddr); addr_ce GetReflectType(int typeId); addr_ce GetString(int stringId); addr_ce GetConstantData(BeConstant* constant); @@ -633,13 +640,15 @@ public: BeModule* GetBeModule(); void DerefMethodInfo(CeFunctionInfo* ceFunctionInfo); void RemoveMethod(BfMethodInstance* methodInstance); - bool WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type); + bool WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type, bool isParams = false); CeErrorKind WriteConstant(CeConstStructData& data, BeConstant* constVal); BfIRValue CreateConstant(BfModule* module, uint8* ptr, BfType* type, BfType** outType = NULL); void CreateFunction(BfMethodInstance* methodInstance, CeFunction* ceFunction); bool Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr); void PrepareFunction(CeFunction* methodInstance, CeBuilder* parentBuilder); + + void CheckFunctions(); CeFunction* GetFunction(BfMethodInstance* methodInstance, BfIRValue func, bool& added); CeFunction* GetPreparedFunction(BfMethodInstance* methodInstance); diff --git a/IDEHelper/Tests/src/ConstEval.bf b/IDEHelper/Tests/src/ConstEval.bf new file mode 100644 index 00000000..aee866e3 --- /dev/null +++ b/IDEHelper/Tests/src/ConstEval.bf @@ -0,0 +1,159 @@ +using System; +using System.Collections; +using System.Diagnostics; + +namespace Tests +{ + class ConstEval + { + struct StructA + { + public int32 mA; + public int32 mB; + + public static int32 sVal = 1000; + + public this(int32 a, int32 b) + { + mA = a + sVal; + mB = b; + } + } + + const String cStrA = "Abc"; + const String cStrB = GetStringA(cStrA, 12, 23); + + [ConstEval] + static String GetStringA(String str, int a, int b) + { + // Const-eval functions can return scope-allocated data + return scope $"{str}:{a}:{b}"; + } + + static int32 Factorial(int32 n) + { + return n <= 1 ? 1 : (n * Factorial(n - 1)); + } + + static int32 Fibonacci(int32 n) + { + return n <= 1 ? n : Fibonacci(n - 1) + Fibonacci(n - 2); + } + + public static String GetTypeDesc() + { + String str = scope .(); + + T val = default; + val.GetType().GetFullName(str); + str.Append(" "); + + for (var fieldInfo in typeof(T).GetFields()) + { + if (!fieldInfo.IsInstanceField) + continue; + if (@fieldInfo.Index > 0) + str.Append(", "); + fieldInfo.FieldType.GetFullName(str); + str.Append(" "); + str.Append(fieldInfo.Name); + } + + return str; + } + + public static Span GetSorted(String numList) + { + List list = scope .(); + for (var sv in numList.Split(',')) + { + sv.Trim(); + if (int32.Parse(sv) case .Ok(let val)) + list.Add(val); + } + list.Sort(); + return list; + } + + public static int32 MethodA() + { + mixin Add10(var a) + { + a += 10 + } + + int32 a = 1; + + void Inc() + { + a++; + } + + for (int i < 2) + { + defer { a *= 2; } + Inc(); + Add10!(a); + } + + return a; + } + + // This method can only be const evaluated + [ConstEval] + public static int32 ConstSum(params int32[] vals) + { + int32 sum = 0; + for (let val in vals) + sum += val; + return sum; + } + + public static int32 MethodB() + { + // Returns different results depending on whether we are const-evaluating + return Compiler.IsConstEval ? 1 : 0; + } + + public static int32 MethodC(StructA sa = .(1, 2), (int32, int32) tup = (20, 30), int32[2] arr = .(300, 400)) + { + return sa.mA + sa.mB + tup.0 + tup.1 + arr[0] + arr[1]; + } + + [Test] + public static void TestBasics() + { + const int fac = Factorial(8); + Test.Assert(fac == 40320); + const int fib = Fibonacci(27); + Test.Assert(fib == 196418); + + // Generated string has reference equality to equivalent literal + Test.Assert(cStrB === "Abc:12:23"); + + const String strC = GetTypeDesc(); + Test.Assert(strC === "Tests.ConstEval.StructA int32 mA, int32 mB"); + + // Const Span results can be used to initialize statically-sized arrays + const int32[?] iArr = GetSorted("8, 1, 3, 7"); + Compiler.Assert(iArr == .(1, 3, 7, 8)); + Test.Assert(iArr == .(1, 3, 7, 8)); + + let val0 = [ConstEval]MethodA(); + Compiler.Assert(val0 == 70); + let val1 = MethodA(); + // 'val1' is a read-only variable, but not const, so the following line would fail + //Compiler.Assert(val1 == 24); + Test.Assert(val1 == 70); + + // This method is marked as ConstEval so it always evaluates as const + let val2 = ConstSum(3, 20, 100); + Compiler.Assert(val2 == 123); + + Test.Assert(MethodB() == 0); + Test.Assert([ConstEval]MethodB() == 1); + + Test.Assert(MethodC() == 1753); + } + } +}