1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Arithmetic overflow checks

This commit is contained in:
Brian Fiete 2022-01-11 08:17:09 -05:00
parent 1f0d2dcc82
commit eb375362a1
29 changed files with 503 additions and 87 deletions

View file

@ -102,6 +102,8 @@ namespace IDE
[Reflect]
public bool? mEmitObjectAccessCheck; // Only valid with mObjectHasDebugFlags
[Reflect]
public bool? mArithmeticCheck;
[Reflect]
public int32? mAllocStackTraceDepth;
[Reflect]
public BuildOptions.AlwaysIncludeKind mReflectAlwaysInclude;
@ -135,6 +137,7 @@ namespace IDE
newVal.mInitLocalVariables = mInitLocalVariables;
newVal.mEmitDynamicCastCheck = mEmitDynamicCastCheck;
newVal.mEmitObjectAccessCheck = mEmitObjectAccessCheck;
newVal.mArithmeticCheck = mArithmeticCheck;
newVal.mAllocStackTraceDepth = mAllocStackTraceDepth;
newVal.mReflectAlwaysInclude = mReflectAlwaysInclude;
newVal.mReflectBoxing = mReflectBoxing;
@ -164,6 +167,8 @@ namespace IDE
mEmitDynamicCastCheck = data.GetBool("EmitDynamicCastCheck");
if (data.Contains("EmitObjectAccessCheck"))
mEmitObjectAccessCheck = data.GetBool("EmitObjectAccessCheck");
if (data.Contains("ArithmeticCheck"))
mArithmeticCheck = data.GetBool("ArithmeticCheck");
if (data.Contains("AllocStackTraceDepth"))
mAllocStackTraceDepth = data.GetInt("AllocStackTraceDepth");
@ -194,6 +199,7 @@ namespace IDE
data.ConditionalAdd("InitLocalVariables", mInitLocalVariables);
data.ConditionalAdd("EmitDynamicCastCheck", mEmitDynamicCastCheck);
data.ConditionalAdd("EmitObjectAccessCheck", mEmitObjectAccessCheck);
data.ConditionalAdd("ArithmeticCheck", mArithmeticCheck);
data.ConditionalAdd("AllocStackTraceDepth", mAllocStackTraceDepth);
data.ConditionalAdd("ReflectAlwaysInclude", mReflectAlwaysInclude);
data.ConditionalAdd("ReflectBoxing", mReflectBoxing);

View file

@ -38,6 +38,7 @@ namespace IDE.Compiler
DebugAlloc = 0x8000,
OmitDebugHelpers = 0x10000,
NoFramePointerElim = 0x20000,
ArithmeticChecks = 0x40000
}
[CallingConvention(.Stdcall), CLink]
@ -663,6 +664,7 @@ namespace IDE.Compiler
SetOpt(options.mEmitDynamicCastCheck, .EmitDynamicCastCheck);
SetOpt(enableObjectDebugFlags, .EnableObjectDebugFlags);
SetOpt(emitObjectAccessCheck, .EmitObjectAccessCheck);
SetOpt(options.mArithmeticCheck, .ArithmeticChecks);
if (options.LeakCheckingEnabled)
SetOpt(options.mEnableRealtimeLeakCheck, .EnableRealtimeLeakCheck);

View file

@ -15,18 +15,19 @@ namespace IDE.Compiler
InitLocalVariables = 2,
EmitDynamicCastCheck = 4,
EmitObjectAccessCheck = 8,
ArithmeticCheck = 0x10,
ReflectAlwaysIncludeType = 0x10,
ReflectAlwaysIncludeAll = 0x20,
ReflectAssumeInstantiated = 0x40,
ReflectBoxing = 0x80,
ReflectStaticFields = 0x100,
ReflectNonStaticFields = 0x200,
ReflectStaticMethods = 0x400,
ReflectNonStaticMethods = 0x800,
ReflectConstructors = 0x1000,
ReflectAlwaysIncludeType = 0x20,
ReflectAlwaysIncludeAll = 0x40,
ReflectAssumeInstantiated = 0x80,
ReflectBoxing = 0x100,
ReflectStaticFields = 0x200,
ReflectNonStaticFields = 0x400,
ReflectStaticMethods = 0x800,
ReflectNonStaticMethods = 0x1000,
ReflectConstructors = 0x2000,
All = 0x1FFF
All = 0x3FFF
};
[CallingConvention(.Stdcall), CLink]
@ -408,6 +409,8 @@ namespace IDE.Compiler
SetFlag(typeOption.mReflectStaticMethods, .ReflectStaticMethods);
SetFlag(typeOption.mReflectNonStaticMethods, .ReflectNonStaticMethods);
SetFlag(typeOption.mReflectConstructors, .ReflectConstructors);
SetFlag(typeOption.mEmitObjectAccessCheck, .EmitObjectAccessCheck);
SetFlag(typeOption.mArithmeticCheck, .ArithmeticCheck);
AddTypeOptions(typeOption.mFilter, typeOption.mBfSIMDSetting, typeOption.mBfOptimizationLevel, typeOption.mEmitDebugInfo, andFlags, orFlags, typeOption.mAllocStackTraceDepth, typeOption.mReflectMethodFilter);
}

View file

