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_export_func.h" 18 19 #include <string> 20 21 #include "clang/AST/ASTContext.h" 22 #include "clang/AST/Decl.h" 23 24 #include "llvm/IR/DataLayout.h" 25 #include "llvm/IR/DerivedTypes.h" 26 27 #include "slang_assert.h" 28 #include "slang_rs_context.h" 29 30 namespace slang { 31 32 namespace { 33 34 // Ensure that the exported function is actually valid 35 static bool ValidateFuncDecl(slang::RSContext *Context, 36 const clang::FunctionDecl *FD) { 37 slangAssert(Context && FD); 38 const clang::ASTContext &C = FD->getASTContext(); 39 if (FD->getReturnType().getCanonicalType() != C.VoidTy) { 40 Context->ReportError( 41 FD->getLocation(), 42 "invokable non-static functions are required to return void"); 43 return false; 44 } 45 return true; 46 } 47 48 } // namespace 49 50 RSExportFunc *RSExportFunc::Create(RSContext *Context, 51 const clang::FunctionDecl *FD) { 52 llvm::StringRef Name = FD->getName(); 53 RSExportFunc *F; 54 55 slangAssert(!Name.empty() && "Function must have a name"); 56 57 if (!ValidateFuncDecl(Context, FD)) { 58 return NULL; 59 } 60 61 F = new RSExportFunc(Context, Name, FD); 62 63 // Initialize mParamPacketType 64 if (FD->getNumParams() <= 0) { 65 F->mParamPacketType = NULL; 66 } else { 67 clang::ASTContext &Ctx = Context->getASTContext(); 68 69 std::string Id = CreateDummyName("helper_func_param", F->getName()); 70 71 clang::RecordDecl *RD = 72 clang::RecordDecl::Create(Ctx, clang::TTK_Struct, 73 Ctx.getTranslationUnitDecl(), 74 clang::SourceLocation(), 75 clang::SourceLocation(), 76 &Ctx.Idents.get(Id)); 77 78 for (unsigned i = 0; i < FD->getNumParams(); i++) { 79 const clang::ParmVarDecl *PVD = FD->getParamDecl(i); 80 llvm::StringRef ParamName = PVD->getName(); 81 82 if (PVD->hasDefaultArg()) 83 fprintf(stderr, "Note: parameter '%s' in function '%s' has default " 84 "value which is not supported\n", 85 ParamName.str().c_str(), 86 F->getName().c_str()); 87 88 clang::FieldDecl *FD = 89 clang::FieldDecl::Create(Ctx, 90 RD, 91 clang::SourceLocation(), 92 clang::SourceLocation(), 93 PVD->getIdentifier(), 94 PVD->getOriginalType(), 95 NULL, 96 /* BitWidth = */ NULL, 97 /* Mutable = */ false, 98 /* HasInit = */ clang::ICIS_NoInit); 99 RD->addDecl(FD); 100 } 101 102 RD->completeDefinition(); 103 104 clang::QualType T = Ctx.getTagDeclType(RD); 105 slangAssert(!T.isNull()); 106 107 RSExportType *ET = 108 RSExportType::Create(Context, T.getTypePtr()); 109 110 if (ET == NULL) { 111 fprintf(stderr, "Failed to export the function %s. There's at least one " 112 "parameter whose type is not supported by the " 113 "reflection\n", F->getName().c_str()); 114 return NULL; 115 } 116 117 slangAssert((ET->getClass() == RSExportType::ExportClassRecord) && 118 "Parameter packet must be a record"); 119 120 F->mParamPacketType = static_cast<RSExportRecordType *>(ET); 121 } 122 123 return F; 124 } 125 126 bool 127 RSExportFunc::checkParameterPacketType(llvm::StructType *ParamTy) const { 128 if (ParamTy == NULL) 129 return !hasParam(); 130 else if (!hasParam()) 131 return false; 132 133 slangAssert(mParamPacketType != NULL); 134 135 const RSExportRecordType *ERT = mParamPacketType; 136 // must have same number of elements 137 if (ERT->getFields().size() != ParamTy->getNumElements()) 138 return false; 139 140 const llvm::StructLayout *ParamTySL = 141 getRSContext()->getDataLayout()->getStructLayout(ParamTy); 142 143 unsigned Index = 0; 144 for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(), 145 FE = ERT->fields_end(); FI != FE; FI++, Index++) { 146 const RSExportRecordType::Field *F = *FI; 147 148 llvm::Type *T1 = F->getType()->getLLVMType(); 149 llvm::Type *T2 = ParamTy->getTypeAtIndex(Index); 150 151 // Fast check 152 if (T1 == T2) 153 continue; 154 155 // Check offset 156 size_t T1Offset = F->getOffsetInParent(); 157 size_t T2Offset = ParamTySL->getElementOffset(Index); 158 159 if (T1Offset != T2Offset) 160 return false; 161 162 // Check size 163 size_t T1Size = F->getType()->getAllocSize(); 164 size_t T2Size = getRSContext()->getDataLayout()->getTypeAllocSize(T2); 165 166 if (T1Size != T2Size) 167 return false; 168 } 169 170 return true; 171 } 172 173 } // namespace slang 174