]> granicus.if.org Git - clang/commitdiff
[analyzer] Always inline functions with bodies generated by BodyFarm.
authorAnna Zaks <ganna@apple.com>
Sat, 2 Feb 2013 00:30:04 +0000 (00:30 +0000)
committerAnna Zaks <ganna@apple.com>
Sat, 2 Feb 2013 00:30:04 +0000 (00:30 +0000)
Inlining these functions is essential for correctness. We often have
cases where we do not inline calls. For example, the shallow mode and
when reanalyzing previously inlined ObjC methods as top level.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174245 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/AnalysisContext.h
lib/Analysis/AnalysisDeclContext.cpp
lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
test/Analysis/NSString.m

index 168fc003dc3ba092efc2b6fe8e2cff9381ab3cb8..062af1bad13da3c5d106a0505d12508c235e90b3 100644 (file)
@@ -133,7 +133,21 @@ public:
   void registerForcedBlockExpression(const Stmt *stmt);
   const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt);
 
+  /// \brief Get the body of the Declaration.
   Stmt *getBody() const;
+
+  /// \brief Get the body of the Declaration.
+  /// \param IsAutosynthesized Output parameter that specifies if the body is
+  /// auto-generated by the BodyFarm.
+  Stmt *getBody(bool &IsAutosynthesized) const;
+
+  /// \brief Checks if the body of the Decl is generated by the BodyFarm.
+  ///
+  /// Note, the lookup is not free. We are going to call getBody behind
+  /// the sceines.
+  /// \sa getBody
+  bool isBodyAutosynthesized() const;
+
   CFG *getCFG();
 
   CFGStmtMap *getCFGStmtMap();
index bcaad9b0db52bca4e2111a2e4c834639de6e05e0..20cc3d55f3e37b60ae472771d951d357239b0fe5 100644 (file)
@@ -86,11 +86,13 @@ static BodyFarm &getBodyFarm(ASTContext &C) {
   return *BF;
 }
 
-Stmt *AnalysisDeclContext::getBody() const {
+Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     Stmt *Body = FD->getBody();
-    if (!Body && Manager && Manager->synthesizeBodies())
+    if (!Body && Manager && Manager->synthesizeBodies()) {
+      IsAutosynthesized = true;
       return getBodyFarm(getASTContext()).getBody(FD);
+    }
     return Body;
   }
   else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
@@ -104,6 +106,17 @@ Stmt *AnalysisDeclContext::getBody() const {
   llvm_unreachable("unknown code decl");
 }
 
+Stmt *AnalysisDeclContext::getBody() const {
+  bool Tmp;
+  return getBody(Tmp);
+}
+
+bool AnalysisDeclContext::isBodyAutosynthesized() const {
+  bool Tmp;
+  getBody(Tmp);
+  return Tmp;
+}
+
 const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
   if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
     return MD->getSelfDecl();
index 2c1f6c1d8f9faf5da0294d4ed34a7e105ba75cdd..1d006b09ccbc2f63942115cfcb5947a96088e59a 100644 (file)
@@ -733,13 +733,27 @@ void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
   Bldr.generateNode(Call.getProgramPoint(), State, Pred);
 }
 
+static bool isEssentialToInline(const CallEvent &Call) {
+  const Decl *D = Call.getDecl();
+  if (D) {
+    AnalysisDeclContext *AD =
+      Call.getLocationContext()->getAnalysisDeclContext()->
+      getManager()->getContext(D);
+
+    // The auto-synthesized bodies are essential to inline as they are
+    // usually small and commonly used.
+    return AD->isBodyAutosynthesized();
+  }
+  return false;
+}
+
 void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
                                  const CallEvent &CallTemplate) {
   // Make sure we have the most recent state attached to the call.
   ProgramStateRef State = Pred->getState();
   CallEventRef<> Call = CallTemplate.cloneWithState(State);
 
-  if (HowToInline == Inline_None) {
+  if (HowToInline == Inline_None && !isEssentialToInline(CallTemplate)) {
     conservativeEvalCall(*Call, Bldr, Pred, State);
     return;
   }
index 9339069f4c4feea5c7c9b463ddac3cbffa0f1db2..e7ac730c72e10179e67f8f5d1f1af8d67f7370b4 100644 (file)
@@ -404,3 +404,27 @@ void testOSCompareAndSwapXXBarrier_parameter_no_direct_release(NSString **old) {
   else    
     return;
 }
+
+@interface AlwaysInlineBodyFarmBodies : NSObject {
+  NSString *_value;
+}
+  - (NSString *)_value;
+  - (void)callValue;
+@end
+
+@implementation AlwaysInlineBodyFarmBodies
+
+- (NSString *)_value {
+  if (!_value) {
+    NSString *s = [[NSString alloc] init];
+    if (!OSAtomicCompareAndSwapPtr(0, s, (void**)&_value)) {
+      [s release];
+    }
+  }
+  return _value;
+}
+
+- (void)callValue {
+  [self _value];
+}
+@end
\ No newline at end of file