@ -240,6 +240,8 @@ namespace IDE
[Reflect]
public bool mEmitObjectAccessCheck; // Only valid with mObjectHasDebugFlags
[Reflect]
public bool mArithmeticCheck;
[Reflect]
public bool mEnableRealtimeLeakCheck;
[Reflect]
public bool mEnableSideStack;
@ -297,6 +299,7 @@ namespace IDE
mEmitDynamicCastCheck = prev.mEmitDynamicCastCheck;
mEnableObjectDebugFlags = prev.mEnableObjectDebugFlags;
mEmitObjectAccessCheck = prev.mEmitObjectAccessCheck;
mArithmeticCheck = prev.mArithmeticCheck;
mEnableRealtimeLeakCheck = prev.mEnableRealtimeLeakCheck;
mEnableSideStack = prev.mEnableSideStack;
mAllowHotSwapping = prev.mAllowHotSwapping;
@ -694,6 +697,7 @@ namespace IDE
data.ConditionalAdd("EmitDynamicCastCheck", options.mEmitDynamicCastCheck, !isRelease);
data.ConditionalAdd("EnableObjectDebugFlags", options.mEnableObjectDebugFlags, !isRelease);
data.ConditionalAdd("EmitObjectAccessCheck", options.mEmitObjectAccessCheck, !isRelease);
data.ConditionalAdd("ArithmeticCheck", options.mArithmeticCheck, false);
data.ConditionalAdd("EnableRealtimeLeakCheck", options.mEnableRealtimeLeakCheck, (platformType == .Windows) && !isRelease);
data.ConditionalAdd("EnableSideStack", options.mEnableSideStack, (platformType == .Windows) && isParanoid);
data.ConditionalAdd("AllowHotSwapping", options.mAllowHotSwapping, (platformType == .Windows) && !isRelease);
@ -888,6 +892,7 @@ namespace IDE
options.mEmitDynamicCastCheck = !isRelease;
options.mEnableObjectDebugFlags = !isRelease;
options.mEmitObjectAccessCheck = !isRelease;
options.mArithmeticCheck = false;
if (platformType == .Windows)
{
@ -994,6 +999,7 @@ namespace IDE
options.mEmitDynamicCastCheck = data.GetBool("EmitDynamicCastCheck", !isRelease);
options.mEnableObjectDebugFlags = data.GetBool("EnableObjectDebugFlags", !isRelease);
options.mEmitObjectAccessCheck = data.GetBool("EmitObjectAccessCheck", !isRelease);
options.mArithmeticCheck = data.GetBool("ArithmeticCheck", false);
options.mEnableRealtimeLeakCheck = data.GetBool("EnableRealtimeLeakCheck", (platformType == .Windows) && !isRelease);
options.mEnableSideStack = data.GetBool("EnableSideStack", (platformType == .Windows) && isParanoid);
options.mAllowHotSwapping = data.GetBool("AllowHotSwapping", (platformType == .Windows) && !isRelease);

View file

@ -143,6 +143,10 @@ namespace IDE.ui
AddPropertiesItem(category, "Object Access Check", typeName,
scope String[] ( "No", "Yes" ));
typeName.Clear(); typeName.Append(optionsName, "mArithmeticCheck");
AddPropertiesItem(category, "Arithmetic Check", typeName,
scope String[] ( "No", "Yes" ));
typeName.Clear(); typeName.Append(optionsName, "mAllocStackTraceDepth");
AddPropertiesItem(category, "Alloc Stack Trace Depth", typeName);

View file

@ -796,6 +796,8 @@ namespace IDE.ui
scope String[] ( "No", "Yes" ));
AddPropertiesItem(category, "Object Access Check", "mEmitObjectAccessCheck",
scope String[] ( "No", "Yes" ));
AddPropertiesItem(category, "Arithmetic Check", "mArithmeticCheck",
scope String[] ( "No", "Yes" ));
AddPropertiesItem(category, "Realtime Leak Check", "mEnableRealtimeLeakCheck",
scope String[] ( "No", "Yes" ));
AddPropertiesItem(category, "Enable Hot Compilation", "mAllowHotSwapping",

View file

@ -590,6 +590,11 @@ void BeIRCodeGen::Read(bool& val)
BE_MEM_END("bool");
}
void BeIRCodeGen::Read(int8& val)
{
val = mStream->Read();
}
void BeIRCodeGen::Read(BeIRTypeEntry*& type)
{
BE_MEM_START;
@ -1432,21 +1437,24 @@ void BeIRCodeGen::HandleNextCmd()
{
CMD_PARAM(BeValue*, lhs);
CMD_PARAM(BeValue*, rhs);
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Add, lhs, rhs));
CMD_PARAM(int8, overflowCheckKind);
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Add, lhs, rhs, (BfOverflowCheckKind)overflowCheckKind));
}
break;
case BfIRCmd_Sub:
{
CMD_PARAM(BeValue*, lhs);
CMD_PARAM(BeValue*, rhs);
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Subtract, lhs, rhs));
CMD_PARAM(int8, overflowCheckKind);
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Subtract, lhs, rhs, (BfOverflowCheckKind)overflowCheckKind));
}
break;
case BfIRCmd_Mul:
{
CMD_PARAM(BeValue*, lhs);
CMD_PARAM(BeValue*, rhs);
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Multiply, lhs, rhs));
CMD_PARAM(int8, overflowCheckKind);
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Multiply, lhs, rhs, (BfOverflowCheckKind)overflowCheckKind));
}
break;
case BfIRCmd_SDiv:
@ -2100,6 +2108,11 @@ void BeIRCodeGen::HandleNextCmd()
mBeModule->RemoveBlock(mActiveFunction, fromBlock);
}
break;
case BfIRCmd_GetInsertBlock:
{
SetResult(curId, mBeModule->mActiveBlock);
}
break;
case BfIRCmd_SetInsertPoint:
{
CMD_PARAM(BeBlock*, block);

View file

@ -119,6 +119,7 @@ public:
void Read(int64& i);
void Read(Val128& i);
void Read(bool& val);
void Read(int8& val);
void Read(BeIRTypeEntry*& type);
void Read(BeType*& beType);
void Read(BeFunctionType*& beType);

View file

@ -6123,6 +6123,10 @@ uint8 BeMCContext::GetJumpOpCode(BeCmpKind cmpKind, bool isLong)
return 0x8D;
case BeCmpKind_UGE: // JAE
return 0x83;
case BeCmpKind_NB: // JNB
return 0x83;
case BeCmpKind_NO: // JNO
return 0x81;
}
}
else
@ -6151,6 +6155,10 @@ uint8 BeMCContext::GetJumpOpCode(BeCmpKind cmpKind, bool isLong)
return 0x7D;
case BeCmpKind_UGE: // JAE
return 0x73;
case BeCmpKind_NB: // JNB
return 0x73;
case BeCmpKind_NO: // JNO
return 0x71;
}
}
@ -10117,7 +10125,9 @@ bool BeMCContext::DoLegalization()
case BeMCInstKind_Mul:
case BeMCInstKind_IMul:
{
if (arg0Type->mSize == 1)
bool handled = false;
if ((arg0Type->mSize == 1) && (arg0Type->IsIntable()))
{
if ((!arg0.IsNativeReg()) || (arg0.mReg != X64Reg_AL) || (inst->mResult))
{
@ -10152,8 +10162,54 @@ bool BeMCContext::DoLegalization()
}
BF_ASSERT(!inst->mResult);
handled = true;
}
else
else if ((inst->mKind == BeMCInstKind_Mul) && (arg0Type->IsIntable()))
{
auto wantReg0 = ResizeRegister(X64Reg_RAX, arg0Type->mSize);
if ((!arg0.IsNativeReg()) || (arg0.mReg != wantReg0) || (inst->mResult))
{
auto srcVRegInfo = GetVRegInfo(inst->mArg0);
// unsigned multiplies can only be done on AX/EAX/RAX
AllocInst(BeMCInstKind_PreserveVolatiles, BeMCOperand::FromReg(X64Reg_RAX), instIdx++);
AllocInst(BeMCInstKind_PreserveVolatiles, BeMCOperand::FromReg(X64Reg_RDX), instIdx++);
auto vregInfo0 = GetVRegInfo(inst->mArg0);
if (vregInfo0 != NULL)
{
vregInfo0->mDisableRAX = true;
vregInfo0->mDisableRDX = true;
}
auto vregInfo1 = GetVRegInfo(inst->mArg1);
if (vregInfo1 != NULL)
{
vregInfo1->mDisableRAX = true;
vregInfo1->mDisableRDX = true;
}
AllocInst(BeMCInstKind_Mov, BeMCOperand::FromReg(wantReg0), inst->mArg0, instIdx++);
AllocInst(BeMCInstKind_Mov, inst->mResult ? inst->mResult : inst->mArg0, BeMCOperand::FromReg(wantReg0), instIdx++ + 1);
inst->mArg0 = BeMCOperand::FromReg(wantReg0);
inst->mResult = BeMCOperand();
AllocInst(BeMCInstKind_RestoreVolatiles, BeMCOperand::FromReg(X64Reg_RDX), instIdx++ + 1);
AllocInst(BeMCInstKind_RestoreVolatiles, BeMCOperand::FromReg(X64Reg_RAX), instIdx++ + 1);
isFinalRun = false;
break;
}
if (inst->mArg1.IsImmediateInt())
{
ReplaceWithNewVReg(inst->mArg1, instIdx, true, false);
}
BF_ASSERT(!inst->mResult);
handled = true;
}
if (handled)
{
if (inst->mResult)
{
@ -14404,6 +14460,51 @@ void BeMCContext::DoCodeEmission()
}
break;
case BeMCInstKind_Mul:
{
if (arg0Type->IsIntable())
{
bool isValid = true;
auto typeCode = GetType(inst->mArg1)->mTypeCode;
switch (typeCode)
{
case BeTypeCode_Int8:
isValid = inst->mArg0 == BeMCOperand::FromReg(X64Reg_AL);
break;
case BeTypeCode_Int16:
isValid = inst->mArg0 == BeMCOperand::FromReg(X64Reg_AX);
break;
case BeTypeCode_Int32:
isValid = inst->mArg0 == BeMCOperand::FromReg(X64Reg_EAX);
break;
case BeTypeCode_Int64:
isValid = inst->mArg0 == BeMCOperand::FromReg(X64Reg_RAX);
break;
default:
isValid = false;
}
if (!isValid)
SoftFail("Invalid mul arguments");
switch (typeCode)
{
case BeTypeCode_Int8:
EmitREX(BeMCOperand(), inst->mArg1, false);
Emit(0xF6);
EmitModRM(4, inst->mArg1);
break;
case BeTypeCode_Int16: Emit(0x66); // Fallthrough
case BeTypeCode_Int32:
case BeTypeCode_Int64:
EmitREX(BeMCOperand(), inst->mArg1, typeCode == BeTypeCode_Int64);
Emit(0xF7); EmitModRM(4, inst->mArg1);
break;
default:
NotImpl();
}
break;
}
}
//Fallthrough
case BeMCInstKind_IMul:
{
if (instForm == BeMCInstForm_XMM128_RM128)
@ -14931,6 +15032,13 @@ void BeMCContext::DoCodeEmission()
}
break;
case BeMCInstKind_CondBr:
{
if (inst->mArg0.mKind == BeMCOperandKind_Immediate_i64)
{
mOut.Write(GetJumpOpCode(inst->mArg1.mCmpKind, false));
mOut.Write((uint8)inst->mArg0.mImmediate);
}
else
{
BF_ASSERT(inst->mArg0.mKind == BeMCOperandKind_Label);
BeMCJump jump;
@ -14944,6 +15052,7 @@ void BeMCContext::DoCodeEmission()
mOut.Write(GetJumpOpCode(jump.mCmpKind, false));
mOut.Write((uint8)0);
}
}
break;
case BeMCInstKind_Br:
{
@ -15857,7 +15966,7 @@ void BeMCContext::Print(bool showVRegFlags, bool showVRegDetails)
OutputDebugStr(ToString(showVRegFlags, showVRegDetails));
}
BeMCOperand BeMCContext::AllocBinaryOp(BeMCInstKind instKind, const BeMCOperand& lhs, const BeMCOperand& rhs, BeMCBinIdentityKind identityKind)
BeMCOperand BeMCContext::AllocBinaryOp(BeMCInstKind instKind, const BeMCOperand& lhs, const BeMCOperand& rhs, BeMCBinIdentityKind identityKind, BeMCOverflowCheckKind overflowCheckKind)
{
if ((lhs.IsImmediate()) && (lhs.mKind == rhs.mKind))
{
@ -15918,6 +16027,13 @@ BeMCOperand BeMCContext::AllocBinaryOp(BeMCInstKind instKind, const BeMCOperand&
auto mcInst = AllocInst(instKind, lhs, rhs);
mcInst->mResult = result;
if (overflowCheckKind != BeMCOverflowCheckKind_None)
{
AllocInst(BeMCInstKind_CondBr, BeMCOperand::FromImmediate(1), BeMCOperand::FromCmpKind((overflowCheckKind == BeMCOverflowCheckKind_B) ? BeCmpKind_NB : BeCmpKind_NO));
AllocInst(BeMCInstKind_DbgBreak);
}
return result;
}
@ -16399,9 +16515,18 @@ void BeMCContext::Generate(BeFunction* function)
switch (castedInst->mOpKind)
{
case BeBinaryOpKind_Add: result = AllocBinaryOp(BeMCInstKind_Add, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsZero); break;
case BeBinaryOpKind_Subtract: result = AllocBinaryOp(BeMCInstKind_Sub, mcLHS, mcRHS, BeMCBinIdentityKind_Right_IsZero); break;
case BeBinaryOpKind_Multiply: result = AllocBinaryOp(BeMCInstKind_IMul, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsOne); break;
case BeBinaryOpKind_Add: result = AllocBinaryOp(BeMCInstKind_Add, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsZero,
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? BeMCOverflowCheckKind_O :
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Unsigned) != 0) ? BeMCOverflowCheckKind_B : BeMCOverflowCheckKind_None);
break;
case BeBinaryOpKind_Subtract: result = AllocBinaryOp(BeMCInstKind_Sub, mcLHS, mcRHS, BeMCBinIdentityKind_Right_IsZero,
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? BeMCOverflowCheckKind_O :
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Unsigned) != 0) ? BeMCOverflowCheckKind_B : BeMCOverflowCheckKind_None);
break;
case BeBinaryOpKind_Multiply: result = AllocBinaryOp(((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Unsigned) != 0) ? BeMCInstKind_Mul : BeMCInstKind_IMul, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsOne,
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? BeMCOverflowCheckKind_O :
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Unsigned) != 0) ? BeMCOverflowCheckKind_O : BeMCOverflowCheckKind_None);
break;
case BeBinaryOpKind_SDivide: result = AllocBinaryOp(BeMCInstKind_IDiv, mcLHS, mcRHS, BeMCBinIdentityKind_Right_IsOne); break;
case BeBinaryOpKind_UDivide: result = AllocBinaryOp(BeMCInstKind_Div, mcLHS, mcRHS, BeMCBinIdentityKind_Right_IsOne); break;
case BeBinaryOpKind_SModulus: result = AllocBinaryOp(BeMCInstKind_IRem, mcLHS, mcRHS, type->IsFloat() ? BeMCBinIdentityKind_None : BeMCBinIdentityKind_Right_IsOne_Result_Zero); break;

