1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 20:42: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

@ -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

@ -117,7 +117,8 @@ public:
bool mAllowHotSwapping;
bool mObjectHasDebugFlags;
bool mEnableRealtimeLeakCheck;
bool mEmitObjectAccessCheck; // Only valid with mObjectHasDebugFlags
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

@ -19769,7 +19769,7 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
bool wantsChecks = checkedKind == BfCheckedKind_Checked;
if (checkedKind == BfCheckedKind_NotSet)
wantsChecks = mModule->GetDefaultCheckedKind() == BfCheckedKind_Checked;
wantsChecks = mModule->GetDefaultCheckedKind() == BfCheckedKind_Checked;
//target.mType = mModule->ResolveGenericType(target.mType);
if (target.mType->IsVar())
@ -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;
}
@ -5394,7 +5415,7 @@ void BfIRBuilder::CreateStatementStart()
}
void BfIRBuilder::CreateObjectAccessCheck(BfIRValue value, bool useAsm)
{
{
auto retBlock = WriteCmd(BfIRCmd_ObjectAccessCheck, value, useAsm);
NEW_CMD_INSERTED_IRBLOCK;
if (!mIgnoreWrites)

View file

@ -174,7 +174,7 @@ enum BfIRCmd : uint8
BfIRCmd_SetName,
BfIRCmd_CreateUndefValue,
BfIRCmd_NumericCast,
BfIRCmd_NumericCast,
BfIRCmd_CmpEQ,
BfIRCmd_CmpNE,
BfIRCmd_CmpSLT,
@ -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,22 +2112,31 @@ 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));
SetResult(curId, mIRBuilder->CreateAdd(lhs, rhs));
}
break;
case BfIRCmd_Sub:
{
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));
}
@ -2528,7 +2613,12 @@ void BfIRCodeGen::HandleNextCmd()
intoInstList.splice(intoInstList.begin(), fromInstList, fromInstList.begin(), fromInstList.end());
fromBlock->eraseFromParent();
}
break;
break;
case BfIRCmd_GetInsertBlock:
{
SetResult(curId, mIRBuilder->GetInsertBlock());
}
break;
case BfIRCmd_SetInsertPoint:
{
CMD_PARAM(llvm::BasicBlock*, block);
@ -2542,7 +2632,7 @@ void BfIRCodeGen::HandleNextCmd()
CMD_PARAM(llvm::BasicBlock*, block);
mIRBuilder->SetInsertPoint(block, block->begin());
}
break;
break;
case BfIRCmd_EraseFromParent:
{
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

@ -20,7 +20,7 @@ namespace llvm
class AttributeList;
class Module;
class LLVMContext;
class TargetMachine;
class TargetMachine;
};
NS_BF_BEGIN
@ -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
};