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