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