slang_rs.cpp revision c460b37ffb50819a32c2a8967754b6f784b28263
18fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams/* 28fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * Copyright 2010, The Android Open Source Project 38fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * 48fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * Licensed under the Apache License, Version 2.0 (the "License"); 58fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * you may not use this file except in compliance with the License. 68fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * You may obtain a copy of the License at 78fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * 88fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * http://www.apache.org/licenses/LICENSE-2.0 98fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * 108fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * Unless required by applicable law or agreed to in writing, software 118fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * distributed under the License is distributed on an "AS IS" BASIS, 128fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * See the License for the specific language governing permissions and 148fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams * limitations under the License. 158fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams */ 168fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 178fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams#include "slang_rs.h" 188fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 198fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams#include <cstring> 208fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams#include <list> 218fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams#include <sstream> 228fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams#include <string> 237d435ae5ba100be5710b685653cc351cab159c11Stephen Hines#include <utility> 247d435ae5ba100be5710b685653cc351cab159c11Stephen Hines#include <vector> 257d435ae5ba100be5710b685653cc351cab159c11Stephen Hines 267d435ae5ba100be5710b685653cc351cab159c11Stephen Hines#include "clang/Basic/SourceLocation.h" 277d435ae5ba100be5710b685653cc351cab159c11Stephen Hines 288fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams#include "clang/Frontend/FrontendDiagnostic.h" 298fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 30ce8b0e674c93035013d1c33aaabc9bb6ceffde0fTim Murray#include "clang/Sema/SemaDiagnostic.h" 318fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 328fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams#include "llvm/Support/Path.h" 338fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 34ce8b0e674c93035013d1c33aaabc9bb6ceffde0fTim Murray#include "os_sep.h" 358fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams#include "slang_rs_backend.h" 368fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams#include "slang_rs_context.h" 378fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams#include "slang_rs_export_type.h" 388fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 398fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Samsnamespace slang { 408fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 418fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams#define RS_HEADER_SUFFIX "rsh" 428fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 438fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams/* RS_HEADER_ENTRY(name) */ 447d435ae5ba100be5710b685653cc351cab159c11Stephen Hines#define ENUM_RS_HEADER() \ 458fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams RS_HEADER_ENTRY(rs_allocation) \ 468fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams RS_HEADER_ENTRY(rs_atomic) \ 478fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams RS_HEADER_ENTRY(rs_cl) \ 488fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams RS_HEADER_ENTRY(rs_core) \ 498fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams RS_HEADER_ENTRY(rs_debug) \ 50ce8b0e674c93035013d1c33aaabc9bb6ceffde0fTim Murray RS_HEADER_ENTRY(rs_graphics) \ 51ce8b0e674c93035013d1c33aaabc9bb6ceffde0fTim Murray RS_HEADER_ENTRY(rs_math) \ 52ce8b0e674c93035013d1c33aaabc9bb6ceffde0fTim Murray RS_HEADER_ENTRY(rs_matrix) \ 53ce8b0e674c93035013d1c33aaabc9bb6ceffde0fTim Murray RS_HEADER_ENTRY(rs_object) \ 548fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams RS_HEADER_ENTRY(rs_quaternion) \ 558fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams RS_HEADER_ENTRY(rs_time) \ 568fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams RS_HEADER_ENTRY(rs_types) \ 578fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 588fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 598fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Samsbool SlangRS::reflectToJava(const std::string &OutputPathBase, 608fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams const std::string &OutputPackageName, 618fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams std::string *RealPackageName) { 628fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams return mRSContext->reflectToJava(OutputPathBase, 637d435ae5ba100be5710b685653cc351cab159c11Stephen Hines OutputPackageName, 6460c5b31f4448410221de043873b94797732afa66Stephen Hines getInputFileName(), 6560c5b31f4448410221de043873b94797732afa66Stephen Hines getOutputFileName(), 667d435ae5ba100be5710b685653cc351cab159c11Stephen Hines RealPackageName); 6760c5b31f4448410221de043873b94797732afa66Stephen Hines} 6860c5b31f4448410221de043873b94797732afa66Stephen Hines 697d435ae5ba100be5710b685653cc351cab159c11Stephen Hinesbool SlangRS::generateBitcodeAccessor(const std::string &OutputPathBase, 707d435ae5ba100be5710b685653cc351cab159c11Stephen Hines const std::string &PackageName) { 717d435ae5ba100be5710b685653cc351cab159c11Stephen Hines RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext; 728fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 738fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams BCAccessorContext.rsFileName = getInputFileName().c_str(); 748fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams BCAccessorContext.bcFileName = getOutputFileName().c_str(); 758fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams BCAccessorContext.reflectPath = OutputPathBase.c_str(); 768fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams BCAccessorContext.packageName = PackageName.c_str(); 778fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams BCAccessorContext.bcStorage = BCST_JAVA_CODE; // Must be BCST_JAVA_CODE 788fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 798fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams return RSSlangReflectUtils::GenerateBitCodeAccessor(BCAccessorContext); 808fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams} 818fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 828fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Samsbool SlangRS::checkODR(const char *CurInputFile) { 838fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(), 848fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams E = mRSContext->exportable_end(); 858fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams I != E; 868fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams I++) { 878fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams RSExportable *RSE = *I; 888fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams if (RSE->getKind() != RSExportable::EX_TYPE) 898fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams continue; 908fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 918fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams RSExportType *ET = static_cast<RSExportType *>(RSE); 928fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams if (ET->getClass() != RSExportType::ExportClassRecord) 938fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams continue; 948fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 958fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET); 968fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 978fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams // Artificial record types (create by us not by user in the source) always 988fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams // conforms the ODR. 998fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams if (ERT->isArtificial()) 1008fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams continue; 1018fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 1028fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams // Key to lookup ERT in ReflectedDefinitions 1038fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams llvm::StringRef RDKey(ERT->getName()); 1048fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams ReflectedDefinitionListTy::const_iterator RD = 1058fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams ReflectedDefinitions.find(RDKey); 1068fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams 1078fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams if (RD != ReflectedDefinitions.end()) { 1088fb4b53aef5216ff5b1b0687a581278d93c2d38fJason Sams const RSExportRecordType *Reflected = RD->getValue().first; 109 // There's a record (struct) with the same name reflected before. Enforce 110 // ODR checking - the Reflected must hold *exactly* the same "definition" 111 // as the one defined previously. We say two record types A and B have the 112 // same definition iff: 113 // 114 // struct A { struct B { 115 // Type(a1) a1, Type(b1) b1, 116 // Type(a2) a2, Type(b1) b2, 117 // ... ... 118 // Type(aN) aN Type(b3) b3, 119 // }; } 120 // Cond. #1. They have same number of fields, i.e., N = M; 121 // Cond. #2. for (i := 1 to N) 122 // Type(ai) = Type(bi) must hold; 123 // Cond. #3. for (i := 1 to N) 124 // Name(ai) = Name(bi) must hold; 125 // 126 // where, 127 // Type(F) = the type of field F and 128 // Name(F) = the field name. 129 130 bool PassODR = false; 131 // Cond. #1 and Cond. #2 132 if (Reflected->equals(ERT)) { 133 // Cond #3. 134 RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(), 135 BI = ERT->fields_begin(); 136 137 for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) { 138 if ((*AI)->getName() != (*BI)->getName()) 139 break; 140 AI++; 141 BI++; 142 } 143 PassODR = (AI == (Reflected->fields_end())); 144 } 145 146 if (!PassODR) { 147 getDiagnostics().Report(mDiagErrorODR) << Reflected->getName() 148 << getInputFileName() 149 << RD->getValue().second; 150 return false; 151 } 152 } else { 153 llvm::StringMapEntry<ReflectedDefinitionTy> *ME = 154 llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(), 155 RDKey.end()); 156 ME->setValue(std::make_pair(ERT, CurInputFile)); 157 158 if (!ReflectedDefinitions.insert(ME)) 159 delete ME; 160 161 // Take the ownership of ERT such that it won't be freed in ~RSContext(). 162 ERT->keep(); 163 } 164 } 165 return true; 166} 167 168void SlangRS::initDiagnostic() { 169 clang::DiagnosticsEngine &DiagEngine = getDiagnostics(); 170 171 if (DiagEngine.setDiagnosticGroupMapping("implicit-function-declaration", 172 clang::diag::MAP_ERROR)) 173 DiagEngine.Report(clang::diag::warn_unknown_warning_option) 174 << "implicit-function-declaration"; 175 176 DiagEngine.setDiagnosticMapping( 177 clang::diag::ext_typecheck_convert_discards_qualifiers, 178 clang::diag::MAP_ERROR, 179 clang::SourceLocation()); 180 181 mDiagErrorInvalidOutputDepParameter = 182 DiagEngine.getCustomDiagID( 183 clang::DiagnosticsEngine::Error, 184 "invalid parameter for output dependencies files."); 185 186 mDiagErrorODR = 187 DiagEngine.getCustomDiagID( 188 clang::DiagnosticsEngine::Error, 189 "type '%0' in different translation unit (%1 v.s. %2) " 190 "has incompatible type definition"); 191 192 mDiagErrorTargetAPIRange = 193 DiagEngine.getCustomDiagID( 194 clang::DiagnosticsEngine::Error, 195 "target API level '%0' is out of range ('%1' - '%2')"); 196} 197 198void SlangRS::initPreprocessor() { 199 clang::Preprocessor &PP = getPreprocessor(); 200 201 std::stringstream RSH; 202 RSH << "#define RS_VERSION " << mTargetAPI << std::endl; 203 RSH << "#include \"rs_core." RS_HEADER_SUFFIX "\"" << std::endl; 204 PP.setPredefines(RSH.str()); 205} 206 207void SlangRS::initASTContext() { 208 mRSContext = new RSContext(getPreprocessor(), 209 getASTContext(), 210 getTargetInfo(), 211 &mPragmas, 212 mTargetAPI, 213 &mGeneratedFileNames); 214} 215 216clang::ASTConsumer 217*SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts, 218 llvm::raw_ostream *OS, 219 Slang::OutputType OT) { 220 return new RSBackend(mRSContext, 221 &getDiagnostics(), 222 CodeGenOpts, 223 getTargetOptions(), 224 &mPragmas, 225 OS, 226 OT, 227 getSourceManager(), 228 mAllowRSPrefix); 229} 230 231bool SlangRS::IsRSHeaderFile(const char *File) { 232#define RS_HEADER_ENTRY(name) \ 233 if (::strcmp(File, #name "."RS_HEADER_SUFFIX) == 0) \ 234 return true; 235ENUM_RS_HEADER() 236#undef RS_HEADER_ENTRY 237 return false; 238} 239 240bool SlangRS::IsFunctionInRSHeaderFile(const clang::FunctionDecl *FD, 241 const clang::SourceManager &SourceMgr) { 242 clang::FullSourceLoc FSL(FD->getLocStart(), SourceMgr); 243 clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL); 244 245 const char *Filename = PLoc.getFilename(); 246 if (!Filename) { 247 return false; 248 } else { 249 return IsRSHeaderFile(llvm::sys::path::filename(Filename).data()); 250 } 251} 252 253SlangRS::SlangRS() 254 : Slang(), mRSContext(NULL), mAllowRSPrefix(false), mTargetAPI(0) { 255} 256 257bool SlangRS::compile( 258 const std::list<std::pair<const char*, const char*> > &IOFiles, 259 const std::list<std::pair<const char*, const char*> > &DepFiles, 260 const std::vector<std::string> &IncludePaths, 261 const std::vector<std::string> &AdditionalDepTargets, 262 Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage, 263 bool AllowRSPrefix, bool OutputDep, 264 unsigned int TargetAPI, bool EmitDebug, 265 llvm::CodeGenOpt::Level OptimizationLevel, 266 const std::string &JavaReflectionPathBase, 267 const std::string &JavaReflectionPackageName) { 268 if (IOFiles.empty()) 269 return true; 270 271 if (OutputDep && (DepFiles.size() != IOFiles.size())) { 272 getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter); 273 return false; 274 } 275 276 std::string RealPackageName; 277 278 const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile; 279 std::list<std::pair<const char*, const char*> >::const_iterator 280 IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin(); 281 282 setIncludePaths(IncludePaths); 283 setOutputType(OutputType); 284 if (OutputDep) { 285 setAdditionalDepTargets(AdditionalDepTargets); 286 } 287 288 setDebugMetadataEmission(EmitDebug); 289 290 setOptimizationLevel(OptimizationLevel); 291 292 mAllowRSPrefix = AllowRSPrefix; 293 294 mTargetAPI = TargetAPI; 295 if (mTargetAPI < SLANG_MINIMUM_TARGET_API || 296 mTargetAPI > SLANG_MAXIMUM_TARGET_API) { 297 getDiagnostics().Report(mDiagErrorTargetAPIRange) << mTargetAPI 298 << SLANG_MINIMUM_TARGET_API << SLANG_MAXIMUM_TARGET_API; 299 return false; 300 } 301 302 // Skip generation of warnings a second time if we are doing more than just 303 // a single pass over the input file. 304 bool SuppressAllWarnings = (OutputType != Slang::OT_Dependency); 305 306 for (unsigned i = 0, e = IOFiles.size(); i != e; i++) { 307 InputFile = IOFileIter->first; 308 OutputFile = IOFileIter->second; 309 310 reset(); 311 312 if (!setInputSource(InputFile)) 313 return false; 314 315 if (!setOutput(OutputFile)) 316 return false; 317 318 if (Slang::compile() > 0) 319 return false; 320 321 if (OutputType != Slang::OT_Dependency) { 322 if (!reflectToJava(JavaReflectionPathBase, 323 JavaReflectionPackageName, 324 &RealPackageName)) 325 return false; 326 327 for (std::vector<std::string>::const_iterator 328 I = mGeneratedFileNames.begin(), E = mGeneratedFileNames.end(); 329 I != E; 330 I++) { 331 std::string ReflectedName = RSSlangReflectUtils::ComputePackagedPath( 332 JavaReflectionPathBase.c_str(), 333 (RealPackageName + OS_PATH_SEPARATOR_STR + *I).c_str()); 334 appendGeneratedFileName(ReflectedName + ".java"); 335 } 336 337 if ((OutputType == Slang::OT_Bitcode) && 338 (BitcodeStorage == BCST_JAVA_CODE) && 339 !generateBitcodeAccessor(JavaReflectionPathBase, 340 RealPackageName.c_str())) 341 return false; 342 } 343 344 if (OutputDep) { 345 BCOutputFile = DepFileIter->first; 346 DepOutputFile = DepFileIter->second; 347 348 setDepTargetBC(BCOutputFile); 349 350 if (!setDepOutput(DepOutputFile)) 351 return false; 352 353 if (SuppressAllWarnings) { 354 getDiagnostics().setSuppressAllDiagnostics(true); 355 } 356 if (generateDepFile() > 0) 357 return false; 358 if (SuppressAllWarnings) { 359 getDiagnostics().setSuppressAllDiagnostics(false); 360 } 361 362 DepFileIter++; 363 } 364 365 if (!checkODR(InputFile)) 366 return false; 367 368 IOFileIter++; 369 } 370 371 return true; 372} 373 374void SlangRS::reset() { 375 delete mRSContext; 376 mRSContext = NULL; 377 mGeneratedFileNames.clear(); 378 Slang::reset(); 379 return; 380} 381 382SlangRS::~SlangRS() { 383 delete mRSContext; 384 for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(), 385 E = ReflectedDefinitions.end(); 386 I != E; 387 I++) { 388 delete I->getValue().first; 389 } 390 return; 391} 392 393} // namespace slang 394