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