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
28namespace clang {
29  class Expr;
30  class Stmt;
31}
32
33namespace slang {
34
35// Recursive check
36bool 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.
48class 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