Home | History | Annotate | Download | only in slang
      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 #include <list>
     21 #include <sstream>
     22 #include <string>
     23 #include <utility>
     24 #include <vector>
     25 
     26 #include "clang/Basic/SourceLocation.h"
     27 
     28 #include "clang/Frontend/FrontendDiagnostic.h"
     29 
     30 #include "clang/Sema/SemaDiagnostic.h"
     31 
     32 #include "llvm/Support/Path.h"
     33 
     34 #include "os_sep.h"
     35 #include "slang_rs_backend.h"
     36 #include "slang_rs_context.h"
     37 #include "slang_rs_export_type.h"
     38 
     39 #include "slang_rs_reflection_cpp.h"
     40 
     41 namespace slang {
     42 
     43 #define RS_HEADER_SUFFIX  "rsh"
     44 
     45 /* RS_HEADER_ENTRY(name) */
     46 #define ENUM_RS_HEADER()  \
     47   RS_HEADER_ENTRY(rs_allocation) \
     48   RS_HEADER_ENTRY(rs_atomic) \
     49   RS_HEADER_ENTRY(rs_cl) \
     50   RS_HEADER_ENTRY(rs_core) \
     51   RS_HEADER_ENTRY(rs_debug) \
     52   RS_HEADER_ENTRY(rs_element) \
     53   RS_HEADER_ENTRY(rs_graphics) \
     54   RS_HEADER_ENTRY(rs_math) \
     55   RS_HEADER_ENTRY(rs_mesh) \
     56   RS_HEADER_ENTRY(rs_matrix) \
     57   RS_HEADER_ENTRY(rs_object) \
     58   RS_HEADER_ENTRY(rs_program) \
     59   RS_HEADER_ENTRY(rs_quaternion) \
     60   RS_HEADER_ENTRY(rs_sampler) \
     61   RS_HEADER_ENTRY(rs_time) \
     62   RS_HEADER_ENTRY(rs_types) \
     63 
     64 
     65 bool SlangRS::reflectToJava(const std::string &OutputPathBase,
     66                             const std::string &OutputPackageName,
     67                             std::string *RealPackageName) {
     68   return mRSContext->reflectToJava(OutputPathBase,
     69                                    OutputPackageName,
     70                                    getInputFileName(),
     71                                    getOutputFileName(),
     72                                    RealPackageName);
     73 }
     74 
     75 bool SlangRS::generateBitcodeAccessor(const std::string &OutputPathBase,
     76                                       const std::string &PackageName) {
     77   RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext;
     78 
     79   BCAccessorContext.rsFileName = getInputFileName().c_str();
     80   BCAccessorContext.bcFileName = getOutputFileName().c_str();
     81   BCAccessorContext.reflectPath = OutputPathBase.c_str();
     82   BCAccessorContext.packageName = PackageName.c_str();
     83   BCAccessorContext.bcStorage = BCST_JAVA_CODE;   // Must be BCST_JAVA_CODE
     84 
     85   return RSSlangReflectUtils::GenerateBitCodeAccessor(BCAccessorContext);
     86 }
     87 
     88 bool SlangRS::checkODR(const char *CurInputFile) {
     89   for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(),
     90           E = mRSContext->exportable_end();
     91        I != E;
     92        I++) {
     93     RSExportable *RSE = *I;
     94     if (RSE->getKind() != RSExportable::EX_TYPE)
     95       continue;
     96 
     97     RSExportType *ET = static_cast<RSExportType *>(RSE);
     98     if (ET->getClass() != RSExportType::ExportClassRecord)
     99       continue;
    100 
    101     RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET);
    102 
    103     // Artificial record types (create by us not by user in the source) always
    104     // conforms the ODR.
    105     if (ERT->isArtificial())
    106       continue;
    107 
    108     // Key to lookup ERT in ReflectedDefinitions
    109     llvm::StringRef RDKey(ERT->getName());
    110     ReflectedDefinitionListTy::const_iterator RD =
    111         ReflectedDefinitions.find(RDKey);
    112 
    113     if (RD != ReflectedDefinitions.end()) {
    114       const RSExportRecordType *Reflected = RD->getValue().first;
    115       // There's a record (struct) with the same name reflected before. Enforce
    116       // ODR checking - the Reflected must hold *exactly* the same "definition"
    117       // as the one defined previously. We say two record types A and B have the
    118       // same definition iff:
    119       //
    120       //  struct A {              struct B {
    121       //    Type(a1) a1,            Type(b1) b1,
    122       //    Type(a2) a2,            Type(b1) b2,
    123       //    ...                     ...
    124       //    Type(aN) aN             Type(b3) b3,
    125       //  };                      }
    126       //  Cond. #1. They have same number of fields, i.e., N = M;
    127       //  Cond. #2. for (i := 1 to N)
    128       //              Type(ai) = Type(bi) must hold;
    129       //  Cond. #3. for (i := 1 to N)
    130       //              Name(ai) = Name(bi) must hold;
    131       //
    132       // where,
    133       //  Type(F) = the type of field F and
    134       //  Name(F) = the field name.
    135 
    136       bool PassODR = false;
    137       // Cond. #1 and Cond. #2
    138       if (Reflected->equals(ERT)) {
    139         // Cond #3.
    140         RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(),
    141                                                  BI = ERT->fields_begin();
    142 
    143         for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) {
    144           if ((*AI)->getName() != (*BI)->getName())
    145             break;
    146           AI++;
    147           BI++;
    148         }
    149         PassODR = (AI == (Reflected->fields_end()));
    150       }
    151 
    152       if (!PassODR) {
    153         getDiagnostics().Report(mDiagErrorODR) << Reflected->getName()
    154                                                << getInputFileName()
    155                                                << RD->getValue().second;
    156         return false;
    157       }
    158     } else {
    159       llvm::StringMapEntry<ReflectedDefinitionTy> *ME =
    160           llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(),
    161                                                               RDKey.end());
    162       ME->setValue(std::make_pair(ERT, CurInputFile));
    163 
    164       if (!ReflectedDefinitions.insert(ME))
    165         delete ME;
    166 
    167       // Take the ownership of ERT such that it won't be freed in ~RSContext().
    168       ERT->keep();
    169     }
    170   }
    171   return true;
    172 }
    173 
    174 void SlangRS::initDiagnostic() {
    175   clang::DiagnosticsEngine &DiagEngine = getDiagnostics();
    176 
    177   if (DiagEngine.setDiagnosticGroupMapping("implicit-function-declaration",
    178                                            clang::diag::MAP_ERROR))
    179     DiagEngine.Report(clang::diag::warn_unknown_warning_option)
    180       << "implicit-function-declaration";
    181 
    182   DiagEngine.setDiagnosticMapping(
    183     clang::diag::ext_typecheck_convert_discards_qualifiers,
    184     clang::diag::MAP_ERROR,
    185     clang::SourceLocation());
    186 
    187   mDiagErrorInvalidOutputDepParameter =
    188     DiagEngine.getCustomDiagID(
    189       clang::DiagnosticsEngine::Error,
    190       "invalid parameter for output dependencies files.");
    191 
    192   mDiagErrorODR =
    193     DiagEngine.getCustomDiagID(
    194       clang::DiagnosticsEngine::Error,
    195       "type '%0' in different translation unit (%1 v.s. %2) "
    196       "has incompatible type definition");
    197 
    198   mDiagErrorTargetAPIRange =
    199     DiagEngine.getCustomDiagID(
    200       clang::DiagnosticsEngine::Error,
    201       "target API level '%0' is out of range ('%1' - '%2')");
    202 }
    203 
    204 void SlangRS::initPreprocessor() {
    205   clang::Preprocessor &PP = getPreprocessor();
    206 
    207   std::stringstream RSH;
    208   RSH << "#define RS_VERSION " << mTargetAPI << std::endl;
    209   RSH << "#include \"rs_core." RS_HEADER_SUFFIX "\"" << std::endl;
    210   PP.setPredefines(RSH.str());
    211 }
    212 
    213 void SlangRS::initASTContext() {
    214   mRSContext = new RSContext(getPreprocessor(),
    215                              getASTContext(),
    216                              getTargetInfo(),
    217                              &mPragmas,
    218                              mTargetAPI,
    219                              &mGeneratedFileNames);
    220 }
    221 
    222 clang::ASTConsumer
    223 *SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts,
    224                         llvm::raw_ostream *OS,
    225                         Slang::OutputType OT) {
    226     return new RSBackend(mRSContext,
    227                          &getDiagnostics(),
    228                          CodeGenOpts,
    229                          getTargetOptions(),
    230                          &mPragmas,
    231                          OS,
    232                          OT,
    233                          getSourceManager(),
    234                          mAllowRSPrefix);
    235 }
    236 
    237 bool SlangRS::IsRSHeaderFile(const char *File) {
    238 #define RS_HEADER_ENTRY(name)  \
    239   if (::strcmp(File, #name "."RS_HEADER_SUFFIX) == 0)  \
    240     return true;
    241 ENUM_RS_HEADER()
    242 #undef RS_HEADER_ENTRY
    243   return false;
    244 }
    245 
    246 bool SlangRS::IsFunctionInRSHeaderFile(const clang::FunctionDecl *FD,
    247                                        const clang::SourceManager &SourceMgr) {
    248   clang::FullSourceLoc FSL(FD->getLocStart(), SourceMgr);
    249   clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL);
    250 
    251   const char *Filename = PLoc.getFilename();
    252   if (!Filename) {
    253     return false;
    254   } else {
    255     return IsRSHeaderFile(llvm::sys::path::filename(Filename).data());
    256   }
    257 }
    258 
    259 SlangRS::SlangRS()
    260   : Slang(), mRSContext(NULL), mAllowRSPrefix(false), mTargetAPI(0) {
    261 }
    262 
    263 bool SlangRS::compile(
    264     const std::list<std::pair<const char*, const char*> > &IOFiles,
    265     const std::list<std::pair<const char*, const char*> > &DepFiles,
    266     const std::vector<std::string> &IncludePaths,
    267     const std::vector<std::string> &AdditionalDepTargets,
    268     Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage,
    269     bool AllowRSPrefix, bool OutputDep,
    270     unsigned int TargetAPI, bool EmitDebug,
    271     llvm::CodeGenOpt::Level OptimizationLevel,
    272     const std::string &JavaReflectionPathBase,
    273     const std::string &JavaReflectionPackageName) {
    274   if (IOFiles.empty())
    275     return true;
    276 
    277   if (OutputDep && (DepFiles.size() != IOFiles.size())) {
    278     getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter);
    279     return false;
    280   }
    281 
    282   std::string RealPackageName;
    283 
    284   const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile;
    285   std::list<std::pair<const char*, const char*> >::const_iterator
    286       IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin();
    287 
    288   setIncludePaths(IncludePaths);
    289   setOutputType(OutputType);
    290   if (OutputDep) {
    291     setAdditionalDepTargets(AdditionalDepTargets);
    292   }
    293 
    294   setDebugMetadataEmission(EmitDebug);
    295 
    296   setOptimizationLevel(OptimizationLevel);
    297 
    298   mAllowRSPrefix = AllowRSPrefix;
    299 
    300   mTargetAPI = TargetAPI;
    301   if (mTargetAPI < SLANG_MINIMUM_TARGET_API ||
    302       mTargetAPI > SLANG_MAXIMUM_TARGET_API) {
    303     getDiagnostics().Report(mDiagErrorTargetAPIRange) << mTargetAPI
    304         << SLANG_MINIMUM_TARGET_API << SLANG_MAXIMUM_TARGET_API;
    305     return false;
    306   }
    307 
    308   // Skip generation of warnings a second time if we are doing more than just
    309   // a single pass over the input file.
    310   bool SuppressAllWarnings = (OutputType != Slang::OT_Dependency);
    311 
    312   for (unsigned i = 0, e = IOFiles.size(); i != e; i++) {
    313     InputFile = IOFileIter->first;
    314     OutputFile = IOFileIter->second;
    315 
    316     reset();
    317 
    318     if (!setInputSource(InputFile))
    319       return false;
    320 
    321     if (!setOutput(OutputFile))
    322       return false;
    323 
    324     if (Slang::compile() > 0)
    325       return false;
    326 
    327     if (OutputType != Slang::OT_Dependency) {
    328 
    329       if (BitcodeStorage == BCST_CPP_CODE) {
    330           RSReflectionCpp R(mRSContext);
    331           bool ret = R.reflect(JavaReflectionPathBase, getInputFileName(), getOutputFileName());
    332           if (!ret) {
    333             return false;
    334           }
    335       } else {
    336 
    337         if (!reflectToJava(JavaReflectionPathBase,
    338                            JavaReflectionPackageName,
    339                            &RealPackageName)) {
    340           return false;
    341         }
    342 
    343         for (std::vector<std::string>::const_iterator
    344                  I = mGeneratedFileNames.begin(), E = mGeneratedFileNames.end();
    345              I != E;
    346              I++) {
    347           std::string ReflectedName = RSSlangReflectUtils::ComputePackagedPath(
    348               JavaReflectionPathBase.c_str(),
    349               (RealPackageName + OS_PATH_SEPARATOR_STR + *I).c_str());
    350           appendGeneratedFileName(ReflectedName + ".java");
    351         }
    352 
    353         if ((OutputType == Slang::OT_Bitcode) &&
    354             (BitcodeStorage == BCST_JAVA_CODE) &&
    355             !generateBitcodeAccessor(JavaReflectionPathBase,
    356                                      RealPackageName.c_str())) {
    357           return false;
    358         }
    359       }
    360     }
    361 
    362     if (OutputDep) {
    363       BCOutputFile = DepFileIter->first;
    364       DepOutputFile = DepFileIter->second;
    365 
    366       setDepTargetBC(BCOutputFile);
    367 
    368       if (!setDepOutput(DepOutputFile))
    369         return false;
    370 
    371       if (SuppressAllWarnings) {
    372         getDiagnostics().setSuppressAllDiagnostics(true);
    373       }
    374       if (generateDepFile() > 0)
    375         return false;
    376       if (SuppressAllWarnings) {
    377         getDiagnostics().setSuppressAllDiagnostics(false);
    378       }
    379 
    380       DepFileIter++;
    381     }
    382 
    383     if (!checkODR(InputFile))
    384       return false;
    385 
    386     IOFileIter++;
    387   }
    388 
    389   return true;
    390 }
    391 
    392 void SlangRS::reset() {
    393   delete mRSContext;
    394   mRSContext = NULL;
    395   mGeneratedFileNames.clear();
    396   Slang::reset();
    397   return;
    398 }
    399 
    400 SlangRS::~SlangRS() {
    401   delete mRSContext;
    402   for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(),
    403           E = ReflectedDefinitions.end();
    404        I != E;
    405        I++) {
    406     delete I->getValue().first;
    407   }
    408   return;
    409 }
    410 
    411 }  // namespace slang
    412