slang_rs_object_ref_count.h revision b478c3dd0a47dc4c0c884d911819c9cf53c46649
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 a zero-initializer expr of the type DT. This processes both
135  // RS matrix type and RS object type.
136  static clang::Expr *CreateZeroInitializerForRSSpecificType(
137      DataType DT,
138      clang::ASTContext &C,
139      const clang::SourceLocation &Loc);
140
141 public:
142  explicit RSObjectRefCount(clang::ASTContext &C)
143      : mCtx(C), RSInitFD(false), mTempID(0) {
144  }
145
146  void Init() {
147    if (!RSInitFD) {
148      GetRSRefCountingFunctions(mCtx);
149      RSInitFD = true;
150    }
151  }
152
153  static clang::FunctionDecl *GetRSSetObjectFD(DataType DT) {
154    slangAssert(RSExportPrimitiveType::IsRSObjectType(DT));
155    if (DT >= 0 && DT < DataTypeMax) {
156      return RSSetObjectFD[DT];
157    } else {
158      slangAssert(false && "incorrect type");
159      return nullptr;
160    }
161  }
162
163  static clang::FunctionDecl *GetRSSetObjectFD(const clang::Type *T) {
164    return GetRSSetObjectFD(RSExportPrimitiveType::GetRSSpecificType(T));
165  }
166
167  static clang::FunctionDecl *GetRSClearObjectFD(DataType DT) {
168    slangAssert(RSExportPrimitiveType::IsRSObjectType(DT));
169    if (DT >= 0 && DT < DataTypeMax) {
170      return RSClearObjectFD[DT];
171    } else {
172      slangAssert(false && "incorrect type");
173      return nullptr;
174    }
175  }
176
177  static clang::FunctionDecl *GetRSClearObjectFD(const clang::Type *T) {
178    return GetRSClearObjectFD(RSExportPrimitiveType::GetRSSpecificType(T));
179  }
180
181  void SetDeclContext(clang::DeclContext* DC) { mCurrentDC = DC; }
182  clang::DeclContext* GetDeclContext() const { return mCurrentDC; }
183
184  void VisitStmt(clang::Stmt *S);
185  void VisitCallExpr(clang::CallExpr *CE);
186  void VisitDeclStmt(clang::DeclStmt *DS);
187  void VisitCompoundStmt(clang::CompoundStmt *CS);
188  void VisitBinAssign(clang::BinaryOperator *AS);
189  void VisitReturnStmt(clang::ReturnStmt *RS);
190  // We believe that RS objects are never involved in CompoundAssignOperator.
191  // I.e., rs_allocation foo; foo += bar;
192
193  // Emit a global destructor to clean up RS objects.
194  clang::FunctionDecl *CreateStaticGlobalDtor();
195};
196
197}  // namespace slang
198
199#endif  // _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_OBJECT_REF_COUNT_H_  NOLINT
200