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 41namespace 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". 67bool 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 76bool SlangRS::reflectToJava(const std::string &OutputPathBase, 77 const std::string &RSPackageName) { 78 return mRSContext->reflectToJava(OutputPathBase, 79 RSPackageName, 80 getInputFileName(), 81 getOutputFileName()); 82} 83 84bool 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 97bool 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 183void 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 213void 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 222void SlangRS::initASTContext() { 223 mRSContext = new RSContext(getPreprocessor(), 224 getASTContext(), 225 getTargetInfo(), 226 &mPragmas, 227 mTargetAPI, 228 &mGeneratedFileNames); 229} 230 231clang::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 247bool SlangRS::IsRSHeaderFile(const char *File) { 248#define RS_HEADER_ENTRY(name) \ 249 if (::strcmp(File, #name "."RS_HEADER_SUFFIX) == 0) \ 250 return true; 251ENUM_RS_HEADER() 252#undef RS_HEADER_ENTRY 253 return false; 254} 255 256bool 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 269SlangRS::SlangRS() 270 : Slang(), mRSContext(NULL), mAllowRSPrefix(false), mTargetAPI(0), 271 mIsFilterscript(false) { 272} 273 274bool 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 410void SlangRS::reset() { 411 delete mRSContext; 412 mRSContext = NULL; 413 mGeneratedFileNames.clear(); 414 Slang::reset(); 415 return; 416} 417 418SlangRS::~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