From d9725dda7c0e2f97b0c75c4395d6d1c892bcb4aa Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Fri, 11 Feb 2022 10:38:57 -0500 Subject: [PATCH] Static local methods and variables, fixed erroneous 'this' capture --- IDEHelper/Backend/BeCOFFObject.cpp | 11 +++++++++ IDEHelper/Compiler/BfExprEvaluator.cpp | 16 +++++++++--- IDEHelper/Compiler/BfModule.cpp | 23 +++++++++++++++-- IDEHelper/Compiler/BfModule.h | 7 ++++-- IDEHelper/Compiler/BfReducer.cpp | 19 +++++++++++--- IDEHelper/Compiler/BfStmtEvaluator.cpp | 34 +++++++++++++++++++++++--- 6 files changed, 97 insertions(+), 13 deletions(-) diff --git a/IDEHelper/Backend/BeCOFFObject.cpp b/IDEHelper/Backend/BeCOFFObject.cpp index 71c1d270..8a86abcf 100644 --- a/IDEHelper/Backend/BeCOFFObject.cpp +++ b/IDEHelper/Backend/BeCOFFObject.cpp @@ -2062,6 +2062,17 @@ void BeCOFFObject::Generate(BeModule* module) sect.mRelocs.push_back(reloc); sect.mData.Write((int64)0); } + else if (auto constVal = BeValueDynCast(globalVar->mInitializer)) + { + MarkSectionUsed(mDataSect); + sym->mSectionNum = mDataSect.mSectionIdx + 1; + mDataSect.mData.Align(globalVar->mAlign); + mDataSect.mAlign = BF_MAX(mDataSect.mAlign, globalVar->mAlign); + + AlignConst(mDataSect, constVal); + sym->mValue = mDataSect.mData.GetSize(); + WriteConst(mDataSect, constVal); + } else { MarkSectionUsed(mBSSSect); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index f9b8abc2..8a0caf7a 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -4161,7 +4161,7 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI } } - BfTypedValue thisValue = mModule->GetThis(); + BfTypedValue thisValue = mModule->GetThis(false); bool forcedIFaceLookup = false; if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsForeignMethodDef)) @@ -4173,7 +4173,10 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI if (thisValue) { if (findName == "this") + { + mModule->MarkUsingThis(); return thisValue; + } if (findName == "base") { auto baseValue = thisValue; @@ -4183,7 +4186,8 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI if (mModule->GetActiveTypeDef()->mTypeCode != BfTypeCode_Extension) { MakeBaseConcrete(baseValue); - } + } + mModule->MarkUsingThis(); return baseValue; } @@ -4214,7 +4218,7 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI { mResultLocalVar = NULL; mResultLocalVarRefNode = NULL; - } + } } if (mPropDef != NULL) @@ -4654,6 +4658,9 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar return BfTypedValue(); } + if ((!field->mIsStatic) && ((flags & BfLookupFieldFlag_IsImplicitThis) != 0)) + mModule->MarkUsingThis(); + mResultFieldInstance = fieldInstance; // Are we accessing a 'var' field that has not yet been resolved? @@ -5043,6 +5050,9 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar mModule->SetElementType(targetSrc, BfSourceElementType_Method); + if ((!prop->mIsStatic) && ((flags & BfLookupFieldFlag_IsImplicitThis) != 0)) + mModule->MarkUsingThis(); + mPropSrc = targetSrc; mPropDef = prop; mPropCheckedKind = checkedKind; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 11fc2a70..74562973 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -14371,7 +14371,23 @@ int BfModule::GetFieldDataIdx(BfTypeInstance* typeInst, int fieldIdx, const char return fieldInstance.mDataIdx; } -BfTypedValue BfModule::GetThis() +void BfModule::MarkUsingThis() +{ + auto useMethodState = mCurMethodState; + while ((useMethodState != NULL) && (useMethodState->mClosureState != NULL) && (useMethodState->mClosureState->mCapturing)) + { + useMethodState = useMethodState->mPrevMethodState; + } + + if ((useMethodState != NULL) && (!useMethodState->mLocals.IsEmpty())) + { + auto localVar = useMethodState->mLocals[0]; + if (localVar->mIsThis) + localVar->mReadFromId = useMethodState->GetRootMethodState()->mCurAccessId++; + } +} + +BfTypedValue BfModule::GetThis(bool markUsing) { auto useMethodState = mCurMethodState; while ((useMethodState != NULL) && (useMethodState->mClosureState != NULL) && (useMethodState->mClosureState->mCapturing)) @@ -14465,7 +14481,8 @@ BfTypedValue BfModule::GetThis() thisValue = thisLocal->mAddr; else thisValue = mBfIRBuilder->CreateLoad(thisLocal->mAddr); - useMethodState->mLocals[0]->mReadFromId = useMethodState->GetRootMethodState()->mCurAccessId++; + if (markUsing) + useMethodState->mLocals[0]->mReadFromId = useMethodState->GetRootMethodState()->mCurAccessId++; if (useMethodState->mClosureState != NULL) { @@ -21462,6 +21479,8 @@ BfModuleMethodInstance BfModule::GetLocalMethodInstance(BfLocalMethod* localMeth wantsVisitBody = false; if (methodInstance->IsOrInUnspecializedVariation()) wantsVisitBody = false; + if ((methodDeclaration != NULL) && (methodDeclaration->mStaticSpecifier != NULL)) + wantsVisitBody = false; if (wantsVisitBody) { diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index ee5aa5a2..cf12b800 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -175,12 +175,13 @@ public: BfLocalVarAssignKind mAssignedKind; bool mHadExitBeforeAssign; bool mIsReadOnly; + bool mIsStatic; bool mIsSplat; bool mIsLowered; bool mAllowAddr; bool mIsShadow; bool mUsedImplicitly; // Passed implicitly to a local method, capture by ref if we can - bool mNotCaptured; + bool mNotCaptured; BfLocalVariable* mShadowedLocal; public: @@ -204,6 +205,7 @@ public: mWrittenToId = -1; mReadFromId = -1; mIsReadOnly = false; + mIsStatic = false; mIsSplat = false; mIsLowered = false; mAllowAddr = false; @@ -1678,7 +1680,8 @@ public: BfTypedValue GetCompilerFieldValue(const StringImpl& str); BfTypedValue ReferenceStaticField(BfFieldInstance* fieldInstance); int GetFieldDataIdx(BfTypeInstance* typeInst, int fieldIdx, const char* fieldName = NULL); - BfTypedValue GetThis(); + BfTypedValue GetThis(bool markUsing = true); + void MarkUsingThis(); BfLocalVariable* GetThisVariable(); bool IsInGeneric(); bool InDefinitionSection(); diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 1a92418d..5a312208 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -4068,9 +4068,12 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS continuingVariable = BfNodeDynCast(exprStmt->mExpression); } } - else if ((token == BfToken_Const) || (token == BfToken_ReadOnly)) + else if ((token == BfToken_Const) || (token == BfToken_ReadOnly) || (token == BfToken_Static)) { - auto stmt = CreateStatementAfter(tokenNode, (CreateStmtFlags)(CreateStmtFlags_FindTrailingSemicolon | CreateStmtFlags_ForceVariableDecl)); + auto flags = (CreateStmtFlags)(CreateStmtFlags_FindTrailingSemicolon | CreateStmtFlags_ForceVariableDecl); + if (token == BfToken_Static) + flags = (CreateStmtFlags)(flags | CreateStmtFlags_AllowLocalFunction); + auto stmt = CreateStatementAfter(tokenNode, flags); if (auto exprStmt = BfNodeDynCast(stmt)) { if (auto variableDecl = BfNodeDynCast(exprStmt->mExpression)) @@ -4080,10 +4083,20 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS Fail(StrFormat("'%s' already specified", BfTokenToString(variableDecl->mModSpecifier->GetToken())), variableDecl->mModSpecifier); } MEMBER_SET(variableDecl, mModSpecifier, tokenNode); - exprStmt->SetSrcStart(variableDecl->mSrcStart); + exprStmt->SetSrcStart(tokenNode->mSrcStart); return stmt; } } + if (auto localMethod = BfNodeDynCast(stmt)) + { + if (localMethod->mMethodDeclaration->mStaticSpecifier != NULL) + { + Fail(StrFormat("'%s' already specified", BfTokenToString(localMethod->mMethodDeclaration->mStaticSpecifier->GetToken())), localMethod->mMethodDeclaration->mStaticSpecifier); + } + MEMBER_SET(localMethod->mMethodDeclaration, mStaticSpecifier, tokenNode); + localMethod->SetSrcStart(tokenNode->mSrcStart); + return localMethod; + } Fail(StrFormat("Unexpected '%s' specifier", BfTokenToString(tokenNode->GetToken())), tokenNode); return stmt; diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index 4b5fd9b9..b5bd1e69 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -1335,6 +1335,7 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD bool isConst = (varDecl->mModSpecifier != NULL) && (varDecl->mModSpecifier->GetToken() == BfToken_Const); bool isReadOnly = (varDecl->mModSpecifier != NULL) && (varDecl->mModSpecifier->GetToken() == BfToken_ReadOnly); + bool isStatic = (varDecl->mModSpecifier != NULL) && (varDecl->mModSpecifier->GetToken() == BfToken_Static); BfLocalVariable* localDef = new BfLocalVariable(); if (varDecl->mNameNode != NULL) @@ -1346,6 +1347,7 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD { localDef->mName = "val"; } + localDef->mIsStatic = isStatic; bool handledExprBoolResult = false; bool handledVarInit = false; @@ -1626,7 +1628,7 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD }; localDef->mResolvedType = resolvedType; - localDef->mIsReadOnly = isReadOnly; + localDef->mIsReadOnly = isReadOnly; if (!initHandled) { @@ -1679,7 +1681,7 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD if ((!initValue) && (!initHandled)) { - if (isConst) + if ((isConst) || (isStatic)) { BfConstResolver constResolver(this); initValue = constResolver.Resolve(varDecl->mInitializer, resolvedType, BfConstResolveFlag_ActualizeValues); @@ -1763,6 +1765,11 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD _CheckConst(); + if (isStatic) + { + NOP; + } + if ((initValue.mKind == BfTypedValueKind_TempAddr) && (!initHandled)) { BF_ASSERT(initValue.IsAddr()); @@ -1781,7 +1788,7 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD mCurMethodState->mCurScope->mDeferredLifetimeEnds.push_back(localDef->mAddr); } - if ((!localDef->mAddr) && (!isConst) && ((!localDef->mIsReadOnly) || (localNeedsAddr))) + if ((!localDef->mAddr) && (!isConst) && (!isStatic) && ((!localDef->mIsReadOnly) || (localNeedsAddr))) { if ((exprEvaluator != NULL) && (exprEvaluator->mResultIsTempComposite)) { @@ -1794,6 +1801,27 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD localDef->mAddr = AllocLocalVariable(resolvedType, localDef->mName); } + if (isStatic) + { + String name = mModuleName + "_" + mCurMethodInstance->mMethodDef->mName + "_" + localDef->mName; + + HashContext closureHashCtx; + closureHashCtx.Mixin(varDecl->mSrcStart); + uint64 closureHash = closureHashCtx.Finish64(); + name += "$"; + name += BfTypeUtils::HashEncode64(closureHash); + + initValue = LoadValue(initValue); + if ((initValue) && (!initValue.mValue.IsConst())) + { + Fail("Static local variables can only be initialized with a const value", varDecl->mInitializer); + initValue = BfTypedValue(); + } + + localDef->mAddr = mBfIRBuilder->CreateGlobalVariable(mBfIRBuilder->MapType(localDef->mResolvedType), false, BfIRLinkageType_Internal, initValue.mValue, name);; + initHandled = true; + } + bool wantsStore = false; if ((initValue) && (!handledVarStore) && (!isConst) && (!initHandled)) {