View file

@ -1293,6 +1293,13 @@ struct BeRMParamsInfo
}
};
enum BeMCOverflowCheckKind
{
BeMCOverflowCheckKind_None,
BeMCOverflowCheckKind_B,
BeMCOverflowCheckKind_O
};
// This class only processes one function per instantiation
class BeMCContext
{
@ -1367,7 +1374,7 @@ public:
BeMCInst* AllocInst(BeMCInstKind instKind, const BeMCOperand& arg0, const BeMCOperand& arg1, int insertIdx = -1);
void MergeInstFlags(BeMCInst* prevInst, BeMCInst* inst, BeMCInst* nextInst);
void RemoveInst(BeMCBlock* block, int instIdx, bool needChangesMerged = true, bool removeFromList = true);
BeMCOperand AllocBinaryOp(BeMCInstKind instKind, const BeMCOperand & lhs, const BeMCOperand & rhs, BeMCBinIdentityKind identityKind);
BeMCOperand AllocBinaryOp(BeMCInstKind instKind, const BeMCOperand & lhs, const BeMCOperand & rhs, BeMCBinIdentityKind identityKind, BeMCOverflowCheckKind overflowCheckKind = BeMCOverflowCheckKind_None);
BeMCOperand GetCallArgVReg(int argIdx, BeTypeCode typeCode);
BeMCOperand CreateCall(const BeMCOperand& func, const SizedArrayImpl<BeMCOperand>& args, BeType* retType = NULL, BfIRCallingConv callingConv = BfIRCallingConv_CDecl, bool structRet = false, bool noReturn = false, bool isVarArg = false);
BeMCOperand CreateCall(const BeMCOperand& func, const SizedArrayImpl<BeValue*>& args, BeType* retType = NULL, BfIRCallingConv callingConv = BfIRCallingConv_CDecl, bool structRet = false, bool noReturn = false, bool isVarArg = false);

View file

@ -1683,6 +1683,8 @@ void BeDumpContext::ToString(StringImpl& str, BeCmpKind cmpKind)
case BeCmpKind_UGT: str += "ugt"; return;
case BeCmpKind_SGE: str += "sge"; return;
case BeCmpKind_UGE: str += "uge"; return;
case BeCmpKind_NB: str += "nb"; return;
case BeCmpKind_NO: str += "no"; return;
default:
str += "???";
}
@ -3292,7 +3294,7 @@ BeCmpInst* BeModule::CreateCmp(BeCmpKind cmpKind, BeValue* lhs, BeValue* rhs)
return inst;
}
BeBinaryOpInst* BeModule::CreateBinaryOp(BeBinaryOpKind opKind, BeValue* lhs, BeValue* rhs)
BeBinaryOpInst* BeModule::CreateBinaryOp(BeBinaryOpKind opKind, BeValue* lhs, BeValue* rhs, BfOverflowCheckKind overflowCheckKind)
{
#ifdef _DEBUG
auto leftType = lhs->GetType();
@ -3303,6 +3305,7 @@ BeBinaryOpInst* BeModule::CreateBinaryOp(BeBinaryOpKind opKind, BeValue* lhs, Be
inst->mOpKind = opKind;
inst->mLHS = lhs;
inst->mRHS = rhs;
inst->mOverflowCheckKind = overflowCheckKind;
AddInst(inst);
return inst;
}

View file

@ -820,6 +820,7 @@ public:
BE_VALUE_TYPE(BeBinaryOpInst, BeInst);
BeBinaryOpKind mOpKind;
BfOverflowCheckKind mOverflowCheckKind;
BeValue* mLHS;
BeValue* mRHS;
@ -829,6 +830,7 @@ public:
{
hashCtx.Mixin(TypeId);
hashCtx.Mixin(mOpKind);
hashCtx.Mixin(mOverflowCheckKind);
mLHS->HashReference(hashCtx);
mRHS->HashReference(hashCtx);
}
@ -847,7 +849,9 @@ enum BeCmpKind
BeCmpKind_SGT,
BeCmpKind_UGT,
BeCmpKind_SGE,
BeCmpKind_UGE
BeCmpKind_UGE,
BeCmpKind_NB,
BeCmpKind_NO,
};
class BeCmpInst : public BeInst
@ -2338,7 +2342,7 @@ public:
BeNumericCastInst* CreateNumericCast(BeValue* value, BeType* toType, bool valSigned, bool toSigned);
BeBitCastInst* CreateBitCast(BeValue* value, BeType* toType);;
BeCmpInst* CreateCmp(BeCmpKind cmpKind, BeValue* lhs, BeValue* rhs);
BeBinaryOpInst* CreateBinaryOp(BeBinaryOpKind opKind, BeValue* lhs, BeValue* rhs);
BeBinaryOpInst* CreateBinaryOp(BeBinaryOpKind opKind, BeValue* lhs, BeValue* rhs, BfOverflowCheckKind overflowCheckKind = BfOverflowCheckKind_None);
BeAllocaInst* CreateAlloca(BeType* type);
BeLoadInst* CreateLoad(BeValue* value, bool isVolatile);

