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:
Scope(clang::CompoundStmt * CS)59     explicit Scope(clang::CompoundStmt *CS) : mCS(CS) {
60     }
61 
hasRSObject()62     bool hasRSObject() const { return !mRSO.empty(); }
63 
addRSObject(clang::VarDecl * VD)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
setCurrentStmt(clang::Stmt * S)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 
emptyScope()117   inline bool emptyScope() const { return mScopeStack.empty(); }
118 
getCurrentScope()119   inline Scope *getCurrentScope() {
120     return mScopeStack.back();
121   }
122 
123   // Returns the next available unique id for temporary variables
getNextID()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:
RSObjectRefCount(clang::ASTContext & C)157   explicit RSObjectRefCount(clang::ASTContext &C)
158       : mCtx(C), RSInitFD(false), mTempID(0) {
159   }
160 
Init()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 
GetRSSetObjectFD(DataType DT)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 
GetRSSetObjectFD(const clang::Type * T)183   static clang::FunctionDecl *GetRSSetObjectFD(const clang::Type *T) {
184     return GetRSSetObjectFD(RSExportPrimitiveType::GetRSSpecificType(T));
185   }
186 
GetRSClearObjectFD(DataType DT)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 
GetRSClearObjectFD(const clang::Type * T)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 
SetDeclContext(clang::DeclContext * DC)277   void SetDeclContext(clang::DeclContext* DC) { mCurrentDC = DC; }
GetDeclContext()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