mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-14 11:39:35 +00:00
Prototype (pre-alpha) implementation of CFRef checker.
llvm-svn: 48272
This commit is contained in:
parent
251084d03e
commit
68d73d19f1
@ -86,6 +86,10 @@ public:
|
||||
return (*Args)[idx];
|
||||
}
|
||||
|
||||
RetEffect getRet() const {
|
||||
return Ret;
|
||||
}
|
||||
|
||||
typedef ArgEffects::const_iterator arg_iterator;
|
||||
|
||||
arg_iterator begin_args() const { return Args->begin(); }
|
||||
@ -113,12 +117,24 @@ class CFRefSummaryManager {
|
||||
llvm::BumpPtrAllocator BPAlloc;
|
||||
|
||||
ArgEffects ScratchArgs;
|
||||
|
||||
|
||||
ArgEffects* getArgEffects();
|
||||
|
||||
CFRefSummary* getCannedCFSummary(FunctionTypeProto* FT, bool isRetain);
|
||||
|
||||
CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName);
|
||||
|
||||
CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT);
|
||||
CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT);
|
||||
|
||||
CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
|
||||
|
||||
public:
|
||||
CFRefSummaryManager() {}
|
||||
~CFRefSummaryManager();
|
||||
|
||||
CFRefSummary* getSummary(FunctionDecl* FD);
|
||||
CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
@ -137,7 +153,59 @@ CFRefSummaryManager::~CFRefSummaryManager() {
|
||||
I->getValue().~ArgEffects();
|
||||
}
|
||||
|
||||
CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD) {
|
||||
ArgEffects* CFRefSummaryManager::getArgEffects() {
|
||||
|
||||
assert (!ScratchArgs.empty());
|
||||
|
||||
llvm::FoldingSetNodeID profile;
|
||||
profile.Add(ScratchArgs);
|
||||
void* InsertPos;
|
||||
|
||||
llvm::FoldingSetNodeWrapper<ArgEffects>* E =
|
||||
AESet.FindNodeOrInsertPos(profile, InsertPos);
|
||||
|
||||
if (E) {
|
||||
ScratchArgs.clear();
|
||||
return &E->getValue();
|
||||
}
|
||||
|
||||
E = (llvm::FoldingSetNodeWrapper<ArgEffects>*)
|
||||
BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
|
||||
|
||||
new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
|
||||
AESet.InsertNode(E, InsertPos);
|
||||
|
||||
ScratchArgs.clear();
|
||||
return &E->getValue();
|
||||
}
|
||||
|
||||
CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE,
|
||||
RetEffect RE) {
|
||||
|
||||
llvm::FoldingSetNodeID profile;
|
||||
CFRefSummary::Profile(profile, AE, RE);
|
||||
void* InsertPos;
|
||||
|
||||
CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
|
||||
|
||||
if (Summ)
|
||||
return Summ;
|
||||
|
||||
Summ = (CFRefSummary*) BPAlloc.Allocate<CFRefSummary>();
|
||||
new (Summ) CFRefSummary(AE, RE);
|
||||
SummarySet.InsertNode(Summ, InsertPos);
|
||||
|
||||
return Summ;
|
||||
}
|
||||
|
||||
|
||||
CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD,
|
||||
ASTContext& Ctx) {
|
||||
|
||||
SourceLocation Loc = FD->getLocation();
|
||||
|
||||
if (!Loc.isFileID())
|
||||
return NULL;
|
||||
|
||||
{ // Look into our cache of summaries to see if we have already computed
|
||||
// a summary for this FunctionDecl.
|
||||
@ -148,12 +216,169 @@ CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD) {
|
||||
return I->second;
|
||||
}
|
||||
|
||||
//
|
||||
#if 0
|
||||
SourceManager& SrcMgr = Ctx.getSourceManager();
|
||||
unsigned fid = Loc.getFileID();
|
||||
const FileEntry* FE = SrcMgr.getFileEntryForID(fid);
|
||||
|
||||
if (!FE)
|
||||
return NULL;
|
||||
|
||||
const char* DirName = FE->getDir()->getName();
|
||||
assert (DirName);
|
||||
assert (strlen(DirName) > 0);
|
||||
|
||||
if (!strstr(DirName, "CoreFoundation")) {
|
||||
SummaryMap[FD] = NULL;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* FName = FD->getIdentifier()->getName();
|
||||
|
||||
if (FName[0] == 'C' && FName[1] == 'F') {
|
||||
CFRefSummary* S = getCFSummary(FD, FName);
|
||||
SummaryMap[FD] = S;
|
||||
return S;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD,
|
||||
const char* FName) {
|
||||
|
||||
// For now, only generate summaries for functions that have a prototype.
|
||||
|
||||
FunctionTypeProto* FT =
|
||||
dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
|
||||
|
||||
if (!FT)
|
||||
return NULL;
|
||||
|
||||
FName += 2;
|
||||
|
||||
if (strcmp(FName, "Retain") == 0)
|
||||
return getCannedCFSummary(FT, true);
|
||||
|
||||
if (strcmp(FName, "Release") == 0)
|
||||
return getCannedCFSummary(FT, false);
|
||||
|
||||
assert (ScratchArgs.empty());
|
||||
bool usesCreateRule = false;
|
||||
|
||||
if (strstr(FName, "Create"))
|
||||
usesCreateRule = true;
|
||||
|
||||
if (!usesCreateRule && strstr(FName, "Copy"))
|
||||
usesCreateRule = true;
|
||||
|
||||
if (usesCreateRule)
|
||||
return getCFSummaryCreateRule(FT);
|
||||
|
||||
if (strstr(FName, "Get"))
|
||||
return getCFSummaryGetRule(FT);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFRefSummary* CFRefSummaryManager::getCannedCFSummary(FunctionTypeProto* FT,
|
||||
bool isRetain) {
|
||||
|
||||
if (FT->getNumArgs() != 1)
|
||||
return NULL;
|
||||
|
||||
TypedefType* ArgT = dyn_cast<TypedefType>(FT->getArgType(0).getTypePtr());
|
||||
|
||||
if (!ArgT)
|
||||
return NULL;
|
||||
|
||||
// For CFRetain/CFRelease, the first (and only) argument is of type
|
||||
// "CFTypeRef".
|
||||
|
||||
const char* TDName = ArgT->getDecl()->getIdentifier()->getName();
|
||||
assert (TDName);
|
||||
|
||||
if (strcmp("CFTypeRef", TDName) == 0)
|
||||
return NULL;
|
||||
|
||||
if (!ArgT->isPointerType())
|
||||
return NULL;
|
||||
|
||||
// Check the return type. It should also be "CFTypeRef".
|
||||
|
||||
QualType RetTy = FT->getResultType();
|
||||
|
||||
if (RetTy.getTypePtr() != ArgT)
|
||||
return NULL;
|
||||
|
||||
// The function's interface checks out. Generate a canned summary.
|
||||
|
||||
assert (ScratchArgs.empty());
|
||||
ScratchArgs.push_back(isRetain ? IncRef : DecRef);
|
||||
|
||||
return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
|
||||
}
|
||||
|
||||
static bool isCFRefType(QualType T) {
|
||||
|
||||
if (!T->isPointerType())
|
||||
return false;
|
||||
|
||||
// Check the typedef for the name "CF" and the substring "Ref".
|
||||
|
||||
TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
|
||||
|
||||
if (!TD)
|
||||
return false;
|
||||
|
||||
const char* TDName = TD->getDecl()->getIdentifier()->getName();
|
||||
assert (TDName);
|
||||
|
||||
if (TDName[0] != 'C' || TDName[1] != 'F')
|
||||
return false;
|
||||
|
||||
if (strstr(TDName, "Ref") == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
CFRefSummary*
|
||||
CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) {
|
||||
|
||||
if (!isCFRefType(FT->getResultType()))
|
||||
return NULL;
|
||||
|
||||
assert (ScratchArgs.empty());
|
||||
|
||||
// FIXME: Add special-cases for functions that retain/release. For now
|
||||
// just handle the default case.
|
||||
|
||||
for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
|
||||
ScratchArgs.push_back(DoNothing);
|
||||
|
||||
return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
|
||||
}
|
||||
|
||||
CFRefSummary*
|
||||
CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) {
|
||||
|
||||
if (!isCFRefType(FT->getResultType()))
|
||||
return NULL;
|
||||
|
||||
assert (ScratchArgs.empty());
|
||||
|
||||
// FIXME: Add special-cases for functions that retain/release. For now
|
||||
// just handle the default case.
|
||||
|
||||
for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
|
||||
ScratchArgs.push_back(DoNothing);
|
||||
|
||||
return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -246,8 +471,8 @@ class CFRefCount : public GRSimpleVals {
|
||||
// Instance variables.
|
||||
|
||||
CFRefSummaryManager Summaries;
|
||||
RefBFactoryTy RefBFactory;
|
||||
|
||||
RefBFactoryTy RefBFactory;
|
||||
|
||||
UseAfterReleasesTy UseAfterReleases;
|
||||
ReleasesNotOwnedTy ReleasesNotOwned;
|
||||
|
||||
@ -282,9 +507,8 @@ public:
|
||||
// Calls.
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
ValueStateManager& StateMgr,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
BasicValueFactory& BasicVals,
|
||||
CallExpr* CE, LVal L,
|
||||
ExplodedNode<ValueState>* Pred);
|
||||
};
|
||||
@ -307,11 +531,12 @@ void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out,
|
||||
}
|
||||
|
||||
void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
ValueStateManager& StateMgr,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
BasicValueFactory& BasicVals,
|
||||
CallExpr* CE, LVal L,
|
||||
ExplodedNode<ValueState>* Pred) {
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
CallExpr* CE, LVal L,
|
||||
ExplodedNode<ValueState>* Pred) {
|
||||
|
||||
ValueStateManager& StateMgr = Engine.getStateManager();
|
||||
|
||||
// FIXME: Support calls to things other than lval::FuncVal. At the very
|
||||
// least we should stop tracking ref-state for ref-counted objects passed
|
||||
@ -323,7 +548,7 @@ void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
|
||||
lval::FuncVal FV = cast<lval::FuncVal>(L);
|
||||
FunctionDecl* FD = FV.getDecl();
|
||||
CFRefSummary* Summ = Summaries.getSummary(FD);
|
||||
CFRefSummary* Summ = Summaries.getSummary(FD, Engine.getContext());
|
||||
|
||||
// Get the state.
|
||||
|
||||
@ -355,35 +580,36 @@ void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
|
||||
if (isa<LVal>(V))
|
||||
StateMgr.Unbind(StVals, cast<LVal>(V));
|
||||
}
|
||||
}
|
||||
|
||||
St = StateMgr.getPersistentState(StVals);
|
||||
Builder.Nodify(Dst, CE, Pred, St);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
||||
// This function has a summary. Evaluate the effect of the arguments.
|
||||
|
||||
unsigned idx = 0;
|
||||
|
||||
for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
|
||||
I!=E; ++I, ++idx) {
|
||||
|
||||
// This function has a summary. Evaluate the effect of the arguments.
|
||||
RVal V = StateMgr.GetRVal(St, *I);
|
||||
|
||||
unsigned idx = 0;
|
||||
|
||||
for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
|
||||
I!=E; ++I, ++idx) {
|
||||
|
||||
RVal V = StateMgr.GetRVal(St, *I);
|
||||
|
||||
if (isa<lval::SymbolVal>(V)) {
|
||||
SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
|
||||
RefBindings B = GetRefBindings(StVals);
|
||||
if (isa<lval::SymbolVal>(V)) {
|
||||
SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
|
||||
RefBindings B = GetRefBindings(StVals);
|
||||
|
||||
if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
|
||||
B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
|
||||
SetRefBindings(StVals, B);
|
||||
if (hasError) break;
|
||||
}
|
||||
if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
|
||||
B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
|
||||
SetRefBindings(StVals, B);
|
||||
if (hasError) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
St = StateMgr.getPersistentState(StVals);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
St = StateMgr.getPersistentState(StVals);
|
||||
GRExprEngine::NodeTy* N = Builder.generateNode(CE, St, Pred);
|
||||
|
||||
if (N) {
|
||||
@ -399,10 +625,61 @@ void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
ReleasesNotOwned.insert(N);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
Builder.Nodify(Dst, CE, Pred, St);
|
||||
|
||||
// Finally, consult the summary for the return value.
|
||||
|
||||
RetEffect RE = Summ->getRet();
|
||||
St = StateMgr.getPersistentState(StVals);
|
||||
|
||||
|
||||
switch (RE.getKind()) {
|
||||
default:
|
||||
assert (false && "Unhandled RetEffect."); break;
|
||||
|
||||
case RetEffect::Alias: {
|
||||
unsigned idx = RE.getValue();
|
||||
assert (idx < CE->getNumArgs());
|
||||
RVal V = StateMgr.GetRVal(St, CE->getArg(idx));
|
||||
St = StateMgr.SetRVal(St, CE, V, Engine.getCFG().isBlkExpr(CE), false);
|
||||
break;
|
||||
}
|
||||
|
||||
case RetEffect::OwnedSymbol: {
|
||||
unsigned Count = Builder.getCurrentBlockCount();
|
||||
SymbolID Sym = Engine.getSymbolManager().getCallRetValSymbol(CE, Count);
|
||||
|
||||
ValueState StImpl = *St;
|
||||
RefBindings B = GetRefBindings(StImpl);
|
||||
SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned(1)));
|
||||
|
||||
St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
|
||||
CE, lval::SymbolVal(Sym),
|
||||
Engine.getCFG().isBlkExpr(CE), false);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case RetEffect::NotOwnedSymbol: {
|
||||
unsigned Count = Builder.getCurrentBlockCount();
|
||||
SymbolID Sym = Engine.getSymbolManager().getCallRetValSymbol(CE, Count);
|
||||
|
||||
ValueState StImpl = *St;
|
||||
RefBindings B = GetRefBindings(StImpl);
|
||||
SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
|
||||
|
||||
St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
|
||||
CE, lval::SymbolVal(Sym),
|
||||
Engine.getCFG().isBlkExpr(CE), false);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Builder.Nodify(Dst, CE, Pred, St);
|
||||
}
|
||||
|
||||
|
||||
@ -418,6 +695,12 @@ CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
|
||||
assert (false && "Unhandled CFRef transition.");
|
||||
|
||||
case DoNothing:
|
||||
if (V.getKind() == RefVal::Released) {
|
||||
V = RefVal::makeUseAfterRelease();
|
||||
hasError = V.getKind();
|
||||
break;
|
||||
}
|
||||
|
||||
return B;
|
||||
|
||||
case IncRef:
|
||||
|
@ -95,13 +95,13 @@ unsigned RunGRSimpleVals(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
|
||||
if (Diag.hasErrorOccurred())
|
||||
return 0;
|
||||
|
||||
GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
|
||||
GRExprEngine* CheckerState = &Engine.getCheckerState();
|
||||
GRCoreEngine<GRExprEngine> Eng(cfg, FD, Ctx);
|
||||
GRExprEngine* CheckerState = &Eng.getCheckerState();
|
||||
GRSimpleVals GRSV;
|
||||
CheckerState->setTransferFunctions(GRSV);
|
||||
|
||||
// Execute the worklist algorithm.
|
||||
Engine.ExecuteWorkList(50000);
|
||||
Eng.ExecuteWorkList(50000);
|
||||
|
||||
SourceManager& SrcMgr = Ctx.getSourceManager();
|
||||
|
||||
@ -144,7 +144,7 @@ unsigned RunGRSimpleVals(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
|
||||
if (Visualize) CheckerState->ViewGraph(TrimGraph);
|
||||
#endif
|
||||
|
||||
return Engine.getGraph().size();
|
||||
return Eng.getGraph().size();
|
||||
}
|
||||
|
||||
} // end clang namespace
|
||||
@ -153,14 +153,16 @@ unsigned RunGRSimpleVals(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
|
||||
// Transfer function for Casts.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
RVal GRSimpleVals::EvalCast(BasicValueFactory& BasicVals, NonLVal X, QualType T) {
|
||||
RVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLVal X, QualType T) {
|
||||
|
||||
if (!isa<nonlval::ConcreteInt>(X))
|
||||
return UnknownVal();
|
||||
|
||||
BasicValueFactory& BasicVals = Eng.getBasicVals();
|
||||
|
||||
llvm::APSInt V = cast<nonlval::ConcreteInt>(X).getValue();
|
||||
V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType());
|
||||
V.extOrTrunc(BasicVals.getContext().getTypeSize(T));
|
||||
V.extOrTrunc(Eng.getContext().getTypeSize(T));
|
||||
|
||||
if (T->isPointerType())
|
||||
return lval::ConcreteInt(BasicVals.getValue(V));
|
||||
@ -170,7 +172,7 @@ RVal GRSimpleVals::EvalCast(BasicValueFactory& BasicVals, NonLVal X, QualType T)
|
||||
|
||||
// Casts.
|
||||
|
||||
RVal GRSimpleVals::EvalCast(BasicValueFactory& BasicVals, LVal X, QualType T) {
|
||||
RVal GRSimpleVals::EvalCast(GRExprEngine& Eng, LVal X, QualType T) {
|
||||
|
||||
if (T->isPointerType() || T->isReferenceType())
|
||||
return X;
|
||||
@ -180,33 +182,35 @@ RVal GRSimpleVals::EvalCast(BasicValueFactory& BasicVals, LVal X, QualType T) {
|
||||
if (!isa<lval::ConcreteInt>(X))
|
||||
return UnknownVal();
|
||||
|
||||
BasicValueFactory& BasicVals = Eng.getBasicVals();
|
||||
|
||||
llvm::APSInt V = cast<lval::ConcreteInt>(X).getValue();
|
||||
V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType());
|
||||
V.extOrTrunc(BasicVals.getContext().getTypeSize(T));
|
||||
V.extOrTrunc(Eng.getContext().getTypeSize(T));
|
||||
|
||||
return nonlval::ConcreteInt(BasicVals.getValue(V));
|
||||
}
|
||||
|
||||
// Unary operators.
|
||||
|
||||
RVal GRSimpleVals::EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U, NonLVal X){
|
||||
RVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLVal X){
|
||||
|
||||
switch (X.getSubKind()) {
|
||||
|
||||
case nonlval::ConcreteIntKind:
|
||||
return cast<nonlval::ConcreteInt>(X).EvalMinus(BasicVals, U);
|
||||
return cast<nonlval::ConcreteInt>(X).EvalMinus(Eng.getBasicVals(), U);
|
||||
|
||||
default:
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
|
||||
RVal GRSimpleVals::EvalComplement(BasicValueFactory& BasicVals, NonLVal X) {
|
||||
RVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLVal X) {
|
||||
|
||||
switch (X.getSubKind()) {
|
||||
|
||||
case nonlval::ConcreteIntKind:
|
||||
return cast<nonlval::ConcreteInt>(X).EvalComplement(BasicVals);
|
||||
return cast<nonlval::ConcreteInt>(X).EvalComplement(Eng.getBasicVals());
|
||||
|
||||
default:
|
||||
return UnknownVal();
|
||||
@ -215,8 +219,11 @@ RVal GRSimpleVals::EvalComplement(BasicValueFactory& BasicVals, NonLVal X) {
|
||||
|
||||
// Binary operators.
|
||||
|
||||
RVal GRSimpleVals::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
|
||||
NonLVal L, NonLVal R) {
|
||||
RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
|
||||
NonLVal L, NonLVal R) {
|
||||
|
||||
BasicValueFactory& BasicVals = Eng.getBasicVals();
|
||||
|
||||
while (1) {
|
||||
|
||||
switch (L.getSubKind()) {
|
||||
@ -242,7 +249,7 @@ RVal GRSimpleVals::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcod
|
||||
if (isa<nonlval::ConcreteInt>(R)) {
|
||||
const SymIntConstraint& C =
|
||||
BasicVals.getConstraint(cast<nonlval::SymbolVal>(L).getSymbol(), Op,
|
||||
cast<nonlval::ConcreteInt>(R).getValue());
|
||||
cast<nonlval::ConcreteInt>(R).getValue());
|
||||
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
@ -256,7 +263,7 @@ RVal GRSimpleVals::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcod
|
||||
|
||||
// Binary Operators (except assignments and comma).
|
||||
|
||||
RVal GRSimpleVals::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
|
||||
RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
|
||||
LVal L, LVal R) {
|
||||
|
||||
switch (Op) {
|
||||
@ -265,23 +272,25 @@ RVal GRSimpleVals::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcod
|
||||
return UnknownVal();
|
||||
|
||||
case BinaryOperator::EQ:
|
||||
return EvalEQ(BasicVals, L, R);
|
||||
return EvalEQ(Eng, L, R);
|
||||
|
||||
case BinaryOperator::NE:
|
||||
return EvalNE(BasicVals, L, R);
|
||||
return EvalNE(Eng, L, R);
|
||||
}
|
||||
}
|
||||
|
||||
// Pointer arithmetic.
|
||||
|
||||
RVal GRSimpleVals::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
|
||||
RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
|
||||
LVal L, NonLVal R) {
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
// Equality operators for LVals.
|
||||
|
||||
RVal GRSimpleVals::EvalEQ(BasicValueFactory& BasicVals, LVal L, LVal R) {
|
||||
RVal GRSimpleVals::EvalEQ(GRExprEngine& Eng, LVal L, LVal R) {
|
||||
|
||||
BasicValueFactory& BasicVals = Eng.getBasicVals();
|
||||
|
||||
switch (L.getSubKind()) {
|
||||
|
||||
@ -337,8 +346,10 @@ RVal GRSimpleVals::EvalEQ(BasicValueFactory& BasicVals, LVal L, LVal R) {
|
||||
return NonLVal::MakeIntTruthVal(BasicVals, false);
|
||||
}
|
||||
|
||||
RVal GRSimpleVals::EvalNE(BasicValueFactory& BasicVals, LVal L, LVal R) {
|
||||
RVal GRSimpleVals::EvalNE(GRExprEngine& Eng, LVal L, LVal R) {
|
||||
|
||||
BasicValueFactory& BasicVals = Eng.getBasicVals();
|
||||
|
||||
switch (L.getSubKind()) {
|
||||
|
||||
default:
|
||||
@ -356,8 +367,8 @@ RVal GRSimpleVals::EvalNE(BasicValueFactory& BasicVals, LVal L, LVal R) {
|
||||
else if (isa<lval::SymbolVal>(R)) {
|
||||
const SymIntConstraint& C =
|
||||
BasicVals.getConstraint(cast<lval::SymbolVal>(R).getSymbol(),
|
||||
BinaryOperator::NE,
|
||||
cast<lval::ConcreteInt>(L).getValue());
|
||||
BinaryOperator::NE,
|
||||
cast<lval::ConcreteInt>(L).getValue());
|
||||
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
@ -368,8 +379,8 @@ RVal GRSimpleVals::EvalNE(BasicValueFactory& BasicVals, LVal L, LVal R) {
|
||||
if (isa<lval::ConcreteInt>(R)) {
|
||||
const SymIntConstraint& C =
|
||||
BasicVals.getConstraint(cast<lval::SymbolVal>(L).getSymbol(),
|
||||
BinaryOperator::NE,
|
||||
cast<lval::ConcreteInt>(R).getValue());
|
||||
BinaryOperator::NE,
|
||||
cast<lval::ConcreteInt>(R).getValue());
|
||||
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
@ -398,9 +409,8 @@ RVal GRSimpleVals::EvalNE(BasicValueFactory& BasicVals, LVal L, LVal R) {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void GRSimpleVals::EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
ValueStateManager& StateMgr,
|
||||
GRExprEngine& Eng,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
BasicValueFactory& BasicVals,
|
||||
CallExpr* CE, LVal L,
|
||||
ExplodedNode<ValueState>* Pred) {
|
||||
|
||||
@ -411,10 +421,10 @@ void GRSimpleVals::EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
|
||||
I != E; ++I) {
|
||||
|
||||
RVal V = StateMgr.GetRVal(St, *I);
|
||||
RVal V = Eng.getStateManager().GetRVal(St, *I);
|
||||
|
||||
if (isa<LVal>(V))
|
||||
St = StateMgr.SetRVal(St, cast<LVal>(V), UnknownVal());
|
||||
St = Eng.getStateManager().SetRVal(St, cast<LVal>(V), UnknownVal());
|
||||
}
|
||||
|
||||
Builder.Nodify(Dst, CE, Pred, St);
|
||||
|
@ -28,34 +28,33 @@ public:
|
||||
|
||||
// Casts.
|
||||
|
||||
virtual RVal EvalCast(BasicValueFactory& BasicVals, NonLVal V, QualType CastT);
|
||||
virtual RVal EvalCast(BasicValueFactory& BasicVals, LVal V, QualType CastT);
|
||||
virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT);
|
||||
virtual RVal EvalCast(GRExprEngine& Engine, LVal V, QualType CastT);
|
||||
|
||||
// Unary Operators.
|
||||
|
||||
virtual RVal EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U, NonLVal X);
|
||||
virtual RVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLVal X);
|
||||
|
||||
virtual RVal EvalComplement(BasicValueFactory& BasicVals, NonLVal X);
|
||||
virtual RVal EvalComplement(GRExprEngine& Engine, NonLVal X);
|
||||
|
||||
// Binary Operators.
|
||||
|
||||
virtual RVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
|
||||
virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
NonLVal L, NonLVal R);
|
||||
|
||||
virtual RVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
|
||||
virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
LVal L, LVal R);
|
||||
|
||||
// Pointer arithmetic.
|
||||
|
||||
virtual RVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
|
||||
virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
LVal L, NonLVal R);
|
||||
|
||||
// Calls.
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
ValueStateManager& StateMgr,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
BasicValueFactory& BasicVals,
|
||||
CallExpr* CE, LVal L,
|
||||
ExplodedNode<ValueState>* Pred);
|
||||
|
||||
@ -63,8 +62,8 @@ protected:
|
||||
|
||||
// Equality operators for LVals.
|
||||
|
||||
RVal EvalEQ(BasicValueFactory& BasicVals, LVal L, LVal R);
|
||||
RVal EvalNE(BasicValueFactory& BasicVals, LVal L, LVal R);
|
||||
RVal EvalEQ(GRExprEngine& Engine, LVal L, LVal R);
|
||||
RVal EvalNE(GRExprEngine& Engine, LVal L, LVal R);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
@ -20,30 +20,84 @@ SymbolID SymbolManager::getSymbol(VarDecl* D) {
|
||||
|
||||
assert (isa<ParmVarDecl>(D) || D->hasGlobalStorage());
|
||||
|
||||
SymbolID& X = DataToSymbol[getKey(D)];
|
||||
llvm::FoldingSetNodeID profile;
|
||||
|
||||
if (!X.isInitialized()) {
|
||||
X = SymbolToData.size();
|
||||
|
||||
if (ParmVarDecl* VD = dyn_cast<ParmVarDecl>(D))
|
||||
SymbolToData.push_back(SymbolDataParmVar(VD));
|
||||
else
|
||||
SymbolToData.push_back(SymbolDataGlobalVar(D));
|
||||
ParmVarDecl* PD = dyn_cast<ParmVarDecl>(D);
|
||||
|
||||
if (PD)
|
||||
SymbolDataParmVar::Profile(profile, PD);
|
||||
else
|
||||
SymbolDataGlobalVar::Profile(profile, D);
|
||||
|
||||
void* InsertPos;
|
||||
|
||||
SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
|
||||
|
||||
if (SD)
|
||||
return SD->getSymbol();
|
||||
|
||||
if (PD) {
|
||||
SD = (SymbolData*) BPAlloc.Allocate<SymbolDataParmVar>();
|
||||
new (SD) SymbolDataParmVar(SymbolCounter, PD);
|
||||
}
|
||||
else {
|
||||
SD = (SymbolData*) BPAlloc.Allocate<SymbolDataGlobalVar>();
|
||||
new (SD) SymbolDataGlobalVar(SymbolCounter, D);
|
||||
}
|
||||
|
||||
return X;
|
||||
DataSet.InsertNode(SD, InsertPos);
|
||||
|
||||
DataMap[SymbolCounter] = SD;
|
||||
return SymbolCounter++;
|
||||
}
|
||||
|
||||
SymbolID SymbolManager::getContentsOfSymbol(SymbolID sym) {
|
||||
SymbolID& X = DataToSymbol[getKey(sym)];
|
||||
|
||||
if (!X.isInitialized()) {
|
||||
X = SymbolToData.size();
|
||||
SymbolToData.push_back(SymbolDataContentsOf(sym));
|
||||
}
|
||||
llvm::FoldingSetNodeID profile;
|
||||
SymbolDataContentsOf::Profile(profile, sym);
|
||||
void* InsertPos;
|
||||
|
||||
return X;
|
||||
SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
|
||||
|
||||
if (SD)
|
||||
return SD->getSymbol();
|
||||
|
||||
SD = (SymbolData*) BPAlloc.Allocate<SymbolDataContentsOf>();
|
||||
new (SD) SymbolDataContentsOf(SymbolCounter, sym);
|
||||
|
||||
|
||||
DataSet.InsertNode(SD, InsertPos);
|
||||
DataMap[SymbolCounter] = SD;
|
||||
|
||||
return SymbolCounter++;
|
||||
}
|
||||
|
||||
SymbolID SymbolManager::getCallRetValSymbol(CallExpr* CE, unsigned Count) {
|
||||
|
||||
llvm::FoldingSetNodeID profile;
|
||||
SymbolDataCallRetVal::Profile(profile, CE, Count);
|
||||
void* InsertPos;
|
||||
|
||||
SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
|
||||
|
||||
if (SD)
|
||||
return SD->getSymbol();
|
||||
|
||||
SD = (SymbolData*) BPAlloc.Allocate<SymbolDataCallRetVal>();
|
||||
new (SD) SymbolDataCallRetVal(SymbolCounter, CE, Count);
|
||||
|
||||
DataSet.InsertNode(SD, InsertPos);
|
||||
DataMap[SymbolCounter] = SD;
|
||||
|
||||
return SymbolCounter++;
|
||||
}
|
||||
|
||||
const SymbolData& SymbolManager::getSymbolData(SymbolID Sym) const {
|
||||
DataMapTy::const_iterator I = DataMap.find(Sym);
|
||||
assert (I != DataMap.end());
|
||||
return *I->second;
|
||||
}
|
||||
|
||||
|
||||
QualType SymbolData::getType(const SymbolManager& SymMgr) const {
|
||||
switch (getKind()) {
|
||||
@ -57,12 +111,14 @@ QualType SymbolData::getType(const SymbolManager& SymMgr) const {
|
||||
return cast<SymbolDataGlobalVar>(this)->getDecl()->getType();
|
||||
|
||||
case ContentsOfKind: {
|
||||
SymbolID x = cast<SymbolDataContentsOf>(this)->getSymbol();
|
||||
SymbolID x = cast<SymbolDataContentsOf>(this)->getContainerSymbol();
|
||||
QualType T = SymMgr.getSymbolData(x).getType(SymMgr);
|
||||
return T->getAsPointerType()->getPointeeType();
|
||||
}
|
||||
|
||||
case CallRetValKind:
|
||||
return cast<SymbolDataCallRetVal>(this)->getCallExpr()->getType();
|
||||
}
|
||||
}
|
||||
|
||||
SymbolManager::SymbolManager() {}
|
||||
SymbolManager::~SymbolManager() {}
|
||||
|
@ -143,6 +143,12 @@ public:
|
||||
return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL;
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return getBlockCounter().getNumVisited(B.getBlockID());
|
||||
}
|
||||
|
||||
ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State,
|
||||
ExplodedNodeImpl* Pred);
|
||||
|
||||
@ -182,6 +188,14 @@ public:
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St));
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return NB.getBlockCounter();
|
||||
}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return NB.getCurrentBlockCount();
|
||||
}
|
||||
|
||||
StateTy* GetState(NodeTy* Pred) const {
|
||||
if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor())
|
||||
return CleanedState;
|
||||
|
@ -263,6 +263,16 @@ public:
|
||||
/// nodes by processing the 'effects' of a switch statement.
|
||||
void ProcessSwitch(SwitchNodeBuilder& builder);
|
||||
|
||||
|
||||
ValueStateManager& getStateManager() { return StateMgr; }
|
||||
const ValueStateManager& getStateManger() const { return StateMgr; }
|
||||
|
||||
BasicValueFactory& getBasicVals() { return BasicVals; }
|
||||
const BasicValueFactory& getBasicVals() const { return BasicVals; }
|
||||
|
||||
SymbolManager& getSymbolManager() { return SymMgr; }
|
||||
const SymbolManager& getSymbolManager() const { return SymMgr; }
|
||||
|
||||
protected:
|
||||
|
||||
ValueState* GetState(NodeTy* N) {
|
||||
@ -394,25 +404,25 @@ protected:
|
||||
return X;
|
||||
|
||||
if (isa<LVal>(X))
|
||||
return TF->EvalCast(BasicVals, cast<LVal>(X), CastT);
|
||||
return TF->EvalCast(*this, cast<LVal>(X), CastT);
|
||||
else
|
||||
return TF->EvalCast(BasicVals, cast<NonLVal>(X), CastT);
|
||||
return TF->EvalCast(*this, cast<NonLVal>(X), CastT);
|
||||
}
|
||||
|
||||
RVal EvalMinus(UnaryOperator* U, RVal X) {
|
||||
return X.isValid() ? TF->EvalMinus(BasicVals, U, cast<NonLVal>(X)) : X;
|
||||
return X.isValid() ? TF->EvalMinus(*this, U, cast<NonLVal>(X)) : X;
|
||||
}
|
||||
|
||||
RVal EvalComplement(RVal X) {
|
||||
return X.isValid() ? TF->EvalComplement(BasicVals, cast<NonLVal>(X)) : X;
|
||||
return X.isValid() ? TF->EvalComplement(*this, cast<NonLVal>(X)) : X;
|
||||
}
|
||||
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, NonLVal L, RVal R) {
|
||||
return R.isValid() ? TF->EvalBinOp(BasicVals, Op, L, cast<NonLVal>(R)) : R;
|
||||
return R.isValid() ? TF->EvalBinOp(*this, Op, L, cast<NonLVal>(R)) : R;
|
||||
}
|
||||
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, NonLVal L, NonLVal R) {
|
||||
return R.isValid() ? TF->EvalBinOp(BasicVals, Op, L, R) : R;
|
||||
return R.isValid() ? TF->EvalBinOp(*this, Op, L, R) : R;
|
||||
}
|
||||
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, RVal L, RVal R) {
|
||||
@ -425,9 +435,9 @@ protected:
|
||||
|
||||
if (isa<LVal>(L)) {
|
||||
if (isa<LVal>(R))
|
||||
return TF->EvalBinOp(BasicVals, Op, cast<LVal>(L), cast<LVal>(R));
|
||||
return TF->EvalBinOp(*this, Op, cast<LVal>(L), cast<LVal>(R));
|
||||
else
|
||||
return TF->EvalBinOp(BasicVals, Op, cast<LVal>(L), cast<NonLVal>(R));
|
||||
return TF->EvalBinOp(*this, Op, cast<LVal>(L), cast<NonLVal>(R));
|
||||
}
|
||||
|
||||
if (isa<LVal>(R)) {
|
||||
@ -437,15 +447,15 @@ protected:
|
||||
assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub);
|
||||
|
||||
// Commute the operands.
|
||||
return TF->EvalBinOp(BasicVals, Op, cast<LVal>(R), cast<NonLVal>(L));
|
||||
return TF->EvalBinOp(*this, Op, cast<LVal>(R), cast<NonLVal>(L));
|
||||
}
|
||||
else
|
||||
return TF->EvalBinOp(BasicVals, Op, cast<NonLVal>(L), cast<NonLVal>(R));
|
||||
return TF->EvalBinOp(*this, Op, cast<NonLVal>(L), cast<NonLVal>(R));
|
||||
}
|
||||
|
||||
void EvalCall(NodeSet& Dst, CallExpr* CE, LVal L, NodeTy* Pred) {
|
||||
assert (Builder && "GRStmtNodeBuilder must be defined.");
|
||||
return TF->EvalCall(Dst, StateMgr, *Builder, BasicVals, CE, L, Pred);
|
||||
return TF->EvalCall(Dst, *this, *Builder, CE, L, Pred);
|
||||
}
|
||||
|
||||
ValueState* MarkBranch(ValueState* St, Stmt* Terminator, bool branchTaken);
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRExprEngine;
|
||||
|
||||
class GRTransferFuncs {
|
||||
public:
|
||||
GRTransferFuncs() {}
|
||||
@ -32,38 +34,34 @@ public:
|
||||
|
||||
// Casts.
|
||||
|
||||
virtual RVal EvalCast(BasicValueFactory& BasicVals, NonLVal V,
|
||||
QualType CastT) =0;
|
||||
|
||||
virtual RVal EvalCast(BasicValueFactory& BasicVals, LVal V,
|
||||
QualType CastT) = 0;
|
||||
virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT) =0;
|
||||
virtual RVal EvalCast(GRExprEngine& Engine, LVal V, QualType CastT) = 0;
|
||||
|
||||
// Unary Operators.
|
||||
|
||||
virtual RVal EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U,
|
||||
NonLVal X) = 0;
|
||||
virtual RVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLVal X) = 0;
|
||||
|
||||
virtual RVal EvalComplement(BasicValueFactory& BasicVals, NonLVal X) = 0;
|
||||
virtual RVal EvalComplement(GRExprEngine& Engine, NonLVal X) = 0;
|
||||
|
||||
// Binary Operators.
|
||||
|
||||
virtual RVal EvalBinOp(BasicValueFactory& BasicVals,
|
||||
BinaryOperator::Opcode Op, NonLVal L, NonLVal R) = 0;
|
||||
virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
NonLVal L, NonLVal R) = 0;
|
||||
|
||||
virtual RVal EvalBinOp(BasicValueFactory& BasicVals,
|
||||
BinaryOperator::Opcode Op, LVal L, LVal R) = 0;
|
||||
virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
LVal L, LVal R) = 0;
|
||||
|
||||
// Pointer arithmetic.
|
||||
|
||||
virtual RVal EvalBinOp(BasicValueFactory& BasicVals,
|
||||
BinaryOperator::Opcode Op, LVal L, NonLVal R) = 0;
|
||||
virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
LVal L, NonLVal R) = 0;
|
||||
|
||||
// Calls.
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
ValueStateManager& StateMgr,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
BasicValueFactory& BasicVals, CallExpr* CE, LVal L,
|
||||
CallExpr* CE, LVal L,
|
||||
ExplodedNode<ValueState>* Pred) = 0;
|
||||
};
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <vector>
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
@ -28,15 +28,14 @@ class SymbolManager;
|
||||
|
||||
class SymbolID {
|
||||
unsigned Data;
|
||||
|
||||
public:
|
||||
SymbolID() : Data(~0) {}
|
||||
SymbolID(unsigned x) : Data(x) {}
|
||||
|
||||
bool isInitialized() const { return Data != (unsigned) ~0; }
|
||||
operator unsigned() const { assert (isInitialized()); return Data; }
|
||||
operator unsigned() const { return Data; }
|
||||
unsigned getNumber() const { return Data; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
assert (isInitialized());
|
||||
ID.AddInteger(Data);
|
||||
}
|
||||
|
||||
@ -44,51 +43,74 @@ public:
|
||||
X.Profile(ID);
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
namespace llvm {
|
||||
template <> struct DenseMapInfo<clang::SymbolID> {
|
||||
static inline clang::SymbolID getEmptyKey() {
|
||||
return clang::SymbolID(~0U);
|
||||
}
|
||||
static inline clang::SymbolID getTombstoneKey() {
|
||||
return clang::SymbolID(~0U - 1);
|
||||
}
|
||||
static unsigned getHashValue(clang::SymbolID X) {
|
||||
return X.getNumber();
|
||||
}
|
||||
static bool isEqual(clang::SymbolID X, clang::SymbolID Y) {
|
||||
return X.getNumber() == Y.getNumber();
|
||||
}
|
||||
static bool isPod() { return true; }
|
||||
};
|
||||
}
|
||||
|
||||
// SymbolData: Used to record meta data about symbols.
|
||||
|
||||
class SymbolData {
|
||||
namespace clang {
|
||||
|
||||
class SymbolData : public llvm::FoldingSetNode {
|
||||
public:
|
||||
enum Kind { UndefKind, ParmKind, GlobalKind, ContentsOfKind };
|
||||
enum Kind { UndefKind, ParmKind, GlobalKind, ContentsOfKind, CallRetValKind };
|
||||
|
||||
private:
|
||||
uintptr_t Data;
|
||||
Kind K;
|
||||
SymbolID Sym;
|
||||
|
||||
protected:
|
||||
SymbolData(uintptr_t D, Kind k) : Data(D), K(k) {}
|
||||
SymbolData(void* D, Kind k) : Data(reinterpret_cast<uintptr_t>(D)), K(k) {}
|
||||
|
||||
void* getPtr() const {
|
||||
assert (K != UndefKind);
|
||||
return reinterpret_cast<void*>(Data);
|
||||
}
|
||||
|
||||
uintptr_t getInt() const {
|
||||
assert (K != UndefKind);
|
||||
return Data;
|
||||
}
|
||||
|
||||
SymbolData(Kind k, SymbolID sym) : K(k), Sym(sym) {}
|
||||
|
||||
public:
|
||||
SymbolData() : Data(0), K(UndefKind) {}
|
||||
virtual ~SymbolData() {}
|
||||
|
||||
Kind getKind() const { return K; }
|
||||
|
||||
inline bool operator==(const SymbolData& R) const {
|
||||
return K == R.K && Data == R.Data;
|
||||
}
|
||||
Kind getKind() const { return K; }
|
||||
|
||||
SymbolID getSymbol() const { return Sym; }
|
||||
|
||||
QualType getType(const SymbolManager& SymMgr) const;
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymbolData*) { return true; }
|
||||
};
|
||||
|
||||
class SymbolDataParmVar : public SymbolData {
|
||||
public:
|
||||
SymbolDataParmVar(ParmVarDecl* VD) : SymbolData(VD, ParmKind) {}
|
||||
ParmVarDecl *VD;
|
||||
|
||||
public:
|
||||
SymbolDataParmVar(SymbolID MySym, ParmVarDecl* vd)
|
||||
: SymbolData(ParmKind, MySym), VD(vd) {}
|
||||
|
||||
ParmVarDecl* getDecl() const { return (ParmVarDecl*) getPtr(); }
|
||||
ParmVarDecl* getDecl() const { return VD; }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& profile, ParmVarDecl* VD) {
|
||||
profile.AddInteger((unsigned) ParmKind);
|
||||
profile.AddPointer(VD);
|
||||
}
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& profile) {
|
||||
Profile(profile, VD);
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymbolData* D) {
|
||||
@ -97,10 +119,22 @@ public:
|
||||
};
|
||||
|
||||
class SymbolDataGlobalVar : public SymbolData {
|
||||
VarDecl *VD;
|
||||
|
||||
public:
|
||||
SymbolDataGlobalVar(VarDecl* VD) : SymbolData(VD, GlobalKind) {}
|
||||
SymbolDataGlobalVar(SymbolID MySym, VarDecl* vd) :
|
||||
SymbolData(GlobalKind, MySym), VD(vd) {}
|
||||
|
||||
VarDecl* getDecl() const { return (VarDecl*) getPtr(); }
|
||||
VarDecl* getDecl() const { return VD; }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& profile, VarDecl* VD) {
|
||||
profile.AddInteger((unsigned) GlobalKind);
|
||||
profile.AddPointer(VD);
|
||||
}
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& profile) {
|
||||
Profile(profile, VD);
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymbolData* D) {
|
||||
@ -109,16 +143,57 @@ public:
|
||||
};
|
||||
|
||||
class SymbolDataContentsOf : public SymbolData {
|
||||
SymbolID Sym;
|
||||
|
||||
public:
|
||||
SymbolDataContentsOf(SymbolID ID) : SymbolData(ID, ContentsOfKind) {}
|
||||
SymbolDataContentsOf(SymbolID MySym, SymbolID sym) :
|
||||
SymbolData(ContentsOfKind, MySym), Sym(sym) {}
|
||||
|
||||
SymbolID getSymbol() const { return (SymbolID) getInt(); }
|
||||
SymbolID getContainerSymbol() const { return Sym; }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& profile, SymbolID Sym) {
|
||||
profile.AddInteger((unsigned) ContentsOfKind);
|
||||
profile.AddInteger(Sym);
|
||||
}
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& profile) {
|
||||
Profile(profile, Sym);
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymbolData* D) {
|
||||
return D->getKind() == ContentsOfKind;
|
||||
}
|
||||
};
|
||||
|
||||
class SymbolDataCallRetVal : public SymbolData {
|
||||
CallExpr* CE;
|
||||
unsigned Count;
|
||||
|
||||
public:
|
||||
SymbolDataCallRetVal(SymbolID Sym, CallExpr* ce, unsigned count)
|
||||
: SymbolData(CallRetValKind, Sym), CE(ce), Count(count) {}
|
||||
|
||||
CallExpr* getCallExpr() const { return CE; }
|
||||
unsigned getCount() const { return Count; }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& profile,
|
||||
CallExpr* CE, unsigned Count) {
|
||||
|
||||
profile.AddInteger((unsigned) CallRetValKind);
|
||||
profile.AddPointer(CE);
|
||||
profile.AddInteger(Count);
|
||||
}
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& profile) {
|
||||
Profile(profile, CE, Count);
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymbolData* D) {
|
||||
return D->getKind() == CallRetValKind;
|
||||
}
|
||||
};
|
||||
|
||||
// Constraints on symbols. Usually wrapped by RValues.
|
||||
|
||||
@ -133,7 +208,7 @@ public:
|
||||
Op(op), Val(V) {}
|
||||
|
||||
BinaryOperator::Opcode getOpcode() const { return Op; }
|
||||
const SymbolID& getSymbol() const { return Symbol; }
|
||||
SymbolID getSymbol() const { return Symbol; }
|
||||
const llvm::APSInt& getInt() const { return Val; }
|
||||
|
||||
static inline void Profile(llvm::FoldingSetNodeID& ID,
|
||||
@ -152,32 +227,28 @@ public:
|
||||
|
||||
|
||||
class SymbolManager {
|
||||
std::vector<SymbolData> SymbolToData;
|
||||
typedef llvm::FoldingSet<SymbolData> DataSetTy;
|
||||
typedef llvm::DenseMap<SymbolID, SymbolData*> DataMapTy;
|
||||
|
||||
typedef llvm::DenseMap<void*,SymbolID> MapTy;
|
||||
MapTy DataToSymbol;
|
||||
DataSetTy DataSet;
|
||||
DataMapTy DataMap;
|
||||
|
||||
void* getKey(void* P) const {
|
||||
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(P) | 0x1);
|
||||
}
|
||||
|
||||
void* getKey(SymbolID sym) const {
|
||||
return reinterpret_cast<void*>((uintptr_t) (sym << 1));
|
||||
}
|
||||
unsigned SymbolCounter;
|
||||
llvm::BumpPtrAllocator& BPAlloc;
|
||||
|
||||
public:
|
||||
SymbolManager();
|
||||
SymbolManager(llvm::BumpPtrAllocator& bpalloc)
|
||||
: SymbolCounter(0), BPAlloc(bpalloc) {}
|
||||
|
||||
~SymbolManager();
|
||||
|
||||
SymbolID getSymbol(VarDecl* D);
|
||||
SymbolID getContentsOfSymbol(SymbolID sym);
|
||||
SymbolID getCallRetValSymbol(CallExpr* CE, unsigned VisitCount);
|
||||
|
||||
inline const SymbolData& getSymbolData(SymbolID ID) const {
|
||||
assert (ID < SymbolToData.size());
|
||||
return SymbolToData[ID];
|
||||
}
|
||||
const SymbolData& getSymbolData(SymbolID ID) const;
|
||||
|
||||
inline QualType getType(SymbolID ID) const {
|
||||
QualType getType(SymbolID ID) const {
|
||||
return getSymbolData(ID).getType(*this);
|
||||
}
|
||||
};
|
||||
|
@ -214,6 +214,7 @@ public:
|
||||
CNEFactory(alloc),
|
||||
CEFactory(alloc),
|
||||
BasicVals(Ctx, alloc),
|
||||
SymMgr(alloc),
|
||||
Alloc(alloc) {}
|
||||
|
||||
ValueState* getInitialState();
|
||||
|
Loading…
Reference in New Issue
Block a user