View file

@ -9729,7 +9729,8 @@ BF_EXPORT void BF_CALLTYPE BfCompiler_SetOptions(BfCompiler* bfCompiler, BfProje
// }
BF_ASSERT(!options->mEnableRealtimeLeakCheck);
#endif
options->mEmitObjectAccessCheck = (optionFlags & BfCompilerOptionFlag_EmitDebugInfo) != 0;
options->mEmitObjectAccessCheck = (optionFlags & BfCompilerOptionFlag_EmitObjectAccessCheck) != 0;
options->mArithmeticChecks = (optionFlags & BfCompilerOptionFlag_ArithmeticChecks) != 0;
options->mAllocStackCount = allocStackCount;
if (hotProject != NULL)
@ -9770,6 +9771,7 @@ BF_EXPORT void BF_CALLTYPE BfCompiler_SetOptions(BfCompiler* bfCompiler, BfProje
options->mObjectHasDebugFlags = false;
options->mEnableRealtimeLeakCheck = false;
options->mEmitObjectAccessCheck = false;
options->mArithmeticChecks = false;
options->mEmitDynamicCastCheck = false;
options->mRuntimeChecks = (optionFlags & BfCompilerOptionFlag_RuntimeChecks) != 0;
}

View file

@ -118,6 +118,7 @@ public:
bool mObjectHasDebugFlags;
bool mEnableRealtimeLeakCheck;
bool mEmitObjectAccessCheck; // Only valid with mObjectHasDebugFlags
bool mArithmeticChecks;
bool mEnableCustodian;
bool mEnableSideStack;
bool mHasVDataExtender;
@ -162,6 +163,7 @@ public:
mEmitDynamicCastCheck = true;
mAllowHotSwapping = false;
mEmitObjectAccessCheck = false;
mArithmeticChecks = false;
mObjectHasDebugFlags = false;
mEnableRealtimeLeakCheck = false;
mWriteIR = false;

View file

@ -2200,6 +2200,7 @@ void BfContext::UpdateRevisedTypes()
workspaceConfigHashCtx.Mixin(options->mObjectHasDebugFlags);
workspaceConfigHashCtx.Mixin(options->mEnableRealtimeLeakCheck);
workspaceConfigHashCtx.Mixin(options->mEmitObjectAccessCheck);
workspaceConfigHashCtx.Mixin(options->mArithmeticChecks);
workspaceConfigHashCtx.Mixin(options->mEnableCustodian);
workspaceConfigHashCtx.Mixin(options->mEnableSideStack);
workspaceConfigHashCtx.Mixin(options->mHasVDataExtender);

View file

@ -22665,23 +22665,43 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL
return;
}
auto _GetOverflowKind = [&](bool wantOverflow)
{
if (!wantOverflow)
return BfOverflowCheckKind_None;
if (mModule->GetDefaultCheckedKind() != BfCheckedKind_Checked)
return BfOverflowCheckKind_None;
bool arithmeticChecks = mModule->mCompiler->mOptions.mArithmeticChecks;
auto typeOptions = mModule->GetTypeOptions();
if (typeOptions != NULL)
arithmeticChecks = typeOptions->Apply(arithmeticChecks, BfOptionFlags_ArithmeticCheck);
if (!arithmeticChecks)
return BfOverflowCheckKind_None;
BfOverflowCheckKind overflowCheckKind = (resultType->IsSigned()) ? BfOverflowCheckKind_Signed : BfOverflowCheckKind_Unsigned;
if (!mModule->IsOptimized())
overflowCheckKind = (BfOverflowCheckKind)(overflowCheckKind | BfOverflowCheckKind_Flag_UseAsm);
return overflowCheckKind;
};
switch (binaryOp)
{
case BfBinaryOp_Add:
case BfBinaryOp_OverflowAdd:
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateAdd(convLeftValue, convRightValue), resultType);
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateAdd(convLeftValue, convRightValue, _GetOverflowKind(binaryOp == BfBinaryOp_Add)), resultType);
if (binaryOp != BfBinaryOp_OverflowAdd)
mModule->CheckRangeError(resultType, opToken);
break;
case BfBinaryOp_Subtract:
case BfBinaryOp_OverflowSubtract:
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateSub(convLeftValue, convRightValue), resultType);
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateSub(convLeftValue, convRightValue, _GetOverflowKind(binaryOp == BfBinaryOp_Subtract)), resultType);
if (binaryOp != BfBinaryOp_OverflowSubtract)
mModule->CheckRangeError(resultType, opToken);
break;
case BfBinaryOp_Multiply:
case BfBinaryOp_OverflowMultiply:
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateMul(convLeftValue, convRightValue), resultType);
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateMul(convLeftValue, convRightValue, _GetOverflowKind(binaryOp == BfBinaryOp_Multiply)), resultType);
if (binaryOp != BfBinaryOp_OverflowMultiply)
mModule->CheckRangeError(resultType, opToken);
break;

