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