Просмотр исходного кода

Static local methods and variables, fixed erroneous 'this' capture

Brian Fiete 3 лет назад
Родитель
Сommit
d9725dda7c

+ 11 - 0
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<BeConstant>(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);

+ 13 - 3
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;

+ 21 - 2
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)
 	{	

+ 5 - 2
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();

+ 16 - 3
IDEHelper/Compiler/BfReducer.cpp

@@ -4068,9 +4068,12 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS
 				continuingVariable = BfNodeDynCast<BfVariableDeclaration>(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<BfExpressionStatement>(stmt))
 			{
 				if (auto variableDecl = BfNodeDynCast<BfVariableDeclaration>(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<BfLocalMethodDeclaration>(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;

+ 31 - 3
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))
 	{