View file

@ -4248,7 +4248,7 @@ BfIRValue BfIRBuilder::CreateCmpGTE(BfIRValue lhs, BfIRValue rhs, bool isSigned)
return retVal;
}
BfIRValue BfIRBuilder::CreateAdd(BfIRValue lhs, BfIRValue rhs)
BfIRValue BfIRBuilder::CreateAdd(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind)
{
mOpFailed = false;
if ((lhs.IsConst()) && (rhs.IsConst()))
@ -4260,12 +4260,19 @@ BfIRValue BfIRBuilder::CreateAdd(BfIRValue lhs, BfIRValue rhs)
}
}
auto retVal = WriteCmd(BfIRCmd_Add, lhs, rhs);
auto retVal = WriteCmd(BfIRCmd_Add, lhs, rhs, overflowCheckKind);
NEW_CMD_INSERTED_IRVALUE;
if ((overflowCheckKind != BfOverflowCheckKind_None) && (!mIgnoreWrites))
{
mInsertBlock = mActualInsertBlock = WriteCmd(BfIRCmd_GetInsertBlock);
NEW_CMD_INSERTED_IRVALUE;
}
return retVal;
}
BfIRValue BfIRBuilder::CreateSub(BfIRValue lhs, BfIRValue rhs)
BfIRValue BfIRBuilder::CreateSub(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind)
{
mOpFailed = false;
if ((lhs.IsConst()) && (rhs.IsConst()))
@ -4273,12 +4280,19 @@ BfIRValue BfIRBuilder::CreateSub(BfIRValue lhs, BfIRValue rhs)
BINOPFUNC_APPLY(lhs, rhs, CheckedSub);
}
auto retVal = WriteCmd(BfIRCmd_Sub, lhs, rhs);
auto retVal = WriteCmd(BfIRCmd_Sub, lhs, rhs, overflowCheckKind);
NEW_CMD_INSERTED;
if ((overflowCheckKind != BfOverflowCheckKind_None) && (!mIgnoreWrites))
{
mInsertBlock = mActualInsertBlock = WriteCmd(BfIRCmd_GetInsertBlock);
NEW_CMD_INSERTED_IRVALUE;
}
return retVal;
}
BfIRValue BfIRBuilder::CreateMul(BfIRValue lhs, BfIRValue rhs)
BfIRValue BfIRBuilder::CreateMul(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind)
{
mOpFailed = false;
if ((lhs.IsConst()) && (rhs.IsConst()))
@ -4286,8 +4300,15 @@ BfIRValue BfIRBuilder::CreateMul(BfIRValue lhs, BfIRValue rhs)
BINOPFUNC_APPLY(lhs, rhs, CheckedMul);
}
auto retVal = WriteCmd(BfIRCmd_Mul, lhs, rhs);
auto retVal = WriteCmd(BfIRCmd_Mul, lhs, rhs, overflowCheckKind);
NEW_CMD_INSERTED_IRVALUE;
if ((overflowCheckKind != BfOverflowCheckKind_None) && (!mIgnoreWrites))
{
mInsertBlock = mActualInsertBlock = WriteCmd(BfIRCmd_GetInsertBlock);
NEW_CMD_INSERTED_IRVALUE;
}
return retVal;
}

View file

