Home | History | Annotate | Download | only in slang
      1 /*
      2  * Copyright 2010, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_OBJECT_REF_COUNT_H_  // NOLINT
     18 #define _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_OBJECT_REF_COUNT_H_
     19 
     20 #include <list>
     21 #include <stack>
     22 
     23 #include "clang/AST/StmtVisitor.h"
     24 
     25 #include "slang_assert.h"
     26 #include "slang_rs_export_type.h"
     27 
     28 namespace clang {
     29   class Expr;
     30   class Stmt;
     31 }
     32 
     33 namespace slang {
     34 
     35 // Recursive check
     36 bool HasRSObjectType(const clang::Type *T);
     37 
     38 // This class provides the overall reference counting mechanism for handling
     39 // local variables of RS object types (rs_font, rs_allocation, ...). This
     40 // class ensures that appropriate functions (rsSetObject, rsClearObject) are
     41 // called at proper points in the object's lifetime.
     42 // 1) Each local object of appropriate type must be zero-initialized to
     43 // prevent corruption during subsequent rsSetObject()/rsClearObject() calls.
     44 // 2) Assignments using these types must also be converted into the
     45 // appropriate (possibly a series of) rsSetObject() calls.
     46 // 3) Finally, rsClearObject() must be called for each local object when it goes
     47 // out of scope.
     48 class RSObjectRefCount : public clang::StmtVisitor<RSObjectRefCount> {
     49  private:
     50   class Scope {
     51    private:
     52     clang::CompoundStmt *mCS;         // Associated compound statement ({ ... })
     53     clang::Stmt *mCurrent;            // The statement currently being analyzed
     54     std::list<clang::VarDecl*> mRSO;  // Declared RS objects in this scope (but
     55                                       // not any scopes nested)
     56 
     57    public:
     58     explicit Scope(clang::CompoundStmt *CS) : mCS(CS) {
     59     }
     60 
     61     bool hasRSObject() const { return !mRSO.empty(); }
     62 
     63     inline void addRSObject(clang::VarDecl* VD) {
     64       mRSO.push_back(VD);
     65     }
     66 
     67     void ReplaceRSObjectAssignment(clang::BinaryOperator *AS);
     68 
     69     void AppendRSObjectInit(clang::VarDecl *VD,
     70                             clang::DeclStmt *DS,
     71                             DataType DT,
     72                             clang::Expr *InitExpr);
     73 
     74     // Inserts rsClearObject() calls at the end and at all exiting points of the
     75     // current scope. At each statement that exits the current scope -- e.g.,
     76     // a return, break, or continue statement in the current or a nested scope
     77     // -- rsClearObject() calls are inserted for local variables defined in the
     78     // current scope before that point.
     79     // Note goto statements are not handled. (See the DestructorVisitor class in
     80     // the .cpp file.)
     81     // Also note this function is called for every nested scope. As a result, for a
     82     // return statement, each rsObject declared in all its (nested) enclosing
     83     // scopes would have a rsClearObject() call properly inserted before
     84     // the return statement.
     85     void InsertLocalVarDestructors();
     86 
     87     // Sets the current statement being analyzed
     88     void setCurrentStmt(clang::Stmt *S) { mCurrent = S; }
     89 
     90     // Inserts a statement before the current statement
     91     void InsertStmt(const clang::ASTContext &C, clang::Stmt *NewStmt);
     92 
     93     // Replaces the current statement with NewStmt;
     94     void ReplaceStmt(const clang::ASTContext &C, clang::Stmt *NewStmt);
     95 
     96     // Replaces OldExpr with NewExpr in the current statement
     97     void ReplaceExpr(const clang::ASTContext& C, clang::Expr* OldExpr,
     98                      clang::Expr* NewExpr);
     99 
    100     static clang::Stmt *ClearRSObject(clang::VarDecl *VD,
    101                                       clang::DeclContext *DC);
    102   };
    103 
    104   clang::ASTContext &mCtx;
    105   std::deque<Scope*> mScopeStack;  // A deque used as a stack to store scopes, but also
    106                                    // accessed through its iterator in read-only mode.
    107   clang::DeclContext* mCurrentDC;
    108   bool RSInitFD;
    109   unsigned mTempID;  // A unique id that can be used to distinguish temporary variables
    110 
    111   // RSSetObjectFD and RSClearObjectFD holds FunctionDecl of rsSetObject()
    112   // and rsClearObject() in the current ASTContext.
    113   static clang::FunctionDecl *RSSetObjectFD[];
    114   static clang::FunctionDecl *RSClearObjectFD[];
    115 
    116   inline bool emptyScope() const { return mScopeStack.empty(); }
    117 
    118   inline Scope *getCurrentScope() {
    119     return mScopeStack.back();
    120   }
    121 
    122   // Returns the next available unique id for temporary variables
    123   unsigned getNextID() { return mTempID++; }
    124 
    125   // Initialize RSSetObjectFD and RSClearObjectFD.
    126   static void GetRSRefCountingFunctions(clang::ASTContext &C);
    127 
    128   // Return false if the type of variable declared in VD does not contain
    129   // an RS object type.
    130   static bool InitializeRSObject(clang::VarDecl *VD,
    131                                  DataType *DT,
    132                                  clang::Expr **InitExpr);
    133 
    134   // Return an empty list initializer expression at the appropriate location.
    135   // This construct can then be used to cheaply construct a zero-initializer
    136   // for any RenderScript objects (like rs_allocation) or rs_matrix* types
    137   // (possibly even embedded within other types). These types are expected to
    138   // be zero-initialized always, and so we can use this helper to ensure that
    139   // they at least have an empty initializer.
    140   static clang::Expr *CreateEmptyInitListExpr(
    141       clang::ASTContext &C,
    142       const clang::SourceLocation &Loc);
    143 
    144   // Given a return statement RS that returns an rsObject, creates a temporary
    145   // variable, and sets it to the original return expression using rsSetObject().
    146   // Creates a new return statement that returns the temporary variable.
    147   // Returns a new compound statement that contains the new variable declaration,
    148   // the rsSetOjbect() call, and the new return statement.
    149   static clang::CompoundStmt* CreateRetStmtWithTempVar(
    150       clang::ASTContext& C,
    151       clang::DeclContext* DC,
    152       clang::ReturnStmt* RS,
    153       const unsigned id);
    154 
    155  public:
    156   explicit RSObjectRefCount(clang::ASTContext &C)
    157       : mCtx(C), RSInitFD(false), mTempID(0) {
    158   }
    159 
    160   void Init() {
    161     if (!RSInitFD) {
    162       GetRSRefCountingFunctions(mCtx);
    163       RSInitFD = true;
    164     }
    165   }
    166 
    167   static clang::FunctionDecl *GetRSSetObjectFD(DataType DT) {
    168     slangAssert(RSExportPrimitiveType::IsRSObjectType(DT));
    169     if (DT >= 0 && DT < DataTypeMax) {
    170       return RSSetObjectFD[DT];
    171     } else {
    172       slangAssert(false && "incorrect type");
    173       return nullptr;
    174     }
    175   }
    176 
    177   static clang::FunctionDecl *GetRSSetObjectFD(const clang::Type *T) {
    178     return GetRSSetObjectFD(RSExportPrimitiveType::GetRSSpecificType(T));
    179   }
    180 
    181   static clang::FunctionDecl *GetRSClearObjectFD(DataType DT) {
    182     slangAssert(RSExportPrimitiveType::IsRSObjectType(DT));
    183     if (DT >= 0 && DT < DataTypeMax) {
    184       return RSClearObjectFD[DT];
    185     } else {
    186       slangAssert(false && "incorrect type");
    187       return nullptr;
    188     }
    189   }
    190 
    191   static clang::FunctionDecl *GetRSClearObjectFD(const clang::Type *T) {
    192     return GetRSClearObjectFD(RSExportPrimitiveType::GetRSSpecificType(T));
    193   }
    194 
    195   void SetDeclContext(clang::DeclContext* DC) { mCurrentDC = DC; }
    196   clang::DeclContext* GetDeclContext() const { return mCurrentDC; }
    197 
    198   void VisitStmt(clang::Stmt *S);
    199   void VisitCallExpr(clang::CallExpr *CE);
    200   void VisitDeclStmt(clang::DeclStmt *DS);
    201   void VisitCompoundStmt(clang::CompoundStmt *CS);
    202   void VisitBinAssign(clang::BinaryOperator *AS);
    203   void VisitReturnStmt(clang::ReturnStmt *RS);
    204   // We believe that RS objects are never involved in CompoundAssignOperator.
    205   // I.e., rs_allocation foo; foo += bar;
    206 
    207   // Emit a global destructor to clean up RS objects.
    208   clang::FunctionDecl *CreateStaticGlobalDtor();
    209 };
    210 
    211 }  // namespace slang
    212 
    213 #endif  // _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_OBJECT_REF_COUNT_H_  NOLINT
    214