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