1 //===--------- Core.cpp - Core ORC APIs (SymbolSource, VSO, etc.) ---------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/ExecutionEngine/Orc/Core.h" 11 #include "llvm/ExecutionEngine/Orc/OrcError.h" 12 13 #if LLVM_ENABLE_THREADS 14 #include <future> 15 #endif 16 17 namespace llvm { 18 namespace orc { 19 20 void SymbolResolver::anchor() {} 21 void SymbolSource::anchor() {} 22 23 AsynchronousSymbolQuery::AsynchronousSymbolQuery( 24 const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved, 25 SymbolsReadyCallback NotifySymbolsReady) 26 : NotifySymbolsResolved(std::move(NotifySymbolsResolved)), 27 NotifySymbolsReady(std::move(NotifySymbolsReady)) { 28 assert(this->NotifySymbolsResolved && 29 "Symbols resolved callback must be set"); 30 assert(this->NotifySymbolsReady && "Symbols ready callback must be set"); 31 OutstandingResolutions = OutstandingFinalizations = Symbols.size(); 32 } 33 34 void AsynchronousSymbolQuery::setFailed(Error Err) { 35 OutstandingResolutions = OutstandingFinalizations = 0; 36 if (NotifySymbolsResolved) 37 NotifySymbolsResolved(std::move(Err)); 38 else 39 NotifySymbolsReady(std::move(Err)); 40 } 41 42 void AsynchronousSymbolQuery::setDefinition(SymbolStringPtr Name, 43 JITEvaluatedSymbol Sym) { 44 // If OutstandingResolutions is zero we must have errored out already. Just 45 // ignore this. 46 if (OutstandingResolutions == 0) 47 return; 48 49 assert(!Symbols.count(Name) && "Symbol has already been assigned an address"); 50 Symbols.insert(std::make_pair(std::move(Name), std::move(Sym))); 51 --OutstandingResolutions; 52 if (OutstandingResolutions == 0) { 53 NotifySymbolsResolved(std::move(Symbols)); 54 // Null out NotifySymbolsResolved to indicate that we've already called it. 55 NotifySymbolsResolved = {}; 56 } 57 } 58 59 void AsynchronousSymbolQuery::notifySymbolFinalized() { 60 // If OutstandingFinalizations is zero we must have errored out already. Just 61 // ignore this. 62 if (OutstandingFinalizations == 0) 63 return; 64 65 assert(OutstandingFinalizations > 0 && "All symbols already finalized"); 66 --OutstandingFinalizations; 67 if (OutstandingFinalizations == 0) 68 NotifySymbolsReady(Error::success()); 69 } 70 71 VSO::MaterializationInfo::MaterializationInfo( 72 JITSymbolFlags Flags, std::shared_ptr<SymbolSource> Source) 73 : Flags(std::move(Flags)), Source(std::move(Source)) {} 74 75 JITSymbolFlags VSO::MaterializationInfo::getFlags() const { return Flags; } 76 77 JITTargetAddress VSO::MaterializationInfo::getAddress() const { 78 return Address; 79 } 80 81 void VSO::MaterializationInfo::replaceWithSource( 82 VSO &V, SymbolStringPtr Name, JITSymbolFlags NewFlags, 83 std::shared_ptr<SymbolSource> NewSource) { 84 assert(Address == 0 && PendingResolution.empty() && 85 PendingFinalization.empty() && 86 "Cannot replace source during or after materialization"); 87 Source->discard(V, Name); 88 Flags = std::move(NewFlags); 89 Source = std::move(NewSource); 90 } 91 92 std::shared_ptr<SymbolSource> VSO::MaterializationInfo::query( 93 SymbolStringPtr Name, std::shared_ptr<AsynchronousSymbolQuery> Query) { 94 if (Address == 0) { 95 PendingResolution.push_back(std::move(Query)); 96 auto S = std::move(Source); 97 Source = nullptr; 98 return S; 99 } 100 101 Query->setDefinition(Name, JITEvaluatedSymbol(Address, Flags)); 102 PendingFinalization.push_back(std::move(Query)); 103 return nullptr; 104 } 105 106 void VSO::MaterializationInfo::resolve(VSO &V, SymbolStringPtr Name, 107 JITEvaluatedSymbol Sym) { 108 if (Source) { 109 Source->discard(V, Name); 110 Source = nullptr; 111 } 112 113 // FIXME: Sanity check flags? 114 Flags = Sym.getFlags(); 115 Address = Sym.getAddress(); 116 for (auto &Query : PendingResolution) { 117 Query->setDefinition(Name, std::move(Sym)); 118 PendingFinalization.push_back(std::move(Query)); 119 } 120 PendingResolution = {}; 121 } 122 123 void VSO::MaterializationInfo::finalize() { 124 for (auto &Query : PendingFinalization) 125 Query->notifySymbolFinalized(); 126 PendingFinalization = {}; 127 } 128 129 VSO::SymbolTableEntry::SymbolTableEntry(JITSymbolFlags Flags, 130 std::shared_ptr<SymbolSource> Source) 131 : Flags(JITSymbolFlags::FlagNames(Flags | JITSymbolFlags::NotMaterialized)), 132 MatInfo( 133 llvm::make_unique<MaterializationInfo>(Flags, std::move(Source))) { 134 // FIXME: Assert flag sanity. 135 } 136 137 VSO::SymbolTableEntry::SymbolTableEntry(JITEvaluatedSymbol Sym) 138 : Flags(Sym.getFlags()), Address(Sym.getAddress()) { 139 // FIXME: Assert flag sanity. 140 } 141 142 VSO::SymbolTableEntry::SymbolTableEntry(SymbolTableEntry &&Other) 143 : Flags(Other.Flags), Address(0) { 144 if (Flags.isMaterialized()) 145 Address = Other.Address; 146 else 147 MatInfo = std::move(Other.MatInfo); 148 } 149 150 VSO::SymbolTableEntry::~SymbolTableEntry() { 151 if (!Flags.isMaterialized()) 152 MatInfo.std::unique_ptr<MaterializationInfo>::~unique_ptr(); 153 } 154 155 JITSymbolFlags VSO::SymbolTableEntry::getFlags() const { return Flags; } 156 157 void VSO::SymbolTableEntry::replaceWithSource( 158 VSO &V, SymbolStringPtr Name, JITSymbolFlags NewFlags, 159 std::shared_ptr<SymbolSource> NewSource) { 160 bool ReplaceExisting = !Flags.isMaterialized(); 161 Flags = NewFlags; 162 if (ReplaceExisting) 163 MatInfo->replaceWithSource(V, Name, Flags, std::move(NewSource)); 164 else 165 new (&MatInfo) std::unique_ptr<MaterializationInfo>( 166 llvm::make_unique<MaterializationInfo>(Flags, std::move(NewSource))); 167 } 168 169 std::shared_ptr<SymbolSource> 170 VSO::SymbolTableEntry::query(SymbolStringPtr Name, 171 std::shared_ptr<AsynchronousSymbolQuery> Query) { 172 if (Flags.isMaterialized()) { 173 Query->setDefinition(std::move(Name), JITEvaluatedSymbol(Address, Flags)); 174 Query->notifySymbolFinalized(); 175 return nullptr; 176 } else 177 return MatInfo->query(std::move(Name), std::move(Query)); 178 } 179 180 void VSO::SymbolTableEntry::resolve(VSO &V, SymbolStringPtr Name, 181 JITEvaluatedSymbol Sym) { 182 if (Flags.isMaterialized()) { 183 // FIXME: Should we assert flag state here (flags must match except for 184 // materialization state, overrides must be legal) or in the caller 185 // in VSO? 186 Flags = Sym.getFlags(); 187 Address = Sym.getAddress(); 188 } else 189 MatInfo->resolve(V, std::move(Name), std::move(Sym)); 190 } 191 192 void VSO::SymbolTableEntry::finalize() { 193 if (!Flags.isMaterialized()) { 194 auto TmpMatInfo = std::move(MatInfo); 195 MatInfo.std::unique_ptr<MaterializationInfo>::~unique_ptr(); 196 // FIXME: Assert flag sanity? 197 Flags = TmpMatInfo->getFlags(); 198 Address = TmpMatInfo->getAddress(); 199 TmpMatInfo->finalize(); 200 } 201 assert(Flags.isMaterialized() && "Trying to finalize not-emitted symbol"); 202 } 203 204 VSO::RelativeLinkageStrength VSO::compareLinkage(Optional<JITSymbolFlags> Old, 205 JITSymbolFlags New) { 206 if (Old == None) 207 return llvm::orc::VSO::NewDefinitionIsStronger; 208 209 if (Old->isStrong()) { 210 if (New.isStrong()) 211 return llvm::orc::VSO::DuplicateDefinition; 212 else 213 return llvm::orc::VSO::ExistingDefinitionIsStronger; 214 } else { 215 if (New.isStrong()) 216 return llvm::orc::VSO::NewDefinitionIsStronger; 217 else 218 return llvm::orc::VSO::ExistingDefinitionIsStronger; 219 } 220 } 221 222 VSO::RelativeLinkageStrength 223 VSO::compareLinkage(SymbolStringPtr Name, JITSymbolFlags NewFlags) const { 224 auto I = Symbols.find(Name); 225 return compareLinkage(I == Symbols.end() 226 ? None 227 : Optional<JITSymbolFlags>(I->second.getFlags()), 228 NewFlags); 229 } 230 231 Error VSO::define(SymbolMap NewSymbols) { 232 Error Err = Error::success(); 233 for (auto &KV : NewSymbols) { 234 auto I = Symbols.find(KV.first); 235 auto LinkageResult = compareLinkage( 236 I == Symbols.end() ? None 237 : Optional<JITSymbolFlags>(I->second.getFlags()), 238 KV.second.getFlags()); 239 240 // Silently discard weaker definitions. 241 if (LinkageResult == ExistingDefinitionIsStronger) 242 continue; 243 244 // Report duplicate definition errors. 245 if (LinkageResult == DuplicateDefinition) { 246 Err = joinErrors(std::move(Err), 247 make_error<orc::DuplicateDefinition>(*KV.first)); 248 continue; 249 } 250 251 if (I != Symbols.end()) { 252 I->second.resolve(*this, KV.first, std::move(KV.second)); 253 I->second.finalize(); 254 } else 255 Symbols.insert(std::make_pair(KV.first, std::move(KV.second))); 256 } 257 return Err; 258 } 259 260 Error VSO::defineLazy(const SymbolFlagsMap &NewSymbols, 261 std::shared_ptr<SymbolSource> Source) { 262 Error Err = Error::success(); 263 for (auto &KV : NewSymbols) { 264 auto I = Symbols.find(KV.first); 265 266 auto LinkageResult = compareLinkage( 267 I == Symbols.end() ? None 268 : Optional<JITSymbolFlags>(I->second.getFlags()), 269 KV.second); 270 271 // Discard weaker definitions. 272 if (LinkageResult == ExistingDefinitionIsStronger) 273 Source->discard(*this, KV.first); 274 275 // Report duplicate definition errors. 276 if (LinkageResult == DuplicateDefinition) { 277 Err = joinErrors(std::move(Err), 278 make_error<orc::DuplicateDefinition>(*KV.first)); 279 continue; 280 } 281 282 if (I != Symbols.end()) 283 I->second.replaceWithSource(*this, KV.first, KV.second, Source); 284 else 285 Symbols.emplace( 286 std::make_pair(KV.first, SymbolTableEntry(KV.second, Source))); 287 } 288 return Err; 289 } 290 291 void VSO::resolve(SymbolMap SymbolValues) { 292 for (auto &KV : SymbolValues) { 293 auto I = Symbols.find(KV.first); 294 assert(I != Symbols.end() && "Resolving symbol not present in this dylib"); 295 I->second.resolve(*this, KV.first, std::move(KV.second)); 296 } 297 } 298 299 void VSO::finalize(SymbolNameSet SymbolsToFinalize) { 300 for (auto &S : SymbolsToFinalize) { 301 auto I = Symbols.find(S); 302 assert(I != Symbols.end() && "Finalizing symbol not present in this dylib"); 303 I->second.finalize(); 304 } 305 } 306 307 SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Names) { 308 309 for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) { 310 auto Tmp = I++; 311 auto SymI = Symbols.find(*Tmp); 312 313 // If the symbol isn't in this dylib then just continue. 314 if (SymI == Symbols.end()) 315 continue; 316 317 Names.erase(Tmp); 318 319 Flags[SymI->first] = 320 JITSymbolFlags::stripTransientFlags(SymI->second.getFlags()); 321 } 322 323 return Names; 324 } 325 326 VSO::LookupResult VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Query, 327 SymbolNameSet Names) { 328 SourceWorkMap MaterializationWork; 329 330 for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) { 331 auto Tmp = I++; 332 auto SymI = Symbols.find(*Tmp); 333 334 // If the symbol isn't in this dylib then just continue. 335 if (SymI == Symbols.end()) 336 continue; 337 338 // The symbol is in the dylib. Erase it from Names and proceed. 339 Names.erase(Tmp); 340 341 // Forward the query to the given SymbolTableEntry, and if it return a 342 // layer to perform materialization with, add that to the 343 // MaterializationWork map. 344 if (auto Source = SymI->second.query(SymI->first, Query)) 345 MaterializationWork[Source].insert(SymI->first); 346 } 347 348 return {std::move(MaterializationWork), std::move(Names)}; 349 } 350 351 Expected<SymbolMap> lookup(const std::vector<VSO *> &VSOs, SymbolNameSet Names, 352 MaterializationDispatcher DispatchMaterialization) { 353 #if LLVM_ENABLE_THREADS 354 // In the threaded case we use promises to return the results. 355 std::promise<SymbolMap> PromisedResult; 356 std::mutex ErrMutex; 357 Error ResolutionError = Error::success(); 358 std::promise<void> PromisedReady; 359 Error ReadyError = Error::success(); 360 auto OnResolve = [&](Expected<SymbolMap> Result) { 361 if (Result) 362 PromisedResult.set_value(std::move(*Result)); 363 else { 364 { 365 ErrorAsOutParameter _(&ResolutionError); 366 std::lock_guard<std::mutex> Lock(ErrMutex); 367 ResolutionError = Result.takeError(); 368 } 369 PromisedResult.set_value(SymbolMap()); 370 } 371 }; 372 auto OnReady = [&](Error Err) { 373 if (Err) { 374 ErrorAsOutParameter _(&ReadyError); 375 std::lock_guard<std::mutex> Lock(ErrMutex); 376 ReadyError = std::move(Err); 377 } 378 PromisedReady.set_value(); 379 }; 380 #else 381 SymbolMap Result; 382 Error ResolutionError = Error::success(); 383 Error ReadyError = Error::success(); 384 385 auto OnResolve = [&](Expected<SymbolMap> R) { 386 ErrorAsOutParameter _(&ResolutionError); 387 if (R) 388 Result = std::move(*R); 389 else 390 ResolutionError = R.takeError(); 391 }; 392 auto OnReady = [&](Error Err) { 393 ErrorAsOutParameter _(&ReadyError); 394 if (Err) 395 ReadyError = std::move(Err); 396 }; 397 #endif 398 399 auto Query = std::make_shared<AsynchronousSymbolQuery>( 400 Names, std::move(OnResolve), std::move(OnReady)); 401 SymbolNameSet UnresolvedSymbols(std::move(Names)); 402 403 for (auto *VSO : VSOs) { 404 405 if (UnresolvedSymbols.empty()) 406 break; 407 408 assert(VSO && "VSO pointers in VSOs list should be non-null"); 409 auto LR = VSO->lookup(Query, UnresolvedSymbols); 410 UnresolvedSymbols = std::move(LR.UnresolvedSymbols); 411 412 for (auto I = LR.MaterializationWork.begin(), 413 E = LR.MaterializationWork.end(); 414 I != E;) { 415 auto Tmp = I++; 416 std::shared_ptr<SymbolSource> Source = Tmp->first; 417 SymbolNameSet Names = std::move(Tmp->second); 418 LR.MaterializationWork.erase(Tmp); 419 DispatchMaterialization(*VSO, std::move(Source), std::move(Names)); 420 } 421 } 422 423 #if LLVM_ENABLE_THREADS 424 auto ResultFuture = PromisedResult.get_future(); 425 auto Result = ResultFuture.get(); 426 427 { 428 std::lock_guard<std::mutex> Lock(ErrMutex); 429 if (ResolutionError) { 430 // ReadyError will never be assigned. Consume the success value. 431 cantFail(std::move(ReadyError)); 432 return std::move(ResolutionError); 433 } 434 } 435 436 auto ReadyFuture = PromisedReady.get_future(); 437 ReadyFuture.get(); 438 439 { 440 std::lock_guard<std::mutex> Lock(ErrMutex); 441 if (ReadyError) 442 return std::move(ReadyError); 443 } 444 445 return std::move(Result); 446 447 #else 448 if (ResolutionError) { 449 // ReadyError will never be assigned. Consume the success value. 450 cantFail(std::move(ReadyError)); 451 return std::move(ResolutionError); 452 } 453 454 if (ReadyError) 455 return std::move(ReadyError); 456 457 return Result; 458 #endif 459 } 460 461 /// @brief Look up a symbol by searching a list of VSOs. 462 Expected<JITEvaluatedSymbol> 463 lookup(const std::vector<VSO *> VSOs, SymbolStringPtr Name, 464 MaterializationDispatcher DispatchMaterialization) { 465 SymbolNameSet Names({Name}); 466 if (auto ResultMap = 467 lookup(VSOs, std::move(Names), std::move(DispatchMaterialization))) { 468 assert(ResultMap->size() == 1 && "Unexpected number of results"); 469 assert(ResultMap->count(Name) && "Missing result for symbol"); 470 return ResultMap->begin()->second; 471 } else 472 return ResultMap.takeError(); 473 } 474 475 ExecutionSession::ExecutionSession(SymbolStringPool &SSP) : SSP(SSP) {} 476 477 VModuleKey ExecutionSession::allocateVModule() { return ++LastKey; } 478 479 void ExecutionSession::releaseVModule(VModuleKey VMod) { 480 // FIXME: Recycle keys. 481 } 482 483 void ExecutionSession::logErrorsToStdErr(Error Err) { 484 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: "); 485 } 486 487 } // End namespace orc. 488 } // End namespace llvm. 489