• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "slang_rs_object_ref_count.h"
18 
19 #include <list>
20 
21 #include "clang/AST/DeclGroup.h"
22 #include "clang/AST/Expr.h"
23 #include "clang/AST/NestedNameSpecifier.h"
24 #include "clang/AST/OperationKinds.h"
25 #include "clang/AST/Stmt.h"
26 #include "clang/AST/StmtVisitor.h"
27 
28 #include "slang_assert.h"
29 #include "slang_rs.h"
30 #include "slang_rs_ast_replace.h"
31 #include "slang_rs_export_type.h"
32 
33 namespace slang {
34 
35 clang::FunctionDecl *RSObjectRefCount::
36     RSSetObjectFD[RSExportPrimitiveType::LastRSObjectType -
37                   RSExportPrimitiveType::FirstRSObjectType + 1];
38 clang::FunctionDecl *RSObjectRefCount::
39     RSClearObjectFD[RSExportPrimitiveType::LastRSObjectType -
40                     RSExportPrimitiveType::FirstRSObjectType + 1];
41 
GetRSRefCountingFunctions(clang::ASTContext & C)42 void RSObjectRefCount::GetRSRefCountingFunctions(clang::ASTContext &C) {
43   for (unsigned i = 0;
44        i < (sizeof(RSClearObjectFD) / sizeof(clang::FunctionDecl*));
45        i++) {
46     RSSetObjectFD[i] = NULL;
47     RSClearObjectFD[i] = NULL;
48   }
49 
50   clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
51 
52   for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
53           E = TUDecl->decls_end(); I != E; I++) {
54     if ((I->getKind() >= clang::Decl::firstFunction) &&
55         (I->getKind() <= clang::Decl::lastFunction)) {
56       clang::FunctionDecl *FD = static_cast<clang::FunctionDecl*>(*I);
57 
58       // points to RSSetObjectFD or RSClearObjectFD
59       clang::FunctionDecl **RSObjectFD;
60 
61       if (FD->getName() == "rsSetObject") {
62         slangAssert((FD->getNumParams() == 2) &&
63                     "Invalid rsSetObject function prototype (# params)");
64         RSObjectFD = RSSetObjectFD;
65       } else if (FD->getName() == "rsClearObject") {
66         slangAssert((FD->getNumParams() == 1) &&
67                     "Invalid rsClearObject function prototype (# params)");
68         RSObjectFD = RSClearObjectFD;
69       } else {
70         continue;
71       }
72 
73       const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
74       clang::QualType PVT = PVD->getOriginalType();
75       // The first parameter must be a pointer like rs_allocation*
76       slangAssert(PVT->isPointerType() &&
77           "Invalid rs{Set,Clear}Object function prototype (pointer param)");
78 
79       // The rs object type passed to the FD
80       clang::QualType RST = PVT->getPointeeType();
81       RSExportPrimitiveType::DataType DT =
82           RSExportPrimitiveType::GetRSSpecificType(RST.getTypePtr());
83       slangAssert(RSExportPrimitiveType::IsRSObjectType(DT)
84              && "must be RS object type");
85 
86       RSObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)] = FD;
87     }
88   }
89 }
90 
91 namespace {
92 
93 // This function constructs a new CompoundStmt from the input StmtList.
BuildCompoundStmt(clang::ASTContext & C,std::list<clang::Stmt * > & StmtList,clang::SourceLocation Loc)94 static clang::CompoundStmt* BuildCompoundStmt(clang::ASTContext &C,
95       std::list<clang::Stmt*> &StmtList, clang::SourceLocation Loc) {
96   unsigned NewStmtCount = StmtList.size();
97   unsigned CompoundStmtCount = 0;
98 
99   clang::Stmt **CompoundStmtList;
100   CompoundStmtList = new clang::Stmt*[NewStmtCount];
101 
102   std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
103   std::list<clang::Stmt*>::const_iterator E = StmtList.end();
104   for ( ; I != E; I++) {
105     CompoundStmtList[CompoundStmtCount++] = *I;
106   }
107   slangAssert(CompoundStmtCount == NewStmtCount);
108 
109   clang::CompoundStmt *CS = new(C) clang::CompoundStmt(
110       C, llvm::makeArrayRef(CompoundStmtList, CompoundStmtCount), Loc, Loc);
111 
112   delete [] CompoundStmtList;
113 
114   return CS;
115 }
116 
AppendAfterStmt(clang::ASTContext & C,clang::CompoundStmt * CS,clang::Stmt * S,std::list<clang::Stmt * > & StmtList)117 static void AppendAfterStmt(clang::ASTContext &C,
118                             clang::CompoundStmt *CS,
119                             clang::Stmt *S,
120                             std::list<clang::Stmt*> &StmtList) {
121   slangAssert(CS);
122   clang::CompoundStmt::body_iterator bI = CS->body_begin();
123   clang::CompoundStmt::body_iterator bE = CS->body_end();
124   clang::Stmt **UpdatedStmtList =
125       new clang::Stmt*[CS->size() + StmtList.size()];
126 
127   unsigned UpdatedStmtCount = 0;
128   unsigned Once = 0;
129   for ( ; bI != bE; bI++) {
130     if (!S && ((*bI)->getStmtClass() == clang::Stmt::ReturnStmtClass)) {
131       // If we come across a return here, we don't have anything we can
132       // reasonably replace. We should have already inserted our destructor
133       // code in the proper spot, so we just clean up and return.
134       delete [] UpdatedStmtList;
135 
136       return;
137     }
138 
139     UpdatedStmtList[UpdatedStmtCount++] = *bI;
140 
141     if ((*bI == S) && !Once) {
142       Once++;
143       std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
144       std::list<clang::Stmt*>::const_iterator E = StmtList.end();
145       for ( ; I != E; I++) {
146         UpdatedStmtList[UpdatedStmtCount++] = *I;
147       }
148     }
149   }
150   slangAssert(Once <= 1);
151 
152   // When S is NULL, we are appending to the end of the CompoundStmt.
153   if (!S) {
154     slangAssert(Once == 0);
155     std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
156     std::list<clang::Stmt*>::const_iterator E = StmtList.end();
157     for ( ; I != E; I++) {
158       UpdatedStmtList[UpdatedStmtCount++] = *I;
159     }
160   }
161 
162   CS->setStmts(C, UpdatedStmtList, UpdatedStmtCount);
163 
164   delete [] UpdatedStmtList;
165 
166   return;
167 }
168 
169 // This class visits a compound statement and inserts DtorStmt
170 // in proper locations. This includes inserting it before any
171 // return statement in any sub-block, at the end of the logical enclosing
172 // scope (compound statement), and/or before any break/continue statement that
173 // would resume outside the declared scope. We will not handle the case for
174 // goto statements that leave a local scope.
175 //
176 // To accomplish these goals, it collects a list of sub-Stmt's that
177 // correspond to scope exit points. It then uses an RSASTReplace visitor to
178 // transform the AST, inserting appropriate destructors before each of those
179 // sub-Stmt's (and also before the exit of the outermost containing Stmt for
180 // the scope).
181 class DestructorVisitor : public clang::StmtVisitor<DestructorVisitor> {
182  private:
183   clang::ASTContext &mCtx;
184 
185   // The loop depth of the currently visited node.
186   int mLoopDepth;
187 
188   // The switch statement depth of the currently visited node.
189   // Note that this is tracked separately from the loop depth because
190   // SwitchStmt-contained ContinueStmt's should have destructors for the
191   // corresponding loop scope.
192   int mSwitchDepth;
193 
194   // The outermost statement block that we are currently visiting.
195   // This should always be a CompoundStmt.
196   clang::Stmt *mOuterStmt;
197 
198   // The destructor to execute for this scope/variable.
199   clang::Stmt* mDtorStmt;
200 
201   // The stack of statements which should be replaced by a compound statement
202   // containing the new destructor call followed by the original Stmt.
203   std::stack<clang::Stmt*> mReplaceStmtStack;
204 
205   // The source location for the variable declaration that we are trying to
206   // insert destructors for. Note that InsertDestructors() will not generate
207   // destructor calls for source locations that occur lexically before this
208   // location.
209   clang::SourceLocation mVarLoc;
210 
211  public:
212   DestructorVisitor(clang::ASTContext &C,
213                     clang::Stmt* OuterStmt,
214                     clang::Stmt* DtorStmt,
215                     clang::SourceLocation VarLoc);
216 
217   // This code walks the collected list of Stmts to replace and actually does
218   // the replacement. It also finishes up by appending the destructor to the
219   // current outermost CompoundStmt.
InsertDestructors()220   void InsertDestructors() {
221     clang::Stmt *S = NULL;
222     clang::SourceManager &SM = mCtx.getSourceManager();
223     std::list<clang::Stmt *> StmtList;
224     StmtList.push_back(mDtorStmt);
225 
226     while (!mReplaceStmtStack.empty()) {
227       S = mReplaceStmtStack.top();
228       mReplaceStmtStack.pop();
229 
230       // Skip all source locations that occur before the variable's
231       // declaration, since it won't have been initialized yet.
232       if (SM.isBeforeInTranslationUnit(S->getLocStart(), mVarLoc)) {
233         continue;
234       }
235 
236       StmtList.push_back(S);
237       clang::CompoundStmt *CS =
238           BuildCompoundStmt(mCtx, StmtList, S->getLocEnd());
239       StmtList.pop_back();
240 
241       RSASTReplace R(mCtx);
242       R.ReplaceStmt(mOuterStmt, S, CS);
243     }
244     clang::CompoundStmt *CS =
245       llvm::dyn_cast<clang::CompoundStmt>(mOuterStmt);
246     slangAssert(CS);
247     AppendAfterStmt(mCtx, CS, NULL, StmtList);
248   }
249 
250   void VisitStmt(clang::Stmt *S);
251   void VisitCompoundStmt(clang::CompoundStmt *CS);
252 
253   void VisitBreakStmt(clang::BreakStmt *BS);
254   void VisitCaseStmt(clang::CaseStmt *CS);
255   void VisitContinueStmt(clang::ContinueStmt *CS);
256   void VisitDefaultStmt(clang::DefaultStmt *DS);
257   void VisitDoStmt(clang::DoStmt *DS);
258   void VisitForStmt(clang::ForStmt *FS);
259   void VisitIfStmt(clang::IfStmt *IS);
260   void VisitReturnStmt(clang::ReturnStmt *RS);
261   void VisitSwitchCase(clang::SwitchCase *SC);
262   void VisitSwitchStmt(clang::SwitchStmt *SS);
263   void VisitWhileStmt(clang::WhileStmt *WS);
264 };
265 
DestructorVisitor(clang::ASTContext & C,clang::Stmt * OuterStmt,clang::Stmt * DtorStmt,clang::SourceLocation VarLoc)266 DestructorVisitor::DestructorVisitor(clang::ASTContext &C,
267                          clang::Stmt *OuterStmt,
268                          clang::Stmt *DtorStmt,
269                          clang::SourceLocation VarLoc)
270   : mCtx(C),
271     mLoopDepth(0),
272     mSwitchDepth(0),
273     mOuterStmt(OuterStmt),
274     mDtorStmt(DtorStmt),
275     mVarLoc(VarLoc) {
276   return;
277 }
278 
VisitStmt(clang::Stmt * S)279 void DestructorVisitor::VisitStmt(clang::Stmt *S) {
280   for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
281        I != E;
282        I++) {
283     if (clang::Stmt *Child = *I) {
284       Visit(Child);
285     }
286   }
287   return;
288 }
289 
VisitCompoundStmt(clang::CompoundStmt * CS)290 void DestructorVisitor::VisitCompoundStmt(clang::CompoundStmt *CS) {
291   VisitStmt(CS);
292   return;
293 }
294 
VisitBreakStmt(clang::BreakStmt * BS)295 void DestructorVisitor::VisitBreakStmt(clang::BreakStmt *BS) {
296   VisitStmt(BS);
297   if ((mLoopDepth == 0) && (mSwitchDepth == 0)) {
298     mReplaceStmtStack.push(BS);
299   }
300   return;
301 }
302 
VisitCaseStmt(clang::CaseStmt * CS)303 void DestructorVisitor::VisitCaseStmt(clang::CaseStmt *CS) {
304   VisitStmt(CS);
305   return;
306 }
307 
VisitContinueStmt(clang::ContinueStmt * CS)308 void DestructorVisitor::VisitContinueStmt(clang::ContinueStmt *CS) {
309   VisitStmt(CS);
310   if (mLoopDepth == 0) {
311     // Switch statements can have nested continues.
312     mReplaceStmtStack.push(CS);
313   }
314   return;
315 }
316 
VisitDefaultStmt(clang::DefaultStmt * DS)317 void DestructorVisitor::VisitDefaultStmt(clang::DefaultStmt *DS) {
318   VisitStmt(DS);
319   return;
320 }
321 
VisitDoStmt(clang::DoStmt * DS)322 void DestructorVisitor::VisitDoStmt(clang::DoStmt *DS) {
323   mLoopDepth++;
324   VisitStmt(DS);
325   mLoopDepth--;
326   return;
327 }
328 
VisitForStmt(clang::ForStmt * FS)329 void DestructorVisitor::VisitForStmt(clang::ForStmt *FS) {
330   mLoopDepth++;
331   VisitStmt(FS);
332   mLoopDepth--;
333   return;
334 }
335 
VisitIfStmt(clang::IfStmt * IS)336 void DestructorVisitor::VisitIfStmt(clang::IfStmt *IS) {
337   VisitStmt(IS);
338   return;
339 }
340 
VisitReturnStmt(clang::ReturnStmt * RS)341 void DestructorVisitor::VisitReturnStmt(clang::ReturnStmt *RS) {
342   mReplaceStmtStack.push(RS);
343   return;
344 }
345 
VisitSwitchCase(clang::SwitchCase * SC)346 void DestructorVisitor::VisitSwitchCase(clang::SwitchCase *SC) {
347   slangAssert(false && "Both case and default have specialized handlers");
348   VisitStmt(SC);
349   return;
350 }
351 
VisitSwitchStmt(clang::SwitchStmt * SS)352 void DestructorVisitor::VisitSwitchStmt(clang::SwitchStmt *SS) {
353   mSwitchDepth++;
354   VisitStmt(SS);
355   mSwitchDepth--;
356   return;
357 }
358 
VisitWhileStmt(clang::WhileStmt * WS)359 void DestructorVisitor::VisitWhileStmt(clang::WhileStmt *WS) {
360   mLoopDepth++;
361   VisitStmt(WS);
362   mLoopDepth--;
363   return;
364 }
365 
ClearSingleRSObject(clang::ASTContext & C,clang::Expr * RefRSVar,clang::SourceLocation Loc)366 clang::Expr *ClearSingleRSObject(clang::ASTContext &C,
367                                  clang::Expr *RefRSVar,
368                                  clang::SourceLocation Loc) {
369   slangAssert(RefRSVar);
370   const clang::Type *T = RefRSVar->getType().getTypePtr();
371   slangAssert(!T->isArrayType() &&
372               "Should not be destroying arrays with this function");
373 
374   clang::FunctionDecl *ClearObjectFD = RSObjectRefCount::GetRSClearObjectFD(T);
375   slangAssert((ClearObjectFD != NULL) &&
376               "rsClearObject doesn't cover all RS object types");
377 
378   clang::QualType ClearObjectFDType = ClearObjectFD->getType();
379   clang::QualType ClearObjectFDArgType =
380       ClearObjectFD->getParamDecl(0)->getOriginalType();
381 
382   // Example destructor for "rs_font localFont;"
383   //
384   // (CallExpr 'void'
385   //   (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
386   //     (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
387   //   (UnaryOperator 'rs_font *' prefix '&'
388   //     (DeclRefExpr 'rs_font':'rs_font' Var='localFont')))
389 
390   // Get address of targeted RS object
391   clang::Expr *AddrRefRSVar =
392       new(C) clang::UnaryOperator(RefRSVar,
393                                   clang::UO_AddrOf,
394                                   ClearObjectFDArgType,
395                                   clang::VK_RValue,
396                                   clang::OK_Ordinary,
397                                   Loc);
398 
399   clang::Expr *RefRSClearObjectFD =
400       clang::DeclRefExpr::Create(C,
401                                  clang::NestedNameSpecifierLoc(),
402                                  clang::SourceLocation(),
403                                  ClearObjectFD,
404                                  false,
405                                  ClearObjectFD->getLocation(),
406                                  ClearObjectFDType,
407                                  clang::VK_RValue,
408                                  NULL);
409 
410   clang::Expr *RSClearObjectFP =
411       clang::ImplicitCastExpr::Create(C,
412                                       C.getPointerType(ClearObjectFDType),
413                                       clang::CK_FunctionToPointerDecay,
414                                       RefRSClearObjectFD,
415                                       NULL,
416                                       clang::VK_RValue);
417 
418   llvm::SmallVector<clang::Expr*, 1> ArgList;
419   ArgList.push_back(AddrRefRSVar);
420 
421   clang::CallExpr *RSClearObjectCall =
422       new(C) clang::CallExpr(C,
423                              RSClearObjectFP,
424                              ArgList,
425                              ClearObjectFD->getCallResultType(),
426                              clang::VK_RValue,
427                              Loc);
428 
429   return RSClearObjectCall;
430 }
431 
ArrayDim(const clang::Type * T)432 static int ArrayDim(const clang::Type *T) {
433   if (!T || !T->isArrayType()) {
434     return 0;
435   }
436 
437   const clang::ConstantArrayType *CAT =
438     static_cast<const clang::ConstantArrayType *>(T);
439   return static_cast<int>(CAT->getSize().getSExtValue());
440 }
441 
442 static clang::Stmt *ClearStructRSObject(
443     clang::ASTContext &C,
444     clang::DeclContext *DC,
445     clang::Expr *RefRSStruct,
446     clang::SourceLocation StartLoc,
447     clang::SourceLocation Loc);
448 
ClearArrayRSObject(clang::ASTContext & C,clang::DeclContext * DC,clang::Expr * RefRSArr,clang::SourceLocation StartLoc,clang::SourceLocation Loc)449 static clang::Stmt *ClearArrayRSObject(
450     clang::ASTContext &C,
451     clang::DeclContext *DC,
452     clang::Expr *RefRSArr,
453     clang::SourceLocation StartLoc,
454     clang::SourceLocation Loc) {
455   const clang::Type *BaseType = RefRSArr->getType().getTypePtr();
456   slangAssert(BaseType->isArrayType());
457 
458   int NumArrayElements = ArrayDim(BaseType);
459   // Actually extract out the base RS object type for use later
460   BaseType = BaseType->getArrayElementTypeNoTypeQual();
461 
462   clang::Stmt *StmtArray[2] = {NULL};
463   int StmtCtr = 0;
464 
465   if (NumArrayElements <= 0) {
466     return NULL;
467   }
468 
469   // Example destructor loop for "rs_font fontArr[10];"
470   //
471   // (CompoundStmt
472   //   (DeclStmt "int rsIntIter")
473   //   (ForStmt
474   //     (BinaryOperator 'int' '='
475   //       (DeclRefExpr 'int' Var='rsIntIter')
476   //       (IntegerLiteral 'int' 0))
477   //     (BinaryOperator 'int' '<'
478   //       (DeclRefExpr 'int' Var='rsIntIter')
479   //       (IntegerLiteral 'int' 10)
480   //     NULL << CondVar >>
481   //     (UnaryOperator 'int' postfix '++'
482   //       (DeclRefExpr 'int' Var='rsIntIter'))
483   //     (CallExpr 'void'
484   //       (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
485   //         (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
486   //       (UnaryOperator 'rs_font *' prefix '&'
487   //         (ArraySubscriptExpr 'rs_font':'rs_font'
488   //           (ImplicitCastExpr 'rs_font *' <ArrayToPointerDecay>
489   //             (DeclRefExpr 'rs_font [10]' Var='fontArr'))
490   //           (DeclRefExpr 'int' Var='rsIntIter')))))))
491 
492   // Create helper variable for iterating through elements
493   clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
494   clang::VarDecl *IIVD =
495       clang::VarDecl::Create(C,
496                              DC,
497                              StartLoc,
498                              Loc,
499                              &II,
500                              C.IntTy,
501                              C.getTrivialTypeSourceInfo(C.IntTy),
502                              clang::SC_None);
503   clang::Decl *IID = (clang::Decl *)IIVD;
504 
505   clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
506   StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
507 
508   // Form the actual destructor loop
509   // for (Init; Cond; Inc)
510   //   RSClearObjectCall;
511 
512   // Init -> "rsIntIter = 0"
513   clang::DeclRefExpr *RefrsIntIter =
514       clang::DeclRefExpr::Create(C,
515                                  clang::NestedNameSpecifierLoc(),
516                                  clang::SourceLocation(),
517                                  IIVD,
518                                  false,
519                                  Loc,
520                                  C.IntTy,
521                                  clang::VK_RValue,
522                                  NULL);
523 
524   clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
525       llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
526 
527   clang::BinaryOperator *Init =
528       new(C) clang::BinaryOperator(RefrsIntIter,
529                                    Int0,
530                                    clang::BO_Assign,
531                                    C.IntTy,
532                                    clang::VK_RValue,
533                                    clang::OK_Ordinary,
534                                    Loc,
535                                    false);
536 
537   // Cond -> "rsIntIter < NumArrayElements"
538   clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
539       llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
540 
541   clang::BinaryOperator *Cond =
542       new(C) clang::BinaryOperator(RefrsIntIter,
543                                    NumArrayElementsExpr,
544                                    clang::BO_LT,
545                                    C.IntTy,
546                                    clang::VK_RValue,
547                                    clang::OK_Ordinary,
548                                    Loc,
549                                    false);
550 
551   // Inc -> "rsIntIter++"
552   clang::UnaryOperator *Inc =
553       new(C) clang::UnaryOperator(RefrsIntIter,
554                                   clang::UO_PostInc,
555                                   C.IntTy,
556                                   clang::VK_RValue,
557                                   clang::OK_Ordinary,
558                                   Loc);
559 
560   // Body -> "rsClearObject(&VD[rsIntIter]);"
561   // Destructor loop operates on individual array elements
562 
563   clang::Expr *RefRSArrPtr =
564       clang::ImplicitCastExpr::Create(C,
565           C.getPointerType(BaseType->getCanonicalTypeInternal()),
566           clang::CK_ArrayToPointerDecay,
567           RefRSArr,
568           NULL,
569           clang::VK_RValue);
570 
571   clang::Expr *RefRSArrPtrSubscript =
572       new(C) clang::ArraySubscriptExpr(RefRSArrPtr,
573                                        RefrsIntIter,
574                                        BaseType->getCanonicalTypeInternal(),
575                                        clang::VK_RValue,
576                                        clang::OK_Ordinary,
577                                        Loc);
578 
579   RSExportPrimitiveType::DataType DT =
580       RSExportPrimitiveType::GetRSSpecificType(BaseType);
581 
582   clang::Stmt *RSClearObjectCall = NULL;
583   if (BaseType->isArrayType()) {
584     RSClearObjectCall =
585         ClearArrayRSObject(C, DC, RefRSArrPtrSubscript, StartLoc, Loc);
586   } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
587     RSClearObjectCall =
588         ClearStructRSObject(C, DC, RefRSArrPtrSubscript, StartLoc, Loc);
589   } else {
590     RSClearObjectCall = ClearSingleRSObject(C, RefRSArrPtrSubscript, Loc);
591   }
592 
593   clang::ForStmt *DestructorLoop =
594       new(C) clang::ForStmt(C,
595                             Init,
596                             Cond,
597                             NULL,  // no condVar
598                             Inc,
599                             RSClearObjectCall,
600                             Loc,
601                             Loc,
602                             Loc);
603 
604   StmtArray[StmtCtr++] = DestructorLoop;
605   slangAssert(StmtCtr == 2);
606 
607   clang::CompoundStmt *CS = new(C) clang::CompoundStmt(
608       C, llvm::makeArrayRef(StmtArray, StmtCtr), Loc, Loc);
609 
610   return CS;
611 }
612 
CountRSObjectTypes(clang::ASTContext & C,const clang::Type * T,clang::SourceLocation Loc)613 static unsigned CountRSObjectTypes(clang::ASTContext &C,
614                                    const clang::Type *T,
615                                    clang::SourceLocation Loc) {
616   slangAssert(T);
617   unsigned RSObjectCount = 0;
618 
619   if (T->isArrayType()) {
620     return CountRSObjectTypes(C, T->getArrayElementTypeNoTypeQual(), Loc);
621   }
622 
623   RSExportPrimitiveType::DataType DT =
624       RSExportPrimitiveType::GetRSSpecificType(T);
625   if (DT != RSExportPrimitiveType::DataTypeUnknown) {
626     return (RSExportPrimitiveType::IsRSObjectType(DT) ? 1 : 0);
627   }
628 
629   if (T->isUnionType()) {
630     clang::RecordDecl *RD = T->getAsUnionType()->getDecl();
631     RD = RD->getDefinition();
632     for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
633            FE = RD->field_end();
634          FI != FE;
635          FI++) {
636       const clang::FieldDecl *FD = *FI;
637       const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
638       if (CountRSObjectTypes(C, FT, Loc)) {
639         slangAssert(false && "can't have unions with RS object types!");
640         return 0;
641       }
642     }
643   }
644 
645   if (!T->isStructureType()) {
646     return 0;
647   }
648 
649   clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
650   RD = RD->getDefinition();
651   for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
652          FE = RD->field_end();
653        FI != FE;
654        FI++) {
655     const clang::FieldDecl *FD = *FI;
656     const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
657     if (CountRSObjectTypes(C, FT, Loc)) {
658       // Sub-structs should only count once (as should arrays, etc.)
659       RSObjectCount++;
660     }
661   }
662 
663   return RSObjectCount;
664 }
665 
ClearStructRSObject(clang::ASTContext & C,clang::DeclContext * DC,clang::Expr * RefRSStruct,clang::SourceLocation StartLoc,clang::SourceLocation Loc)666 static clang::Stmt *ClearStructRSObject(
667     clang::ASTContext &C,
668     clang::DeclContext *DC,
669     clang::Expr *RefRSStruct,
670     clang::SourceLocation StartLoc,
671     clang::SourceLocation Loc) {
672   const clang::Type *BaseType = RefRSStruct->getType().getTypePtr();
673 
674   slangAssert(!BaseType->isArrayType());
675 
676   // Structs should show up as unknown primitive types
677   slangAssert(RSExportPrimitiveType::GetRSSpecificType(BaseType) ==
678               RSExportPrimitiveType::DataTypeUnknown);
679 
680   unsigned FieldsToDestroy = CountRSObjectTypes(C, BaseType, Loc);
681   slangAssert(FieldsToDestroy != 0);
682 
683   unsigned StmtCount = 0;
684   clang::Stmt **StmtArray = new clang::Stmt*[FieldsToDestroy];
685   for (unsigned i = 0; i < FieldsToDestroy; i++) {
686     StmtArray[i] = NULL;
687   }
688 
689   // Populate StmtArray by creating a destructor for each RS object field
690   clang::RecordDecl *RD = BaseType->getAsStructureType()->getDecl();
691   RD = RD->getDefinition();
692   for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
693          FE = RD->field_end();
694        FI != FE;
695        FI++) {
696     // We just look through all field declarations to see if we find a
697     // declaration for an RS object type (or an array of one).
698     bool IsArrayType = false;
699     clang::FieldDecl *FD = *FI;
700     const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
701     const clang::Type *OrigType = FT;
702     while (FT && FT->isArrayType()) {
703       FT = FT->getArrayElementTypeNoTypeQual();
704       IsArrayType = true;
705     }
706 
707     if (RSExportPrimitiveType::IsRSObjectType(FT)) {
708       clang::DeclAccessPair FoundDecl =
709           clang::DeclAccessPair::make(FD, clang::AS_none);
710       clang::MemberExpr *RSObjectMember =
711           clang::MemberExpr::Create(C,
712                                     RefRSStruct,
713                                     false,
714                                     clang::NestedNameSpecifierLoc(),
715                                     clang::SourceLocation(),
716                                     FD,
717                                     FoundDecl,
718                                     clang::DeclarationNameInfo(),
719                                     NULL,
720                                     OrigType->getCanonicalTypeInternal(),
721                                     clang::VK_RValue,
722                                     clang::OK_Ordinary);
723 
724       slangAssert(StmtCount < FieldsToDestroy);
725 
726       if (IsArrayType) {
727         StmtArray[StmtCount++] = ClearArrayRSObject(C,
728                                                     DC,
729                                                     RSObjectMember,
730                                                     StartLoc,
731                                                     Loc);
732       } else {
733         StmtArray[StmtCount++] = ClearSingleRSObject(C,
734                                                      RSObjectMember,
735                                                      Loc);
736       }
737     } else if (FT->isStructureType() && CountRSObjectTypes(C, FT, Loc)) {
738       // In this case, we have a nested struct. We may not end up filling all
739       // of the spaces in StmtArray (sub-structs should handle themselves
740       // with separate compound statements).
741       clang::DeclAccessPair FoundDecl =
742           clang::DeclAccessPair::make(FD, clang::AS_none);
743       clang::MemberExpr *RSObjectMember =
744           clang::MemberExpr::Create(C,
745                                     RefRSStruct,
746                                     false,
747                                     clang::NestedNameSpecifierLoc(),
748                                     clang::SourceLocation(),
749                                     FD,
750                                     FoundDecl,
751                                     clang::DeclarationNameInfo(),
752                                     NULL,
753                                     OrigType->getCanonicalTypeInternal(),
754                                     clang::VK_RValue,
755                                     clang::OK_Ordinary);
756 
757       if (IsArrayType) {
758         StmtArray[StmtCount++] = ClearArrayRSObject(C,
759                                                     DC,
760                                                     RSObjectMember,
761                                                     StartLoc,
762                                                     Loc);
763       } else {
764         StmtArray[StmtCount++] = ClearStructRSObject(C,
765                                                      DC,
766                                                      RSObjectMember,
767                                                      StartLoc,
768                                                      Loc);
769       }
770     }
771   }
772 
773   slangAssert(StmtCount > 0);
774   clang::CompoundStmt *CS = new(C) clang::CompoundStmt(
775       C, llvm::makeArrayRef(StmtArray, StmtCount), Loc, Loc);
776 
777   delete [] StmtArray;
778 
779   return CS;
780 }
781 
CreateSingleRSSetObject(clang::ASTContext & C,clang::Expr * DstExpr,clang::Expr * SrcExpr,clang::SourceLocation StartLoc,clang::SourceLocation Loc)782 static clang::Stmt *CreateSingleRSSetObject(clang::ASTContext &C,
783                                             clang::Expr *DstExpr,
784                                             clang::Expr *SrcExpr,
785                                             clang::SourceLocation StartLoc,
786                                             clang::SourceLocation Loc) {
787   const clang::Type *T = DstExpr->getType().getTypePtr();
788   clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(T);
789   slangAssert((SetObjectFD != NULL) &&
790               "rsSetObject doesn't cover all RS object types");
791 
792   clang::QualType SetObjectFDType = SetObjectFD->getType();
793   clang::QualType SetObjectFDArgType[2];
794   SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
795   SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
796 
797   clang::Expr *RefRSSetObjectFD =
798       clang::DeclRefExpr::Create(C,
799                                  clang::NestedNameSpecifierLoc(),
800                                  clang::SourceLocation(),
801                                  SetObjectFD,
802                                  false,
803                                  Loc,
804                                  SetObjectFDType,
805                                  clang::VK_RValue,
806                                  NULL);
807 
808   clang::Expr *RSSetObjectFP =
809       clang::ImplicitCastExpr::Create(C,
810                                       C.getPointerType(SetObjectFDType),
811                                       clang::CK_FunctionToPointerDecay,
812                                       RefRSSetObjectFD,
813                                       NULL,
814                                       clang::VK_RValue);
815 
816   llvm::SmallVector<clang::Expr*, 2> ArgList;
817   ArgList.push_back(new(C) clang::UnaryOperator(DstExpr,
818                                                 clang::UO_AddrOf,
819                                                 SetObjectFDArgType[0],
820                                                 clang::VK_RValue,
821                                                 clang::OK_Ordinary,
822                                                 Loc));
823   ArgList.push_back(SrcExpr);
824 
825   clang::CallExpr *RSSetObjectCall =
826       new(C) clang::CallExpr(C,
827                              RSSetObjectFP,
828                              ArgList,
829                              SetObjectFD->getCallResultType(),
830                              clang::VK_RValue,
831                              Loc);
832 
833   return RSSetObjectCall;
834 }
835 
836 static clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
837                                             clang::Expr *LHS,
838                                             clang::Expr *RHS,
839                                             clang::SourceLocation StartLoc,
840                                             clang::SourceLocation Loc);
841 
842 /*static clang::Stmt *CreateArrayRSSetObject(clang::ASTContext &C,
843                                            clang::Expr *DstArr,
844                                            clang::Expr *SrcArr,
845                                            clang::SourceLocation StartLoc,
846                                            clang::SourceLocation Loc) {
847   clang::DeclContext *DC = NULL;
848   const clang::Type *BaseType = DstArr->getType().getTypePtr();
849   slangAssert(BaseType->isArrayType());
850 
851   int NumArrayElements = ArrayDim(BaseType);
852   // Actually extract out the base RS object type for use later
853   BaseType = BaseType->getArrayElementTypeNoTypeQual();
854 
855   clang::Stmt *StmtArray[2] = {NULL};
856   int StmtCtr = 0;
857 
858   if (NumArrayElements <= 0) {
859     return NULL;
860   }
861 
862   // Create helper variable for iterating through elements
863   clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
864   clang::VarDecl *IIVD =
865       clang::VarDecl::Create(C,
866                              DC,
867                              StartLoc,
868                              Loc,
869                              &II,
870                              C.IntTy,
871                              C.getTrivialTypeSourceInfo(C.IntTy),
872                              clang::SC_None,
873                              clang::SC_None);
874   clang::Decl *IID = (clang::Decl *)IIVD;
875 
876   clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
877   StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
878 
879   // Form the actual loop
880   // for (Init; Cond; Inc)
881   //   RSSetObjectCall;
882 
883   // Init -> "rsIntIter = 0"
884   clang::DeclRefExpr *RefrsIntIter =
885       clang::DeclRefExpr::Create(C,
886                                  clang::NestedNameSpecifierLoc(),
887                                  IIVD,
888                                  Loc,
889                                  C.IntTy,
890                                  clang::VK_RValue,
891                                  NULL);
892 
893   clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
894       llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
895 
896   clang::BinaryOperator *Init =
897       new(C) clang::BinaryOperator(RefrsIntIter,
898                                    Int0,
899                                    clang::BO_Assign,
900                                    C.IntTy,
901                                    clang::VK_RValue,
902                                    clang::OK_Ordinary,
903                                    Loc);
904 
905   // Cond -> "rsIntIter < NumArrayElements"
906   clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
907       llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
908 
909   clang::BinaryOperator *Cond =
910       new(C) clang::BinaryOperator(RefrsIntIter,
911                                    NumArrayElementsExpr,
912                                    clang::BO_LT,
913                                    C.IntTy,
914                                    clang::VK_RValue,
915                                    clang::OK_Ordinary,
916                                    Loc);
917 
918   // Inc -> "rsIntIter++"
919   clang::UnaryOperator *Inc =
920       new(C) clang::UnaryOperator(RefrsIntIter,
921                                   clang::UO_PostInc,
922                                   C.IntTy,
923                                   clang::VK_RValue,
924                                   clang::OK_Ordinary,
925                                   Loc);
926 
927   // Body -> "rsSetObject(&Dst[rsIntIter], Src[rsIntIter]);"
928   // Loop operates on individual array elements
929 
930   clang::Expr *DstArrPtr =
931       clang::ImplicitCastExpr::Create(C,
932           C.getPointerType(BaseType->getCanonicalTypeInternal()),
933           clang::CK_ArrayToPointerDecay,
934           DstArr,
935           NULL,
936           clang::VK_RValue);
937 
938   clang::Expr *DstArrPtrSubscript =
939       new(C) clang::ArraySubscriptExpr(DstArrPtr,
940                                        RefrsIntIter,
941                                        BaseType->getCanonicalTypeInternal(),
942                                        clang::VK_RValue,
943                                        clang::OK_Ordinary,
944                                        Loc);
945 
946   clang::Expr *SrcArrPtr =
947       clang::ImplicitCastExpr::Create(C,
948           C.getPointerType(BaseType->getCanonicalTypeInternal()),
949           clang::CK_ArrayToPointerDecay,
950           SrcArr,
951           NULL,
952           clang::VK_RValue);
953 
954   clang::Expr *SrcArrPtrSubscript =
955       new(C) clang::ArraySubscriptExpr(SrcArrPtr,
956                                        RefrsIntIter,
957                                        BaseType->getCanonicalTypeInternal(),
958                                        clang::VK_RValue,
959                                        clang::OK_Ordinary,
960                                        Loc);
961 
962   RSExportPrimitiveType::DataType DT =
963       RSExportPrimitiveType::GetRSSpecificType(BaseType);
964 
965   clang::Stmt *RSSetObjectCall = NULL;
966   if (BaseType->isArrayType()) {
967     RSSetObjectCall = CreateArrayRSSetObject(C, DstArrPtrSubscript,
968                                              SrcArrPtrSubscript,
969                                              StartLoc, Loc);
970   } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
971     RSSetObjectCall = CreateStructRSSetObject(C, DstArrPtrSubscript,
972                                               SrcArrPtrSubscript,
973                                               StartLoc, Loc);
974   } else {
975     RSSetObjectCall = CreateSingleRSSetObject(C, DstArrPtrSubscript,
976                                               SrcArrPtrSubscript,
977                                               StartLoc, Loc);
978   }
979 
980   clang::ForStmt *DestructorLoop =
981       new(C) clang::ForStmt(C,
982                             Init,
983                             Cond,
984                             NULL,  // no condVar
985                             Inc,
986                             RSSetObjectCall,
987                             Loc,
988                             Loc,
989                             Loc);
990 
991   StmtArray[StmtCtr++] = DestructorLoop;
992   slangAssert(StmtCtr == 2);
993 
994   clang::CompoundStmt *CS =
995       new(C) clang::CompoundStmt(C, StmtArray, StmtCtr, Loc, Loc);
996 
997   return CS;
998 } */
999 
CreateStructRSSetObject(clang::ASTContext & C,clang::Expr * LHS,clang::Expr * RHS,clang::SourceLocation StartLoc,clang::SourceLocation Loc)1000 static clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
1001                                             clang::Expr *LHS,
1002                                             clang::Expr *RHS,
1003                                             clang::SourceLocation StartLoc,
1004                                             clang::SourceLocation Loc) {
1005   clang::QualType QT = LHS->getType();
1006   const clang::Type *T = QT.getTypePtr();
1007   slangAssert(T->isStructureType());
1008   slangAssert(!RSExportPrimitiveType::IsRSObjectType(T));
1009 
1010   // Keep an extra slot for the original copy (memcpy)
1011   unsigned FieldsToSet = CountRSObjectTypes(C, T, Loc) + 1;
1012 
1013   unsigned StmtCount = 0;
1014   clang::Stmt **StmtArray = new clang::Stmt*[FieldsToSet];
1015   for (unsigned i = 0; i < FieldsToSet; i++) {
1016     StmtArray[i] = NULL;
1017   }
1018 
1019   clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
1020   RD = RD->getDefinition();
1021   for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
1022          FE = RD->field_end();
1023        FI != FE;
1024        FI++) {
1025     bool IsArrayType = false;
1026     clang::FieldDecl *FD = *FI;
1027     const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
1028     const clang::Type *OrigType = FT;
1029 
1030     if (!CountRSObjectTypes(C, FT, Loc)) {
1031       // Skip to next if we don't have any viable RS object types
1032       continue;
1033     }
1034 
1035     clang::DeclAccessPair FoundDecl =
1036         clang::DeclAccessPair::make(FD, clang::AS_none);
1037     clang::MemberExpr *DstMember =
1038         clang::MemberExpr::Create(C,
1039                                   LHS,
1040                                   false,
1041                                   clang::NestedNameSpecifierLoc(),
1042                                   clang::SourceLocation(),
1043                                   FD,
1044                                   FoundDecl,
1045                                   clang::DeclarationNameInfo(),
1046                                   NULL,
1047                                   OrigType->getCanonicalTypeInternal(),
1048                                   clang::VK_RValue,
1049                                   clang::OK_Ordinary);
1050 
1051     clang::MemberExpr *SrcMember =
1052         clang::MemberExpr::Create(C,
1053                                   RHS,
1054                                   false,
1055                                   clang::NestedNameSpecifierLoc(),
1056                                   clang::SourceLocation(),
1057                                   FD,
1058                                   FoundDecl,
1059                                   clang::DeclarationNameInfo(),
1060                                   NULL,
1061                                   OrigType->getCanonicalTypeInternal(),
1062                                   clang::VK_RValue,
1063                                   clang::OK_Ordinary);
1064 
1065     if (FT->isArrayType()) {
1066       FT = FT->getArrayElementTypeNoTypeQual();
1067       IsArrayType = true;
1068     }
1069 
1070     RSExportPrimitiveType::DataType DT =
1071         RSExportPrimitiveType::GetRSSpecificType(FT);
1072 
1073     if (IsArrayType) {
1074       clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
1075       DiagEngine.Report(
1076         clang::FullSourceLoc(Loc, C.getSourceManager()),
1077         DiagEngine.getCustomDiagID(
1078           clang::DiagnosticsEngine::Error,
1079           "Arrays of RS object types within structures cannot be copied"));
1080       // TODO(srhines): Support setting arrays of RS objects
1081       // StmtArray[StmtCount++] =
1082       //    CreateArrayRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
1083     } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
1084       StmtArray[StmtCount++] =
1085           CreateStructRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
1086     } else if (RSExportPrimitiveType::IsRSObjectType(DT)) {
1087       StmtArray[StmtCount++] =
1088           CreateSingleRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
1089     } else {
1090       slangAssert(false);
1091     }
1092   }
1093 
1094   slangAssert(StmtCount < FieldsToSet);
1095 
1096   // We still need to actually do the overall struct copy. For simplicity,
1097   // we just do a straight-up assignment (which will still preserve all
1098   // the proper RS object reference counts).
1099   clang::BinaryOperator *CopyStruct =
1100       new(C) clang::BinaryOperator(LHS, RHS, clang::BO_Assign, QT,
1101                                    clang::VK_RValue, clang::OK_Ordinary, Loc,
1102                                    false);
1103   StmtArray[StmtCount++] = CopyStruct;
1104 
1105   clang::CompoundStmt *CS = new(C) clang::CompoundStmt(
1106       C, llvm::makeArrayRef(StmtArray, StmtCount), Loc, Loc);
1107 
1108   delete [] StmtArray;
1109 
1110   return CS;
1111 }
1112 
1113 }  // namespace
1114 
ReplaceRSObjectAssignment(clang::BinaryOperator * AS)1115 void RSObjectRefCount::Scope::ReplaceRSObjectAssignment(
1116     clang::BinaryOperator *AS) {
1117 
1118   clang::QualType QT = AS->getType();
1119 
1120   clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
1121       RSExportPrimitiveType::DataTypeRSFont)->getASTContext();
1122 
1123   clang::SourceLocation Loc = AS->getExprLoc();
1124   clang::SourceLocation StartLoc = AS->getLHS()->getExprLoc();
1125   clang::Stmt *UpdatedStmt = NULL;
1126 
1127   if (!RSExportPrimitiveType::IsRSObjectType(QT.getTypePtr())) {
1128     // By definition, this is a struct assignment if we get here
1129     UpdatedStmt =
1130         CreateStructRSSetObject(C, AS->getLHS(), AS->getRHS(), StartLoc, Loc);
1131   } else {
1132     UpdatedStmt =
1133         CreateSingleRSSetObject(C, AS->getLHS(), AS->getRHS(), StartLoc, Loc);
1134   }
1135 
1136   RSASTReplace R(C);
1137   R.ReplaceStmt(mCS, AS, UpdatedStmt);
1138   return;
1139 }
1140 
AppendRSObjectInit(clang::VarDecl * VD,clang::DeclStmt * DS,RSExportPrimitiveType::DataType DT,clang::Expr * InitExpr)1141 void RSObjectRefCount::Scope::AppendRSObjectInit(
1142     clang::VarDecl *VD,
1143     clang::DeclStmt *DS,
1144     RSExportPrimitiveType::DataType DT,
1145     clang::Expr *InitExpr) {
1146   slangAssert(VD);
1147 
1148   if (!InitExpr) {
1149     return;
1150   }
1151 
1152   clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
1153       RSExportPrimitiveType::DataTypeRSFont)->getASTContext();
1154   clang::SourceLocation Loc = RSObjectRefCount::GetRSSetObjectFD(
1155       RSExportPrimitiveType::DataTypeRSFont)->getLocation();
1156   clang::SourceLocation StartLoc = RSObjectRefCount::GetRSSetObjectFD(
1157       RSExportPrimitiveType::DataTypeRSFont)->getInnerLocStart();
1158 
1159   if (DT == RSExportPrimitiveType::DataTypeIsStruct) {
1160     const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1161     clang::DeclRefExpr *RefRSVar =
1162         clang::DeclRefExpr::Create(C,
1163                                    clang::NestedNameSpecifierLoc(),
1164                                    clang::SourceLocation(),
1165                                    VD,
1166                                    false,
1167                                    Loc,
1168                                    T->getCanonicalTypeInternal(),
1169                                    clang::VK_RValue,
1170                                    NULL);
1171 
1172     clang::Stmt *RSSetObjectOps =
1173         CreateStructRSSetObject(C, RefRSVar, InitExpr, StartLoc, Loc);
1174 
1175     std::list<clang::Stmt*> StmtList;
1176     StmtList.push_back(RSSetObjectOps);
1177     AppendAfterStmt(C, mCS, DS, StmtList);
1178     return;
1179   }
1180 
1181   clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(DT);
1182   slangAssert((SetObjectFD != NULL) &&
1183               "rsSetObject doesn't cover all RS object types");
1184 
1185   clang::QualType SetObjectFDType = SetObjectFD->getType();
1186   clang::QualType SetObjectFDArgType[2];
1187   SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
1188   SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
1189 
1190   clang::Expr *RefRSSetObjectFD =
1191       clang::DeclRefExpr::Create(C,
1192                                  clang::NestedNameSpecifierLoc(),
1193                                  clang::SourceLocation(),
1194                                  SetObjectFD,
1195                                  false,
1196                                  Loc,
1197                                  SetObjectFDType,
1198                                  clang::VK_RValue,
1199                                  NULL);
1200 
1201   clang::Expr *RSSetObjectFP =
1202       clang::ImplicitCastExpr::Create(C,
1203                                       C.getPointerType(SetObjectFDType),
1204                                       clang::CK_FunctionToPointerDecay,
1205                                       RefRSSetObjectFD,
1206                                       NULL,
1207                                       clang::VK_RValue);
1208 
1209   const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1210   clang::DeclRefExpr *RefRSVar =
1211       clang::DeclRefExpr::Create(C,
1212                                  clang::NestedNameSpecifierLoc(),
1213                                  clang::SourceLocation(),
1214                                  VD,
1215                                  false,
1216                                  Loc,
1217                                  T->getCanonicalTypeInternal(),
1218                                  clang::VK_RValue,
1219                                  NULL);
1220 
1221   llvm::SmallVector<clang::Expr*, 2> ArgList;
1222   ArgList.push_back(new(C) clang::UnaryOperator(RefRSVar,
1223                                                 clang::UO_AddrOf,
1224                                                 SetObjectFDArgType[0],
1225                                                 clang::VK_RValue,
1226                                                 clang::OK_Ordinary,
1227                                                 Loc));
1228   ArgList.push_back(InitExpr);
1229 
1230   clang::CallExpr *RSSetObjectCall =
1231       new(C) clang::CallExpr(C,
1232                              RSSetObjectFP,
1233                              ArgList,
1234                              SetObjectFD->getCallResultType(),
1235                              clang::VK_RValue,
1236                              Loc);
1237 
1238   std::list<clang::Stmt*> StmtList;
1239   StmtList.push_back(RSSetObjectCall);
1240   AppendAfterStmt(C, mCS, DS, StmtList);
1241 
1242   return;
1243 }
1244 
InsertLocalVarDestructors()1245 void RSObjectRefCount::Scope::InsertLocalVarDestructors() {
1246   for (std::list<clang::VarDecl*>::const_iterator I = mRSO.begin(),
1247           E = mRSO.end();
1248         I != E;
1249         I++) {
1250     clang::VarDecl *VD = *I;
1251     clang::Stmt *RSClearObjectCall = ClearRSObject(VD, VD->getDeclContext());
1252     if (RSClearObjectCall) {
1253       DestructorVisitor DV((*mRSO.begin())->getASTContext(),
1254                            mCS,
1255                            RSClearObjectCall,
1256                            VD->getSourceRange().getBegin());
1257       DV.Visit(mCS);
1258       DV.InsertDestructors();
1259     }
1260   }
1261   return;
1262 }
1263 
ClearRSObject(clang::VarDecl * VD,clang::DeclContext * DC)1264 clang::Stmt *RSObjectRefCount::Scope::ClearRSObject(
1265     clang::VarDecl *VD,
1266     clang::DeclContext *DC) {
1267   slangAssert(VD);
1268   clang::ASTContext &C = VD->getASTContext();
1269   clang::SourceLocation Loc = VD->getLocation();
1270   clang::SourceLocation StartLoc = VD->getInnerLocStart();
1271   const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1272 
1273   // Reference expr to target RS object variable
1274   clang::DeclRefExpr *RefRSVar =
1275       clang::DeclRefExpr::Create(C,
1276                                  clang::NestedNameSpecifierLoc(),
1277                                  clang::SourceLocation(),
1278                                  VD,
1279                                  false,
1280                                  Loc,
1281                                  T->getCanonicalTypeInternal(),
1282                                  clang::VK_RValue,
1283                                  NULL);
1284 
1285   if (T->isArrayType()) {
1286     return ClearArrayRSObject(C, DC, RefRSVar, StartLoc, Loc);
1287   }
1288 
1289   RSExportPrimitiveType::DataType DT =
1290       RSExportPrimitiveType::GetRSSpecificType(T);
1291 
1292   if (DT == RSExportPrimitiveType::DataTypeUnknown ||
1293       DT == RSExportPrimitiveType::DataTypeIsStruct) {
1294     return ClearStructRSObject(C, DC, RefRSVar, StartLoc, Loc);
1295   }
1296 
1297   slangAssert((RSExportPrimitiveType::IsRSObjectType(DT)) &&
1298               "Should be RS object");
1299 
1300   return ClearSingleRSObject(C, RefRSVar, Loc);
1301 }
1302 
InitializeRSObject(clang::VarDecl * VD,RSExportPrimitiveType::DataType * DT,clang::Expr ** InitExpr)1303 bool RSObjectRefCount::InitializeRSObject(clang::VarDecl *VD,
1304                                           RSExportPrimitiveType::DataType *DT,
1305                                           clang::Expr **InitExpr) {
1306   slangAssert(VD && DT && InitExpr);
1307   const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1308 
1309   // Loop through array types to get to base type
1310   while (T && T->isArrayType()) {
1311     T = T->getArrayElementTypeNoTypeQual();
1312   }
1313 
1314   bool DataTypeIsStructWithRSObject = false;
1315   *DT = RSExportPrimitiveType::GetRSSpecificType(T);
1316 
1317   if (*DT == RSExportPrimitiveType::DataTypeUnknown) {
1318     if (RSExportPrimitiveType::IsStructureTypeWithRSObject(T)) {
1319       *DT = RSExportPrimitiveType::DataTypeIsStruct;
1320       DataTypeIsStructWithRSObject = true;
1321     } else {
1322       return false;
1323     }
1324   }
1325 
1326   bool DataTypeIsRSObject = false;
1327   if (DataTypeIsStructWithRSObject) {
1328     DataTypeIsRSObject = true;
1329   } else {
1330     DataTypeIsRSObject = RSExportPrimitiveType::IsRSObjectType(*DT);
1331   }
1332   *InitExpr = VD->getInit();
1333 
1334   if (!DataTypeIsRSObject && *InitExpr) {
1335     // If we already have an initializer for a matrix type, we are done.
1336     return DataTypeIsRSObject;
1337   }
1338 
1339   clang::Expr *ZeroInitializer =
1340       CreateZeroInitializerForRSSpecificType(*DT,
1341                                              VD->getASTContext(),
1342                                              VD->getLocation());
1343 
1344   if (ZeroInitializer) {
1345     ZeroInitializer->setType(T->getCanonicalTypeInternal());
1346     VD->setInit(ZeroInitializer);
1347   }
1348 
1349   return DataTypeIsRSObject;
1350 }
1351 
CreateZeroInitializerForRSSpecificType(RSExportPrimitiveType::DataType DT,clang::ASTContext & C,const clang::SourceLocation & Loc)1352 clang::Expr *RSObjectRefCount::CreateZeroInitializerForRSSpecificType(
1353     RSExportPrimitiveType::DataType DT,
1354     clang::ASTContext &C,
1355     const clang::SourceLocation &Loc) {
1356   clang::Expr *Res = NULL;
1357   switch (DT) {
1358     case RSExportPrimitiveType::DataTypeIsStruct:
1359     case RSExportPrimitiveType::DataTypeRSElement:
1360     case RSExportPrimitiveType::DataTypeRSType:
1361     case RSExportPrimitiveType::DataTypeRSAllocation:
1362     case RSExportPrimitiveType::DataTypeRSSampler:
1363     case RSExportPrimitiveType::DataTypeRSScript:
1364     case RSExportPrimitiveType::DataTypeRSMesh:
1365     case RSExportPrimitiveType::DataTypeRSPath:
1366     case RSExportPrimitiveType::DataTypeRSProgramFragment:
1367     case RSExportPrimitiveType::DataTypeRSProgramVertex:
1368     case RSExportPrimitiveType::DataTypeRSProgramRaster:
1369     case RSExportPrimitiveType::DataTypeRSProgramStore:
1370     case RSExportPrimitiveType::DataTypeRSFont: {
1371       //    (ImplicitCastExpr 'nullptr_t'
1372       //      (IntegerLiteral 0)))
1373       llvm::APInt Zero(C.getTypeSize(C.IntTy), 0);
1374       clang::Expr *Int0 = clang::IntegerLiteral::Create(C, Zero, C.IntTy, Loc);
1375       clang::Expr *CastToNull =
1376           clang::ImplicitCastExpr::Create(C,
1377                                           C.NullPtrTy,
1378                                           clang::CK_IntegralToPointer,
1379                                           Int0,
1380                                           NULL,
1381                                           clang::VK_RValue);
1382 
1383       llvm::SmallVector<clang::Expr*, 1>InitList;
1384       InitList.push_back(CastToNull);
1385 
1386       Res = new(C) clang::InitListExpr(C, Loc, InitList, Loc);
1387       break;
1388     }
1389     case RSExportPrimitiveType::DataTypeRSMatrix2x2:
1390     case RSExportPrimitiveType::DataTypeRSMatrix3x3:
1391     case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
1392       // RS matrix is not completely an RS object. They hold data by themselves.
1393       // (InitListExpr rs_matrix2x2
1394       //   (InitListExpr float[4]
1395       //     (FloatingLiteral 0)
1396       //     (FloatingLiteral 0)
1397       //     (FloatingLiteral 0)
1398       //     (FloatingLiteral 0)))
1399       clang::QualType FloatTy = C.FloatTy;
1400       // Constructor sets value to 0.0f by default
1401       llvm::APFloat Val(C.getFloatTypeSemantics(FloatTy));
1402       clang::FloatingLiteral *Float0Val =
1403           clang::FloatingLiteral::Create(C,
1404                                          Val,
1405                                          /* isExact = */true,
1406                                          FloatTy,
1407                                          Loc);
1408 
1409       unsigned N = 0;
1410       if (DT == RSExportPrimitiveType::DataTypeRSMatrix2x2)
1411         N = 2;
1412       else if (DT == RSExportPrimitiveType::DataTypeRSMatrix3x3)
1413         N = 3;
1414       else if (DT == RSExportPrimitiveType::DataTypeRSMatrix4x4)
1415         N = 4;
1416       unsigned N_2 = N * N;
1417 
1418       // Assume we are going to be allocating 16 elements, since 4x4 is max.
1419       llvm::SmallVector<clang::Expr*, 16> InitVals;
1420       for (unsigned i = 0; i < N_2; i++)
1421         InitVals.push_back(Float0Val);
1422       clang::Expr *InitExpr =
1423           new(C) clang::InitListExpr(C, Loc, InitVals, Loc);
1424       InitExpr->setType(C.getConstantArrayType(FloatTy,
1425                                                llvm::APInt(32, N_2),
1426                                                clang::ArrayType::Normal,
1427                                                /* EltTypeQuals = */0));
1428       llvm::SmallVector<clang::Expr*, 1> InitExprVec;
1429       InitExprVec.push_back(InitExpr);
1430 
1431       Res = new(C) clang::InitListExpr(C, Loc, InitExprVec, Loc);
1432       break;
1433     }
1434     case RSExportPrimitiveType::DataTypeUnknown:
1435     case RSExportPrimitiveType::DataTypeFloat16:
1436     case RSExportPrimitiveType::DataTypeFloat32:
1437     case RSExportPrimitiveType::DataTypeFloat64:
1438     case RSExportPrimitiveType::DataTypeSigned8:
1439     case RSExportPrimitiveType::DataTypeSigned16:
1440     case RSExportPrimitiveType::DataTypeSigned32:
1441     case RSExportPrimitiveType::DataTypeSigned64:
1442     case RSExportPrimitiveType::DataTypeUnsigned8:
1443     case RSExportPrimitiveType::DataTypeUnsigned16:
1444     case RSExportPrimitiveType::DataTypeUnsigned32:
1445     case RSExportPrimitiveType::DataTypeUnsigned64:
1446     case RSExportPrimitiveType::DataTypeBoolean:
1447     case RSExportPrimitiveType::DataTypeUnsigned565:
1448     case RSExportPrimitiveType::DataTypeUnsigned5551:
1449     case RSExportPrimitiveType::DataTypeUnsigned4444:
1450     case RSExportPrimitiveType::DataTypeMax: {
1451       slangAssert(false && "Not RS object type!");
1452     }
1453     // No default case will enable compiler detecting the missing cases
1454   }
1455 
1456   return Res;
1457 }
1458 
VisitDeclStmt(clang::DeclStmt * DS)1459 void RSObjectRefCount::VisitDeclStmt(clang::DeclStmt *DS) {
1460   for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
1461        I != E;
1462        I++) {
1463     clang::Decl *D = *I;
1464     if (D->getKind() == clang::Decl::Var) {
1465       clang::VarDecl *VD = static_cast<clang::VarDecl*>(D);
1466       RSExportPrimitiveType::DataType DT =
1467           RSExportPrimitiveType::DataTypeUnknown;
1468       clang::Expr *InitExpr = NULL;
1469       if (InitializeRSObject(VD, &DT, &InitExpr)) {
1470         // We need to zero-init all RS object types (including matrices), ...
1471         getCurrentScope()->AppendRSObjectInit(VD, DS, DT, InitExpr);
1472         // ... but, only add to the list of RS objects if we have some
1473         // non-matrix RS object fields.
1474         if (CountRSObjectTypes(mCtx, VD->getType().getTypePtr(),
1475                                VD->getLocation())) {
1476           getCurrentScope()->addRSObject(VD);
1477         }
1478       }
1479     }
1480   }
1481   return;
1482 }
1483 
VisitCompoundStmt(clang::CompoundStmt * CS)1484 void RSObjectRefCount::VisitCompoundStmt(clang::CompoundStmt *CS) {
1485   if (!CS->body_empty()) {
1486     // Push a new scope
1487     Scope *S = new Scope(CS);
1488     mScopeStack.push(S);
1489 
1490     VisitStmt(CS);
1491 
1492     // Destroy the scope
1493     slangAssert((getCurrentScope() == S) && "Corrupted scope stack!");
1494     S->InsertLocalVarDestructors();
1495     mScopeStack.pop();
1496     delete S;
1497   }
1498   return;
1499 }
1500 
VisitBinAssign(clang::BinaryOperator * AS)1501 void RSObjectRefCount::VisitBinAssign(clang::BinaryOperator *AS) {
1502   clang::QualType QT = AS->getType();
1503 
1504   if (CountRSObjectTypes(mCtx, QT.getTypePtr(), AS->getExprLoc())) {
1505     getCurrentScope()->ReplaceRSObjectAssignment(AS);
1506   }
1507 
1508   return;
1509 }
1510 
VisitStmt(clang::Stmt * S)1511 void RSObjectRefCount::VisitStmt(clang::Stmt *S) {
1512   for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
1513        I != E;
1514        I++) {
1515     if (clang::Stmt *Child = *I) {
1516       Visit(Child);
1517     }
1518   }
1519   return;
1520 }
1521 
1522 // This function walks the list of global variables and (potentially) creates
1523 // a single global static destructor function that properly decrements
1524 // reference counts on the contained RS object types.
CreateStaticGlobalDtor()1525 clang::FunctionDecl *RSObjectRefCount::CreateStaticGlobalDtor() {
1526   Init();
1527 
1528   clang::DeclContext *DC = mCtx.getTranslationUnitDecl();
1529   clang::SourceLocation loc;
1530 
1531   llvm::StringRef SR(".rs.dtor");
1532   clang::IdentifierInfo &II = mCtx.Idents.get(SR);
1533   clang::DeclarationName N(&II);
1534   clang::FunctionProtoType::ExtProtoInfo EPI;
1535   clang::QualType T = mCtx.getFunctionType(mCtx.VoidTy,
1536       llvm::ArrayRef<clang::QualType>(), EPI);
1537   clang::FunctionDecl *FD = NULL;
1538 
1539   // Generate rsClearObject() call chains for every global variable
1540   // (whether static or extern).
1541   std::list<clang::Stmt *> StmtList;
1542   for (clang::DeclContext::decl_iterator I = DC->decls_begin(),
1543           E = DC->decls_end(); I != E; I++) {
1544     clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I);
1545     if (VD) {
1546       if (CountRSObjectTypes(mCtx, VD->getType().getTypePtr(), loc)) {
1547         if (!FD) {
1548           // Only create FD if we are going to use it.
1549           FD = clang::FunctionDecl::Create(mCtx, DC, loc, loc, N, T, NULL,
1550                                            clang::SC_None);
1551         }
1552         // Make sure to create any helpers within the function's DeclContext,
1553         // not the one associated with the global translation unit.
1554         clang::Stmt *RSClearObjectCall = Scope::ClearRSObject(VD, FD);
1555         StmtList.push_back(RSClearObjectCall);
1556       }
1557     }
1558   }
1559 
1560   // Nothing needs to be destroyed, so don't emit a dtor.
1561   if (StmtList.empty()) {
1562     return NULL;
1563   }
1564 
1565   clang::CompoundStmt *CS = BuildCompoundStmt(mCtx, StmtList, loc);
1566 
1567   FD->setBody(CS);
1568 
1569   return FD;
1570 }
1571 
1572 }  // namespace slang
1573