slang_rs_object_ref_count.cpp revision a858cb6f3d9223d65bf73e1230c6324ded4095f6
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/OperationKinds.h"
24#include "clang/AST/Stmt.h"
25#include "clang/AST/StmtVisitor.h"
26
27#include "slang_rs.h"
28#include "slang_rs_export_type.h"
29
30namespace slang {
31
32clang::FunctionDecl *RSObjectRefCount::Scope::
33    RSSetObjectFD[RSExportPrimitiveType::LastRSObjectType -
34                  RSExportPrimitiveType::FirstRSObjectType + 1];
35clang::FunctionDecl *RSObjectRefCount::Scope::
36    RSClearObjectFD[RSExportPrimitiveType::LastRSObjectType -
37                    RSExportPrimitiveType::FirstRSObjectType + 1];
38
39void RSObjectRefCount::Scope::GetRSRefCountingFunctions(
40    clang::ASTContext &C) {
41  for (unsigned i = 0;
42       i < (sizeof(RSClearObjectFD) / sizeof(clang::FunctionDecl*));
43       i++) {
44    RSSetObjectFD[i] = NULL;
45    RSClearObjectFD[i] = NULL;
46  }
47
48  clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
49
50  for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
51          E = TUDecl->decls_end(); I != E; I++) {
52    if ((I->getKind() >= clang::Decl::firstFunction) &&
53        (I->getKind() <= clang::Decl::lastFunction)) {
54      clang::FunctionDecl *FD = static_cast<clang::FunctionDecl*>(*I);
55
56      // points to RSSetObjectFD or RSClearObjectFD
57      clang::FunctionDecl **RSObjectFD;
58
59      if (FD->getName() == "rsSetObject") {
60        assert((FD->getNumParams() == 2) &&
61               "Invalid rsSetObject function prototype (# params)");
62        RSObjectFD = RSSetObjectFD;
63      } else if (FD->getName() == "rsClearObject") {
64        assert((FD->getNumParams() == 1) &&
65               "Invalid rsClearObject function prototype (# params)");
66        RSObjectFD = RSClearObjectFD;
67      } else {
68        continue;
69      }
70
71      const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
72      clang::QualType PVT = PVD->getOriginalType();
73      // The first parameter must be a pointer like rs_allocation*
74      assert(PVT->isPointerType() &&
75             "Invalid rs{Set,Clear}Object function prototype (pointer param)");
76
77      // The rs object type passed to the FD
78      clang::QualType RST = PVT->getPointeeType();
79      RSExportPrimitiveType::DataType DT =
80          RSExportPrimitiveType::GetRSSpecificType(RST.getTypePtr());
81      assert(RSExportPrimitiveType::IsRSObjectType(DT)
82             && "must be RS object type");
83
84      RSObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)] = FD;
85    }
86  }
87}
88
89namespace {
90
91static void AppendToCompoundStatement(clang::ASTContext& C,
92                                      clang::CompoundStmt *CS,
93                                      std::list<clang::Stmt*> &StmtList,
94                                      bool InsertAtEndOfBlock) {
95  // Destructor code will be inserted before any return statement.
96  // Any subsequent statements in the compound statement are then placed
97  // after our new code.
98  // TODO(srhines): This should also handle the case of goto/break/continue.
99
100  clang::CompoundStmt::body_iterator bI = CS->body_begin();
101
102  unsigned OldStmtCount = 0;
103  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
104    OldStmtCount++;
105  }
106
107  unsigned NewStmtCount = StmtList.size();
108
109  clang::Stmt **UpdatedStmtList;
110  UpdatedStmtList = new clang::Stmt*[OldStmtCount+NewStmtCount];
111
112  unsigned UpdatedStmtCount = 0;
113  bool FoundReturn = false;
114  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
115    if ((*bI)->getStmtClass() == clang::Stmt::ReturnStmtClass) {
116      FoundReturn = true;
117      break;
118    }
119    UpdatedStmtList[UpdatedStmtCount++] = *bI;
120  }
121
122  // Always insert before a return that we found, or if we are told
123  // to insert at the end of the block
124  if (FoundReturn || InsertAtEndOfBlock) {
125    std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
126    for (std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
127         I != StmtList.end();
128         I++) {
129      UpdatedStmtList[UpdatedStmtCount++] = *I;
130    }
131  }
132
133  // Pick up anything left over after a return statement
134  for ( ; bI != CS->body_end(); bI++) {
135    UpdatedStmtList[UpdatedStmtCount++] = *bI;
136  }
137
138  CS->setStmts(C, UpdatedStmtList, UpdatedStmtCount);
139
140  delete [] UpdatedStmtList;
141
142  return;
143}
144
145// This class visits a compound statement and inserts the StmtList containing
146// destructors in proper locations. This includes inserting them before any
147// return statement in any sub-block, at the end of the logical enclosing
148// scope (compound statement), and/or before any break/continue statement that
149// would resume outside the declared scope. We will not handle the case for
150// goto statements that leave a local scope.
151// TODO(srhines): Make this work properly for break/continue.
152class DestructorVisitor : public clang::StmtVisitor<DestructorVisitor> {
153 private:
154  clang::ASTContext &mC;
155  std::list<clang::Stmt*> &mStmtList;
156  bool mTopLevel;
157 public:
158  DestructorVisitor(clang::ASTContext &C, std::list<clang::Stmt*> &StmtList);
159  void VisitStmt(clang::Stmt *S);
160  void VisitCompoundStmt(clang::CompoundStmt *CS);
161};
162
163DestructorVisitor::DestructorVisitor(clang::ASTContext &C,
164                                     std::list<clang::Stmt*> &StmtList)
165  : mC(C),
166    mStmtList(StmtList),
167    mTopLevel(true) {
168  return;
169}
170
171void DestructorVisitor::VisitCompoundStmt(clang::CompoundStmt *CS) {
172  if (!CS->body_empty()) {
173    AppendToCompoundStatement(mC, CS, mStmtList, mTopLevel);
174    mTopLevel = false;
175    VisitStmt(CS);
176  }
177  return;
178}
179
180void DestructorVisitor::VisitStmt(clang::Stmt *S) {
181  for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
182       I != E;
183       I++) {
184    if (clang::Stmt *Child = *I) {
185      Visit(Child);
186    }
187  }
188  return;
189}
190
191static int ArrayDim(clang::VarDecl *VD) {
192  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
193
194  if (!T || !T->isArrayType()) {
195    return 0;
196  }
197
198  const clang::ConstantArrayType *CAT =
199    static_cast<const clang::ConstantArrayType *>(T);
200  return static_cast<int>(CAT->getSize().getSExtValue());
201}
202
203static clang::Stmt *ClearArrayRSObject(clang::VarDecl *VD,
204    const clang::Type *T,
205    clang::FunctionDecl *ClearObjectFD) {
206  clang::ASTContext &C = VD->getASTContext();
207  clang::SourceRange Range = VD->getQualifierRange();
208  clang::SourceLocation Loc = Range.getEnd();
209
210  clang::Stmt *StmtArray[2] = {NULL};
211  int StmtCtr = 0;
212
213  int NumArrayElements = ArrayDim(VD);
214  if (NumArrayElements <= 0) {
215    return NULL;
216  }
217
218  // Example destructor loop for "rs_font fontArr[10];"
219  //
220  // (CompoundStmt
221  //   (DeclStmt "int rsIntIter")
222  //   (ForStmt
223  //     (BinaryOperator 'int' '='
224  //       (DeclRefExpr 'int' Var='rsIntIter')
225  //       (IntegerLiteral 'int' 0))
226  //     (BinaryOperator 'int' '<'
227  //       (DeclRefExpr 'int' Var='rsIntIter')
228  //       (IntegerLiteral 'int' 10)
229  //     NULL << CondVar >>
230  //     (UnaryOperator 'int' postfix '++'
231  //       (DeclRefExpr 'int' Var='rsIntIter'))
232  //     (CallExpr 'void'
233  //       (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
234  //         (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
235  //       (UnaryOperator 'rs_font *' prefix '&'
236  //         (ArraySubscriptExpr 'rs_font':'rs_font'
237  //           (ImplicitCastExpr 'rs_font *' <ArrayToPointerDecay>
238  //             (DeclRefExpr 'rs_font [10]' Var='fontArr'))
239  //           (DeclRefExpr 'int' Var='rsIntIter')))))))
240
241  // Create helper variable for iterating through elements
242  clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
243  clang::VarDecl *IIVD =
244      clang::VarDecl::Create(C,
245                             VD->getDeclContext(),
246                             Loc,
247                             &II,
248                             C.IntTy,
249                             C.getTrivialTypeSourceInfo(C.IntTy),
250                             clang::SC_None,
251                             clang::SC_None);
252  clang::Decl *IID = (clang::Decl *)IIVD;
253
254  clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
255  StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
256
257  // Form the actual destructor loop
258  // for (Init; Cond; Inc)
259  //   RSClearObjectCall;
260
261  // Init -> "rsIntIter = 0"
262  clang::DeclRefExpr *RefrsIntIter =
263      clang::DeclRefExpr::Create(C,
264                                 NULL,
265                                 Range,
266                                 IIVD,
267                                 Loc,
268                                 C.IntTy);
269
270  clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
271      llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
272
273  clang::BinaryOperator *Init =
274      new(C) clang::BinaryOperator(RefrsIntIter,
275                                   Int0,
276                                   clang::BO_Assign,
277                                   C.IntTy,
278                                   Loc);
279
280  // Cond -> "rsIntIter < NumArrayElements"
281  clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
282      llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
283
284  clang::BinaryOperator *Cond =
285      new(C) clang::BinaryOperator(RefrsIntIter,
286                                   NumArrayElementsExpr,
287                                   clang::BO_LT,
288                                   C.IntTy,
289                                   Loc);
290
291  // Inc -> "rsIntIter++"
292  clang::UnaryOperator *Inc =
293      new(C) clang::UnaryOperator(RefrsIntIter,
294                                  clang::UO_PostInc,
295                                  C.IntTy,
296                                  Loc);
297
298  // Body -> "rsClearObject(&VD[rsIntIter]);"
299  // Destructor loop operates on individual array elements
300  clang::QualType ClearObjectFDType = ClearObjectFD->getType();
301  clang::QualType ClearObjectFDArgType =
302      ClearObjectFD->getParamDecl(0)->getOriginalType();
303
304  const clang::Type *VT = RSExportType::GetTypeOfDecl(VD);
305  clang::DeclRefExpr *RefRSVar =
306      clang::DeclRefExpr::Create(C,
307                                 NULL,
308                                 Range,
309                                 VD,
310                                 Loc,
311                                 VT->getCanonicalTypeInternal());
312
313  clang::Expr *RefRSVarPtr =
314      clang::ImplicitCastExpr::Create(C,
315          C.getPointerType(T->getCanonicalTypeInternal()),
316          clang::CK_ArrayToPointerDecay,
317          RefRSVar,
318          NULL,
319          clang::VK_RValue);
320
321  clang::Expr *RefRSVarPtrSubscript =
322      new(C) clang::ArraySubscriptExpr(RefRSVarPtr,
323                                       RefrsIntIter,
324                                       T->getCanonicalTypeInternal(),
325                                       VD->getLocation());
326
327  clang::Expr *AddrRefRSVarPtrSubscript =
328      new(C) clang::UnaryOperator(RefRSVarPtrSubscript,
329                                  clang::UO_AddrOf,
330                                  ClearObjectFDArgType,
331                                  VD->getLocation());
332
333  clang::Expr *RefRSClearObjectFD =
334      clang::DeclRefExpr::Create(C,
335                                 NULL,
336                                 Range,
337                                 ClearObjectFD,
338                                 Loc,
339                                 ClearObjectFDType);
340
341  clang::Expr *RSClearObjectFP =
342      clang::ImplicitCastExpr::Create(C,
343                                      C.getPointerType(ClearObjectFDType),
344                                      clang::CK_FunctionToPointerDecay,
345                                      RefRSClearObjectFD,
346                                      NULL,
347                                      clang::VK_RValue);
348
349  clang::CallExpr *RSClearObjectCall =
350      new(C) clang::CallExpr(C,
351                             RSClearObjectFP,
352                             &AddrRefRSVarPtrSubscript,
353                             1,
354                             ClearObjectFD->getCallResultType(),
355                             Loc);
356
357  clang::ForStmt *DestructorLoop =
358      new(C) clang::ForStmt(C,
359                            Init,
360                            Cond,
361                            NULL,  // no condVar
362                            Inc,
363                            RSClearObjectCall,
364                            Loc,
365                            Loc,
366                            Loc);
367
368  StmtArray[StmtCtr++] = DestructorLoop;
369  assert(StmtCtr == 2);
370
371  clang::CompoundStmt *CS =
372      new(C) clang::CompoundStmt(C, StmtArray, StmtCtr, Loc, Loc);
373
374  return CS;
375}
376
377}  // namespace
378
379void RSObjectRefCount::Scope::InsertLocalVarDestructors() {
380  std::list<clang::Stmt*> RSClearObjectCalls;
381  for (std::list<clang::VarDecl*>::const_iterator I = mRSO.begin(),
382          E = mRSO.end();
383        I != E;
384        I++) {
385    clang::Stmt *S = ClearRSObject(*I);
386    if (S) {
387      RSClearObjectCalls.push_back(S);
388    }
389  }
390  if (RSClearObjectCalls.size() > 0) {
391    DestructorVisitor DV((*mRSO.begin())->getASTContext(), RSClearObjectCalls);
392    DV.Visit(mCS);
393  }
394  return;
395}
396
397clang::Stmt *RSObjectRefCount::Scope::ClearRSObject(clang::VarDecl *VD) {
398  bool IsArrayType = false;
399  clang::ASTContext &C = VD->getASTContext();
400  clang::SourceLocation Loc = VD->getLocation();
401  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
402
403  // Loop through array types to get to base type
404  while (T && T->isArrayType()) {
405    T = T->getArrayElementTypeNoTypeQual();
406    IsArrayType = true;
407  }
408
409  RSExportPrimitiveType::DataType DT =
410      RSExportPrimitiveType::GetRSSpecificType(T);
411
412  assert((RSExportPrimitiveType::IsRSObjectType(DT)) &&
413      "Should be RS object");
414
415  // Find the rsClearObject() for VD of RS object type DT
416  clang::FunctionDecl *ClearObjectFD =
417      RSClearObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)];
418  assert((ClearObjectFD != NULL) &&
419      "rsClearObject doesn't cover all RS object types");
420
421  if (IsArrayType) {
422    return ClearArrayRSObject(VD, T, ClearObjectFD);
423  }
424
425  clang::QualType ClearObjectFDType = ClearObjectFD->getType();
426  clang::QualType ClearObjectFDArgType =
427      ClearObjectFD->getParamDecl(0)->getOriginalType();
428
429  // Example destructor for "rs_font localFont;"
430  //
431  // (CallExpr 'void'
432  //   (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
433  //     (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
434  //   (UnaryOperator 'rs_font *' prefix '&'
435  //     (DeclRefExpr 'rs_font':'rs_font' Var='localFont')))
436
437  // Reference expr to target RS object variable
438  clang::DeclRefExpr *RefRSVar =
439      clang::DeclRefExpr::Create(C,
440                                 NULL,
441                                 VD->getQualifierRange(),
442                                 VD,
443                                 Loc,
444                                 T->getCanonicalTypeInternal());
445
446  // Get address of RSObject in VD
447  clang::Expr *AddrRefRSVar =
448      new(C) clang::UnaryOperator(RefRSVar,
449                                  clang::UO_AddrOf,
450                                  ClearObjectFDArgType,
451                                  Loc);
452
453  clang::Expr *RefRSClearObjectFD =
454      clang::DeclRefExpr::Create(C,
455                                 NULL,
456                                 ClearObjectFD->getQualifierRange(),
457                                 ClearObjectFD,
458                                 ClearObjectFD->getLocation(),
459                                 ClearObjectFDType);
460
461  clang::Expr *RSClearObjectFP =
462      clang::ImplicitCastExpr::Create(C,
463                                      C.getPointerType(ClearObjectFDType),
464                                      clang::CK_FunctionToPointerDecay,
465                                      RefRSClearObjectFD,
466                                      NULL,
467                                      clang::VK_RValue);
468
469  clang::CallExpr *RSClearObjectCall =
470      new(C) clang::CallExpr(C,
471                             RSClearObjectFP,
472                             &AddrRefRSVar,
473                             1,
474                             ClearObjectFD->getCallResultType(),
475                             clang::SourceLocation());
476
477  return RSClearObjectCall;
478}
479
480bool RSObjectRefCount::InitializeRSObject(clang::VarDecl *VD) {
481  bool IsArrayType = false;
482  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
483
484  // Loop through array types to get to base type
485  while (T && T->isArrayType()) {
486    T = T->getArrayElementTypeNoTypeQual();
487    IsArrayType = true;
488  }
489
490  RSExportPrimitiveType::DataType DT =
491      RSExportPrimitiveType::GetRSSpecificType(T);
492
493  if (DT == RSExportPrimitiveType::DataTypeUnknown) {
494    return false;
495  }
496
497  if (VD->hasInit()) {
498    // TODO(srhines): Update the reference count of RS object in initializer.
499    // This can potentially be done as part of the assignment pass.
500  } else {
501    clang::Expr *ZeroInitializer =
502        CreateZeroInitializerForRSSpecificType(DT,
503                                               VD->getASTContext(),
504                                               VD->getLocation());
505
506    if (ZeroInitializer) {
507      ZeroInitializer->setType(T->getCanonicalTypeInternal());
508      VD->setInit(ZeroInitializer);
509    }
510  }
511
512  return RSExportPrimitiveType::IsRSObjectType(DT);
513}
514
515clang::Expr *RSObjectRefCount::CreateZeroInitializerForRSSpecificType(
516    RSExportPrimitiveType::DataType DT,
517    clang::ASTContext &C,
518    const clang::SourceLocation &Loc) {
519  clang::Expr *Res = NULL;
520  switch (DT) {
521    case RSExportPrimitiveType::DataTypeRSElement:
522    case RSExportPrimitiveType::DataTypeRSType:
523    case RSExportPrimitiveType::DataTypeRSAllocation:
524    case RSExportPrimitiveType::DataTypeRSSampler:
525    case RSExportPrimitiveType::DataTypeRSScript:
526    case RSExportPrimitiveType::DataTypeRSMesh:
527    case RSExportPrimitiveType::DataTypeRSProgramFragment:
528    case RSExportPrimitiveType::DataTypeRSProgramVertex:
529    case RSExportPrimitiveType::DataTypeRSProgramRaster:
530    case RSExportPrimitiveType::DataTypeRSProgramStore:
531    case RSExportPrimitiveType::DataTypeRSFont: {
532      //    (ImplicitCastExpr 'nullptr_t'
533      //      (IntegerLiteral 0)))
534      llvm::APInt Zero(C.getTypeSize(C.IntTy), 0);
535      clang::Expr *Int0 = clang::IntegerLiteral::Create(C, Zero, C.IntTy, Loc);
536      clang::Expr *CastToNull =
537          clang::ImplicitCastExpr::Create(C,
538                                          C.NullPtrTy,
539                                          clang::CK_IntegralToPointer,
540                                          Int0,
541                                          NULL,
542                                          clang::VK_RValue);
543
544      Res = new(C) clang::InitListExpr(C, Loc, &CastToNull, 1, Loc);
545      break;
546    }
547    case RSExportPrimitiveType::DataTypeRSMatrix2x2:
548    case RSExportPrimitiveType::DataTypeRSMatrix3x3:
549    case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
550      // RS matrix is not completely an RS object. They hold data by themselves.
551      // (InitListExpr rs_matrix2x2
552      //   (InitListExpr float[4]
553      //     (FloatingLiteral 0)
554      //     (FloatingLiteral 0)
555      //     (FloatingLiteral 0)
556      //     (FloatingLiteral 0)))
557      clang::QualType FloatTy = C.FloatTy;
558      // Constructor sets value to 0.0f by default
559      llvm::APFloat Val(C.getFloatTypeSemantics(FloatTy));
560      clang::FloatingLiteral *Float0Val =
561          clang::FloatingLiteral::Create(C,
562                                         Val,
563                                         /* isExact = */true,
564                                         FloatTy,
565                                         Loc);
566
567      unsigned N = 0;
568      if (DT == RSExportPrimitiveType::DataTypeRSMatrix2x2)
569        N = 2;
570      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix3x3)
571        N = 3;
572      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix4x4)
573        N = 4;
574
575      // Directly allocate 16 elements instead of dynamically allocate N*N
576      clang::Expr *InitVals[16];
577      for (unsigned i = 0; i < sizeof(InitVals) / sizeof(InitVals[0]); i++)
578        InitVals[i] = Float0Val;
579      clang::Expr *InitExpr =
580          new(C) clang::InitListExpr(C, Loc, InitVals, N * N, Loc);
581      InitExpr->setType(C.getConstantArrayType(FloatTy,
582                                               llvm::APInt(32, 4),
583                                               clang::ArrayType::Normal,
584                                               /* EltTypeQuals = */0));
585
586      Res = new(C) clang::InitListExpr(C, Loc, &InitExpr, 1, Loc);
587      break;
588    }
589    case RSExportPrimitiveType::DataTypeUnknown:
590    case RSExportPrimitiveType::DataTypeFloat16:
591    case RSExportPrimitiveType::DataTypeFloat32:
592    case RSExportPrimitiveType::DataTypeFloat64:
593    case RSExportPrimitiveType::DataTypeSigned8:
594    case RSExportPrimitiveType::DataTypeSigned16:
595    case RSExportPrimitiveType::DataTypeSigned32:
596    case RSExportPrimitiveType::DataTypeSigned64:
597    case RSExportPrimitiveType::DataTypeUnsigned8:
598    case RSExportPrimitiveType::DataTypeUnsigned16:
599    case RSExportPrimitiveType::DataTypeUnsigned32:
600    case RSExportPrimitiveType::DataTypeUnsigned64:
601    case RSExportPrimitiveType::DataTypeBoolean:
602    case RSExportPrimitiveType::DataTypeUnsigned565:
603    case RSExportPrimitiveType::DataTypeUnsigned5551:
604    case RSExportPrimitiveType::DataTypeUnsigned4444:
605    case RSExportPrimitiveType::DataTypeMax: {
606      assert(false && "Not RS object type!");
607    }
608    // No default case will enable compiler detecting the missing cases
609  }
610
611  return Res;
612}
613
614void RSObjectRefCount::VisitDeclStmt(clang::DeclStmt *DS) {
615  for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
616       I != E;
617       I++) {
618    clang::Decl *D = *I;
619    if (D->getKind() == clang::Decl::Var) {
620      clang::VarDecl *VD = static_cast<clang::VarDecl*>(D);
621      if (InitializeRSObject(VD))
622        getCurrentScope()->addRSObject(VD);
623    }
624  }
625  return;
626}
627
628void RSObjectRefCount::VisitCompoundStmt(clang::CompoundStmt *CS) {
629  if (!CS->body_empty()) {
630    // Push a new scope
631    Scope *S = new Scope(CS);
632    mScopeStack.push(S);
633
634    VisitStmt(CS);
635
636    // Destroy the scope
637    // TODO(srhines): Update reference count of the RS object refenced by
638    //                getCurrentScope().
639    assert((getCurrentScope() == S) && "Corrupted scope stack!");
640    S->InsertLocalVarDestructors();
641    mScopeStack.pop();
642    delete S;
643  }
644  return;
645}
646
647void RSObjectRefCount::VisitBinAssign(clang::BinaryOperator *AS) {
648  // TODO(srhines): Update reference count
649  return;
650}
651
652void RSObjectRefCount::VisitStmt(clang::Stmt *S) {
653  for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
654       I != E;
655       I++) {
656    if (clang::Stmt *Child = *I) {
657      Visit(Child);
658    }
659  }
660  return;
661}
662
663}  // namespace slang
664