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 ;
//////////////////////////////////////////////////////////////////////////
2022-02-05 09:23:44 -05:00
DwMethodMatcher : : DwMethodMatcher ( BfAstNode * targetSrc , DbgExprEvaluator * exprEvaluator , const StringImpl & methodName , SizedArrayImpl < DbgTypedValue > & arguments , BfSizedArray < ASTREF ( BfAstNode * ) > * methodGenericArguments ) :
2019-08-23 11:56:54 -07:00
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 )
{
2022-01-25 12:31:01 -05:00
if ( genericArg = = NULL )
return ;
2019-08-23 11:56:54 -07:00
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
2020-01-24 10:36:22 -08:00
if ( mModule - > CanCast ( DbgTypedValue ( NULL , argType ) , prevGenericMethodArg ) )
2019-08-23 11:56:54 -07:00
return true ;
// New best?
2020-01-24 10:36:22 -08:00
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 ;
2020-06-05 07:01:58 -07:00
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
{
2020-01-24 10:36:22 -08:00
if ( mExprEvaluator - > CanCast ( DbgTypedValue : : GetValueless ( paramType ) , prevParamType ) )
2019-08-23 11:56:54 -07:00
isBetter = true ;
2020-01-24 10:36:22 -08:00
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 ] ;
2020-01-24 10:36:22 -08:00
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 ;
2020-01-24 10:36:22 -08:00
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 ;
2020-01-24 10:36:22 -08:00
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
2019-11-07 13:35:56 -08:00
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 ;
2022-05-21 11:58:01 -07:00
mHadMemberReference = false ;
2019-08-23 11:56:54 -07:00
mCreatedPendingCall = false ;
2022-05-21 11:58:01 -07:00
mStackSearch = NULL ;
2019-08-23 11:56:54 -07:00
mValidateOnly = false ;
mReceivingValue = NULL ;
mCallResults = NULL ;
mCallResultIdx = 0 ;
2020-10-17 10:52:54 -07:00
mCallStackPreservePos = 0 ;
2019-08-23 11:56:54 -07:00
mPropGet = NULL ;
mPropSet = NULL ;
2022-05-21 11:58:01 -07:00
mPropSrc = NULL ;
2019-08-23 11:56:54 -07:00
}
DbgExprEvaluator : : ~ DbgExprEvaluator ( )
{
2022-05-21 11:58:01 -07:00
delete mStackSearch ;
2019-08-23 11:56:54 -07:00
}
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 ;
2020-05-17 06:11:54 -07:00
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_ " ) )
2022-05-23 08:48:55 -07:00
{
auto dbgModule = mDbgModule ;
char * endPtr = NULL ;
int typeIdx = strtol ( name . c_str ( ) + 3 , & endPtr , 10 ) ;
if ( ( endPtr ! = NULL ) & & ( * endPtr = = ' _ ' ) )
{
int moduleIdx = typeIdx ;
typeIdx = atoi ( endPtr + 1 ) ;
mDebugTarget - > mDbgModuleMap . TryGetValue ( moduleIdx , & dbgModule ) ;
}
if ( ( dbgModule ! = NULL ) & & ( typeIdx > = 0 ) & & ( typeIdx < ( int ) dbgModule - > mTypes . size ( ) ) )
return dbgModule - > mTypes [ typeIdx ] ;
2019-08-23 11:56:54 -07:00
}
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 ] ;
2022-05-23 08:48:55 -07:00
if ( ( ( c < ' 0 ' ) | | ( c > ' 9 ' ) ) & & ( c ! = ' _ ' ) )
2019-08-23 11:56:54 -07:00
{
endIdx = i ;
break ;
}
}
2022-05-23 08:48:55 -07:00
auto dbgModule = mDbgModule ;
char * endPtr = NULL ;
int typeIdx = strtol ( name . c_str ( ) + 3 , & endPtr , 10 ) ;
if ( ( endPtr ! = NULL ) & & ( * endPtr = = ' _ ' ) )
{
int moduleIdx = typeIdx ;
typeIdx = atoi ( endPtr + 1 ) ;
mDebugTarget - > mDbgModuleMap . TryGetValue ( moduleIdx , & dbgModule ) ;
}
if ( ( dbgModule ! = NULL ) & & ( typeIdx > = 0 ) & & ( typeIdx < ( int ) dbgModule - > mTypes . size ( ) ) )
2019-08-23 11:56:54 -07:00
{
if ( ( mExplicitThisExpr ! = NULL ) & & ( parentChildRef ! = NULL ) )
mDeferredInsertExplicitThisVector . push_back ( NodeReplaceRecord ( typeRef , parentChildRef , true ) ) ;
2022-05-23 08:48:55 -07:00
DbgType * dbgType = dbgModule - > mTypes [ typeIdx ] ;
2019-08-23 11:56:54 -07:00
for ( int i = endIdx ; i < ( int ) name . length ( ) ; i + + )
{
if ( name [ i ] = = ' * ' )
2022-05-23 08:48:55 -07:00
dbgType = dbgModule - > GetPointerType ( dbgType ) ;
2019-08-23 11:56:54 -07:00
}
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 )
{
2019-09-02 17:39:47 -07:00
if ( mDebugTarget - > mTargetBinary = = NULL )
return DbgTypedValue ( ) ;
2020-08-25 11:25:22 -07:00
if ( mDebugTarget - > mTargetBinary - > mBfTypesInfoAddr = = 0 )
2019-08-23 11:56:54 -07:00
{
2020-08-25 11:25:22 -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
{
2020-08-25 11:25:22 -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
{
2020-08-25 11:25:22 -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
) ;
2020-08-25 11:25:22 -07:00
if ( entry )
mDebugTarget - > mTargetBinary - > mBfTypesInfoAddr = entry - > mValue - > mAddress ;
2019-08-23 11:56:54 -07:00
}
}
}
2020-08-25 11:25:22 -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 )
{
2019-10-01 12:48:08 -07:00
mDebugTarget - > GetCompilerSettings ( ) ;
2019-08-23 11:56:54 -07:00
int objectSize = mDebugTarget - > mBfObjectSize ;
2019-10-01 12:48:08 -07:00
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 ;
} ;
2020-06-22 17:06:26 -07:00
struct _PointerType : _Type
{
2020-08-25 07:34:09 -07:00
int16 mPadding0 ;
2020-06-22 17:06:26 -07:00
_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 ) ) ;
2020-06-22 17:06:26 -07:00
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 ;
2020-07-03 13:54:45 -07:00
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();
2020-01-22 12:37:44 -08:00
return FixThis ( ReadTypedValue ( NULL , valType , valAddr , addrType ) ) ;
2019-08-23 11:56:54 -07:00
}
if ( mDebugTarget - > GetValueByName ( GetCurrentMethod ( ) , " __closure " , stackFrame , & valAddr , & valType , & addrType ) )
{
2020-01-22 12:37:44 -08:00
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
2020-01-24 10:36:22 -08:00
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 ) )
{
2020-01-22 12:37:44 -08:00
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
{
2022-05-21 11:58:01 -07:00
if ( mStackSearch ! = NULL )
{
if ( mStackSearch - > mIdentifier = = targetSrc )
{
if ( ! mStackSearch - > mSearchedTypes . Add ( curCheckType ) )
return DbgTypedValue ( ) ;
}
}
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 ;
2020-01-22 12:37:44 -08:00
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 ;
2020-01-22 12:37:44 -08:00
return ReadTypedValue ( targetSrc , checkMember - > mType , valAddr , addrType ) ;
2019-08-23 11:56:54 -07:00
}
else if ( checkMember - > mIsConst )
{
2020-01-22 12:37:44 -08:00
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 ( ) ) )
{
2020-01-22 12:37:44 -08:00
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 ;
2020-01-22 12:37:44 -08:00
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 )
2020-09-29 11:58:07 -07:00
{
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 ;
}
2020-09-29 11:58:07 -07:00
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 ( ) ;
}
2020-09-29 11:58:07 -07:00
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 ) ;
}
2020-01-22 12:37:44 -08:00
DbgTypedValue DbgExprEvaluator : : ReadTypedValue ( BfAstNode * targetSrc , DbgType * dbgType , uint64 valAddr , DbgAddrType addrType )
2019-08-23 11:56:54 -07:00
{
bool failedReadMemory = false ;
2020-01-22 12:37:44 -08:00
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 )
{
2020-01-22 12:37:44 -08:00
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 ;
2020-01-22 12:37:44 -08:00
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 :
2020-01-22 12:37:44 -08:00
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 + + ;
}
} */
}
2022-05-21 11:58:01 -07:00
DbgTypedValue DbgExprEvaluator : : DoLookupIdentifier ( 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 " )
2019-09-02 17:39:47 -07:00
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 " )
2019-09-02 17:39:47 -07:00
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 = = " _ " )
{
2019-12-05 06:49:23 -08:00
if ( mSubjectValue )
{
if ( mSubjectValue . mSrcAddress ! = 0 )
{
2020-01-22 12:37:44 -08:00
auto refreshVal = ReadTypedValue ( identifierNode , mSubjectValue . mType , mSubjectValue . mSrcAddress , DbgAddrType_Target ) ;
2019-12-05 06:49:23 -08:00
if ( refreshVal )
mSubjectValue = refreshVal ;
}
2019-08-23 11:56:54 -07:00
return mSubjectValue ;
2019-12-05 06:49:23 -08:00
}
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;
2020-01-22 12:37:44 -08:00
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 ) )
{
2020-01-22 12:37:44 -08:00
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 ( ) ;
}
2022-05-21 11:58:01 -07:00
DbgTypedValue DbgExprEvaluator : : LookupIdentifier ( BfAstNode * identifierNode , bool ignoreInitialError , bool * hadError )
{
if ( ( mStackSearch ! = NULL ) & & ( mStackSearch - > mIdentifier = = NULL ) )
{
mStackSearch - > mIdentifier = identifierNode ;
mStackSearch - > mStartingStackIdx = mCallStackIdx ;
int skipCount = 0 ;
StringT < 256 > findStr ;
for ( int i = 0 ; i < mStackSearch - > mSearchStr . mLength ; i + + )
{
char c = mStackSearch - > mSearchStr [ i ] ;
if ( c = = ' ^ ' )
{
skipCount = atoi ( mStackSearch - > mSearchStr . c_str ( ) + i + 1 ) ;
break ;
}
if ( c = = ' . ' )
{
findStr + = ' : ' ;
findStr + = ' : ' ;
}
else
findStr + = c ;
}
while ( true )
{
auto stackFrame = GetStackFrame ( ) ;
bool matches = true ;
if ( mStackSearch - > mSearchStr ! = " * " )
{
mDebugger - > UpdateCallStackMethod ( mCallStackIdx ) ;
if ( stackFrame - > mSubProgram ! = NULL )
{
int strLen = strlen ( stackFrame - > mSubProgram - > mName ) ;
if ( strLen > = findStr . mLength )
{
if ( strncmp ( stackFrame - > mSubProgram - > mName + strLen - findStr . mLength , findStr . c_str ( ) , findStr . mLength ) = = 0 )
{
if ( strLen > findStr . mLength )
{
char endC = stackFrame - > mSubProgram - > mName [ strLen - findStr . mLength - 1 ] ;
if ( endC ! = ' : ' )
matches = false ;
}
}
else
matches = false ;
}
else
matches = false ;
}
else
matches = false ;
}
if ( matches )
{
if ( skipCount > 0 )
{
skipCount - - ;
}
else
{
auto result = DoLookupIdentifier ( identifierNode , ignoreInitialError , hadError ) ;
if ( result )
return result ;
}
}
mCallStackIdx + + ;
if ( mCallStackIdx > = mDebugger - > mCallStack . mSize )
mDebugger - > UpdateCallStack ( ) ;
if ( mCallStackIdx > = mDebugger - > mCallStack . mSize )
return DbgTypedValue ( ) ;
}
}
return DoLookupIdentifier ( identifierNode , ignoreInitialError , hadError ) ;
}
2019-08-23 11:56:54 -07:00
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 )
{
2022-05-21 11:58:01 -07:00
if ( mStackSearch ! = NULL )
{
if ( ! mStackSearch - > mAutocompleteSearchedTypes . Add ( dbgType ) )
return ;
}
2019-08-23 11:56:54 -07:00
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 ;
}
2020-04-03 10:34:26 -07:00
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 ;
}
2020-01-22 12:37:44 -08:00
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 ;
2020-01-22 12:37:44 -08:00
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 ) ;
}
2022-03-03 12:56:10 -08:00
void DbgExprEvaluator : : Visit ( BfAttributedIdentifierNode * node )
{
VisitChild ( node - > mIdentifier ) ;
}
2019-08-23 11:56:54 -07:00
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 ;
2020-01-22 12:37:44 -08:00
mResult = ReadTypedValue ( NULL , valType , valAddr , addrType ) ;
2019-08-23 11:56:54 -07:00
return ;
}
}
}
}
2020-01-22 12:37:44 -08:00
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 ) ; */
2020-01-22 12:37:44 -08:00
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 ) )
{
//
}
2020-01-22 12:37:44 -08:00
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 ;
}
2020-01-22 12:37:44 -08:00
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 )
2020-01-22 12:37:44 -08:00
{
if ( ! mDebugTarget - > GetValueByName ( curMethod , findName , stackFrame , & valAddr , & valType , & addrType ) )
2019-08-23 11:56:54 -07:00
return ;
2020-01-22 12:37:44 -08:00
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 ;
2020-01-22 12:37:44 -08:00
}
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 ;
2020-01-22 12:37:44 -08:00
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 ) ;
} */
2020-01-22 12:37:44 -08:00
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 )
{
2020-01-22 12:37:44 -08:00
// 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 ) ;
2021-11-28 09:42:22 -08:00
if ( ( target . mVariable = = NULL ) & & ( target . mType - > GetByteCount ( ) ! = 0 ) )
Fail ( " Splat variable not found " , ( lookupNode ! = NULL ) ? lookupNode : targetNode ) ;
//BF_ASSERT((target.mVariable != NULL) || (target.mType->GetByteCount() == 0));
2019-08-23 11:56:54 -07:00
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 ;
2020-07-03 13:54:45 -07:00
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
{
2019-12-05 06:49:23 -08: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 ( ) ) )
{
2020-01-24 10:36:22 -08:00
/*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 ;
}
2020-01-22 12:37:44 -08:00
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 ( ) ) ;
2019-09-28 16:27:19 -07:00
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 ;
}
2020-10-17 10:52:54 -07:00
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 ( ) ;
} */
2020-10-17 10:52:54 -07:00
# 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 ) )
{
2020-10-17 10:52:54 -07:00
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 )
{
2020-10-17 10:52:54 -07:00
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 )
{
2020-10-17 10:52:54 -07:00
auto & callResult = ( * mCallResults ) [ curCallResultIdx ] ;
2019-08-23 11:56:54 -07:00
CPURegisters newPhysRegisters ;
mDebugger - > PopulateRegisters ( & newPhysRegisters ) ;
DbgTypedValue returnVal ;
if ( method - > mReturnType ! = 0 )
2020-10-17 10:52:54 -07:00
{
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 )
{
2020-01-22 12:37:44 -08:00
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 ( ) ) ;
}
2020-10-17 10:52:54 -07:00
BfLogDbgExpr ( " using new results %s \n " , _GetResultString ( returnVal ) . c_str ( ) ) ;
2019-08-23 11:56:54 -07:00
mDebugger - > RestoreAllRegisters ( ) ;
2020-10-17 10:52:54 -07:00
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 ;
}
2020-10-17 10:52:54 -07:00
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 ;
2020-10-17 10:52:54 -07:00
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 ( ) ) )
{
2020-06-10 07:12:07 -07:00
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 ( ) )
{
2020-01-22 12:37:44 -08:00
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 ) ;
} ;
2020-09-29 11:58:07 -07:00
bool thisByValue = false ;
2019-08-23 11:56:54 -07:00
int methodParamCount = method - > mParams . Size ( ) ;
2020-09-29 11:58:07 -07:00
if ( methodParamCount > 0 )
{
method - > mParams ;
}
2019-08-23 11:56:54 -07:00
if ( method - > mHasThis )
{
auto param = method - > mParams [ paramIdx ] ;
2020-09-29 11:58:07 -07:00
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 ( ) ;
}
2020-09-29 11:58:07 -07:00
_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 ( ) ;
2020-01-24 10:36:22 -08:00
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 ;
2022-05-31 11:01:26 -07:00
DbgTypedValue argValue ;
2019-08-23 11:56:54 -07:00
if ( argIdx < ( int ) arguments . size ( ) )
{
arg = arguments [ argIdx ] ;
2022-05-31 11:01:26 -07:00
argValue = argValues [ argIdx ] ;
}
else if ( param - > mIsConst )
{
argValue . mType = param - > mType ;
argValue . mInt64 = param - > mConstValue ;
2019-08-23 11:56:54 -07:00
}
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 ;
}
2022-05-31 11:01:26 -07:00
2019-08-23 11:56:54 -07:00
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 + + ;
2020-09-29 11:58:07 -07:00
}
2019-08-23 11:56:54 -07:00
return CreateCall ( method , argPushQueue , bypassVirtual ) ;
}
DbgTypedValue DbgExprEvaluator : : CreateCall ( DbgSubprogram * method , SizedArrayImpl < DbgMethodArgument > & argPushQueue , bool bypassVirtual )
{
2020-10-17 10:52:54 -07:00
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 ) ;
}
2020-10-17 10:52:54 -07:00
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 ( ) ;
2020-10-17 10:52:54 -07:00
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 - - ;
2020-09-29 11:58:07 -07:00
bool thisByValue = false ;
if ( ( method - > mHasThis ) & & ( ! method - > mParams . IsEmpty ( ) ) )
{
auto param = method - > mParams [ 0 ] ;
if ( ( param - > mType ! = NULL ) & & ( param - > mType - > IsValueType ( ) ) )
thisByValue = true ;
}
2020-10-17 10:52:54 -07:00
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 ;
2020-10-17 10:52:54 -07:00
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 ;
}
}
2020-10-17 10:52:54 -07:00
if ( structRetVal . mSrcAddress ! = 0 )
2019-08-23 11:56:54 -07:00
{
2020-10-17 10:52: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 ) ;
2020-10-17 10:52:54 -07:00
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 ) ;
}
2020-10-17 10:52:54 -07:00
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 ,
2022-02-05 09:23:44 -05:00
const BfSizedArray < ASTREF ( BfExpression * ) > & arguments , BfSizedArray < ASTREF ( BfAstNode * ) > * methodGenericArguments )
2019-08-23 11:56:54 -07:00
{
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 ) )
{
2022-03-15 16:33:30 -07:00
if ( typeName . IsEmpty ( ) )
{
// Fake this int as a type pointer
arg . mSrcAddress = arg . mUInt64 ;
BeefTypeToString ( arg , typeName ) ;
}
else
typeName + = BfTypeUtils : : HashEncode64 ( arg . mInt64 ) ;
2019-08-23 11:56:54 -07:00
}
else
{
BeefTypeToString ( arg , typeName ) ;
}
}
2020-07-06 09:09:28 -07:00
auto castedType = mDbgModule - > FindType ( typeName , NULL , GetLanguage ( ) , true ) ;
2019-08-23 11:56:54 -07:00
if ( castedType = = NULL )
{
if ( typeName . EndsWith ( ' * ' ) )
{
2020-07-06 09:09:28 -07:00
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 " )
{
2020-06-10 07:12:07 -07:00
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 ;
}
}
}
}
2020-06-10 07:12:07 -07:00
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 ) )
{
2022-05-21 11:58:01 -07:00
demangledName = BfDemangler : : Demangle ( symbolName , GetLanguage ( ) ) ;
2019-08-23 11:56:54 -07:00
}
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 ) )
{
2022-05-21 11:58:01 -07:00
String firstParamType = BfDemangler : : Demangle ( symbolName , GetLanguage ( ) , BfDemangler : : Flag_CaptureTargetType ) ;
2019-08-23 11:56:54 -07:00
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 ] ;
2022-03-08 06:27:06 -08:00
int64 andBits = ( 0x8000000000000000LL ) > > ( ( argValues [ 0 ] . mType - > GetByteCount ( ) - 8 ) * 8 + bitCount - 1 ) ;
2019-08-23 11:56:54 -07:00
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 ) ;
}
2022-02-05 09:23:44 -05:00
void DbgExprEvaluator : : DoInvocation ( BfAstNode * target , BfSizedArray < ASTREF ( BfExpression * ) > & args , BfSizedArray < ASTREF ( BfAstNode * ) > * methodGenericArguments )
2019-08-23 11:56:54 -07:00
{
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 ) ;
2020-10-17 06:11:32 -07:00
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 ) ;
2020-10-17 06:11:32 -07:00
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 ) ; */
2022-02-05 09:23:44 -05:00
BfSizedArray < ASTREF ( BfAstNode * ) > * methodGenericArguments = NULL ;
2019-08-23 11:56:54 -07:00
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 ;
2022-01-16 07:59:51 -05:00
default :
Fail ( " Invalid attribute expression " , typeAttrExpr ) ;
2019-08-23 11:56:54 -07:00
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
{
2020-10-17 10:52:54 -07:00
//BfLogDbgExpr("Dbg Evaluate %s\n", expr->ToString().c_str());
2019-08-23 11:56:54 -07:00
BF_ASSERT ( ! HasPropResult ( ) ) ;
2020-10-17 10:52:54 -07:00
mCallStackPreservePos = 0 ;
2019-08-23 11:56:54 -07:00
SetAndRestoreValue < DbgType * > prevType ( mExpectingType , wantType ) ;
SetAndRestoreValue < DbgTypedValue > prevResult ( mResult , DbgTypedValue ( ) ) ;
2020-05-15 14:54:43 -07:00
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 ;
}