slang_rs.cpp revision 641558f02fe6ce0ee3ae5076eb366c25e2ad5903
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.h"
18
19#include <cstring>
20
21#include "clang/Frontend/FrontendDiagnostic.h"
22
23#include "clang/Sema/SemaDiagnostic.h"
24
25#include "slang_rs_backend.h"
26#include "slang_rs_context.h"
27#include "slang_rs_export_type.h"
28
29using namespace slang;
30
31#define RS_HEADER_SUFFIX  "rsh"
32
33#define ENUM_RS_HEADER()  \
34  RS_HEADER_ENTRY(rs_types) \
35  RS_HEADER_ENTRY(rs_cl) \
36  RS_HEADER_ENTRY(rs_core) \
37  RS_HEADER_ENTRY(rs_math)
38
39#define RS_HEADER_ENTRY(x)  \
40  extern const char x ## _header[]; \
41  extern unsigned x ## _header_size;
42ENUM_RS_HEADER()
43#undef RS_HEADER_ENTRY
44
45bool SlangRS::reflectToJava(const std::string &OutputPathBase,
46                            const std::string &OutputPackageName,
47                            std::string *RealPackageName) {
48  return mRSContext->reflectToJava(OutputPathBase,
49                                   OutputPackageName,
50                                   getInputFileName(),
51                                   getOutputFileName(),
52                                   RealPackageName);
53}
54
55bool SlangRS::generateBitcodeAccessor(const std::string &OutputPathBase,
56                                      const std::string &PackageName) {
57  RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext;
58
59  BCAccessorContext.rsFileName = getInputFileName().c_str();
60  BCAccessorContext.bcFileName = getOutputFileName().c_str();
61  BCAccessorContext.reflectPath = OutputPathBase.c_str();
62  BCAccessorContext.packageName = PackageName.c_str();
63  BCAccessorContext.bcStorage = BCST_JAVA_CODE;   // Must be BCST_JAVA_CODE
64
65  return RSSlangReflectUtils::GenerateBitCodeAccessor(BCAccessorContext);
66}
67
68bool SlangRS::checkODR() {
69  for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(),
70          E = mRSContext->exportable_end();
71       I != E;
72       I++) {
73    RSExportable *E = *I;
74    if (E->getKind() != RSExportable::EX_TYPE)
75      continue;
76
77    RSExportType *ET = static_cast<RSExportType *>(E);
78    if (ET->getClass() != RSExportType::ExportClassRecord)
79      continue;
80
81    RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET);
82
83    // Artificial record types (create by us not by user in the source) always
84    // conforms the ODR.
85    if (ERT->isArtificial())
86      continue;
87
88    // Key to lookup ERT in ReflectedDefinitions
89    llvm::StringRef RDKey(ERT->getName());
90    ReflectedDefinitionListTy::const_iterator RD =
91        ReflectedDefinitions.find(RDKey);
92
93    if (RD != ReflectedDefinitions.end()) {
94      const RSExportRecordType *Reflected = RD->getValue().first;
95      // There's a record (struct) with the same name reflected before. Enforce
96      // ODR checking - the Reflected must hold *exactly* the same "definition"
97      // as the one defined previously. We say two record types A and B have the
98      // same definition iff:
99      //
100      //  struct A {              struct B {
101      //    Type(a1) a1,            Type(b1) b1,
102      //    Type(a2) a2,            Type(b1) b2,
103      //    ...                     ...
104      //    Type(aN) aN             Type(b3) b3,
105      //  };                      }
106      //  Cond. #1. They have same number of fields, i.e., N = M;
107      //  Cond. #2. for (i := 1 to N)
108      //              Type(ai) = Type(bi) must hold;
109      //  Cond. #3. for (i := 1 to N)
110      //              Name(ai) = Name(bi) must hold;
111      //
112      // where,
113      //  Type(F) = the type of field F and
114      //  Name(F) = the field name.
115
116      bool PassODR = false;
117      // Cond. #1 and Cond. #2
118      if (Reflected->equals(ERT)) {
119        // Cond #3.
120        RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(),
121                                                 BI = ERT->fields_begin();
122
123        for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) {
124          if ((*AI)->getName() != (*BI)->getName())
125            break;
126          AI++;
127          BI++;
128        }
129        PassODR = (AI == (Reflected->fields_end()));
130      }
131
132      if (!PassODR) {
133        getDiagnostics().Report(mDiagErrorODR) << Reflected->getName()
134                                               << getInputFileName()
135                                               << RD->getValue().second;
136        return false;
137      }
138    } else {
139      llvm::StringMapEntry<ReflectedDefinitionTy> *ME =
140          llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(),
141                                                              RDKey.end());
142      ME->setValue(std::make_pair(ERT, getInputFileName().c_str()));
143
144      if (!ReflectedDefinitions.insert(ME))
145        delete ME;
146
147      // Take the ownership of ERT such that it won't be freed in ~RSContext().
148      ERT->keep();
149    }
150
151  }
152  return true;
153}
154
155void SlangRS::initDiagnostic() {
156  clang::Diagnostic &Diag = getDiagnostics();
157  if (Diag.setDiagnosticGroupMapping("implicit-function-declaration",
158                                     clang::diag::MAP_ERROR))
159    Diag.Report(clang::diag::warn_unknown_warning_option)
160        << "implicit-function-declaration";
161
162  Diag.setDiagnosticMapping(
163      clang::diag::ext_typecheck_convert_discards_qualifiers,
164      clang::diag::MAP_ERROR);
165
166  mDiagErrorInvalidOutputDepParameter =
167      Diag.getCustomDiagID(clang::Diagnostic::Error,
168                           "invalid parameter for output dependencies files.");
169
170  mDiagErrorODR =
171      Diag.getCustomDiagID(clang::Diagnostic::Error,
172                           "type '%0' in different translation unit (%1 v.s. "
173                           "%2) has incompatible type definition");
174
175  return;
176}
177
178void SlangRS::initPreprocessor() {
179  clang::Preprocessor &PP = getPreprocessor();
180
181  std::string RSH;
182#define RS_HEADER_ENTRY(x)  \
183  RSH.append("#line 1 \"" #x "."RS_HEADER_SUFFIX"\"\n"); \
184  RSH.append(x ## _header, x ## _header_size);
185ENUM_RS_HEADER()
186#undef RS_HEADER_ENTRY
187  PP.setPredefines(RSH);
188
189  return;
190}
191
192void SlangRS::initASTContext() {
193  mRSContext = new RSContext(&getPreprocessor(),
194                             &getASTContext(),
195                             &getTargetInfo());
196  return;
197}
198
199clang::ASTConsumer
200*SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts,
201                        llvm::raw_ostream *OS,
202                        Slang::OutputType OT) {
203    return new RSBackend(mRSContext,
204                         getDiagnostics(),
205                         CodeGenOpts,
206                         getTargetOptions(),
207                         mPragmas,
208                         OS,
209                         OT,
210                         getSourceManager(),
211                         mAllowRSPrefix);
212}
213
214bool SlangRS::IsRSHeaderFile(const char *File) {
215#define RS_HEADER_ENTRY(x)  \
216  if (::strcmp(File, #x "."RS_HEADER_SUFFIX) == 0)  \
217    return true;
218ENUM_RS_HEADER()
219#undef RS_HEADER_ENTRY
220  // Deal with rs_graphics.rsh special case
221  if (::strcmp(File, "rs_graphics."RS_HEADER_SUFFIX) == 0)
222    return true;
223  return false;
224}
225
226SlangRS::SlangRS() : Slang(), mRSContext(NULL), mAllowRSPrefix(false) {
227  return;
228}
229
230bool SlangRS::compile(
231    const std::list<std::pair<const char*, const char*> > &IOFiles,
232    const std::list<std::pair<const char*, const char*> > &DepFiles,
233    const std::vector<std::string> &IncludePaths,
234    const std::vector<std::string> &AdditionalDepTargets,
235    Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage,
236    bool AllowRSPrefix, bool OutputDep,
237    const std::string &JavaReflectionPathBase,
238    const std::string &JavaReflectionPackageName) {
239  if (IOFiles.empty())
240    return true;
241
242  if (OutputDep && (DepFiles.size() != IOFiles.size())) {
243    getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter);
244    return false;
245  }
246
247  std::string RealPackageName;
248
249  const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile;
250  std::list<std::pair<const char*, const char*> >::const_iterator
251      IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin();
252
253  setIncludePaths(IncludePaths);
254  setOutputType(OutputType);
255  if (OutputDep)
256    setAdditionalDepTargets(AdditionalDepTargets);
257
258  mAllowRSPrefix = AllowRSPrefix;
259
260  for (unsigned i = 0, e = IOFiles.size(); i != e; i++) {
261    InputFile = IOFileIter->first;
262    OutputFile = IOFileIter->second;
263
264    reset();
265
266    if (!setInputSource(InputFile))
267      return false;
268
269    if (!setOutput(OutputFile))
270      return false;
271
272    if (OutputDep) {
273      BCOutputFile = DepFileIter->first;
274      DepOutputFile = DepFileIter->second;
275
276      setDepTargetBC(BCOutputFile);
277
278      if (!setDepOutput(DepOutputFile))
279        return false;
280
281      if (generateDepFile() > 0)
282        return false;
283
284      DepFileIter++;
285    }
286
287    if (Slang::compile() > 0)
288      return false;
289
290    if (OutputType != Slang::OT_Dependency) {
291      if (!reflectToJava(JavaReflectionPathBase,
292                         JavaReflectionPackageName,
293                         &RealPackageName))
294        return false;
295
296      if ((OutputType == Slang::OT_Bitcode) &&
297          (BitcodeStorage == BCST_JAVA_CODE) &&
298          !generateBitcodeAccessor(JavaReflectionPathBase,
299                                     RealPackageName.c_str()))
300          return false;
301    }
302
303    if (!checkODR())
304      return false;
305
306    IOFileIter++;
307  }
308
309  return true;
310}
311
312void SlangRS::reset() {
313  delete mRSContext;
314  mRSContext = NULL;
315  Slang::reset();
316  return;
317}
318
319SlangRS::~SlangRS() {
320  delete mRSContext;
321  for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(),
322          E = ReflectedDefinitions.end();
323       I != E;
324       I++) {
325    delete I->getValue().first;
326  }
327  return;
328}
329