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 #include <vector>
     23 
     24 #include "clang/AST/StmtVisitor.h"
     25 
     26 #include "slang_assert.h"
     27 #include "slang_rs_export_type.h"
     28 
     29 namespace clang {
     30   class Expr;
     31   class Stmt;
     32 }
     33 
     34 namespace slang {
     35 
     36 // Recursive check
     37 bool HasRSObjectType(const clang::Type *T);
     38 
     39 // This class provides the overall reference counting mechanism for handling
     40 // local variables of RS object types (rs_font, rs_allocation, ...). This
     41 // class ensures that appropriate functions (rsSetObject, rsClearObject) are
     42 // called at proper points in the object's lifetime.
     43 // 1) Each local object of appropriate type must be zero-initialized to
     44 // prevent corruption during subsequent rsSetObject()/rsClearObject() calls.
     45 // 2) Assignments using these types must also be converted into the
     46 // appropriate (possibly a series of) rsSetObject() calls.
     47 // 3) Finally, rsClearObject() must be called for each local object when it goes
     48 // out of scope.
     49 class RSObjectRefCount : public clang::StmtVisitor<RSObjectRefCount> {
     50  private:
     51   class Scope {
     52    private:
     53     clang::CompoundStmt *mCS;         // Associated compound statement ({ ... })
     54     clang::Stmt *mCurrent;            // The statement currently being analyzed
     55     std::list<clang::VarDecl*> mRSO;  // Declared RS objects in this scope (but
     56                                       // not any scopes nested)
     57 
     58    public:
     59     explicit Scope(clang::CompoundStmt *CS) : mCS(CS) {
     60     }
     61 
     62     bool hasRSObject() const { return !mRSO.empty(); }
     63 
     64     inline void addRSObject(clang::VarDecl* VD) {
     65       mRSO.push_back(VD);
     66     }
     67 
     68     void ReplaceRSObjectAssignment(clang::BinaryOperator *AS);
     69 
     70     void AppendRSObjectInit(clang::VarDecl *VD,
     71                             clang::DeclStmt *DS,
     72                             DataType DT,
     73                             clang::Expr *InitExpr);
     74 
     75     // Inserts rsClearObject() calls at the end and at all exiting points of the
     76     // current scope. At each statement that exits the current scope -- e.g.,
     77     // a return, break, or continue statement in the current or a nested scope
     78     // -- rsClearObject() calls are inserted for local variables defined in the
     79     // current scope before that point.
     80     // Note goto statements are not handled. (See the DestructorVisitor class in
     81     // the .cpp file.)
     82     // Also note this function is called for every nested scope. As a result, for a
     83     // return statement, each rsObject declared in all its (nested) enclosing
     84     // scopes would have a rsClearObject() call properly inserted before
     85     // the return statement.
     86     void InsertLocalVarDestructors();
     87 
     88     // Sets the current statement being analyzed
     89     void setCurrentStmt(clang::Stmt *S) { mCurrent = S; }
     90 
     91     // Inserts a statement before the current statement
     92     void InsertStmt(const clang::ASTContext &C, clang::Stmt *NewStmt);
     93 
     94     // Replaces the current statement with NewStmt;
     95     void ReplaceStmt(const clang::ASTContext &C, clang::Stmt *NewStmt);
     96 
     97     // Replaces OldExpr with NewExpr in the current statement
     98     void ReplaceExpr(const clang::ASTContext& C, clang::Expr* OldExpr,
     99                      clang::Expr* NewExpr);
    100 
    101     static clang::Stmt *ClearRSObject(clang::VarDecl *VD,
    102                                       clang::DeclContext *DC);
    103   };
    104 
    105   clang::ASTContext &mCtx;
    106   std::deque<Scope*> mScopeStack;  // A deque used as a stack to store scopes, but also
    107                                    // accessed through its iterator in read-only mode.
    108   clang::DeclContext* mCurrentDC;
    109   bool RSInitFD;  // TODO: this should be static, since this flag affects all instances.
    110   unsigned mTempID;  // A unique id that can be used to distinguish temporary variables
    111 
    112   // RSSetObjectFD and RSClearObjectFD holds FunctionDecl of rsSetObject()
    113   // and rsClearObject() in the current ASTContext.
    114   static clang::FunctionDecl *RSSetObjectFD[];
    115   static clang::FunctionDecl *RSClearObjectFD[];
    116 
    117   inline bool emptyScope() const { return mScopeStack.empty(); }
    118 
    119   inline Scope *getCurrentScope() {
    120     return mScopeStack.back();
    121   }
    122 
    123   // Returns the next available unique id for temporary variables
    124   unsigned getNextID() { return mTempID++; }
    125 
    126   // Initialize RSSetObjectFD and RSClearObjectFD.
    127   static void GetRSRefCountingFunctions(clang::ASTContext &C);
    128 
    129   // Return false if the type of variable declared in VD does not contain
    130   // an RS object type.
    131   static bool InitializeRSObject(clang::VarDecl *VD,
    132                                  DataType *DT,
    133                                  clang::Expr **InitExpr);
    134 
    135   // Return an empty list initializer expression at the appropriate location.
    136   // This construct can then be used to cheaply construct a zero-initializer
    137   // for any RenderScript objects (like rs_allocation) or rs_matrix* types
    138   // (possibly even embedded within other types). These types are expected to
    139   // be zero-initialized always, and so we can use this helper to ensure that
    140   // they at least have an empty initializer.
    141   static clang::Expr *CreateEmptyInitListExpr(
    142       clang::ASTContext &C,
    143       const clang::SourceLocation &Loc);
    144 
    145   // Given a return statement RS that returns an rsObject, creates a temporary
    146   // variable, and sets it to the original return expression using rsSetObject().
    147   // Creates a new return statement that returns the temporary variable.
    148   // Returns a new compound statement that contains the new variable declaration,
    149   // the rsSetOjbect() call, and the new return statement.
    150   static clang::CompoundStmt* CreateRetStmtWithTempVar(
    151       clang::ASTContext& C,
    152       clang::DeclContext* DC,
    153       clang::ReturnStmt* RS,
    154       const unsigned id);
    155 
    156  public:
    157   explicit RSObjectRefCount(clang::ASTContext &C)
    158       : mCtx(C), RSInitFD(false), mTempID(0) {
    159   }
    160 
    161   void Init() {
    162     if (!RSInitFD) {
    163       GetRSRefCountingFunctions(mCtx);
    164       RSInitFD = true;
    165     }
    166   }
    167 
    168   // For function parameters and local variables that are or contain RS objects,
    169   // e.g., rs_allocation, this method transforms the function body to correctly
    170   // adjust reference counts of those objects.
    171   void HandleParamsAndLocals(clang::FunctionDecl *FD);
    172 
    173   static clang::FunctionDecl *GetRSSetObjectFD(DataType DT) {
    174     slangAssert(RSExportPrimitiveType::IsRSObjectType(DT));
    175     if (DT >= 0 && DT < DataTypeMax) {
    176       return RSSetObjectFD[DT];
    177     } else {
    178       slangAssert(false && "incorrect type");
    179       return nullptr;
    180     }
    181   }
    182 
    183   static clang::FunctionDecl *GetRSSetObjectFD(const clang::Type *T) {
    184     return GetRSSetObjectFD(RSExportPrimitiveType::GetRSSpecificType(T));
    185   }
    186 
    187   static clang::FunctionDecl *GetRSClearObjectFD(DataType DT) {
    188     slangAssert(RSExportPrimitiveType::IsRSObjectType(DT));
    189     if (DT >= 0 && DT < DataTypeMax) {
    190       return RSClearObjectFD[DT];
    191     } else {
    192       slangAssert(false && "incorrect type");
    193       return nullptr;
    194     }
    195   }
    196 
    197   static clang::FunctionDecl *GetRSClearObjectFD(const clang::Type *T) {
    198     return GetRSClearObjectFD(RSExportPrimitiveType::GetRSSpecificType(T));
    199   }
    200 
    201   // This method creates a "guard" variable for the expression E that is object-
    202   // typed or object-containing, e.g., a struct with object-type fields.
    203   // It creates one or more rsSetObject() calls to set the value of the guard to E.
    204   // This effectively increases the sysRef count of the objects referenced by E
    205   // by 1, therefore "guarding" the objects, which might otherwise lose a
    206   // reference and get deleted. Statements that declare the new variable and set
    207   // the value of the new variable are added to the vector NewStmts.
    208   //
    209   // Parameters:
    210   // C: The clang AST Context.
    211   // DC: The DeclContext for any new Decl to add
    212   // E: The expression with reference to the objects for which we want to
    213   //    increase the sysRef count
    214   // VarName: The name to use for the new guard variable
    215   // NewStmts: The vector for all statements added to create and set the guard.
    216   //
    217   // Returns:
    218   // An expression consisting of the guard variable
    219   //
    220   static clang::DeclRefExpr *CreateGuard(clang::ASTContext &C,
    221                                          clang::DeclContext *DC,
    222                                          clang::Expr *E,
    223                                          const llvm::Twine &VarName,
    224                                          std::vector<clang::Stmt*> &NewStmts);
    225 
    226   // For any function parameter that is object-typed or object-containing, if it
    227   // is overwritten inside the function, a system reference (sysRef) count
    228   // would decrement and may reach 0, leading the object to be deleted. This may
    229   // create a dangling pointer reference after a call to the function.
    230   // For example, the object in parameter a in the function below may be deleted
    231   // before the function returns.
    232   //   void foo(rs_allocation a) {  // assuming a references obj with sysRef of 1
    233   //     rs_allocation b = {};
    234   //     a = b;  // decrements sysRef of obj and deletes it
    235   //   }
    236   //
    237   // To avoid this problem, the sysRef counts of objects contained in parameters
    238   // --directly for object-typed parameters or indirectly as fields for struct-
    239   // typed parameters--are incremented at the beginning of the function, and
    240   // decremented at the end and any exiting point of the function. To achieve
    241   // these effects, the compiler creates a temporary local variable, and calls
    242   // rsSetObject() to set its value to that of the parameter. At the end of the
    243   // function and at any exiting point, the compiler adds calls to
    244   // rsClearObject() on the parameter. Each rsClearObject() call would decrement
    245   // the sysRef count of an incoming object if the parameter is never overwritten
    246   // in the function, or it would properly decrement the sysRef count of the new
    247   // object that the parameter is updated to in the function, since now the
    248   // parameter is going out of scope. For example, the compiler would transform
    249   // the previous code example into the following.
    250   //   void foo(rs_allocation a) {  // assuming a references obj with sysRef of 1
    251   //     rs_allocation .rs.param.a;
    252   //     rsSetObject(&.rs.param.a, a);  // sysRef of obj becomes 2
    253   //     rs_allocation b = {};
    254   //     a = b;  // sysRef of obj becomes 1
    255   //     rsClearObject(&a);  // sysRef of obj stays 1. obj stays undeleted.
    256   //   }
    257   //
    258   // This method creates the guard variable for a object-type parameter,
    259   // named with the prefix ".rs.param." added to the parameter name. It calls
    260   // CreateGuard() to do this. The rsClearObject() call for the parameter as
    261   // described above is not added by this function, but by the caller of this
    262   // function, i.e., HandleParametersAndLocals().
    263   //
    264   // Parameters:
    265   // C: The clang AST Context.
    266   // DC: The DeclContext for any new Decl to add. It should be the FunctionnDecl
    267   //     of the function being transformed.
    268   // PD: The ParmDecl for the parameter.
    269   // NewStmts: The vector for all statements added to create and set the guard.
    270   //
    271   static void CreateParameterGuard(
    272       clang::ASTContext &C,
    273       clang::DeclContext *DC,
    274       clang::ParmVarDecl *PD,
    275       std::vector<clang::Stmt*> &NewStmts);
    276 
    277   void SetDeclContext(clang::DeclContext* DC) { mCurrentDC = DC; }
    278   clang::DeclContext* GetDeclContext() const { return mCurrentDC; }
    279 
    280   void VisitStmt(clang::Stmt *S);
    281   void VisitCallExpr(clang::CallExpr *CE);
    282   void VisitDeclStmt(clang::DeclStmt *DS);
    283   void VisitCompoundStmt(clang::CompoundStmt *CS);
    284   void VisitBinAssign(clang::BinaryOperator *AS);
    285   void VisitReturnStmt(clang::ReturnStmt *RS);
    286   // We believe that RS objects are never involved in CompoundAssignOperator.
    287   // I.e., rs_allocation foo; foo += bar;
    288 
    289   // Emit a global destructor to clean up RS objects.
    290   clang::FunctionDecl *CreateStaticGlobalDtor();
    291 };
    292 
    293 }  // namespace slang
    294 
    295 #endif  // _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_OBJECT_REF_COUNT_H_  NOLINT
    296