@ -247,6 +247,7 @@ enum BfIRCmd : uint8
BfIRCmd_AddBlock,
BfIRCmd_DropBlocks,
BfIRCmd_MergeBlockDown,
BfIRCmd_GetInsertBlock,
BfIRCmd_SetInsertPoint,
BfIRCmd_SetInsertPointAtStart,
BfIRCmd_EraseFromParent,
@ -964,6 +965,14 @@ struct BfIRState
Array<BfFilePosition> mSavedDebugLocs;
};
enum BfOverflowCheckKind : int8
{
BfOverflowCheckKind_None = 0,
BfOverflowCheckKind_Signed = 1,
BfOverflowCheckKind_Unsigned = 2,
BfOverflowCheckKind_Flag_UseAsm = 4
};
class BfIRBuilder : public BfIRConstHolder
{
public:
@ -1182,9 +1191,9 @@ public:
BfIRValue CreateCmpLTE(BfIRValue lhs, BfIRValue rhs, bool isSigned);
BfIRValue CreateCmpGT(BfIRValue lhs, BfIRValue rhs, bool isSigned);
BfIRValue CreateCmpGTE(BfIRValue lhs, BfIRValue rhs, bool isSigned);
BfIRValue CreateAdd(BfIRValue lhs, BfIRValue rhs);
BfIRValue CreateSub(BfIRValue lhs, BfIRValue rhs);
BfIRValue CreateMul(BfIRValue lhs, BfIRValue rhs);
BfIRValue CreateAdd(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind = BfOverflowCheckKind_None);
BfIRValue CreateSub(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind = BfOverflowCheckKind_None);
BfIRValue CreateMul(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind = BfOverflowCheckKind_None);
BfIRValue CreateDiv(BfIRValue lhs, BfIRValue rhs, bool isSigned);
BfIRValue CreateRem(BfIRValue lhs, BfIRValue rhs, bool isSigned);
BfIRValue CreateAnd(BfIRValue lhs, BfIRValue rhs);

View file

@ -340,7 +340,8 @@ BfIRCodeGen::BfIRCodeGen()
mLLVMTargetMachine = NULL;
mNopInlineAsm = NULL;
mAsmObjectCheckAsm = NULL;
mObjectCheckAsm = NULL;
mOverflowCheckAsm = NULL;
mHasDebugLoc = false;
mAttrSet = NULL;
mIRBuilder = NULL;
@ -730,6 +731,11 @@ void BfIRCodeGen::Read(bool& val)
val = mStream->Read() != 0;
}
void BfIRCodeGen::Read(int8& val)
{
val = mStream->Read();
}
void BfIRCodeGen::Read(BfIRTypeEntry*& type)
{
int typeId = (int)ReadSLEB128();
@ -1447,6 +1453,72 @@ llvm::Value* BfIRCodeGen::FixGEP(llvm::Value* fromValue, llvm::Value* result)
return result;
}
llvm::Value* BfIRCodeGen::DoCheckedIntrinsic(llvm::Intrinsic::ID intrin, llvm::Value* lhs, llvm::Value* rhs, bool useAsm)
{
if ((mTargetTriple.GetMachineType() != BfMachineType_x86) && (mTargetTriple.GetMachineType() != BfMachineType_x64))
useAsm = false;
CmdParamVec<llvm::Type*> useParams;
useParams.push_back(lhs->getType());
auto func = llvm::Intrinsic::getDeclaration(mLLVMModule, intrin, useParams);
CmdParamVec<llvm::Value*> args;
args.push_back(lhs);
args.push_back(rhs);
llvm::FunctionType* funcType = NULL;
if (auto ptrType = llvm::dyn_cast<llvm::PointerType>(func->getType()))
funcType = llvm::dyn_cast<llvm::FunctionType>(ptrType->getElementType());
auto aggResult = mIRBuilder->CreateCall(funcType, func, args);
auto valResult = mIRBuilder->CreateExtractValue(aggResult, 0);
auto failResult = mIRBuilder->CreateExtractValue(aggResult, 1);
if (!useAsm)
{
mLockedBlocks.Add(mIRBuilder->GetInsertBlock());
auto failBB = llvm::BasicBlock::Create(*mLLVMContext, "access.fail");
auto passBB = llvm::BasicBlock::Create(*mLLVMContext, "access.pass");
mIRBuilder->CreateCondBr(failResult, failBB, passBB);
mActiveFunction->getBasicBlockList().push_back(failBB);
mIRBuilder->SetInsertPoint(failBB);
auto trapDecl = llvm::Intrinsic::getDeclaration(mLLVMModule, llvm::Intrinsic::trap);
auto callInst = mIRBuilder->CreateCall(trapDecl);
callInst->addAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::NoReturn);
mIRBuilder->CreateBr(passBB);
mActiveFunction->getBasicBlockList().push_back(passBB);
mIRBuilder->SetInsertPoint(passBB);
}
else
{
if (mOverflowCheckAsm == NULL)
{
std::vector<llvm::Type*> paramTypes;
paramTypes.push_back(llvm::Type::getInt8Ty(*mLLVMContext));
auto funcType = llvm::FunctionType::get(llvm::Type::getVoidTy(*mLLVMContext), paramTypes, false);
String asmStr =
"testb $$1, $0\n"
"jz 1f\n"
"int $$3\n"
"1:";
mOverflowCheckAsm = llvm::InlineAsm::get(funcType,
asmStr.c_str(), "r,~{dirflag},~{fpsr},~{flags}", true,
false, llvm::InlineAsm::AD_ATT);
}
llvm::SmallVector<llvm::Value*, 1> llvmArgs;
llvmArgs.push_back(mIRBuilder->CreateIntCast(failResult, llvm::Type::getInt8Ty(*mLLVMContext), false));
llvm::CallInst* callInst = mIRBuilder->CreateCall(mOverflowCheckAsm, llvmArgs);
callInst->addAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::NoUnwind);
}
return valResult;
}
void BfIRCodeGen::CreateMemSet(llvm::Value* addr, llvm::Value* val, llvm::Value* size, int alignment, bool isVolatile)
{
auto sizeConst = llvm::dyn_cast<llvm::ConstantInt>(size);
@ -2040,12 +2112,17 @@ void BfIRCodeGen::HandleNextCmd()
SetResult(curId, mIRBuilder->CreateICmpUGE(lhs, rhs));
}
break;
case BfIRCmd_Add:
{
CMD_PARAM(llvm::Value*, lhs);
CMD_PARAM(llvm::Value*, rhs);
CMD_PARAM(int8, overflowCheckKind);
if (lhs->getType()->isFloatingPointTy())
SetResult(curId, mIRBuilder->CreateFAdd(lhs, rhs));
else if ((overflowCheckKind & (BfOverflowCheckKind_Signed | BfOverflowCheckKind_Unsigned)) != 0)
SetResult(curId, DoCheckedIntrinsic(((overflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? llvm::Intrinsic::sadd_with_overflow : llvm::Intrinsic::uadd_with_overflow,
lhs, rhs, (overflowCheckKind & BfOverflowCheckKind_Flag_UseAsm) != 0));
else
SetResult(curId, mIRBuilder->CreateAdd(lhs, rhs));
}
@ -2054,8 +2131,12 @@ void BfIRCodeGen::HandleNextCmd()
{
CMD_PARAM(llvm::Value*, lhs);
CMD_PARAM(llvm::Value*, rhs);
CMD_PARAM(int8, overflowCheckKind);
if (lhs->getType()->isFloatingPointTy())
SetResult(curId, mIRBuilder->CreateFSub(lhs, rhs));
else if ((overflowCheckKind & (BfOverflowCheckKind_Signed | BfOverflowCheckKind_Unsigned)) != 0)
SetResult(curId, DoCheckedIntrinsic(((overflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? llvm::Intrinsic::ssub_with_overflow : llvm::Intrinsic::usub_with_overflow,
lhs, rhs, (overflowCheckKind & BfOverflowCheckKind_Flag_UseAsm) != 0));
else
SetResult(curId, mIRBuilder->CreateSub(lhs, rhs));
}
@ -2064,8 +2145,12 @@ void BfIRCodeGen::HandleNextCmd()
{
CMD_PARAM(llvm::Value*, lhs);
CMD_PARAM(llvm::Value*, rhs);
CMD_PARAM(int8, overflowCheckKind);
if (lhs->getType()->isFloatingPointTy())
SetResult(curId, mIRBuilder->CreateFMul(lhs, rhs));
else if ((overflowCheckKind & (BfOverflowCheckKind_Signed | BfOverflowCheckKind_Unsigned)) != 0)
SetResult(curId, DoCheckedIntrinsic(((overflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? llvm::Intrinsic::smul_with_overflow : llvm::Intrinsic::umul_with_overflow,
lhs, rhs, (overflowCheckKind & BfOverflowCheckKind_Flag_UseAsm) != 0));
else
SetResult(curId, mIRBuilder->CreateMul(lhs, rhs));
}
@ -2529,6 +2614,11 @@ void BfIRCodeGen::HandleNextCmd()
fromBlock->eraseFromParent();
}
break;
case BfIRCmd_GetInsertBlock:
{
SetResult(curId, mIRBuilder->GetInsertBlock());
}
break;
case BfIRCmd_SetInsertPoint:
{
CMD_PARAM(llvm::BasicBlock*, block);
@ -3906,7 +3996,7 @@ void BfIRCodeGen::HandleNextCmd()
else
{
llvm::Type* voidPtrType = llvm::Type::getInt8PtrTy(*mLLVMContext);
if (mAsmObjectCheckAsm == NULL)
if (mObjectCheckAsm == NULL)
{
std::vector<llvm::Type*> paramTypes;
paramTypes.push_back(voidPtrType);
@ -3918,7 +4008,7 @@ void BfIRCodeGen::HandleNextCmd()
"int $$3\n"
"1:";
mAsmObjectCheckAsm = llvm::InlineAsm::get(funcType,
mObjectCheckAsm = llvm::InlineAsm::get(funcType,
asmStr.c_str(), "r,~{dirflag},~{fpsr},~{flags}", true,
false, llvm::InlineAsm::AD_ATT);
}
@ -3926,7 +4016,7 @@ void BfIRCodeGen::HandleNextCmd()
llvm::SmallVector<llvm::Value*, 1> llvmArgs;
llvmArgs.push_back(mIRBuilder->CreateBitCast(val, voidPtrType));
llvm::CallInst* callInst = irBuilder->CreateCall(mAsmObjectCheckAsm, llvmArgs);
llvm::CallInst* callInst = irBuilder->CreateCall(mObjectCheckAsm, llvmArgs);
callInst->addAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::NoUnwind);
SetResult(curId, mIRBuilder->GetInsertBlock());

View file

@ -100,7 +100,8 @@ public:
llvm::TargetMachine* mLLVMTargetMachine;
Array<llvm::DebugLoc> mSavedDebugLocs;
llvm::InlineAsm* mNopInlineAsm;
llvm::InlineAsm* mAsmObjectCheckAsm;
llvm::InlineAsm* mObjectCheckAsm;
llvm::InlineAsm* mOverflowCheckAsm;
llvm::DebugLoc mDebugLoc;
BfCodeGenOptions mCodeGenOptions;
bool mHasDebugLoc;
@ -140,6 +141,7 @@ public:
llvm::Type* GetSizeAlignedType(BfIRTypeEntry* typeEntry);
llvm::Value* GetAlignedPtr(llvm::Value* val);
llvm::Value* FixGEP(llvm::Value* fromValue, llvm::Value* result);
llvm::Value* DoCheckedIntrinsic(llvm::Intrinsic::ID intrin, llvm::Value* lhs, llvm::Value* rhs, bool useAsm);
public:
BfIRCodeGen();
@ -158,6 +160,7 @@ public:
void Read(int64& i);
void Read(Val128& i);
void Read(bool& val);
void Read(int8& val);
void Read(BfIRTypeEntry*& type);
void Read(llvm::Type*& llvmType, BfIRTypeEntry** outTypeEntry = NULL);
void Read(llvm::FunctionType*& llvmType);

View file

@ -160,6 +160,7 @@ enum BfCompilerOptionFlags
BfCompilerOptionFlag_DebugAlloc = 0x8000,
BfCompilerOptionFlag_OmitDebugHelpers = 0x10000,
BfCompilerOptionFlag_NoFramePointerElim = 0x20000,
BfCompilerOptionFlag_ArithmeticChecks = 0x40000,
};
enum BfTypeFlags
@ -1441,19 +1442,20 @@ enum BfOptionFlags
BfOptionFlags_InitLocalVariables = 2,
BfOptionFlags_EmitDynamicCastCheck = 4,
BfOptionFlags_EmitObjectAccessCheck = 8,
BfOptionFlags_ArithmeticCheck = 0x10,
BfOptionFlags_ReflectAlwaysIncludeType = 0x10,
BfOptionFlags_ReflectAlwaysIncludeAll = 0x20,
BfOptionFlags_ReflectAssumeInstantiated = 0x40,
BfOptionFlags_ReflectBoxing = 0x80,
BfOptionFlags_ReflectStaticFields = 0x100,
BfOptionFlags_ReflectNonStaticFields = 0x200,
BfOptionFlags_ReflectStaticMethods = 0x400,
BfOptionFlags_ReflectNonStaticMethods = 0x800,
BfOptionFlags_ReflectConstructors = 0x1000,
BfOptionFlags_ReflectAlwaysIncludeType = 0x20,
BfOptionFlags_ReflectAlwaysIncludeAll = 0x40,
BfOptionFlags_ReflectAssumeInstantiated = 0x80,
BfOptionFlags_ReflectBoxing = 0x100,
BfOptionFlags_ReflectStaticFields = 0x200,
BfOptionFlags_ReflectNonStaticFields = 0x400,
BfOptionFlags_ReflectStaticMethods = 0x800,
BfOptionFlags_ReflectNonStaticMethods = 0x1000,
BfOptionFlags_ReflectConstructors = 0x2000,
BfOptionFlags_Reflect_MethodMask = BfOptionFlags_ReflectStaticMethods | BfOptionFlags_ReflectNonStaticMethods | BfOptionFlags_ReflectConstructors,
BfOptionFlags_Mask = 0xFFF
BfOptionFlags_Mask = 0x3FFF
};

View file

@ -61,4 +61,11 @@ enum DbgAddrType : uint8
DbgAddrType_Alias
};
enum DbgBreakKind
{
DbgBreakKind_None,
DbgBreakKind_ObjectAccess,
DbgBreakKind_ArithmeticOverflow
};
NS_BF_END

View file

@ -2449,18 +2449,18 @@ bool DebugTarget::DecodeInstruction(addr_target address, CPUInst* inst)
}
bool DebugTarget::IsObjectAccessBreak(addr_target address, CPURegisters* registers, intptr_target* objAddr)
DbgBreakKind DebugTarget::GetDbgBreakKind(addr_target address, CPURegisters* registers, intptr_target* objAddr)
{
for (auto dwarf : mDbgModules)
{
if ((address >= dwarf->mImageBase) && (address < dwarf->mImageBase + dwarf->mImageSize) && (dwarf->mOrigImageData != NULL))
{
bool result = mDebugger->mCPU->IsObjectAccessBreak(address, dwarf->mOrigImageData, registers->mIntRegsArray, objAddr);
auto result = mDebugger->mCPU->GetDbgBreakKind(address, dwarf->mOrigImageData, registers->mIntRegsArray, objAddr);
return result;
}
}
return false;
return DbgBreakKind_None;
}

View file

@ -111,7 +111,7 @@ public:
const DbgMemoryFlags ReadOrigImageData(addr_target address, uint8* data, int size);
bool DecodeInstruction(addr_target address, CPUInst* inst);
bool IsObjectAccessBreak(addr_target address, CPURegisters* regs, intptr_target* objAddr);
DbgBreakKind GetDbgBreakKind(addr_target address, CPURegisters* regs, intptr_target* objAddr);
DbgModule* FindDbgModuleForAddress(addr_target address);
DbgModule* GetMainDbgModule();
void ReportMemory(MemReporter* memReporter);

View file

@ -4866,7 +4866,8 @@ void WinDebugger::CheckNonDebuggerBreak()
}
intptr_target objAddr;
if (mDebugTarget->IsObjectAccessBreak(pcAddress, &registers, &objAddr))
auto dbgBreakKind = mDebugTarget->GetDbgBreakKind(pcAddress, &registers, &objAddr);
if (dbgBreakKind == DbgBreakKind_ObjectAccess)
{
String errorStr = "error Attempted to access deleted object";
String objectAddr = EncodeDataPtr((addr_target)objAddr, true);
@ -4874,6 +4875,12 @@ void WinDebugger::CheckNonDebuggerBreak()
mDebugManager->mOutMessages.push_back(errorStr);
return;
}
else if (dbgBreakKind == DbgBreakKind_ArithmeticOverflow)
{
String errorStr = "error Arithmetic overflow detected";
mDebugManager->mOutMessages.push_back(errorStr);
return;
}
bool showMainThread = false;

View file

@ -985,7 +985,7 @@ String X64CPU::InstructionToString(X64Instr* inst, uint64 addr)
return result;
}
bool X64CPU::IsObjectAccessBreak(uint64 address, DbgModuleMemoryCache* memoryCache, int64* regs, int64* outObjectPtr)
DbgBreakKind X64CPU::GetDbgBreakKind(uint64 address, DbgModuleMemoryCache* memoryCache, int64* regs, int64* outObjectPtr)
{
// We've looking for a CMP BYTE PTR [<reg>], -0x80
// if <reg> is R12 then encoding takes an extra 2 bytes
@ -1005,6 +1005,19 @@ bool X64CPU::IsObjectAccessBreak(uint64 address, DbgModuleMemoryCache* memoryCac
continue;
auto immediateType = (instDesc.TSFlags & llvm::X86II::ImmMask);
if ((immediateType == llvm::X86II::Imm8) && (inst.mMCInst.getNumOperands() == 2))
{
// We're checking for a TEST [<reg>], 1
if (inst.mMCInst.getOpcode() != llvm::X86::TEST8ri)
continue;
auto immOp = inst.mMCInst.getOperand(1);
if (!immOp.isImm())
continue;
if (immOp.getImm() != 1)
continue;
return DbgBreakKind_ArithmeticOverflow;
}
if ((immediateType == 0) || (inst.mMCInst.getNumOperands() < 6))
continue;
@ -1027,10 +1040,35 @@ bool X64CPU::IsObjectAccessBreak(uint64 address, DbgModuleMemoryCache* memoryCac
*outObjectPtr = (uint64)regs[regNum];
return true;
return DbgBreakKind_ObjectAccess;
}
return false;
// check jno/jnb
for (int offset = 3; offset <= 3; offset++)
{
if (!Decode(address - offset, memoryCache, &inst))
continue;
if (inst.GetLength() != 2)
continue;
const MCInstrDesc &instDesc = mInstrInfo->get(inst.mMCInst.getOpcode());
if (!instDesc.isBranch())
continue;
auto immediateType = (instDesc.TSFlags & llvm::X86II::ImmMask);
if ((immediateType == llvm::X86II::Imm8PCRel) && (inst.mMCInst.getNumOperands() == 2))
{
auto immOp = inst.mMCInst.getOperand(1);
if (!immOp.isImm())
continue;
if ((immOp.getImm() != 1) && (immOp.getImm() != 3))
continue;
return DbgBreakKind_ArithmeticOverflow;
}
}
return DbgBreakKind_None;
}
int X64CPU::GetOpcodesForMnemonic(const StringImpl& mnemonic, Array<int>& outOpcodes)

View file

@ -508,7 +508,7 @@ public:
String InstructionToString(X64Instr* inst, uint64 addr);
void GetNextPC(uint64 baseAddress, const uint8* dataBase, int dataLength, const uint8* dataPtr, uint32* regs, uint64 nextPCs[2]);
bool IsObjectAccessBreak(uint64 address, DbgModuleMemoryCache* memoryCache, int64* regs, int64* outObjectPtr);
DbgBreakKind GetDbgBreakKind(uint64 address, DbgModuleMemoryCache* memoryCache, int64* regs, int64* outObjectPtr);
int GetOpcodesForMnemonic(const StringImpl& mnemonic, Array<int>& outOpcodes);
void GetClobbersForMnemonic(const StringImpl& mnemonic, int argCount, Array<int>& outImplicitClobberRegNums, int& outClobberArgCount, bool& outMayClobberMem);

View file

@ -575,7 +575,7 @@ String X86CPU::InstructionToString(X86Instr* inst, uint32 addr)
return result;
}
bool X86CPU::IsObjectAccessBreak(uint32 address, DbgModuleMemoryCache* memoryCache, int32* regs, int32* outObjectPtr)
DbgBreakKind X86CPU::GetDbgBreakKind(uint32 address, DbgModuleMemoryCache* memoryCache, int32* regs, int32* outObjectPtr)
{
// We've looking for a CMP BYTE PTR [<reg>], -0x80
// if <reg> is R12 then encoding takes an extra 2 bytes
@ -590,11 +590,24 @@ bool X86CPU::IsObjectAccessBreak(uint32 address, DbgModuleMemoryCache* memoryCac
if (inst.GetLength() != checkLen)
continue;
const MCInstrDesc &instDesc = mInstrInfo->get(inst.mMCInst.getOpcode());
const MCInstrDesc& instDesc = mInstrInfo->get(inst.mMCInst.getOpcode());
if (!instDesc.isCompare())
continue;
auto immediateType = (instDesc.TSFlags & llvm::X86II::ImmMask);
if ((immediateType == llvm::X86II::Imm8) && (inst.mMCInst.getNumOperands() == 2))
{
// We're checking for a TEST [<reg>], 1
if (inst.mMCInst.getOpcode() != llvm::X86::TEST8ri)
continue;
auto immOp = inst.mMCInst.getOperand(1);
if (!immOp.isImm())
continue;
if (immOp.getImm() != 1)
continue;
return DbgBreakKind_ArithmeticOverflow;
}
if ((immediateType == 0) || (inst.mMCInst.getNumOperands() < 6))
continue;
@ -617,10 +630,35 @@ bool X86CPU::IsObjectAccessBreak(uint32 address, DbgModuleMemoryCache* memoryCac
*outObjectPtr = (uint64)regs[regNum];
return true;
return DbgBreakKind_ObjectAccess;
}
return false;
// check jno/jnb
for (int offset = 3; offset <= 3; offset++)
{
if (!Decode(address - offset, memoryCache, &inst))
continue;
if (inst.GetLength() != 2)
continue;
const MCInstrDesc& instDesc = mInstrInfo->get(inst.mMCInst.getOpcode());
if (!instDesc.isBranch())
continue;
auto immediateType = (instDesc.TSFlags & llvm::X86II::ImmMask);
if ((immediateType == llvm::X86II::Imm8PCRel) && (inst.mMCInst.getNumOperands() == 2))
{
auto immOp = inst.mMCInst.getOperand(1);
if (!immOp.isImm())
continue;
if ((immOp.getImm() != 1) && (immOp.getImm() != 3))
continue;
return DbgBreakKind_ArithmeticOverflow;
}
}
return DbgBreakKind_None;
}
int X86CPU::GetOpcodesForMnemonic(const StringImpl& mnemonic, Array<int>& outOpcodes)

View file

@ -344,7 +344,7 @@ public:
String InstructionToString(X86Instr* inst, uint32 addr);
void GetNextPC(uint32 baseAddress, const uint8* dataBase, int dataLength, const uint8* dataPtr, uint32* regs, uint32 nextPCs[2]);
bool IsObjectAccessBreak(uint32 address, DbgModuleMemoryCache* memoryCache, int32* regs, int32* outObjectPtr);
DbgBreakKind GetDbgBreakKind(uint32 address, DbgModuleMemoryCache* memoryCache, int32* regs, int32* outObjectPtr);
int GetOpcodesForMnemonic(const StringImpl& mnemonic, Array<int>& outOpcodes);
void GetClobbersForMnemonic(const StringImpl& mnemonic, int argCount, Array<int>& outImplicitClobberRegNums, int& outClobberArgCount, bool& outMayClobberMem);