slang_rs.cpp revision e86245a09bb8b9e72f5dc68083444ec938865798
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 21#include "clang/Frontend/FrontendDiagnostic.h" 22 23#include "clang/Sema/SemaDiagnostic.h" 24 25#include "slang_rs_backend.h" 26#include "slang_rs_context.h" 27#include "slang_rs_export_type.h" 28 29using namespace slang; 30 31#define RS_HEADER_SUFFIX "rsh" 32 33#define ENUM_RS_HEADER() \ 34 RS_HEADER_ENTRY(rs_types) \ 35 RS_HEADER_ENTRY(rs_cl) \ 36 RS_HEADER_ENTRY(rs_core) \ 37 RS_HEADER_ENTRY(rs_math) 38 39#define RS_HEADER_ENTRY(x) \ 40 extern const char x ## _header[]; \ 41 extern unsigned x ## _header_size; 42ENUM_RS_HEADER() 43#undef RS_HEADER_ENTRY 44 45bool SlangRS::reflectToJava(const std::string &OutputPathBase, 46 const std::string &OutputPackageName, 47 std::string *RealPackageName) { 48 return mRSContext->reflectToJava(OutputPathBase, 49 OutputPackageName, 50 getInputFileName(), 51 getOutputFileName(), 52 RealPackageName); 53} 54 55bool SlangRS::generateBitcodeAccessor(const std::string &OutputPathBase, 56 const std::string &PackageName) { 57 RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext; 58 59 BCAccessorContext.rsFileName = getInputFileName().c_str(); 60 BCAccessorContext.bcFileName = getOutputFileName().c_str(); 61 BCAccessorContext.reflectPath = OutputPathBase.c_str(); 62 BCAccessorContext.packageName = PackageName.c_str(); 63 BCAccessorContext.bcStorage = BCST_JAVA_CODE; // Must be BCST_JAVA_CODE 64 65 return RSSlangReflectUtils::GenerateBitCodeAccessor(BCAccessorContext); 66} 67 68bool SlangRS::checkODR(const char *CurInputFile) { 69 for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(), 70 E = mRSContext->exportable_end(); 71 I != E; 72 I++) { 73 RSExportable *E = *I; 74 if (E->getKind() != RSExportable::EX_TYPE) 75 continue; 76 77 RSExportType *ET = static_cast<RSExportType *>(E); 78 if (ET->getClass() != RSExportType::ExportClassRecord) 79 continue; 80 81 RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET); 82 83 // Artificial record types (create by us not by user in the source) always 84 // conforms the ODR. 85 if (ERT->isArtificial()) 86 continue; 87 88 // Key to lookup ERT in ReflectedDefinitions 89 llvm::StringRef RDKey(ERT->getName()); 90 ReflectedDefinitionListTy::const_iterator RD = 91 ReflectedDefinitions.find(RDKey); 92 93 if (RD != ReflectedDefinitions.end()) { 94 const RSExportRecordType *Reflected = RD->getValue().first; 95 // There's a record (struct) with the same name reflected before. Enforce 96 // ODR checking - the Reflected must hold *exactly* the same "definition" 97 // as the one defined previously. We say two record types A and B have the 98 // same definition iff: 99 // 100 // struct A { struct B { 101 // Type(a1) a1, Type(b1) b1, 102 // Type(a2) a2, Type(b1) b2, 103 // ... ... 104 // Type(aN) aN Type(b3) b3, 105 // }; } 106 // Cond. #1. They have same number of fields, i.e., N = M; 107 // Cond. #2. for (i := 1 to N) 108 // Type(ai) = Type(bi) must hold; 109 // Cond. #3. for (i := 1 to N) 110 // Name(ai) = Name(bi) must hold; 111 // 112 // where, 113 // Type(F) = the type of field F and 114 // Name(F) = the field name. 115 116 bool PassODR = false; 117 // Cond. #1 and Cond. #2 118 if (Reflected->equals(ERT)) { 119 // Cond #3. 120 RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(), 121 BI = ERT->fields_begin(); 122 123 for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) { 124 if ((*AI)->getName() != (*BI)->getName()) 125 break; 126 AI++; 127 BI++; 128 } 129 PassODR = (AI == (Reflected->fields_end())); 130 } 131 132 if (!PassODR) { 133 getDiagnostics().Report(mDiagErrorODR) << Reflected->getName() 134 << getInputFileName() 135 << RD->getValue().second; 136 return false; 137 } 138 } else { 139 llvm::StringMapEntry<ReflectedDefinitionTy> *ME = 140 llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(), 141 RDKey.end()); 142 ME->setValue(std::make_pair(ERT, CurInputFile)); 143 144 if (!ReflectedDefinitions.insert(ME)) 145 delete ME; 146 147 // Take the ownership of ERT such that it won't be freed in ~RSContext(). 148 ERT->keep(); 149 } 150 151 } 152 return true; 153} 154 155void SlangRS::initDiagnostic() { 156 clang::Diagnostic &Diag = getDiagnostics(); 157 if (Diag.setDiagnosticGroupMapping("implicit-function-declaration", 158 clang::diag::MAP_ERROR)) 159 Diag.Report(clang::diag::warn_unknown_warning_option) 160 << "implicit-function-declaration"; 161 162 Diag.setDiagnosticMapping( 163 clang::diag::ext_typecheck_convert_discards_qualifiers, 164 clang::diag::MAP_ERROR); 165 166 mDiagErrorInvalidOutputDepParameter = 167 Diag.getCustomDiagID(clang::Diagnostic::Error, 168 "invalid parameter for output dependencies files."); 169 170 mDiagErrorODR = 171 Diag.getCustomDiagID(clang::Diagnostic::Error, 172 "type '%0' in different translation unit (%1 v.s. " 173 "%2) has incompatible type definition"); 174 175 return; 176} 177 178void SlangRS::initPreprocessor() { 179 clang::Preprocessor &PP = getPreprocessor(); 180 181 std::string RSH; 182#define RS_HEADER_ENTRY(x) \ 183 RSH.append("#line 1 \"" #x "."RS_HEADER_SUFFIX"\"\n"); \ 184 RSH.append(x ## _header, x ## _header_size); 185ENUM_RS_HEADER() 186#undef RS_HEADER_ENTRY 187 PP.setPredefines(RSH); 188 189 return; 190} 191 192void SlangRS::initASTContext() { 193 mRSContext = new RSContext(&getPreprocessor(), 194 &getASTContext(), 195 &getTargetInfo()); 196 return; 197} 198 199clang::ASTConsumer 200*SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts, 201 llvm::raw_ostream *OS, 202 Slang::OutputType OT) { 203 return new RSBackend(mRSContext, 204 getDiagnostics(), 205 CodeGenOpts, 206 getTargetOptions(), 207 mPragmas, 208 OS, 209 OT, 210 getSourceManager(), 211 mAllowRSPrefix); 212} 213 214bool SlangRS::IsRSHeaderFile(const char *File) { 215#define RS_HEADER_ENTRY(x) \ 216 if (::strcmp(File, #x "."RS_HEADER_SUFFIX) == 0) \ 217 return true; 218ENUM_RS_HEADER() 219#undef RS_HEADER_ENTRY 220 // Deal with rs_graphics.rsh special case 221 if (::strcmp(File, "rs_graphics."RS_HEADER_SUFFIX) == 0) 222 return true; 223 return false; 224} 225 226SlangRS::SlangRS() : Slang(), mRSContext(NULL), mAllowRSPrefix(false) { 227 return; 228} 229 230bool SlangRS::compile( 231 const std::list<std::pair<const char*, const char*> > &IOFiles, 232 const std::list<std::pair<const char*, const char*> > &DepFiles, 233 const std::vector<std::string> &IncludePaths, 234 const std::vector<std::string> &AdditionalDepTargets, 235 Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage, 236 bool AllowRSPrefix, bool OutputDep, 237 const std::string &JavaReflectionPathBase, 238 const std::string &JavaReflectionPackageName) { 239 if (IOFiles.empty()) 240 return true; 241 242 if (OutputDep && (DepFiles.size() != IOFiles.size())) { 243 getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter); 244 return false; 245 } 246 247 std::string RealPackageName; 248 249 const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile; 250 std::list<std::pair<const char*, const char*> >::const_iterator 251 IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin(); 252 253 setIncludePaths(IncludePaths); 254 setOutputType(OutputType); 255 if (OutputDep) 256 setAdditionalDepTargets(AdditionalDepTargets); 257 258 mAllowRSPrefix = AllowRSPrefix; 259 260 for (unsigned i = 0, e = IOFiles.size(); i != e; i++) { 261 InputFile = IOFileIter->first; 262 OutputFile = IOFileIter->second; 263 264 reset(); 265 266 if (!setInputSource(InputFile)) 267 return false; 268 269 if (!setOutput(OutputFile)) 270 return false; 271 272 if (OutputDep) { 273 BCOutputFile = DepFileIter->first; 274 DepOutputFile = DepFileIter->second; 275 276 setDepTargetBC(BCOutputFile); 277 278 if (!setDepOutput(DepOutputFile)) 279 return false; 280 281 if (generateDepFile() > 0) 282 return false; 283 284 DepFileIter++; 285 } 286 287 if (Slang::compile() > 0) 288 return false; 289 290 if (OutputType != Slang::OT_Dependency) { 291 if (!reflectToJava(JavaReflectionPathBase, 292 JavaReflectionPackageName, 293 &RealPackageName)) 294 return false; 295 296 if ((OutputType == Slang::OT_Bitcode) && 297 (BitcodeStorage == BCST_JAVA_CODE) && 298 !generateBitcodeAccessor(JavaReflectionPathBase, 299 RealPackageName.c_str())) 300 return false; 301 } 302 303 if (!checkODR(InputFile)) 304 return false; 305 306 IOFileIter++; 307 } 308 309 return true; 310} 311 312void SlangRS::reset() { 313 delete mRSContext; 314 mRSContext = NULL; 315 Slang::reset(); 316 return; 317} 318 319SlangRS::~SlangRS() { 320 delete mRSContext; 321 for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(), 322 E = ReflectedDefinitions.end(); 323 I != E; 324 I++) { 325 delete I->getValue().first; 326 } 327 return; 328} 329