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