mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 19:48:20 +02:00
2198 lines
82 KiB
C++
2198 lines
82 KiB
C++
#pragma once
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4141)
|
|
#pragma warning(disable:4146)
|
|
#pragma warning(disable:4291)
|
|
#pragma warning(disable:4244)
|
|
#pragma warning(disable:4267)
|
|
#pragma warning(disable:4624)
|
|
#pragma warning(disable:4800)
|
|
#pragma warning(disable:4996)
|
|
|
|
#include "BeefySysLib/Common.h"
|
|
#include "BeefySysLib/util/CritSect.h"
|
|
#include "BeefySysLib/util/PerfTimer.h"
|
|
#include "BeefySysLib/util/Hash.h"
|
|
#include "BeefySysLib/util/HashSet.h"
|
|
#include "BeefySysLib/util/SizedArray.h"
|
|
#include "BeefySysLib/Span.h"
|
|
#include "BfSourceClassifier.h"
|
|
#include "BfAst.h"
|
|
#include "BfSystem.h"
|
|
#include "BfIRBuilder.h"
|
|
#include "BfResolvedTypeUtils.h"
|
|
#include "BfUtil.h"
|
|
#include <unordered_set>
|
|
#include <functional>
|
|
|
|
#pragma warning(pop)
|
|
|
|
NS_BF_BEGIN
|
|
|
|
class BfType;
|
|
class BfResolvedType;
|
|
class BfExprEvaluator;
|
|
class CeEmitContext;
|
|
class CeDbgState;
|
|
enum BfCeTypeEmitSourceKind : int8;
|
|
|
|
enum BfPopulateType
|
|
{
|
|
BfPopulateType_TypeDef,
|
|
BfPopulateType_Identity,
|
|
BfPopulateType_IdentityNoRemapAlias,
|
|
BfPopulateType_Declaration,
|
|
BfPopulateType_BaseType,
|
|
BfPopulateType_CustomAttributes,
|
|
BfPopulateType_Interfaces_Direct,
|
|
BfPopulateType_AllowStaticMethods,
|
|
BfPopulateType_Interfaces_All,
|
|
BfPopulateType_Data_Soft,
|
|
BfPopulateType_Data,
|
|
BfPopulateType_DataAndMethods,
|
|
BfPopulateType_Full = BfPopulateType_DataAndMethods,
|
|
|
|
BfPopulateType_Full_Force
|
|
};
|
|
|
|
enum BfEvalExprFlags : int64
|
|
{
|
|
BfEvalExprFlags_None = 0,
|
|
BfEvalExprFlags_ExplicitCast = 1,
|
|
BfEvalExprFlags_NoCast = 2,
|
|
BfEvalExprFlags_NoValueAddr = 4,
|
|
BfEvalExprFlags_PropogateNullConditional = 8,
|
|
BfEvalExprFlags_IgnoreNullConditional = 0x10,
|
|
BfEvalExprFlags_AllowSplat = 0x20,
|
|
BfEvalExprFlags_AllowEnumId = 0x40,
|
|
BfEvalExprFlags_AllowIntUnknown = 0x80,
|
|
BfEvalExprFlags_CreateConditionalScope = 0x100,
|
|
BfEvalExprFlags_PendingPropSet = 0x200,
|
|
BfEvalExprFlags_AllowParamsExpr = 0x400,
|
|
BfEvalExprFlags_AllowRefExpr = 0x800,
|
|
BfEvalExprFlags_AllowOutExpr = 0x1000,
|
|
BfEvalExprFlags_FieldInitializer = 0x2000,
|
|
BfEvalExprFlags_VariableDeclaration = 0x4000,
|
|
BfEvalExprFlags_NoAutoComplete = 0x8000,
|
|
BfEvalExprFlags_AllowNonConst = 0x10000,
|
|
BfEvalExprFlags_StringInterpolateFormat = 0x20000,
|
|
BfEvalExprFlags_NoLookupError = 0x40000,
|
|
BfEvalExprFlags_Comptime = 0x80000,
|
|
BfEvalExprFlags_DisallowComptime = 0x100000,
|
|
BfEvalExprFlags_InCascade = 0x200000,
|
|
BfEvalExprFlags_InferReturnType = 0x400000,
|
|
BfEvalExprFlags_WasMethodRef = 0x800000,
|
|
BfEvalExprFlags_DeclType = 0x1000000,
|
|
BfEvalExprFlags_AllowBase = 0x2000000,
|
|
BfEvalExprFlags_NoCeRebuildFlags = 0x4000000,
|
|
BfEvalExprFlags_FromConversionOp = 0x8000000,
|
|
BfEvalExprFlags_FromConversionOp_Explicit = 0x10000000,
|
|
BfEvalExprFlags_AllowGenericConstValue = 0x20000000,
|
|
BfEvalExprFlags_IsExpressionBody = 0x40000000,
|
|
BfEvalExprFlags_AppendFieldInitializer = 0x80000000,
|
|
BfEvalExprFlags_NameOf = 0x100000000LL,
|
|
BfEvalExprFlags_NameOfSuccess = 0x200000000LL,
|
|
BfEvalExprFlags_InParamsExpr = 0x400000000LL,
|
|
|
|
BfEvalExprFlags_InheritFlags = BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_Comptime | BfEvalExprFlags_DeclType
|
|
};
|
|
|
|
enum BfCastFlags
|
|
{
|
|
BfCastFlags_None = 0,
|
|
BfCastFlags_Explicit = 1,
|
|
BfCastFlags_Unchecked = 2,
|
|
BfCastFlags_Internal = 4,
|
|
BfCastFlags_SilentFail = 8,
|
|
BfCastFlags_NoBox = 0x10,
|
|
BfCastFlags_NoBoxDtor = 0x20,
|
|
BfCastFlags_NoInterfaceImpl = 0x40,
|
|
BfCastFlags_NoConversionOperator = 0x80,
|
|
BfCastFlags_FromCompiler = 0x100, // Not user specified
|
|
BfCastFlags_Force = 0x200,
|
|
BfCastFlags_PreferAddr = 0x400,
|
|
BfCastFlags_WarnOnBox = 0x800,
|
|
BfCastFlags_IsCastCheck = 0x1000,
|
|
BfCastFlags_IsConstraintCheck = 0x2000,
|
|
BfCastFlags_WantsConst = 0x4000,
|
|
BfCastFlags_FromComptimeReturn = 0x8000
|
|
};
|
|
|
|
enum BfCastResultFlags : int8
|
|
{
|
|
BfCastResultFlags_None = 0,
|
|
BfCastResultFlags_IsAddr = 1,
|
|
BfCastResultFlags_IsTemp = 2
|
|
};
|
|
|
|
enum BfAllocFlags : int8
|
|
{
|
|
BfAllocFlags_None = 0,
|
|
BfAllocFlags_HasAppendWantMark = 1,
|
|
BfAllocFlags_RawArray = 2,
|
|
BfAllocFlags_ZeroMemory = 4,
|
|
BfAllocFlags_NoDtorCall = 8,
|
|
BfAllocFlags_NoDefaultToMalloc = 0x10,
|
|
};
|
|
|
|
enum BfProtectionCheckFlags : int8
|
|
{
|
|
BfProtectionCheckFlag_None = 0,
|
|
BfProtectionCheckFlag_CheckedProtected = 1,
|
|
BfProtectionCheckFlag_CheckedPrivate = 2,
|
|
BfProtectionCheckFlag_AllowProtected = 4,
|
|
BfProtectionCheckFlag_AllowPrivate = 8,
|
|
BfProtectionCheckFlag_InstanceLookup = 0x10
|
|
};
|
|
|
|
enum BfEmbeddedStatementFlags : int8
|
|
{
|
|
BfEmbeddedStatementFlags_None = 0,
|
|
BfEmbeddedStatementFlags_IsConditional = 1,
|
|
BfEmbeddedStatementFlags_IsDeferredBlock = 2,
|
|
BfEmbeddedStatementFlags_Unscoped = 4,
|
|
BfEmbeddedStatementFlags_CheckStack = 8
|
|
};
|
|
|
|
enum BfLocalVarAssignKind : int8
|
|
{
|
|
BfLocalVarAssignKind_None = 0,
|
|
BfLocalVarAssignKind_Conditional = 1,
|
|
BfLocalVarAssignKind_Unconditional = 2
|
|
};
|
|
|
|
struct BfCreateTypeDataContext
|
|
{
|
|
Dictionary<int, int> mUsedStringIdMap;
|
|
HashSet<BfTypeInstance*> mReflectTypeSet;
|
|
};
|
|
|
|
class BfLocalVariable
|
|
{
|
|
public:
|
|
int64 mUnassignedFieldFlags;
|
|
BfType* mResolvedType;
|
|
BfIdentifierNode* mNameNode;
|
|
String mName;
|
|
BfIRValue mAddr;
|
|
BfIRValue mConstValue;
|
|
BfIRValue mValue;
|
|
BfIRMDNode mDbgVarInst;
|
|
BfIRValue mDbgDeclareInst;
|
|
BfIRBlock mDeclBlock;
|
|
int mLocalVarIdx; // Index in mLocals
|
|
int mLocalVarId; // Unique Id for identification (does not get reused, unlike mLocalVarIdx)
|
|
int mCompositeCount;
|
|
int mWrittenToId;
|
|
int mReadFromId;
|
|
int mParamIdx;
|
|
uint8 mNamePrefixCount;
|
|
bool mIsThis;
|
|
bool mHasLocalStructBacking;
|
|
bool mIsStruct;
|
|
bool mIsImplicitParam;
|
|
bool mParamFailed;
|
|
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 mIsConst;
|
|
bool mIsBumpAlloc;
|
|
BfLocalVariable* mShadowedLocal;
|
|
|
|
public:
|
|
BfLocalVariable()
|
|
{
|
|
mUnassignedFieldFlags = 0;
|
|
mResolvedType = NULL;
|
|
mNameNode = NULL;
|
|
mLocalVarIdx = -1;
|
|
mLocalVarId = -1;
|
|
mCompositeCount = -1;
|
|
mParamIdx = -2;
|
|
mNamePrefixCount = 0;
|
|
mIsThis = false;
|
|
mHasLocalStructBacking = false;
|
|
mIsStruct = false;
|
|
mIsImplicitParam = false;
|
|
mParamFailed = false;
|
|
mAssignedKind = BfLocalVarAssignKind_None;
|
|
mHadExitBeforeAssign = false;
|
|
mWrittenToId = -1;
|
|
mReadFromId = -1;
|
|
mIsReadOnly = false;
|
|
mIsStatic = false;
|
|
mIsSplat = false;
|
|
mIsLowered = false;
|
|
mAllowAddr = false;
|
|
mIsShadow = false;
|
|
mUsedImplicitly = false;
|
|
mNotCaptured = false;
|
|
mIsConst = false;
|
|
mIsBumpAlloc = false;
|
|
mShadowedLocal = NULL;
|
|
}
|
|
|
|
bool IsParam()
|
|
{
|
|
return mParamIdx != -2;
|
|
}
|
|
void Init();
|
|
};
|
|
|
|
class BfMethodState;
|
|
class BfMixinState;
|
|
class BfClosureState;
|
|
|
|
class BfLocalMethod
|
|
{
|
|
public:
|
|
BfSystem* mSystem;
|
|
BfModule* mModule;
|
|
BfSource* mSource;
|
|
BfMethodDeclaration* mMethodDeclaration;
|
|
String mExpectedFullName;
|
|
String mMethodName;
|
|
BfMethodDef* mMethodDef;
|
|
BfLocalMethod* mOuterLocalMethod;
|
|
BfMethodInstanceGroup* mMethodInstanceGroup;
|
|
BfMethodInstance* mLambdaInvokeMethodInstance;
|
|
BfLambdaBindExpression* mLambdaBindExpr;
|
|
BfMethodState* mDeclMethodState;
|
|
BfIRMDNode mDeclDIScope;
|
|
BfMixinState* mDeclMixinState;
|
|
OwnedVector<BfDirectTypeReference> mDirectTypeRefs;
|
|
bool mDeclOnly;
|
|
bool mDidBodyErrorPass;
|
|
BfLocalMethod* mNextWithSameName;
|
|
|
|
public:
|
|
BfLocalMethod()
|
|
{
|
|
mModule = NULL;
|
|
mSystem = NULL;
|
|
mSource = NULL;
|
|
mMethodDeclaration = NULL;
|
|
mMethodDef = NULL;
|
|
mOuterLocalMethod = NULL;
|
|
mMethodInstanceGroup = NULL;
|
|
mLambdaInvokeMethodInstance = NULL;
|
|
mLambdaBindExpr = NULL;
|
|
mDeclMethodState = NULL;
|
|
mDeclMixinState = NULL;
|
|
mDeclOnly = false;
|
|
mDidBodyErrorPass = false;
|
|
mNextWithSameName = NULL;
|
|
}
|
|
~BfLocalMethod();
|
|
void Dispose();
|
|
};
|
|
|
|
class BfDeferredCapture
|
|
{
|
|
public:
|
|
String mName;
|
|
BfTypedValue mValue;
|
|
};
|
|
|
|
class BfDeferredCallEntry
|
|
{
|
|
public:
|
|
BfDeferredCallEntry* mNext;
|
|
|
|
BfAstNode* mSrcNode;
|
|
BfTypedValue mTarget;
|
|
BfModuleMethodInstance mModuleMethodInstance;
|
|
BfIRValue mDeferredAlloca;
|
|
SizedArray<BfIRValue, 2> mOrigScopeArgs;
|
|
SizedArray<BfIRValue, 2> mScopeArgs;
|
|
Array<BfDeferredCapture> mCaptures;
|
|
BfBlock* mDeferredBlock;
|
|
BfAstNode* mEmitRefNode;
|
|
int64 mBlockId;
|
|
int mHandlerCount;
|
|
bool mBypassVirtual;
|
|
bool mDoNullCheck;
|
|
bool mCastThis;
|
|
bool mArgsNeedLoad;
|
|
bool mIgnored;
|
|
|
|
SLIList<BfDeferredCallEntry*> mDynList;
|
|
BfIRValue mDynCallTail;
|
|
|
|
public:
|
|
BfDeferredCallEntry()
|
|
{
|
|
mBypassVirtual = false;
|
|
mDoNullCheck = false;
|
|
mNext = NULL;
|
|
mSrcNode = NULL;
|
|
mDeferredBlock = NULL;
|
|
mEmitRefNode = NULL;
|
|
mBlockId = -1;
|
|
mHandlerCount = 0;
|
|
mArgsNeedLoad = false;
|
|
mCastThis = false;
|
|
mIgnored = false;
|
|
}
|
|
|
|
~BfDeferredCallEntry()
|
|
{
|
|
mDynList.DeleteAll();
|
|
}
|
|
|
|
bool IsDynList()
|
|
{
|
|
return (bool)mDynCallTail;
|
|
}
|
|
};
|
|
|
|
struct BfDeferredHandler
|
|
{
|
|
BfIRBlock mHandlerBlock;
|
|
BfIRBlock mDoneBlock;
|
|
};
|
|
|
|
class BfScopeData;
|
|
|
|
struct BfAssignedLocal
|
|
{
|
|
BfLocalVariable* mLocalVar;
|
|
int mLocalVarField;
|
|
BfLocalVarAssignKind mAssignKind;
|
|
|
|
bool operator==(const BfAssignedLocal& second) const
|
|
{
|
|
return (mLocalVar == second.mLocalVar) && (mLocalVarField == second.mLocalVarField) && (mAssignKind == second.mAssignKind);
|
|
}
|
|
};
|
|
|
|
// We use this structure in the case where we have multiple execution paths, then we merge the assigned variables together
|
|
// So when we have "if (check) { a = 1; } else {a = 2; }" we can know that a IS definitely assigned afterwards
|
|
class BfDeferredLocalAssignData
|
|
{
|
|
public:
|
|
BfScopeData* mScopeData;
|
|
int mVarIdBarrier;
|
|
SizedArray<BfAssignedLocal, 4> mAssignedLocals;
|
|
bool mIsChained;
|
|
BfDeferredLocalAssignData* mChainedAssignData;
|
|
bool mHadFallthrough;
|
|
bool mHadReturn;
|
|
bool mHadBreak;
|
|
bool mIsUnconditional;
|
|
bool mIsIfCondition;
|
|
bool mIfMayBeSkipped;
|
|
bool mLeftBlock;
|
|
bool mLeftBlockUncond;
|
|
|
|
public:
|
|
BfDeferredLocalAssignData(BfScopeData* scopeData = NULL)
|
|
{
|
|
mScopeData = scopeData;
|
|
mVarIdBarrier = -1;
|
|
mHadFallthrough = false;
|
|
mHadReturn = false;
|
|
mHadBreak = false;
|
|
mChainedAssignData = NULL;
|
|
mIsChained = false;
|
|
mIsUnconditional = false;
|
|
mIsIfCondition = false;
|
|
mIfMayBeSkipped = false;
|
|
mLeftBlock = false;
|
|
mLeftBlockUncond = false;
|
|
}
|
|
|
|
bool Contains(const BfAssignedLocal& val)
|
|
{
|
|
for (int i = 0; i < (int)mAssignedLocals.mSize; i++)
|
|
{
|
|
auto& check = mAssignedLocals[i];
|
|
if ((check.mLocalVar == val.mLocalVar) && (check.mLocalVarField == val.mLocalVarField) && (check.mAssignKind >= val.mAssignKind))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ExtendFrom(BfDeferredLocalAssignData* outerLocalAssignData, bool doChain = false);
|
|
void BreakExtendChain();
|
|
void SetIntersection(const BfDeferredLocalAssignData& otherLocalAssignData);
|
|
void Validate() const;
|
|
void SetUnion(const BfDeferredLocalAssignData& otherLocalAssignData);
|
|
};
|
|
|
|
enum BfScopeKind
|
|
{
|
|
BfScopeKind_Normal,
|
|
BfScopeKind_StatementTarget,
|
|
BfScopeKind_StatementTarget_Conditional,
|
|
};
|
|
|
|
class BfDeferredCallProcessorInstance
|
|
{
|
|
public:
|
|
BfDeferredCallEntry* mDeferredCallEntry;
|
|
BfIRBlock mProcessorBlock;
|
|
BfIRBlock mContinueBlock;
|
|
};
|
|
|
|
// "Looped" means this scope will execute zero to many times, "Conditional" means zero or one.
|
|
// Looped and Conditional are mutually exclusive. "Dyn" means Looped OR Conditional.
|
|
class BfScopeData
|
|
{
|
|
public:
|
|
BfScopeData* mPrevScope;
|
|
BfScopeKind mScopeKind;
|
|
BfIRMDNode mDIScope;
|
|
BfIRMDNode mDIInlinedAt;
|
|
String mLabel;
|
|
BfIdentifierNode* mLabelNode;
|
|
int mLocalVarStart;
|
|
int mScopeDepth;
|
|
int mMixinDepth;
|
|
int mScopeLocalId;
|
|
bool mIsScopeHead; // For first scope data or for inlined start
|
|
bool mIsLoop;
|
|
bool mIsConditional; // Rarely set - usually we rely on OuterIsConditional or InnerIsConditional
|
|
bool mOuterIsConditional;
|
|
bool mInnerIsConditional;
|
|
bool mHadOuterDynStack;
|
|
bool mAllowTargeting;
|
|
bool mHadScopeValueRetain;
|
|
bool mIsDeferredBlock;
|
|
bool mAllowVariableDeclarations;
|
|
bool mInInitBlock;
|
|
bool mSupressNextUnreachable;
|
|
bool mInConstIgnore;
|
|
bool mIsSharedTempBlock;
|
|
bool mDone;
|
|
BfMixinState* mMixinState;
|
|
BfBlock* mAstBlock;
|
|
BfAstNode* mCloseNode;
|
|
BfExprEvaluator* mExprEvaluator;
|
|
SLIList<BfDeferredCallEntry*> mDeferredCallEntries;
|
|
Array<BfDeferredCallProcessorInstance> mDeferredCallProcessorInstances;
|
|
BfIRValue mBlock;
|
|
BfIRValue mValueScopeStart;
|
|
BfIRValue mSavedStack;
|
|
Array<BfIRValue> mSavedStackUses;
|
|
Array<BfDeferredHandler> mDeferredHandlers; // These get cleared when us our a parent gets new entries added into mDeferredCallEntries
|
|
Array<BfIRBlock> mAtEndBlocks; // Move these to the end after we close scope
|
|
Array<BfIRValue> mDeferredLifetimeEnds;
|
|
BfDeferredLocalAssignData* mExitLocalAssignData;
|
|
BfIRMDNode mAltDIFile;
|
|
BfIRMDNode mAltDIScope;
|
|
|
|
public:
|
|
BfScopeData()
|
|
{
|
|
mScopeKind = BfScopeKind_Normal;
|
|
mPrevScope = NULL;
|
|
mLocalVarStart = 0;
|
|
mLabelNode = NULL;
|
|
mMixinState = NULL;
|
|
mAstBlock = NULL;
|
|
mCloseNode = NULL;
|
|
mExprEvaluator = NULL;
|
|
mIsScopeHead = false;
|
|
mIsLoop = false;
|
|
mIsConditional = false;
|
|
mOuterIsConditional = false;
|
|
mInnerIsConditional = false;
|
|
mHadOuterDynStack = false;
|
|
mHadScopeValueRetain = false;
|
|
mIsDeferredBlock = false;
|
|
mSupressNextUnreachable = false;
|
|
mAllowTargeting = true;
|
|
mAllowVariableDeclarations = true;
|
|
mInInitBlock = false;
|
|
mInConstIgnore = false;
|
|
mIsSharedTempBlock = false;
|
|
mDone = false;
|
|
mMixinDepth = 0;
|
|
mScopeDepth = 0;
|
|
mScopeLocalId = -1;
|
|
mExitLocalAssignData = NULL;
|
|
}
|
|
|
|
~BfScopeData()
|
|
{
|
|
mDeferredCallEntries.DeleteAll();
|
|
delete mExitLocalAssignData;
|
|
}
|
|
|
|
BfScopeData* GetHead()
|
|
{
|
|
auto checkScope = this;
|
|
while (!checkScope->mIsScopeHead)
|
|
checkScope = checkScope->mPrevScope;
|
|
return checkScope;
|
|
}
|
|
|
|
BfScopeData* GetTargetable()
|
|
{
|
|
if (!mAllowTargeting)
|
|
return mPrevScope->GetTargetable();
|
|
return this;
|
|
}
|
|
|
|
bool IsLooped(BfScopeData* scopeData)
|
|
{
|
|
auto checkScope = this;
|
|
while (checkScope != NULL)
|
|
{
|
|
if (checkScope->mIsLoop)
|
|
return true;
|
|
if (checkScope == scopeData)
|
|
break;
|
|
checkScope = checkScope->mPrevScope;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool IsDyn(BfScopeData* scopeData)
|
|
{
|
|
auto checkScope = this;
|
|
// Scoping to a loop is dynamic - it doesn't have to cross the loop boundary.
|
|
// Scoping to a loop _body_ is not necessarily dynamic, however.
|
|
while (checkScope != NULL)
|
|
{
|
|
if (checkScope->mIsConditional)
|
|
return true;
|
|
if ((checkScope->mIsLoop) || (checkScope->mInnerIsConditional))
|
|
return true;
|
|
if (checkScope == scopeData)
|
|
break;
|
|
if (checkScope->mOuterIsConditional)
|
|
return true;
|
|
checkScope = checkScope->mPrevScope;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CrossesMixin(BfScopeData* scopeData)
|
|
{
|
|
// Check for a transition for having an inlinedAt to not having one
|
|
if (!mDIInlinedAt)
|
|
return false;
|
|
auto checkScope = this;
|
|
while (checkScope != scopeData)
|
|
{
|
|
checkScope = checkScope->mPrevScope;
|
|
if (!checkScope->mDIInlinedAt)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ClearHandlers(BfScopeData* scopeData)
|
|
{
|
|
auto checkScope = this;
|
|
while (true)
|
|
{
|
|
checkScope->mDeferredHandlers.Clear();
|
|
if (checkScope == scopeData)
|
|
break;
|
|
checkScope = checkScope->mPrevScope;
|
|
}
|
|
}
|
|
|
|
int GetDepth()
|
|
{
|
|
int depth = 0;
|
|
auto checkScopeData = this;
|
|
while (true)
|
|
{
|
|
checkScopeData = checkScopeData->mPrevScope;
|
|
if (checkScopeData == NULL)
|
|
break;
|
|
depth++;
|
|
}
|
|
return depth;
|
|
}
|
|
|
|
bool ExtendLifetime(BfIRValue irValue)
|
|
{
|
|
if (mDeferredLifetimeEnds.Remove(irValue))
|
|
{
|
|
if (mPrevScope != NULL)
|
|
mPrevScope->mDeferredLifetimeEnds.Add(irValue);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
struct BfCaptureInfo
|
|
{
|
|
public:
|
|
struct Entry
|
|
{
|
|
BfCaptureType mCaptureType;
|
|
bool mUsed;
|
|
BfAstNode* mRefNode;
|
|
BfAstNode* mNameNode;
|
|
|
|
Entry()
|
|
{
|
|
mCaptureType = BfCaptureType_Copy;
|
|
mUsed = false;
|
|
mRefNode = NULL;
|
|
mNameNode = NULL;
|
|
}
|
|
};
|
|
|
|
public:
|
|
Array<Entry> mCaptures;
|
|
};
|
|
|
|
class BfAllocTarget
|
|
{
|
|
public:
|
|
BfScopeData* mScopeData;
|
|
BfAstNode* mRefNode;
|
|
BfTypedValue mCustomAllocator;
|
|
BfScopedInvocationTarget* mScopedInvocationTarget;
|
|
int mAlignOverride;
|
|
BfCaptureInfo* mCaptureInfo;
|
|
bool mIsFriend;
|
|
|
|
public:
|
|
BfAllocTarget()
|
|
{
|
|
mScopeData = NULL;
|
|
mRefNode = NULL;
|
|
mCustomAllocator = NULL;
|
|
mScopedInvocationTarget = NULL;
|
|
mAlignOverride = -1;
|
|
mIsFriend = false;
|
|
mCaptureInfo = NULL;
|
|
}
|
|
|
|
BfAllocTarget(BfScopeData* scopeData)
|
|
{
|
|
mScopeData = scopeData;
|
|
mRefNode = NULL;
|
|
mCustomAllocator = NULL;
|
|
mScopedInvocationTarget = NULL;
|
|
mAlignOverride = -1;
|
|
}
|
|
|
|
BfAllocTarget(const BfTypedValue& customAllocator, BfAstNode* refNode)
|
|
{
|
|
mScopeData = NULL;
|
|
mCustomAllocator = customAllocator;
|
|
mRefNode = NULL;
|
|
mScopedInvocationTarget = NULL;
|
|
mAlignOverride = -1;
|
|
}
|
|
};
|
|
|
|
class BfBreakData
|
|
{
|
|
public:
|
|
BfBreakData* mPrevBreakData;
|
|
BfScopeData* mScope;
|
|
BfIRBlock mIRContinueBlock;
|
|
BfIRBlock mIRBreakBlock;
|
|
BfIRBlock mIRFallthroughBlock;
|
|
BfIRValue mInnerValueScopeStart;
|
|
bool mHadBreak;
|
|
|
|
public:
|
|
BfBreakData()
|
|
{
|
|
mPrevBreakData = NULL;
|
|
mScope = NULL;
|
|
mHadBreak = false;
|
|
}
|
|
};
|
|
|
|
class BfMixinRecord
|
|
{
|
|
public:
|
|
BfAstNode * mSource;
|
|
};
|
|
|
|
class BfDeferredLocalMethod
|
|
{
|
|
public:
|
|
BfLocalMethod* mLocalMethod;
|
|
BfMethodInstance* mMethodInstance;
|
|
Array<BfLocalMethod*> mLocalMethods; // Local methods that were in scope at the time
|
|
Array<BfLocalVariable> mConstLocals;
|
|
Array<BfMixinRecord> mMixinStateRecords;
|
|
};
|
|
|
|
enum BfReturnTypeInferState
|
|
{
|
|
BfReturnTypeInferState_None,
|
|
BfReturnTypeInferState_Inferring,
|
|
BfReturnTypeInferState_Fail,
|
|
};
|
|
|
|
class BfClosureState
|
|
{
|
|
public:
|
|
bool mCapturing;
|
|
bool mCaptureVisitingBody;
|
|
int mCaptureStartAccessId;
|
|
// When we need to look into another local method to determine captures, but we don't want to process local variable declarations or cause infinite recursion
|
|
bool mBlindCapturing;
|
|
bool mDeclaringMethodIsMutating;
|
|
bool mCapturedDelegateSelf;
|
|
BfReturnTypeInferState mReturnTypeInferState;
|
|
BfLocalMethod* mLocalMethod;
|
|
BfClosureInstanceInfo* mClosureInstanceInfo;
|
|
BfMethodDef* mClosureMethodDef;
|
|
BfType* mReturnType;
|
|
BfTypeInstance* mDelegateType;
|
|
BfTypeInstance* mClosureType;
|
|
BfDeferredLocalMethod* mActiveDeferredLocalMethod;
|
|
Array<BfLocalVariable> mConstLocals; // Locals not inserted into the captured 'this'
|
|
HashSet<BfFieldInstance*> mReferencedOuterClosureMembers;
|
|
HashSet<BfMethodInstance*> mLocalMethodRefSet;
|
|
Array<BfMethodInstance*> mLocalMethodRefs;
|
|
Array<BfMethodInstance*> mDeferredProcessLocalMethods;
|
|
|
|
public:
|
|
BfClosureState()
|
|
{
|
|
mClosureMethodDef = NULL;
|
|
mLocalMethod = NULL;
|
|
mClosureInstanceInfo = NULL;
|
|
mCapturing = false;
|
|
mCaptureVisitingBody = false;
|
|
mCaptureStartAccessId = -1;
|
|
mBlindCapturing = false;
|
|
mDeclaringMethodIsMutating = false;
|
|
mCapturedDelegateSelf = false;
|
|
mReturnTypeInferState = BfReturnTypeInferState_None;
|
|
mActiveDeferredLocalMethod = NULL;
|
|
mReturnType = NULL;
|
|
mDelegateType = NULL;
|
|
mClosureType = NULL;
|
|
}
|
|
};
|
|
|
|
class BfIteratorClassState
|
|
{
|
|
public:
|
|
BfTypeInstance* mIteratorClass;
|
|
bool mCapturing;
|
|
|
|
public:
|
|
BfIteratorClassState()
|
|
{
|
|
mCapturing = false;
|
|
}
|
|
};
|
|
|
|
class BfPendingNullConditional
|
|
{
|
|
public:
|
|
BfIRBlock mPrevBB;
|
|
BfIRBlock mCheckBB;
|
|
BfIRBlock mDoneBB;
|
|
SizedArray<BfIRBlock, 4> mNotNullBBs;
|
|
};
|
|
|
|
class BfAttributeState
|
|
{
|
|
public:
|
|
enum Flags
|
|
{
|
|
Flag_None,
|
|
Flag_StopOnError = 1,
|
|
Flag_HadError = 2
|
|
};
|
|
|
|
public:
|
|
Flags mFlags;
|
|
BfAstNode* mSrc;
|
|
BfAttributeTargets mTarget;
|
|
BfCustomAttributes* mCustomAttributes;
|
|
bool mUsed;
|
|
|
|
BfAttributeState()
|
|
{
|
|
mSrc = NULL;
|
|
mFlags = Flag_None;
|
|
mTarget = BfAttributeTargets_None;
|
|
mCustomAttributes = NULL;
|
|
mUsed = false;
|
|
}
|
|
|
|
~BfAttributeState()
|
|
{
|
|
if (mCustomAttributes != NULL)
|
|
delete mCustomAttributes;
|
|
}
|
|
};
|
|
|
|
class BfMixinState
|
|
{
|
|
public:
|
|
BfMixinState* mPrevMixinState;
|
|
BfAstNode* mSource;
|
|
BfScopeData* mCallerScope;
|
|
BfScopeData* mTargetScope; // Equals caller scope unless user explicitly calls specifies scope override
|
|
BfFilePosition mInjectFilePosition;
|
|
BfMethodInstance* mMixinMethodInstance;
|
|
BfAstNode* mResultExpr;
|
|
SizedArray<BfType*, 8> mArgTypes;
|
|
SizedArray<BfIRValue, 8> mArgConsts;
|
|
int mLocalsStartIdx;
|
|
bool mUsedInvocationScope;
|
|
bool mHasDeferredUsage;
|
|
bool mCheckedCircularRef;
|
|
bool mDoCircularVarResult;
|
|
bool mUseMixinGenerics;
|
|
BfTypedValue mTarget;
|
|
int mLastTargetAccessId;
|
|
|
|
public:
|
|
BfMixinState()
|
|
{
|
|
mPrevMixinState = NULL;
|
|
mSource = NULL;
|
|
mCallerScope = NULL;
|
|
mTarget = NULL;
|
|
mMixinMethodInstance = NULL;
|
|
mResultExpr = NULL;
|
|
mLocalsStartIdx = 0;
|
|
mUsedInvocationScope = false;
|
|
mHasDeferredUsage = false;
|
|
mCheckedCircularRef = false;
|
|
mDoCircularVarResult = false;
|
|
mUseMixinGenerics = false;
|
|
mLastTargetAccessId = -1;
|
|
}
|
|
|
|
BfMixinState* GetRoot()
|
|
{
|
|
auto curMixin = this;
|
|
while (curMixin->mPrevMixinState != NULL)
|
|
curMixin = curMixin->mPrevMixinState;
|
|
return curMixin;
|
|
}
|
|
};
|
|
|
|
class BfDeferredCallEmitState
|
|
{
|
|
public:
|
|
BfAstNode* mCloseNode;
|
|
|
|
public:
|
|
BfDeferredCallEmitState()
|
|
{
|
|
mCloseNode = NULL;
|
|
}
|
|
};
|
|
|
|
class BfTypeLookupError
|
|
{
|
|
public:
|
|
enum BfErrorKind
|
|
{
|
|
BfErrorKind_None,
|
|
BfErrorKind_Ambiguous,
|
|
BfErrorKind_Inaccessible
|
|
};
|
|
|
|
public:
|
|
BfErrorKind mErrorKind;
|
|
BfAstNode* mRefNode;
|
|
BfTypeDef* mAmbiguousTypeDef;
|
|
|
|
public:
|
|
BfTypeLookupError()
|
|
{
|
|
mErrorKind = BfErrorKind_None;
|
|
mRefNode = NULL;
|
|
mAmbiguousTypeDef = NULL;
|
|
}
|
|
};
|
|
|
|
/*struct BfSplatDecompHash
|
|
{
|
|
size_t operator()(const std::pair<BfIRValue, int>& val) const
|
|
{
|
|
return (val.first.mId << 4) + val.second;
|
|
}
|
|
};
|
|
|
|
struct BfSplatDecompEquals
|
|
{
|
|
bool operator()(const std::pair<BfIRValue, int>& lhs, const std::pair<BfIRValue, int>& rhs) const
|
|
{
|
|
return (lhs.first.mFlags == rhs.first.mFlags) && (lhs.first.mId == rhs.first.mId) && (lhs.second == rhs.second);
|
|
}
|
|
};*/
|
|
|
|
struct BfMethodRefHash
|
|
{
|
|
size_t operator()(const BfMethodRef& val) const
|
|
{
|
|
if (val.mTypeInstance == NULL)
|
|
return 0;
|
|
return val.mTypeInstance->mTypeId ^ (val.mMethodNum << 10);
|
|
}
|
|
};
|
|
|
|
class BfConstResolveState
|
|
{
|
|
public:
|
|
BfMethodInstance* mMethodInstance;
|
|
BfConstResolveState* mPrevConstResolveState;
|
|
bool mInCalcAppend;
|
|
bool mFailed;
|
|
|
|
BfConstResolveState()
|
|
{
|
|
mMethodInstance = NULL;
|
|
mPrevConstResolveState = NULL;
|
|
mInCalcAppend = false;
|
|
mFailed = false;
|
|
}
|
|
};
|
|
|
|
struct BfLocalVarEntry
|
|
{
|
|
BfLocalVariable* mLocalVar;
|
|
|
|
BfLocalVarEntry(BfLocalVariable* localVar)
|
|
{
|
|
mLocalVar = localVar;
|
|
}
|
|
|
|
bool operator==(const BfLocalVarEntry& other) const
|
|
{
|
|
return mLocalVar->mName == other.mLocalVar->mName;
|
|
}
|
|
|
|
bool operator==(const StringImpl& name) const
|
|
{
|
|
return mLocalVar->mName == name;
|
|
}
|
|
};
|
|
|
|
class BfLambdaCaptureInfo
|
|
{
|
|
public:
|
|
String mName;
|
|
};
|
|
|
|
class BfLambdaInstance
|
|
{
|
|
public:
|
|
BfTypeInstance* mDelegateTypeInstance;
|
|
BfTypeInstance* mUseTypeInstance;
|
|
BfClosureType* mClosureTypeInstance;
|
|
BfMixinState* mDeclMixinState;
|
|
BfTypeInstance* mOuterClosure;
|
|
BfIRValue mClosureFunc;
|
|
BfIRValue mDtorFunc;
|
|
bool mCopyOuterCaptures;
|
|
bool mDeclaringMethodIsMutating;
|
|
bool mIsStatic;
|
|
Array<BfLambdaCaptureInfo> mCaptures;
|
|
BfMethodInstance* mMethodInstance;
|
|
BfMethodInstance* mDtorMethodInstance;
|
|
Array<BfLocalVariable> mConstLocals;
|
|
OwnedVector<BfParameterDeclaration> mParamDecls;
|
|
|
|
public:
|
|
BfLambdaInstance()
|
|
{
|
|
mDelegateTypeInstance = NULL;
|
|
mUseTypeInstance = NULL;
|
|
mClosureTypeInstance = NULL;
|
|
mDeclMixinState = NULL;
|
|
mOuterClosure = NULL;
|
|
mCopyOuterCaptures = false;
|
|
mDeclaringMethodIsMutating = false;
|
|
mIsStatic = false;
|
|
mMethodInstance = NULL;
|
|
mDtorMethodInstance = NULL;
|
|
}
|
|
|
|
~BfLambdaInstance()
|
|
{
|
|
auto methodDef = mMethodInstance->mMethodDef;
|
|
delete mMethodInstance;
|
|
delete methodDef;
|
|
|
|
if (mDtorMethodInstance != NULL)
|
|
{
|
|
auto methodDef = mDtorMethodInstance->mMethodDef;
|
|
delete mDtorMethodInstance;
|
|
delete methodDef;
|
|
}
|
|
}
|
|
};
|
|
|
|
class BfParentNodeEntry
|
|
{
|
|
public:
|
|
BfAstNode* mNode;
|
|
BfParentNodeEntry* mPrev;
|
|
};
|
|
|
|
class BfMethodState
|
|
{
|
|
public:
|
|
enum TempKind
|
|
{
|
|
TempKind_None,
|
|
TempKind_Static,
|
|
TempKind_NonStatic
|
|
};
|
|
|
|
public:
|
|
BumpAllocator mBumpAlloc;
|
|
BfMethodState* mPrevMethodState; // Only non-null for things like local methods
|
|
BfConstResolveState* mConstResolveState;
|
|
BfMethodInstance* mMethodInstance;
|
|
BfHotDataReferenceBuilder* mHotDataReferenceBuilder;
|
|
BfTypeInstance* mPrivateTypeInstance;
|
|
BfIRFunction mIRFunction;
|
|
BfIRBlock mIRHeadBlock;
|
|
BfIRBlock mIRInitBlock;
|
|
BfIRBlock mIREntryBlock;
|
|
Array<BfLocalVariable*, AllocatorBump> mLocals;
|
|
HashSet<BfLocalVarEntry, AllocatorBump> mLocalVarSet;
|
|
Array<BfLocalMethod*> mLocalMethods;
|
|
Dictionary<String, BfLocalMethod*> mLocalMethodMap;
|
|
Dictionary<String, BfLocalMethod*> mLocalMethodCache; // So any lambda 'capturing' and 'processing' stages use the same local method
|
|
Array<BfDeferredLocalMethod*> mDeferredLocalMethods;
|
|
OwnedVector<BfMixinState> mMixinStates;
|
|
Dictionary<BfAstNodeList, BfLambdaInstance*> mLambdaCache;
|
|
Array<BfLambdaInstance*> mDeferredLambdaInstances;
|
|
Array<BfIRValue> mSplatDecompAddrs;
|
|
BfDeferredLocalAssignData* mDeferredLocalAssignData;
|
|
BfProjectSet mVisibleProjectSet;
|
|
int mDeferredLoopListCount;
|
|
int mDeferredLoopListEntryCount;
|
|
HashSet<int> mSkipObjectAccessChecks; // Indexed by BfIRValue value id
|
|
|
|
Dictionary<int64, BfType*>* mGenericTypeBindings;
|
|
|
|
BfIRMDNode mDIFile;
|
|
bool mInHeadScope; // Is in starting scope of code on entry, controls mStackAllocUncondCount
|
|
BfTypedValue mRetVal;
|
|
BfIRValue mRetValAddr;
|
|
int mCurAppendAlign;
|
|
BfIRValue mDynStackRevIdx; // Increments when we restore the stack, which can invalidate dynSize for dynamic looped allocs
|
|
BfIRBlock mIRExitBlock;
|
|
BfBreakData* mBreakData;
|
|
int mBlockNestLevel; // 0 = top level
|
|
bool mIgnoreObjectAccessCheck;
|
|
bool mDisableChecks;
|
|
BfMixinState* mMixinState;
|
|
BfClosureState* mClosureState;
|
|
BfDeferredCallEmitState* mDeferredCallEmitState;
|
|
BfIteratorClassState* mIteratorClassState;
|
|
BfPendingNullConditional* mPendingNullConditional;
|
|
BfTypeOptions* mMethodTypeOptions; // for [Options] attribute
|
|
BfIRMDNode mDIRetVal;
|
|
|
|
BfScopeData mHeadScope;
|
|
BfScopeData* mCurScope;
|
|
BfScopeData* mTailScope; // Usually equals mCurScope
|
|
BfScopeData* mOverrideScope;
|
|
BfAstNode* mEmitRefNode;
|
|
TempKind mTempKind; // Used for var inference, etc
|
|
bool mInDeferredBlock;
|
|
bool mHadReturn;
|
|
bool mHadContinue;
|
|
bool mMayNeedThisAccessCheck;
|
|
bool mLeftBlockUncond; // Definitely left block. mHadReturn also sets mLeftBlock
|
|
bool mLeftBlockCond; // May have left block.
|
|
bool mInPostReturn; // Unreachable code
|
|
bool mCrossingMixin; // ie: emitting dtors in response to a return in a mixin
|
|
bool mNoBind;
|
|
bool mInConditionalBlock; // IE: RHS of ((A) && (B)), indicates an allocation in 'B' won't be dominated by a dtor, for example
|
|
bool mAllowUinitReads;
|
|
bool mDisableReturns;
|
|
bool mCancelledDeferredCall;
|
|
bool mNoObjectAccessChecks;
|
|
int mCurLocalVarId; // Can also refer to a label
|
|
int mCurAccessId; // For checking to see if a block reads from or writes to a local
|
|
|
|
public:
|
|
BfMethodState()
|
|
{
|
|
mLocals.mAlloc = &mBumpAlloc;
|
|
mLocalVarSet.mAlloc = &mBumpAlloc;
|
|
|
|
mMethodInstance = NULL;
|
|
mPrevMethodState = NULL;
|
|
mConstResolveState = NULL;
|
|
mHotDataReferenceBuilder = NULL;
|
|
mPrivateTypeInstance = NULL;
|
|
mHeadScope.mIsScopeHead = true;
|
|
mCurScope = &mHeadScope;
|
|
mTailScope = &mHeadScope;
|
|
mEmitRefNode = NULL;
|
|
mOverrideScope = NULL;
|
|
mHadReturn = false;
|
|
mLeftBlockUncond = false;
|
|
mLeftBlockCond = false;
|
|
mHadContinue = false;
|
|
mMayNeedThisAccessCheck = false;
|
|
mTempKind = TempKind_None;
|
|
mInHeadScope = true;
|
|
mBreakData = NULL;
|
|
mBlockNestLevel = 0;
|
|
mInPostReturn = false;
|
|
mCrossingMixin = false;
|
|
mNoBind = false;
|
|
mIgnoreObjectAccessCheck = false;
|
|
mDisableChecks = false;
|
|
mInConditionalBlock = false;
|
|
mAllowUinitReads = false;
|
|
mDisableReturns = false;
|
|
mCancelledDeferredCall = false;
|
|
mNoObjectAccessChecks = false;
|
|
mInDeferredBlock = false;
|
|
mDeferredLocalAssignData = NULL;
|
|
mCurLocalVarId = 0;
|
|
mCurAccessId = 1;
|
|
mCurAppendAlign = 0;
|
|
mDeferredLoopListCount = 0;
|
|
mDeferredLoopListEntryCount = 0;
|
|
mClosureState = NULL;
|
|
mDeferredCallEmitState = NULL;
|
|
mIteratorClassState = NULL;
|
|
|
|
mGenericTypeBindings = NULL;
|
|
mMixinState = NULL;
|
|
mPendingNullConditional = NULL;
|
|
mMethodTypeOptions = NULL;
|
|
}
|
|
|
|
~BfMethodState();
|
|
|
|
void AddScope(BfScopeData* newScopeData)
|
|
{
|
|
BF_ASSERT(newScopeData != mCurScope);
|
|
|
|
mInHeadScope = false;
|
|
newScopeData->mDIScope = mCurScope->mDIScope;
|
|
newScopeData->mDIInlinedAt = mCurScope->mDIInlinedAt;
|
|
newScopeData->mLocalVarStart = mCurScope->mLocalVarStart;
|
|
newScopeData->mExprEvaluator = mCurScope->mExprEvaluator;
|
|
newScopeData->mAltDIFile = mCurScope->mAltDIFile;
|
|
newScopeData->mPrevScope = mCurScope;
|
|
newScopeData->mMixinDepth = mCurScope->mMixinDepth;
|
|
newScopeData->mScopeDepth = mCurScope->mScopeDepth + 1;
|
|
newScopeData->mInConstIgnore = mCurScope->mInConstIgnore;
|
|
mCurScope = newScopeData;
|
|
mTailScope = mCurScope;
|
|
}
|
|
|
|
void SetHadReturn(bool hadReturn)
|
|
{
|
|
mHadReturn = hadReturn;
|
|
if (mDeferredLocalAssignData != NULL)
|
|
mDeferredLocalAssignData->mHadReturn = hadReturn;
|
|
}
|
|
|
|
BfMethodState* GetRootMethodState()
|
|
{
|
|
auto checkMethodState = this;
|
|
while (checkMethodState->mPrevMethodState != NULL)
|
|
checkMethodState = checkMethodState->mPrevMethodState;
|
|
return checkMethodState;
|
|
}
|
|
|
|
BfMethodState* GetNonCaptureState()
|
|
{
|
|
//TODO: Why did this require mLocalMethod to not be null? That means lambda captures we're not crossed over
|
|
auto checkMethodState = this;
|
|
while ((checkMethodState->mPrevMethodState != NULL) && (checkMethodState->mClosureState != NULL) &&
|
|
(checkMethodState->mClosureState->mCapturing) /*&& (checkMethodState->mClosureState->mLocalMethod != NULL)*/)
|
|
checkMethodState = checkMethodState->mPrevMethodState;
|
|
return checkMethodState;
|
|
}
|
|
|
|
BfMethodState* GetMethodStateForLocal(BfLocalVariable* localVar);
|
|
|
|
bool InMainMixinScope()
|
|
{
|
|
if (mMixinState == NULL)
|
|
return false;
|
|
return mMixinState->mCallerScope == mCurScope->mPrevScope;
|
|
}
|
|
|
|
BfMixinState* GetRootMixinState()
|
|
{
|
|
BfMixinState* mixinState = mMixinState;
|
|
while ((mixinState != NULL) && (mixinState->mPrevMixinState != NULL))
|
|
{
|
|
mixinState = mixinState->mPrevMixinState;
|
|
}
|
|
return mixinState;
|
|
}
|
|
|
|
BfAstNode* GetRootMixinSource()
|
|
{
|
|
BfMixinState* mixinState = NULL;
|
|
auto checkMethodState = this;
|
|
while (checkMethodState != NULL)
|
|
{
|
|
if (checkMethodState->mMixinState != NULL)
|
|
mixinState = checkMethodState->mMixinState;
|
|
|
|
if (checkMethodState->mClosureState != NULL)
|
|
{
|
|
auto activeLocalMethod = checkMethodState->mClosureState->mActiveDeferredLocalMethod;
|
|
if (activeLocalMethod != NULL)
|
|
{
|
|
if (!activeLocalMethod->mMixinStateRecords.IsEmpty())
|
|
return activeLocalMethod->mMixinStateRecords.back().mSource;
|
|
}
|
|
}
|
|
|
|
checkMethodState = checkMethodState->mPrevMethodState;
|
|
}
|
|
|
|
if (mixinState != NULL)
|
|
return mixinState->GetRoot()->mSource;
|
|
return NULL;
|
|
}
|
|
|
|
bool HasMixin()
|
|
{
|
|
auto checkMethodState = this;
|
|
while (checkMethodState != NULL)
|
|
{
|
|
if (checkMethodState->mMixinState != NULL)
|
|
return true;
|
|
checkMethodState = checkMethodState->mPrevMethodState;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool HasNonStaticMixin()
|
|
{
|
|
auto checkMethodState = this;
|
|
while (checkMethodState != NULL)
|
|
{
|
|
if ((checkMethodState->mMixinState != NULL) && (!checkMethodState->mMixinState->mMixinMethodInstance->mMethodDef->mIsStatic))
|
|
return true;
|
|
checkMethodState = checkMethodState->mPrevMethodState;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void LocalDefined(BfLocalVariable* localVar, int fieldIdx = -1, BfLocalVarAssignKind assignKind = BfLocalVarAssignKind_None, bool isFromDeferredAssignData = false);
|
|
void ApplyDeferredLocalAssignData(const BfDeferredLocalAssignData& deferredLocalAssignData);
|
|
void Reset();
|
|
|
|
int GetLocalStartIdx()
|
|
{
|
|
if (mMixinState != NULL)
|
|
return mMixinState->mLocalsStartIdx;
|
|
return 0;
|
|
}
|
|
|
|
bool IsTemporary()
|
|
{
|
|
return mTempKind != TempKind_None;
|
|
}
|
|
};
|
|
|
|
class BfDeferredMethodCallData;
|
|
|
|
enum BfValueFlags
|
|
{
|
|
BfValueFlags_None = 0,
|
|
BfValueFlags_Boxed = 1,
|
|
};
|
|
|
|
enum BfBuiltInFuncType
|
|
{
|
|
BfBuiltInFuncType_PrintF,
|
|
BfBuiltInFuncType_Malloc,
|
|
BfBuiltInFuncType_Free,
|
|
BfBuiltInFuncType_LoadSharedLibraries,
|
|
|
|
BfBuiltInFuncType_Count
|
|
};
|
|
|
|
// These are the options that can be applied to individual methods that cause AltModules
|
|
// to be build, since they are exclusive to an LLVMModule; LLVM optimization-related
|
|
// options always apply to entire LLVM modules
|
|
struct BfModuleOptions
|
|
{
|
|
public:
|
|
BfSIMDSetting mSIMDSetting;
|
|
int mEmitDebugInfo;
|
|
BfOptLevel mOptLevel;
|
|
|
|
bool operator==(const BfModuleOptions& other)
|
|
{
|
|
return (mSIMDSetting == other.mSIMDSetting) &&
|
|
(mEmitDebugInfo == other.mEmitDebugInfo) &&
|
|
(mOptLevel == other.mOptLevel);
|
|
}
|
|
|
|
bool operator!=(const BfModuleOptions& other)
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
BfModuleOptions()
|
|
{
|
|
mSIMDSetting = BfSIMDSetting_None;
|
|
mEmitDebugInfo = false;
|
|
mOptLevel = BfOptLevel_NotSet;
|
|
}
|
|
};
|
|
|
|
struct BfGenericParamSource
|
|
{
|
|
public:
|
|
BfTypeInstance* mTypeInstance;
|
|
BfMethodInstance* mMethodInstance;
|
|
bool mCheckAccessibility;
|
|
|
|
public:
|
|
BfGenericParamSource()
|
|
{
|
|
mTypeInstance = NULL;
|
|
mMethodInstance = NULL;
|
|
mCheckAccessibility = true;
|
|
}
|
|
|
|
BfGenericParamSource(BfTypeInstance* typeInstance)
|
|
{
|
|
mTypeInstance = typeInstance;
|
|
mMethodInstance = NULL;
|
|
mCheckAccessibility = true;
|
|
}
|
|
|
|
BfGenericParamSource(BfMethodInstance* methodInstance)
|
|
{
|
|
mTypeInstance = NULL;
|
|
mMethodInstance = methodInstance;
|
|
mCheckAccessibility = true;
|
|
}
|
|
|
|
BfTypeInstance* GetTypeInstance() const
|
|
{
|
|
if (mTypeInstance != NULL)
|
|
return mTypeInstance;
|
|
if (mMethodInstance != NULL)
|
|
return mMethodInstance->GetOwner();
|
|
return NULL;
|
|
}
|
|
};
|
|
|
|
class BfAmbiguityContext
|
|
{
|
|
public:
|
|
class Entry
|
|
{
|
|
public:
|
|
BfTypeInterfaceEntry* mInterfaceEntry;
|
|
int mMethodIdx;
|
|
Array<BfMethodInstance*> mCandidates;
|
|
};
|
|
|
|
public:
|
|
BfModule* mModule;
|
|
BfTypeInstance* mTypeInstance;
|
|
bool mIsProjectSpecific;
|
|
bool mIsReslotting;
|
|
Dictionary<int, Entry> mEntries;
|
|
|
|
public:
|
|
BfAmbiguityContext()
|
|
{
|
|
mModule = NULL;
|
|
mTypeInstance = NULL;
|
|
mIsProjectSpecific = false;
|
|
mIsReslotting = false;
|
|
}
|
|
void Add(int id, BfTypeInterfaceEntry* ifaceEntry, int methodIdx, BfMethodInstance* candidateA, BfMethodInstance* candidateB);
|
|
void Remove(int id);
|
|
void Finish();
|
|
};
|
|
|
|
enum BfDefaultValueKind
|
|
{
|
|
BfDefaultValueKind_Const,
|
|
BfDefaultValueKind_Value,
|
|
BfDefaultValueKind_Addr,
|
|
BfDefaultValueKind_Undef
|
|
};
|
|
|
|
class BfModuleFileName
|
|
{
|
|
public:
|
|
Array<BfProject*> mProjects;
|
|
String mFileName;
|
|
bool mModuleWritten;
|
|
bool mWroteToLib;
|
|
|
|
bool operator==(const BfModuleFileName& second) const
|
|
{
|
|
return (mProjects == second.mProjects) && (mFileName == second.mFileName);
|
|
}
|
|
};
|
|
|
|
class BfGlobalLookup
|
|
{
|
|
public:
|
|
enum Kind
|
|
{
|
|
Kind_All,
|
|
Kind_Field,
|
|
Kind_Method
|
|
};
|
|
|
|
public:
|
|
Kind mKind;
|
|
String mName;
|
|
};
|
|
|
|
enum BfSrcPosFlags
|
|
{
|
|
BfSrcPosFlag_None = 0,
|
|
BfSrcPosFlag_Expression = 1,
|
|
BfSrcPosFlag_NoSetDebugLoc = 2,
|
|
BfSrcPosFlag_Force = 4
|
|
};
|
|
|
|
enum BfDeferredBlockFlags
|
|
{
|
|
BfDeferredBlockFlag_None = 0,
|
|
BfDeferredBlockFlag_BypassVirtual = 1,
|
|
BfDeferredBlockFlag_DoNullChecks = 2,
|
|
BfDeferredBlockFlag_SkipObjectAccessCheck = 4,
|
|
BfDeferredBlockFlag_MoveNewBlocksToEnd = 8,
|
|
};
|
|
|
|
enum BfGetCustomAttributesFlags
|
|
{
|
|
BfGetCustomAttributesFlags_None = 0,
|
|
BfGetCustomAttributesFlags_AllowNonConstArgs = 1,
|
|
BfGetCustomAttributesFlags_KeepConstsInModule = 2
|
|
};
|
|
|
|
class BfVDataExtEntry
|
|
{
|
|
public:
|
|
BfTypeInstance* mDeclTypeInst;
|
|
BfTypeInstance* mImplTypeInst;
|
|
|
|
bool operator==(const BfVDataExtEntry& rhs)
|
|
{
|
|
return ((mDeclTypeInst == rhs.mDeclTypeInst) && (mImplTypeInst == rhs.mImplTypeInst));
|
|
}
|
|
};
|
|
|
|
#define BFMODULE_FATAL(module, msg) (module)->FatalError((msg), __FILE__, __LINE__)
|
|
|
|
struct BfCEParseContext
|
|
{
|
|
int mFailIdx;
|
|
int mWarnIdx;
|
|
};
|
|
|
|
class BfModule : public BfStructuralVisitor
|
|
{
|
|
public:
|
|
enum RebuildKind
|
|
{
|
|
RebuildKind_None,
|
|
RebuildKind_SkipOnDemandTypes,
|
|
RebuildKind_All
|
|
};
|
|
|
|
public:
|
|
Val128 mDataHash;
|
|
|
|
#ifdef _DEBUG
|
|
StringT<128> mModuleName;
|
|
#else
|
|
String mModuleName;
|
|
#endif
|
|
Array<BfModuleFileName> mOutFileNames;
|
|
// SpecializedModules contain method specializations with types that come from other projects
|
|
Dictionary<Array<BfProject*>, BfModule*> mSpecializedMethodModules;
|
|
BfModule* mParentModule;
|
|
BfModule* mNextAltModule; // Linked
|
|
BfModuleOptions* mModuleOptions; // Only in altModules
|
|
|
|
BfSystem* mSystem;
|
|
BfCompiler* mCompiler;
|
|
BfContext* mContext;
|
|
BfProject* mProject;
|
|
BfIRType mStringLiteralType;
|
|
|
|
BfTypeInstance* mCurTypeInstance;
|
|
Dictionary<BfParserData*, BfFileInstance*> mFileInstanceMap;
|
|
Dictionary<String, BfFileInstance*> mNamedFileInstanceMap;
|
|
Array<BfTypeInstance*> mOwnedTypeInstances;
|
|
|
|
Dictionary<int, BfIRValue> mStringObjectPool;
|
|
Dictionary<int, BfIRValue> mStringCharPtrPool;
|
|
Array<int> mStringPoolRefs;
|
|
HashSet<int> mUnreifiedStringPoolRefs;
|
|
|
|
Array<BfIRBuilder*> mPrevIRBuilders; // Before extensions
|
|
BfIRBuilder* mBfIRBuilder;
|
|
|
|
BfMethodState* mCurMethodState;
|
|
BfAttributeState* mAttributeState;
|
|
BfFilePosition mCurFilePosition;
|
|
BfMethodInstance* mCurMethodInstance;
|
|
BfParentNodeEntry* mParentNodeEntry;
|
|
|
|
BfIRFunction mBuiltInFuncs[BfBuiltInFuncType_Count];
|
|
|
|
Array<BfDllImportEntry> mDllImportEntries;
|
|
Array<int> mImportFileNames;
|
|
Dictionary<BfMethodRef, BfIRValue> mFuncReferences;
|
|
Dictionary<BfFieldRef, BfIRValue> mStaticFieldRefs;
|
|
Dictionary<BfTypeInstance*, BfIRValue> mInterfaceSlotRefs;
|
|
Dictionary<BfTypeInstance*, BfIRValue> mClassVDataRefs;
|
|
Dictionary<BfVDataExtEntry, BfIRValue> mClassVDataExtRefs;
|
|
Dictionary<BfType*, BfIRValue> mTypeDataRefs;
|
|
Dictionary<BfType*, BfIRValue> mDbgRawAllocDataRefs;
|
|
Dictionary<BfMethodInstance*, BfDeferredMethodCallData*> mDeferredMethodCallData;
|
|
HashSet<int64> mDeferredMethodIds;
|
|
HashSet<BfModule*> mModuleRefs;
|
|
|
|
BfIRMDNode mDICompileUnit;
|
|
int mRevision;
|
|
int mRebuildIdx;
|
|
int mLastUsedRevision;
|
|
int mExtensionCount;
|
|
int mIncompleteMethodCount;
|
|
int mOnDemandMethodCount;
|
|
int mLastModuleWrittenRevision;
|
|
int mCurLocalMethodId;
|
|
int16 mUsedSlotCount; // -1 = not used, 0 = awaiting
|
|
bool mAddedToCount;
|
|
bool mHasForceLinkMarker;
|
|
bool mIsReified;
|
|
bool mGeneratesCode;
|
|
bool mReifyQueued;
|
|
bool mWantsIRIgnoreWrites;
|
|
bool mHasGenericMethods;
|
|
bool mIsSpecialModule; // vdata, unspecialized, external
|
|
bool mIsComptimeModule;
|
|
bool mIsScratchModule;
|
|
bool mIsSpecializedMethodModuleRoot;
|
|
bool mIsModuleMutable; // Set to false after writing module to disk, can be set back to true after doing extension module
|
|
bool mWroteToLib;
|
|
bool mHadBuildError;
|
|
bool mHadBuildWarning;
|
|
bool mIgnoreErrors;
|
|
bool mHadIgnoredError;
|
|
bool mIgnoreWarnings;
|
|
bool mSetIllegalSrcPosition;
|
|
bool mReportErrors; // Still puts system in error state when set to false
|
|
bool mIsInsideAutoComplete;
|
|
bool mIsHotModule;
|
|
bool mIsDeleting;
|
|
bool mSkipInnerLookup;
|
|
bool mAwaitingInitFinish;
|
|
bool mAwaitingFinish;
|
|
bool mHasFullDebugInfo;
|
|
bool mNoResolveGenericParams;
|
|
bool mHadHotObjectWrites;
|
|
|
|
public:
|
|
void FatalError(const StringImpl& error, const char* file = NULL, int line = -1, int column = -1);
|
|
void FatalError(const StringImpl& error, BfAstNode* refNode);
|
|
void FatalError(const StringImpl& error, BfFailHandleKind failHandleKind);
|
|
void InternalError(const StringImpl& error, BfAstNode* refNode = NULL, const char* file = NULL, int line = -1);
|
|
void NotImpl(BfAstNode* astNode);
|
|
void AddMethodReference(const BfMethodRef& methodRef, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None);
|
|
bool CheckProtection(BfProtection protection, BfTypeDef* checkType, bool allowProtected, bool allowPrivate);
|
|
void GetAccessAllowed(BfTypeInstance* checkType, bool& allowProtected, bool& allowPrivate);
|
|
bool CheckProtection(BfProtectionCheckFlags& flags, BfTypeInstance* memberOwner, BfProject* memberProject, BfProtection memberProtection, BfTypeInstance* lookupStartType);
|
|
void SetElementType(BfAstNode* astNode, BfSourceElementType elementType);
|
|
void SetHighestElementType(BfAstNode* astNode, BfSourceElementType elementType);
|
|
bool PreFail();
|
|
void SetFail();
|
|
void VerifyOnDemandMethods();
|
|
bool IsSkippingExtraResolveChecks();
|
|
bool AddErrorContext(StringImpl& errorString, BfAstNode* refNode, BfWhileSpecializingFlags& isWhileSpecializing, bool isWarning);
|
|
CeDbgState* GetCeDbgState();
|
|
BfError* Fail(const StringImpl& error, BfAstNode* refNode = NULL, bool isPersistent = false, bool deferError = false);
|
|
BfError* FailInternal(const StringImpl& error, BfAstNode* refNode = NULL);
|
|
BfError* FailAfter(const StringImpl& error, BfAstNode* refNode);
|
|
BfError* Warn(int warningNum, const StringImpl& warning, BfAstNode* refNode = NULL, bool isPersistent = false, bool showInSpecialized = false);
|
|
void CheckErrorAttributes(BfTypeInstance* typeInstance, BfMethodInstance* methodInstance, BfFieldInstance* fieldInstance, BfCustomAttributes* customAttributes, BfAstNode* targetSrc);
|
|
void CheckRangeError(BfType* type, BfAstNode* refNode);
|
|
bool CheckCircularDataError(bool failTypes = true, bool forceFail = false);
|
|
BfFileInstance* GetFileFromNode(BfAstNode* astNode);
|
|
//void UpdateSrcPos(BfAstNode* astNode, bool setDebugLoc = true, int debugLocOffset = 0, bool force = false);
|
|
void UpdateSrcPos(BfAstNode* astNode, BfSrcPosFlags flags = BfSrcPosFlag_None, int debugLocOffset = 0);
|
|
void UseDefaultSrcPos(BfSrcPosFlags flags = BfSrcPosFlag_None, int debugLocOffset = 0);
|
|
void UpdateExprSrcPos(BfAstNode* astNode, BfSrcPosFlags flags = BfSrcPosFlag_None);
|
|
void SetIllegalSrcPos(BfSrcPosFlags flags = BfSrcPosFlag_None);
|
|
void SetIllegalExprSrcPos(BfSrcPosFlags flags = BfSrcPosFlag_None);
|
|
void GetConstClassValueParam(BfIRValue classVData, SizedArrayImpl<BfIRValue>& typeValueParams);
|
|
BfIRValue GetConstValue(int64 val);
|
|
BfIRValue GetConstValue(int64 val, BfType* type);
|
|
BfIRValue GetConstValue8(int val);
|
|
BfIRValue GetConstValue32(int32 val);
|
|
BfIRValue GetConstValue64(int64 val);
|
|
BfIRValue GetDefaultValue(BfType* type);
|
|
BfTypedValue GetFakeTypedValue(BfType* type);
|
|
BfTypedValue GetDefaultTypedValue(BfType* type, bool allowRef = false, BfDefaultValueKind defaultValueKind = BfDefaultValueKind_Const);
|
|
void FixConstValueParams(BfTypeInstance* typeInst, SizedArrayImpl<BfIRValue>& valueParams, bool fillInPadding = false);
|
|
BfIRValue CreateStringObjectValue(const StringImpl& str, int stringId, bool define);
|
|
BfIRValue CreateStringCharPtr(const StringImpl& str, int stringId, bool define);
|
|
bool HasStringId(BfIRValue constantStr, BfIRConstHolder* constHolder = NULL);
|
|
int GetStringPoolIdx(BfIRValue constantStr, BfIRConstHolder* constHolder = NULL);
|
|
String* GetStringPoolString(BfIRValue constantStr, BfIRConstHolder* constHolder = NULL);
|
|
BfIRValue GetStringCharPtr(int stringId, bool force = false);
|
|
BfIRValue GetStringCharPtr(BfIRValue strValue, bool force = false);
|
|
BfIRValue GetStringCharPtr(const StringImpl& str, bool force = false);
|
|
BfIRValue GetStringObjectValue(int idx, bool define, bool force);
|
|
BfIRValue GetStringObjectValue(const StringImpl& str, bool define = false, bool force = false);
|
|
BfIRValue CreateGlobalConstValue(const StringImpl& name, BfIRValue constant, BfIRType type, bool external);
|
|
void DataToString(StringImpl& str, void* ptr, BfType* type);
|
|
void VariantToString(StringImpl& str, const BfVariant& variant, BfType* type = NULL);
|
|
StringT<128> TypeToString(BfType* resolvedType, Array<String>* genericMethodParamNameOverrides = NULL);
|
|
StringT<128> TypeToString(BfType* resolvedType, BfTypeNameFlags typeNameFlags, Array<String>* genericMethodParamNameOverrides = NULL);
|
|
void DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameFlags typeNameFlags = BfTypeNameFlags_None, Array<String>* genericMethodParamNameOverrides = NULL);
|
|
String FieldToString(BfFieldInstance* fieldInstance);
|
|
StringT<128> MethodToString(BfMethodInstance* methodInst, BfMethodNameFlags methodNameFlags = BfMethodNameFlag_ResolveGenericParamNames, BfTypeVector* typeGenericArgs = NULL, BfTypeVector* methodGenericArgs = NULL);
|
|
void pt(BfType* type);
|
|
void pm(BfMethodInstance* type);
|
|
BfIRType CurrentAddToConstHolder(BfIRType irType);
|
|
void CurrentAddToConstHolder(BfIRValue& irVal);
|
|
void ClearConstData();
|
|
bool HasUnactializedConstant(BfConstant* constant, BfIRConstHolder* constHolder);
|
|
BfTypedValue GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType);
|
|
BfIRValue ConstantToCurrent(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType, bool allowUnactualized = false);
|
|
void ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget, bool force = false);
|
|
void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags = BfGetCustomAttributesFlags_None, BfCaptureInfo* captureInfo = NULL);
|
|
BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags = BfGetCustomAttributesFlags_None, BfCaptureInfo* captureInfo = NULL);
|
|
BfCustomAttributes* GetCustomAttributes(BfTypeDef* typeDef);
|
|
void FinishAttributeState(BfAttributeState* attributeState);
|
|
void ProcessTypeInstCustomAttributes(int& packing, bool& isUnion, bool& isCRepr, bool& isOrdered, int& alignOverride, BfType*& underlyingArrayType, int& underlyingArraySize);
|
|
void ProcessCustomAttributeData();
|
|
bool TryGetConstString(BfIRConstHolder* constHolder, BfIRValue irValue, StringImpl& str);
|
|
BfVariant TypedValueToVariant(BfAstNode* refNode, const BfTypedValue& value, bool allowUndef = false);
|
|
|
|
BfTypedValue FlushNullConditional(BfTypedValue result, bool ignoreNullable = false);
|
|
void NewScopeState(bool createLexicalBlock = true, bool flushValueScope = true); // returns prev scope data
|
|
BfIRValue CreateAlloca(BfType* type, bool addLifetime = true, const char* name = NULL, BfIRValue arraySize = BfIRValue());
|
|
BfIRValue CreateAllocaInst(BfTypeInstance* typeInst, bool addLifetime = true, const char* name = NULL);
|
|
BfDeferredCallEntry* AddStackAlloc(BfTypedValue val, BfIRValue arraySize, BfAstNode* refNode, BfScopeData* scope, bool condAlloca = false, bool mayEscape = false, BfIRBlock valBlock = BfIRBlock());
|
|
void RestoreScoreState_LocalVariables(int localVarStart);
|
|
void RestoreScopeState();
|
|
void MarkDynStack(BfScopeData* scope);
|
|
void SaveStackState(BfScopeData* scope);
|
|
BfIRValue ValueScopeStart();
|
|
void ValueScopeEnd(BfIRValue valueScopeStart);
|
|
BfProjectSet* GetVisibleProjectSet();
|
|
bool IsProjectVisible(BfProject* project);
|
|
|
|
void AddBasicBlock(BfIRBlock bb, bool activate = true);
|
|
void VisitEmbeddedStatement(BfAstNode* stmt, BfExprEvaluator* exprEvaluator = NULL, BfEmbeddedStatementFlags flags = BfEmbeddedStatementFlags_None);
|
|
void VisitCodeBlock(BfBlock* block);
|
|
void VisitCodeBlock(BfBlock* block, BfIRBlock continueBlock, BfIRBlock breakBlock, BfIRBlock fallthroughBlock, bool defaultBreak, bool* hadReturn = NULL, BfLabelNode* labelNode = NULL, bool closeScope = false, BfEmbeddedStatementFlags flags = BfEmbeddedStatementFlags_None);
|
|
void DoForLess(BfForEachStatement* forEachStmt);
|
|
|
|
// Util
|
|
void CreateReturn(BfIRValue val);
|
|
void EmitReturn(const BfTypedValue& val);
|
|
void EmitDefaultReturn();
|
|
void EmitDeferredCall(BfModuleMethodInstance moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfDeferredBlockFlags flags = BfDeferredBlockFlag_None);
|
|
bool AddDeferredCallEntry(BfDeferredCallEntry* deferredCallEntry, BfScopeData* scope);
|
|
BfDeferredCallEntry* AddDeferredBlock(BfBlock* block, BfScopeData* scope, Array<BfDeferredCapture>* captures = NULL);
|
|
BfDeferredCallEntry* AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfScopeData* scope, BfAstNode* srcNode = NULL, bool bypassVirtual = false, bool doNullCheck = false);
|
|
void EmitDeferredCall(BfScopeData* scopeData, BfDeferredCallEntry& deferredCallEntry, bool moveBlocks);
|
|
void EmitDeferredCallProcessor(BfScopeData* scopeData, SLIList<BfDeferredCallEntry*>& callEntries, BfIRValue callTail);
|
|
void EmitDeferredCallProcessorInstances(BfScopeData* scopeData);
|
|
bool CanCast(BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags = BfCastFlags_None);
|
|
bool AreSplatsCompatible(BfType* fromType, BfType* toType, bool* outNeedsMemberCasting);
|
|
BfType* GetClosestNumericCastType(const BfTypedValue& typedVal, BfType* wantType);
|
|
BfTypedValue BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType /*Can be System.Object or interface*/, const BfAllocTarget& allocTarget, BfCastFlags castFlags = BfCastFlags_None);
|
|
BfIRValue CastToFunction(BfAstNode* srcNode, const BfTypedValue& targetValue, BfMethodInstance* methodInstance, BfType* toType, BfCastFlags castFlags = BfCastFlags_None, BfIRValue irFunc = BfIRValue());
|
|
BfIRValue CastToValue(BfAstNode* srcNode, BfTypedValue val, BfType* toType, BfCastFlags castFlags = BfCastFlags_None, BfCastResultFlags* resultFlags = NULL);
|
|
BfTypedValue Cast(BfAstNode* srcNode, const BfTypedValue& val, BfType* toType, BfCastFlags castFlags = BfCastFlags_None);
|
|
BfPrimitiveType* GetIntCoercibleType(BfType* type);
|
|
BfTypedValue GetIntCoercible(const BfTypedValue& typedValue);
|
|
bool WantsDebugInfo();
|
|
BfTypeOptions* GetTypeOptions();
|
|
BfReflectKind GetUserReflectKind(BfTypeInstance* attrType);
|
|
BfReflectKind GetReflectKind(BfReflectKind reflectKind, BfTypeInstance* typeInstance);
|
|
void CleanupFileInstances();
|
|
void AssertErrorState();
|
|
void AssertParseErrorState();
|
|
void InitTypeInst(BfTypedValue typedValue, BfScopeData* scope, bool zeroMemory, BfIRValue dataSize, BfAllocFlags allocFlags = BfAllocFlags_None);
|
|
bool IsAllocatorAligned();
|
|
BfIRValue AllocBytes(BfAstNode* refNode, const BfAllocTarget& allocTarget, BfType* type, BfIRValue sizeValue, BfIRValue alignValue, BfAllocFlags allocFlags/*bool zeroMemory, bool defaultToMalloc*/);
|
|
BfIRValue GetMarkFuncPtr(BfType* type);
|
|
BfIRValue GetDbgRawAllocData(BfType* type);
|
|
BfIRValue AllocFromType(BfType* type, const BfAllocTarget& allocTarget, BfIRValue appendSizeValue = BfIRValue(), BfIRValue arraySize = BfIRValue(), int arrayDim = 0, /*bool isRawArrayAlloc = false, bool zeroMemory = true*/BfAllocFlags allocFlags = BfAllocFlags_ZeroMemory, int alignOverride = -1);
|
|
void ValidateAllocation(BfType* type, BfAstNode* refNode);
|
|
bool IsOptimized();
|
|
void EmitAppendAlign(int align, int sizeMultiple = 0);
|
|
BfIRValue AppendAllocFromType(BfType* type, BfIRValue appendSizeValue = BfIRValue(), int appendAllocAlign = 0, BfIRValue arraySize = BfIRValue(), int arrayDim = 0, bool isRawArrayAlloc = false, bool zeroMemory = true);
|
|
bool IsTargetingBeefBackend();
|
|
bool WantsLifetimes();
|
|
bool HasCompiledOutput();
|
|
bool HasExecutedOutput();
|
|
void SkipObjectAccessCheck(BfTypedValue typedVal);
|
|
bool WantsObjectAccessCheck(BfType* type);
|
|
void EmitObjectAccessCheck(BfTypedValue typedVal);
|
|
bool WantsDebugHelpers();
|
|
void EmitEnsureInstructionAt();
|
|
void EmitDynamicCastCheck(const BfTypedValue& targetValue, BfType* targetType, BfIRBlock trueBlock, BfIRBlock falseBlock, bool nullSucceeds = false);
|
|
void EmitDynamicCastCheck(BfTypedValue typedVal, BfType* type, bool allowNull);
|
|
void CheckStaticAccess(BfTypeInstance* typeInstance);
|
|
BfTypedValue RemoveRef(BfTypedValue typedValue, bool makeInReadOnly = true);
|
|
BfTypedValue SanitizeAddr(BfTypedValue typedValue);
|
|
BfTypedValue ToRef(BfTypedValue typedValue, BfRefType* refType = NULL);
|
|
BfTypedValue LoadOrAggregateValue(BfTypedValue typedValue);
|
|
BfTypedValue LoadValue(BfTypedValue typedValue, BfAstNode* refNode = NULL, bool isVolatile = false);
|
|
BfTypedValue PrepareConst(BfTypedValue& typedValue);
|
|
void AggregateSplatIntoAddr(BfTypedValue typedValue, BfIRValue addrVal);
|
|
BfTypedValue AggregateSplat(BfTypedValue typedValue, BfIRValue* valueArrPtr = NULL);
|
|
BfTypedValue MakeAddressable(BfTypedValue typedValue, bool forceMutable = false, bool forceAddressable = false);
|
|
BfTypedValue RemoveReadOnly(BfTypedValue typedValue);
|
|
BfTypedValue CopyValue(const BfTypedValue& typedValue);
|
|
BfIRValue ExtractSplatValue(BfTypedValue typedValue, int componentIdx, BfType* wantType = NULL, bool* isAddr = NULL);
|
|
BfTypedValue ExtractValue(BfTypedValue typedValue, BfFieldInstance* fieldInst, int fieldIdx);
|
|
BfIRValue ExtractValue(BfTypedValue typedValue, int dataIdx);
|
|
BfIRValue CreateIndexedValue(BfType* elementType, BfIRValue value, BfIRValue indexValue, bool isElementIndex = false);
|
|
BfIRValue CreateIndexedValue(BfType* elementType, BfIRValue value, int indexValue, bool isElementIndex = false);
|
|
bool CheckModifyValue(BfTypedValue& typedValue, BfAstNode* refNode, const char* modifyType = NULL);
|
|
BfIRValue GetInterfaceSlotNum(BfTypeInstance* ifaceType);
|
|
void HadSlotCountDependency();
|
|
BfTypedValue GetCompilerFieldValue(const StringImpl& str);
|
|
BfTypedValue GetCompilerFieldValue(const BfTypedValue typedVal);
|
|
BfTypedValue ReferenceStaticField(BfFieldInstance* fieldInstance);
|
|
BfFieldInstance* GetFieldInstance(BfTypeInstance* typeInst, int fieldIdx, const char* fieldName = NULL);
|
|
BfTypedValue GetThis(bool markUsing = true);
|
|
void MarkUsingThis();
|
|
BfLocalVariable* GetThisVariable();
|
|
bool IsInGeneric();
|
|
bool InDefinitionSection();
|
|
bool IsInSpecializedGeneric();
|
|
bool IsInSpecializedSection(); // Either a specialized generic or an injected mixin
|
|
bool IsInUnspecializedGeneric();
|
|
|
|
// BfStmtEvaluator.cpp
|
|
virtual void Visit(BfAstNode* astNode) override;
|
|
virtual void Visit(BfIdentifierNode* identifierNode) override;
|
|
virtual void Visit(BfTypeReference* typeRef) override;
|
|
virtual void Visit(BfEmptyStatement* astNode) override;
|
|
virtual void Visit(BfExpression* expressionStmt) override;
|
|
virtual void Visit(BfExpressionStatement* expressionStmt) override;
|
|
virtual void Visit(BfVariableDeclaration* varDecl) override;
|
|
virtual void Visit(BfLocalMethodDeclaration* methodDecl) override;
|
|
virtual void Visit(BfAttributedStatement* attribStmt) override;
|
|
virtual void Visit(BfThrowStatement* throwStmt) override;
|
|
virtual void Visit(BfDeleteStatement* deleteStmt) override;
|
|
virtual void Visit(BfSwitchStatement* switchStmt) override;
|
|
virtual void Visit(BfTryStatement* tryStmt) override;
|
|
virtual void Visit(BfCatchStatement* catchStmt) override;
|
|
virtual void Visit(BfFinallyStatement* finallyStmt) override;
|
|
virtual void Visit(BfCheckedStatement* checkedStmt) override;
|
|
virtual void Visit(BfUncheckedStatement* uncheckedStmt) override;
|
|
void DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool includeFalseStmt);
|
|
virtual void Visit(BfIfStatement* ifStmt) override;
|
|
virtual void Visit(BfReturnStatement* returnStmt) override;
|
|
virtual void Visit(BfYieldStatement* yieldStmt) override;
|
|
virtual void Visit(BfBreakStatement* breakStmt) override;
|
|
virtual void Visit(BfContinueStatement* continueStmt) override;
|
|
virtual void Visit(BfFallthroughStatement* fallthroughStmt) override;
|
|
virtual void Visit(BfUsingStatement* usingStmt) override;
|
|
virtual void Visit(BfDoStatement* doStmt) override;
|
|
virtual void Visit(BfRepeatStatement* doStmt) override;
|
|
virtual void Visit(BfWhileStatement* whileStmt) override;
|
|
virtual void Visit(BfForStatement* forStmt) override;
|
|
virtual void Visit(BfForEachStatement* forEachStmt) override;
|
|
virtual void Visit(BfDeferStatement* deferStmt) override;
|
|
virtual void Visit(BfBlock* block) override;
|
|
virtual void Visit(BfUnscopedBlock* block) override;
|
|
virtual void Visit(BfLabeledBlock* labeledBlock) override;
|
|
virtual void Visit(BfRootNode* rootNode) override;
|
|
virtual void Visit(BfInlineAsmStatement* asmStmt) override;
|
|
|
|
// Type helpers
|
|
BfGenericExtensionEntry* BuildGenericExtensionInfo(BfTypeInstance* genericTypeInst, BfTypeDef* partialTypeDef);
|
|
bool InitGenericParams(BfType* resolvedTypeRef);
|
|
bool FinishGenericParams(BfType* resolvedTypeRef);
|
|
bool ValidateGenericConstraints(BfAstNode* typeRef, BfTypeInstance* genericTypeInstance, bool ignoreErrors);
|
|
BfType* ResolveGenericMethodTypeRef(BfTypeReference* typeRef, BfMethodInstance* methodInstance, BfGenericParamInstance* genericParamInstance, BfTypeVector* methodGenericArgsOverride);
|
|
bool AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGenericParamInstance* checkOuter);
|
|
bool CheckConstraintState(BfAstNode* refNode);
|
|
void ValidateGenericParams(BfGenericParamKind genericParamKind, Span<BfGenericParamInstance*> genericParams);
|
|
bool ShouldAllowMultipleDefinitions(BfTypeInstance* typeInst, BfTypeDef* firstDeclaringTypeDef, BfTypeDef* secondDeclaringTypeDef);
|
|
void CheckInjectNewRevision(BfTypeInstance* typeInstance);
|
|
void InitType(BfType* resolvedTypeRef, BfPopulateType populateType);
|
|
BfProtection FixProtection(BfProtection protection, BfProject* defProject);
|
|
bool CheckAccessMemberProtection(BfProtection protection, BfTypeInstance* memberType);
|
|
bool CheckDefineMemberProtection(BfProtection protection, BfType* memberType);
|
|
void CheckMemberNames(BfTypeInstance* typeInst);
|
|
void AddDependency(BfType* usedType, BfType* userType, BfDependencyMap::DependencyFlags flags, BfDepContext* depContext = NULL);
|
|
void AddDependency(BfGenericParamInstance* genericParam, BfTypeInstance* usingType);
|
|
void AddCallDependency(BfMethodInstance* methodInstance, bool devirtualized = false);
|
|
void AddFieldDependency(BfTypeInstance* typeInstance, BfFieldInstance* fieldInstance, BfType* fieldType);
|
|
void TypeFailed(BfTypeInstance* typeInstance);
|
|
bool IsAttribute(BfTypeInstance* typeInst);
|
|
void PopulateGlobalContainersList(const BfGlobalLookup& globalLookup);
|
|
BfStaticSearch* GetStaticSearch();
|
|
BfInternalAccessSet* GetInternalAccessSet();
|
|
bool CheckInternalProtection(BfTypeDef* usingTypeDef);
|
|
void AddFailType(BfTypeInstance* typeInstance);
|
|
void DeferRebuildType(BfTypeInstance* typeInstance);
|
|
void MarkDerivedDirty(BfTypeInstance* typeInst);
|
|
void CheckAddFailType();
|
|
void PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType = BfPopulateType_Data);
|
|
BfTypeOptions* GetTypeOptions(BfTypeDef* typeDef);
|
|
bool ApplyTypeOptionMethodFilters(bool includeMethod, BfMethodDef* methodDef, BfTypeOptions* typeOptions);
|
|
int GenerateTypeOptions(BfCustomAttributes* customAttributes, BfTypeInstance* typeInstance, bool checkTypeName);
|
|
void SetTypeOptions(BfTypeInstance* typeInstance);
|
|
BfModuleOptions GetModuleOptions();
|
|
BfCheckedKind GetDefaultCheckedKind();
|
|
void FinishCEParseContext(BfAstNode* refNode, BfTypeInstance* typeInstance, BfCEParseContext* ceParseContext);
|
|
BfCEParseContext CEEmitParse(BfTypeInstance* typeInstance, BfTypeDef* declaringType, const StringImpl& src, BfAstNode* refNode, BfCeTypeEmitSourceKind emitSourceKind);
|
|
void UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfTypeDef* declaringType, const StringImpl& ctxString, BfAstNode* refNode, BfCeTypeEmitSourceKind emitSourceKind);
|
|
void HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfFieldInstance* fieldInstance, BfCustomAttributes* customAttributes, Dictionary<BfTypeInstance*, BfIRValue>& foundAttributes, bool underlyingTypeDeferred);
|
|
void CEMixin(BfAstNode* refNode, const StringImpl& src);
|
|
void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred);
|
|
void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred);
|
|
void DoCEEmit(BfMethodInstance* methodInstance);
|
|
void PopulateUsingFieldData(BfTypeInstance* typeInstance);
|
|
void DoPopulateType_TypeAlias(BfTypeAliasType* typeAlias);
|
|
void DoPopulateType_InitSearches(BfTypeInstance* typeInstance);
|
|
void DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance);
|
|
void DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred, HashContext* dataMemberHashCtx, BfType* unionInnerType);
|
|
void DoPopulateType_CeCheckEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred);
|
|
void DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateType = BfPopulateType_Data);
|
|
static BfModule* GetModuleFor(BfType* type);
|
|
void DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance);
|
|
void RebuildMethods(BfTypeInstance* typeInstance);
|
|
BfFieldInstance* GetFieldByName(BfTypeInstance* typeInstance, const StringImpl& fieldName, bool isRequired = true, BfAstNode* refNode = NULL);
|
|
void CreateStaticField(BfFieldInstance* fieldInstance, bool isThreadLocal = false);
|
|
void ResolveConstField(BfTypeInstance* typeInst, BfFieldInstance* fieldInstance, BfFieldDef* field, bool forceResolve = false);
|
|
BfTypedValue GetFieldInitializerValue(BfFieldInstance* fieldInstance, BfExpression* initializer = NULL, BfFieldDef* fieldDef = NULL, BfType* fieldType = NULL, bool doStore = false);
|
|
bool TryGetAppendedObjectInfo(BfFieldInstance* fieldInstance, int& dataSize, int& alignSize);
|
|
void AppendedObjectInit(BfFieldInstance* fieldInstance);
|
|
void MarkFieldInitialized(BfFieldInstance* fieldInstance);
|
|
bool IsThreadLocal(BfFieldInstance* fieldInstance);
|
|
BfType* ResolveVarFieldType(BfTypeInstance* typeInst, BfFieldInstance* fieldInstance, BfFieldDef* field);
|
|
void FindSubTypes(BfTypeInstance* classType, SizedArrayImpl<int>* outVals, SizedArrayImpl<BfTypeInstance*>* exChecks, bool isInterfacePass);
|
|
BfType* CheckUnspecializedGenericType(BfTypeInstance* genericTypeInst, BfPopulateType populateType);
|
|
BfTypeInstance* GetUnspecializedTypeInstance(BfTypeInstance* typeInst);
|
|
BfArrayType* CreateArrayType(BfType* resolvedType, int dimensions);
|
|
BfSizedArrayType* CreateSizedArrayType(BfType* resolvedType, int size);
|
|
BfUnknownSizedArrayType* CreateUnknownSizedArrayType(BfType* resolvedType, BfType* sizeParam);
|
|
BfPointerType* CreatePointerType(BfType* resolvedType);
|
|
BfPointerType* CreatePointerType(BfTypeReference* typeRef);
|
|
BfConstExprValueType* CreateConstExprValueType(const BfTypedValue& typedValue, bool allowCreate = true);
|
|
BfConstExprValueType* CreateConstExprValueType(const BfVariant& variant, BfType* type, bool allowCreate = true);
|
|
BfBoxedType* CreateBoxedType(BfType* resolvedTypeRef, bool allowCreate = true);
|
|
BfTypeInstance* CreateTupleType(const BfTypeVector& fieldTypes, const Array<String>& fieldNames, bool allowVar = false);
|
|
BfTypeInstance* SantizeTupleType(BfTypeInstance* tupleType);
|
|
BfRefType* CreateRefType(BfType* resolvedTypeRef, BfRefType::RefKind refKind = BfRefType::RefKind_Ref);
|
|
BfModifiedTypeType* CreateModifiedTypeType(BfType* resolvedTypeRef, BfToken modifiedKind);
|
|
BfConcreteInterfaceType* CreateConcreteInterfaceType(BfTypeInstance* interfaceType);
|
|
BfTypeInstance* GetWrappedStructType(BfType* type, bool allowSpecialized = true);
|
|
BfTypeInstance* GetPrimitiveStructType(BfTypeCode typeCode);
|
|
BfPrimitiveType* GetPrimitiveType(BfTypeCode typeCode);
|
|
BfIRType GetIRLoweredType(BfTypeCode loweredTypeCode, BfTypeCode loweredTypeCode2);
|
|
BfMethodRefType* CreateMethodRefType(BfMethodInstance* methodInstance, bool mustAlreadyExist = false);
|
|
BfType* FixIntUnknown(BfType* type);
|
|
void FixIntUnknown(BfTypedValue& typedVal, BfType* matchType = NULL);
|
|
void FixIntUnknown(BfTypedValue& lhs, BfTypedValue& rhs);
|
|
void FixValueActualization(BfTypedValue& typedVal, bool force = false);
|
|
bool TypeEquals(BfTypedValue& val, BfType* type);
|
|
BfTypeDef* ResolveGenericInstanceDef(BfGenericInstanceTypeRef* genericTypeRef, BfType** outType = NULL, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
|
|
BfType* ResolveType(BfType* lookupType, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
|
|
void ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized, Array<BfTypeReference*>* deferredResolveTypes = NULL);
|
|
String GenericParamSourceToString(const BfGenericParamSource& genericParamSource);
|
|
bool CheckGenericConstraints(const BfGenericParamSource& genericParamSource, BfType* checkArgType, BfAstNode* checkArgTypeRef, BfGenericParamInstance* genericParamInst, BfTypeVector* methodGenericArgs = NULL, BfError** errorOut = NULL);
|
|
BfIRValue AllocLocalVariable(BfType* type, const StringImpl& name, bool doLifetimeEnd = true);
|
|
void DoAddLocalVariable(BfLocalVariable* localVar);
|
|
void FixLocalVariable(BfLocalVariable* localVar);
|
|
void DoLocalVariableDebugInfo(BfLocalVariable* localVar, bool doAliasValue = false, BfIRValue declareBefore = BfIRValue(), BfIRInitType initType = BfIRInitType_NotSet);
|
|
BfLocalVariable* AddLocalVariableDef(BfLocalVariable* localVarDef, bool addDebugInfo = false, bool doAliasValue = false, BfIRValue declareBefore = BfIRValue(), BfIRInitType initType = BfIRInitType_NotSet);
|
|
bool TryLocalVariableInit(BfLocalVariable* localVar);
|
|
void LocalVariableDone(BfLocalVariable* localVar, bool isMethodExit);
|
|
void CreateRetValLocal();
|
|
void CreateDIRetVal();
|
|
BfTypedValue CreateTuple(const Array<BfTypedValue>& values, const Array<String>& fieldNames);
|
|
void CheckTupleVariableDeclaration(BfTupleExpression* tupleExpr, BfType* initType);
|
|
void HandleTupleVariableDeclaration(BfVariableDeclaration* varDecl, BfTupleExpression* tupleExpr, BfTypedValue initTupleValue, bool isReadOnly, bool isConst, bool forceAddr, BfIRBlock* declBlock = NULL);
|
|
void HandleTupleVariableDeclaration(BfVariableDeclaration* varDecl);
|
|
void HandleCaseEnumMatch_Tuple(BfTypedValue tupleVal, const BfSizedArray<BfExpression*>& arguments, BfAstNode* tooFewRef, BfIRValue phiVal, BfIRBlock& matchedBlockStart,
|
|
BfIRBlock& matchedBlockEnd, BfIRBlock& falseBlockStart, BfIRBlock& falseBlockEnd, bool& hadConditional, bool clearOutOnMismatch, bool prevHadFallthrough);
|
|
BfTypedValue TryCaseTupleMatch(BfTypedValue tupleVal, BfTupleExpression* tupleExpr, BfIRBlock* eqBlock, BfIRBlock* notEqBlock, BfIRBlock* matchBlock, bool& hadConditional, bool clearOutOnMismatch, bool prevHadFallthrough);
|
|
BfTypedValue TryCaseEnumMatch(BfTypedValue enumVal, BfTypedValue tagVal, BfExpression* expr, BfIRBlock* eqBlock, BfIRBlock* notEqBlock, BfIRBlock* matchBlock, int& uncondTagId, bool& hadConditional, bool clearOutOnMismatch, bool prevHadFallthrough);
|
|
BfTypedValue HandleCaseBind(BfTypedValue enumVal, const BfTypedValue& tagVal, BfEnumCaseBindExpression* bindExpr, BfIRBlock* eqBlock = NULL, BfIRBlock* notEqBlock = NULL, BfIRBlock* matchBlock = NULL, int* outEnumIdx = NULL);
|
|
void TryInitVar(BfAstNode* checkNode, BfLocalVariable* varDecl, BfTypedValue initValue, BfTypedValue& checkResult);
|
|
BfLocalVariable* HandleVariableDeclaration(BfVariableDeclaration* varDecl, BfExprEvaluator* exprEvaluator = NULL);
|
|
BfLocalVariable* HandleVariableDeclaration(BfType* type, BfAstNode* nameNode, BfTypedValue val, bool updateSrcLoc = true, bool forceAddr = false);
|
|
BfLocalVariable* HandleVariableDeclaration(BfVariableDeclaration* varDecl, BfTypedValue val, bool updateSrcLoc = true, bool forceAddr = false);
|
|
void CheckVariableDef(BfLocalVariable* variableDef);
|
|
BfScopeData* FindScope(BfAstNode* scopeName, BfMixinState* curMixinState, bool allowAcrossDeferredBlock);
|
|
BfScopeData* FindScope(BfAstNode* scopeName, bool allowAcrossDeferredBlock);
|
|
BfBreakData* FindBreakData(BfAstNode* scopeName);
|
|
void EmitLifetimeEnds(BfScopeData* scopeData);
|
|
void ClearLifetimeEnds();
|
|
bool HasDeferredScopeCalls(BfScopeData* scope);
|
|
void EmitDeferredScopeCalls(bool useSrcPositions, BfScopeData* scope, BfIRBlock doneBlock = BfIRBlock());
|
|
void MarkScopeLeft(BfScopeData* scopeData, bool isNoReturn = false);
|
|
BfGenericParamType* GetGenericParamType(BfGenericParamKind paramKind, int paramIdx);
|
|
BfType* ResolveGenericType(BfType* unspecializedType, BfTypeVector* typeGenericArguments, BfTypeVector* methodGenericArguments, BfType* selfType, bool allowFail = false);
|
|
BfType* ResolveSelfType(BfType* type, BfType* selfType);
|
|
bool IsUnboundGeneric(BfType* type);
|
|
BfGenericParamInstance* GetGenericTypeParamInstance(int paramIdx, BfFailHandleKind failHandleKind = BfFailHandleKind_Normal);
|
|
BfGenericParamInstance* GetGenericParamInstance(BfGenericParamType* type, bool checkMixinBind = false, BfFailHandleKind failHandleKind = BfFailHandleKind_Normal);
|
|
void GetActiveTypeGenericParamInstances(SizedArray<BfGenericParamInstance*, 4>& genericParamInstance);
|
|
BfGenericParamInstance* GetMergedGenericParamData(BfType* type, BfGenericParamFlags& outFlags, BfType*& outTypeConstraint);
|
|
BfTypeInstance* GetBaseType(BfTypeInstance* typeInst);
|
|
void HandleTypeGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDef, int typeGenericParamIdx);
|
|
void HandleMethodGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDef, BfMethodDef* methodDef, int typeGenericParamIdx);
|
|
BfType* SafeResolveAliasType(BfTypeAliasType* aliasType);
|
|
bool ResolveTypeResult_Validate(BfAstNode* typeRef, BfType* resolvedTypeRef);
|
|
BfType* ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTypeRef, BfPopulateType populateType, BfResolveTypeRefFlags resolveFlags);
|
|
void ShowAmbiguousTypeError(BfAstNode* refNode, BfTypeDef* typeDef, BfTypeDef* otherTypeDef);
|
|
void ShowGenericArgCountError(BfAstNode* typeRef, int wantedGenericParams);
|
|
BfTypeDef* GetActiveTypeDef(BfTypeInstance* typeInstanceOverride = NULL, bool useMixinDecl = false, bool useForeignImpl = false); // useMixinDecl is useful for type lookup, but we don't want the decl project to limit what methods the user can call
|
|
BfTypeDef* FindTypeDefRaw(const BfAtomComposite& findName, int numGenericArgs, BfTypeInstance* typeInstance, BfTypeDef* useTypeDef, BfTypeLookupError* error, BfTypeLookupResultCtx* lookupResultCtx = NULL, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0);
|
|
BfTypeDef* FindTypeDef(const BfAtomComposite& findName, int numGenericArgs = 0, BfTypeInstance* typeInstanceOverride = NULL, BfTypeLookupError* error = NULL, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0);
|
|
BfTypeDef* FindTypeDef(const StringImpl& typeName, int numGenericArgs = 0, BfTypeInstance* typeInstanceOverride = NULL, BfTypeLookupError* error = NULL, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0);
|
|
BfTypeDef* FindTypeDef(BfTypeReference* typeRef, BfTypeInstance* typeInstanceOverride = NULL, BfTypeLookupError* error = NULL, int numGenericParams = 0, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0);
|
|
BfTypedValue TryLookupGenericConstVaue(BfIdentifierNode* identifierNode, BfType* expectingType);
|
|
void CheckTypeRefFixit(BfAstNode* typeRef, const char* appendName = NULL);
|
|
void CheckIdentifierFixit(BfAstNode* node);
|
|
void TypeRefNotFound(BfTypeReference* typeRef, const char* appendName = NULL);
|
|
bool ValidateTypeWildcard(BfAstNode* typeRef, bool isAttributeRef);
|
|
void GetDelegateTypeRefAttributes(BfDelegateTypeRef* delegateTypeRef, BfCallingConvention& callingConvention);
|
|
BfType* ResolveTypeRef_Ref(BfTypeReference* typeRef, BfPopulateType populateType, BfResolveTypeRefFlags& resolveFlags, int numGenericArgs);
|
|
BfType* ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0, int numGenericArgs = 0);
|
|
BfType* ResolveTypeRefAllowUnboundGenerics(BfTypeReference* typeRef, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0, bool resolveGenericParam = true);
|
|
BfType* ResolveTypeRef_Type(BfAstNode* astNode, const BfSizedArray<BfAstNode*>* genericArgs, BfPopulateType populateType, BfResolveTypeRefFlags& resolveFlags);
|
|
BfType* ResolveTypeRef_Ref(BfAstNode* astNode, const BfSizedArray<BfAstNode*>* genericArgs, BfPopulateType populateType, BfResolveTypeRefFlags& resolveFlags);
|
|
BfType* ResolveTypeRef_Ref(BfAstNode* astNode, BfPopulateType populateType);
|
|
BfType* ResolveTypeRef(BfAstNode* astNode, const BfSizedArray<BfAstNode*>* genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0);
|
|
|
|
BfType* ResolveTypeDef(BfTypeDef* typeDef, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
|
|
BfType* ResolveTypeDef(BfTypeDef* typeDef, const BfTypeVector& genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
|
|
BfType* ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopulateType populateType = BfPopulateType_Data, bool ignoreErrors = false, int numGenericArgs = 0, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
|
|
BfTypeDef* GetCombinedPartialTypeDef(BfTypeDef* type);
|
|
BfTypeInstance* GetOuterType(BfType* type);
|
|
bool IsInnerType(BfType* checkInnerType, BfType* checkOuterType);
|
|
bool IsInnerType(BfTypeDef* checkInnerType, BfTypeDef* checkOuterType);
|
|
bool TypeHasParentOrEquals(BfTypeDef* checkChildTypeDef, BfTypeDef* checkParentTypeDef);
|
|
BfTypeDef* FindCommonOuterType(BfTypeDef* type, BfTypeDef* type2);
|
|
bool TypeIsSubTypeOf(BfTypeInstance* srcType, BfTypeInstance* wantType, bool checkAccessibility = true);
|
|
bool TypeIsSubTypeOf(BfTypeInstance* srcType, BfTypeDef* wantType);
|
|
int GetTypeDistance(BfType* fromType, BfType* toType);
|
|
bool IsTypeMoreSpecific(BfType* leftType, BfType* rightType);
|
|
bool GetBasePropertyDef(BfPropertyDef*& propDef, BfTypeInstance*& typeInst);
|
|
|
|
// Method helpers
|
|
void CheckInterfaceMethod(BfMethodInstance* methodInstance);
|
|
void CreateDelegateInvokeMethod();
|
|
BfType* GetDelegateReturnType(BfType* delegateType);
|
|
BfMethodInstance* GetDelegateInvokeMethod(BfTypeInstance* typeInstance);
|
|
String GetLocalMethodName(const StringImpl& baseName, BfAstNode* anchorNode, BfMethodState* declMethodState, BfMixinState* declMixinState);
|
|
BfMethodDef* GetLocalMethodDef(BfLocalMethod* localMethod);
|
|
BfModuleMethodInstance GetLocalMethodInstance(BfLocalMethod* localMethod, const BfTypeVector& methodGenericArguments, BfMethodInstance* methodInstance = NULL, bool force = false);
|
|
int GetLocalInferrableGenericArgCount(BfMethodDef* methodDef);
|
|
void GetMethodCustomAttributes(BfMethodInstance* methodInstance);
|
|
void SetupIRFunction(BfMethodInstance* methodInstance, StringImpl& mangledName, bool isTemporaryFunc, bool* outIsIntrinsic);
|
|
void CheckHotMethod(BfMethodInstance* methodInstance, const StringImpl& mangledName);
|
|
void StartMethodDeclaration(BfMethodInstance* methodInstance, BfMethodState* prevMethodState);
|
|
void DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool isTemporaryFunc, bool addToWorkList = true);
|
|
void AddMethodToWorkList(BfMethodInstance* methodInstance);
|
|
bool IsInterestedInMethod(BfTypeInstance* typeInstance, BfMethodDef* methodDef);
|
|
void CalcAppendAlign(BfMethodInstance* methodInst);
|
|
BfAllowAppendKind GetBaseAllowAppend(BfMethodInstance* curMethodInstance);
|
|
BfTypedValue TryConstCalcAppend(BfMethodInstance* methodInst, SizedArrayImpl<BfIRValue>& args, bool force = false);
|
|
BfTypedValue CallBaseCtorCalc(bool constOnly);
|
|
void EmitCtorCalcAppend();
|
|
void CreateStaticCtor();
|
|
BfIRValue CreateDllImportGlobalVar(BfMethodInstance* methodInstance, bool define = false);
|
|
void CreateDllImportMethod();
|
|
BfIRCallingConv GetIRCallingConvention(BfMethodInstance* methodInstance);
|
|
void SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func, bool isInlined);
|
|
void EmitInitBlocks(const std::function<void(BfAstNode*)>& initBlockCallback);
|
|
void EmitCtorBody(bool& skipBody);
|
|
void EmitDtorBody();
|
|
void EmitEnumToStringBody();
|
|
void EmitTupleToStringBody();
|
|
void EmitGCMarkAppended(BfTypedValue markVal);
|
|
void EmitGCMarkValue(BfTypedValue& thisValue, BfType* checkType, int memberDepth, int curOffset, HashSet<int>& objectOffsets, BfModuleMethodInstance markFromGCThreadMethodInstance, bool isAppendObject = false);
|
|
void EmitGCMarkValue(BfTypedValue markVal, BfModuleMethodInstance markFromGCThreadMethodInstance);
|
|
void EmitGCMarkMembers();
|
|
void EmitGCFindTLSMembers();
|
|
void EmitIteratorBlock(bool& skipBody);
|
|
void EmitEquals(BfTypedValue leftValue, BfTypedValue rightValue, BfIRBlock exitBB, bool strictEquals);
|
|
void CreateFakeCallerMethod(const String& funcName);
|
|
void CallChainedMethods(BfMethodInstance* methodInstance, bool reverse = false);
|
|
void AddHotDataReferences(BfHotDataReferenceBuilder* builder);
|
|
void ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfType* thisType, bool wantsDIData, SizedArrayImpl<BfIRMDNode>* diParams);
|
|
void ProcessMethod_ProcessDeferredLocals(int startIdx = 0);
|
|
void ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup = false, bool forceIRWrites = false);
|
|
void CreateDynamicCastMethod();
|
|
void CreateDelegateEqualsMethod();
|
|
void CreateValueTypeEqualsMethod(bool strictEquals);
|
|
BfIRFunction GetIntrinsic(BfMethodInstance* methodInstance, bool reportFailure = false);
|
|
BfIRFunction GetBuiltInFunc(BfBuiltInFuncType funcType);
|
|
BfIRValue CreateFunctionFrom(BfMethodInstance* methodInstance, bool tryExisting, bool isInlined);
|
|
void EvaluateWithNewConditionalScope(BfExprEvaluator& exprEvaluator, BfExpression* expr, BfEvalExprFlags flags);
|
|
BfTypedValue CreateValueFromExpression(BfExprEvaluator& exprEvaluator, BfExpression* expr, BfType* wantTypeRef = NULL, BfEvalExprFlags flags = BfEvalExprFlags_None, BfType** outOrigType = NULL);
|
|
BfTypedValue CreateValueFromExpression(BfExpression* expr, BfType* wantTypeRef = NULL, BfEvalExprFlags flags = BfEvalExprFlags_None, BfType** outOrigType = NULL);
|
|
BfTypedValue GetOrCreateVarAddr(BfExpression* expr);
|
|
BfMethodInstance* GetRawMethodInstanceAtIdx(BfTypeInstance* typeInstance, int methodIdx, const char* assertName = NULL);
|
|
BfMethodInstance* GetRawMethodInstance(BfTypeInstance* typeInstance, BfMethodDef* methodDef);
|
|
BfMethodInstance* GetRawMethodByName(BfTypeInstance* typeInstance, const StringImpl& methodName, int paramCount = -1, bool checkBase = false, bool allowMixin = false);
|
|
BfMethodInstance* GetUnspecializedMethodInstance(BfMethodInstance* methodInstance, bool useUnspecializedType = true); // Unspecialized owner type and unspecialized method type
|
|
int GetGenericParamAndReturnCount(BfMethodInstance* methodInstance);
|
|
BfModule* GetSpecializedMethodModule(const SizedArrayImpl<BfProject*>& projectList);
|
|
BfModuleMethodInstance GetMethodInstanceAtIdx(BfTypeInstance* typeInstance, int methodIdx, const char* assertName = NULL, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None);
|
|
BfModuleMethodInstance GetMethodByName(BfTypeInstance* typeInstance, const StringImpl& methodName, int paramCount = -1, bool checkBase = false);
|
|
BfModuleMethodInstance GetMethodByName(BfTypeInstance* typeInstance, const StringImpl& methodName, const Array<BfType*>& paramTypes, bool checkBase = false);
|
|
BfModuleMethodInstance GetInternalMethod(const StringImpl& methodName, int paramCount = -1);
|
|
BfOperatorInfo* GetOperatorInfo(BfTypeInstance* typeInstance, BfOperatorDef* operatorDef);
|
|
BfType* CheckOperator(BfTypeInstance* typeInstance, BfOperatorDef* operatorDef, const BfTypedValue& lhs, const BfTypedValue& rhs);
|
|
bool IsMethodImplementedAndReified(BfTypeInstance* typeInstance, const StringImpl& methodName, int paramCount = -1, bool checkBase = false);
|
|
bool HasMixin(BfTypeInstance* typeInstance, const StringImpl& methodName, int paramCount, bool checkBase = false);
|
|
bool CompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstance* methodB); // Doesn't compare return types nor static
|
|
bool StrictCompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstance* methodB); // Compares return types and static
|
|
bool IsCompatibleInterfaceMethod(BfMethodInstance* methodA, BfMethodInstance* methodB);
|
|
void UniqueSlotVirtualMethod(BfMethodInstance* methodInstance);
|
|
void CompareDeclTypes(BfTypeInstance* typeInst, BfTypeDef* newDeclType, BfTypeDef* prevDeclType, bool& isBetter, bool& isWorse);
|
|
bool SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityContext* ambiguityContext = NULL);
|
|
void CheckOverridenMethod(BfMethodInstance* methodInstance, BfMethodInstance* methodOverriden);
|
|
bool SlotInterfaceMethod(BfMethodInstance* methodInstance);
|
|
void SetMethodDependency(BfMethodInstance* methodInstance);
|
|
BfModuleMethodInstance ReferenceExternalMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None);
|
|
BfModule* GetOrCreateMethodModule(BfMethodInstance* methodInstance);
|
|
BfModuleMethodInstance GetMethodInstance(BfTypeInstance* typeInst, BfMethodDef* methodDef, const BfTypeVector& methodGenericArguments, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None, BfTypeInstance* foreignType = NULL, BfModule* referencingModule = NULL);
|
|
BfModuleMethodInstance GetMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None);
|
|
BfMethodInstance* GetOuterMethodInstance(BfMethodInstance* methodInstance); // Only useful for local methods
|
|
void SetupMethodIdHash(BfMethodInstance* methodInstance);
|
|
bool CheckUseMethodInstance(BfMethodInstance* methodInstance, BfAstNode* refNode);
|
|
|
|
// Type Data
|
|
BfIRValue CreateClassVDataGlobal(BfTypeInstance* typeInstance, int* outNumElements = NULL, String* outMangledName = NULL);
|
|
BfIRValue GetClassVDataPtr(BfTypeInstance* typeInstance);
|
|
BfIRValue CreateClassVDataExtGlobal(BfTypeInstance* declTypeInst, BfTypeInstance* implTypeInst, int startVirtIdx);
|
|
BfIRValue CreateTypeDataRef(BfType* type, bool forceConstant = false);
|
|
void EncodeAttributeData(BfTypeInstance* typeInstance, BfType* argType, BfIRValue arg, SizedArrayImpl<uint8>& data, Dictionary<int, int>& usedStringIdMap);
|
|
BfIRValue CreateFieldData(BfFieldInstance* fieldInstance, int customAttrIdx);
|
|
void CreateSlotOfs(BfTypeInstance* typeInstance);
|
|
BfIRValue GetTypeTypeData(BfType* type, BfCreateTypeDataContext& ctx, bool needsTypeData, bool wantsTypeDecl, bool needsTypeNames, int& typeFlags, int& typeCode);
|
|
BfIRValue CreateTypeDeclData(BfType* type, BfProject* curProject);
|
|
BfIRValue CreateTypeData(BfType* type, BfCreateTypeDataContext& ctx, bool forceReflectFields, bool needsTypeData, bool needsTypeNames, bool needsVData);
|
|
BfIRValue FixClassVData(BfIRValue value);
|
|
|
|
public:
|
|
BfModule(BfContext* context, const StringImpl& moduleName);
|
|
virtual ~BfModule();
|
|
|
|
void Init(bool isFullRebuild = true);
|
|
bool WantsFinishModule();
|
|
bool IsHotCompile();
|
|
void FinishInit();
|
|
void CalcGeneratesCode();
|
|
void ReifyModule();
|
|
void UnreifyModule();
|
|
void Cleanup();
|
|
void StartNewRevision(RebuildKind rebuildKind = RebuildKind_All, bool force = false);
|
|
void PrepareForIRWriting(BfTypeInstance* typeInst);
|
|
void SetupIRBuilder(bool dbgVerifyCodeGen);
|
|
void EnsureIRBuilder(bool dbgVerifyCodeGen = false);
|
|
void DbgFinish();
|
|
BfIRValue CreateForceLinkMarker(BfModule* module, String* outName);
|
|
void ClearModuleData(bool clearTransientData = true);
|
|
void DisownMethods();
|
|
void ClearModule();
|
|
void StartExtension(); // For new method specializations
|
|
bool Finish();
|
|
void RemoveModuleData();
|
|
|
|
void ReportMemory(MemReporter* memReporter);
|
|
};
|
|
|
|
class BfAutoParentNodeEntry
|
|
{
|
|
public:
|
|
BfModule* mModule;
|
|
BfParentNodeEntry mParentNodeEntry;
|
|
BfAutoParentNodeEntry(BfModule* module, BfAstNode* node)
|
|
{
|
|
mModule = module;
|
|
mParentNodeEntry.mNode = node;
|
|
mParentNodeEntry.mPrev = module->mParentNodeEntry;
|
|
module->mParentNodeEntry = &mParentNodeEntry;
|
|
}
|
|
~BfAutoParentNodeEntry()
|
|
{
|
|
mModule->mParentNodeEntry = mParentNodeEntry.mPrev;
|
|
}
|
|
};
|
|
|
|
class BfVDataModule : public BfModule
|
|
{
|
|
public:
|
|
HashSet<int> mDefinedStrings;
|
|
|
|
public:
|
|
BfVDataModule(BfContext* context) : BfModule(context, StringImpl::MakeRef("vdata"))
|
|
{
|
|
}
|
|
};
|
|
|
|
NS_BF_END
|
|
|
|
namespace std
|
|
{
|
|
template<>
|
|
struct hash<Beefy::BfMethodRef>
|
|
{
|
|
size_t operator()(const Beefy::BfMethodRef& val) const
|
|
{
|
|
if (val.mTypeInstance == NULL)
|
|
return 0;
|
|
return val.mTypeInstance->mTypeId ^ (val.mMethodNum << 10);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct hash<Beefy::BfVDataExtEntry>
|
|
{
|
|
size_t operator()(const Beefy::BfVDataExtEntry& val) const
|
|
{
|
|
return ((size_t)(val.mDeclTypeInst) * 17) ^ (size_t)(val.mDeclTypeInst);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct hash<Beefy::BfLocalVarEntry>
|
|
{
|
|
size_t operator()(const Beefy::BfLocalVarEntry& val) const
|
|
{
|
|
return std::hash<Beefy::String>()(val.mLocalVar->mName);
|
|
}
|
|
};
|
|
}
|