1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 03:28:20 +02:00
Beef/IDEHelper/DbgExprEvaluator.cpp

8346 lines
230 KiB
C++
Raw Normal View History

2019-08-23 11:56:54 -07:00
#include "DbgExprEvaluator.h"
#include "WinDebugger.h"
#include "Compiler/BfUtil.h"
#include "Compiler/BfSystem.h"
#include "Compiler/BfParser.h"
#include "Compiler/BfReducer.h"
#include "Compiler/BfPrinter.h"
#include "Compiler/BfDemangler.h"
#include "DWARFInfo.h"
#include "DebugManager.h"
#include "DebugVisualizers.h"
#include "BeefySysLib/util/BeefPerf.h"
#include "BeefySysLib/util/StackHelper.h"
#include "BeefySysLib/util/AllocDebug.h"
USING_NS_BF_DBG;
using namespace llvm;
//////////////////////////////////////////////////////////////////////////
DwMethodMatcher::DwMethodMatcher(BfAstNode* targetSrc, DbgExprEvaluator* exprEvaluator, const StringImpl& methodName, SizedArrayImpl<DbgTypedValue>& arguments, BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArguments) :
mArguments(arguments)
{
mTargetSrc = targetSrc;
mExprEvaluator = exprEvaluator;
mMethodName = methodName;
mArguments = arguments;
mBestMethodDef = NULL;
mBackupMethodDef = NULL;
mBestMethodTypeInstance = NULL;
mExplicitInterfaceCheck = NULL;
mHadExplicitGenericArguments = false;
mTargetIsConst = false;
if (methodGenericArguments != NULL)
{
for (auto genericArg : *methodGenericArguments)
{
auto genericArgType = mExprEvaluator->ResolveTypeRef(genericArg);
if (genericArgType == NULL)
return;
mBestMethodGenericArguments.push_back(genericArgType);
//mBestMethodGenericArgumentSrcs.push_back(genericArg);
}
mHadExplicitGenericArguments = true;
}
}
/*bool DwMethodMatcher::InferGenericArgument(DbgType* argType, DbgType* wantType)
{
if (argType == NULL)
return false;
if (wantType->IsGenericParam())
{
auto wantGenericParam = (BfGenericParamType*)wantType;
if (wantGenericParam->mGenericParamKind == BfGenericParamKind_Method)
{
auto prevGenericMethodArg = mCheckMethodGenericArguments[wantGenericParam->mGenericParamIdx];
if (prevGenericMethodArg == NULL)
{
mCheckMethodGenericArguments[wantGenericParam->mGenericParamIdx] = argType;
return true;
}
// Prev is already best
if (mModule->CanCast(DbgTypedValue(NULL, argType), prevGenericMethodArg))
2019-08-23 11:56:54 -07:00
return true;
// New best?
if (mModule->CanCast(DbgTypedValue(NULL, prevGenericMethodArg), argType))
2019-08-23 11:56:54 -07:00
{
mCheckMethodGenericArguments[wantGenericParam->mGenericParamIdx] = argType;
return true;
}
// No implicit conversion, FAIL!
mCheckMethodGenericArguments[wantGenericParam->mGenericParamIdx] = NULL;
return false;
}
return true;
}
if (wantType->IsGenericTypeInstance())
{
if (!argType->IsGenericTypeInstance())
return true;
auto wantGenericType = (BfTypeInstance*)wantType;
auto argGenericType = (BfTypeInstance*)argType;
2019-08-23 11:56:54 -07:00
if (argGenericType->mTypeDef != wantGenericType->mTypeDef)
return true;
for (int genericArgIdx = 0; genericArgIdx < (int)argGenericType->mTypeGenericArguments.size(); genericArgIdx++)
InferGenericArgument(argGenericType->mTypeGenericArguments[genericArgIdx], wantGenericType->mTypeGenericArguments[genericArgIdx]);
return true;
}
if (wantType->IsRef())
{
if (!argType->IsRef())
return true;
auto wantRefType = (BfRefType*)wantType;
auto argRefType = (BfRefType*)argType;
if (wantRefType->mIsOut != argRefType->mIsOut)
return true;
InferGenericArgument(argRefType->mElementType, wantRefType->mElementType);
return true;
}
if (wantType->IsPointer())
{
if (!argType->IsPointer())
return true;
auto wantPointerType = (BfPointerType*) wantType;
auto argPointerType = (BfPointerType*) argType;
InferGenericArgument(argPointerType->mElementType, wantPointerType->mElementType);
return true;
}
return true;
}*/
void DwMethodMatcher::CompareMethods(DbgSubprogram* prevMethodInstance, DwTypeVector* prevGenericArgumentsSubstitute,
DbgSubprogram* newMethodInstance, DwTypeVector* genericArgumentsSubstitute,
bool* outNewIsBetter, bool* outNewIsWorse, bool allowSpecializeFail)
{
int numUsedParams = 0;
int prevNumUsedParams = 0;
bool usedExtendedForm = false;
bool prevUsedExtendedForm = false;
bool isBetter = false;
bool isWorse = false;
int argIdx = 0;
DbgSubprogram* prevMethodDef = prevMethodInstance;
DbgSubprogram* newMethodDef = newMethodInstance;
#define SET_BETTER_OR_WORSE(lhs, rhs) \
if ((lhs) && !(rhs)) isBetter = true; \
if (!(lhs) && (rhs)) isWorse = true;
int newArgOffset = newMethodInstance->mHasThis ? 1 : 0;
int prevArgOffset = prevMethodInstance->mHasThis ? 1 : 0;
DbgVariable* param = newMethodInstance->mParams.mHead;
if (newMethodInstance->mHasThis)
param = param->mNext;
DbgVariable* prevParam = prevMethodInstance->mParams.mHead;
if (prevMethodInstance->mHasThis)
prevParam = prevParam->mNext;
for (argIdx = 0; argIdx < (int) mArguments.size(); argIdx++)
{
DbgTypedValue arg = mArguments[argIdx];
DbgType* paramType = param->mType;
DbgType* prevParamType = prevParam->mType;
numUsedParams++;
prevNumUsedParams++;
/*if ((genericArgumentsSubstitute != NULL) && (paramType->IsUnspecializedType()))
paramType = mModule->SpecializeMethodType(paramType, *genericArgumentsSubstitute, allowSpecializeFail);
if (prevParamType->IsUnspecializedType())
prevParamType = mModule->SpecializeMethodType(prevParamType, *prevGenericArgumentsSubstitute, allowSpecializeFail);*/
//paramType = paramType->RemoveModifiers();
//prevParamType = prevParamType->RemoveModifiers();
if (paramType != prevParamType)
{
/*if ((paramType->IsGenericParam()) || (prevParamType->IsGenericParam()))
{
BF_ASSERT(allowSpecializeFail);
if (!prevParamType->IsGenericParam())
isBetter = true;
else if (!paramType->IsGenericParam())
isWorse = true;
}
else*/ if ((paramType->IsInteger()) && (prevParamType->IsInteger()))
{
if (paramType == arg.mType)
isBetter = true;
else if (prevParamType == arg.mType)
isWorse = true;
else
{
if (paramType->mSize < prevParamType->mSize)
isBetter = true;
else if (paramType->mSize > prevParamType->mSize)
isWorse = true;
else if (paramType->IsSigned())
isBetter = true;
else
isWorse = true;
}
}
else
{
if (mExprEvaluator->CanCast(DbgTypedValue::GetValueless(paramType), prevParamType))
2019-08-23 11:56:54 -07:00
isBetter = true;
if (mExprEvaluator->CanCast(DbgTypedValue::GetValueless(prevParamType), paramType))
2019-08-23 11:56:54 -07:00
isWorse = true;
}
}
/*if (newMethodDef->mParams[argIdx]->mParamType == BfParamType_Params)
usedExtendedForm = true;
if (prevMethodDef->mParams[argIdx]->mParamType == BfParamType_Params)
prevUsedExtendedForm = true;*/
if ((usedExtendedForm) || (prevUsedExtendedForm))
break;
param = param->mNext;
prevParam = prevParam->mNext;
}
// Check for unused extended params as next param - that still counts as using extended form
/*if ((argIdx < (int) newMethodDef->mParams.size()) && (newMethodDef->mParams[argIdx]->mParamType == BfParamType_Params))
usedExtendedForm = true;
if ((argIdx < (int) prevMethodDef->mParams.size()) && (prevMethodDef->mParams[argIdx]->mParamType == BfParamType_Params))
prevUsedExtendedForm = true;*/
// Non-generic trumps generic
/*if ((!isBetter) && (!isWorse))
{
SET_BETTER_OR_WORSE(newMethodInstance->mMethodGenericArguments.size() == 0, prevMethodInstance->mMethodGenericArguments.size() == 0);
}*/
// Normal form trumps extended form
if ((!isBetter) && (!isWorse))
{
SET_BETTER_OR_WORSE(!usedExtendedForm, !prevUsedExtendedForm);
}
// More used params trumps less params
if ((!isBetter) && (!isWorse))
{
int paramDiff = (int) numUsedParams - (int) prevNumUsedParams;
SET_BETTER_OR_WORSE(paramDiff > 0, paramDiff < 0);
}
// Fewer defaults trumps more defaults
/*if ((!isBetter) && (!isWorse))
{
// Since we know the number of used params is the same (previous check), we infer that the rest are defaults
int paramDiff = (int) newMethodInstance->mParamTypes.size() - (int) prevMethodInstance->mParamTypes.size();
SET_BETTER_OR_WORSE(paramDiff < 0, paramDiff > 0);
}*/
// Check specificity of args
if ((!isBetter) && (!isWorse))
{
param = newMethodInstance->mParams.mHead;
if (newMethodInstance->mHasThis)
param = param->mNext;
prevParam = prevMethodInstance->mParams.mHead;
if (prevMethodInstance->mHasThis)
prevParam = prevParam->mNext;
for (argIdx = 0; argIdx < (int) mArguments.size(); argIdx++)
{
DbgType* paramType = param->mType;
DbgType* prevParamType = prevParam->mType;
//TODO:
//isBetter |= mModule->IsTypeMoreSpecific(paramType, prevParamType);
//isWorse |= mModule->IsTypeMoreSpecific(prevParamType, paramType);
param = param->mNext;
prevParam = prevParam->mNext;
}
}
// Prefer virtual - this helps us bind to a virtual override instead of the concrete method implementation so we can ignore it and
// continue searching through the base types to find the original virtual method
if ((!isBetter) && (!isWorse))
{
SET_BETTER_OR_WORSE(newMethodInstance->mVirtual, prevMethodInstance->mVirtual);
}
if ((!isBetter) && (!isWorse))
{
SET_BETTER_OR_WORSE(newMethodInstance->mBlock.mLowPC != 0, prevMethodInstance->mBlock.mLowPC != 0);
}
if ((!isBetter) && (!isWorse))
{
if ((newMethodInstance->mHasThis) && (prevMethodInstance->mHasThis))
{
SET_BETTER_OR_WORSE(
newMethodInstance->mParams.mHead->mType->IsConst() == mTargetIsConst,
prevMethodInstance->mParams.mHead->mType->IsConst() == mTargetIsConst);
}
}
*outNewIsBetter = isBetter;
*outNewIsWorse = isWorse;
}
bool DwMethodMatcher::CheckMethod(DbgType* typeInstance, DbgSubprogram* checkMethod)
{
bool hadMatch = false;
checkMethod->PopulateSubprogram();
// Never consider overrides - they only get found at original method declaration
/*if ((checkMethod->mVirtual) && (checkMethod->mVTableLoc == -1))
return true;*/
//BfMethodInstance* methodInstance = mModule->GetRawMethodInstanceAtIdx(typeInstance, checkMethod->mIdx);
DbgSubprogram* methodInstance = checkMethod;
DwAutoComplete* autoComplete = mExprEvaluator->mAutoComplete;
if ((autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo))
{
DwAutoComplete::MethodMatchEntry methodMatchEntry;
methodMatchEntry.mDwSubprogram = methodInstance;
autoComplete->mMethodMatchInfo->mInstanceList.push_back(methodMatchEntry);
}
/*if ((mHadExplicitGenericArguments) && (checkMethod->mGenericParams.size() != mBestMethodGenericArguments.size()))
goto NoMatch;*/
for (auto& checkGenericArgRef : mCheckMethodGenericArguments)
checkGenericArgRef = NULL;
/*mCheckMethodGenericArguments.resize(checkMethod->mGenericParams.size());
for (auto& genericArgRef : mCheckMethodGenericArguments)
genericArgRef = NULL;*/
int argIdx = 0;
int paramIdx = 0;
DbgType* paramsElementType = NULL;
//bool needInferGenericParams = (checkMethod->mGenericParams.size() != 0) && (!mHadExplicitGenericArguments);
DwTypeVector* genericArgumentsSubstitute = NULL;
/*if (mHadExplicitGenericArguments)
genericArgumentsSubstitute = &mBestMethodGenericArguments;
else if (needInferGenericParams)
genericArgumentsSubstitute = &mCheckMethodGenericArguments;
if (needInferGenericParams)
{
for (int argIdx = 0; argIdx < (int)mArguments.size(); argIdx++)
{
if (argIdx >= (int)checkMethod->mParams.size())
break;
auto wantType = methodInstance->mParamTypes[argIdx];
if (wantType->IsUnspecializedType())
{
if (!InferGenericArgument(mArguments[argIdx].mType, wantType))
goto NoMatch;
}
}
for (int checkArgIdx = 0; checkArgIdx < (int) checkMethod->mGenericParams.size(); checkArgIdx++)
if (mCheckMethodGenericArguments[checkArgIdx] == NULL)
goto NoMatch;
}*/
// Iterate through params
int paramOffset = checkMethod->mHasThis ? 1 : 0;
while (true)
{
// Too many arguments
if (paramIdx >= checkMethod->mParams.Size() - paramOffset)
{
break;
}
DbgVariable* paramDef = checkMethod->mParams[paramIdx + paramOffset];
//TODO:
/*if ((paramDef->mParamType == BfParamType_Params) && (paramsElementType == NULL))
{
if (paramIdx >= (int) mArguments.size())
break; // No params
if (!mArguments[argIdx])
goto NoMatch;
// Check to see if we're directly passing the params type (like an int[])
auto paramsArrayType = methodInstance->mParamTypes[paramIdx];
if (mModule->CanCast(mArguments[argIdx], paramsArrayType))
2019-08-23 11:56:54 -07:00
{
argIdx++;
paramIdx++;
break;
}
BF_ASSERT(paramsArrayType->IsArray());
auto arrayType = (BfArrayType*)paramsArrayType;
paramsElementType = arrayType->mTypeGenericArguments[0];
while (argIdx < (int)mArguments.size())
{
if (!mArguments[argIdx])
goto NoMatch;
if (!mModule->CanCast(mArguments[argIdx], paramsElementType))
2019-08-23 11:56:54 -07:00
goto NoMatch;
argIdx++;
}
break;
}*/
if (paramIdx >= (int) mArguments.size())
{
// We have defaults the rest of the way, so that's cool
//TODO:
/*if (paramDef->mParamDeclaration->mInitializer != NULL)
break;*/
// We have unused params left over
goto NoMatch;
}
auto wantType = paramDef->mType;
/*if ((genericArgumentsSubstitute != NULL) && (wantType->IsUnspecializedType()))
wantType = mModule->SpecializeMethodType(wantType, *genericArgumentsSubstitute);*/
if (!mArguments[argIdx])
goto NoMatch;
if (!mExprEvaluator->CanCast(mArguments[argIdx], wantType))
2019-08-23 11:56:54 -07:00
goto NoMatch;
paramIdx++;
argIdx++;
if ((autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo))
{
auto methodMatchInfo = autoComplete->mMethodMatchInfo;
if (!methodMatchInfo->mHadExactMatch)
{
bool isBetter = false;
bool isWorse = false;
int methodIdx = (int)methodMatchInfo->mInstanceList.size() - 1;
if (methodMatchInfo->mBestIdx < (int)methodMatchInfo->mInstanceList.size())
{
auto prevMethodMatchEntry = &methodMatchInfo->mInstanceList[methodMatchInfo->mBestIdx];
if (checkMethod->mParams.Size() < (int)mArguments.size())
{
isWorse = true;
}
else if (prevMethodMatchEntry->mDwSubprogram->mParams.Size() < (int) mArguments.size())
{
isBetter = true;
}
else
{
//BfMethodInstance* prevMethodInstance = mModule->GetRawMethodInstanceAtIdx(prevMethodMatchEntry->mTypeInstance, prevMethodMatchEntry->mMethodDef->mIdx);
DbgSubprogram* prevMethodInstance = prevMethodMatchEntry->mDwSubprogram;
CompareMethods(prevMethodInstance, &prevMethodMatchEntry->mDwGenericArguments,
methodInstance, genericArgumentsSubstitute, &isBetter, &isWorse, true);
}
}
if ((argIdx > methodMatchInfo->mMostParamsMatched) ||
((argIdx == methodMatchInfo->mMostParamsMatched) && (isBetter)) ||
((argIdx == methodMatchInfo->mMostParamsMatched) && (methodIdx == methodMatchInfo->mPrevBestIdx) && (!isWorse)))
{
methodMatchInfo->mBestIdx = methodIdx;
methodMatchInfo->mMostParamsMatched = argIdx;
}
}
}
}
//TODO: Does this ever get hit?
// Not enough arguments?
if (argIdx < (int)mArguments.size())
{
goto NoMatch;
}
// Method is applicable, check to see which method is better
if (mBestMethodDef != NULL)
{
bool isBetter = false;
bool isWorse = false;
//BfMethodInstance* prevMethodInstance = mModule->GetRawMethodInstanceAtIdx(mBestMethodTypeInstance, mBestMethodDef->mIdx);
DbgSubprogram* prevMethodInstance = mBestMethodDef;
CompareMethods(prevMethodInstance, &mBestMethodGenericArguments, methodInstance, genericArgumentsSubstitute, &isBetter, &isWorse, false);
// If we had both a 'better' and 'worse', that's ambiguous because the methods are each better in different ways (not allowed)
// And if neither better nor worse then they are equally good, which is not allowed either
if (((!isBetter) && (!isWorse)) || ((isBetter) && (isWorse)))
{
// When we have [Checked] and [Unchecked] both, they will confict here but be equal
if (!prevMethodInstance->Equals(methodInstance))
{
mExprEvaluator->Fail(StrFormat("Ambiguous method call between '%s' and '%s'", prevMethodInstance->ToString().c_str(),
methodInstance->ToString().c_str()), mTargetSrc);
}
}
if (!isBetter)
goto Done;
}
if ((autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo))
{
auto methodMatchInfo = autoComplete->mMethodMatchInfo;
// Try to persist with previous partial match, if we have one - this keeps us from locking onto
// an incorrect method just because it had the current number of params that we've typed so far
if (methodMatchInfo->mPrevBestIdx == -1)
{
methodMatchInfo->mHadExactMatch = true;
methodMatchInfo->mBestIdx = (int) methodMatchInfo->mInstanceList.size() - 1;
}
}
hadMatch = true;
mBestMethodDef = checkMethod;
NoMatch:
if (!hadMatch)
{
if (mBestMethodDef != NULL)
return true;
//TODO:
/*if ((mHadExplicitGenericArguments) && (mBestMethodGenericArguments.size() != checkMethod->mGenericParams.size()))
return true;*/
// At least prefer a backup method that we have an address for
if ((mBackupMethodDef != NULL) && (mBackupMethodDef->mBlock.mLowPC != 0))
return true;
mBackupMethodDef = checkMethod;
// Lie temporarily to store at least one candidate (but mBestMethodDef is still NULL)
hadMatch = true;
}
if (hadMatch)
{
mBestMethodTypeInstance = typeInstance;
if (!mHadExplicitGenericArguments)
{
mBestMethodGenericArguments = mCheckMethodGenericArguments;
}
}
Done:
if ((autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo) && (genericArgumentsSubstitute != NULL))
{
auto methodMatchInfo = autoComplete->mMethodMatchInfo;
methodMatchInfo->mInstanceList[methodMatchInfo->mInstanceList.size() - 1].mDwGenericArguments = *genericArgumentsSubstitute;
}
return true;
}
bool DwMethodMatcher::CheckType(DbgType* typeInstance, bool isFailurePass)
{
typeInstance = typeInstance->RemoveModifiers();
if (typeInstance->IsPointer())
typeInstance = typeInstance->mTypeParam;
typeInstance = typeInstance->GetPrimaryType();
//bool allowPrivate = typeInstance == mExprEvaluator->GetCurrentType();
//bool allowProtected = allowPrivate || mExprEvaluator->TypeIsSubTypeOf(mExprEvaluator->GetCurrentType(), typeInstance);
bool allowPrivate = true;
bool allowProtected = true;
auto curType = typeInstance;
bool wantCtor = false;
auto baseItr = typeInstance->mBaseTypes.begin();
auto altItr = typeInstance->mAlternates.begin();
while (true)
{
bool foundMethodInType = false;
curType->PopulateType();
// Why did we have this "&&" check on there?
// It made it so invocations would fail unless we had autocompleted the type
if ((curType->mNeedsGlobalsPopulated)
/*&& ((curType->IsNamespace()) || (curType->IsRoot()))*/)
{
// These aren't proper TPI types so we don't have any method declarations until we PopulateTypeGlobals
mExprEvaluator->mDbgModule->PopulateTypeGlobals(curType);
}
for (auto methodNameEntry : curType->mMethodNameList)
{
if ((methodNameEntry->mCompileUnitId != -1) && (methodNameEntry->mName == mMethodName))
{
// If we hot-replaced this type then we replaced and parsed all the methods too
if (!curType->mCompileUnit->mDbgModule->IsObjectFile())
2019-08-23 11:56:54 -07:00
curType->mCompileUnit->mDbgModule->MapCompileUnitMethods(methodNameEntry->mCompileUnitId);
methodNameEntry->mCompileUnitId = -1;
}
}
auto checkMethod = curType->mMethodList.mHead;
while (checkMethod != NULL)
{
/*if ((!checkMethod->mHasThis) && (!checkStatic))
continue;
if ((checkMethod->mHasThis) && (!checkNonStatic))
continue;*/
// These can only be invoked when the target itself is the interface
/*if (checkMethod->mExplicitInterface != NULL)
continue;*/
if ((wantCtor) && (checkMethod->mMethodType != DbgMethodType_Ctor))
{
checkMethod = checkMethod->mNext;
continue;
}
if (!wantCtor)
{
if (checkMethod->mMethodType != DbgMethodType_Normal)
{
checkMethod = checkMethod->mNext;
continue;
}
if ((checkMethod->mName == NULL) || (checkMethod->mName != mMethodName))
{
checkMethod = checkMethod->mNext;
continue;
}
}
if ((!isFailurePass) && (!CheckProtection(checkMethod->mProtection, allowProtected, allowPrivate)))
{
checkMethod = checkMethod->mNext;
continue;
}
if (!curType->mHasGlobalsPopulated)
mExprEvaluator->mDbgModule->PopulateTypeGlobals(curType);
/*if (!foundMethodInType)
{
if (curType->mCompileUnit->mLanguage != DbgLanguage_Beef)
{
String fullMethodName = String(curType->mTypeName) + "::" + mMethodName;
curType->mCompileUnit->mDbgModule->EnsureMethodMapped(fullMethodName.c_str());
}
foundMethodInType = true;
}*/
if (!CheckMethod(curType, checkMethod))
return false;
checkMethod = checkMethod->mNext;
}
if (mBestMethodDef != NULL)
{
if ((mBestMethodDef->mVirtual) && (mBestMethodDef->mVTableLoc == -1))
{
// It's an override, keep searching through the base types to find the original method declaration
mBestMethodDef = NULL;
mBackupMethodDef = NULL;
}
else
return true;
}
/*if (baseItr != typeInstance->mBaseTypes.end())
{
auto baseTypeEntry = *baseItr;
curType = baseTypeEntry->mBaseType;
baseItr++;
continue;;
}*/
if (altItr != typeInstance->mAlternates.end())
{
curType = *altItr;
++altItr;
continue;
}
/*allowPrivate = false;
if ((isFailurePass) && (mBackupMethodDef != NULL))
break;*/
break;
}
if (mBestMethodDef == NULL)
{
// FAILED, but select the first method which will fire an actual error on param type matching
mBestMethodDef = mBackupMethodDef;
for (auto subType : typeInstance->mSubTypeList)
{
if ((subType->mName == NULL) || (subType->IsGlobalsContainer()))
{
if (!CheckType(subType, isFailurePass))
return false;
if (mBestMethodDef != NULL)
break;
}
}
if (mBestMethodDef == NULL)
{
for (auto baseTypeEntry : typeInstance->mBaseTypes)
{
if (!CheckType(baseTypeEntry->mBaseType, isFailurePass))
return false;
if (mBestMethodDef != NULL)
break;
}
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
DbgExprEvaluator::DbgExprEvaluator(WinDebugger* winDebugger, DbgModule* dbgModule, BfPassInstance* passInstance, int callStackIdx, int cursorPos)
{
mCountResultOverride = -1;
mCapturingChildRef = true;
mPassInstance = passInstance;
mDebugger = winDebugger;
2020-07-31 06:16:29 -07:00
mLanguage = DbgLanguage_NotSet;
2019-08-23 11:56:54 -07:00
mOrigDbgModule = dbgModule;
2020-07-31 06:16:29 -07:00
if (dbgModule != NULL)
{
mDebugTarget = dbgModule->mDebugTarget;
mDbgModule = dbgModule->GetLinkedModule();
}
else
{
mDebugTarget = NULL;
mDbgModule = NULL;
}
2019-08-23 11:56:54 -07:00
mDbgCompileUnit = NULL;
mExplicitThisExpr = NULL;
mExpectingType = NULL;
mCurMethod = NULL;
mIgnoreErrors = false;
mCallStackIdx = callStackIdx;
mCursorPos = cursorPos;
mAutoComplete = NULL;
mIsEmptyTarget = (dbgModule == NULL) || (dbgModule->mDebugTarget->mIsEmpty);
2020-06-15 09:01:49 -07:00
mExpressionFlags = DwEvalExpressionFlag_None;
2019-08-23 11:56:54 -07:00
mHadSideEffects = false;
2020-06-15 09:01:49 -07:00
mBlockedSideEffects = false;
2019-08-23 11:56:54 -07:00
mReferenceId = NULL;
mIsComplexExpression = false;
mHadMemberReference = false;
mCreatedPendingCall = false;
mValidateOnly = false;
mReceivingValue = NULL;
mCallResults = NULL;
mCallResultIdx = 0;
mCallStackPreservePos = 0;
2019-08-23 11:56:54 -07:00
mPropGet = NULL;
mPropSet = NULL;
mPropSrc = NULL;
}
DbgExprEvaluator::~DbgExprEvaluator()
{
}
DbgTypedValue DbgExprEvaluator::GetInt(int value)
{
DbgTypedValue dbgValue;
dbgValue.mType = mDbgModule->GetPrimitiveType(DbgType_i32, GetLanguage());
dbgValue.mInt32 = value;
return dbgValue;
}
DbgTypedValue DbgExprEvaluator::GetString(const StringImpl& str)
{
String* resultPtr;
mDebugger->mLiteralSet.TryAdd(str, &resultPtr);
DbgTypedValue dbgValue;
auto language = GetLanguage();
auto charPtrType = mDbgModule->GetPrimitiveType((language == DbgLanguage_Beef) ? DbgType_UChar : DbgType_SChar, language);
if (charPtrType != NULL)
charPtrType = mDbgModule->GetPointerType(charPtrType);
if (charPtrType != NULL)
{
dbgValue.mType = charPtrType;
dbgValue.mLocalPtr = resultPtr->c_str();
dbgValue.mIsLiteral = true;
dbgValue.mDataLen = resultPtr->mLength;
2019-08-23 11:56:54 -07:00
}
return dbgValue;
}
void DbgExprEvaluator::Fail(const StringImpl& error, BfAstNode* node)
{
if ((!mIgnoreErrors) && (mPassInstance != NULL))
mPassInstance->Fail(error, node);
}
void DbgExprEvaluator::Warn(const StringImpl& error, BfAstNode * node)
{
if ((!mIgnoreErrors) && (mPassInstance != NULL))
mPassInstance->Warn(0, error, node);
}
DbgType* DbgExprEvaluator::GetExpectingType()
{
if ((mExpectingType == NULL) && (!mExpectingTypeName.empty()))
{
mExpectingType = ResolveTypeRef(mExpectingTypeName);
mExpectingTypeName.clear();
}
return mExpectingType;
}
void DbgExprEvaluator::GetNamespaceSearch()
{
if (!mNamespaceSearch.empty())
return;
auto currentMethod = GetCurrentMethod();
if (currentMethod != NULL)
{
auto parent = currentMethod->GetParent();
while (parent != NULL)
{
parent = parent->GetPrimaryType();
mNamespaceSearch.push_back(parent);
parent = parent->mParent;
}
}
if (!mNamespaceSearchStr.empty())
{
auto language = GetLanguage();
int lastComma = -1;
for (int i = 0; i < (int)mNamespaceSearchStr.length(); i++)
{
if (mNamespaceSearchStr[i] == ',')
{
String namespaceEntry = mNamespaceSearchStr.Substring(lastComma + 1, i - lastComma - 1);
auto dbgTypeEntry = mDbgModule->mTypeMap.Find(namespaceEntry.c_str(), language);
if (dbgTypeEntry != NULL)
mNamespaceSearch.push_back(dbgTypeEntry->mValue);
lastComma = i;
}
}
String namespaceEntry = mNamespaceSearchStr.Substring(lastComma + 1);
auto dbgTypeEntry = mDbgModule->mTypeMap.Find(namespaceEntry.c_str(), language);
if (dbgTypeEntry != NULL)
mNamespaceSearch.push_back(dbgTypeEntry->mValue);
}
}
DbgType* DbgExprEvaluator::ResolveSubTypeRef(DbgType* checkType, const StringImpl& name)
{
checkType->PopulateType();
for (auto subType : checkType->mSubTypeList)
{
if (strcmp(subType->mTypeName, name.c_str()) == 0)
return subType;
}
for (auto checkBaseType : checkType->mBaseTypes)
{
DbgType* subType = ResolveSubTypeRef(checkBaseType->mBaseType, name);
if (subType != NULL)
return subType;
}
return NULL;
}
DbgType* DbgExprEvaluator::FixType(DbgType* dbgType)
{
if (dbgType->IsBfObject())
dbgType = mDbgModule->GetPointerType(dbgType);
return dbgType;
}
DbgTypedValue DbgExprEvaluator::FixThis(const DbgTypedValue& thisVal)
{
/*if ((thisVal.mType != NULL) && (thisVal.mType->GetLanguage() == DbgLanguage_Beef) &&
(!thisVal.mType->IsBfObjectPtr()) && (thisVal.mType->IsPointer()))
{
// Beef structs expect 'this' as a valuetype, not a pointer
DbgTypedValue fixedThisVal;
fixedThisVal.mType = thisVal.mType->mTypeParam;
fixedThisVal.mSrcAddress = thisVal.mPtr;
fixedThisVal.mPtr = thisVal.mPtr;
int byteCount = fixedThisVal.mType->GetByteCount();
if (byteCount <= 8) // For typed primitive loads
mDebugger->ReadMemory(fixedThisVal.mSrcAddress, byteCount, &fixedThisVal.mInt64);
return fixedThisVal;
}*/
return thisVal;
}
DbgType* DbgExprEvaluator::ResolveTypeRef(BfTypeReference* typeRef)
{
mDbgModule->ParseTypeData();
if (auto ptrTypeRef = BfNodeDynCastExact<BfPointerTypeRef>(typeRef))
{
// If it's a pointer type ref then create our own type
auto innerType = ResolveTypeRef(ptrTypeRef->mElementType);
if (innerType == NULL)
return NULL;
return mDbgModule->GetPointerType(innerType);
}
if (auto arrayTypeRef = BfNodeDynCastExact<BfArrayTypeRef>(typeRef))
{
if (arrayTypeRef->mParams.size() == 1)
{
if (auto literalExpr = BfNodeDynCastExact<BfLiteralExpression>(arrayTypeRef->mParams[0]))
{
auto elementType = ResolveTypeRef(arrayTypeRef->mElementType);
if (elementType == NULL)
return NULL;
int count = 1;
if ((literalExpr->mValue.mTypeCode >= BfTypeCode_Int16) && (literalExpr->mValue.mTypeCode <= BfTypeCode_UIntUnknown))
{
count = literalExpr->mValue.mInt32;
if (count < 0)
{
Fail(StrFormat("Illegal array size"), arrayTypeRef->mParams[0]);
count = 1;
}
}
else
{
Fail(StrFormat("Illegal array size type"), arrayTypeRef->mParams[0]);
}
return mDbgModule->GetSizedArrayType(elementType, count);
}
}
}
2021-01-15 14:28:21 -08:00
if (auto declTypeRef = BfNodeDynCastExact<BfExprModTypeRef>(typeRef))
2019-08-23 11:56:54 -07:00
{
mResult = DbgTypedValue();
VisitChild(declTypeRef->mTarget);
auto type = mResult.mType;
mResult = DbgTypedValue();
return type;
}
String name = typeRef->ToString();
if (name.StartsWith("_T_"))
{
int idx = atoi(name.c_str() + 3);
if ((idx >= 0) && (idx < (int)mDbgModule->mTypes.size()))
return mDbgModule->mTypes[idx];
}
auto entry = mDbgModule->mTypeMap.Find(name.c_str(), GetLanguage());
if (entry != NULL)
return FixType(entry->mValue);
if (mExplicitThis)
{
bool isPtr = typeRef->IsA<BfPointerTypeRef>();
if (isPtr)
{
BfPointerTypeRef* ptrTypeRef = (BfPointerTypeRef*)typeRef;
BfTypeReference* innerTypeRef = ptrTypeRef->mElementType;
name = innerTypeRef->ToString();
}
auto checkType = mExplicitThis.mType;
if (checkType->IsPointer())
checkType = checkType->mTypeParam;
ResolveSubTypeRef(checkType, name);
}
auto currentType = GetCurrentType();
if (currentType != NULL)
{
GetNamespaceSearch();
for (auto usingNamespace : mNamespaceSearch)
{
auto usingNamespaceString = usingNamespace->ToString();
entry = mDbgModule->mTypeMap.Find((usingNamespaceString + "." + name).c_str(), GetLanguage());
if (entry != NULL)
return FixType(entry->mValue);
}
}
Fail(StrFormat("Unable to locate type"), typeRef);
return NULL;
}
DbgType* DbgExprEvaluator::ResolveTypeRef(BfAstNode* typeRef, BfAstNode** parentChildRef)
{
StringT<128> name = typeRef->ToString();
if ((name.StartsWith("_T_")) && ((int)name.IndexOf('.') == -1))
{
int endIdx = name.length();
for (int i = 3; i < (int)name.length(); i++)
{
char c = name[i];
if ((c < '0') || (c > '9'))
{
endIdx = i;
break;
}
}
int idx = atoi(name.c_str() + 3);
if ((idx >= 0) && (idx < (int)mDbgModule->mTypes.size()))
{
if ((mExplicitThisExpr != NULL) && (parentChildRef != NULL))
mDeferredInsertExplicitThisVector.push_back(NodeReplaceRecord(typeRef, parentChildRef, true));
DbgType* dbgType = mDbgModule->mTypes[idx];
for (int i = endIdx; i < (int)name.length(); i++)
{
if (name[i] == '*')
dbgType = mDbgModule->GetPointerType(dbgType);
}
return dbgType;
}
}
/*for (int i = 1; i < (int)name.length(); i++)
{
if ((name[i] == ':') && (name[i - 1] == ':'))
{
name[i] = '.';
name.erase(name.begin() + i - 1);
i--;
}
}*/
auto language = GetLanguage();
auto entry = mDbgModule->FindType(name.c_str(), language);
if (entry != NULL)
return entry->mValue;
auto currentType = GetCurrentType();
if (currentType != NULL)
{
GetNamespaceSearch();
for (auto usingNamespace : mNamespaceSearch)
{
auto usingNamespaceString = usingNamespace->ToString();
entry = mDbgModule->FindType((usingNamespaceString + "." + name).c_str(), language);
if (entry != NULL)
return entry->mValue;
}
}
Fail("Unable to locate type", typeRef);
return NULL;
}
DbgType* DbgExprEvaluator::ResolveTypeRef(const StringImpl& typeName)
{
auto entry = mDbgModule->mTypeMap.Find(typeName.c_str(), GetLanguage());
if (entry != NULL)
return entry->mValue;
mPassInstance->Fail("Unable to locate type: " + typeName);
return NULL;
}
bool DbgExprEvaluator::TypeIsSubTypeOf(DbgType* srcType, DbgType* wantType, int* thisOffset, addr_target* thisAddr)
{
if (srcType == NULL)
return false;
srcType = srcType->GetPrimaryType();
wantType = wantType->GetPrimaryType();
if ((wantType->IsPrimitiveType()) && (srcType->IsPrimitiveType()))
{
return wantType->mTypeCode == srcType->mTypeCode;
}
if ((srcType == NULL) || (wantType == NULL))
return false;
if (srcType->Equals(wantType))
return true;
if (srcType->mTypeCode == DbgType_TypeDef)
return TypeIsSubTypeOf(srcType->mTypeParam, wantType);
if (wantType->mTypeCode == DbgType_TypeDef)
return TypeIsSubTypeOf(srcType, wantType->mTypeParam);
srcType->PopulateType();
for (auto srcBaseType : srcType->mBaseTypes)
{
bool isSubtype = TypeIsSubTypeOf(srcBaseType->mBaseType, wantType);
if (isSubtype)
{
if (srcBaseType->mVTableOffset != -1)
{
if (thisAddr == NULL)
return false;
int32 virtThisOffset = 0;
addr_target vtableAddr = 0;
gDebugger->ReadMemory(*thisAddr, sizeof(addr_target), &vtableAddr);
gDebugger->ReadMemory(vtableAddr + srcBaseType->mVTableOffset * sizeof(int32), sizeof(int32), &virtThisOffset);
*thisOffset += virtThisOffset;
}
else if (thisOffset != NULL)
*thisOffset += srcBaseType->mThisOffset;
return true;
}
}
return false;
}
DbgTypedValue DbgExprEvaluator::GetBeefTypeById(int typeId)
{
if (mDebugTarget->mTargetBinary == NULL)
return DbgTypedValue();
if (mDebugTarget->mTargetBinary->mBfTypesInfoAddr == 0)
2019-08-23 11:56:54 -07:00
{
mDebugTarget->mTargetBinary->mBfTypesInfoAddr = -1;
mDebugTarget->mTargetBinary->ParseTypeData();
auto typeTypeEntry = mDebugTarget->mTargetBinary->FindType("System.Type", DbgLanguage_Beef);
if ((typeTypeEntry != NULL) && (typeTypeEntry->mValue != NULL))
2019-08-23 11:56:54 -07:00
{
auto typeType = typeTypeEntry->mValue;
mDebugTarget->mTargetBinary->mBfTypeType = typeType;
if (typeType->mNeedsGlobalsPopulated)
typeType->mCompileUnit->mDbgModule->PopulateTypeGlobals(typeType);
for (auto member : typeType->mMemberList)
{
if ((member->mIsStatic) && (member->mName != NULL) && (strcmp(member->mName, "sTypes") == 0) && (member->mLocationData != NULL))
{
auto stackFrame = GetStackFrame();
DbgAddrType addrType;
mDebugTarget->mTargetBinary->mBfTypesInfoAddr = member->mCompileUnit->mDbgModule->EvaluateLocation(NULL, member->mLocationData, member->mLocationLen, stackFrame, &addrType);
}
}
if (mDebugTarget->mTargetBinary->mBfTypesInfoAddr <= 0)
2019-08-23 11:56:54 -07:00
{
mDebugTarget->mTargetBinary->ParseSymbolData();
2021-02-26 14:54:38 -08:00
auto entry = mDebugTarget->mTargetBinary->mSymbolNameMap.Find(
#ifdef BF_DBG_64
"?sTypes@Type@System@bf@@2PEAPEAV123@A"
#else
"?sTypes@Type@System@bf@@2PAPAV123@A"
#endif
);
if (entry)
mDebugTarget->mTargetBinary->mBfTypesInfoAddr = entry->mValue->mAddress;
2019-08-23 11:56:54 -07:00
}
}
}
if (mDebugTarget->mTargetBinary->mBfTypesInfoAddr > 0)
{
DbgTypedValue typedVal;
typedVal.mType = mDebugTarget->mTargetBinary->mBfTypeType;
addr_target addr = mDebugTarget->mTargetBinary->mBfTypesInfoAddr + typeId * sizeof(addr_target);
typedVal.mSrcAddress = mDebugger->ReadMemory<addr_target>(addr);
return typedVal;
}
2019-08-23 11:56:54 -07:00
return DbgTypedValue();
}
void DbgExprEvaluator::BeefStringToString(addr_target addr, String& outStr)
{
mDebugTarget->GetCompilerSettings();
2019-08-23 11:56:54 -07:00
int objectSize = mDebugTarget->mBfObjectSize;
int32 strLen = 0;
addr_target charPtr = 0;
if (!mDebugTarget->mBfHasLargeStrings)
{
strLen = mDebugger->ReadMemory<int32>(addr + objectSize);
int32 allocSizeAndFlags = mDebugger->ReadMemory<int32>(addr + objectSize + 4);
if ((allocSizeAndFlags & 0x40000000) != 0)
charPtr = mDebugger->ReadMemory<addr_target>(addr + objectSize + 4 + 4);
else
charPtr = addr + objectSize + 4 + 4;
}
else
{
strLen = mDebugger->ReadMemory<int32>(addr + objectSize);
int64 allocSizeAndFlags = mDebugger->ReadMemory<int64>(addr + objectSize + 8);
if ((allocSizeAndFlags & 0x40000000'00000000LL) != 0)
charPtr = mDebugger->ReadMemory<addr_target>(addr + objectSize + 8 + 8);
else
charPtr = addr + objectSize + 4 + 4;
}
2019-08-23 11:56:54 -07:00
if ((strLen > 0) && (strLen < 4096))
{
outStr.Append('?', strLen);
mDebugger->ReadMemory(charPtr, strLen, &outStr[outStr.length() - strLen]);
}
}
void DbgExprEvaluator::BeefStringToString(const DbgTypedValue& val, String& outStr)
{
mDebugTarget->GetCompilerSettings();
auto useVal = val;
if (useVal.mType->IsBfObjectPtr())
{
useVal.mType = useVal.mType->mTypeParam;
useVal.mSrcAddress = useVal.mPtr;
}
BeefStringToString(useVal.mSrcAddress, outStr);
}
void DbgExprEvaluator::BeefTypeToString(const DbgTypedValue& val, String& outStr)
{
if (!val)
return;
mDebugTarget->GetCompilerSettings();
auto useVal = val;
if (useVal.mType->IsBfObjectPtr())
{
useVal.mType = useVal.mType->mTypeParam;
useVal.mSrcAddress = useVal.mPtr;
}
typedef int32 _TypeId;
typedef uint32 _TypeFlags;
typedef int8 _TypeCode;
2020-08-25 07:34:09 -07:00
#pragma pack(push, 1)
2019-08-23 11:56:54 -07:00
struct _Type
{
int32 mSize;
_TypeId mTypeId;
2020-09-14 07:52:08 -07:00
_TypeId mBoxedType;
2019-08-23 11:56:54 -07:00
_TypeFlags mTypeFlags;
int32 mMemberDataOffset;
_TypeCode mTypeCode;
uint8 mAlign;
};
struct _PointerType : _Type
{
2020-08-25 07:34:09 -07:00
int16 mPadding0;
_TypeCode mElementType;
};
2020-07-31 06:16:29 -07:00
struct _SizedArrayType : _Type
{
2020-08-25 07:34:09 -07:00
int16 mPadding0;
2020-07-31 06:16:29 -07:00
_TypeId mElementType;
int32 mElementCount;
};
2019-08-23 11:56:54 -07:00
struct _String
{
};
struct _MethodData
{
};
struct _FieldData
{
};
struct _ClassVData
{
};
struct _TypeInstance : public _Type
{
2020-08-25 07:34:09 -07:00
#ifdef BF_DBG_32
int16 mPadding0;
#else
int16 mPadding0;
#endif
addr_target mTypeClassVData;
addr_target mName;
addr_target mNamespace;
2019-08-23 11:56:54 -07:00
int32 mInstSize;
int32 mInstAlign;
int32 mCustomAttributesIdx;
_TypeId mBaseType;
_TypeId mUnderlyingType;
_TypeId mOuterType;
int32 mInheritanceId;
int32 mInheritanceCount;
2021-02-26 14:54:38 -08:00
uint8 mInterfaceSlot;
2019-08-23 11:56:54 -07:00
uint8 mInterfaceCount;
2021-02-26 14:54:38 -08:00
int16 mInterfaceMethodCount;
2019-08-23 11:56:54 -07:00
int16 mMethodDataCount;
int16 mPropertyDataCount;
2020-07-31 06:16:29 -07:00
int16 mFieldDataCount;
2019-08-23 11:56:54 -07:00
2021-02-26 14:54:38 -08:00
#ifdef BF_DBG_32
int16 mPadding1;
#else
int8 mPadding1[6];
#endif
2020-08-25 07:34:09 -07:00
addr_target mInterfaceDataPtr;
2020-09-14 07:52:08 -07:00
addr_target mInterfaceMethodTable;
2020-08-25 07:34:09 -07:00
addr_target mMethodDataPtr;
addr_target mPropertyDataPtr;
addr_target mFieldDataPtr;
2021-02-26 14:54:38 -08:00
addr_target mCustomAttrDataPtr;
2019-08-23 11:56:54 -07:00
};
2020-07-31 06:16:29 -07:00
struct _SpecializedGenericType : _TypeInstance
{
_TypeId mUnspecializedType;
2020-08-25 07:34:09 -07:00
#ifdef BF_DBG_64
int32 mPadding0;
#endif
addr_target mResolvedTypeRefs;
2020-07-31 06:16:29 -07:00
};
struct _ArrayType : _SpecializedGenericType
{
int32 mElementSize;
uint8 mRank;
uint8 mElemensDataOffset;
};
2020-08-25 07:34:09 -07:00
#pragma pack(pop)
2019-08-23 11:56:54 -07:00
int typeIdSize = sizeof(_TypeId);
int ptrSize = (int)sizeof(addr_target);
int objectSize = mDebugTarget->mBfObjectSize;
int typeSize = sizeof(_Type);
int typeInstanceSize = objectSize + sizeof(_TypeInstance);
2020-07-31 06:16:29 -07:00
2019-08-23 11:56:54 -07:00
auto addr = useVal.mSrcAddress;
auto typeAddr = addr + objectSize;
_TypeFlags typeFlags = mDebugger->ReadMemory<_TypeFlags>(typeAddr + offsetof(_Type, mTypeFlags));
2020-07-31 06:16:29 -07:00
if ((typeFlags & BfTypeFlags_Array) != 0)
{
_TypeId unspecializedTypeId = mDebugger->ReadMemory<_TypeId>(typeAddr + offsetof(_SpecializedGenericType, mUnspecializedType));
addr_target elementsArrayAddr = mDebugger->ReadMemory<addr_target>(typeAddr + offsetof(_SpecializedGenericType, mResolvedTypeRefs));
_TypeId elementTypeId = mDebugger->ReadMemory<_TypeId>(elementsArrayAddr);
auto elementType = GetBeefTypeById(elementTypeId);
BeefTypeToString(elementType, outStr);
outStr += "[";
int rank = mDebugger->ReadMemory<uint8>(typeAddr + offsetof(_ArrayType, mRank));
for (int commaIdx = 0; commaIdx < rank - 1; commaIdx++)
outStr += ",";
outStr += "]";
}
else if ((typeFlags & BfTypeFlags_Pointer) != 0)
{
_TypeId elementTypeId = mDebugger->ReadMemory<_TypeId>(typeAddr + offsetof(_PointerType, mElementType));
auto elementType = GetBeefTypeById(elementTypeId);
BeefTypeToString(elementType, outStr);
2020-08-25 07:34:09 -07:00
outStr += "*";
2020-07-31 06:16:29 -07:00
}
else if ((typeFlags & BfTypeFlags_Delegate) != 0)
{
outStr += "delegate";
}
else if ((typeFlags & BfTypeFlags_Function) != 0)
{
outStr += "function";
}
// else if ((typeFlags & BfTypeFlags_Tuple) != 0)
// {
// outStr += "function";
// }
else if ((typeFlags & BfTypeFlags_SizedArray) != 0)
{
_TypeId elementTypeId = mDebugger->ReadMemory<_TypeId>(typeAddr + objectSize + offsetof(_SizedArrayType, mElementType));
auto elementType = GetBeefTypeById(elementTypeId);
BeefTypeToString(elementType, outStr);
int elementCount = mDebugger->ReadMemory<int32>(typeAddr + objectSize + offsetof(_SizedArrayType, mElementCount));
outStr += StrFormat("[%d]", elementCount);
}
else if (((typeFlags & BfTypeFlags_Struct) != 0) || ((typeFlags & BfTypeFlags_TypedPrimitive) != 0) || ((typeFlags & BfTypeFlags_Object) != 0))
2019-08-23 11:56:54 -07:00
{
2020-08-25 07:34:09 -07:00
addr_target addr0 = typeAddr;
addr_target addr1 = typeAddr + offsetof(_Type, mTypeFlags);
addr_target addr2 = typeAddr + offsetof(_Type, mAlign);
addr_target addr3 = typeAddr + offsetof(_TypeInstance, mPadding0);
addr_target addr4 = typeAddr + offsetof(_TypeInstance, mTypeClassVData);
2019-08-23 11:56:54 -07:00
addr_target namePtr = mDebugger->ReadMemory<addr_target>(typeAddr + offsetof(_TypeInstance, mName));
addr_target namespacePtr = mDebugger->ReadMemory<addr_target>(typeAddr + offsetof(_TypeInstance, mNamespace));
int outerTypeId = mDebugger->ReadMemory<_TypeId>(typeAddr + offsetof(_TypeInstance, mOuterType));
DbgTypedValue outerType;
if (outerTypeId != 0)
{
outerType = GetBeefTypeById(outerTypeId);
BeefTypeToString(outerType, outStr);
outStr += ".";
}
else if (namespacePtr != 0)
{
String namespaceName;
BeefStringToString(namespacePtr, namespaceName);
if (!namespaceName.empty())
{
outStr += namespaceName;
outStr += ".";
}
}
BeefStringToString(namePtr, outStr);
if ((typeFlags & BfTypeFlags_SpecializedGeneric) != 0)
{
int unspecializedTypeId = mDebugger->ReadMemory<_TypeId>(addr + typeInstanceSize);
auto unspecializedType = GetBeefTypeById(unspecializedTypeId);
outStr += "<";
if (unspecializedType)
{
int startGenericIdx = 0;
int genericCount = mDebugger->ReadMemory<uint8>(unspecializedType.mSrcAddress + typeInstanceSize);
if (outerType)
{
int outerUnspecializedTypeId = mDebugger->ReadMemory<_TypeId>(outerType.mSrcAddress + typeInstanceSize);
auto outerUnspecializedType = GetBeefTypeById(outerUnspecializedTypeId);
startGenericIdx = mDebugger->ReadMemory<uint8>(outerUnspecializedType.mSrcAddress + typeInstanceSize);
}
addr_target genericParamsPtr = mDebugger->ReadMemory<addr_target>(addr + BF_ALIGN(typeInstanceSize + typeIdSize, ptrSize));
for (int i = startGenericIdx; i < genericCount; i++)
{
int genericParamTypeId = mDebugger->ReadMemory<_TypeId>(genericParamsPtr + i * typeIdSize);
if (i > startGenericIdx)
outStr += ", ";
BeefTypeToString(GetBeefTypeById(genericParamTypeId), outStr);
}
}
outStr += ">";
}
}
else
{
BfTypeCode typeCode = (BfTypeCode)mDebugger->ReadMemory<uint8>(typeAddr + (int)offsetof(_Type, mTypeCode));
if (typeCode == BfTypeCode_Pointer)
{
_TypeId elementType = mDebugger->ReadMemory<_TypeId>(typeAddr + offsetof(_PointerType, mElementType));
BeefTypeToString(GetBeefTypeById(elementType), outStr);
outStr += "*";
return;
}
2019-08-23 11:56:54 -07:00
switch (typeCode)
{
case BfTypeCode_None: outStr += "void"; break;
case BfTypeCode_CharPtr: outStr += "char8*"; break;
case BfTypeCode_Pointer: outStr += "*"; break;
case BfTypeCode_NullPtr: outStr += ""; break;
case BfTypeCode_Var: outStr += "var"; break;
case BfTypeCode_Let: outStr += "let"; break;
case BfTypeCode_Boolean: outStr += "bool"; break;
case BfTypeCode_Int8: outStr += "int8"; break;
case BfTypeCode_UInt8: outStr += "uint8"; break;
case BfTypeCode_Int16: outStr += "int16"; break;
case BfTypeCode_UInt16: outStr += "uint16"; break;
case BfTypeCode_Int32: outStr += "int32"; break;
case BfTypeCode_UInt32: outStr += "uint32"; break;
case BfTypeCode_Int64: outStr += "int64"; break;
case BfTypeCode_UInt64: outStr += "uint64"; break;
case BfTypeCode_IntPtr: outStr += "int"; break;
case BfTypeCode_UIntPtr: outStr += "uint"; break;
case BfTypeCode_IntUnknown: outStr += "int unknown"; break;
case BfTypeCode_UIntUnknown: outStr += "uint unknown"; break;
case BfTypeCode_Char8: outStr += "char8"; break;
case BfTypeCode_Char16: outStr += "char16"; break;
case BfTypeCode_Char32: outStr += "char32"; break;
case BfTypeCode_Float: outStr += "float"; break;
2019-08-23 11:56:54 -07:00
case BfTypeCode_Double: outStr += "double"; break;
}
}
}
CPUStackFrame* DbgExprEvaluator::GetStackFrame()
{
if (mIsEmptyTarget)
return NULL;
static CPUStackFrame emptyStackFrame;
if (mCallStackIdx == -1)
return &emptyStackFrame;
if (mDebugger->mRunState == RunState_NotStarted)
return &emptyStackFrame;
if (mDebugger->mCallStack.size() == 0)
mDebugger->UpdateCallStack();
if (mCallStackIdx >= (int)mDebugger->mCallStack.size())
return &emptyStackFrame;
return mDebugger->mCallStack[mCallStackIdx];
}
CPURegisters* DbgExprEvaluator::GetRegisters()
{
if (mIsEmptyTarget)
return NULL;
auto stackFrame = GetStackFrame();
if (stackFrame != NULL)
return &stackFrame->mRegisters;
return NULL;
}
DbgTypedValue DbgExprEvaluator::GetRegister(const StringImpl& regName)
{
if (mIsEmptyTarget)
return DbgTypedValue();
if (!mDebugger->mIsRunning)
return DbgTypedValue();
Array<RegForm>* regForms = NULL;
if (mCallStackIdx != -1)
{
if (mCallStackIdx < (int)mDebugger->mCallStack.size())
regForms = &mDebugger->mCallStack[mCallStackIdx]->mRegForms;
}
DbgTypedValue result = mDebugger->GetRegister(regName, GetLanguage(), GetRegisters(), regForms);
if ((result) && (mReferenceId != NULL))
{
int regNum = CPURegisters::GetCompositeRegister(result.mRegNum);
const char* regName = CPURegisters::GetRegisterName(regNum);
if (regName != NULL)
*mReferenceId = String("$") + regName;
}
return result;
}
DbgSubprogram* DbgExprEvaluator::GetCurrentMethod()
{
if (mIsEmptyTarget)
return NULL;
if (!mDebugger->mIsRunning)
return NULL;
if (mCallStackIdx == -1)
return NULL;
mDebugger->UpdateCallStackMethod(mCallStackIdx);
if (mCallStackIdx >= (int)mDebugger->mCallStack.size())
return NULL;
auto callStack = mDebugger->mCallStack[mCallStackIdx];
auto subProgram = callStack->mSubProgram;
if (subProgram != NULL)
subProgram->PopulateSubprogram();
return subProgram;
}
DbgType* DbgExprEvaluator::GetCurrentType()
{
auto curMethod = GetCurrentMethod();
if (curMethod != NULL)
return curMethod->mParentType;
return NULL;
}
DbgTypedValue DbgExprEvaluator::GetThis()
{
if (mExplicitThis)
return mExplicitThis;
String findName = "this";
CPUStackFrame* stackFrame = GetStackFrame();
if (stackFrame != NULL)
{
intptr valAddr;
DbgType* valType;
DbgAddrType addrType = DbgAddrType_Value;
if (mDebugTarget->GetValueByName(GetCurrentMethod(), findName, stackFrame, &valAddr, &valType, &addrType))
{
//valType = valType->RemoveModifiers();
return FixThis(ReadTypedValue(NULL, valType, valAddr, addrType));
2019-08-23 11:56:54 -07:00
}
if (mDebugTarget->GetValueByName(GetCurrentMethod(), "__closure", stackFrame, &valAddr, &valType, &addrType))
{
DbgTypedValue result = ReadTypedValue(NULL, valType, valAddr, addrType);
2019-08-23 11:56:54 -07:00
if (!result)
return result;
SetAndRestoreValue<bool> prevIgnoreError(mIgnoreErrors, true);
return FixThis(LookupField(NULL, result, "__this"));
}
}
return DbgTypedValue();
}
DbgTypedValue DbgExprEvaluator::GetDefaultTypedValue(DbgType* srcType)
{
DbgTypedValue typedValue;
typedValue.mType = srcType;
return typedValue;
}
String DbgExprEvaluator::TypeToString(DbgType* type)
{
return type->ToString();
}
bool DbgExprEvaluator::CheckHasValue(DbgTypedValue typedValue, BfAstNode* refNode)
{
if ((!typedValue) && (typedValue.mType != NULL))
{
mResult = DbgTypedValue();
Fail("Value required", refNode);
return false;
}
return true;
}
//TODO: Expand this
bool DbgExprEvaluator::CanCast(DbgTypedValue typedVal, DbgType* toType, BfCastFlags castFlags)
2019-08-23 11:56:54 -07:00
{
DbgType* fromType = typedVal.mType;
if (fromType == toType)
return true;
if ((fromType->IsConst()) && (!toType->IsConst()))
return false;
fromType = fromType->RemoveModifiers();
toType = toType->RemoveModifiers();
// Ptr -> const Ptr
if ((fromType->IsPointer()) && (toType->IsPointer()))
{
if (toType->mTypeParam->IsConst())
{
auto primaryFrom = fromType->mTypeParam->GetPrimaryType();
auto primaryTo = toType->mTypeParam->mTypeParam->GetPrimaryType();
if ((primaryFrom->IsCompositeType()) || (primaryTo->IsCompositeType()))
{
if (primaryFrom == primaryTo)
return true;
}
else if (primaryFrom->IsPrimitiveType())
{
return primaryFrom->mTypeCode == primaryTo->mTypeCode;
}
}
}
if ((fromType->IsCompositeType()) && ((toType->IsCompositeType() || (toType->IsInterface()))))
{
bool allowCast = false;
//TODO: Allow explicit interface casts on any object
//TODO: Insert cast checking code
int thisOffset = 0;
addr_target thisVal = typedVal.mSrcAddress;
if (TypeIsSubTypeOf(fromType, toType, &thisOffset, &thisVal))
{
return true;
}
}
if ((fromType->IsPrimitiveType()) && (toType->IsPrimitiveType()))
{
DbgTypeCode fromTypeCode = fromType->mTypeCode;
DbgTypeCode toTypeCode = toType->mTypeCode;
if ((fromTypeCode == toTypeCode))
return true;
// Must be from a default int to do an implicit constant cast, not casted by user, ie: (ushort)123
if ((toType->IsInteger()) /*&& (typedVal.mValue != NULL) && (fromTypeCode == DbgType_i32)*/)
{
// Allow constant ints to be implicitly downcasted if they fit
if (typedVal.mIsLiteral)
{
int64 srcVal = typedVal.GetInt64();
if (toType->IsSigned())
{
int64 minVal = -(1LL << (8 * toType->mSize - 1));
int64 maxVal = (1LL << (8 * toType->mSize - 1)) - 1;
if ((srcVal >= minVal) && (srcVal <= maxVal))
return true;
}
else if (toType->mSize == 8) // ulong
{
if (srcVal > 0)
return true;
}
else
{
int64 minVal = 0;
int64 maxVal = (1LL << (8 * toType->mSize)) - 1;
if ((srcVal >= minVal) && (srcVal <= maxVal))
return true;
}
}
}
switch (toTypeCode)
{
case DbgType_u8:
case DbgType_UChar:
switch (fromTypeCode)
{
case DbgType_UChar:
case DbgType_u8:
return true;
}
break;
case DbgType_SChar16:
case DbgType_i16:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_SChar:
case DbgType_SChar16:
return true;
case DbgType_u8:
case DbgType_UChar:
return true;
}
break;
case DbgType_u16:
switch (fromTypeCode)
{
case DbgType_i8:
return true;
case DbgType_u8:
case DbgType_UChar:
case DbgType_UChar16:
return true;
}
break;
case DbgType_SChar32:
case DbgType_i32:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
return true;
case DbgType_u8:
case DbgType_u16:
case DbgType_UChar:
case DbgType_UChar16:
return true;
}
break;
case DbgType_UChar32:
case DbgType_u32:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_SChar:
case DbgType_SChar16:
return true;
case DbgType_u8:
case DbgType_u16:
case DbgType_u32:
case DbgType_UChar:
case DbgType_UChar16:
case DbgType_UChar32:
return true;
}
break;
case DbgType_i64:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_i32:
case DbgType_i64:
case DbgType_SChar:
case DbgType_SChar16:
case DbgType_SChar32:
return true;
case DbgType_u8:
case DbgType_u16:
case DbgType_u32:
case DbgType_UChar:
case DbgType_UChar16:
case DbgType_UChar32:
return true;
}
break;
case DbgType_u64:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_i32:
case DbgType_SChar:
case DbgType_SChar16:
case DbgType_SChar32:
return true;
case DbgType_u8:
case DbgType_u16:
case DbgType_u32:
case DbgType_UChar:
case DbgType_UChar32:
return true;
}
break;
case DbgType_Single:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_i32:
return true;
case DbgType_u8:
case DbgType_u16:
case DbgType_u32:
case DbgType_UChar:
case DbgType_UChar32:
return true;
}
break;
case DbgType_Double:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_i32:
case DbgType_i64:
case DbgType_SChar:
case DbgType_SChar16:
case DbgType_SChar32:
return true;
case DbgType_u8:
case DbgType_u16:
case DbgType_u32:
case DbgType_UChar:
case DbgType_UChar16:
case DbgType_UChar32:
return true;
case DbgType_Single:
return true;
}
break;
}
}
return false;
}
DbgTypedValue DbgExprEvaluator::Cast(BfAstNode* srcNode, const DbgTypedValue& typedVal, DbgType* toType, bool explicitCast, bool silentFail)
{
if (!typedVal)
return typedVal;
DbgType* fromType = typedVal.mType;
fromType = fromType->RemoveModifiers();
toType = toType->RemoveModifiers();
fromType = fromType->GetPrimaryType();
toType = toType->GetPrimaryType();
2020-01-30 07:03:27 -08:00
if ((toType->IsBfObject()) && (fromType->IsPointer()))
toType = toType->GetDbgModule()->GetPointerType(toType);
2019-08-23 11:56:54 -07:00
if (toType->IsPrimitiveType())
{
if (fromType->mTypeCode == toType->mTypeCode)
return typedVal;
2019-11-07 06:52:03 -08:00
if ((fromType->IsStruct()) || (fromType->IsEnum()))
{
if (fromType->mTypeParam != NULL)
2019-08-23 11:56:54 -07:00
{
2019-11-07 06:52:03 -08:00
DbgTypedValue underlyingTypedValue = typedVal;
underlyingTypedValue.mType = fromType->mTypeParam;
auto castedVal = Cast(srcNode, underlyingTypedValue, toType, explicitCast, true);
if (castedVal)
return castedVal;
2019-08-23 11:56:54 -07:00
}
2019-11-07 06:52:03 -08:00
}
2019-08-23 11:56:54 -07:00
}
2019-11-07 06:52:03 -08:00
2019-08-23 11:56:54 -07:00
if (fromType == toType)
return typedVal;
if ((fromType->mTypeCode == DbgType_Null) &&
(toType->mTypeCode == DbgType_Ptr))
{
DbgTypedValue val;
val.mPtr = typedVal.mPtr;
val.mType = toType;
return val;
}
auto curTypeInstance = GetCurrentType();
if ((fromType->IsCompositeType()) && ((toType->IsCompositeType() || (toType->IsInterface()))))
{
bool allowCast = false;
//TODO: Allow explicit interface casts on any object
//TODO: Insert cast checking code
int thisOffset = 0;
addr_target thisVal = typedVal.mSrcAddress;
if (TypeIsSubTypeOf(fromType, toType, &thisOffset, &thisVal))
{
allowCast = true;
}
else if ((explicitCast) && ((toType->IsInterface()) || (TypeIsSubTypeOf(toType, fromType, &thisOffset))))
{
thisOffset = -thisOffset;
allowCast = true;
}
if (fromType->IsBfPayloadEnum())
{
if (!allowCast)
{
for (auto member : fromType->mMemberList)
{
if (member->mType->Equals(toType))
{
allowCast = true;
break;
}
}
}
}
if (allowCast)
{
DbgTypedValue val;
//val.mPtr = typedVal.mPtr + thisOffset;
val.mInt64 = typedVal.mInt64;
val.mSrcAddress = thisVal + thisOffset;
val.mType = toType;
// Doing this allows us to modify a typed value that is tied to a register through its '[base]'
if ((typedVal.mRegNum != -1) && (val.mType->GetByteCount() == typedVal.mType->GetByteCount()))
val.mRegNum = typedVal.mRegNum;
return val;
}
}
// Payload discriminator
if ((fromType->IsBfPayloadEnum()) && (toType->IsInteger()))
{
intptr valAddr;
DbgType* valType;
DbgAddrType addrType = DbgAddrType_Value;
String findName = "$";
//BF_ASSERT(typedVal.mVariable != NULL);
if (typedVal.mVariable != NULL)
findName += typedVal.mVariable->mName;
findName += "$d";
if (mDebugTarget->GetValueByName(GetCurrentMethod(), findName, GetStackFrame(), &valAddr, &valType, &addrType))
{
return ReadTypedValue(srcNode, valType, valAddr, addrType);
2019-08-23 11:56:54 -07:00
}
}
// Optimized composite - probably stored in register
if ((toType->IsCompositeType()) && (fromType->IsInteger()) && (explicitCast))
{
if (toType->GetByteCount() <= 8)
{
DbgTypedValue val;
val.mType = toType;
val.mInt64 = typedVal.mInt64;
val.mSrcAddress = typedVal.mSrcAddress;
return val;
}
}
// Ptr -> const Ptr
if ((fromType->IsPointer()) && (toType->IsPointer()))
{
if (toType->mTypeParam->IsConst())
{
bool canCast = false;
auto primaryFrom = fromType->mTypeParam->GetPrimaryType();
auto primaryTo = toType->mTypeParam->mTypeParam->GetPrimaryType();
if ((primaryFrom->IsCompositeType()) || (primaryTo->IsCompositeType()))
{
if (primaryFrom == primaryTo)
canCast = true;
}
else if (primaryFrom->IsPrimitiveType())
{
canCast = primaryFrom->mTypeCode == primaryTo->mTypeCode;
}
if (canCast)
{
DbgTypedValue val = typedVal;
val.mType = toType;
return val;
}
}
}
if ((fromType->IsPointer()) && (fromType->mTypeParam->IsCompositeType()) &&
(toType->IsPointer()) && (toType->mTypeParam->IsCompositeType()))
{
auto fromInnerType = fromType->mTypeParam->RemoveModifiers();
auto toInnerType = toType->mTypeParam->RemoveModifiers();
/*DbgTypedValue fromVal;
fromVal.mType = fromInnerTytpe;
fromVal.mSrcAddress = typedVal.mPtr;
DbgTypedValue toVal = Cast(srcNode, fromVal, toInnerType, explicitCast, silentFail);
if (toVal)
{
// Back to pointer form
toVal.mType = toType;
toVal.mPtr = toVal.mSrcAddress;
toVal.mSrcAddress = 0;
}
return toVal;*/
bool allowCast = false;
//TODO: Allow explicit interface casts on any object
//TODO: Insert cast checking code
int thisOffset = 0;
addr_target thisVal = typedVal.mSrcAddress;
if (TypeIsSubTypeOf(fromInnerType, toInnerType, &thisOffset, &thisVal))
{
allowCast = true;
}
else if ((explicitCast) && ((toInnerType->IsInterface()) || (TypeIsSubTypeOf(toInnerType, fromInnerType, &thisOffset))))
{
thisOffset = -thisOffset;
allowCast = true;
}
if (allowCast)
{
DbgTypedValue toVal;
toVal.mType = toType;
toVal.mPtr = typedVal.mPtr + thisOffset;
toVal.mSrcAddress = 0;
return toVal;
}
}
// IFace -> object|IFace
if ((fromType->IsInterface()) ||
((fromType->IsPointer()) && (fromType->mTypeParam->IsInterface())))
{
if (toType->IsBfObject())
{
DbgTypedValue val;
val.mPtr = typedVal.GetPointer();
val.mType = toType;
return val;
}
}
// Int|Ptr|Arr -> Int|Ptr|Arr
if (((fromType->IsInteger()) || (fromType->IsPointer()) || (fromType->IsSizedArray())) &&
((toType->IsInteger()) || (toType->IsPointer()) || (toType->IsSizedArray())))
{
bool allowCast = explicitCast;
if (allowCast)
{
DbgTypedValue val;
if (toType->IsSizedArray())
val.mSrcAddress = typedVal.GetPointer();
else
val.mPtr = typedVal.GetPointer();
val.mType = toType;
return val;
}
}
// Enum -> Int
if ((((fromType->IsBfEnum()) || (fromType->IsEnum())) && (toType->IsInteger())) &&
((explicitCast) || (fromType == curTypeInstance)))
{
DbgTypedValue result = typedVal;
result.mType = toType;
return result;
}
// Int -> Enum
if (((fromType->IsInteger()) && ((toType->IsBfEnum()) || (toType->IsEnum()))) &&
((explicitCast) || (toType == curTypeInstance)))
{
DbgTypedValue result = typedVal;
result.mType = toType;
return result;
}
// TypedPrimitive -> Primitive
if ((fromType->IsTypedPrimitive()) && (toType->IsPrimitiveType()))
{
DbgTypedValue fromValue = typedVal;
fromValue.mType = fromType->GetBaseType();
return Cast(srcNode, fromValue, toType, explicitCast);
}
// TypedPrimitive -> TypedPrimitive
if ((fromType->IsTypedPrimitive()) && (toType->IsTypedPrimitive()))
{
DbgTypedValue fromValue = typedVal;
fromValue.mType = fromType->GetBaseType();
DbgTypedValue primTypedVal = Cast(srcNode, fromValue, toType->GetBaseType(), explicitCast, silentFail);
if (primTypedVal)
{
primTypedVal.mType = toType;
return primTypedVal;
}
}
// Primitive -> TypedPrimitive
if ((fromType->IsPrimitiveType()) && (toType->IsTypedPrimitive()))
{
DbgTypedValue primTypedVal = Cast(srcNode, typedVal, toType->GetBaseType(), true);
if (primTypedVal)
{
primTypedVal.mType = toType;
return primTypedVal;
}
}
if ((fromType->IsPrimitiveType()) && (toType->IsPrimitiveType()))
{
DbgTypeCode fromTypeCode = fromType->mTypeCode;
DbgTypeCode toTypeCode = toType->mTypeCode;
if ((toType->IsInteger()) && (fromType->IsIntegral()))
{
// Allow constant ints to be implicitly shrunk if they fit
if (typedVal.mIsLiteral)
{
int64 srcVal = typedVal.GetInt64();
/*if (toType->IsSigned())
{
int64 minVal = -(1LL << (8 * toType->mSize - 1));
int64 maxVal = (1LL << (8 * toType->mSize - 1)) - 1;
if ((srcVal >= minVal) && (srcVal <= maxVal))
explicitCast = true;
}
else if (toType->mSize == 8) // ulong
{
if (srcVal > 0)
explicitCast = true;
}
else
{
int64 minVal = 0;
int64 maxVal = (1LL << (8 * toType->mSize)) - 1;
if ((srcVal >= minVal) && (srcVal <= maxVal))
explicitCast = true;
}*/
if (toType->IsChar())
{
if (srcVal == 0)
explicitCast = true;
}
else if ((fromType->IsChar()) && (!toType->IsChar()))
{
// Never allow this
}
else if ((fromTypeCode == BfTypeCode_UInt64) && (srcVal < 0))
{
// There's nothing that this could fit into
}
else if (toType->IsSigned())
{
int64 minVal = -(1LL << (8 * toType->mSize - 1));
int64 maxVal = (1LL << (8 * toType->mSize - 1)) - 1;
if ((srcVal >= minVal) && (srcVal <= maxVal))
explicitCast = true;
}
else if (toType->mSize == 8) // ulong
{
if (srcVal >= 0)
explicitCast = true;
}
else
{
int64 minVal = 0;
int64 maxVal = (1LL << (8 * toType->mSize)) - 1;
if ((srcVal >= minVal) && (srcVal <= maxVal))
explicitCast = true;
}
}
}
DbgTypedValue result;
result.mType = toType;
if (((fromType->IsInteger()) || (fromType->IsChar())) &&
(toType->IsInteger()) || (toType->IsChar()))
{
result.mInt64 = typedVal.GetInt64();
if (explicitCast)
return result;
}
switch (toTypeCode)
{
case DbgType_u8:
case DbgType_UChar:
switch (fromTypeCode)
{
case DbgType_u8:
case DbgType_UChar:
return result;
}
break;
case DbgType_i16:
case DbgType_SChar16:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_SChar:
case DbgType_SChar16:
return result;
case DbgType_u8:
case DbgType_UChar:
return result;
}
break;
case DbgType_u16:
case DbgType_UChar16:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_SChar:
return result;
case DbgType_u8:
case DbgType_UChar:
return result;
}
break;
case DbgType_i32:
case DbgType_SChar32:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_i32:
case DbgType_SChar:
case DbgType_SChar16:
case DbgType_SChar32:
return result;
case DbgType_u8:
case DbgType_u16:
case DbgType_UChar:
case DbgType_UChar16:
return result;
}
break;
case DbgType_UChar32:
case DbgType_u32:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_SChar:
case DbgType_SChar16:
return result;
case DbgType_u8:
case DbgType_u16:
case DbgType_u32:
case DbgType_UChar:
case DbgType_UChar16:
case DbgType_UChar32:
return result;
}
break;
case DbgType_i64:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_i32:
case DbgType_SChar:
case DbgType_SChar16:
case DbgType_SChar32:
return result;
case DbgType_u8:
case DbgType_u16:
case DbgType_u32:
case DbgType_UChar:
case DbgType_UChar16:
case DbgType_UChar32:
return result;
}
break;
case DbgType_u64:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_i32:
case DbgType_SChar:
case DbgType_SChar16:
case DbgType_SChar32:
return result;
case DbgType_u8:
case DbgType_u16:
case DbgType_u32:
case DbgType_UChar:
case DbgType_UChar32:
return result;
}
break;
case DbgType_Single:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_i32:
case DbgType_i64:
case DbgType_SChar:
case DbgType_SChar16:
case DbgType_SChar32:
result.mSingle = typedVal.GetInt64();
return result;
case DbgType_u8:
case DbgType_u16:
case DbgType_u32:
case DbgType_u64:
case DbgType_UChar:
case DbgType_UChar16:
case DbgType_UChar32:
result.mSingle = typedVal.GetInt64();
return result;
}
break;
case DbgType_Double:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_i32:
case DbgType_i64:
case DbgType_SChar:
case DbgType_SChar16:
case DbgType_SChar32:
result.mDouble = typedVal.GetInt64();
return result;
case DbgType_u8:
case DbgType_u16:
case DbgType_u32:
case DbgType_u64:
case DbgType_UChar:
case DbgType_UChar16:
case DbgType_UChar32:
result.mDouble = typedVal.GetInt64();
return result;
case DbgType_Single:
result.mDouble = typedVal.mSingle;
return result;
}
break;
}
if (explicitCast)
{
if (toType->IsInteger())
{
if (typedVal.mType->IsInteger())
{
return result;
}
else if (typedVal.mType->IsFloat())
{
if (typedVal.mType->mTypeCode == DbgType_Single)
result.mInt64 = typedVal.mSingle;
else
result.mInt64 = (int64)typedVal.mDouble;
return result;
}
}
switch (toTypeCode)
{
case DbgType_Single:
switch (fromTypeCode)
{
case DbgType_i8:
case DbgType_i16:
case DbgType_i32:
case DbgType_SChar:
case DbgType_SChar16:
case DbgType_SChar32:
result.mSingle = (float)typedVal.GetInt64();
return result;
case DbgType_u8:
case DbgType_u16:
case DbgType_u32:
case DbgType_UChar:
case DbgType_UChar16:
case DbgType_UChar32:
result.mSingle = (float)typedVal.GetInt64();
return result;
case DbgType_Double:
result.mSingle = (float)typedVal.mDouble;
return result;
}
break;
}
}
}
if (fromType->mTypeCode == DbgType_TypeDef)
{
DbgTypedValue realTypedVal = typedVal;
realTypedVal.mType = fromType->mTypeParam;
return Cast(srcNode, realTypedVal, toType, explicitCast, silentFail);
}
if (toType->mTypeCode == DbgType_TypeDef)
return Cast(srcNode, typedVal, toType->mTypeParam, explicitCast, silentFail);
if (!silentFail)
{
auto language = GetLanguage();
const char* errStr = explicitCast ?
"Unable to cast '%s' to '%s'" :
"Unable to implicitly cast '%s' to '%s'";
Fail(StrFormat(errStr, fromType->ToString(language).c_str(), toType->ToString(language).c_str()), srcNode);
}
return DbgTypedValue();
}
bool DbgExprEvaluator::HasField(DbgType* curCheckType, const StringImpl& fieldName)
{
curCheckType = curCheckType->RemoveModifiers();
curCheckType = curCheckType->GetPrimaryType();
curCheckType->PopulateType();
for (auto checkMember : curCheckType->mMemberList)
{
if (checkMember->mName == NULL)
{
auto checkResult = HasField(checkMember->mType, fieldName);
if (checkResult)
return checkResult;
}
else if (checkMember->mName == fieldName)
return true;
}
for (auto baseTypeEntry : curCheckType->mBaseTypes)
{
auto baseType = baseTypeEntry->mBaseType;
auto result = HasField(baseType, fieldName);
if (result)
return result;
}
//if (wantsStatic)
{
// Look for statics in anonymous inner classes
for (auto checkSubType : curCheckType->mSubTypeList)
{
if (checkSubType->mTypeName == NULL)
{
auto result = HasField(checkSubType, fieldName);
if (result)
return result;
}
}
for (auto altType : curCheckType->mAlternates)
{
auto result = HasField(altType, fieldName);
if (result)
return result;
}
}
return false;
}
DbgTypedValue DbgExprEvaluator::DoLookupField(BfAstNode* targetSrc, DbgTypedValue target, DbgType* curCheckType, const StringImpl& fieldName, CPUStackFrame* stackFrame, bool allowImplicitThis)
2020-01-31 17:16:44 -08:00
{
2019-08-23 11:56:54 -07:00
bool wantsStatic = (!target) || (target.mHasNoValue);
auto flavor = GetFlavor();
auto language = GetLanguage();
if (language != DbgLanguage_Beef)
{
// C allows static lookups by non-static member reference
wantsStatic = true;
}
curCheckType = curCheckType->RemoveModifiers();
curCheckType = curCheckType->GetPrimaryType();
curCheckType->PopulateType();
//BfLogDbgExpr("DoLookupField %s %s Priority=%d\n", fieldName.c_str(), curCheckType->mName, curCheckType->mPriority);
if ((curCheckType->mNeedsGlobalsPopulated) && ((curCheckType->IsNamespace()) || (curCheckType->IsRoot())))
{
// Global variables don't show up in any type declaration like static fields do, so we need to populate here
mDbgModule->PopulateTypeGlobals(curCheckType);
}
/*auto checkMember = curCheckType->mMemberList.mHead;
while (checkMember != NULL)*/
String findFieldName = fieldName;
if ((language == DbgLanguage_Beef) && (flavor == DbgFlavor_MS) && (target.mHasNoValue))
{
//if ((curCheckType->IsRoot()) || (curCheckType->IsNamespace()))
//findFieldName.insert(0, "bf__");
}
//for (auto checkMember : curCheckType->mMemberList)
auto nextMember = curCheckType->mMemberList.mHead;
while (nextMember != NULL)
{
auto checkMember = nextMember;
nextMember = checkMember->mNext;
if (checkMember->mName == NULL)
{
//TODO: Check inside anonymous type
DbgTypedValue innerTarget;
addr_target targetPtr = target.mSrcAddress;
if ((target.mType != NULL) && (target.mType->HasPointer()))
targetPtr = target.mPtr;
innerTarget.mSrcAddress = targetPtr + checkMember->mMemberOffset;
/*if (target.mPtr != 0)
innerTarget.mPtr = target.mPtr + checkMember->mMemberOffset;*/
innerTarget.mType = checkMember->mType;
auto checkResult = LookupField(targetSrc, innerTarget, fieldName);
if (checkResult)
return checkResult;
}
else if (checkMember->mName == findFieldName)
{
//BfLogDbgExpr(" Got Match\n");
//TODO:
/*if (field->mIsConst)
{
if (fieldInstance->mStaticValue == NULL)
mModule->ResolveConstField(curCheckType, field);
return DbgTypedValue(fieldInstance->mStaticValue, fieldInstance->mType);
}*/
//checkMember->mMemberOffset
if (mReferenceId != NULL)
{
if (curCheckType->IsRoot())
*mReferenceId = fieldName;
else if (curCheckType->IsEnum())
*mReferenceId = curCheckType->ToString();
else
*mReferenceId = curCheckType->ToString() + "." + fieldName;
}
if ((checkMember->mLocationLen == 0) && (checkMember->mIsStatic) && (!checkMember->mIsConst))
{
if (checkMember->mCompileUnit->mDbgModule->mDbgFlavor == DbgFlavor_MS)
{
if (curCheckType->mNeedsGlobalsPopulated)
{
mDbgModule->PopulateTypeGlobals(curCheckType);
return DoLookupField(targetSrc, target, curCheckType, fieldName, stackFrame, allowImplicitThis);
}
/*String memberName = curCheckType->ToString() + "::" + checkMember->mName;
mDbgModule->ParseSymbolData();
auto entry = mDbgModule->mSymbolNameMap.Find(memberName.c_str());
if (entry != NULL)
{
auto sym = entry->mValue;
int locLen = 1 + sizeof(addr_target);
uint8* locData = checkMember->mCompileUnit->mDbgModule->mAlloc.AllocBytes(locLen);
locData[0] = DW_OP_addr_noRemap;
*((addr_target*)(locData + 1)) = sym->mAddress;
checkMember->mLocationData = locData;
checkMember->mLocationLen = locLen;
}
else
{
BF_ASSERT("Static field not found" == 0);
}*/
}
else
{
continue;
//BF_FATAL("Unhandled");
//TODO: Is this needed anymore since we have 'primary types'?
/*auto altType = mDebugTarget->FindType(target.mType->ToString(true));
if (altType != NULL)
{
auto altChildNode = altType->mAlternates.mHead;
while ((altType != NULL) && (checkMember->mLocationLen == 0))
{
for (auto altMember : altType->mMemberList)
{
if (strcmp(altMember->mName, checkMember->mName))
{
if (altMember->mLocationData != NULL)
{
checkMember->mLinkName = altMember->mLinkName;
checkMember->mLocationData = altMember->mLocationData;
checkMember->mLocationLen = altMember->mLocationLen;
break;
}
}
}
if (altChildNode != NULL)
{
altType = altChildNode->mValue;
altChildNode = altChildNode->mNext;
}
else
break;
}
}*/
}
}
if (checkMember->mLocationLen != 0)
{
DbgAddrType addrType;
intptr valAddr = checkMember->mCompileUnit->mDbgModule->EvaluateLocation(NULL, checkMember->mLocationData, checkMember->mLocationLen, stackFrame, &addrType);
2019-08-23 11:56:54 -07:00
if ((language == DbgLanguage_Beef) && (checkMember->mType->IsConst()) && (checkMember->mType->mTypeParam->IsSizedArray()))
{
// We need an extra deref
valAddr = mDebugger->ReadMemory<addr_target>(valAddr);
}
if (checkMember->mIsConst)
addrType = DbgAddrType_Value;
return ReadTypedValue(targetSrc, checkMember->mType, valAddr, addrType);
2019-08-23 11:56:54 -07:00
}
else if (checkMember->mIsConst)
{
return ReadTypedValue(targetSrc, checkMember->mType, (uint64)&checkMember->mConstValue, DbgAddrType_Local);
2019-08-23 11:56:54 -07:00
}
else if (checkMember->mIsStatic)
{
if (curCheckType->mNeedsGlobalsPopulated)
{
mDbgModule->PopulateTypeGlobals(curCheckType);
nextMember = curCheckType->mMemberList.mHead;
continue;
}
Fail("Static variable not found, may have be optimized out", targetSrc);
2020-04-14 11:35:54 -07:00
//BfLogDbgExpr(" Static variable optimized out\n");
2019-08-23 11:56:54 -07:00
}
else
{
if ((allowImplicitThis) && (target.mPtr == 0))
target = GetThis();
if (!target)
{
Fail("Cannot reference a non-static member from a static method", targetSrc);
return DbgTypedValue();
}
addr_target targetPtr = target.mSrcAddress;
DbgTypedValue typedValue;
if (targetPtr == -1)
{
LookupSplatMember(target, fieldName);
typedValue = mResult;
mResult = DbgTypedValue();
}
else if ((targetPtr == 0) && (target.mPtr != 0) && (!target.mType->HasPointer()))
{
typedValue = ReadTypedValue(targetSrc, checkMember->mType, (uint64)&target.mPtr + checkMember->mMemberOffset, DbgAddrType_Local);
2019-08-23 11:56:54 -07:00
}
else
{
if (target.mType->HasPointer())
targetPtr = target.mPtr;
typedValue = ReadTypedValue(targetSrc, checkMember->mType, targetPtr + checkMember->mMemberOffset, DbgAddrType_Target);
2019-08-23 11:56:54 -07:00
}
if (checkMember->mBitSize != 0)
{
int expectedShift = (checkMember->mType->mSize * 8) - checkMember->mBitSize;
int shift = expectedShift - checkMember->mBitOffset;
typedValue.mUInt64 = typedValue.mUInt64 >> shift;
uint64 mask = 0;
for (int i = 0; i < checkMember->mBitSize; i++)
mask |= (1ULL << i);
typedValue.mUInt64 &= mask;
if ((checkMember->mType->IsSigned()) && ((typedValue.mUInt64 & (1LL << (checkMember->mBitSize - 1))) != 0))
{
// Sign extend
typedValue.mUInt64 |= ~mask;
}
}
return typedValue;
}
}
//checkMember = checkMember->mNext;
}
BF_ASSERT((mPropGet == NULL) && (mPropSet == NULL));
if (curCheckType->mMethodList.IsEmpty())
{
bool hasProps = false;
for (auto methodNameEntry : curCheckType->mMethodNameList)
{
const char* methodName = methodNameEntry->mName;
if (((methodName[0] == 'g') || (methodName[0] == 's')) &&
((strncmp(methodName, "get__", 5) == 0) ||
(strncmp(methodName, "set__", 5) == 0)))
{
if (strcmp(methodName + 5, fieldName.c_str()) == 0)
{
curCheckType->mCompileUnit->mDbgModule->MapCompileUnitMethods(methodNameEntry->mCompileUnitId);
methodNameEntry->mCompileUnitId = -1;
}
}
}
}
for (int pass = 0; pass < 2; pass++)
{
for (auto method : curCheckType->mMethodList)
{
2019-08-23 11:56:54 -07:00
if (method->mName != NULL)
{
if (((method->mName[0] == 'g') || (method->mName[0] == 's')) &&
((strncmp(method->mName, "get__", 5) == 0) ||
(strncmp(method->mName, "set__", 5) == 0)))
{
if (strcmp(method->mName + 5, fieldName.c_str()) == 0)
{
bool isGetter = method->mName[0] == 'g';
method->PopulateSubprogram();
if (fieldName.IsEmpty())
{
int expectedParams = (int)mIndexerValues.size();
if (!isGetter)
expectedParams++;
if (method->GetParamCount() != expectedParams)
continue;
}
DbgSubprogram*& subprogramRef = isGetter ? mPropGet : mPropSet;
if ((subprogramRef == NULL) ||
((!method->mHasThis) && (wantsStatic)) ||
2019-08-23 11:56:54 -07:00
((method->mHasThis) && (!wantsStatic || allowImplicitThis)))
{
if ((method->mHasThis) && (allowImplicitThis) && (!target))
{
target = GetThis();
}
2019-08-23 11:56:54 -07:00
if (subprogramRef == NULL)
subprogramRef = method;
else if ((method->mVTableLoc != -1) || (subprogramRef->mVTableLoc == -1))
subprogramRef = method;
}
}
}
}
}
bool loadedCompileUnit = false;
for (int methodIdx = 0; methodIdx < 2; methodIdx++)
{
auto method = (methodIdx == 0) ? mPropGet : mPropSet;
if (method == NULL)
continue;
if (method->mBlock.mLowPC == 0)
{
if (!curCheckType->mHasGlobalsPopulated)
mDbgModule->PopulateTypeGlobals(curCheckType);
for (auto methodNameEntry : curCheckType->mMethodNameList)
{
const char* methodName = methodNameEntry->mName;
if ((methodNameEntry->mCompileUnitId >= 0) && (strcmp(methodName, method->mName) == 0))
{
curCheckType->mCompileUnit->mDbgModule->MapCompileUnitMethods(methodNameEntry->mCompileUnitId);
loadedCompileUnit = true;
}
}
}
}
if (!loadedCompileUnit)
break;
}
// Found a result
if ((mPropGet != NULL) || (mPropSet != NULL))
{
mPropSrc = targetSrc;
mPropTarget = target;
return DbgTypedValue();
}
//TODO:
/*for (auto prop : curCheckType->mTypeDef->mProperties)
{
if (prop->mName == fieldName)
{
mModule->Fail("Cannot reference property");
return DbgTypedValue();
}
}*/
//curCheckType = curCheckType->GetBaseType();
for (auto baseTypeEntry : curCheckType->mBaseTypes)
{
auto baseType = baseTypeEntry->mBaseType;
DbgTypedValue baseTarget = target;
addr_target* ptrRef = NULL;
if ((baseTarget.mPtr != 0) && (target.mType->HasPointer()))
ptrRef = &baseTarget.mPtr;
else if (baseTarget.mSrcAddress != 0)
ptrRef = &baseTarget.mSrcAddress;
if (ptrRef != NULL)
{
if (baseTypeEntry->mVTableOffset != -1)
{
addr_target vtableAddr = mDebugger->ReadMemory<addr_target>(target.mPtr);
int32 virtThisOffset = mDebugger->ReadMemory<int32>(vtableAddr + baseTypeEntry->mVTableOffset * sizeof(int32));
*ptrRef += virtThisOffset;
}
else
*ptrRef += baseTypeEntry->mThisOffset;
}
//BF_ASSERT(baseTypeEntry->mVTableOffset == -1);
auto result = DoLookupField(targetSrc, baseTarget, baseType, fieldName, stackFrame, allowImplicitThis);
if (result)
return result;
}
if (wantsStatic)
{
// Look for statics in anonymous inner classes
for (auto checkSubType : curCheckType->mSubTypeList)
{
bool includeSubType = ((checkSubType->mTypeName == NULL) || (checkSubType->IsGlobalsContainer()));
if ((language == DbgLanguage_C) && (checkSubType->IsEnum()))
includeSubType = true;
if (includeSubType)
{
if ((checkSubType->IsGlobalsContainer()) && (checkSubType->mPriority <= DbgTypePriority_Normal))
continue;
auto rawCheckSubType = checkSubType->RemoveModifiers();
auto result = DoLookupField(targetSrc, DbgTypedValue(), rawCheckSubType, fieldName, stackFrame, false);
if (result)
return result;
}
}
//Turn alternates back on!
/*for (auto altType : curCheckType->mAlternates)
{
auto result = DoLookupField(targetSrc, DbgTypedValue(), altType, fieldName, stackFrame, false);
if (result)
return result;
}*/
}
return DbgTypedValue();
}
DbgTypedValue DbgExprEvaluator::LookupField(BfAstNode* targetSrc, DbgTypedValue target, const StringImpl& fieldName)
2020-01-31 17:16:44 -08:00
{
2019-08-23 11:56:54 -07:00
CPUStackFrame* stackFrame = GetStackFrame();
DbgType* curCheckType = NULL;
/*if (currentMethod != NULL)
curCheckType = currentMethod->mParentType;*/
DbgType* curMethodType = curCheckType;
if (target)
{
if (target.mType->IsPrimitiveType())
{
curCheckType = mDbgModule->GetPrimitiveStructType(target.mType->mTypeCode);
if (curCheckType == NULL)
return DbgTypedValue();
}
else
{
curCheckType = target.mType;
}
BF_ASSERT(curCheckType != NULL);
}
else if (target.mType != NULL)
curCheckType = target.mType;
if (curCheckType != NULL)
{
curCheckType = curCheckType->RemoveModifiers();
if (curCheckType->mTypeCode == DbgType_Ptr)
curCheckType = curCheckType->mTypeParam;
}
bool allowImplicitThis = false;
if (curCheckType == NULL)
{
auto currentMethod = GetCurrentMethod();
if (currentMethod != NULL)
{
curCheckType = currentMethod->GetTargetType();
allowImplicitThis = currentMethod->mHasThis;
}
}
//SetAndRestoreValue<DbgType*> prevTypeInstance(curMethodType, curCheckType);
if (curCheckType == NULL)
return DbgTypedValue();
return DoLookupField(targetSrc, target, curCheckType, fieldName, stackFrame, allowImplicitThis);
}
void DbgExprEvaluator::Visit(BfAstNode* node)
{
Fail("Invalid debug expression", node);
}
DbgTypedValue DbgExprEvaluator::ReadTypedValue(BfAstNode* targetSrc, DbgType* dbgType, uint64 valAddr, DbgAddrType addrType)
2019-08-23 11:56:54 -07:00
{
bool failedReadMemory = false;
if (addrType == DbgAddrType_Alias)
{
String findName = (const char*)valAddr;
if (targetSrc == NULL)
return DbgTypedValue();
auto source = targetSrc->GetSourceData();
auto bfParser = source->ToParser();
if (bfParser == NULL)
return DbgTypedValue();
auto identifierNode = source->mAlloc.Alloc<BfIdentifierNode>();
int srcStart = bfParser->AllocChars(findName.length());
memcpy((char*)source->mSrc + srcStart, findName.c_str(), findName.length());
identifierNode->Init(srcStart, srcStart, srcStart + findName.length());
SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, true);
auto result = LookupIdentifier(identifierNode);
if (result)
return result;
// Allow lookup in calling method if we are inlined (for mixin references)
auto currentMethod = GetCurrentMethod();
if ((currentMethod != NULL) && (currentMethod->mInlineeInfo != NULL))
{
SetAndRestoreValue<int> preCallstackIdx(mCallStackIdx);
mCallStackIdx++;
result = LookupIdentifier(identifierNode);
}
return result;
}
2019-08-23 11:56:54 -07:00
if (addrType == DbgAddrType_LocalSplat)
{
DbgTypedValue val;
val.mVariable = (DbgVariable*)valAddr;
val.mType = dbgType;
val.mSrcAddress = -1;
val.mIsReadOnly = true;
return val;
}
if (addrType == DbgAddrType_TargetDeref)
{
DbgTypedValue result = ReadTypedValue(targetSrc, dbgType, valAddr, DbgAddrType_Target);
2019-08-23 11:56:54 -07:00
if ((result.mType != NULL) && (result.mType->IsPointer()))
{
result.mType = result.mType->mTypeParam;
result.mSrcAddress = result.mPtr;
}
return result;
}
if (addrType == DbgAddrType_NoValue)
{
mPassInstance->Fail(StrFormat("No value", valAddr));
return DbgTypedValue();
}
else if (addrType == DbgAddrType_OptimizedOut)
{
mPassInstance->Fail(StrFormat("Optimized out", valAddr));
return DbgTypedValue();
}
bool hadRef = false;
DbgType* origDwType = dbgType;
while (true)
{
if (dbgType->mTypeCode == DbgType_Const)
{
dbgType = mDbgModule->GetInnerTypeOrVoid(dbgType);
}
else if ((dbgType->mTypeCode == DbgType_TypeDef) || (dbgType->mTypeCode == DbgType_Volatile))
{
dbgType = mDbgModule->GetInnerTypeOrVoid(dbgType);
}
else if ((dbgType->mTypeCode == DbgType_Ref) || (dbgType->mTypeCode == DbgType_RValueReference))
{
hadRef = true;
auto innerType = dbgType->mTypeParam;
if ((!innerType->IsCompositeType()) || (addrType == DbgAddrType_Target))
{
if (addrType == DbgAddrType_Target)
valAddr = mDebugger->ReadMemory<addr_target>(valAddr);
if (addrType == DbgAddrType_Register)
{
auto registers = GetRegisters();
valAddr = registers->mIntRegsArray[valAddr];
}
//valIsAddr = true;
addrType = DbgAddrType_Target;
//local = false;
}
else
{
//local = false;
//valIsAddr = true;
if (addrType == DbgAddrType_Register)
{
auto registers = GetRegisters();
valAddr = registers->mIntRegsArray[valAddr];
}
addrType = DbgAddrType_Target;
}
dbgType = dbgType->mTypeParam;
}
else
break;
}
dbgType = dbgType->GetPrimaryType();
if (dbgType->GetByteCount() == 0)
{
DbgTypedValue result;
result.mType = dbgType;
return result;
}
if (dbgType->mTypeCode == DbgType_Bitfield)
{
DbgType* underlyingType = dbgType->mTypeParam;
DbgTypedValue result = ReadTypedValue(targetSrc, dbgType->mTypeParam, valAddr, addrType);
2019-08-23 11:56:54 -07:00
result.mType = dbgType;
auto dbgBitfieldType = (DbgBitfieldType*)dbgType;
result.mUInt64 = result.mUInt64 >> dbgBitfieldType->mPosition;
uint64 mask = ((uint64)1 << dbgBitfieldType->mLength) - 1;
result.mUInt64 &= mask;
if ((underlyingType->IsSigned()) && ((result.mUInt64 & (1LL << (dbgBitfieldType->mLength - 1))) != 0))
{
// Sign extend
result.mUInt64 |= ~mask;
}
return result;
}
bool local = addrType == DbgAddrType_Local;
bool valIsAddr = (addrType == DbgAddrType_Local) || (addrType == DbgAddrType_Target);
DbgTypedValue result;
result.mType = origDwType;
if (addrType == DbgAddrType_Register)
{
result.mRegNum = (int)valAddr;
auto registers = GetRegisters();
if (result.mRegNum < CPURegisters::kNumIntRegs)
result.mUInt64 = registers->mIntRegsArray[result.mRegNum];
else if ((result.mRegNum >= CPUReg_XMMREG_FIRST) && (result.mRegNum <= CPUReg_XMMREG_LAST))
{
auto dwType = origDwType->RemoveModifiers();
if (dwType->IsTypedPrimitive())
2020-05-15 12:39:18 -07:00
dwType = dwType->GetUnderlyingType();
2019-08-23 11:56:54 -07:00
if (dwType->mTypeCode == DbgType_Single)
result.mSingle = *(float*)((float*)registers->mXmmRegsArray + (result.mRegNum - CPUReg_XMMREG_FIRST));
else if (dwType->mTypeCode == DbgType_Double)
result.mDouble = *(double*)((float*)registers->mXmmRegsArray + (result.mRegNum - CPUReg_XMMREG_FIRST));
else
BF_ASSERT("Not implemented" == 0);
}
auto primaryType = result.mType->GetPrimaryType();
result.mType = primaryType;
// In release builds, VC will place int-sized structs into a single register. This code was breaking that.
/*if ((primaryType->IsCompositeType()) && (!primaryType->IsTypedPrimitive()))
{
result.mSrcAddress = result.mPtr;
result.mPtr = 0;
}*/
return result;
}
if (dbgType->mTypeCode == DbgType_Bitfield)
dbgType = dbgType->mTypeParam;
switch (dbgType->mTypeCode)
{
case DbgType_Void:
break;
case DbgType_Bool:
case DbgType_i8:
case DbgType_u8:
case DbgType_SChar:
case DbgType_UChar:
if (valIsAddr)
result.mInt8 = mDebugger->ReadMemory<int8>(valAddr, local, &failedReadMemory);
else
result.mUInt8 = (uint8)valAddr;
break;
case DbgType_i16:
case DbgType_u16:
case DbgType_SChar16:
case DbgType_UChar16:
if (valIsAddr)
result.mInt16 = mDebugger->ReadMemory<int16>(valAddr, local, &failedReadMemory);
else
result.mUInt16 = (uint16)valAddr;
break;
case DbgType_i32:
case DbgType_u32:
case DbgType_SChar32:
case DbgType_UChar32:
if (valIsAddr)
result.mInt32 = mDebugger->ReadMemory<int32>(valAddr, local, &failedReadMemory);
else
result.mUInt32 = (uint32)valAddr;
break;
case DbgType_i64:
case DbgType_u64:
if (valIsAddr)
result.mInt64 = mDebugger->ReadMemory<int64>(valAddr, local, &failedReadMemory);
else
result.mUInt64 = (uint64)valAddr;
break;
case DbgType_Single:
result.mSingle = mDebugger->ReadMemory<float>(valAddr, local, &failedReadMemory);
break;
case DbgType_Double:
result.mDouble = mDebugger->ReadMemory<double>(valAddr, local, &failedReadMemory);
break;
case DbgType_Struct:
case DbgType_Class:
case DbgType_Union:
case DbgType_SizedArray:
if (((dbgType->IsTypedPrimitive()) || (local)) && (dbgType->GetByteCount() <= 8))
{
mDebugger->ReadMemory(valAddr, dbgType->GetByteCount(), &result.mInt64, local);
result.mSrcAddress = (addr_target)valAddr;
}
else
{
BF_ASSERT(!local);
if (hadRef)
result.mPtr = (addr_target)valAddr;
else
result.mSrcAddress = (addr_target)valAddr;
}
//result.mPtr = (addr_target)valAddr;
break;
//TODO: Why was it treated as a pointer
//case DbgType_SizedArray:
case DbgType_Ptr:
if (valIsAddr)
result.mPtr = mDebugger->ReadMemory<addr_target>(valAddr, local, &failedReadMemory);
else
result.mPtr = valAddr;
break;
case DbgType_Enum:
result = ReadTypedValue(targetSrc, dbgType->mTypeParam, valAddr, addrType);
2019-08-23 11:56:54 -07:00
if (result)
result.mType = dbgType;
break;
case DbgType_Subroutine:
{
auto funcPtr = result.mPtr;
String symbolName;
addr_target offset;
DbgModule* dwarf;
if (mDebugTarget->FindSymbolAt(funcPtr, &symbolName, &offset, &dwarf))
{
#ifdef BF_DBG_32
if ((symbolName.length() > 0) && (symbolName[0] == '_'))
symbolName = symbolName.Substring(1);
#endif
static String demangledName;
demangledName = BfDemangler::Demangle(symbolName, dbgType->GetLanguage());
DbgTypedValue result;
result.mCharPtr = demangledName.c_str();
}
else
{
result.mCharPtr = NULL;
}
}
break;
default:
if (mPassInstance != NULL)
mPassInstance->Fail("Invalid data type");
}
if ((!local) && (valIsAddr))
{
result.mSrcAddress = valAddr;
}
if ((failedReadMemory) && (!mValidateOnly))
{
if (mPassInstance == NULL)
return DbgTypedValue();
if (addrType == DbgAddrType_NoValue)
mPassInstance->Fail("No value");
else if ((valAddr == 0) && (local))
mPassInstance->Fail("Optimized out");
else if (!mBlockedSideEffects)
mPassInstance->Fail(StrFormat("Failed to read from address %s", EncodeDataPtr(valAddr, true).c_str()));
}
return result;
}
bool DbgExprEvaluator::CheckTupleCreation(addr_target receiveAddr, BfAstNode* targetSrc, DbgType* tupleType, const BfSizedArray<BfExpression*>& argValues, BfSizedArray<BfTupleNameNode*>* names)
{
int memberIdx = 0;
tupleType = tupleType->RemoveModifiers();
tupleType = tupleType->GetPrimaryType();
for (auto member : tupleType->mMemberList)
{
if (member->mIsStatic)
continue;
DbgTypedValue receivingValue;
receivingValue.mSrcAddress = receiveAddr + member->mMemberOffset;
receivingValue.mType = member->mType;
if (memberIdx < argValues.size())
{
if ((names != NULL) && (memberIdx < names->size()) && ((*names)[memberIdx] != NULL))
{
String name;
if (auto tupleName = BfNodeDynCast<BfTupleNameNode>((*names)[memberIdx]))
name = tupleName->mNameNode->ToString();
else
name = (*names)[memberIdx]->ToString();
if ((member->mName != NULL) && (!isdigit(member->mName[0])) && (name != member->mName))
{
Fail(StrFormat("Name '%s' does not match expect name '%s'", name.c_str(), member->mName), (*names)[memberIdx]);
}
}
StoreValue(receivingValue, argValues[memberIdx]);
}
else
{
Fail("Not enough arguments", targetSrc);
}
memberIdx++;
}
if (memberIdx < argValues.size())
{
Fail("Too many arguments", argValues[memberIdx]);
}
return false;
}
DbgTypedValue DbgExprEvaluator::CheckEnumCreation(BfAstNode* targetSrc, DbgType* enumType, const StringImpl& caseName, const BfSizedArray<BfExpression*>& argValues)
{
BF_ASSERT(enumType->IsBfPayloadEnum());
addr_target receiveAddr = 0;
if (mReceivingValue != NULL)
{
receiveAddr = mReceivingValue->mSrcAddress;
}
if (receiveAddr == 0)
{
Fail("Address for enum cannot be inferred", targetSrc);
return DbgTypedValue();
}
enumType = enumType->RemoveModifiers();
enumType = enumType->GetPrimaryType();
int caseNum = -1;
DbgVariable* matchedMember = NULL;
for (auto member : enumType->mMemberList)
{
if ((member->mName[0] == '_') && (member->mName[1] >= '0') && (member->mName[1] <= '9'))
{
for (int i = 1; true; i++)
{
if (member->mName[i] == '_')
{
if (caseName == member->mName + i + 1)
{
caseNum = atoi(member->mName + 1);
matchedMember = member;
}
break;
}
else if (member->mName[i] == 0)
break;
}
}
if (strcmp(member->mName, "__bftag") == 0)
{
if (mReceivingValue != NULL)
mReceivingValue = NULL;
mDebugger->WriteMemory(receiveAddr + member->mMemberOffset, &caseNum, member->mType->GetByteCount());
CheckTupleCreation(receiveAddr + matchedMember->mMemberOffset, targetSrc, matchedMember->mType, argValues, NULL);
DbgTypedValue typedValue;
typedValue.mType = enumType;
typedValue.mSrcAddress = receiveAddr;
return typedValue;
}
}
return DbgTypedValue();
}
bool DbgExprEvaluator::IsAutoCompleteNode(BfAstNode* node, int lengthAdd)
{
if (node == NULL)
return false;
return ((mCursorPos >= node->GetSrcStart()) && (mCursorPos < node->GetSrcEnd() + lengthAdd));
}
void DbgExprEvaluator::AutocompleteCheckType(BfTypeReference* typeReference)
{
if (!IsAutoCompleteNode(typeReference))
return;
if (auto namedTypeRef = BfNodeDynCast <BfNamedTypeReference>(typeReference))
{
String filter = namedTypeRef->ToString();
mAutoComplete->mInsertStartIdx = namedTypeRef->GetSrcStart();
mAutoComplete->mInsertEndIdx = namedTypeRef->GetSrcEnd();
AutocompleteAddTopLevelTypes(filter);
}
else if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(typeReference))
{
if (IsAutoCompleteNode(qualifiedTypeRef->mLeft))
{
AutocompleteCheckType(qualifiedTypeRef->mLeft);
return;
}
auto dbgType = ResolveTypeRef(qualifiedTypeRef->mLeft);
if (dbgType != NULL)
{
String filter;
if (qualifiedTypeRef->mRight != NULL)
{
filter = qualifiedTypeRef->mRight->ToString();
mAutoComplete->mInsertStartIdx = qualifiedTypeRef->mRight->GetSrcStart();
mAutoComplete->mInsertEndIdx = qualifiedTypeRef->mRight->GetSrcEnd();
}
else
{
mAutoComplete->mInsertStartIdx = qualifiedTypeRef->mDot->GetSrcEnd();
mAutoComplete->mInsertEndIdx = qualifiedTypeRef->mDot->GetSrcEnd();
}
AutocompleteAddMembers(dbgType, false, false, filter);
}
}
else if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(typeReference))
{
AutocompleteCheckType(elementedTypeRef->mElementType);
}
}
void DbgExprEvaluator::AutocompleteAddTopLevelTypes(const StringImpl& filter)
{
GetNamespaceSearch();
for (auto usingNamespace : mNamespaceSearch)
{
usingNamespace = usingNamespace->GetPrimaryType();
AutocompleteAddMembers(usingNamespace, true, false, filter);
}
mDbgModule->ParseGlobalsData();
int methodEntryCount = 0;
//for (auto compileUnit : mDbgModule->mCompileUnits)
for (int compileIdx = 0; compileIdx < (int)mDbgModule->mCompileUnits.size(); compileIdx++)
{
auto compileUnit = mDbgModule->mCompileUnits[compileIdx];
if (mDbgCompileUnit == NULL)
continue;
if ((compileUnit->mLanguage != DbgLanguage_Unknown) && (compileUnit->mLanguage != mDbgCompileUnit->mLanguage))
continue;
AutocompleteAddMembers(compileUnit->mGlobalType, true, false, filter);
/*for (auto dwMethod : compileUnit->mGlobalType.mMethodList)
{
if (dwMethod->mName != NULL)
{
methodEntryCount++;
mAutoComplete->AddEntry(AutoCompleteEntry("method", dwMethod->mName), filter);
}
}*/
}
auto language = GetLanguage();
if (language == DbgLanguage_Beef)
{
for (auto primType : mDbgModule->mBfPrimitiveTypes)
{
if (primType != NULL)
mAutoComplete->AddEntry(AutoCompleteEntry("valuetype", primType->mName), filter);
}
char* primNames[2] = { "int", "uint" };
for (auto primName : primNames)
mAutoComplete->AddEntry(AutoCompleteEntry("valuetype", primName), filter);
}
else
{
for (auto primType : mDbgModule->mCPrimitiveTypes)
{
if (primType != NULL)
mAutoComplete->AddEntry(AutoCompleteEntry("valuetype", primType->mName), filter);
}
}
int typeEntrCount = 0;
//TODO: Does this get everything?
/*for (auto dwTypeEntry : mDbgModule->mTypeMap)
{
auto dbgType = dwTypeEntry->mValue;
if ((dbgType->mParent == NULL) && (dbgType->mTypeParam == NULL) &&
(dbgType->mTypeCode != DbgType_Ptr) && (dbgType->mTypeCode != DbgType_Ref))
{
String typeStr = dbgType->ToString();
if (typeStr[typeStr.length() - 1] == '^')
continue;
mAutoComplete->AddEntry(AutoCompleteEntry("type", typeStr), filter);
typeEntrCount++;
}
}*/
}
DbgTypedValue DbgExprEvaluator::LookupIdentifier(BfAstNode* identifierNode, bool ignoreInitialError, bool* hadError)
2020-01-31 17:16:44 -08:00
{
2019-08-23 11:56:54 -07:00
if (!mDebugger->mIsRunning)
return DbgTypedValue();
auto qualifiedNameNode = BfNodeDynCast<BfQualifiedNameNode>(identifierNode);
if (qualifiedNameNode != NULL)
{
LookupQualifiedName(qualifiedNameNode, ignoreInitialError, hadError);
auto qualifiedResult = mResult;
mResult = DbgTypedValue();
return qualifiedResult;
}
String findName = identifierNode->ToString();
2020-03-24 07:08:54 -07:00
if ((findName.StartsWith('$')) && (findName != "$prim"))
2019-08-23 11:56:54 -07:00
{
if (IsAutoCompleteNode(identifierNode))
{
String filter = identifierNode->ToString();
const char* identifiers[] =
{
"$ThreadId", "$ThreadName", "$TargetName", "$TargetPath", "$ModuleName", "$ModulePath",
"$HitCount", "$ProcessId"
};
for (int idx = 0; idx < BF_ARRAY_COUNT(identifiers); idx++)
mAutoComplete->AddEntry(AutoCompleteEntry("dbg", identifiers[idx]), filter);
mAutoComplete->mInsertStartIdx = identifierNode->GetSrcStart();
mAutoComplete->mInsertEndIdx = identifierNode->GetSrcEnd();
}
if (findName == "$this")
return GetThis();
else if (findName == "$ThreadId")
return GetInt(mDebugger->mActiveThread->mThreadId);
else if (findName == "$ThreadName")
return GetString(mDebugger->mActiveThread->mName);
else if (findName == "$TargetName")
return GetString(GetFileName(mDebugTarget->mTargetPath));
else if (findName == "LaunchName")
return GetString(GetFileName(mDebugTarget->mLaunchBinary->mFilePath));
2019-08-23 11:56:54 -07:00
else if (findName == "$TargetPath")
return GetString(mDebugTarget->mTargetPath);
2019-08-23 11:56:54 -07:00
else if (findName == "$ModuleName")
return GetString(GetFileName(mDbgModule->mFilePath));
else if (findName == "$ModulePath")
return GetString(mDbgModule->mFilePath);
else if (findName == "$HitCount")
{
if (mDebugger->mActiveBreakpoint != NULL)
return GetInt(mDebugger->mActiveBreakpoint->GetHeadBreakpoint()->mHitCount);
return GetInt(0);
}
else if (findName == "$BreakpointCondition")
{
if ((mDebugger->mActiveBreakpoint != NULL) && (mDebugger->mActiveBreakpoint->mCondition != NULL))
return GetString(mDebugger->mActiveBreakpoint->GetHeadBreakpoint()->mCondition->mExpr);
return GetString("");
}
else if (findName == "$ProcessId")
return GetInt(mDebugger->mProcessInfo.dwProcessId);
bool mayBeRegister = true;
for (int i = 1; i < findName.length(); i++)
if (findName[i] == '$')
mayBeRegister = false;
if (mayBeRegister)
2019-11-02 06:02:00 -07:00
{
DbgTypedValue val = GetRegister(findName.Substring(1));
if (val)
return val;
}
2019-08-23 11:56:54 -07:00
}
DbgTypedValue result;
if (mExplicitThis)
{
if ((mExplicitThis.mSrcAddress == -1) && ((DbgVariable*)mExplicitThis.mVariable != NULL))
{
mResult = DbgTypedValue();
LookupSplatMember(mExplicitThis, findName);
result = mResult;
mResult = DbgTypedValue();
}
else if (!result)
{
mExplicitThis.mType = mExplicitThis.mType->RemoveModifiers();
result = LookupField(identifierNode, mExplicitThis, findName);
}
if (result)
{
if (mExplicitThisExpr != NULL)
mDeferredInsertExplicitThisVector.push_back(NodeReplaceRecord(identifierNode, mCurChildRef));
return result;
}
}
CPUStackFrame* stackFrame = GetStackFrame();
auto language = GetLanguage();
intptr valAddr;
DbgType* valType;
DbgAddrType addrType = DbgAddrType_None;
if (IsAutoCompleteNode(identifierNode))
{
String filter = identifierNode->ToString();
DbgType* dbgType = NULL;
auto currentMethod = GetCurrentMethod();
auto thisVal = GetThis();
auto targetType = thisVal.mType;
if (currentMethod != NULL)
{
if (targetType != NULL)
dbgType = targetType;
else if (!thisVal)
dbgType = currentMethod->GetTargetType();
}
Array<String> capturedNames;
Array<DbgType*> capturedTypes;
mDebugTarget->mCapturedNamesPtr = &capturedNames;
mDebugTarget->mCapturedTypesPtr = &capturedTypes;
2020-01-31 17:16:44 -08:00
{
2019-08-23 11:56:54 -07:00
mDebugTarget->GetValueByName(GetCurrentMethod(), "*", stackFrame, &valAddr, &valType, &addrType);
}
mDebugTarget->mCapturedNamesPtr = NULL;
mDebugTarget->mCapturedTypesPtr = NULL;
auto language = GetLanguage();
BF_ASSERT(capturedTypes.size() == capturedNames.size());
2020-01-31 17:16:44 -08:00
{
2019-08-23 11:56:54 -07:00
//for (auto capturedName : capturedNames)
for (int i = 0; i < (int)capturedNames.size(); i++)
{
const String capturedName = capturedNames[i];
if (language == DbgLanguage_Beef)
{
// Don't put splats
if ((capturedName.length() > 0) && (capturedName[0] == '$'))
continue;
}
//TODO: Show the type icon
mAutoComplete->AddEntry(AutoCompleteEntry(GetTypeName(capturedTypes[i]), capturedNames[i]), filter);
}
}
if (!mSubjectExpr.IsEmpty())
{
mAutoComplete->AddEntry(AutoCompleteEntry("valuetype", "_"), filter);
}
if (dbgType != NULL)
{
dbgType = dbgType->RemoveModifiers();
if (dbgType->IsPointerOrRef())
{
dbgType = dbgType->mTypeParam;
dbgType = dbgType->RemoveModifiers();
}
if (dbgType->mIsDeclaration)
dbgType = dbgType->GetPrimaryType();
bool wantsStatic = true;
bool wantsNonStatic = currentMethod->mHasThis;
// In Beef, we can only access statics by class name
if (dbgType->GetLanguage() != DbgLanguage_Beef)
wantsStatic = !wantsNonStatic;
AutocompleteAddMembers(dbgType, wantsStatic, wantsNonStatic, filter);
if (currentMethod != NULL)
{
if (language == DbgLanguage_C)
{
// C++ closures
auto currentMethod = GetCurrentMethod();
if (currentMethod != NULL)
{
if (strstr(currentMethod->mName, "operator()") != NULL)
{
if (mDebugTarget->GetValueByName(currentMethod, "this", stackFrame, &valAddr, &valType, &addrType))
{
valType = valType->RemoveModifiers();
if (valType->IsPointer())
valType = valType->mTypeParam;
valType = valType->RemoveModifiers();
AutocompleteAddMembers(valType, true, true, filter, true);
}
}
}
}
else
{
// If in a Beef closure...
if (mDebugTarget->GetValueByName(currentMethod, "__closure", stackFrame, &valAddr, &valType, &addrType))
{
valType = valType->RemoveModifiers();
if (valType->IsPointer())
valType = valType->mTypeParam;
AutocompleteAddMembers(valType, true, true, filter, true);
}
}
auto targetType = currentMethod->GetTargetType();
if ((targetType != dbgType) && (targetType != NULL))
{
AutocompleteAddMembers(targetType, wantsStatic, wantsNonStatic, filter);
}
}
}
mAutoComplete->mInsertStartIdx = identifierNode->GetSrcStart();
mAutoComplete->mInsertEndIdx = identifierNode->GetSrcEnd();
AutocompleteAddTopLevelTypes(filter);
}
if (language == DbgLanguage_C)
{
2020-01-31 17:16:44 -08:00
// For C++ lambdas, captured a "this" is named "__this", so allow lookups into that
2019-08-23 11:56:54 -07:00
auto currentMethod = GetCurrentMethod();
if (currentMethod != NULL)
{
if (strstr(currentMethod->mName, "operator()") != NULL)
{
DbgTypedValue rootThisValue = GetThis();
if (rootThisValue)
{
DbgTypedValue thisValue = LookupField(identifierNode, rootThisValue, "__this");
if (thisValue)
{
if (findName == "this")
return thisValue;
auto fieldValue = LookupField(identifierNode, thisValue, findName);
if (fieldValue)
return fieldValue;
}
}
}
}
}
if (findName == "this")
return GetThis();
if (findName == "_")
{
if (mSubjectValue)
{
if (mSubjectValue.mSrcAddress != 0)
{
auto refreshVal = ReadTypedValue(identifierNode, mSubjectValue.mType, mSubjectValue.mSrcAddress, DbgAddrType_Target);
if (refreshVal)
mSubjectValue = refreshVal;
}
2019-08-23 11:56:54 -07:00
return mSubjectValue;
}
2019-08-23 11:56:54 -07:00
if (!mSubjectExpr.IsEmpty())
{
DwFormatInfo formatInfo;
formatInfo.mLanguage = language;
DbgEvaluationContext dbgEvaluationContext(mDebugger, mDbgModule, mSubjectExpr, &formatInfo);
mSubjectValue = dbgEvaluationContext.EvaluateInContext(mExplicitThis);
if (!mSubjectValue)
{
Fail("Failed to generate subject value", identifierNode);
}
if (mSubjectValue)
return mSubjectValue;
}
}
if (stackFrame != NULL)
2020-01-31 17:16:44 -08:00
{
2019-08-23 11:56:54 -07:00
if (mDebugTarget->GetValueByName(GetCurrentMethod(), findName, stackFrame, &valAddr, &valType, &addrType))
{
//BF_ASSERT(valType != NULL);
if (valType == NULL)
{
if (sizeof(addr_target) == 8)
valType = mDbgModule->GetPrimitiveType(DbgType_i64, DbgLanguage_C);
else
valType = mDbgModule->GetPrimitiveType(DbgType_i32, DbgLanguage_C);
}
if (valType != NULL)
{
if (mReferenceId != NULL)
*mReferenceId = findName;
//bool isLocal = !valIsAddr;
//if (valType->IsCompositeType())
//isLocal = false;
return ReadTypedValue(identifierNode, valType, valAddr, addrType);
2019-08-23 11:56:54 -07:00
}
}
}
bool isClosure = false;
if (language == DbgLanguage_Beef)
2020-01-31 17:16:44 -08:00
{
2019-08-23 11:56:54 -07:00
intptr valAddr;
DbgType* valType;
//bool valIsAddr = false;
if (mDebugTarget->GetValueByName(GetCurrentMethod(), "__closure", stackFrame, &valAddr, &valType, &addrType))
{
DbgTypedValue closureValue = ReadTypedValue(identifierNode, valType, valAddr, addrType);
2019-08-23 11:56:54 -07:00
if (closureValue)
{
SetAndRestoreValue<bool> prevIgnoreError(mIgnoreErrors, true);
DbgTypedValue fieldValue = LookupField(identifierNode, closureValue, findName);
if (fieldValue)
return fieldValue;
DbgTypedValue thisValue = LookupField(identifierNode, closureValue, "__this");
if (thisValue)
{
fieldValue = LookupField(identifierNode, thisValue, findName);
if (fieldValue)
return fieldValue;
}
}
}
}
/*if (mModule->mCurMethodState != NULL)
{
for (int localIdx = mModule->mCurMethodState->mLocals.size() - 1; localIdx >= 0; localIdx--)
{
auto& varDecl = mModule->mCurMethodState->mLocals[localIdx];
if (varDecl.mName == findName)
{
if (varDecl.mAddr != NULL)
{
return DbgTypedValue(varDecl.mAddr, varDecl.mUnresolvedType, true);
}
else
return DbgTypedValue(varDecl.mArgument, varDecl.mUnresolvedType, false);
return DbgTypedValue();
}
}
}*/
if (!isClosure)
{
// This uses an incorrect 'this' in the case of a closure
result = LookupField(identifierNode, DbgTypedValue(), findName);
if ((result) || (HasPropResult()))
return result;
}
result = GetRegister(findName);
if ((result) || (HasPropResult()))
{
return result;
}
mDbgModule->ParseGlobalsData();
for (auto compileUnit : mDbgModule->mCompileUnits)
{
if (mDbgCompileUnit == NULL)
continue;
if ((compileUnit->mLanguage != DbgLanguage_Unknown) && (compileUnit->mLanguage != mDbgCompileUnit->mLanguage))
continue;
result = DoLookupField(identifierNode, DbgTypedValue(), compileUnit->mGlobalType, findName, NULL, false);
if ((result) || (HasPropResult()))
return result;
}
auto currentMethod = GetCurrentMethod();
if ((currentMethod != NULL) && (currentMethod->mParentType == NULL) && (currentMethod->mHasQualifiedName))
{
currentMethod->mCompileUnit->mDbgModule->MapCompileUnitMethods(currentMethod->mCompileUnit);
}
if ((currentMethod != NULL) && (currentMethod->mParentType != NULL))
{
auto dbgType = currentMethod->mParentType;
if (dbgType->IsPointerOrRef())
dbgType = dbgType->mTypeParam;
auto curAlloc = &dbgType->mCompileUnit->mDbgModule->mAlloc;
result = DoLookupField(identifierNode, DbgTypedValue(), dbgType, findName, NULL, false);
if ((result) || (HasPropResult()))
return result;
GetNamespaceSearch();
for (auto usingNamespace : mNamespaceSearch)
{
usingNamespace = usingNamespace->GetPrimaryType();
result = DoLookupField(identifierNode, DbgTypedValue(), usingNamespace, findName, NULL, false);
if ((result) || (HasPropResult()))
return result;
for (auto checkNamespace : usingNamespace->mAlternates)
{
result = DoLookupField(identifierNode, DbgTypedValue(), checkNamespace, findName, NULL, false);
if ((result) || (HasPropResult()))
return result;
}
}
}
return DbgTypedValue();
}
void DbgExprEvaluator::Visit(BfAssignmentExpression* assignExpr)
{
mHadSideEffects = true;
auto binaryOp = BfAssignOpToBinaryOp(assignExpr->mOp);
//auto ptr = mModule->GetOrCreateVarAddr(assignExpr->mLeft);
VisitChild(assignExpr->mLeft);
if ((!mResult) && (!HasPropResult()))
return;
if (HasPropResult())
{
if (mPropSet == NULL)
{
Fail("Property has no setter", mPropSrc);
return;
}
auto propSrc = mPropSrc;
auto propSet = mPropSet;
auto propTarget = mPropTarget;
auto indexerValues = mIndexerValues;
auto indexerExprValues = mIndexerExprValues;
mPropGet = NULL;
mPropSet = NULL;
mPropSrc = NULL;
mPropTarget = DbgTypedValue();
mIndexerValues.clear();
mIndexerExprValues.clear();
auto valueParam = propSet->mParams.back();
if (valueParam == NULL)
{
Fail("Invalid property setter", mPropSrc);
return;
}
DbgTypedValue convVal;
if (binaryOp != BfBinaryOp_None)
{
PerformBinaryOperation(assignExpr->mLeft, assignExpr->mRight, binaryOp, assignExpr->mOpToken, true);
if (!mResult)
return;
convVal = mResult;
}
else
{
convVal = CreateValueFromExpression(assignExpr->mRight, valueParam->mType);
}
if (!convVal)
return;
// SizedArray<DbgTypedValue, 4> argPushQueue;
// if (propSet->mHasThis)
// argPushQueue.push_back(propTarget);
// for (auto indexer : indexerValues)
// argPushQueue.push_back(indexer);
// argPushQueue.push_back(convVal);
// if (propSet->mParams.Size() == argPushQueue.size())
// {
// mResult = CreateCall(propSet, argPushQueue, false);
//
// }
indexerExprValues.push_back(assignExpr->mRight);
indexerValues.push_back(convVal);
mResult = CreateCall(propSrc, propTarget, propSet, false, indexerExprValues, indexerValues);
return;
}
GetResult();
auto ptr = mResult;
mResult = DbgTypedValue();
if (binaryOp != NULL)
{
PerformBinaryOperation(assignExpr->mLeft, assignExpr->mRight, binaryOp, assignExpr->mOpToken, true);
}
else
{
SetAndRestoreValue<DbgTypedValue*> prevReceiveValue(mReceivingValue, &ptr);
mResult = DbgTypedValue();
mResult = CreateValueFromExpression(assignExpr->mRight, ptr.mType, DbgEvalExprFlags_NoCast);
if (mReceivingValue == NULL)
{
// Receiving value used
mResult = ptr;
return;
}
}
if (!mResult)
return;
if ((ptr.mType->mTypeCode == DbgType_Ref) || (ptr.mType->mTypeCode == DbgType_RValueReference))
ptr.mType = ptr.mType->mTypeParam;
if ((mResult.mType->mTypeCode == DbgType_i32) && (mResult.mIsLiteral) && (ptr.mType->IsPointer()))
{
// Allow for literal pointer setting
mResult.mType = ptr.mType;
}
if ((mResult.mType->IsPointer()) && (mResult.mIsLiteral))
{
Fail("Cannot assign from literal value", assignExpr->mRight);
return;
}
mResult = Cast(assignExpr->mRight, mResult, ptr.mType, true);
if (!mResult)
return;
if ((mExpressionFlags & DwEvalExpressionFlag_AllowSideEffects) == 0)
{
mBlockedSideEffects = true;
return;
}
StoreValue(ptr, mResult, assignExpr->mLeft);
}
bool DbgExprEvaluator::StoreValue(DbgTypedValue& ptr, DbgTypedValue& value, BfAstNode* refNode)
{
if ((!HasPropResult()) && ((ptr.mSrcAddress == 0) || (ptr.mIsReadOnly)) && (ptr.mRegNum < 0))
{
Fail("Cannot assign to value", refNode);
return false;
}
if (ptr.mSrcAddress)
{
if (ptr.mType->mTypeCode == DbgType_Bitfield)
{
auto dbgBitfieldType = (DbgBitfieldType*)ptr.mType;
uint64 tempVal = 0;
mDebugger->ReadMemory(ptr.mSrcAddress, ptr.mType->GetByteCount(), &tempVal);
uint64 srcMask = ((uint64)1 << dbgBitfieldType->mLength) - 1;
uint64 destMask = srcMask << dbgBitfieldType->mPosition;
value.mUInt64 &= srcMask;
tempVal &= ~destMask;
tempVal |= value.mUInt64 << dbgBitfieldType->mPosition;
if (!mDebugger->WriteMemory(ptr.mSrcAddress, &tempVal, ptr.mType->GetByteCount()))
mPassInstance->Fail("Failed to write to memory");
if ((dbgBitfieldType->mTypeParam->IsSigned()) && ((value.mUInt64 & (1LL << (dbgBitfieldType->mLength - 1))) != 0))
{
// Sign extend
value.mUInt64 |= ~srcMask;
}
}
else
{
if (!mDebugger->WriteMemory(ptr.mSrcAddress, &value.mInt8, ptr.mType->GetByteCount()))
mPassInstance->Fail("Failed to write to memory");
}
}
else
{
String error;
if (!mDebugger->AssignToReg(mCallStackIdx, ptr, value, error))
mPassInstance->Fail(error);
}
return true;
}
bool DbgExprEvaluator::StoreValue(DbgTypedValue& ptr, BfExpression* expr)
{
auto receiveAddr = ptr.mSrcAddress;
if (receiveAddr == 0)
{
Fail("Unable to determine receiving address", expr);
return false;
}
SetAndRestoreValue<DbgTypedValue*> prevReceivingValue(mReceivingValue, &ptr);
auto wantType = ptr.mType->RemoveModifiers();
auto result = Resolve(expr, ptr.mType);
if (mReceivingValue == NULL)
return true; // Already written
if (!result)
return false;
return StoreValue(ptr, result, expr);;
}
void DbgExprEvaluator::Visit(BfParenthesizedExpression* parenExpr)
{
VisitChild(parenExpr->mExpression);
}
const char* DbgExprEvaluator::GetTypeName(DbgType* type)
{
if (type != NULL)
{
if (type->IsBfObjectPtr())
return "object";
if (type->IsPointer())
return "pointer";
}
return "value";
}
DbgTypedValue DbgExprEvaluator::GetResult()
{
if (!mResult)
{
if (HasPropResult())
{
if (mPropGet == NULL)
{
Fail("Property has no getter", mPropSrc);
}
else
{
// SizedArray<DbgTypedValue, 4> argPushQueue;
// auto curParam = mPropGet->mParams.mHead;
// if (mPropGet->mHasThis)
// {
// argPushQueue.push_back(mPropTarget);
// if (curParam != NULL)
// curParam = curParam->mNext;
// }
// bool failed = false;
// for (int indexerIdx = 0; indexerIdx < (int)mIndexerValues.size(); indexerIdx++)
// {
// auto val = mIndexerValues[indexerIdx];
// if (curParam != NULL)
// {
// val = Cast(mPropSrc, val, curParam->mType);
// if (!val)
// {
// failed = true;
// break;
// }
// }
// argPushQueue.push_back(val);
//
// if (curParam != NULL)
// curParam = curParam->mNext;
// }
// if (!failed)
// {
// if (mPropGet->mParams.Size() == argPushQueue.size())
// {
// mResult = CreateCall(mPropGet, argPushQueue, false);
// }
// else
// {
// Fail("Indexer parameter count mismatch", mPropSrc);
// }
// }
2020-06-15 09:01:49 -07:00
SetAndRestoreValue<DwEvalExpressionFlags> prevFlags(mExpressionFlags);
if ((mExpressionFlags & DwEvalExpressionFlag_AllowPropertyEval) != 0)
mExpressionFlags = (DwEvalExpressionFlags)(mExpressionFlags | DwEvalExpressionFlag_AllowCalls);
2019-08-23 11:56:54 -07:00
mResult = CreateCall(mPropSrc, mPropTarget, mPropGet, false, mIndexerExprValues, mIndexerValues);
}
}
}
if ((mResult) && (mResult.mType->IsConst()) && (GetLanguage() == DbgLanguage_Beef))
{
mResult.mIsReadOnly = true; // Pretend we don't really have the address
}
mPropGet = NULL;
mPropSet = NULL;
mPropSrc = NULL;
mIndexerValues.clear();
mIndexerExprValues.clear();
return mResult;
}
bool DbgExprEvaluator::HasPropResult()
{
return (mPropGet != NULL) || (mPropSet != NULL);
}
DbgLanguage DbgExprEvaluator::GetLanguage()
{
if (mLanguage != DbgLanguage_NotSet)
return mLanguage;
if ((mDbgCompileUnit != NULL) && (mDbgCompileUnit->mLanguage != DbgLanguage_Unknown))
return mDbgCompileUnit->mLanguage;
if (mExplicitThis)
return mExplicitThis.mType->mLanguage;
auto currentMethod = GetCurrentMethod();
if (currentMethod != NULL)
return currentMethod->GetLanguage();
return DbgLanguage_Beef; // Default to Beef
}
DbgFlavor DbgExprEvaluator::GetFlavor()
{
if (mDbgCompileUnit != NULL)
return mDbgCompileUnit->mDbgModule->mDbgFlavor;
if (mExplicitThis)
return mExplicitThis.mType->mCompileUnit->mDbgModule->mDbgFlavor;
return DbgFlavor_Unknown;
}
void DbgExprEvaluator::AutocompleteAddMethod(const char* methodName, const StringImpl& filter)
{
const char* atPos = strchr(methodName, '@');
if (atPos == NULL)
{
if ((strncmp(methodName, "get__", 5) == 0) ||
(strncmp(methodName, "set__", 5) == 0))
{
const char* propName = methodName + 5;
if (*propName != (char)0)
mAutoComplete->AddEntry(AutoCompleteEntry("property", propName), filter);
}
else if (strncmp(methodName, "__", 2) != 0)
mAutoComplete->AddEntry(AutoCompleteEntry("method", methodName), filter);
}
}
void DbgExprEvaluator::AutocompleteAddMembers(DbgType* dbgType, bool wantsStatic, bool wantsNonStatic, const StringImpl& filter, bool isCapture)
{
DbgLanguage language = GetLanguage();
DbgFlavor flavor = GetFlavor();
if ((mDbgCompileUnit != NULL) && (dbgType->mLanguage != DbgLanguage_Unknown) && (dbgType->mLanguage != language))
return;
dbgType->PopulateType();
if (dbgType->mNeedsGlobalsPopulated)
mDbgModule->PopulateTypeGlobals(dbgType);
// Don't get primary type for namespace, causes mAlternates infinite loop
if (!dbgType->IsNamespace())
dbgType = dbgType->GetPrimaryType();
// false/false means just add subtypes
if ((wantsStatic) || (!wantsNonStatic))
{
auto subType = dbgType->mSubTypeList.mHead;
while (subType != NULL)
{
if (subType->mLanguage != language)
{
// Ignore
}
else if (subType->mTypeName == NULL)
{
AutocompleteAddMembers(subType, wantsStatic, wantsNonStatic, filter);
}
else
{
bool allowType = true;
for (const char* cPtr = subType->mTypeName; *cPtr != '\0'; cPtr++)
{
char c = *cPtr;
if ((c == '`') || (c == '[') || (c == '.') || (c == '$') || (c == '('))
allowType = false;
}
if ((allowType) && (subType->IsNamespace()))
{
// Is it a "using" declaration?
if ((!dbgType->IsRoot()) && (!dbgType->IsNamespace()))
allowType = false;
}
if ((!subType->IsAnonymous()) && (!subType->IsSizedArray()) && (allowType))
{
mDbgModule->TempRemoveTemplateStr(subType->mTypeName, subType->mTemplateNameIdx);
// We set the true mEntryType after the filter passes. This is because IsBfObject() is a "heavyweight" operation that we don't want to
// just run on ALL types immediately
AutoCompleteEntry* entry = mAutoComplete->AddEntry(AutoCompleteEntry("type", subType->mTypeName), filter);
if (entry != NULL)
{
if (subType->IsBfObject())
entry->mEntryType = "class";
else if (subType->IsNamespace())
entry->mEntryType = "namespace";
else
entry->mEntryType = "valuetype";
}
mDbgModule->ReplaceTemplateStr(subType->mTypeName, subType->mTemplateNameIdx);
}
else if (subType->IsGlobalsContainer())
{
if (subType->mPriority > DbgTypePriority_Normal)
AutocompleteAddMembers(subType, wantsStatic, wantsNonStatic, filter);
}
if ((subType->mTypeCode == DbgType_Enum) && (language == DbgLanguage_C))
{
AutocompleteAddMembers(subType, wantsStatic, wantsNonStatic, filter);
}
}
subType = subType->mNext;
}
if (dbgType->mTypeCode == DbgType_Namespace)
{
for (auto altType : dbgType->mAlternates)
{
AutocompleteAddMembers(altType, wantsStatic, wantsNonStatic, filter);
}
}
}
// In beef, all globals are stored inside global containers so we can skip the rest
bool skipMembers = (language == DbgLanguage_Beef) && (dbgType->mTypeCode == DbgType_Root);
if (skipMembers)
return;
for (auto member : dbgType->mMemberList)
{
if (((member->mIsStatic) && (wantsStatic)) ||
((!member->mIsStatic) && (wantsNonStatic)))
{
const char* name = member->mName;
if (name != NULL)
{
if (member->mName[0] == '?')
continue;
mAutoComplete->AddEntry(AutoCompleteEntry(GetTypeName(member->mType), name), filter);
if ((isCapture) && (strcmp(member->mName, "__this") == 0))
{
mAutoComplete->AddEntry(AutoCompleteEntry(GetTypeName(member->mType), "this"), filter);
auto thisType = member->mType;
if (thisType->IsPointer())
thisType = thisType->mTypeParam;
thisType = thisType->RemoveModifiers();
AutocompleteAddMembers(thisType, wantsStatic, wantsNonStatic, filter);
}
}
else
{
AutocompleteAddMembers(member->mType, wantsStatic, wantsNonStatic, filter);
}
}
}
if ((dbgType->IsNamespace()) || (dbgType->IsRoot()))
{
// We only add these ones because we can be certain they are all static, otherwise we need the full
// method information which is in the compile units
for (auto methodNameEntry : dbgType->mMethodNameList)
{
const char* methodName = methodNameEntry->mName;
AutocompleteAddMethod(methodName, filter);
}
}
else
{
//TODO: Not needed since we added the declarations now, right?
//dbgType->EnsureMethodsMapped();
}
for (auto method : dbgType->mMethodList)
{
if (((!method->mHasThis) && (wantsStatic)) ||
((method->mHasThis) && (wantsNonStatic)))
{
if ((method->mName != NULL) && (strcmp(method->mName, "this") != 0))
{
mDbgModule->FindTemplateStr(method->mName, method->mTemplateNameIdx);
if (method->mTemplateNameIdx == -1)
{
AutocompleteAddMethod(method->mName, filter);
}
}
}
}
/*if (!dbgType->mMethodNameList.IsEmpty())
{
BF_ASSERT(!dbgType->mMethodList.IsEmpty());
}*/
/*
for (auto methodNameEntry : dbgType->mMethodNameList)
{
const char* methodName = methodNameEntry->mName;
AutocompleteAddMethod(methodName, filter);
}*/
for (auto baseTypeEntry : dbgType->mBaseTypes)
{
AutocompleteAddMembers(baseTypeEntry->mBaseType, wantsStatic, wantsNonStatic, filter);
}
}
void DbgExprEvaluator::AutocompleteCheckMemberReference(BfAstNode* target, BfAstNode* dotToken, BfAstNode* memberName)
{
if ((IsAutoCompleteNode(dotToken)) || (IsAutoCompleteNode(memberName)))
{
mDbgModule->ParseGlobalsData();
bool isCType = dotToken->ToString() == "::";
String filter;
if (memberName != NULL)
{
filter = memberName->ToString();
mAutoComplete->mInsertStartIdx = memberName->GetSrcStart();
mAutoComplete->mInsertEndIdx = memberName->GetSrcEnd();
}
else
{
mAutoComplete->mInsertStartIdx = dotToken->GetSrcEnd();
mAutoComplete->mInsertEndIdx = dotToken->GetSrcEnd();
}
SetAndRestoreValue<bool> prevIgnoreError(mIgnoreErrors, true);
if (target == NULL)
{
mResult.mType = GetExpectingType();
if (mResult.mType != NULL)
mResult.mHasNoValue = true;
}
else if (auto typeRef = BfNodeDynCast<BfTypeReference>(target))
{
mResult.mType = ResolveTypeRef(typeRef);
mResult.mHasNoValue = true;
}
else
{
VisitChild(target);
GetResult();
}
if (mResult.mType != NULL)
{
mResult.mType = mResult.mType->RemoveModifiers();
auto dbgType = mResult.mType;
// if (dbgType->IsPrimitiveType())
// {
// //TODO: Boxed primitive structs
// }
//dbgType = dbgType->GetPrimaryType();
if ((dbgType != NULL) && (dbgType->IsPointerOrRef()))
{
dbgType = dbgType->mTypeParam;
dbgType = dbgType->RemoveModifiers();
}
//if (dbgType->mIsDeclaration)
dbgType = dbgType->GetPrimaryType();
if ((dbgType != NULL) /*&& ((dbgType->IsCompositeType()) || (dbgType->IsEnum()))*/)
{
bool wantsStatic = mResult.mHasNoValue;
bool wantsNonStatic = !mResult.mHasNoValue;
// C allows static lookups by non-static member reference
if (dbgType->GetLanguage() != DbgLanguage_Beef)
wantsStatic = true;
AutocompleteAddMembers(dbgType, wantsStatic, wantsNonStatic, filter);
if ((wantsStatic) && (dbgType->IsBfPayloadEnum()))
{
for (auto member : dbgType->mMemberList)
{
if ((member->mName[0] == '_') && (member->mName[1] >= '0') && (member->mName[1] <= '9'))
{
int val = atoi(member->mName + 1);
for (int i = 1; true; i++)
{
if (member->mName[i] == '_')
{
mAutoComplete->AddEntry(AutoCompleteEntry("method", member->mName + i + 1), filter);
break;
}
if (member->mName[i] == 0)
break;
}
}
}
}
}
//String prefixStr = dbgType->ToString();
//AutocompleteAddMembersFromNamespace(prefixStr, filter, isCType);
mResult = DbgTypedValue();
}
else
{
//return AutocompleteAddMembersFromNamespace(memberRefExpr->mTarget->ToString(), filter, isCType);
}
}
}
void DbgExprEvaluator::Visit(BfMemberReferenceExpression* memberRefExpr)
{
DbgTypedValue thisValue;
/*if (auto typeRef = BfNodeDynCast<DwTypeReference>(memberRefExpr->mTarget))
{
// Look up static field
//thisValue = DbgTypedValue(NULL, mModule->ResolveTypeRef(typeRef));
thisValue.mType = ResolveTypeRef(typeRef);
}*/
auto flavor = GetFlavor();
String findName;
BfAstNode* nameRefNode = memberRefExpr->mMemberName;
if (auto attrIdentifierExpr = BfNodeDynCast<BfAttributedIdentifierNode>(memberRefExpr->mMemberName))
{
nameRefNode = attrIdentifierExpr->mIdentifier;
if (nameRefNode != NULL)
findName = attrIdentifierExpr->mIdentifier->ToString();
}
else if (memberRefExpr->mMemberName != NULL)
findName = memberRefExpr->mMemberName->ToString();
AutocompleteCheckMemberReference(memberRefExpr->mTarget, memberRefExpr->mDotToken, nameRefNode);
//
{
SetAndRestoreValue<bool> prevIgnoreError(mIgnoreErrors, true);
mResult.mType = ResolveTypeRef(memberRefExpr);
if (mResult.mType != NULL)
{
mResult.mHasNoValue = true;
return;
}
}
if (memberRefExpr->mMemberName == NULL)
{
return;
}
if (memberRefExpr->mTarget == NULL)
{
auto expectingType = GetExpectingType();
if (expectingType != NULL)
{
DbgTypedValue expectingVal;
expectingVal.mType = expectingType;
mResult = LookupField(memberRefExpr->mMemberName, expectingVal, findName);
if ((mResult) || (HasPropResult()))
return;
}
}
{
SetAndRestoreValue<bool> prevIgnoreError(mIgnoreErrors, true);
if (memberRefExpr->mTarget == NULL)
thisValue.mType = mExpectingType;
else
thisValue.mType = ResolveTypeRef(memberRefExpr->mTarget, (BfAstNode**)&(memberRefExpr->mTarget));
if (thisValue.mType != NULL)
thisValue.mHasNoValue = true;
}
if (thisValue.mType == NULL)
{
if (auto exprTarget = BfNodeDynCast<BfExpression>(memberRefExpr->mTarget))
{
//thisValue = mModule->CreateValueFromExpression(exprTarget);
VisitChild(memberRefExpr->mTarget);
GetResult();
if (mResult.mType == NULL)
return;
mResult.mType = mResult.mType->RemoveModifiers();
thisValue = mResult;
}
else if (memberRefExpr->mTarget == NULL)
{
Fail("Identifier expected", memberRefExpr->mDotToken);
}
else
{
Fail("Unable to resolve target", memberRefExpr->mTarget);
}
}
/*else if (auto typeRef = BfNodeDynCast<BfTypeReference>(memberRefExpr->mTarget))
{
// Look up static field
thisValue.mType = ResolveTypeRef(typeRef);
}*/
if (thisValue.mSrcAddress == -1)
{
LookupSplatMember(memberRefExpr->mTarget, memberRefExpr, thisValue, findName);
}
else
mResult = LookupField(memberRefExpr->mMemberName, thisValue, findName);
/*if (mResult)
{
if (mReferenceId != NULL)
*mReferenceId = thisValue.mType->ToString() + "." + findName;
}*/
if ((!mResult) && (!HasPropResult()))
{
//String fullTokenString = memberRefExpr->ToString();
//mDbgModule->EnsureMethodsMapped(fullTokenString.c_str());
mResult = LookupField(memberRefExpr->mMemberName, thisValue, findName);
}
//TODO: Do type lookup?
if ((!mResult) && (!HasPropResult()))
{
if (thisValue.mHasNoValue)
{
for (auto altDwType : thisValue.mType->mAlternates)
{
auto altThisValue = thisValue;
altThisValue.mType = altDwType;
mResult = LookupField(memberRefExpr->mMemberName, altThisValue, findName);
if (mResult)
return;
}
}
Fail("Unable to find member", memberRefExpr->mMemberName);
}
}
DbgTypedValue DbgExprEvaluator::RemoveRef(DbgTypedValue typedValue)
{
bool hadRef = false;
typedValue.mType = typedValue.mType->RemoveModifiers(&hadRef);
if (hadRef)
typedValue.mSrcAddress = typedValue.mPtr;
return typedValue;
}
void DbgExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
{
VisitChild(indexerExpr->mTarget);
GetResult();
if (!mResult)
return;
DbgTypedValue collection = RemoveRef(mResult);
bool indexerFailed = false;
mIndexerValues.clear();
mIndexerExprValues.clear();
SizedArray<BfExpression*, 2> indexerExprValues;
SizedArray<DbgTypedValue, 2> indexerValues;
for (auto indexExpr : indexerExpr->mArguments)
{
indexerExprValues.push_back(indexExpr);
VisitChild(indexExpr);
GetResult();
if (!mResult)
indexerFailed = true;
indexerValues.push_back(mResult);
mResult = DbgTypedValue();
}
if (indexerFailed)
{
mResult = DbgTypedValue();
return;
}
bool isBfArrayIndex = false;
if ((collection.mType->IsBfObjectPtr()) || (collection.mType->IsStruct()))
{
DbgType* bfType = collection.mType->mTypeParam;
if (bfType != NULL)
{
DbgType* baseType = bfType->GetBaseType();
if ((baseType != NULL) && (strcmp(baseType->mName, "System.Array") == 0))
{
isBfArrayIndex = true;
}
}
if (!isBfArrayIndex)
{
mIndexerExprValues = indexerExprValues;
mIndexerValues = indexerValues;
mResult = LookupField(indexerExpr->mTarget, collection, "");
if (HasPropResult())
{
// Only use this if we actually have the method. Otherwise fall through so we can try a debug visualizer or something
if ((mPropGet != NULL) && (mPropGet->mBlock.mLowPC != 0))
return;
}
// else
// {
// mResult = DbgTypedValue();
// Fail(StrFormat("Unable to index type '%s'", TypeToString(collection.mType).c_str()), indexerExpr->mOpenBracket);
// }
// return;
}
}
if (indexerValues.size() != 1)
{
Fail("Expected single index", indexerExpr->mOpenBracket);
return;
}
DbgTypedValue indexArgument = indexerValues[0];
indexArgument.mType = indexArgument.mType->RemoveModifiers();
2019-08-23 11:56:54 -07:00
if (!indexArgument.mType->IsInteger())
{
mResult = DbgTypedValue();
Fail("Expected integer index", indexerExpr->mArguments[0]);
return;
}
if (mReferenceId != NULL)
*mReferenceId += "[]";
if (isBfArrayIndex)
{
DbgType* bfType = collection.mType->mTypeParam;
bfType = bfType->GetPrimaryType();
DbgType* baseType = bfType->GetBaseType();
DbgVariable* lenVariable = baseType->mMemberList.mHead;
DbgVariable* typeVariable = bfType->mMemberList.mTail;
if ((lenVariable != NULL) && (typeVariable != NULL))
{
int len = mDebugger->ReadMemory<int>(collection.mPtr + lenVariable->mMemberOffset);
int idx = (int)indexArgument.GetInt64();
if ((idx < 0) || (idx >= len))
{
Fail("Index out of range", indexerExpr->mArguments[0]);
return;
}
auto result = ReadTypedValue(indexerExpr, typeVariable->mType, collection.mPtr + typeVariable->mMemberOffset + (idx * typeVariable->mType->GetStride()), DbgAddrType_Target);
2019-08-23 11:56:54 -07:00
if (mResult.mIsReadOnly)
result.mIsReadOnly = true;
mResult = result;
return;
}
}
SetAndRestoreValue<String*> prevReferenceId(mReferenceId, NULL);
Array<String> dbgVisWildcardCaptures;
auto debugVis = mDebugger->FindVisualizerForType(collection.mType, &dbgVisWildcardCaptures);
if (debugVis != NULL)
{
if ((debugVis->mCollectionType == DebugVisualizerEntry::CollectionType_Array) && (debugVis->mLowerDimSizes.size() == 0))
{
auto debugVisualizers = mDebugger->mDebugManager->mDebugVisualizers;
DbgTypedValue sizeValue = mDebugger->EvaluateInContext(mDbgCompileUnit, collection, debugVisualizers->DoStringReplace(debugVis->mSize, dbgVisWildcardCaptures));
Array<int> lowerDimSizes;
if (sizeValue)
{
int len = (int)sizeValue.GetInt64();
int idx = (int)indexArgument.GetInt64();
if ((idx < 0) || (idx >= len))
{
Fail("Index out of range", indexerExpr->mArguments[0]);
return;
}
addr_target dataPtr = (collection.mType->IsPointer()) ? collection.mPtr : collection.mSrcAddress;
String ptrUseDataTypeStr = collection.mType->ToStringRaw();
String ptrUseDataStr = StrFormat("(%s)", ptrUseDataTypeStr.c_str()) + EncodeDataPtr(dataPtr, true);
//String evalStr = "(" + debugVisualizers->DoStringReplace(debugVis->mValuePointer, dbgVisWildcardCaptures) + StrFormat("[%d]), this=", idx);
String evalStr = "*(" + debugVisualizers->DoStringReplace(debugVis->mValuePointer, dbgVisWildcardCaptures) + StrFormat(" + %d), this=", idx) + ptrUseDataStr;
evalStr += ptrUseDataStr;
auto result = mDebugger->EvaluateInContext(mDbgCompileUnit, collection, evalStr);
if (mResult.mIsReadOnly)
result.mIsReadOnly = true;
mResult = result;
if (mResult)
return;
}
}
}
addr_target target = collection.mPtr;
if (collection.mType->mTypeCode == DbgType_SizedArray)
target = collection.mSrcAddress;
if ((!collection.mType->IsPointer()) && (collection.mType->mTypeCode != DbgType_SizedArray))
{
mResult = DbgTypedValue();
//Fail("Expected pointer type", indexerExpr->mTarget);
Fail(StrFormat("Unable to index type '%s'", TypeToString(collection.mType).c_str()), indexerExpr->mOpenBracket);
return;
}
if (collection.mType->mTypeCode == DbgType_SizedArray)
{
int innerSize = collection.mType->mTypeParam->GetStride();
int len = 0;
if (innerSize > 0)
len = collection.mType->GetStride() / innerSize;
int idx = (int)indexArgument.GetInt64();
if ((idx < 0) || (idx >= len))
{
Fail("Index out of range", indexerExpr->mArguments[0]);
return;
}
}
2019-12-24 10:32:20 -08:00
if ((collection.mType->IsBfObjectPtr()) || (collection.mType->IsStruct()))
{
// This should have been handled by some other cases
mResult = DbgTypedValue();
Fail(StrFormat("Unable to index type '%s'", TypeToString(collection.mType).c_str()), indexerExpr->mOpenBracket);
}
2019-08-23 11:56:54 -07:00
auto memberType = collection.mType->mTypeParam;
auto result = ReadTypedValue(indexerExpr, memberType, target + indexArgument.GetInt64() * memberType->GetStride(), DbgAddrType_Target);
2019-08-23 11:56:54 -07:00
if (mResult.mIsReadOnly)
result.mIsReadOnly = true;
mResult = result;
}
void DbgExprEvaluator::Visit(BfThisExpression* thisExpr)
{
if (mExplicitThis)
{
if (mExplicitThisExpr != NULL)
mDeferredInsertExplicitThisVector.push_back(NodeReplaceRecord(thisExpr, mCurChildRef));
mResult = mExplicitThis;
/*if (mReferenceId != NULL)
{
auto checkType = mExplicitThis.mType;
if (checkType->IsPointer())
checkType = checkType->mTypeParam;
*mReferenceId = checkType->ToString(true);
}*/
return;
}
bool hadError;
mResult = LookupIdentifier(thisExpr, false, &hadError);
if (!mResult)
{
if (GetCurrentMethod() != NULL)
Fail("Static methods don't have 'this'", thisExpr);
else
Fail("Execution must be paused to retrieve 'this'", thisExpr);
}
}
void DbgExprEvaluator::Visit(BfIdentifierNode* identifierNode)
{
2020-04-14 11:35:54 -07:00
//BfLogDbgExpr("Visit BfIdentifierNode %s\n", identifierNode->ToString().c_str());
2019-08-23 11:56:54 -07:00
mResult = LookupIdentifier(identifierNode, false, NULL);
if (!mResult)
{
//??
//mDbgModule->EnsureMethodsMapped(identifierNode->ToString().c_str());
//mResult = LookupIdentifier(identifierNode, false, NULL);
}
if ((mResult) || (HasPropResult()))
return;
{
SetAndRestoreValue<bool> prevIgnoreError(mIgnoreErrors, true);
mResult.mType = ResolveTypeRef(identifierNode);
if (mResult.mType != NULL)
{
mResult.mHasNoValue = true;
return;
}
}
Fail("Identifier not found", identifierNode);
}
void DbgExprEvaluator::Visit(BfMixinExpression* mixinExpr)
{
mResult = LookupIdentifier(mixinExpr, false, NULL);
if (mResult)
return;
Fail("Identifier not found", mixinExpr);
}
void DbgExprEvaluator::LookupSplatMember(const DbgTypedValue& target, const StringImpl& fieldName)
{
BF_ASSERT(target.mSrcAddress == -1);
DbgVariable* dbgVariable = (DbgVariable*)target.mVariable;
if (dbgVariable == NULL)
return;
auto wantType = target.mType->RemoveModifiers();
auto checkType = dbgVariable->mType->RemoveModifiers();
// Use real name, in case of aliases
String findName = target.mVariable->mName;
bool foundWantType = false;
/*if (checkType != wantType)
{
checkType = valType;
foundWantType = false;
if (checkType->IsBfPayloadEnum())
{
if (wasCast)
{
findName += "$u";
checkType = wantType;
foundWantType = true;
}
}
}*/
bool found = false;
while (checkType != NULL)
{
checkType = checkType->GetPrimaryType();
if ((!foundWantType) && (checkType->Equals(wantType)))
foundWantType = true;
if (foundWantType)
{
for (auto member : checkType->mMemberList)
{
if (member->mName == fieldName)
{
found = true;
break;
}
}
}
if (found)
break;
checkType = checkType->GetBaseType();
findName += "$b";
}
if (found)
{
findName = "$" + findName + "$m$" + fieldName;
CPUStackFrame* stackFrame = GetStackFrame();
intptr valAddr;
DbgType* valType;
DbgAddrType addrType = DbgAddrType_Value;
if (mDebugTarget->GetValueByName(GetCurrentMethod(), findName, stackFrame, &valAddr, &valType, &addrType))
{
BF_ASSERT(valType != NULL);
if (valType != NULL)
{
if (mReferenceId != NULL)
*mReferenceId = findName;
mResult = ReadTypedValue(NULL, valType, valAddr, addrType);
2019-08-23 11:56:54 -07:00
return;
}
}
}
}
void DbgExprEvaluator::LookupSplatMember(BfAstNode* targetNode, BfAstNode* lookupNode, const DbgTypedValue& target, const StringImpl& fieldName, String* outFindName, bool* outIsConst, StringImpl* forceName)
2019-08-23 11:56:54 -07:00
{
/*DbgVariable* dbgVariable = (DbgVariable*)target.mVariable;
if (dbgVariable != NULL)
return LookupSplatMember(target, fieldName);*/
auto curMethod = GetCurrentMethod();
2019-08-23 11:56:54 -07:00
while (auto parenNode = BfNodeDynCast<BfParenthesizedExpression>(lookupNode))
lookupNode = parenNode->mExpression;
SplatLookupEntry* splatLookupEntry = NULL;
if (lookupNode != NULL)
{
if (mSplatLookupMap.TryAdd(lookupNode, NULL, &splatLookupEntry))
{
//
}
else if (forceName == NULL)
{
2019-08-23 11:56:54 -07:00
if (outFindName != NULL)
*outFindName = splatLookupEntry->mFindName;
if (outIsConst != NULL)
*outIsConst = splatLookupEntry->mIsConst;
mResult = splatLookupEntry->mResult;
return;
}
}
String findName;
bool wasCast = false;
mResult = DbgTypedValue();
BfAstNode* checkNode = targetNode;
BfAstNode* parentNode = NULL;
while (true)
{
if (checkNode == NULL)
return;
if (auto qualifiedNameNode = BfNodeDynCast<BfQualifiedNameNode>(checkNode))
{
parentNode = qualifiedNameNode->mLeft;
findName = qualifiedNameNode->mRight->ToString();
break;
}
else if (auto memberRefExpr = BfNodeDynCast<BfMemberReferenceExpression>(checkNode))
{
parentNode = memberRefExpr->mTarget;
findName = memberRefExpr->mMemberName->ToString();
break;
}
else if (auto identifier = BfNodeDynCast<BfIdentifierNode>(checkNode))
{
findName = identifier->ToString();
break;
}
else if (auto thisExpr = BfNodeDynCast<BfThisExpression>(checkNode))
{
findName = thisExpr->ToString();
break;
}
else if (auto castExpr = BfNodeDynCast<BfCastExpression>(checkNode))
{
wasCast = true;
checkNode = castExpr->mExpression;
}
else if (auto parenExpr = BfNodeDynCast<BfParenthesizedExpression>(checkNode))
{
checkNode = parenExpr->mExpression;
}
else
return;
}
if (forceName != NULL)
findName = *forceName;
2019-08-23 11:56:54 -07:00
CPUStackFrame* stackFrame = GetStackFrame();
intptr valAddr;
DbgType* valType = NULL;
DbgAddrType addrType = DbgAddrType_Value;
bool foundWantType = true;
DbgType* wantType = target.mType;
auto checkType = target.mType;
checkType = checkType->RemoveModifiers();
bool valWasConst = false;
bool foundParent = false;
if (target.mSrcAddress == -1)
{
if (parentNode != NULL)
{
DbgTypedValue origTarget;
origTarget.mSrcAddress = -1;
origTarget.mType = target.mVariable->mType;
origTarget.mVariable = target.mVariable;
bool parentIsConst = false;
String parentFindName;
LookupSplatMember(parentNode, targetNode, origTarget, findName, &parentFindName, &parentIsConst);
if (!parentFindName.IsEmpty())
{
foundParent = true;
findName = parentFindName;
valType = mResult.mType;
valWasConst = parentIsConst;
}
}
}
if (!foundParent)
{
if (!mDebugTarget->GetValueByName(curMethod, findName, stackFrame, &valAddr, &valType, &addrType))
2019-08-23 11:56:54 -07:00
return;
if (addrType == DbgAddrType_Alias)
{
findName = (const char*)valAddr;
if (!mDebugTarget->GetValueByName(curMethod, findName, stackFrame, &valAddr, &valType, &addrType))
{
if (curMethod->mInlineeInfo != NULL)
{
// Look outside to inline
SetAndRestoreValue<int> prevStackIdx(mCallStackIdx, mCallStackIdx + 1);
LookupSplatMember(targetNode, lookupNode, target, fieldName, outFindName, outIsConst, &findName);
return;
}
return;
}
}
2019-08-23 11:56:54 -07:00
if (addrType == DbgAddrType_LocalSplat)
{
DbgVariable* dbgVariable = (DbgVariable*)valAddr;
// Use real name, in case of aliases
findName = dbgVariable->mName;
}
2019-08-23 11:56:54 -07:00
}
if ((wasCast) && (valType != NULL))
{
checkType = valType->RemoveModifiers();
foundWantType = false;
if (checkType->IsBfPayloadEnum())
{
if (wasCast)
{
findName += "$u";
checkType = wantType;
foundWantType = true;
}
}
}
mResult = DbgTypedValue();
if (valType != NULL)
valWasConst |= valType->IsConst();
DbgType* memberType = NULL;
bool found = false;
bool wasUnion = false;
while (checkType != NULL)
{
checkType = checkType->GetPrimaryType();
if ((!foundWantType) && (checkType->Equals(wantType)))
foundWantType = true;
if (foundWantType)
{
for (auto member : checkType->mMemberList)
{
if (member->mName == fieldName)
{
wasUnion = checkType->IsBfUnion();
memberType = member->mType;
found = true;
break;
}
}
}
if (found)
break;
checkType = checkType->GetBaseType();
findName += "$b";
}
if (found)
{
bool wantConst = ((valWasConst) && (!memberType->IsConst()) && (!memberType->IsRef()));
if (!findName.StartsWith("$"))
findName = "$" + findName;
if (wasUnion)
findName += "$u";
else
findName += "$m$" + fieldName;
if (outFindName != NULL)
*outFindName = findName;
if (outIsConst != NULL)
*outIsConst = wantConst;
if (mDebugTarget->GetValueByName(curMethod, findName, stackFrame, &valAddr, &valType, &addrType))
2019-08-23 11:56:54 -07:00
{
BF_ASSERT(valType != NULL);
if (valType != NULL)
{
if (mReferenceId != NULL)
*mReferenceId = findName;
/*if ((valType->IsConst()) && (!memberType->IsConst()))
{
// Set readonly if the original value was const
memberType = mDbgModule->GetConstType(valType);
}*/
mResult = ReadTypedValue(targetNode, memberType, valAddr, addrType);
2019-08-23 11:56:54 -07:00
if (wantConst)
{
// Set readonly if the original value was const
mResult.mIsReadOnly = true;
}
}
}
else
{
if (target.mSrcAddress == -1)
{
// if (curMethod->mInlineeInfo != NULL)
// {
// // Look outside to inline
// SetAndRestoreValue<int> prevStackIdx(mCallStackIdx, mCallStackIdx + 1);
// LookupSplatMember(targetNode, lookupNode, target, fieldName, outFindName, outIsConst, true);
// return;
// }
2019-08-23 11:56:54 -07:00
if (!memberType->IsStruct())
Fail("Failed to lookup splat member", (lookupNode != NULL) ? lookupNode : targetNode);
BF_ASSERT((target.mVariable != NULL) || (target.mType->GetByteCount() == 0));
mResult = target;
mResult.mType = memberType;
}
}
if (splatLookupEntry != NULL)
{
splatLookupEntry->mFindName = findName;
splatLookupEntry->mIsConst = wantConst;
splatLookupEntry->mResult = mResult;
}
}
}
void DbgExprEvaluator::LookupQualifiedName(BfQualifiedNameNode* nameNode, bool ignoreInitialError, bool* hadError)
{
String fieldName = nameNode->mRight->ToString();
mResult = LookupIdentifier(nameNode->mLeft, ignoreInitialError, hadError);
mResult = GetResult();
if (!mResult)
{
if (!ignoreInitialError)
Fail("Identifier not found", nameNode->mLeft);
return;
}
if (!mResult)
return;
/*if (!mResult.mType->IsTypeInstance())
{
Fail("Type has no fields", nameNode->mLeft);
return;
}*/
if (mResult.mSrcAddress == -1)
{
auto target = mResult;
mResult = DbgTypedValue();
LookupSplatMember(nameNode->mLeft, nameNode, target, fieldName);
}
else
{
mResult = LookupField(nameNode, mResult, fieldName);
if (mPropSrc != NULL)
{
if (nameNode->mLeft->ToString() == "base")
{
//mPropDefBypassVirtual = true;
}
}
}
if ((mResult) || (mPropSrc != NULL))
return;
if (hadError != NULL)
*hadError = true;
Fail("Unable to find member", nameNode->mRight);
}
DbgType* DbgExprEvaluator::FindSubtype(DbgType* type, const StringImpl& name)
{
for (auto subType : type->mSubTypeList)
{
if ((subType->mTypeName != NULL) && (strcmp(subType->mTypeName, name.c_str()) == 0))
return subType;
}
for (auto baseType : type->mBaseTypes)
{
auto subType = FindSubtype(baseType->mBaseType->GetPrimaryType(), name);
if (subType != NULL)
return subType;
}
return NULL;
}
void DbgExprEvaluator::LookupQualifiedStaticField(BfQualifiedNameNode* nameNode, bool ignoreIdentifierNotFoundError)
{
// Lookup left side as a type
{
DbgType* type;
{
SetAndRestoreValue<bool> prevIgnoreErro(mIgnoreErrors, true);
type = ResolveTypeRef(nameNode->mLeft);
}
if (type != NULL)
{
DbgTypedValue lookupType;
/*if (type->IsPrimitiveType())
lookupType.mType = mModule->GetPrimitiveStructType(type));
else*/
lookupType.mType = type;
lookupType.mHasNoValue = true;
mResult = LookupField(nameNode->mRight, lookupType, nameNode->mRight->ToString());
if ((mResult) || (mPropSrc != NULL))
return;
DbgType* fullType = NULL;
//
{
SetAndRestoreValue<bool> prevIgnoreError(mIgnoreErrors, true);
fullType = ResolveTypeRef(nameNode);
if ((fullType == NULL) && (!type->IsNamespace()))
{
String subName = nameNode->mRight->ToString();
fullType = FindSubtype(type, subName);
}
}
if (fullType != NULL)
{
mResult.mType = fullType;
mResult.mHasNoValue = true;
return;
}
Fail("Field not found", nameNode->mRight);
return;
}
}
String fieldName = nameNode->mRight->ToString();
if (auto qualifiedLeftName = BfNodeDynCast<BfQualifiedNameNode>(nameNode->mLeft))
LookupQualifiedStaticField(qualifiedLeftName);
else
VisitChild(nameNode->mLeft);
GetResult();
if (!mResult)
{
Fail("Identifier not found", nameNode->mLeft);
return;
}
if (!mResult)
return;
auto checkType = mResult.mType->RemoveModifiers();
if (checkType->IsPointer())
checkType = checkType->mTypeParam;
if ((checkType == NULL) || (!checkType->IsCompositeType()))
{
Fail("Type has no fields", nameNode->mLeft);
return;
}
mResult = LookupField(nameNode, mResult, fieldName);
if ((mResult) || (mPropSrc != NULL))
return;
Fail("Unable to find member", nameNode->mRight);
}
bool DbgExprEvaluator::EnsureRunning(BfAstNode* astNode)
{
if (mDebugger->mIsRunning)
return true;
Fail("Target is not running", astNode);
return false;
}
void DbgExprEvaluator::Visit(BfQualifiedNameNode* nameNode)
{
AutocompleteCheckMemberReference(nameNode->mLeft, nameNode->mDot, nameNode->mRight);
bool hadError = false;
LookupQualifiedName(nameNode, true, &hadError);
if ((mResult) || (mPropSrc != NULL))
return;
if (hadError)
return;
LookupQualifiedStaticField(nameNode);
}
void DbgExprEvaluator::Visit(BfDefaultExpression* defaultExpr)
{
mIsComplexExpression = true;
/*auto type = mModule->ResolveTypeRef(defaultExpr->mTypeRef);
if (!type)
return;
mResult = DbgTypedValue(mModule->GetDefaultValue(type), type);*/
}
void DbgExprEvaluator::Visit(BfLiteralExpression* literalExpr)
{
mIsComplexExpression = true;
mResult.mIsLiteral = true;
auto language = GetLanguage();
switch (literalExpr->mValue.mTypeCode)
{
case BfTypeCode_NullPtr:
{
mResult.mPtr = 0;
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Null, GetLanguage());
}
break;
case BfTypeCode_CharPtr:
mResult = GetString(*literalExpr->mValue.mString);
break;
case BfTypeCode_Boolean:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
mResult.mBool = literalExpr->mValue.mBool;
break;
case BfTypeCode_Char8:
mResult.mType = mDbgModule->GetPrimitiveType((language == DbgLanguage_Beef) ? DbgType_UChar : DbgType_SChar, language);
mResult.mInt8 = literalExpr->mValue.mInt8;
break;
case BfTypeCode_Char16:
mResult.mType = mDbgModule->GetPrimitiveType((language == DbgLanguage_Beef) ? DbgType_UChar16 : DbgType_SChar16, language);
mResult.mInt16 = literalExpr->mValue.mInt16;
break;
case BfTypeCode_Char32:
mResult.mType = mDbgModule->GetPrimitiveType((language == DbgLanguage_Beef) ? DbgType_UChar32 : DbgType_SChar32, language);
mResult.mInt32 = literalExpr->mValue.mInt32;
break;
case BfTypeCode_Int8:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_i8, GetLanguage());
mResult.mUInt8 = literalExpr->mValue.mUInt8;
break;
case BfTypeCode_UInt8:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_u8, GetLanguage());
mResult.mUInt8 = literalExpr->mValue.mUInt8;
break;
case BfTypeCode_Int16:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_i16, GetLanguage());
mResult.mInt16 = literalExpr->mValue.mInt16;
break;
case BfTypeCode_UInt16:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_u16, GetLanguage());
mResult.mUInt16 = literalExpr->mValue.mUInt16;
break;
case BfTypeCode_Int32:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_i32, GetLanguage());
mResult.mInt32 = literalExpr->mValue.mInt32;
break;
case BfTypeCode_UInt32:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_u32, GetLanguage());
mResult.mUInt32 = literalExpr->mValue.mUInt32;
break;
case BfTypeCode_Int64:
case BfTypeCode_IntUnknown:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_i64, GetLanguage());
mResult.mInt64 = literalExpr->mValue.mInt64;
break;
case BfTypeCode_UInt64:
case BfTypeCode_UIntUnknown:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_u64, GetLanguage());
mResult.mUInt64 = literalExpr->mValue.mUInt64;
break;
case BfTypeCode_IntPtr:
if (sizeof(addr_target) == 8)
{
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_i64, GetLanguage());
mResult.mInt64 = literalExpr->mValue.mInt64;
}
else
{
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_i32, GetLanguage());
mResult.mInt32 = literalExpr->mValue.mInt32;
}
break;
case BfTypeCode_UIntPtr:
if (sizeof(addr_target) == 8)
{
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_u64, GetLanguage());
mResult.mUInt64 = literalExpr->mValue.mUInt64;
}
else
{
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_u32, GetLanguage());
mResult.mUInt32 = literalExpr->mValue.mUInt32;
}
break;
case BfTypeCode_Float:
2019-08-23 11:56:54 -07:00
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Single, GetLanguage());
mResult.mSingle = literalExpr->mValue.mSingle;
break;
case BfTypeCode_Double:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Double, GetLanguage());
mResult.mDouble = literalExpr->mValue.mDouble;
break;
default:
Fail("Invalid literal", literalExpr);
break;
}
}
void DbgExprEvaluator::Visit(BfCastExpression* castExpr)
{
mIsComplexExpression = true;
if (castExpr->mTypeRef == NULL)
return; // Error
AutocompleteCheckType(castExpr->mTypeRef);
auto resolvedType = ResolveTypeRef(castExpr->mTypeRef);
if (resolvedType == NULL)
return;
if (mExplicitThisExpr != NULL)
mDeferredInsertExplicitThisVector.push_back(NodeReplaceRecord(castExpr->mTypeRef, (BfAstNode**)&castExpr->mTypeRef));
mResult = CreateValueFromExpression(castExpr->mExpression);
if (!mResult)
return;
mResult = Cast(castExpr, mResult, resolvedType, true);
}
// We pass by reference to support "RAW" debug expression simplification
DbgTypedValue DbgExprEvaluator::CreateValueFromExpression(ASTREF(BfExpression*)& expr, DbgType* castToType, DbgEvalExprFlags flags)
{
//
{
BP_ZONE("DbgExprEvaluator::CreateValueFromExpression:CheckStack");
StackHelper stackHelper;
if (!stackHelper.CanStackExpand(64 * 1024))
{
DbgTypedValue result;
if (!stackHelper.Execute([&]()
{
result = CreateValueFromExpression(expr, castToType, flags);
}))
{
Fail("Expression too complex", expr);
}
return result;
}
}
mExpectingType = castToType;
VisitChild(expr);
GetResult();
auto result = mResult;
if ((result) && (castToType != NULL) && ((flags & DbgEvalExprFlags_NoCast) == 0))
result = Cast(expr, result, castToType, false);
mResult = DbgTypedValue();
if ((result.mHasNoValue) && ((flags & DbgEvalExprFlags_AllowTypeResult) == 0))
Fail("Value expected", expr);
return result;
}
void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpression, ASTREF(BfExpression*)& rightExpression, BfBinaryOp binaryOp, BfTokenNode* opToken, bool forceLeftType)
{
DbgTypedValue leftValue;
if (leftExpression != NULL)
leftValue = CreateValueFromExpression(leftExpression, mExpectingType, DbgEvalExprFlags_NoCast);
DbgTypedValue rightValue;
if (rightExpression == NULL)
{
return;
}
if (!leftValue)
{
VisitChild(rightExpression);
return;
}
leftValue.mType = leftValue.mType->RemoveModifiers();
/*if (leftValue.mType->IsRef())
leftValue.mType = leftValue.mType->GetUnderlyingType();*/
if ((binaryOp == BfBinaryOp_ConditionalAnd) || (binaryOp == BfBinaryOp_ConditionalOr))
{
bool isAnd = binaryOp == BfBinaryOp_ConditionalAnd;
if (!leftValue.mType->IsBoolean())
{
Fail(StrFormat("Operator requires boolean operand. Left hand side is '%s", leftValue.mType->ToString().c_str()), opToken);
return;
}
auto boolType = leftValue.mType;
if (isAnd)
{
if (!leftValue.mBool)
{
mResult = leftValue;
return;
}
rightValue = CreateValueFromExpression(rightExpression);
if (rightValue)
rightValue = Cast(rightExpression, rightValue, boolType);
mResult = rightValue;
}
else
{
if (leftValue.mBool)
{
mResult = leftValue;
return;
}
rightValue = CreateValueFromExpression(rightExpression);
if (rightValue)
rightValue = Cast(rightExpression, rightValue, boolType);
mResult = rightValue;
}
return;
}
if ((binaryOp == BfBinaryOp_NullCoalesce) && ((leftValue.mType->IsPointer()) || (leftValue.mType->IsBfObject())))
{
if (leftValue.mPtr != 0)
{
mResult = leftValue;
return;
}
CreateValueFromExpression(rightExpression, leftValue.mType);
return;
}
rightValue = CreateValueFromExpression(rightExpression, mExpectingType, DbgEvalExprFlags_NoCast);
if ((!leftValue) || (!rightValue))
return;
rightValue.mType = rightValue.mType->RemoveModifiers();
if (leftValue.mType->IsTypedPrimitive())
leftValue.mType = leftValue.mType->GetUnderlyingType();
if (rightValue.mType->IsTypedPrimitive())
rightValue.mType = rightValue.mType->GetUnderlyingType();
// Prefer floats, prefer unsigned
int leftCompareSize = leftValue.mType->GetByteCount();
if (leftValue.mType->IsFloat())
leftCompareSize += 16;
if (!leftValue.mType->IsPrimitiveType())
leftCompareSize += 0x100;
if ((leftValue.mIsLiteral) && (leftValue.mType->IsPointer()))
leftCompareSize += 0x200;
int rightCompareSize = rightValue.mType->GetByteCount();
if (rightValue.mType->IsFloat())
rightCompareSize += 16;
if (!rightValue.mType->IsPrimitiveType())
rightCompareSize += 0x100;
if ((rightValue.mIsLiteral) && (rightValue.mType->IsPointer()))
rightCompareSize += 0x200;
/*if ((leftValue.mType->IsTypedPrimitive()) && (rightValue.mType->IsTypedPrimitive()))
{
int leftInheritDepth = leftValue.mType->ToTypeInstance()->mInheritDepth;
int rightInheritDepth = rightValue.mType->ToTypeInstance()->mInheritDepth;
if (leftInheritDepth < rightInheritDepth)
{
// If both are typed primitives then choose the type with the lowest inherit depth
// so we will choose the base type when applicable
forceLeftType = true;
}
}*/
auto resultType = leftValue.mType;
if (!forceLeftType)
{
if ((resultType->IsNull()) ||
(rightCompareSize > leftCompareSize) ||
(((rightCompareSize == leftCompareSize) && (!rightValue.mType->IsSigned()))) ||
(rightValue.mType->IsTypedPrimitive()))
{
// Select the type with the "most information"
if (!rightValue.mType->IsNull())
resultType = rightValue.mType;
}
if ((!resultType->IsPointer()) && (rightValue.mType->IsPointer()))
resultType = rightValue.mType;
}
//bool explicitCast = false;
bool explicitCast = true;
DbgTypedValue* resultTypedValue;
DbgTypedValue* otherTypedValue;
DbgType* otherType;
BfAstNode* resultTypeSrc;
BfAstNode* otherTypeSrc;
if (resultType == leftValue.mType)
{
resultTypedValue = &leftValue;
resultTypeSrc = leftExpression;
otherTypedValue = &rightValue;
otherTypeSrc = rightExpression;
otherType = otherTypedValue->mType;
}
else
{
resultTypedValue = &rightValue;
resultTypeSrc = rightExpression;
otherTypedValue = &leftValue;
otherTypeSrc = leftExpression;
otherType = otherTypedValue->mType;
}
if ((resultTypedValue->mIsLiteral) && (resultType->IsPointer()))
{
// If we're comparing against a string literal like 'str == "Hey!"', handle that
2020-06-17 05:13:53 -07:00
if (BfBinOpEqualityCheck(binaryOp))
2019-08-23 11:56:54 -07:00
{
DbgType* useType = otherType;
useType = useType->RemoveModifiers();
if (useType->IsPointer())
useType = useType->mTypeParam;
DbgTypedValue useTypedValue = *otherTypedValue;
if (useTypedValue.mType->IsPointer())
{
useTypedValue.mSrcAddress = useTypedValue.mPtr;
useTypedValue.mType = useTypedValue.mType->mTypeParam;
}
auto language = useType->GetLanguage();
auto dbgCompileUnit = useType->mCompileUnit;
auto dbgModule = useType->GetDbgModule();
Array<String> dbgVisWildcardCaptures;
auto debugVis = mDebugger->FindVisualizerForType(useType, &dbgVisWildcardCaptures);
if (debugVis != NULL)
{
auto& displayStringList = debugVis->mStringViews;
String displayString;
for (auto displayEntry : displayStringList)
{
auto& displayStringList = debugVis->mStringViews;
DwFormatInfo formatInfo;
formatInfo.mRawString = true;
formatInfo.mLanguage = language;
if (!displayEntry->mCondition.empty())
{
if (!mDebugger->EvalCondition(debugVis, dbgCompileUnit, useTypedValue, formatInfo, displayEntry->mCondition, dbgVisWildcardCaptures, displayString))
continue;
}
String displayStr = mDebugger->mDebugManager->mDebugVisualizers->DoStringReplace(displayEntry->mString, dbgVisWildcardCaptures);
mDebugger->ProcessEvalString(dbgCompileUnit, useTypedValue, displayStr, displayString, formatInfo, debugVis, false);
bool isEq = displayString == resultTypedValue->mCharPtr;
auto boolType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
mResult.mType = boolType;
2020-06-17 05:13:53 -07:00
mResult.mBool = isEq == ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality));
2019-08-23 11:56:54 -07:00
return;
}
}
}
Fail("Cannot perform operation with a literal value", resultTypeSrc);
return;
}
DbgTypedValue convLeftValue;
DbgTypedValue convRightValue;
/*if ((resultType->IsVar()) || (otherType->IsVar()))
{
mResult = DbgTypedValue(mModule->GetDefaultValue(resultType), resultType);
return;
}*/
2020-06-17 05:13:53 -07:00
if ((otherType->IsNull()) && BfBinOpEqualityCheck(binaryOp))
2019-08-23 11:56:54 -07:00
{
2020-06-17 05:13:53 -07:00
bool isEquality = (binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality);
2019-08-23 11:56:54 -07:00
if (resultType->IsValueType())
{
/*if (!mModule->IsInSpecializedGeneric())
{
//CS0472: The result of the expression is always 'true' since a value of type 'int' is never equal to 'null' of type '<null>'
mModule->mCompiler->mPassInstance->Warn(BfWarning_CS0472_ValueTypeNullCompare,
StrFormat("The result of the expression is always '%s' since a value of type '%s' can never be null",
isEquality ? "false" : "true", mModule->TypeToString(resultType).c_str()), otherTypeSrc);
}*/
// Valuetypes never equal null
auto boolType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
mResult.mType = boolType;
mResult.mBool = !isEquality;
return;
}
}
//TODO: Use operator methods?
/*if ((leftValue.mType->IsTypeInstance()) || (rightValue.mType->IsTypeInstance()))
{
SmallVector<BfResolvedArg, 2> args;
BfResolvedArg leftArg;
leftArg.mExpression = leftExpression;
leftArg.mTypedValue = leftValue;
args.push_back(leftArg);
BfResolvedArg rightArg;
rightArg.mExpression = rightExpression;
rightArg.mTypedValue = rightValue;
args.push_back(rightArg);
BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL);
BfBaseClassWalker baseClassWalker(leftValue.mType->ToTypeInstance(), rightValue.mType->ToTypeInstance());
bool invertResult = false;
while (auto checkType = baseClassWalker.Next())
{
BfOperatorDef* oppositeOperatorDef = NULL;
BfBinaryOp oppositeBinaryOp = GetOppositeBinaryOp(binaryOp);
for (auto operatorDef : checkType->mTypeDef->mOperators)
{
if (operatorDef->mOperatorDeclaration->mBinOp == binaryOp)
methodMatcher.CheckMethod(checkType, operatorDef);
else if (operatorDef->mOperatorDeclaration->mBinOp == oppositeBinaryOp)
oppositeOperatorDef = operatorDef;
}
if ((methodMatcher.mBestMethodDef == NULL) && (oppositeOperatorDef != NULL))
{
if (methodMatcher.CheckMethod(checkType, oppositeOperatorDef))
invertResult = true;
}
}
if (methodMatcher.mBestMethodDef != NULL)
{
SetElementType(opToken, BfSourceElementType_Method);
mResult = CreateCall(&methodMatcher, DbgTypedValue());
if ((invertResult) && (mResult.mType == mModule->GetPrimitiveType(BfTypeCode_Boolean)))
mResult.mValue = mModule->mIRBuilder->CreateNot(mResult.mValue);
return;
}
}*/
if (resultType->IsPointer() && otherType->IsPointer())
{
//TODO: Allow all pointer comparisons, but only allow SUBTRACTION between equal pointer types
if (binaryOp == BfBinaryOp_Subtract)
{
if (!resultType->Equals(otherType))
{
Fail(StrFormat("Operands must be the same type, '%s' doesn't match '%s'",
leftValue.mType->ToString().c_str(), rightValue.mType->ToString().c_str()),
opToken);
return;
}
DbgType* intPtrType = mDbgModule->GetPrimitiveType(DbgType_IntPtr_Alias, GetLanguage());
long ptrDiff = leftValue.mPtr - rightValue.mPtr;
int elemSize = resultType->mTypeParam->GetStride();
if (elemSize == 0)
{
Fail("Invalid operation on void values", opToken);
return;
}
//BF_ASSERT((ptrDiff % elemSize) == 0);
mResult.mInt64 = ptrDiff / elemSize;
mResult.mType = intPtrType;
return;
}
2020-06-17 05:13:53 -07:00
else if ((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_StrictEquality) &
(binaryOp != BfBinaryOp_InEquality) && (binaryOp != BfBinaryOp_StrictInEquality) &&
2019-08-23 11:56:54 -07:00
(binaryOp != BfBinaryOp_LessThan) && (binaryOp != BfBinaryOp_LessThanOrEqual) &&
(binaryOp != BfBinaryOp_GreaterThan) && (binaryOp != BfBinaryOp_GreaterThanOrEqual))
{
Fail("Invalid operation on pointers", opToken);
return;
}
// Compare them as ints
resultType = mDbgModule->GetPrimitiveType(DbgType_UIntPtr_Alias, GetLanguage());
explicitCast = true;
}
else if (resultType->IsPointer())
{
if (otherType->IsNull())
{
2020-06-17 05:13:53 -07:00
if (!BfBinOpEqualityCheck(binaryOp))
2019-08-23 11:56:54 -07:00
{
Fail(StrFormat("Invalid operation between '%s' and null", resultType->ToString().c_str()), opToken);
return;
}
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (binaryOp == BfBinaryOp_Equality)
mResult.mBool = resultTypedValue->mPtr == NULL;
else
mResult.mBool = resultTypedValue->mPtr != NULL;
return;
}
bool isCompare = (binaryOp >= BfBinaryOp_Equality) && (binaryOp <= BfBinaryOp_LessThanOrEqual);
// One pointer
if ((!otherType->IsInteger()) ||
2021-07-15 06:01:17 -07:00
((binaryOp != BfBinaryOp_Add) && (binaryOp != BfBinaryOp_Subtract) && (binaryOp != BfBinaryOp_OverflowAdd) && (binaryOp != BfBinaryOp_OverflowSubtract) && (!isCompare)))
2019-08-23 11:56:54 -07:00
{
Fail("Can only add or subtract integer values from pointers", rightExpression);
return;
}
2021-07-15 06:01:17 -07:00
if ((binaryOp == BfBinaryOp_Add) || (binaryOp == BfBinaryOp_Subtract) || (binaryOp == BfBinaryOp_OverflowAdd) || (binaryOp == BfBinaryOp_OverflowSubtract))
2019-08-23 11:56:54 -07:00
{
auto underlyingType = otherType->GetUnderlyingType();
mResult.mType = resultType;
DbgType* innerType = resultType->mTypeParam;
if (binaryOp == BfBinaryOp_Subtract)
{
if (resultTypeSrc == rightExpression)
Fail("Cannot subtract a pointer from an integer", resultTypeSrc);
mResult.mPtr = resultTypedValue->mPtr - otherTypedValue->GetInt64() * innerType->GetStride();
}
else
{
mResult.mPtr = resultTypedValue->mPtr + otherTypedValue->GetInt64() * innerType->GetStride();
}
if (innerType->GetByteCount() == 0)
{
Warn("Adding to a pointer to a zero-sized element has no effect", opToken);
}
return;
}
}
if ((resultType->IsPointer()) || (resultType->IsBfObject()) || (resultType->IsInterface()) /*|| (resultType->IsGenericParam())*/)
{
2020-06-17 05:13:53 -07:00
if (!BfBinOpEqualityCheck(binaryOp))
2019-08-23 11:56:54 -07:00
{
if (resultType->IsPointer())
Fail("Invalid operation for pointers", opToken);
else
Fail("Invalid operation for objects", opToken);
2019-08-23 11:56:54 -07:00
return;
}
if (otherType->IsNull())
{
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
2020-06-17 05:13:53 -07:00
if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality))
2019-08-23 11:56:54 -07:00
mResult.mBool = resultTypedValue->mPtr == NULL;
else
mResult.mBool = resultTypedValue->mPtr != NULL;
}
else
{
bool explicitCast = true;
if (otherType->IsInteger())
explicitCast = true;
auto convertedValue = Cast(otherTypeSrc, *otherTypedValue, resultType, explicitCast);
if (!convertedValue)
return;
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
2020-06-17 05:13:53 -07:00
if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality))
2019-08-23 11:56:54 -07:00
mResult.mBool = resultTypedValue->mPtr == convertedValue.mPtr;
else
mResult.mBool = resultTypedValue->mPtr != convertedValue.mPtr;
}
return;
}
/*else if (resultType->IsTypedPrimitive())
{
bool needsOtherCast = true;
if (otherType != resultType)
{
if (otherType->IsPrimitiveType())
{
// Allow zero comparisons to match all typed primitives
if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_InEquality))
{
auto intConstant = dyn_cast<ConstantInt>(otherTypedValue->mValue);
if (intConstant != NULL)
{
if (intConstant->getSExtValue() == 0)
{
needsOtherCast = false;
}
}
}
}
if (needsOtherCast)
{
// The only purpose of this cast is to potentially throw a casting error
Value* otherCastResult = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, explicitCast);
if (otherCastResult == NULL)
return;
}
}
auto underlyingType = resultType->GetUnderlyingType();
Value* convResultValue = mModule->CastToValue(resultTypeSrc, *resultTypedValue, underlyingType, true);
Value* convOtherValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, underlyingType, true);
if ((!underlyingType->IsValuelessType()) && ((convResultValue == NULL) || (convOtherValue == NULL)))
return;
if (resultTypedValue == &leftValue)
PerformBinaryOperation(underlyingType, convResultValue, convOtherValue, binaryOp, opToken);
else
PerformBinaryOperation(underlyingType, convOtherValue, convResultValue, binaryOp, opToken);
if (mResult.mType == underlyingType)
mResult.mType = resultType;
return;
}*/
else if (((leftValue.mType->IsStruct()) || (leftValue.mType->IsBfObject())) && (!resultType->IsEnum()))
{
if (leftValue.mType == rightValue.mType)
{
Fail(StrFormat("Operator '%s' cannot be applied to operands of type '%s'",
opToken->ToString().c_str(),
TypeToString(leftValue.mType).c_str()), opToken);
}
else
{
Fail(StrFormat("Operator '%s' cannot be applied to operands of type '%s' and '%s'",
opToken->ToString().c_str(),
TypeToString(leftValue.mType).c_str(),
TypeToString(rightValue.mType).c_str()), opToken);
}
return;
}
if ((resultType->IsInteger()) && (!forceLeftType))
{
bool isBitwiseExpr =
(binaryOp == BfBinaryOp_BitwiseAnd) |
(binaryOp == BfBinaryOp_BitwiseOr) |
(binaryOp == BfBinaryOp_ExclusiveOr) |
(binaryOp == BfBinaryOp_LeftShift) |
(binaryOp == BfBinaryOp_RightShift);
// For binary expressions we don't promote to 'int' unless the types don't match
if ((!isBitwiseExpr) || (leftValue.mType != rightValue.mType))
{
if (binaryOp == BfBinaryOp_Subtract)
{
}
else if (resultType->GetByteCount() < 4)
{
resultType = mDbgModule->GetPrimitiveType(DbgType_i32, GetLanguage());
}
else if (leftValue.mType != rightValue.mType)
{
if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift))
{
// For shifts we leave it in the target type if we're already at 'int' or higher
}
else if ((!resultType->IsSigned()) && (otherType->IsSigned()))
{
/*if (CanCast(*otherTypedValue, resultType))
2019-08-23 11:56:54 -07:00
{
// If we can convert the 'other' value implicitly then it's a convertible literal, leave as uint
}
else if (resultType->mSize == 4)
{
resultType = mDbgModule->GetPrimitiveType(DbgType_i64);
}
else
{
Fail(StrFormat("Operator cannot be applied to operands of type '%s' and '%s'",
TypeToString(leftValue.mType).c_str(),
TypeToString(rightValue.mType).c_str()), opToken);
return;
}*/
explicitCast = true;
}
}
}
}
if (convLeftValue == NULL)
convLeftValue = Cast(leftExpression, leftValue, resultType, explicitCast);
if (convRightValue == NULL)
convRightValue = Cast(rightExpression, rightValue, resultType, explicitCast);
PerformBinaryOperation(resultType, convLeftValue, convRightValue, binaryOp, opToken);
}
void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue convLeftValue, DbgTypedValue convRightValue, BfBinaryOp binaryOp, BfTokenNode* opToken)
{
if (resultType->IsValuelessType())
{
switch (binaryOp)
{
case BfBinaryOp_Equality:
2020-06-17 05:13:53 -07:00
case BfBinaryOp_StrictEquality:
2019-08-23 11:56:54 -07:00
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
mResult.mBool = true;
break;
case BfBinaryOp_InEquality:
2020-06-17 05:13:53 -07:00
case BfBinaryOp_StrictInEquality:
2019-08-23 11:56:54 -07:00
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
mResult.mBool = false;
break;
default:
Fail("Invalid operation for void", opToken);
break;
}
return;
}
if ((convLeftValue == NULL) || (convRightValue == NULL))
return;
if ((resultType->IsEnum()) || (resultType->IsTypedPrimitive()))
resultType = resultType->GetUnderlyingType();
if (resultType->IsPrimitiveType())
{
auto primType = resultType;
if (primType->mTypeCode == DbgType_Bool)
{
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
switch (binaryOp)
{
2020-06-17 05:13:53 -07:00
case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
2019-08-23 11:56:54 -07:00
mResult.mBool = convLeftValue.mBool == convRightValue.mBool;
break;
case BfBinaryOp_InEquality:
2020-06-17 05:13:53 -07:00
case BfBinaryOp_StrictInEquality:
2019-08-23 11:56:54 -07:00
mResult.mBool = convLeftValue.mBool != convRightValue.mBool;
break;
case BfBinaryOp_ConditionalAnd:
mResult.mBool = convLeftValue.mBool && convRightValue.mBool;
break;
case BfBinaryOp_ConditionalOr:
mResult.mBool = convLeftValue.mBool | convRightValue.mBool;
break;
case BfBinaryOp_ExclusiveOr:
mResult.mBool = convLeftValue.mBool ^ convRightValue.mBool;
break;
default:
Fail("Invalid operation for booleans", opToken);
break;
}
return;
}
}
if ((!resultType->IsIntegral()) && (!resultType->IsFloat()))
{
Fail(StrFormat("Cannot perform operation on type '%s'", TypeToString(resultType).c_str()), opToken);
return;
}
mResult.mType = resultType;
if (resultType->IsInteger())
{
switch (binaryOp)
{
case BfBinaryOp_BitwiseAnd:
mResult.mInt64 = convLeftValue.GetInt64() & convRightValue.GetInt64();
return;
case BfBinaryOp_BitwiseOr:
mResult.mInt64 = convLeftValue.GetInt64() | convRightValue.GetInt64();
return;
case BfBinaryOp_ExclusiveOr:
mResult.mInt64 = convLeftValue.GetInt64() ^ convRightValue.GetInt64();
return;
case BfBinaryOp_LeftShift:
mResult.mInt64 = convLeftValue.GetInt64() << convRightValue.GetInt64();
return;
case BfBinaryOp_RightShift:
mResult.mInt64 = convLeftValue.GetInt64() >> convRightValue.GetInt64();
return;
}
}
switch (binaryOp)
{
case BfBinaryOp_Add:
2021-07-15 06:01:17 -07:00
case BfBinaryOp_OverflowAdd:
2019-08-23 11:56:54 -07:00
if (resultType->mTypeCode == DbgType_Single)
mResult.mSingle = convLeftValue.mSingle + convRightValue.mSingle;
else if (resultType->mTypeCode == DbgType_Double)
mResult.mDouble = convLeftValue.mDouble + convRightValue.mDouble;
else
mResult.mInt64 = convLeftValue.GetInt64() + convRightValue.GetInt64();
break;
case BfBinaryOp_Subtract:
2021-07-15 06:01:17 -07:00
case BfBinaryOp_OverflowSubtract:
2019-08-23 11:56:54 -07:00
if (resultType->mTypeCode == DbgType_Single)
mResult.mSingle = convLeftValue.mSingle - convRightValue.mSingle;
else if (resultType->mTypeCode == DbgType_Double)
mResult.mDouble = convLeftValue.mDouble - convRightValue.mDouble;
else
mResult.mInt64 = convLeftValue.GetInt64() - convRightValue.GetInt64();
break;
case BfBinaryOp_Multiply:
2021-07-15 06:01:17 -07:00
case BfBinaryOp_OverflowMultiply:
2019-08-23 11:56:54 -07:00
if (resultType->mTypeCode == DbgType_Single)
mResult.mSingle = convLeftValue.mSingle * convRightValue.mSingle;
else if (resultType->mTypeCode == DbgType_Double)
mResult.mDouble = convLeftValue.mDouble * convRightValue.mDouble;
else
mResult.mInt64 = convLeftValue.GetInt64() * convRightValue.GetInt64();
break;
case BfBinaryOp_Divide:
{
bool isZero = false;
if (resultType->mTypeCode == DbgType_Single)
{
mResult.mSingle = convLeftValue.mSingle / convRightValue.mSingle;
}
else if (resultType->mTypeCode == DbgType_Double)
{
mResult.mDouble = convLeftValue.mDouble / convRightValue.mDouble;
}
else
{
if (convRightValue.GetInt64() == 0)
isZero = true;
else
mResult.mInt64 = convLeftValue.GetInt64() / convRightValue.GetInt64();
}
if (isZero)
Fail("Divide by zero", opToken);
}
break;
case BfBinaryOp_Modulus:
{
bool isZero = false;
if (resultType->mTypeCode == DbgType_Single)
mResult.mSingle = fmod(convLeftValue.mSingle, convRightValue.mSingle);
else if (resultType->mTypeCode == DbgType_Double)
mResult.mDouble = fmod(convLeftValue.mDouble, convRightValue.mDouble);
else
{
if (convRightValue.GetInt64() == 0)
isZero = true;
else
mResult.mInt64 = convLeftValue.GetInt64() % convRightValue.GetInt64();
}
if (isZero)
Fail("Divide by zero", opToken);
}
break;
case BfBinaryOp_Equality:
2020-06-17 05:13:53 -07:00
case BfBinaryOp_StrictEquality:
2019-08-23 11:56:54 -07:00
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (resultType->mTypeCode == DbgType_Single)
mResult.mBool = convLeftValue.mSingle == convRightValue.mSingle;
else if (resultType->mTypeCode == DbgType_Double)
mResult.mBool = convLeftValue.mDouble == convRightValue.mDouble;
else
mResult.mBool = convLeftValue.GetInt64() == convRightValue.GetInt64();
break;
case BfBinaryOp_InEquality:
2020-06-17 05:13:53 -07:00
case BfBinaryOp_StrictInEquality:
2019-08-23 11:56:54 -07:00
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (resultType->mTypeCode == DbgType_Single)
mResult.mBool = convLeftValue.mSingle != convRightValue.mSingle;
else if (resultType->mTypeCode == DbgType_Double)
mResult.mBool = convLeftValue.mDouble != convRightValue.mDouble;
else
mResult.mBool = convLeftValue.GetInt64() != convRightValue.GetInt64();
break;
case BfBinaryOp_LessThan:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (resultType->mTypeCode == DbgType_Single)
mResult.mBool = convLeftValue.mSingle < convRightValue.mSingle;
else if (resultType->mTypeCode == DbgType_Double)
mResult.mBool = convLeftValue.mDouble < convRightValue.mDouble;
else
mResult.mBool = convLeftValue.GetInt64() < convRightValue.GetInt64();
break;
case BfBinaryOp_LessThanOrEqual:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (resultType->mTypeCode == DbgType_Single)
mResult.mBool = convLeftValue.mSingle <= convRightValue.mSingle;
else if (resultType->mTypeCode == DbgType_Double)
mResult.mBool = convLeftValue.mDouble <= convRightValue.mDouble;
else
mResult.mBool = convLeftValue.GetInt64() <= convRightValue.GetInt64();
break;
case BfBinaryOp_GreaterThan:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (resultType->mTypeCode == DbgType_Single)
mResult.mBool = convLeftValue.mSingle > convRightValue.mSingle;
else if (resultType->mTypeCode == DbgType_Double)
mResult.mBool = convLeftValue.mDouble > convRightValue.mDouble;
else
mResult.mBool = convLeftValue.GetInt64() > convRightValue.GetInt64();
break;
case BfBinaryOp_GreaterThanOrEqual:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (resultType->mTypeCode == DbgType_Single)
mResult.mBool = convLeftValue.mSingle >= convRightValue.mSingle;
else if (resultType->mTypeCode == DbgType_Double)
mResult.mBool = convLeftValue.mDouble >= convRightValue.mDouble;
else
mResult.mBool = convLeftValue.GetInt64() >= convRightValue.GetInt64();
break;
default:
Fail("Invalid operation", opToken);
break;
}
}
void DbgExprEvaluator::Visit(BfBinaryOperatorExpression* binOpExpr)
{
//mIsComplexExpression = true;
//PerformBinaryOperation(binOpExpr->mLeft, binOpExpr->mRight, binOpExpr->mOp, binOpExpr->mOpToken, false);
// Check for "(double)-1.0" style cast, misidentified as a binary operation
if ((binOpExpr->mOp == BfBinaryOp_Add) || (binOpExpr->mOp == BfBinaryOp_Subtract) ||
(binOpExpr->mOp == BfBinaryOp_BitwiseAnd) || (binOpExpr->mOp == BfBinaryOp_Multiply))
{
if (auto parenExpr = BfNodeDynCast<BfParenthesizedExpression>(binOpExpr->mLeft))
{
BfAstNode* castTypeExpr = BfNodeDynCast<BfIdentifierNode>(parenExpr->mExpression);
if (castTypeExpr == NULL)
castTypeExpr = BfNodeDynCast<BfMemberReferenceExpression>(parenExpr->mExpression);
if (castTypeExpr != NULL)
{
SetAndRestoreValue<bool> prevIgnoreError(mIgnoreErrors, true);
auto resolvedType = ResolveTypeRef(castTypeExpr);
prevIgnoreError.Restore();
if (resolvedType != NULL)
{
if (binOpExpr->mOp == BfBinaryOp_BitwiseAnd)
{
PerformUnaryExpression(binOpExpr->mOpToken, BfUnaryOp_AddressOf, binOpExpr->mRight);
}
else if (binOpExpr->mOp == BfBinaryOp_Multiply)
{
PerformUnaryExpression(binOpExpr->mOpToken, BfUnaryOp_Dereference, binOpExpr->mRight);
}
else
{
VisitChild(binOpExpr->mRight);
if (!mResult)
return;
}
if ((mResult) && (binOpExpr->mOp == BfBinaryOp_Subtract))
{
if (mResult.mType->mTypeCode == DbgType_Single)
mResult.mSingle = -mResult.mSingle;
else if (mResult.mType->mTypeCode == DbgType_Double)
mResult.mDouble = -mResult.mDouble;
else
mResult.mInt64 = -mResult.GetInt64();
}
mResult = Cast(binOpExpr, mResult, resolvedType, true);
return;
}
}
}
}
if (binOpExpr->mRight == NULL)
{
//mModule->AssertErrorState();
// We visit the children for autocompletion only
if (binOpExpr->mLeft != NULL)
VisitChild(binOpExpr->mLeft);
if (mResult)
{
//if (mAutoComplete != NULL)
//mAutoComplete->CheckEmptyStart(binOpExpr->mOpToken, mResult.mType);
}
if (binOpExpr->mRight != NULL)
VisitChild(binOpExpr->mRight);
return;
}
PerformBinaryOperation(binOpExpr->mLeft, binOpExpr->mRight, binOpExpr->mOp, binOpExpr->mOpToken, false);
}
void DbgExprEvaluator::PerformUnaryExpression(BfAstNode* opToken, BfUnaryOp unaryOp, ASTREF(BfExpression*)& expr)
{
if (unaryOp != BfUnaryOp_Dereference)
mIsComplexExpression = true;
VisitChild(expr);
GetResult();
if (!mResult)
return;
bool wasLiteral = mResult.mIsLiteral;
mResult.mIsLiteral = false;
switch (unaryOp)
{
case BfUnaryOp_Decrement:
case BfUnaryOp_PostDecrement:
case BfUnaryOp_Increment:
case BfUnaryOp_PostIncrement:
auto ptr = mResult;
ptr.mType = ptr.mType->RemoveModifiers();
if (ptr.mType->IsEnum())
ptr.mType = ptr.mType->mTypeParam;
auto val = mResult;
int add = ((unaryOp == BfUnaryOp_Decrement) || (unaryOp == BfUnaryOp_PostDecrement)) ? -1 : 1;
switch (ptr.mType->mTypeCode)
{
case DbgType_UChar:
case DbgType_SChar:
case DbgType_i8:
case DbgType_u8:
case DbgType_Utf8:
val.mUInt8 += add;
break;
case DbgType_UChar16:
case DbgType_SChar16:
case DbgType_i16:
case DbgType_u16:
case DbgType_Utf16:
val.mUInt16 += add;
break;
case DbgType_UChar32:
case DbgType_SChar32:
case DbgType_i32:
case DbgType_u32:
case DbgType_Utf32:
val.mUInt32 += add;
break;
case DbgType_i64:
case DbgType_u64:
val.mUInt64 += add;
break;
case DbgType_Single:
val.mSingle += add;
break;
case DbgType_Double:
val.mDouble += add;
break;
default:
Fail(StrFormat("Unable to perform operation on type '%s'", ptr.mType->ToString()), expr);
return;
}
if ((mExpressionFlags & DwEvalExpressionFlag_AllowSideEffects) == 0)
{
mBlockedSideEffects = true;
return;
}
else
{
StoreValue(mResult, val, opToken);
}
if ((unaryOp == BfUnaryOp_Decrement) || (unaryOp == BfUnaryOp_Increment))
mResult = val;
return;
}
bool numericFail = false;
switch (unaryOp)
{
case BfUnaryOp_Dereference:
{
auto type = mResult.mType->RemoveModifiers();
if (!type->IsPointer())
{
Fail("Operator can only be used on pointer values", opToken);
return;
}
mResult = ReadTypedValue(opToken, type->mTypeParam, mResult.mPtr, DbgAddrType_Target);
2019-08-23 11:56:54 -07:00
}
break;
case BfUnaryOp_AddressOf:
{
if ((mResult.mSrcAddress == 0) || (mResult.mSrcAddress == -1))
{
if (mResult.mRegNum != -1)
{
Fail(StrFormat("Cannot take address of register '%s'", CPURegisters::GetRegisterName(mResult.mRegNum)), opToken);
return;
}
Fail("Cannot take address of value", opToken);
return;
}
mResult.mType = mResult.mType->RemoveModifiers();
mResult.mType = mDbgModule->GetPointerType(mResult.mType);
mResult.mPtr = mResult.mSrcAddress;
mResult.mSrcAddress = 0;
}
break;
case BfUnaryOp_Not:
{
auto boolType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (mResult.mType->mTypeCode != DbgType_Bool)
2019-08-23 11:56:54 -07:00
{
Fail("Operator can only be used on boolean values", opToken);
return;
}
mResult.mIsLiteral = wasLiteral;
mResult.mBool = !mResult.mBool;
}
break;
case BfUnaryOp_Negate:
{
if (mResult.mType->IsInteger())
{
auto primType = mResult.mType;
auto wantType = primType;
if (wasLiteral)
{
// This is a special case where the user entered -0x80000000 (maxint) but we thought "0x80000000" was a uint in the parser
// which would get expanded to an int64 for this negate. Properly bring back down to an int32
if ((primType->mTypeCode == DbgType_u32) && (mResult.GetInt64() == -0x80000000LL))
{
//mResult = DbgTypedValue(mModule->GetConstValue((int) i64Val), mModule->GetPrimitiveType(DwTypeCode_Int32));
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_i32, GetLanguage());
return;
}
}
if (!primType->IsSigned())
{
if (primType->mSize == 1)
wantType = mDbgModule->GetPrimitiveType(DbgType_i16, GetLanguage());
else if (primType->mSize == 2)
wantType = mDbgModule->GetPrimitiveType(DbgType_i32, GetLanguage());
else if (primType->mSize == 4)
wantType = mDbgModule->GetPrimitiveType(DbgType_i64, GetLanguage());
}
mResult.mIsLiteral = wasLiteral;
mResult.mInt64 = -mResult.GetInt64();
mResult.mType = wantType;
return;
}
mResult.mIsLiteral = wasLiteral;
if (mResult.mType->mTypeCode == DbgType_Single)
mResult.mSingle = -mResult.mSingle;
else if (mResult.mType->mTypeCode == DbgType_Double)
mResult.mDouble = -mResult.mDouble;
else
numericFail = true;
}
break;
case BfUnaryOp_InvertBits:
{
mResult.mIsLiteral = wasLiteral;
if (mResult.mType->IsInteger())
{
switch (mResult.mType->mSize)
{
case 1:
mResult.mUInt8 = ~mResult.mUInt8;
break;
case 2:
mResult.mUInt16 = ~mResult.mUInt16;
break;
case 4:
mResult.mUInt32 = ~mResult.mUInt32;
break;
case 8:
mResult.mUInt64 = ~mResult.mUInt64;
break;
}
}
}
break;
default:
Fail("Invalid operator for debug expression", opToken);
break;
}
if (numericFail)
{
Fail("Operator can only be used on numeric types", opToken);
mResult = DbgTypedValue();
}
}
void DbgExprEvaluator::Visit(BfUnaryOperatorExpression* unaryOpExpr)
{
PerformUnaryExpression(unaryOpExpr->mOpToken, unaryOpExpr->mOp, unaryOpExpr->mExpression);
}
bool DbgExprEvaluator::ResolveArgValues(const BfSizedArray<ASTREF(BfExpression*)>& arguments, SizedArrayImpl<DbgTypedValue>& outArgValues)
{
for (int argIdx = 0; argIdx < (int) arguments.size(); argIdx++)
{
//BfExprEvaluator exprEvaluator(mModule);
//exprEvaluator.Evaluate(arguments[argIdx]);
auto arg = arguments[argIdx];
DbgTypedValue argValue;
if (arg != NULL)
argValue = Resolve(arg);
if (argValue)
{
/*if (argValue.mType->IsRef())
{
argValue.mIsAddr = false;
}
else if (!argValue.mType->IsStruct())
argValue = mModule->LoadValue(argValue);*/
}
outArgValues.push_back(argValue);
}
return true;
}
DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, DbgTypedValue thisVal, DbgTypedValue structRetVal, bool bypassVirtual, CPURegisters* registers)
2019-08-23 11:56:54 -07:00
{
// Why did we have the Not Runing thing for Exception? It means that when we crash we can't execute functions anymore.
// That doesn't seem good
/*if (mDebugger->mRunState == RunState_Exception)
{
mPassInstance->Fail("Not running");
return DbgTypedValue();
}*/
#ifdef BF_WANTS_LOG_DBGEXPR
auto _GetResultString = [&](DbgTypedValue val)
{
String result;
if (val.mSrcAddress != 0)
{
result += StrFormat("0x%p ", val.mSrcAddress);
int64 vals[4] = { 0 };
mDebugger->ReadMemory(val.mSrcAddress, 4 * 8, vals);
result += StrFormat("%lld %lld %lld %lld", vals[0], vals[1], vals[2], vals[3]);
}
else
{
result += StrFormat("%lld", val.mInt64);
}
return result;
};
#endif
2019-08-23 11:56:54 -07:00
int curCallResultIdx = mCallResultIdx++;
if (((mExpressionFlags & DwEvalExpressionFlag_AllowCalls) == 0) || (mCreatedPendingCall))
{
BfLogDbgExpr(" BlockedSideEffects\n");
2019-08-23 11:56:54 -07:00
mBlockedSideEffects = true;
return GetDefaultTypedValue(method->mReturnType);
}
mHadSideEffects = true;
// Our strategy is to create "pending results" for each call in a debug expression, and then we continually re-evaluate the
// entire expression using the actual returned results for each of those calls until we can finally evaluate it as a whole
if (curCallResultIdx < (int)mCallResults->size() - 1)
{
auto callResult = (*mCallResults)[curCallResultIdx];
auto result = callResult.mResult;
if (!callResult.mSRetData.IsEmpty())
{
result = structRetVal;
mDebugger->WriteMemory(result.mSrcAddress, &callResult.mSRetData[0], (int)callResult.mSRetData.size());
}
BfLogDbgExpr(" using cached results %s\n", _GetResultString(result).c_str());
return result;
2019-08-23 11:56:54 -07:00
}
else if (curCallResultIdx == (int)mCallResults->size() - 1)
{
auto& callResult = (*mCallResults)[curCallResultIdx];
2019-08-23 11:56:54 -07:00
CPURegisters newPhysRegisters;
mDebugger->PopulateRegisters(&newPhysRegisters);
DbgTypedValue returnVal;
if (method->mReturnType != 0)
{
if (callResult.mStructRetVal)
returnVal = callResult.mStructRetVal;
else
returnVal = mDebugger->ReadReturnValue(&newPhysRegisters, method->mReturnType);
2019-08-23 11:56:54 -07:00
bool hadRef = false;
auto returnType = method->mReturnType->RemoveModifiers(&hadRef);
if (hadRef)
{
returnVal = ReadTypedValue(NULL, returnType, returnVal.mPtr, DbgAddrType_Target);
2019-08-23 11:56:54 -07:00
returnVal.mType = returnType;
}
}
else
{
returnVal.mType = mDbgModule->GetPrimitiveType(DbgType_Void, GetLanguage());
}
BfLogDbgExpr(" using new results %s\n", _GetResultString(returnVal).c_str());
2019-08-23 11:56:54 -07:00
mDebugger->RestoreAllRegisters();
if ((method->mReturnType->IsCompositeType()) && (mDebugger->CheckNeedsSRetArgument(method->mReturnType)))
{
callResult.mSRetData.Resize(method->mReturnType->GetByteCount());
mDebugger->ReadMemory(returnVal.mSrcAddress, method->mReturnType->GetByteCount(), &callResult.mSRetData[0]);
}
callResult.mResult = returnVal;
2019-08-23 11:56:54 -07:00
return returnVal;
}
else
{
BfLogDbgExpr(" new call\n");
}
2019-08-23 11:56:54 -07:00
// It's a new call
addr_target startAddr = method->mBlock.mLowPC;
if ((method->mVTableLoc != -1) && (thisVal))
{
addr_target thisPtr;
bool isBfObject = false;
if (thisVal.mType->IsCompositeType())
{
isBfObject = thisVal.mType->IsBfObject();
thisPtr = thisVal.mSrcAddress;
}
else
{
isBfObject = thisVal.mType->IsBfObjectPtr();
thisPtr = thisVal.mPtr;
}
addr_target vtablePtr = mDebugger->ReadMemory<addr_target>(thisPtr);
if (isBfObject)
{
mDebugTarget->GetCompilerSettings();
if (mDebugTarget->mBfObjectHasFlags)
vtablePtr &= ~0xFF;
}
if (method->mVTableLoc >= 0x100000)
{
// Virtual ext method, double indirection
addr_target extAddr = mDebugger->ReadMemory<addr_target>(vtablePtr + (uint)((method->mVTableLoc>>20) - 1)*sizeof(addr_target));
startAddr = mDebugger->ReadMemory<addr_target>(extAddr + (uint)(method->mVTableLoc & 0xFFFFF)*sizeof(addr_target));
}
else
startAddr = mDebugger->ReadMemory<addr_target>(vtablePtr + method->mVTableLoc);
}
else
{
if ((startAddr == 0) && (method->mLinkName != NULL))
{
startAddr = mDebugTarget->FindSymbolAddr(method->mLinkName);
}
else if ((startAddr == 0) && (method->mName != NULL))
{
startAddr = mDebugTarget->FindSymbolAddr(method->mName);
}
}
if ((startAddr == (addr_target)0) || (startAddr == (addr_target)-1))
{
mPassInstance->Fail("Unable to find address for method, possibly due to compiler optimizations.");
return DbgTypedValue();
}
mDebugger->SaveAllRegisters();
BfLogDbg("Starting RunState_DebugEval on thread %d\n", mDebugger->mActiveThread->mThreadId);
addr_target prevSP = registers->GetSP();
//registers->mIntRegs.efl = 0x244;
//mDebugger->PushValue(registers, 0);
mDebugger->PushValue(registers, 42);
*(registers->GetPCRegisterRef()) = startAddr;
mDebugger->mDebugEvalSetRegisters = *registers;
// Set trap flag, which raises "single-step" exception
// If we step ONTO the PC we set, then that means we have returned from kernel mode
// so we need to set the registers again (they would have been clobbered due to SetThreadContext bugs).
// If we step past the PC then we're all good
registers->mIntRegs.efl |= 0x100;
mDebugger->SetRegisters(registers);
//::ResumeThread(mDebugger->mActiveThread->mHThread);
//TODO: For debugging stepping:
if ((mExpressionFlags & DwEvalExpressionFlag_StepIntoCalls) != 0)
{
mDebugger->mDebugManager->mOutMessages.push_back("rehupLoc");
return DbgTypedValue();
}
/*if (true)
{
return DbgTypedValue();
}*/
// mDebugger->mActiveThread->mIsAtBreakpointAddress = 0;
// mDebugger->mActiveThread->mBreakpointAddressContinuing = 0;
auto prevRunState = mDebugger->mRunState;
mDebugger->mRunState = RunState_DebugEval;
mDebugger->mExplicitStopThread = NULL;
mDebugger->mRequestedStackFrameIdx = -1;
BfLogDbg("DbgExprEvaluator::CreateCall %p in thread %d\n", startAddr, mDebugger->mActiveThread->mThreadId);
DbgCallResult callResult;
callResult.mSubProgram = method;
callResult.mStructRetVal = structRetVal;
2019-08-23 11:56:54 -07:00
mCallResults->push_back(callResult);
mCreatedPendingCall = true;
return GetDefaultTypedValue(method->mReturnType);
}
DbgTypedValue DbgExprEvaluator::CreateCall(BfAstNode* targetSrc, DbgTypedValue target, DbgSubprogram* method, bool bypassVirtual, const BfSizedArray<ASTREF(BfExpression*)>& arguments, SizedArrayImpl<DbgTypedValue>& argValues)
{
HashSet<String> splatParams;
SizedArray<DbgMethodArgument, 4> argPushQueue;
//
{
for (auto variable : method->mBlock.mVariables)
{
if ((variable->mName == NULL) && (variable->mName[0] != '$'))
continue;
const char* dollarPos = strchr(variable->mName + 1, '$');
if (dollarPos == NULL)
continue;
String varName = String(variable->mName + 1, dollarPos - variable->mName - 1);
splatParams.Add(varName);
}
}
int argIdx = 0;
int paramIdx = 0;
auto _PushArg = [&](const DbgTypedValue& typedValue, DbgVariable* param)
{
if (typedValue.mType->GetByteCount() == 0)
return;
if ((param != NULL) && (param->mType != NULL) && (param->mType->IsCompositeType()))
{
if ((param->mName != NULL) && (splatParams.Contains(param->mName)))
2019-08-23 11:56:54 -07:00
{
std::function<void(const DbgTypedValue& typedVal)> _SplatArgs = [&](const DbgTypedValue& typedVal)
{
auto type = typedVal.mType->RemoveModifiers();
type = type->GetPrimaryType();
if (type->IsValuelessType())
return;
if (!type->IsCompositeType())
{
auto elemTypedValue = ReadTypedValue(targetSrc, type, typedVal.mSrcAddress, DbgAddrType_Target);
2019-08-23 11:56:54 -07:00
DbgMethodArgument methodArg;
methodArg.mTypedValue = elemTypedValue;
argPushQueue.push_back(methodArg);
return;
}
auto baseType = type->GetBaseType();
if (baseType != NULL)
{
DbgTypedValue baseValue = typedVal;
baseValue.mType = baseType;
_SplatArgs(baseValue);
}
for (auto member : type->mMemberList)
{
if ((member->mIsStatic) || (member->mIsConst))
continue;
DbgTypedValue memberValue;
memberValue.mSrcAddress = typedVal.mSrcAddress + member->mMemberOffset;
memberValue.mType = member->mType;
_SplatArgs(memberValue);
}
};
_SplatArgs(typedValue);
return;
}
}
DbgMethodArgument methodArg;
methodArg.mTypedValue = typedValue;
methodArg.mWantsRef = param->mType->IsRef();
argPushQueue.push_back(methodArg);
};
bool thisByValue = false;
2019-08-23 11:56:54 -07:00
int methodParamCount = method->mParams.Size();
if (methodParamCount > 0)
{
method->mParams;
}
2019-08-23 11:56:54 -07:00
if (method->mHasThis)
{
auto param = method->mParams[paramIdx];
if ((param->mType != NULL) && (param->mType->IsValueType()))
thisByValue = true;
2019-08-23 11:56:54 -07:00
if (!target)
{
Fail(StrFormat("An object reference is required to invoke the non-static method '%s'", method->ToString().c_str()), targetSrc);
return DbgTypedValue();
}
_PushArg(target, param);
methodParamCount--;
2019-08-23 11:56:54 -07:00
}
else
{
if (target.mPtr != 0)
{
Fail(StrFormat("Method '%s' cannot be accessed with an instance reference; qualify it with a type name instead", method->ToString().c_str()), targetSrc);
return DbgTypedValue();
}
}
DbgTypedValue expandedParamsArray;
DbgType* expandedParamsElementType = NULL;
int extendedParamIdx = 0;
int paramOffset = method->mHasThis ? 1 : 0;
while (true)
{
if (paramIdx >= (int)method->mParams.Size() - paramOffset)
{
if (argIdx < (int)arguments.size())
{
int showArgIdx = (int)method->mParams.Size();
if (method->mHasThis)
showArgIdx--;
//WTF- what was this "Calling constructor" error about?!
/*if (methodInstance->mMethodDef->mMethodDeclaration != NULL)
mModule->mSystem->Warn(StrFormat("Trying to call constructor '%s'", mModule->MethodToString(methodInstance).c_str()), methodInstance->mMethodDef->GetRefNode());*/
Fail(StrFormat("Too many arguments. Expected %d fewer.", (int)arguments.size() - (methodParamCount)), arguments[showArgIdx]);
/*if (methodInstance->mMethodDef->mMethodDeclaration != NULL)
mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("See method declaration"), methodInstance->mMethodDef->mMethodDeclaration);*/
return DbgTypedValue();
}
break;
}
DbgVariable* param = NULL;
DbgType* wantType = NULL;
if (expandedParamsElementType != NULL)
{
wantType = expandedParamsElementType;
}
else
{
param = method->mParams[paramIdx + paramOffset];
wantType = param->mType;
//TODO:
/*if (method->mParams[paramIdx]->mParamType == BfParamType_Params)
{
//TODO: Check to see if it's a direct array pass
bool isDirectPass = false;
if (argIdx < (int)arguments.size())
{
if (argValues[argIdx].mValue == NULL)
return DbgTypedValue();
if (mModule->CanCast(argValues[argIdx], wantType))
2019-08-23 11:56:54 -07:00
isDirectPass = true;
}
if (!isDirectPass)
{
BfArrayType* arrayType = (BfArrayType*) wantType;
if (arrayType->IsIncomplete())
mModule->PopulateType(arrayType, true);
expandedParamsElementType = arrayType->mTypeGenericArguments[0];
int arrayClassSize = arrayType->mInstSize - expandedParamsElementType->mSize;
int numElements = (int) arguments.size() - argIdx;
Value* sizeValue = mModule->GetConstValue(arrayClassSize);
Value* elementDataSize = mModule->mIRBuilder->CreateMul(mModule->GetConstValue(expandedParamsElementType->mSize), mModule->GetConstValue(numElements));
sizeValue = mModule->mIRBuilder->CreateAdd(sizeValue, elementDataSize);
auto paramsData = mModule->GetHeadIRBuilder()->CreateAlloca(Type::getInt8Ty(*mModule->mLLVMContext), sizeValue, "paramsData");
expandedParamsArray = DbgTypedValue(mModule->mIRBuilder->CreateBitCast(paramsData, arrayType->mLLVMType),
arrayType, false);
MatchConstructor(targetSrc, expandedParamsArray, arrayType, SizedArray<BfExpression*, 1>(), false);
//TODO: Assert 'length' var is at slot 1
auto arrayBits = mModule->mIRBuilder->CreateBitCast(expandedParamsArray.mValue, arrayType->mBaseType->mPtrLLVMType);
if ((arrayType->mBaseType->mFieldInstances.size() < 0) || (arrayType->mBaseType->mFieldInstances[0].GetFieldDef()->mName != "mLength"))
{
mModule->Fail("INTERNAL ERROR: Unable to find array 'length' field", targetSrc);
return DbgTypedValue();
}
auto addr = mModule->mIRBuilder->CreateConstInBoundsGEP2_32(arrayBits, 0, 1, "length");
mModule->mIRBuilder->CreateStore(mModule->GetConstValue(numElements), addr);
llvmArgs.push_back(expandedParamsArray.mValue);
continue;
}
}*/
}
BfExpression* arg = NULL;
if (argIdx < (int) arguments.size())
{
arg = arguments[argIdx];
}
else if (mPassInstance != NULL)
{
if (expandedParamsArray)
break;
//TODO: Default values
/*if ((argIdx >= (int) methodInstance->mDefaultValues.size()) || (methodInstance->mDefaultValues[argIdx] == NULL))
{
BfAstNode* refNode = targetSrc;
if (arguments.size() > 0)
refNode = arguments.back();
mModule->Fail(StrFormat("Not enough parameters specified. Got %d, expected %d.", arguments.size(), methodInstance->mParamTypes.size()), refNode);
return DbgTypedValue();
}
llvmArgs.push_back(methodInstance->mDefaultValues[argIdx]);*/
BfAstNode* refNode = targetSrc;
if (arguments.size() > 0)
refNode = arguments.back();
Fail(StrFormat("Not enough parameters specified. Expected %d more.", methodParamCount - (int)arguments.size()), refNode);
return DbgTypedValue();
argIdx++;
paramIdx++;
continue;
}
auto argValue = argValues[argIdx];
if (argValue.mType == NULL)
return DbgTypedValue();
if (arg != NULL)
{
/*if (wantType->IsGenericParam())
{
auto genericParamType = (BfGenericParamType*) wantType;
if (genericParamType->mGenericParamKind == BfGenericParamKind_Method)
wantType = moduleMethodInstance.mMethodInstance->mMethodGenericArguments[genericParamType->mGenericParamIdx];
}*/
if ((wantType->mTypeCode == DbgType_Struct) ||
(wantType->mTypeCode == DbgType_Class) ||
(wantType->mTypeCode == DbgType_Union))
{
if (GetLanguage() != DbgLanguage_Beef)
{
Fail(StrFormat("Calling methods that take structs, classes, or unions by value is not supported"), arg);
return DbgTypedValue();
}
}
if (wantType->IsRef())
wantType = wantType->mTypeParam;
/*{
if (argValue.mSrcAddress == 0)
{
Fail(StrFormat("Unable to get address of argument %s", method->GetParamName(paramIdx).c_str()), arg);
return DbgTypedValue();
}
wantType = mDbgModule->GetPointerType(wantType->mTypeParam);
argValue.mPtr = argValue.mSrcAddress;
argValue.mSrcAddress = 0;
argValue.mType = wantType;
}*/
argValue = Cast(arg, argValue, wantType);
if (!argValue)
return DbgTypedValue();
/*if (wantType->IsStruct())
{
// We need to make a temp and get the addr of that
if (!argValue.mIsAddr)
{
auto tempVar = mModule->GetHeadIRBuilder()->CreateAlloca(argValue.mType->mLLVMType, NULL, "agg.tmp");
int align = argValue.mType->mAlign;
tempVar->setAlignment(align);
mModule->mIRBuilder->CreateStore(argValue.mValue, tempVar);
//mModule->mIRBuilder->CreateMemCpy(tempVar, argValue.mValue, mModule->GetConstValue(argValue.mType->mDataSize), align, argValue.mType->IsVolatile());
argValue = DbgTypedValue(tempVar, argValue.mType, true);
}
}
else if (!wantType->IsRef())
argValue = mModule->LoadValue(argValue);*/
}
if (!argValue)
{
Fail("Invalid expression type", arg);
return DbgTypedValue();
}
//TODO:
/*if (expandedParamsArray)
{
auto firstAddr = mModule->mIRBuilder->CreateConstInBoundsGEP2_32(expandedParamsArray.mValue, 0, 1);
auto indexedAddr = mModule->mIRBuilder->CreateConstInBoundsGEP1_32(firstAddr, extendedParamIdx);
mModule->mIRBuilder->CreateStore(argValue.mValue, indexedAddr);
extendedParamIdx++;
}
else*/
{
//llvmArgs.push_back(argValue.mValue);
_PushArg(argValue, param);
paramIdx++;
}
argIdx++;
}
2019-08-23 11:56:54 -07:00
return CreateCall(method, argPushQueue, bypassVirtual);
}
DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, SizedArrayImpl<DbgMethodArgument>& argPushQueue, bool bypassVirtual)
{
BfLogDbgExpr("CreateCall #%d %s", mCallResultIdx, method->mName);
2019-08-23 11:56:54 -07:00
if (mDebugger->IsMiniDumpDebugger())
{
Fail("Cannot call functions in a minidump", NULL);
return GetDefaultTypedValue(method->mReturnType);
}
if ((mExpressionFlags & DwEvalExpressionFlag_AllowCalls) == 0)
{
mBlockedSideEffects = true;
return GetDefaultTypedValue(method->mReturnType);
}
mHadSideEffects = true;
2019-08-23 11:56:54 -07:00
// We need current physical registers to make sure we push params in correct stack frame
CPURegisters registers;
bool canSetRegisters = mDebugger->PopulateRegisters(&registers);
auto* regSP = registers.GetSPRegisterRef();
if (mCallStackPreservePos != 0)
{
if (mCallStackPreservePos <= *regSP)
*regSP = mCallStackPreservePos;
}
2019-08-23 11:56:54 -07:00
int paramIdx = argPushQueue.size() - 1;
if (method->mHasThis)
paramIdx--;
bool thisByValue = false;
if ((method->mHasThis) && (!method->mParams.IsEmpty()))
{
auto param = method->mParams[0];
if ((param->mType != NULL) && (param->mType->IsValueType()))
thisByValue = true;
}
DbgTypedValue structRetVal;
2019-08-23 11:56:54 -07:00
if (mDebugger->CheckNeedsSRetArgument(method->mReturnType))
{
int retSize = BF_ALIGN(method->mReturnType->GetByteCount(), 16);
*regSP -= retSize;
structRetVal.mType = method->mReturnType;
structRetVal.mSrcAddress = *regSP;
// For chained calls we need to leave the sret form the previous calls intact
mCallStackPreservePos = *regSP;
}
2019-08-23 11:56:54 -07:00
for (int i = (int)argPushQueue.size() - 1; i >= 0; i--)
{
auto& arg = argPushQueue[i];
// If we have something like an int constant when we need to pass by int&, then we need to allocate
// on the stack and pass that address
if (arg.mWantsRef)
{
auto& typedValue = arg.mTypedValue;
auto rootType = typedValue.mType->RemoveModifiers();
if (arg.mTypedValue.mSrcAddress != 0)
{
typedValue.mPtr = typedValue.mSrcAddress;
}
else
{
int rootSize = rootType->GetByteCount();
*regSP -= BF_ALIGN(rootSize, 16);
mDebugger->WriteMemory(*regSP, &arg.mTypedValue.mInt64, rootSize); // Write from debugger memory to target
typedValue.mPtr = *regSP;
}
typedValue.mType = mDbgModule->GetPointerType(rootType);
typedValue.mSrcAddress = 0;
}
}
if (structRetVal.mSrcAddress != 0)
2019-08-23 11:56:54 -07:00
{
BfLogDbgExpr(" SRet:0x%p", structRetVal.mSrcAddress);
mDebugger->AddParamValue(0, method->mHasThis && !thisByValue, &registers, structRetVal);
2019-08-23 11:56:54 -07:00
paramIdx++;
}
DbgTypedValue thisVal;
for (int padCount = 0; true; padCount++)
{
auto regSave = registers;
int paramIdxSave = paramIdx;
*regSP -= padCount * sizeof(addr_target);
for (int i = (int)argPushQueue.size() - 1; i >= 0; i--)
{
auto& arg = argPushQueue[i];
if ((i == 0) && (method->mHasThis) && (!method->ThisIsSplat()))
{
thisVal = arg.mTypedValue;
addr_target thisAddr;
if (thisVal.mType->IsCompositeType())
thisAddr = thisVal.mSrcAddress;
else
thisAddr = thisVal.mPtr;
mDebugger->SetThisRegister(&registers, thisAddr);
if (padCount == 0)
BfLogDbgExpr(" This:0x%p", thisAddr);
2019-08-23 11:56:54 -07:00
}
else
{
mDebugger->AddParamValue(paramIdx, method->mHasThis, &registers, arg.mTypedValue);
paramIdx--;
}
}
#ifdef BF_DBG_64
// Stack must be 16-byte aligned
if ((*regSP & 0xF) == 0)
break;
#else
break;
#endif
registers = regSave;
paramIdx = paramIdxSave;
BF_ASSERT(padCount < 3);
}
return CreateCall(method, thisVal, structRetVal, bypassVirtual, &registers);
2019-08-23 11:56:54 -07:00
}
DbgTypedValue DbgExprEvaluator::MatchMethod(BfAstNode* targetSrc, DbgTypedValue target, bool allowImplicitThis, bool bypassVirtual, const StringImpl& methodName,
const BfSizedArray<ASTREF(BfExpression*)>& arguments, BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArguments)
{
SetAndRestoreValue<String*> prevReferenceId(mReferenceId, NULL);
bool wantCtor = methodName.IsEmpty();
mDbgModule->ParseGlobalsData();
//mDbgModule->ParseSymbolData();
SizedArray<DbgTypedValue, 4> argValues;
if (!ResolveArgValues(arguments, argValues))
return DbgTypedValue();
if ((methodName == "__cast") || (methodName == "__bitcast"))
{
if (argValues.size() > 0)
{
String typeName = "";
for (int argIdx = 0; argIdx < (int)argValues.size() - 1; argIdx++)
{
auto arg = argValues[argIdx];
if (!arg)
return DbgTypedValue();
if ((arg.mType->IsPointer()) && ((arg.mType->mTypeParam->mTypeCode == DbgType_UChar) || (arg.mType->mTypeParam->mTypeCode == DbgType_SChar)))
{
typeName += arg.mCharPtr;
}
else if ((arg.mType->mTypeCode == DbgType_i32) || (arg.mType->mTypeCode == DbgType_i64))
{
typeName += BfTypeUtils::HashEncode64(arg.mInt64);
}
else
{
BeefTypeToString(arg, typeName);
}
}
auto castedType = mDbgModule->FindType(typeName, NULL, GetLanguage(), true);
2019-08-23 11:56:54 -07:00
if (castedType == NULL)
{
if (typeName.EndsWith('*'))
{
auto noPtrTypeEntry = mDbgModule->FindType(typeName.Substring(0, typeName.length() - 1), NULL, DbgLanguage_Beef, true);
2019-08-23 11:56:54 -07:00
if (noPtrTypeEntry != NULL)
castedType = mDbgModule->GetPointerType(noPtrTypeEntry);
}
}
int targetArgIdx = argValues.size() - 1;
if (castedType == NULL)
{
Fail(StrFormat("Unable to find type: '%s'", typeName.c_str()), targetSrc);
return argValues[targetArgIdx];
}
if (methodName == "__bitcast")
{
DbgTypedValue result = argValues[targetArgIdx];
result.mType = castedType;
return result;
}
return Cast(arguments[targetArgIdx], argValues[targetArgIdx], castedType, true);
}
}
else if (methodName == "__hasField")
{
if (argValues.size() == 2)
{
auto checkType = argValues[0].mType;
if ((checkType != NULL) && (checkType->IsPointer()))
checkType = checkType->mTypeParam;
if (checkType != NULL)
{
//TODO: Protect
String findFieldName = argValues[1].mCharPtr;
DbgTypedValue result;
result.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
result.mBool = HasField(checkType, findFieldName);
return result;
}
}
}
else if (methodName == "__desc")
{
if (argValues.size() == 1)
{
auto checkType = argValues[0].mType;
if ((checkType != NULL) && (checkType->IsPointer()))
checkType = checkType->mTypeParam;
if (checkType != NULL)
{
checkType = checkType->GetPrimaryType();
String dsc = "DESCRIPTION OF ";
dsc += checkType->ToString();
dsc += "\n";
dsc += "From Compile Unit: ";
dsc += checkType->mCompileUnit->mName;
dsc += "\n";
dsc += StrFormat("Size: %d\n", checkType->GetByteCount());
dsc += StrFormat("Align: %d\n", checkType->GetAlign());
for (auto member : checkType->mMemberList)
{
dsc += " ";
if (member->mIsConst)
dsc += "const ";
if (member->mIsExtern)
dsc += "extern ";
if (member->mIsStatic)
dsc += "static ";
dsc += member->mType->ToString();
dsc += " ";
dsc += member->mName;
if (!member->mIsStatic)
{
dsc += StrFormat(" Offset:%d", member->mMemberOffset);
}
dsc += StrFormat(" Size:%d", member->mType->GetByteCount());
if (member->mLinkName != NULL)
dsc += member->mLinkName;
dsc += "\n";
}
if ((mExpressionFlags & DwEvalExpressionFlag_AllowCalls) != 0)
mDebugger->OutputMessage(dsc);
return DbgTypedValue();
}
}
}
else if (methodName == "__demangleMethod")
{
if (argValues.size() == 2)
2019-08-23 11:56:54 -07:00
{
auto checkType = argValues[0].mType;
if (checkType->IsPointer())
checkType = checkType->mTypeParam;
//TODO: Protect
String findMethodName = argValues[1].mCharPtr;
checkType->PopulateType();
for (auto checkMethod : checkType->mMethodList)
{
if (checkMethod->mName == findMethodName)
{
static String demangledName;
demangledName = BfDemangler::Demangle(checkMethod->mLinkName, checkType->GetLanguage());
DbgTypedValue result;
result.mType = argValues[1].mType;
result.mCharPtr = demangledName.c_str();
result.mIsLiteral = true;
return result;
}
}
}
}
else if (methodName == "__demangle")
{
if (argValues.size() == 1)
{
auto rawTextType = mDbgModule->GetPrimitiveType(DbgType_RawText, GetLanguage());
String mangledName = argValues[0].mCharPtr;
static String demangledName;
demangledName = BfDemangler::Demangle(mangledName, DbgLanguage_Unknown);
if (demangledName.StartsWith("bf."))
demangledName.Remove(0, 3);
DbgTypedValue result;
result.mType = rawTextType;
result.mCharPtr = demangledName.c_str();
result.mIsLiteral = true;
return result;
}
}
2019-08-23 11:56:54 -07:00
else if (methodName == "__demangleFakeMember")
{
if (argValues.size() == 1)
{
auto checkType = argValues[0].mType;
if (checkType->IsPointer())
checkType = checkType->mTypeParam;
auto rawTextType = mDbgModule->GetPrimitiveType(DbgType_RawText, GetLanguage());
checkType->PopulateType();
auto firstMember = checkType->mMemberList.mHead;
static String demangledName;
demangledName = BfDemangler::Demangle(firstMember->mName, checkType->GetLanguage());
if (demangledName.StartsWith("bf."))
demangledName.Remove(0, 3);
DbgTypedValue result;
result.mType = rawTextType;
result.mCharPtr = demangledName.c_str();
result.mIsLiteral = true;
return result;
}
}
else if (methodName == "__funcName")
{
if (argValues.size() == 1)
{
auto funcPtr = argValues[0].mPtr;
String symbolName;
addr_target offset;
DbgModule* dwarf;
static String demangledName;
auto subProgram = mDebugTarget->FindSubProgram(funcPtr);
if (subProgram != NULL)
{
demangledName = subProgram->ToString();
}
else if (mDebugTarget->FindSymbolAt(funcPtr, &symbolName, &offset, &dwarf))
{
demangledName = BfDemangler::Demangle(symbolName, DbgLanguage_Beef);
}
else
{
demangledName = StrFormat("0x%@", funcPtr);
}
DbgTypedValue result;
result.mType = mDbgModule->GetPrimitiveType(DbgType_Subroutine, GetLanguage());
result.mCharPtr = demangledName.c_str();
return result;
}
}
else if (methodName == "__funcTarget")
{
if (argValues.size() == 2)
{
auto funcPtr = argValues[0].mPtr;
auto funcTarget = argValues[1].mPtr;
String symbolName;
addr_target offset;
DbgModule* dwarf;
if (mDebugTarget->FindSymbolAt(funcPtr, &symbolName, &offset, &dwarf))
{
String firstParamType = BfDemangler::Demangle(symbolName, DbgLanguage_Beef, BfDemangler::Flag_CaptureTargetType);
auto targetType = mDbgModule->FindType(firstParamType, NULL, DbgLanguage_BeefUnfixed);
if (targetType)
{
if (!targetType->IsPointer())
targetType = mDbgModule->GetPointerType(targetType);
DbgTypedValue result;
result.mType = targetType;
result.mPtr = funcTarget;
return result;
}
}
return argValues[1];
}
}
else if (methodName == "__stringView")
{
if (argValues.size() >= 2)
{
if ((argValues[1].mType != NULL) && (argValues[1].mType->IsInteger()))
2019-12-09 10:29:31 -08:00
mCountResultOverride = (intptr)argValues[1].GetInt64();
2019-08-23 11:56:54 -07:00
return argValues[0];
}
}
else if (methodName == "__getHighBits")
{
if ((argValues.size() == 2) && (argValues[0]) && (argValues[1]))
{
2020-03-20 09:22:53 -07:00
uint64 val = argValues[0].mUInt64;
2019-08-23 11:56:54 -07:00
int bitCount = (int)argValues[1].GetInt64();
DbgTypedValue result;
result.mType = argValues[0].mType;
result.mInt64 = val >> (argValues[0].mType->GetByteCount() * 8 - bitCount);
return result;
}
}
else if (methodName == "__clearHighBits")
{
if ((argValues.size() == 2) && (argValues[0]) && (argValues[1]))
{
2020-03-20 09:22:53 -07:00
uint64 val = argValues[0].mUInt64;
2019-08-23 11:56:54 -07:00
int bitCount = (int)argValues[1].GetInt64();
if (bitCount <= 0)
return argValues[0];
int64 andBits = (0x8000000000000000LL) >> ((argValues[0].mType->GetByteCount() - 8) * 8 + bitCount - 1);
DbgTypedValue result;
result.mType = argValues[0].mType;
result.mInt64 = val & ~andBits;
return result;
}
}
2020-11-18 09:31:52 -08:00
else if (methodName == "__parseCompileUnits")
{
for (auto dbgModule : mDebugTarget->mDbgModules)
{
dbgModule->ParseCompileUnits();
}
}
2019-08-23 11:56:54 -07:00
DbgType* curTypeDef;
DbgType* targetTypeInst = NULL;
bool checkNonStatic = true;
if (target)
{
targetTypeInst = target.mType;
curTypeDef = targetTypeInst;
}
else if (target.mType) // Static targeted
{
if (target.mType->IsPrimitiveType())
{
//TODO ;
//targetTypeInst = mModule->GetPrimitiveStructType(target.mType);
}
else
targetTypeInst = target.mType;
if (targetTypeInst == NULL)
{
Fail("No static methods available", targetSrc);
return DbgTypedValue();
}
curTypeDef = targetTypeInst;
checkNonStatic = false;
}
else // Current scope
{
curTypeDef = GetCurrentType();
targetTypeInst = GetCurrentType();
auto currentMethod = GetCurrentMethod();
checkNonStatic = (currentMethod != NULL) && (currentMethod->mHasThis);
}
DbgSubprogram* methodDef = NULL;
BfTypeVector checkMethodGenericArguments;
bool isFailurePass = false;
DbgType* curTypeInst = targetTypeInst;
DwMethodMatcher methodMatcher(targetSrc, this, methodName, argValues, methodGenericArguments);
if (targetTypeInst != NULL)
methodMatcher.mTargetIsConst = targetTypeInst->IsConst();
if (targetTypeInst != NULL)
{
methodMatcher.CheckType(targetTypeInst, false);
if (methodMatcher.mBestMethodDef == NULL)
{
isFailurePass = true;
methodMatcher.CheckType(targetTypeInst, true);
}
}
if (methodMatcher.mBestMethodDef != NULL)
{
//methodGenericArguments = methodMatcher.mBestMethodGenericArguments;
curTypeInst = methodMatcher.mBestMethodTypeInstance;
methodDef = methodMatcher.mBestMethodDef;
}
if ((methodDef) && (methodDef->mHasThis) && (!target) && (allowImplicitThis))
{
target = GetThis();
/*if (!target)
{
mModule->Fail("Target required for non-static method", targetSrc);
return DbgTypedValue();
}*/
}
// Fail, check for delegate invocation
if (methodDef == NULL)
{
DbgTypedValue fieldVal;
if (allowImplicitThis)
{
//auto thisValue = mModule->GetThis();
//LookupField(targetSrc, thisValue, methodName);
fieldVal = LookupIdentifier(BfNodeDynCast<BfIdentifierNode>(targetSrc));
}
else
{
fieldVal = LookupField(targetSrc, target, methodName);
}
//TODO:
/*if (mPropDef != NULL)
fieldVal = GetResult();*/
/*if (fieldVal)
{
if (fieldVal.mType->IsTypeInstance())
{
auto fieldTypeInst = fieldVal.mType->ToTypeInstance();
if (fieldTypeInst->mTypeDef->mIsDelegate)
return MatchMethod(targetSrc, fieldVal, false, false, "Invoke", arguments, methodGenericArguments);
}
fieldVal.mType = mModule->ResolveGenericParam(fieldVal.mType);
if (fieldVal.mType->IsVar())
return DbgTypedValue(mModule->GetDefaultValue(fieldVal.mType), fieldVal.mType);
mModule->Fail(StrFormat("Cannot perform invocation on type '%s'", mModule->TypeToString(fieldVal.mType).c_str()), targetSrc);
return DbgTypedValue();
}*/
}
/*if ((!methodDef) && (!target))
{
String checkTypeName = methodName;
int wantNumGenericArgs = 0;
if ((methodGenericArguments != NULL) && (methodGenericArguments->size() > 0))
wantNumGenericArgs = (int)methodGenericArguments->size();
auto typeDef = mModule->mSystem->FindTypeDef(checkTypeName, wantNumGenericArgs, mModule->mCurTypeInstance->mTypeDef->mNamespaceSearch);
if (typeDef != NULL)
{
BfTypeVector genericArgs;
if (methodGenericArguments != NULL)
{
for (auto genericArg : *methodGenericArguments)
{
auto typeDef = mModule->ResolveTypeRef(genericArg);
if (typeDef == NULL)
return DbgTypedValue();
genericArgs.push_back(typeDef);
}
}
auto resolvedType = mModule->ResolveTypeDef(typeDef, genericArgs)->ToTypeInstance();
if (resolvedType != NULL)
{
if (!resolvedType->IsStruct())
{
mModule->Fail("Objects must be allocated through 'new' or 'stack'", targetSrc);
return DbgTypedValue();
}
DbgTypedValue structInst = DbgTypedValue(mModule->mIRBuilder->CreateAlloca(resolvedType->mLLVMType),
resolvedType, false);
MatchConstructor(targetSrc, structInst, resolvedType, arguments, false);
return DbgTypedValue(mModule->mIRBuilder->CreateLoad(structInst.mValue), resolvedType, false);
}
}
}*/
if ((methodDef == NULL) && (!target))
{
for (int compileUnitIdx = 0; compileUnitIdx < (int)mDbgModule->mCompileUnits.size(); compileUnitIdx++)
{
auto compileUnit = mDbgModule->mCompileUnits[compileUnitIdx];
methodMatcher.CheckType(compileUnit->mGlobalType, isFailurePass);
if (methodMatcher.mBestMethodDef != NULL)
{
isFailurePass = false;
curTypeInst = methodMatcher.mBestMethodTypeInstance;
methodDef = methodMatcher.mBestMethodDef;
break;
}
}
}
if ((methodDef == NULL) && ((methodGenericArguments == NULL) || (methodGenericArguments->IsEmpty())))
{
DbgTypedValue enumResult;
DbgType* enumType = target.mType;
if ((enumType != NULL) && (enumType->IsBfPayloadEnum()))
{
enumResult = CheckEnumCreation(targetSrc, enumType, methodName, arguments);
if (enumResult)
return enumResult;
}
}
if (methodDef == NULL)
{
Fail("Method does not exist", targetSrc);
return DbgTypedValue();
}
// Don't execute the method if we've had a failure (like an ambiguous lookup)
if ((mPassInstance != NULL) && (mPassInstance->HasFailed()))
return DbgTypedValue();
DbgTypedValue callTarget;
if (targetTypeInst == curTypeInst)
{
callTarget = target;
}
else if (target)
{
bool handled = false;
if (target.mType->IsCompositeType())
{
//BF_FATAL("Not implemented");
callTarget = target;
/*if (curTypeInst->IsObject())
{
// Box it
callTarget = mModule->Cast(targetSrc, target, curTypeInst, true);
handled = true;
}*/
}
/*else
target = mModule->LoadValue(target);*/
if (!handled)
{
/*Value* targetValue = target.mValue;
callTarget = DbgTypedValue(mModule->mIRBuilder->CreateBitCast(targetValue, curTypeInst->mPtrLLVMType), curTypeInst);*/
callTarget = target;
}
}
if (prevReferenceId.mPrevVal != NULL)
{
if (prevReferenceId.mPrevVal->IsEmpty())
*prevReferenceId.mPrevVal += ".";
*prevReferenceId.mPrevVal += methodDef->ToString();
}
return CreateCall(targetSrc, callTarget, methodDef, bypassVirtual, arguments, argValues);
}
void DbgExprEvaluator::DoInvocation(BfAstNode* target, BfSizedArray<ASTREF(BfExpression*)>& args, BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArguments)
{
bool allowImplicitThis = false;
BfAstNode* methodNodeSrc = target;
bool bypassVirtual = false;
String targetFunctionName;
DbgTypedValue thisValue;
//TODO: This may just be a fully qualified static method name, so let's check that also
if (auto memberRefExpression = BfNodeDynCast<BfMemberReferenceExpression>(target))
{
//GetAutoComplete()->CheckMemberReference(memberRefExpression->mTarget, memberRefExpression->mDotToken, memberRefExpression->mMemberName);
if (memberRefExpression->mMemberName == NULL)
return;
if (memberRefExpression->IsA<BfBaseExpression>())
bypassVirtual = true;
methodNodeSrc = memberRefExpression->mMemberName;
if (auto attrIdentifier = BfNodeDynCast<BfAttributedIdentifierNode>(memberRefExpression->mMemberName))
{
methodNodeSrc = attrIdentifier->mIdentifier;
if (attrIdentifier->mIdentifier != NULL)
targetFunctionName = attrIdentifier->mIdentifier->ToString();
}
else
targetFunctionName = memberRefExpression->mMemberName->ToString();
if (memberRefExpression->mTarget == NULL)
{
// Dot-qualified
if ((mExpectingType != NULL) && (mExpectingType->IsStruct()))
{
mResult = DbgTypedValue();
mResult.mType = mExpectingType;
}
else
Fail("Unqualified dot syntax can only be used when the result type can be inferred", memberRefExpression->mDotToken);
}
else if (auto typeRef = BfNodeDynCast<BfTypeReference>(memberRefExpression->mTarget))
{
// Static method
mResult = DbgTypedValue();
mResult.mType = ResolveTypeRef(typeRef);
}
else
VisitChild(memberRefExpression->mTarget);
GetResult();
2019-08-23 11:56:54 -07:00
if (mResult.mType == NULL)
return;
thisValue = mResult;
mResult = DbgTypedValue();
}
else if (auto qualifiedName = BfNodeDynCast<BfQualifiedNameNode>(target))
{
/*if (GetAutoComplete() != NULL)
GetAutoComplete()->CheckMemberReference(qualifiedName->mLeft, qualifiedName->mDot, qualifiedName->mRight);*/
String leftName = qualifiedName->mLeft->ToString();
if (leftName == "base")
bypassVirtual = true;
methodNodeSrc = qualifiedName->mRight;
if (auto attrIdentifier = BfNodeDynCast<BfAttributedIdentifierNode>(qualifiedName->mRight))
{
methodNodeSrc = attrIdentifier->mIdentifier;
targetFunctionName = attrIdentifier->mIdentifier->ToString();
}
else
targetFunctionName = qualifiedName->mRight->ToString();
bool hadError = false;
thisValue = LookupIdentifier(qualifiedName->mLeft, true, &hadError);
if (!thisValue)
thisValue = GetResult();
2019-08-23 11:56:54 -07:00
if (hadError)
return;
if (!thisValue)
{
// Identifier not found. Static method? Just check speculatively don't throw error
DbgType* type;
{
SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, true);
type = ResolveTypeRef(qualifiedName->mLeft);
}
/*if (type->IsGenericParam())
{
auto genericParamInstance = mModule->GetGenericParamInstance((BfGenericParamType*)type);
type = genericParamInstance->mTypeConstraint;
}*/
if (type != NULL)
thisValue.mType = type;
else if (auto qualifiedLeft = BfNodeDynCast<BfQualifiedNameNode>(qualifiedName->mLeft))
{
LookupQualifiedStaticField(qualifiedLeft, true);
thisValue = mResult;
mResult = DbgTypedValue();
}
thisValue.mHasNoValue = true;
}
if (!thisValue.mType)
{
Fail("Identifier not found", qualifiedName->mLeft);
return;
}
mResult = DbgTypedValue();
}
else if (auto identiferExpr = BfNodeDynCast<BfIdentifierNode>(target))
{
allowImplicitThis = true;
targetFunctionName = target->ToString();
}
else if (auto invocationExpr = BfNodeDynCast<BfInvocationExpression>(target))
{
// It appears we're attempting to invoke a delegate returned from another method
Visit(invocationExpr);
auto innerInvocationResult = mResult;
mResult = DbgTypedValue();
if (!innerInvocationResult)
return;
/*if (innerInvocationResult.mType->IsTypeInstance())
{
auto invocationTypeInst = innerInvocationResult.mType->ToTypeInstance();
if (invocationTypeInst->mTypeDef->mIsDelegate)
{
thisValue = innerInvocationResult;
targetFunctionName = "Invoke";
}
}*/
if (!thisValue)
{
Fail(StrFormat("Cannot perform invocation on type '%s'", innerInvocationResult.mType->ToString().c_str()), invocationExpr->mTarget);
return;
}
}
else
{
Fail("Invalid invocation target", target);
return;
}
if (thisValue)
{
if (thisValue.mType->IsPointer())
{
//BF_ASSERT(thisValue.mIsAddr);
thisValue.mType = thisValue.mType->mTypeParam;
thisValue.mSrcAddress = thisValue.mPtr;
}
if (thisValue.mType->IsPrimitiveType())
{
//TODO:
/*auto primStructType = GetPrimitiveStructType(thisValue.mType);
//thisValue = mModule->Cast(target, thisValue, primStructType);
auto srcAlloca = mModule->GetHeadIRBuilder()->CreateAlloca(primStructType->mInstLLVMType, 0);
srcAlloca->setAlignment(primStructType->mAlign);
auto primPtr = mModule->mIRBuilder->CreateConstInBoundsGEP2_32(srcAlloca, 0, 0);
mModule->mIRBuilder->CreateStore(thisValue.mValue, primPtr);
thisValue = DbgTypedValue(srcAlloca, primStructType, true);*/
}
if (thisValue.mType->IsEnum())
{
//auto enumStructType = thisValue.mType->ToTypeInstance();
/*auto srcAlloca = mModule->GetHeadIRBuilder()->CreateAlloca(enumStructType->mInstLLVMType, 0);
srcAlloca->setAlignment(enumStructType->mAlign);
auto enumPtr = mModule->mIRBuilder->CreateConstInBoundsGEP2_32(srcAlloca, 0, 0);
mModule->mIRBuilder->CreateStore(thisValue.mValue, enumPtr);*/
//thisValue = DbgTypedValue(mModule->mIRBuilder->CreateBitCast(srcAlloca, enumStructType->mBaseType->mPtrLLVMType), enumStructType->mBaseType, true);
}
/*if (!thisValue.mType->IsTypeInstance())
{
Fail(StrFormat("Invalid target type: '%s'", mModule->TypeToString(thisValue.mType).c_str()), target);
return;
}*/
}
mResult = MatchMethod(methodNodeSrc, thisValue, allowImplicitThis, bypassVirtual, targetFunctionName, args, methodGenericArguments);
}
void DbgExprEvaluator::Visit(BfInvocationExpression* invocationExpr)
{
mIsComplexExpression = true;
auto wasCapturingMethodInfo = (mAutoComplete != NULL) && (mAutoComplete->mIsCapturingMethodMatchInfo);
/*if (mAutoComplete != NULL)
mAutoComplete->CheckInvocation(invocationExpr, invocationExpr->mOpenParen, invocationExpr->mCloseParen, invocationExpr->mCommas);*/
BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArguments = NULL;
if (invocationExpr->mGenericArgs != NULL)
methodGenericArguments = &invocationExpr->mGenericArgs->mGenericArgs;
DoInvocation(invocationExpr->mTarget, invocationExpr->mArguments, methodGenericArguments);
if ((wasCapturingMethodInfo) && (!mAutoComplete->mIsCapturingMethodMatchInfo))
{
mAutoComplete->mIsCapturingMethodMatchInfo = true;
BF_ASSERT(mAutoComplete->mMethodMatchInfo != NULL);
}
else if (mAutoComplete != NULL)
mAutoComplete->mIsCapturingMethodMatchInfo = false;
}
void DbgExprEvaluator::Visit(BfConditionalExpression* condExpr)
{
VisitChild(condExpr->mConditionExpression);
GetResult();
if (!mResult)
return;
auto boolResult = Cast(condExpr->mConditionExpression, mResult, mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()));
if (!boolResult)
return;
if (boolResult.mBool)
{
if (condExpr->mTrueExpression != NULL)
VisitChild(condExpr->mTrueExpression);
else
mResult = DbgTypedValue();
}
else
{
if (condExpr->mFalseExpression != NULL)
VisitChild(condExpr->mFalseExpression);
else
mResult = DbgTypedValue();
}
}
void DbgExprEvaluator::Visit(BfTypeAttrExpression* typeAttrExpr)
{
if (typeAttrExpr->mTypeRef == NULL)
return;
AutocompleteCheckType(typeAttrExpr->mTypeRef);
auto dbgType = ResolveTypeRef(typeAttrExpr->mTypeRef);
if (dbgType == NULL)
return;
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_i32, GetLanguage());
switch (typeAttrExpr->mToken->GetToken())
{
case BfToken_SizeOf:
mResult.mInt64 = dbgType->GetByteCount();
break;
case BfToken_AlignOf:
mResult.mInt64 = dbgType->GetAlign();
break;
case BfToken_StrideOf:
mResult.mInt64 = dbgType->GetStride();
break;
case BfToken_TypeOf:
//TODO:
break;
}
}
void DbgExprEvaluator::Visit(BfTupleExpression* tupleExpr)
{
if (mReceivingValue == NULL)
{
Fail("Tuple expressions can only be used when the receiving address can be inferred", tupleExpr);
return;
}
if (mReceivingValue->mIsReadOnly)
{
Fail("Cannot write to read-only value", tupleExpr);
return;
}
auto type = mReceivingValue->mType->RemoveModifiers();
if (!type->IsBfTuple())
{
Fail(StrFormat("Tuple expressions cannot be used for type '%s'", mReceivingValue->mType->ToString().c_str()), tupleExpr);
return;
}
CheckTupleCreation(mReceivingValue->mSrcAddress, tupleExpr, mReceivingValue->mType, tupleExpr->mValues, &tupleExpr->mNames);
mReceivingValue = NULL;
}
DbgTypedValue DbgExprEvaluator::Resolve(BfExpression* expr, DbgType* wantType)
2020-01-31 17:16:44 -08:00
{
//BfLogDbgExpr("Dbg Evaluate %s\n", expr->ToString().c_str());
2019-08-23 11:56:54 -07:00
BF_ASSERT(!HasPropResult());
mCallStackPreservePos = 0;
2019-08-23 11:56:54 -07:00
SetAndRestoreValue<DbgType*> prevType(mExpectingType, wantType);
SetAndRestoreValue<DbgTypedValue> prevResult(mResult, DbgTypedValue());
if ((mExpressionFlags & DwEvalExpressionFlag_AllowCalls) != 0)
{
BF_ASSERT(mCallResults != NULL);
}
2019-08-23 11:56:54 -07:00
if (mExplicitThis)
mExplicitThis = FixThis(mExplicitThis);
mExpectingType = wantType;
VisitChildNoRef(expr);
GetResult();
while (true)
{
if (!mResult)
break;
if (//(mResult.mType->mTypeCode == DbgType_Const) ||
(mResult.mType->mTypeCode == DbgType_Volatile))
mResult.mType = mResult.mType->mTypeParam;
else
break;
}
if ((mResult) && (wantType != NULL))
mResult = Cast(expr, mResult, wantType);
if ((mReferenceId != NULL) && (mIsComplexExpression))
mReferenceId->clear();
return mResult;
}
BfAstNode* DbgExprEvaluator::FinalizeExplicitThisReferences(BfAstNode* headNode)
{
//return headNode;
if (mExplicitThisExpr == NULL)
return headNode;
auto explicitThisExpr = mExplicitThisExpr;
mExplicitThisExpr = NULL;
BfReducer bfReducer;
BfPrinter bfPrinter(explicitThisExpr->GetSourceData()->mRootNode, NULL, NULL);
bfPrinter.mIgnoreTrivia = true;
bfPrinter.mReformatting = true;
bfPrinter.VisitChild(explicitThisExpr);
bool doWrap = false;
String thisExprStr = bfPrinter.mOutString;
if (auto unaryOpExpr = BfNodeDynCast<BfUnaryOperatorExpression>(explicitThisExpr))
{
if ((unaryOpExpr->mOp != BfUnaryOp_AddressOf) && (unaryOpExpr->mOp != BfUnaryOp_Dereference))
doWrap = true;
}
if ((explicitThisExpr->IsA<BfCastExpression>()) ||
(explicitThisExpr->IsA<BfBinaryOperatorExpression>()) ||
(explicitThisExpr->IsA<BfUnaryOperatorExpression>()))
doWrap = true;
if (doWrap)
{
thisExprStr = "(" + thisExprStr + ")";
}
auto bfParser = headNode->GetSourceData()->ToParser();
BF_ASSERT(bfParser != NULL);
auto source = headNode->GetSourceData();
for (auto& replaceNodeRecord : mDeferredInsertExplicitThisVector)
{
auto replaceNode = replaceNodeRecord.mNode;
DbgType* castType = NULL;
auto typeRef = BfNodeDynCast<BfTypeReference>(replaceNode);
if ((typeRef != NULL) || (replaceNodeRecord.mForceTypeRef))
{
castType = ResolveTypeRef(replaceNode);
if (castType == NULL)
continue;
}
// Use an identifier as a text placeholder for the whole 'this' expression
// We must do this because we can't insert the actual 'this' node into multiple parents
auto thisExprNode = source->mAlloc.Alloc<BfIdentifierNode>();
BfAstNode* newNode = NULL;
if (castType != NULL)
{
bfReducer.ReplaceNode(replaceNode, thisExprNode);
newNode = thisExprNode;
}
else if (auto thisNode = BfNodeDynCast<BfThisExpression>(replaceNode))
{
bfReducer.ReplaceNode(replaceNode, thisExprNode);
newNode = thisExprNode;
}
else if (auto identifierNode = BfNodeDynCast<BfIdentifierNode>(replaceNode))
{
auto memberRefNode = source->mAlloc.Alloc<BfMemberReferenceExpression>();
bfReducer.ReplaceNode(replaceNode, memberRefNode);
memberRefNode->mMemberName = identifierNode;
auto tokeNode = source->mAlloc.Alloc<BfTokenNode>();
tokeNode->SetToken(BfToken_Dot);
bfReducer.MoveNode(tokeNode, memberRefNode);
memberRefNode->mDotToken = tokeNode;
bfReducer.MoveNode(thisExprNode, memberRefNode);
memberRefNode->mTarget = thisExprNode;
newNode = memberRefNode;
}
if (newNode != NULL)
{
if (replaceNodeRecord.mNodeRef != NULL)
*replaceNodeRecord.mNodeRef = newNode;
if (replaceNode == headNode)
headNode = newNode;
}
String replaceString;
if (castType != NULL)
{
replaceString = castType->ToString();
}
else
replaceString = thisExprStr;
int thisLen = (int)replaceString.length();
int srcStart = bfParser->AllocChars(thisLen);
memcpy((char*)source->mSrc + srcStart, replaceString.c_str(), thisLen);
thisExprNode->Init(srcStart, srcStart, srcStart + thisLen);
}
return headNode;
}