#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 "BfSourceClassifier.h" #include "BfAst.h" #include "BfSystem.h" #include "BfIRBuilder.h" #include "BfResolvedTypeUtils.h" #include "BfUtil.h" #include #include #pragma warning(pop) NS_BF_BEGIN class BfType; class BfResolvedType; class BfExprEvaluator; enum BfPopulateType { BfPopulateType_TypeDef, BfPopulateType_Identity, BfPopulateType_IdentityNoRemapAlias, BfPopulateType_Declaration, BfPopulateType_BaseType, BfPopulateType_Interfaces, BfPopulateType_Data, BfPopulateType_DataAndMethods, BfPopulateType_Full = BfPopulateType_DataAndMethods , BfPopulateType_Full_Force }; enum BfEvalExprFlags { 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 }; enum BfCastFlags { BfCastFlags_None = 0, BfCastFlags_Explicit = 1, BfCastFlags_Unchecked = 2, BfCastFlags_Internal = 4, BfCastFlags_SilentFail = 8, BfCastFlags_NoBox = 0x10, BfCastFlags_NoBoxDtor = 0x20, BfCastFlags_NoConversionOperator = 0x40, BfCastFlags_FromCompiler = 0x80, // Not user specified BfCastFlags_Force = 0x100, BfCastFlags_PreferAddr = 0x200, BfCastFlags_WarnOnBox = 0x400, BfCastFlags_IsCastCheck = 0x800, BfCastFlags_IsConstraintCheck = 0x1000 }; enum BfCastResultFlags { BfCastResultFlags_None = 0, BfCastResultFlags_IsAddr = 1, BfCastResultFlags_IsTemp = 2 }; enum BfAllocFlags { BfAllocFlags_None = 0, BfAllocFlags_RawArray = 1, BfAllocFlags_ZeroMemory = 2, BfAllocFlags_NoDtorCall = 4, BfAllocFlags_NoDefaultToMalloc = 8 }; enum BfProtectionCheckFlags { BfProtectionCheckFlag_None = 0, BfProtectionCheckFlag_CheckedProtected = 1, BfProtectionCheckFlag_CheckedPrivate = 2, BfProtectionCheckFlag_AllowProtected = 4, BfProtectionCheckFlag_AllowPrivate = 8, }; enum BfEmbeddedStatementFlags { BfEmbeddedStatementFlags_None = 0, BfEmbeddedStatementFlags_IsConditional = 1, BfEmbeddedStatementFlags_IsDeferredBlock = 2 }; enum BfLocalVarAssignKind { BfLocalVarAssignKind_None = 0, BfLocalVarAssignKind_Conditional = 1, BfLocalVarAssignKind_Unconditional = 2 }; 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; bool mIsThis; bool mHasLocalStructBacking; bool mIsStruct; bool mIsImplicitParam; bool mParamFailed; BfLocalVarAssignKind mAssignedKind; bool mHadExitBeforeAssign; bool mIsReadOnly; bool mIsSplat; bool mIsLowered; bool mAllowAddr; bool mIsShadow; bool mUsedImplicitly; // Passed implicitly to a local method, capture by ref if we can bool mNotCaptured; BfLocalVariable* mShadowedLocal; public: BfLocalVariable() { mUnassignedFieldFlags = 0; mResolvedType = NULL; mNameNode = NULL; mLocalVarIdx = -1; mLocalVarId = -1; mCompositeCount = -1; mParamIdx = -2; mIsThis = false; mHasLocalStructBacking = false; mIsStruct = false; mIsImplicitParam = false; mParamFailed = false; mAssignedKind = BfLocalVarAssignKind_None; mHadExitBeforeAssign = false; mWrittenToId = -1; mReadFromId = -1; mIsReadOnly = false; mIsSplat = false; mIsLowered = false; mAllowAddr = false; mIsShadow = false; mUsedImplicitly = false; mNotCaptured = 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 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(); }; class BfDeferredCapture { public: String mName; BfTypedValue mValue; }; class BfDeferredCallEntry { public: BfDeferredCallEntry* mNext; BfAstNode* mSrcNode; BfTypedValue mTarget; BfModuleMethodInstance mModuleMethodInstance; BfIRValue mDeferredAlloca; SizedArray mScopeArgs; Array mCaptures; BfBlock* mDeferredBlock; int64 mBlockId; int mHandlerCount; bool mBypassVirtual; bool mDoNullCheck; bool mCastThis; bool mArgsNeedLoad; bool mIgnored; SLIList mDynList; BfIRValue mDynCallTail; public: BfDeferredCallEntry() { mBypassVirtual = false; mDoNullCheck = false; mNext = NULL; mSrcNode = NULL; mDeferredBlock = 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 mAssignedLocals; bool mIsChained; BfDeferredLocalAssignData* mChainedAssignData; bool mHadFallthrough; bool mHadReturn; bool mIsUnconditional; bool mIsIfCondition; bool mIfMayBeSkipped; bool mLeftBlock; public: BfDeferredLocalAssignData(BfScopeData* scopeData = NULL) { mScopeData = scopeData; mVarIdBarrier = -1; mHadFallthrough = false; mHadReturn = false; mChainedAssignData = NULL; mIsChained = false; mIsUnconditional = false; mIsIfCondition = false; mIfMayBeSkipped = false; mLeftBlock = 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, }; // "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; BfBlock* mAstBlock; BfAstNode* mCloseNode; BfExprEvaluator* mExprEvaluator; SLIList mDeferredCallEntries; BfIRValue mBlock; BfIRValue mValueScopeStart; BfIRValue mSavedStack; Array mSavedStackUses; Array mDeferredHandlers; // These get cleared when us our a parent gets new entries added into mDeferredCallEntries Array mAtEndBlocks; // Move these to the end after we close scope Array mDeferredLifetimeEnds; BfDeferredLocalAssignData* mExitLocalAssignData; BfIRMDNode mAltDIFile; BfIRMDNode mAltDIScope; public: BfScopeData() { mScopeKind = BfScopeKind_Normal; mPrevScope = NULL; mLocalVarStart = 0; mLabelNode = NULL; mAstBlock = NULL; mCloseNode = NULL; mExprEvaluator = NULL; mIsScopeHead = false; mIsLoop = false; mIsConditional = false; mOuterIsConditional = false; mInnerIsConditional = false; mHadOuterDynStack = false; mHadScopeValueRetain = false; mIsDeferredBlock = false; mAllowTargeting = true; mAllowVariableDeclarations = true; 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; } }; struct BfCaptureInfo { public: struct Entry { BfCaptureType mCaptureType; bool mUsed; BfIdentifierNode* mNameNode; Entry() { mCaptureType = BfCaptureType_Copy; mUsed = false; mNameNode = NULL; } }; public: Array 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; } 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 mLocalMethods; // Local methods that were in scope at the time Array mConstLocals; Array mMixinStateRecords; }; 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; BfLocalMethod* mLocalMethod; BfClosureInstanceInfo* mClosureInstanceInfo; BfMethodDef* mClosureMethodDef; BfType* mReturnType; BfTypeInstance* mClosureType; BfDeferredLocalMethod* mActiveDeferredLocalMethod; Array mConstLocals; // Locals not inserted into the captured 'this' HashSet mReferencedOuterClosureMembers; HashSet mLocalMethodRefSet; Array mLocalMethodRefs; Array mDeferredProcessLocalMethods; public: BfClosureState() { mClosureMethodDef = NULL; mLocalMethod = NULL; mClosureInstanceInfo = NULL; mCapturing = false; mCaptureVisitingBody = false; mCaptureStartAccessId = -1; mBlindCapturing = false; mDeclaringMethodIsMutating = false; mActiveDeferredLocalMethod = NULL; mReturnType = NULL; mClosureType = NULL; } }; class BfIteratorClassState { public: BfTypeInstance* mIteratorClass; bool mCapturing; public: BfIteratorClassState() { mCapturing = false; } }; class BfPendingNullConditional { public: BfIRBlock mPrevBB; BfIRBlock mCheckBB; BfIRBlock mDoneBB; SizedArray 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 BfMethodInstance* mMixinMethodInstance; BfAstNode* mResultExpr; int mLocalsStartIdx; bool mUsedInvocationScope; bool mHasDeferredUsage; BfTypedValue mTarget; int mLastTargetAccessId; public: BfMixinState() { 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& val) const { return (val.first.mId << 4) + val.second; } }; struct BfSplatDecompEquals { bool operator()(const std::pair& lhs, const std::pair& 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; BfConstResolveState() { mMethodInstance = NULL; mPrevConstResolveState = NULL; } }; 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 mCaptures; BfMethodInstance* mMethodInstance; BfMethodInstance* mDtorMethodInstance; Array mConstLocals; OwnedVector mParamDecls; public: BfLambdaInstance() { mDelegateTypeInstance = NULL; mUseTypeInstance = NULL; mClosureTypeInstance = NULL; mDeclMixinState = NULL; mOuterClosure = NULL; mCopyOuterCaptures = false; mDeclaringMethodIsMutating = false; mIsStatic = false; mMethodInstance = NULL; mDtorMethodInstance = NULL; } ~BfLambdaInstance() { delete mMethodInstance->mMethodDef; delete mMethodInstance; if (mDtorMethodInstance != NULL) { delete mDtorMethodInstance->mMethodDef; delete mDtorMethodInstance; } } }; 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; BfIRFunction mIRFunction; BfIRBlock mIRHeadBlock; BfIRBlock mIRInitBlock; BfIRBlock mIREntryBlock; Array > mLocals; HashSet > mLocalVarSet; Array mLocalMethods; Dictionary mLocalMethodMap; Dictionary mLocalMethodCache; // So any lambda 'capturing' and 'processing' stages use the same local method Array mDeferredLocalMethods; OwnedVector mMixinStates; Dictionary mLambdaCache; Array mDeferredLambdaInstances; Array mSplatDecompAddrs; BfDeferredLocalAssignData* mDeferredLocalAssignData; BfProjectSet mVisibleProjectSet; int mDeferredLoopListCount; int mDeferredLoopListEntryCount; HashSet mSkipObjectAccessChecks; // Indexed by BfIRValue value id Dictionary* 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; 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 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; mLocals.Reserve(8); mLocalVarSet.mAlloc = &mBumpAlloc; mLocalVarSet.Reserve(8); mMethodInstance = NULL; mPrevMethodState = NULL; mConstResolveState = NULL; mHotDataReferenceBuilder = NULL; mHeadScope.mIsScopeHead = true; mCurScope = &mHeadScope; mTailScope = &mHeadScope; 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; 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; 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); } }; 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 mCandidates; }; public: BfModule* mModule; BfTypeInstance* mTypeInstance; bool mIsProjectSpecific; bool mIsReslotting; Dictionary 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 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, }; 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__) 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 mOutFileNames; // SpecializedModules contain method specializations with types that come from other projects Dictionary, 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 mFileInstanceMap; Dictionary mNamedFileInstanceMap; Array mOwnedTypeInstances; Dictionary mStringObjectPool; Dictionary mStringCharPtrPool; Array mStringPoolRefs; Array mPrevIRBuilders; // Before extensions BfIRBuilder* mBfIRBuilder; BfMethodState* mCurMethodState; BfAttributeState* mAttributeState; BfFilePosition mCurFilePosition; BfMethodInstance* mCurMethodInstance; BfParentNodeEntry* mParentNodeEntry; BfIRFunction mBuiltInFuncs[BfBuiltInFuncType_Count]; Array mDllImportEntries; Array mImportFileNames; Dictionary mFuncReferences; Dictionary mStaticFieldRefs; Dictionary mInterfaceSlotRefs; Dictionary mClassVDataRefs; Dictionary mClassVDataExtRefs; Dictionary mTypeDataRefs; Dictionary mDbgRawAllocDataRefs; Dictionary mDeferredMethodCallData; HashSet mDeferredMethodIds; HashSet 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 mReifyQueued; bool mWantsIRIgnoreWrites; bool mHasGenericMethods; bool mIsSpecialModule; // vdata, unspecialized, external 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 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); 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 SetFail(); BfError* Fail(const StringImpl& error, BfAstNode* refNode = NULL, bool isPersistent = 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); void CheckErrorAttributes(BfTypeInstance* typeInstance, BfMethodInstance* methodInstance, BfCustomAttributes* customAttributes, BfAstNode* targetSrc); void CheckRangeError(BfType* type, BfAstNode* refNode); bool CheckCircularDataError(); 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& 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); BfIRValue CreateStringObjectValue(const StringImpl& str, int stringId, bool define); BfIRValue CreateStringCharPtr(const StringImpl& str, int stringId, bool define); int GetStringPoolIdx(BfIRValue constantStr, BfIRConstHolder* constHolder = NULL); String* GetStringPoolString(BfIRValue constantStr, BfIRConstHolder* constHolder = NULL); BfIRValue GetStringCharPtr(int stringId); BfIRValue GetStringCharPtr(BfIRValue strValue); BfIRValue GetStringCharPtr(const StringImpl& str); BfIRValue GetStringObjectValue(int idx); BfIRValue GetStringObjectValue(const StringImpl& str, bool define = false); BfIRValue CreateGlobalConstValue(const StringImpl& name, BfIRValue constant, BfIRType type, bool external); void VariantToString(StringImpl& str, const BfVariant& variant); StringT<128> TypeToString(BfType* resolvedType, Array* genericMethodParamNameOverrides = NULL); StringT<128> TypeToString(BfType* resolvedType, BfTypeNameFlags typeNameFlags, Array* genericMethodParamNameOverrides = NULL); void DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameFlags typeNameFlags = BfTypeNameFlags_None, Array* genericMethodParamNameOverrides = NULL); StringT<128> MethodToString(BfMethodInstance* methodInst, BfMethodNameFlags methodNameFlags = BfMethodNameFlag_ResolveGenericParamNames, BfTypeVector* methodGenericArgs = NULL); void pv(BfType* type); void CurrentAddToConstHolder(BfIRValue& irVal); void ClearConstData(); BfTypedValue GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType); BfIRValue ConstantToCurrent(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType); void ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget); void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL); BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL); void FinishAttributeState(BfAttributeState* attributeState); void ProcessTypeInstCustomAttributes(bool& isPacked, 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); void AddStackAlloc(BfTypedValue val, BfIRValue arraySize, BfAstNode* refNode, BfScopeData* scope, bool condAlloca = false, bool mayEscape = false); void RestoreScoreState_LocalVariables(); void RestoreScopeState(); void MarkDynStack(BfScopeData* scope); void SaveStackState(BfScopeData* scope); BfIRValue ValueScopeStart(); void ValueScopeEnd(BfIRValue valueScopeStart); BfProjectSet* GetVisibleProjectSet(); 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); void DoForLess(BfForEachStatement* forEachStmt); // Util void CreateReturn(BfIRValue val); void EmitReturn(BfIRValue val); void EmitDefaultReturn(); void EmitDeferredCall(BfModuleMethodInstance moduleMethodInstance, SizedArrayImpl& llvmArgs, BfDeferredBlockFlags flags = BfDeferredBlockFlag_None); bool AddDeferredCallEntry(BfDeferredCallEntry* deferredCallEntry, BfScopeData* scope); void AddDeferredBlock(BfBlock* block, BfScopeData* scope, Array* captures = NULL); BfDeferredCallEntry* AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl& llvmArgs, BfScopeData* scope, BfAstNode* srcNode = NULL, bool bypassVirtual = false, bool doNullCheck = false); void EmitDeferredCall(BfDeferredCallEntry& deferredCallEntry, bool moveBlocks); void EmitDeferredCallProcessor(SLIList& callEntries, BfIRValue callTail); bool CanCast(BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags = BfCastFlags_None); bool AreSplatsCompatible(BfType* fromType, BfType* toType, bool* outNeedsMemberCasting); BfTypedValue BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType /*Can be System.Object or interface*/, const BfAllocTarget& allocTarget, bool callDtor = true); BfIRValue CastToFunction(BfAstNode* srcNode, const BfTypedValue& targetValue, BfMethodInstance* methodInstance, BfType* toType, BfCastFlags castFlags = BfCastFlags_None); 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); 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 EmitAlign(BfIRValue& appendCurIdx, int align); 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(); void SkipObjectAccessCheck(BfTypedValue typedVal); void EmitObjectAccessCheck(BfTypedValue typedVal); 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); BfTypedValue LoadOrAggregateValue(BfTypedValue typedValue); BfTypedValue LoadValue(BfTypedValue typedValue, BfAstNode* refNode = NULL, bool isVolatile = false); void AggregateSplatIntoAddr(BfTypedValue typedValue, BfIRValue addrVal); BfTypedValue AggregateSplat(BfTypedValue typedValue, BfIRValue* valueArrPtr = NULL); BfTypedValue MakeAddressable(BfTypedValue typedValue); BfTypedValue RemoveReadOnly(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 ReferenceStaticField(BfFieldInstance* fieldInstance); BfTypedValue GetThis(); 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(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(BfTypeReference* typeRef, BfTypeInstance* genericTypeInstance, bool ignoreErrors); bool AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGenericParamInstance* checkOuter); bool CheckConstraintState(BfAstNode* refNode); 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); 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 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 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); void MarkFieldInitialized(BfFieldInstance* fieldInstance); bool IsThreadLocal(BfFieldInstance* fieldInstance); BfType* ResolveVarFieldType(BfTypeInstance* typeInst, BfFieldInstance* fieldInstance, BfFieldDef* field); void FindSubTypes(BfTypeInstance* classType, SizedArrayImpl* outVals, SizedArrayImpl* 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); BfBoxedType* CreateBoxedType(BfType* resolvedTypeRef, bool allowCreate = true); BfTypeInstance* CreateTupleType(const BfTypeVector& fieldTypes, const Array& 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); 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); 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 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 CreateDIRetVal(); 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& arguments, BfAstNode* tooFewRef, BfIRValue phiVal, BfIRBlock& matchedBlock, BfIRBlock falseBlock, bool& hadConditional, bool clearOutOnMismatch); BfTypedValue TryCaseTupleMatch(BfTypedValue tupleVal, BfTupleExpression* tupleExpr, BfIRBlock* eqBlock, BfIRBlock* notEqBlock, BfIRBlock* matchBlock, bool& hadConditional, bool clearOutOnMismatch); BfTypedValue TryCaseEnumMatch(BfTypedValue enumVal, BfTypedValue tagVal, BfExpression* expr, BfIRBlock* eqBlock, BfIRBlock* notEqBlock, BfIRBlock* matchBlock, int& uncondTagId, bool& hadConditional, bool clearOutOnMismatch); 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(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); BfGenericParamType* GetGenericParamType(BfGenericParamKind paramKind, int paramIdx); BfType* ResolveGenericType(BfType* unspecializedType, BfTypeVector* typeGenericArguments, BfTypeVector* methodGenericArguments, bool allowFail = false); bool IsUnboundGeneric(BfType* type); BfGenericParamInstance* GetGenericTypeParamInstance(int paramIdx); BfGenericParamInstance* GetGenericParamInstance(BfGenericParamType* type); void GetActiveTypeGenericParamInstances(SizedArray& genericParamInstance); BfTypeInstance* GetBaseType(BfTypeInstance* typeInst); void HandleTypeGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDef, int typeGenericParamIdx); void HandleMethodGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDef, BfMethodDef* methodDef, int typeGenericParamIdx); BfType* ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTypeRef, BfPopulateType populateType, BfResolveTypeRefFlags resolveFlags); void ShowAmbiguousTypeError(BfAstNode* refNode, BfTypeDef* typeDef, BfTypeDef* otherTypeDef); void ShowGenericArgCountError(BfTypeReference* typeRef, int wantedGenericParams); BfTypeDef* GetActiveTypeDef(BfTypeInstance* typeInstanceOverride = NULL, bool useMixinDecl = 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); BfTypeDef* FindTypeDef(const BfAtomComposite& findName, int numGenericArgs = 0, BfTypeInstance* typeInstanceOverride = NULL, BfTypeLookupError* error = NULL); BfTypeDef* FindTypeDef(const StringImpl& typeName, int numGenericArgs = 0, BfTypeInstance* typeInstanceOverride = NULL, BfTypeLookupError* error = NULL); 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(BfTypeReference* typeRef, bool isAttributeRef); BfType* ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0, int numGenericArgs = 0); BfType* ResolveTypeRefAllowUnboundGenerics(BfTypeReference* typeRef, BfPopulateType populateType = BfPopulateType_Data, bool resolveGenericParam = true); BfType* ResolveTypeRef(BfAstNode* astNode, const BfSizedArray* genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0); //BfType* ResolveTypeRef(BfIdentifierNode* identifier, const BfSizedArray& 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, BfTypeReference* typeRef, BfPopulateType populateType = BfPopulateType_Data, bool ignoreErrors = false, int numGenericArgs = 0); BfType* ResolveInnerType(BfType* outerType, BfIdentifierNode* identifier, BfPopulateType populateType = BfPopulateType_Data, bool ignoreErrors = false); 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); 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 DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool isTemporaryFunc, bool addToWorkList = true); void AddMethodToWorkList(BfMethodInstance* methodInstance); bool IsInterestedInMethod(BfTypeInstance* typeInstance, BfMethodDef* methodDef); void CalcAppendAlign(BfMethodInstance* methodInst); BfTypedValue TryConstCalcAppend(BfMethodInstance* methodInst, SizedArrayImpl& args); 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 EmitCtorBody(bool& skipBody); void EmitDtorBody(); void EmitEnumToStringBody(); void EmitTupleToStringBody(); void EmitGCMarkValue(BfTypedValue& thisValue, BfType* checkType, int memberDepth, int curOffset, HashSet& objectOffsets, BfModuleMethodInstance markFromGCThreadMethodInstance); 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* diParams); void ProcessMethod_ProcessDeferredLocals(int startIdx = 0); void ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup = false); void CreateDynamicCastMethod(); void CreateValueTypeEqualsMethod(bool strictEquals); BfIRFunction GetIntrinsic(BfMethodInstance* methodInstance, bool reportFailure = false); BfIRFunction GetBuiltInFunc(BfBuiltInFuncType funcType); BfIRValue CreateFunctionFrom(BfMethodInstance* methodInstance, bool tryExisting, bool isInlined); void EvaluateWithNewScope(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& 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& 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(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); BfModuleMethodInstance GetMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None); BfMethodInstance* GetOuterMethodInstance(BfMethodInstance* methodInstance); // Only useful for local methods void SetupMethodIdHash(BfMethodInstance* methodInstance); // 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); BfIRValue CreateTypeData(BfType* type, Dictionary& usedStringIdMap, 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(); void FinishInit(); void ReifyModule(); void UnreifyModule(); void Cleanup(); void StartNewRevision(RebuildKind rebuildKind = RebuildKind_All, bool force = false); void PrepareForIRWriting(BfTypeInstance* typeInst); 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 mDefinedStrings; public: BfVDataModule(BfContext* context) : BfModule(context, StringImpl::MakeRef("vdata")) { } }; NS_BF_END namespace std { template<> struct hash { size_t operator()(const Beefy::BfMethodRef& val) const { if (val.mTypeInstance == NULL) return 0; return val.mTypeInstance->mTypeId ^ (val.mMethodNum << 10); } }; template<> struct hash { size_t operator()(const Beefy::BfVDataExtEntry& val) const { return ((size_t)(val.mDeclTypeInst) * 17) ^ (size_t)(val.mDeclTypeInst); } }; template<> struct hash { size_t operator()(const Beefy::BfLocalVarEntry& val) const { return std::hash()(val.mLocalVar->mName); } }; }