slang_rs_object_ref_count.cpp revision e639eb5caa2c386b4a60659a4929e8a6141a2cbe
14b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines/* 24b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * Copyright 2010, The Android Open Source Project 34b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * 44b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * Licensed under the Apache License, Version 2.0 (the "License"); 54b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * you may not use this file except in compliance with the License. 64b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * You may obtain a copy of the License at 74b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * 84b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * http://www.apache.org/licenses/LICENSE-2.0 94b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * 104b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * Unless required by applicable law or agreed to in writing, software 114b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * distributed under the License is distributed on an "AS IS" BASIS, 124b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * See the License for the specific language governing permissions and 144b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines * limitations under the License. 154b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines */ 164b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 174b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines#include "slang_rs_object_ref_count.h" 184b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 19e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines#include <list> 20e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines 214b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines#include "clang/AST/DeclGroup.h" 224b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines#include "clang/AST/Expr.h" 234b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines#include "clang/AST/OperationKinds.h" 244b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines#include "clang/AST/Stmt.h" 254b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines#include "clang/AST/StmtVisitor.h" 264b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 274b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines#include "slang_rs.h" 284b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines#include "slang_rs_export_type.h" 294b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 30e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hinesnamespace slang { 314b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 321bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hinesclang::FunctionDecl *RSObjectRefCount::Scope:: 331bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSSetObjectFD[RSExportPrimitiveType::LastRSObjectType - 341bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSExportPrimitiveType::FirstRSObjectType + 1]; 351bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hinesclang::FunctionDecl *RSObjectRefCount::Scope:: 361bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSClearObjectFD[RSExportPrimitiveType::LastRSObjectType - 371bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSExportPrimitiveType::FirstRSObjectType + 1]; 381bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 391bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hinesvoid RSObjectRefCount::Scope::GetRSRefCountingFunctions( 401bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::ASTContext &C) { 411bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines for (unsigned i = 0; 421bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines i < (sizeof(RSClearObjectFD) / sizeof(clang::FunctionDecl*)); 431bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines i++) { 441bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSSetObjectFD[i] = NULL; 451bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSClearObjectFD[i] = NULL; 461bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 471bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 481bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl(); 491bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 501bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(), 511bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines E = TUDecl->decls_end(); I != E; I++) { 521bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines if ((I->getKind() >= clang::Decl::firstFunction) && 531bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines (I->getKind() <= clang::Decl::lastFunction)) { 541bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::FunctionDecl *FD = static_cast<clang::FunctionDecl*>(*I); 551bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 561bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // points to RSSetObjectFD or RSClearObjectFD 571bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::FunctionDecl **RSObjectFD; 581bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 591bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines if (FD->getName() == "rsSetObject") { 601bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines assert((FD->getNumParams() == 2) && 611bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines "Invalid rsSetObject function prototype (# params)"); 621bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSObjectFD = RSSetObjectFD; 631bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } else if (FD->getName() == "rsClearObject") { 641bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines assert((FD->getNumParams() == 1) && 651bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines "Invalid rsClearObject function prototype (# params)"); 661bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSObjectFD = RSClearObjectFD; 67e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines } else { 681bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines continue; 691bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 701bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 711bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines const clang::ParmVarDecl *PVD = FD->getParamDecl(0); 721bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::QualType PVT = PVD->getOriginalType(); 731bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // The first parameter must be a pointer like rs_allocation* 741bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines assert(PVT->isPointerType() && 751bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines "Invalid rs{Set,Clear}Object function prototype (pointer param)"); 761bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 771bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // The rs object type passed to the FD 781bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::QualType RST = PVT->getPointeeType(); 791bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSExportPrimitiveType::DataType DT = 801bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSExportPrimitiveType::GetRSSpecificType(RST.getTypePtr()); 811bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines assert(RSExportPrimitiveType::IsRSObjectType(DT) 821bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines && "must be RS object type"); 831bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 841bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)] = FD; 851bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 861bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 871bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines} 881bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 891bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hinesvoid RSObjectRefCount::Scope::AppendToCompoundStatement( 901bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::ASTContext& C, std::list<clang::Expr*> &ExprList) { 911bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // Destructor code will be inserted before any return statement. 921bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // Any subsequent statements in the compound statement are then placed 931bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // after our new code. 94e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines // TODO(srhines): This should also handle the case of goto/break/continue. 951bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::CompoundStmt::body_iterator bI = mCS->body_begin(); 961bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::CompoundStmt::body_iterator bE = mCS->body_end(); 971bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 981bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines unsigned OldStmtCount = 0; 991bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines for ( ; bI != bE; bI++) { 1001bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines OldStmtCount++; 1011bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 1021bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1031bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines unsigned NewExprCount = ExprList.size(); 1041bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1051bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::Stmt **StmtList; 1061bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines StmtList = new clang::Stmt*[OldStmtCount+NewExprCount]; 1071bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1081bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines unsigned UpdatedStmtCount = 0; 1091bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines for (bI = mCS->body_begin(); bI != bE; bI++) { 1101bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines if ((*bI)->getStmtClass() == clang::Stmt::ReturnStmtClass) { 1111bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines break; 1121bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 1131bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines StmtList[UpdatedStmtCount++] = *bI; 1141bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 1151bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1161bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines std::list<clang::Expr*>::const_iterator E = ExprList.end(); 1171bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines for (std::list<clang::Expr*>::const_iterator I = ExprList.begin(), 1181bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines E = ExprList.end(); 1191bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines I != E; 1201bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines I++) { 1211bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines StmtList[UpdatedStmtCount++] = *I; 1221bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 1231bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1241bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // Pick up anything left over after a return statement 1251bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines for ( ; bI != bE; bI++) { 1261bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines StmtList[UpdatedStmtCount++] = *bI; 1271bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 1281bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1291bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines mCS->setStmts(C, StmtList, UpdatedStmtCount); 1301bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines assert(UpdatedStmtCount == (OldStmtCount + NewExprCount)); 1311bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1321bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines delete [] StmtList; 1331bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1341bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines return; 1351bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines} 1361bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1371bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hinesvoid RSObjectRefCount::Scope::InsertLocalVarDestructors() { 1381bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines std::list<clang::Expr*> RSClearObjectCalls; 1391bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines for (std::list<clang::VarDecl*>::const_iterator I = mRSO.begin(), 1401bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines E = mRSO.end(); 1411bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines I != E; 1421bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines I++) { 1431bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::Expr *E = ClearRSObject(*I); 1441bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines if (E) { 1451bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSClearObjectCalls.push_back(E); 1461bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 1471bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 1481bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines if (RSClearObjectCalls.size() > 0) { 1491bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::ASTContext &C = (*mRSO.begin())->getASTContext(); 1501bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines AppendToCompoundStatement(C, RSClearObjectCalls); 151e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines // TODO(srhines): This should also be extended to append destructors to any 1521bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // further nested scope (we need another visitor here from within the 1531bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // current compound statement in case they call return/goto). 1541bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines } 1551bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines return; 1561bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines} 1571bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1581bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hinesclang::Expr *RSObjectRefCount::Scope::ClearRSObject(clang::VarDecl *VD) { 1591bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::ASTContext &C = VD->getASTContext(); 1601bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::SourceLocation Loc = VD->getLocation(); 1611bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines const clang::Type *T = RSExportType::GetTypeOfDecl(VD); 1621bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSExportPrimitiveType::DataType DT = 1631bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSExportPrimitiveType::GetRSSpecificType(T); 1641bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1651bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines assert((RSExportPrimitiveType::IsRSObjectType(DT)) && 1661bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines "Should be RS object"); 1671bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1681bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // Find the rsClearObject() for VD of RS object type DT 1691bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::FunctionDecl *ClearObjectFD = 1701bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RSClearObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)]; 1711bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines assert((ClearObjectFD != NULL) && 1721bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines "rsClearObject doesn't cover all RS object types"); 1731bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1741bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::QualType ClearObjectFDType = ClearObjectFD->getType(); 1751bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::QualType ClearObjectFDArgType = 1761bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines ClearObjectFD->getParamDecl(0)->getOriginalType(); 1771bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1781bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // We generate a call to rsClearObject passing &VD as the parameter 1791bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // (CallExpr 'void' 1801bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay> 1811bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject')) 1821bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // (UnaryOperator 'rs_font *' prefix '&' 1831bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // (DeclRefExpr 'rs_font':'rs_font' Var='[var name]'))) 1841bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1851bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // Reference expr to target RS object variable 1861bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::DeclRefExpr *RefRSVar = 1871bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::DeclRefExpr::Create(C, 1881bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines NULL, 1891bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines VD->getQualifierRange(), 1901bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines VD, 1911bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines Loc, 1921bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines T->getCanonicalTypeInternal(), 1931bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines NULL); 1941bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 1951bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines // Get address of RSObject in VD 1961bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::Expr *AddrRefRSVar = 197e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines new(C) clang::UnaryOperator(RefRSVar, 198e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines clang::UO_AddrOf, 199e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines ClearObjectFDArgType, 200e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines Loc); 2011bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 2021bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::Expr *RefRSClearObjectFD = 2031bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::DeclRefExpr::Create(C, 2041bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines NULL, 2051bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines ClearObjectFD->getQualifierRange(), 2061bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines ClearObjectFD, 2071bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines ClearObjectFD->getLocation(), 2081bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines ClearObjectFDType, 2091bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines NULL); 2101bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 2111bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::Expr *RSClearObjectFP = 2121bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::ImplicitCastExpr::Create(C, 2131bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines C.getPointerType(ClearObjectFDType), 2141bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::CK_FunctionToPointerDecay, 2151bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines RefRSClearObjectFD, 2161bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines NULL, 2171bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::VK_RValue); 2181bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 2191bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines clang::CallExpr *RSClearObjectCall = 220e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines new(C) clang::CallExpr(C, 221e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines RSClearObjectFP, 222e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines &AddrRefRSVar, 223e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines 1, 224e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines ClearObjectFD->getCallResultType(), 225e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines clang::SourceLocation()); 2261bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 2271bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines return RSClearObjectCall; 2281bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines} 2291bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines 2304b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hinesbool RSObjectRefCount::InitializeRSObject(clang::VarDecl *VD) { 2314b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines const clang::Type *T = RSExportType::GetTypeOfDecl(VD); 2324b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines RSExportPrimitiveType::DataType DT = 2334b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines RSExportPrimitiveType::GetRSSpecificType(T); 2344b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 2354b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines if (DT == RSExportPrimitiveType::DataTypeUnknown) 2364b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines return false; 2374b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 2384b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines if (VD->hasInit()) { 239e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines // TODO(srhines): Update the reference count of RS object in initializer. 2404b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // This can potentially be done as part of the assignment pass. 2414b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } else { 2424b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::Expr *ZeroInitializer = 2434b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines CreateZeroInitializerForRSSpecificType(DT, 2444b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines VD->getASTContext(), 2454b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines VD->getLocation()); 2464b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 2474b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines if (ZeroInitializer) { 2484b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines ZeroInitializer->setType(T->getCanonicalTypeInternal()); 2494b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines VD->setInit(ZeroInitializer); 2504b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } 2514b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } 2524b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 2534b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines return RSExportPrimitiveType::IsRSObjectType(DT); 2544b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines} 2554b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 2564b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hinesclang::Expr *RSObjectRefCount::CreateZeroInitializerForRSSpecificType( 2574b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines RSExportPrimitiveType::DataType DT, 2584b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::ASTContext &C, 2594b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines const clang::SourceLocation &Loc) { 2604b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::Expr *Res = NULL; 2614b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines switch (DT) { 2624b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSElement: 2634b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSType: 2644b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSAllocation: 2654b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSSampler: 2664b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSScript: 2674b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSMesh: 2684b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSProgramFragment: 2694b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSProgramVertex: 2704b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSProgramRaster: 2714b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSProgramStore: 2724b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSFont: { 2734b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // (ImplicitCastExpr 'nullptr_t' 2744b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // (IntegerLiteral 0))) 2754b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines llvm::APInt Zero(C.getTypeSize(C.IntTy), 0); 2764b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::Expr *Int0 = clang::IntegerLiteral::Create(C, Zero, C.IntTy, Loc); 2774b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::Expr *CastToNull = 2784b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::ImplicitCastExpr::Create(C, 2794b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines C.NullPtrTy, 2804b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::CK_IntegralToPointer, 2814b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines Int0, 2824b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines NULL, 2834b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::VK_RValue); 2844b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 285e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines Res = new(C) clang::InitListExpr(C, Loc, &CastToNull, 1, Loc); 2864b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines break; 2874b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } 2884b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSMatrix2x2: 2894b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSMatrix3x3: 2904b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeRSMatrix4x4: { 2914b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // RS matrix is not completely an RS object. They hold data by themselves. 2924b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // (InitListExpr rs_matrix2x2 2934b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // (InitListExpr float[4] 2944b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // (FloatingLiteral 0) 2954b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // (FloatingLiteral 0) 2964b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // (FloatingLiteral 0) 2974b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // (FloatingLiteral 0))) 2984b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::QualType FloatTy = C.FloatTy; 2994b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // Constructor sets value to 0.0f by default 3004b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines llvm::APFloat Val(C.getFloatTypeSemantics(FloatTy)); 3014b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::FloatingLiteral *Float0Val = 3024b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::FloatingLiteral::Create(C, 3034b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines Val, 3044b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines /* isExact = */true, 3054b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines FloatTy, 3064b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines Loc); 3074b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 3084b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines unsigned N = 0; 3094b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines if (DT == RSExportPrimitiveType::DataTypeRSMatrix2x2) 3104b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines N = 2; 3114b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines else if (DT == RSExportPrimitiveType::DataTypeRSMatrix3x3) 3124b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines N = 3; 3134b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines else if (DT == RSExportPrimitiveType::DataTypeRSMatrix4x4) 3144b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines N = 4; 3154b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 3164b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // Directly allocate 16 elements instead of dynamically allocate N*N 3174b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::Expr *InitVals[16]; 3184b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines for (unsigned i = 0; i < sizeof(InitVals) / sizeof(InitVals[0]); i++) 3194b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines InitVals[i] = Float0Val; 3204b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::Expr *InitExpr = 321e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines new(C) clang::InitListExpr(C, Loc, InitVals, N * N, Loc); 3224b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines InitExpr->setType(C.getConstantArrayType(FloatTy, 3234b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines llvm::APInt(32, 4), 3244b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::ArrayType::Normal, 3254b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines /* EltTypeQuals = */0)); 3264b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 327e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines Res = new(C) clang::InitListExpr(C, Loc, &InitExpr, 1, Loc); 3284b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines break; 3294b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } 3304b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeUnknown: 3314b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeFloat16: 3324b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeFloat32: 3334b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeFloat64: 3344b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeSigned8: 3354b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeSigned16: 3364b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeSigned32: 3374b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeSigned64: 3384b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeUnsigned8: 3394b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeUnsigned16: 3404b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeUnsigned32: 3414b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeUnsigned64: 3424b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeBoolean: 3434b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeUnsigned565: 3444b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeUnsigned5551: 3454b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeUnsigned4444: 3464b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines case RSExportPrimitiveType::DataTypeMax: { 3474b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines assert(false && "Not RS object type!"); 3484b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } 3494b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // No default case will enable compiler detecting the missing cases 3504b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } 3514b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 3524b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines return Res; 3534b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines} 3544b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 3554b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hinesvoid RSObjectRefCount::VisitDeclStmt(clang::DeclStmt *DS) { 3564b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); 3574b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines I != E; 3584b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines I++) { 3594b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::Decl *D = *I; 3604b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines if (D->getKind() == clang::Decl::Var) { 3614b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines clang::VarDecl *VD = static_cast<clang::VarDecl*>(D); 3624b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines if (InitializeRSObject(VD)) 3634b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines getCurrentScope()->addRSObject(VD); 3644b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } 3654b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } 3664b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines return; 3674b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines} 3684b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 3694b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hinesvoid RSObjectRefCount::VisitCompoundStmt(clang::CompoundStmt *CS) { 3704b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines if (!CS->body_empty()) { 3714b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // Push a new scope 3724b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines Scope *S = new Scope(CS); 3734b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines mScopeStack.push(S); 3744b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 3754b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines VisitStmt(CS); 3764b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 3774b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines // Destroy the scope 378e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines // TODO(srhines): Update reference count of the RS object refenced by 379e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines // getCurrentScope(). 3804b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines assert((getCurrentScope() == S) && "Corrupted scope stack!"); 3811bdd4978caabcdc9489bdcb7f1cd6087340699e8Stephen Hines S->InsertLocalVarDestructors(); 3824b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines mScopeStack.pop(); 3834b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines delete S; 3844b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } 3854b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines return; 3864b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines} 3874b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 3884b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hinesvoid RSObjectRefCount::VisitBinAssign(clang::BinaryOperator *AS) { 389e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines // TODO(srhines): Update reference count 3904b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines return; 3914b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines} 3924b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 3934b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hinesvoid RSObjectRefCount::VisitStmt(clang::Stmt *S) { 3944b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end(); 3954b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines I != E; 3964b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines I++) { 3974b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines if (clang::Stmt *Child = *I) { 3984b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines Visit(Child); 3994b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } 4004b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines } 4014b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines return; 4024b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines} 4034b32ffdfc1ac766f8932e7effbcdf7484e804a8eStephen Hines 404e639eb5caa2c386b4a60659a4929e8a6141a2cbeStephen Hines} // namespace slang 405