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:
Scope(clang::CompoundStmt * CS)58     explicit Scope(clang::CompoundStmt *CS) : mCS(CS) {
59     }
60 
hasRSObject()61     bool hasRSObject() const { return !mRSO.empty(); }
62 
addRSObject(clang::VarDecl * VD)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
setCurrentStmt(clang::Stmt * S)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 
emptyScope()116   inline bool emptyScope() const { return mScopeStack.empty(); }
117 
getCurrentScope()118   inline Scope *getCurrentScope() {
119     return mScopeStack.back();
120   }
121 
122   // Returns the next available unique id for temporary variables
getNextID()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:
RSObjectRefCount(clang::ASTContext & C)156   explicit RSObjectRefCount(clang::ASTContext &C)
157       : mCtx(C), RSInitFD(false), mTempID(0) {
158   }
159 
Init()160   void Init() {
161     if (!RSInitFD) {
162       GetRSRefCountingFunctions(mCtx);
163       RSInitFD = true;
164     }
165   }
166 
GetRSSetObjectFD(DataType DT)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 
GetRSSetObjectFD(const clang::Type * T)177   static clang::FunctionDecl *GetRSSetObjectFD(const clang::Type *T) {
178     return GetRSSetObjectFD(RSExportPrimitiveType::GetRSSpecificType(T));
179   }
180 
GetRSClearObjectFD(DataType DT)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 
GetRSClearObjectFD(const clang::Type * T)191   static clang::FunctionDecl *GetRSClearObjectFD(const clang::Type *T) {
192     return GetRSClearObjectFD(RSExportPrimitiveType::GetRSSpecificType(T));
193   }
194 
SetDeclContext(clang::DeclContext * DC)195   void SetDeclContext(clang::DeclContext* DC) { mCurrentDC = DC; }
GetDeclContext()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