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 namespace llvm { 14 namespace orc { 15 16 void SymbolResolver::anchor() {} 17 void SymbolSource::anchor() {} 18 19 AsynchronousSymbolQuery::AsynchronousSymbolQuery( 20 const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved, 21 SymbolsReadyCallback NotifySymbolsReady) 22 : NotifySymbolsResolved(std::move(NotifySymbolsResolved)), 23 NotifySymbolsReady(std::move(NotifySymbolsReady)) { 24 assert(this->NotifySymbolsResolved && 25 "Symbols resolved callback must be set"); 26 assert(this->NotifySymbolsReady && "Symbols ready callback must be set"); 27 OutstandingResolutions = OutstandingFinalizations = Symbols.size(); 28 } 29 30 void AsynchronousSymbolQuery::setFailed(Error Err) { 31 OutstandingResolutions = OutstandingFinalizations = 0; 32 if (NotifySymbolsResolved) 33 NotifySymbolsResolved(std::move(Err)); 34 else 35 NotifySymbolsReady(std::move(Err)); 36 } 37 38 void AsynchronousSymbolQuery::setDefinition(SymbolStringPtr Name, 39 JITEvaluatedSymbol Sym) { 40 // If OutstandingResolutions is zero we must have errored out already. Just 41 // ignore this. 42 if (OutstandingResolutions == 0) 43 return; 44 45 assert(!Symbols.count(Name) && "Symbol has already been assigned an address"); 46 Symbols.insert(std::make_pair(std::move(Name), std::move(Sym))); 47 --OutstandingResolutions; 48 if (OutstandingResolutions == 0) { 49 NotifySymbolsResolved(std::move(Symbols)); 50 // Null out NotifySymbolsResolved to indicate that we've already called it. 51 NotifySymbolsResolved = {}; 52 } 53 } 54 55 void AsynchronousSymbolQuery::notifySymbolFinalized() { 56 // If OutstandingFinalizations is zero we must have errored out already. Just 57 // ignore this. 58 if (OutstandingFinalizations == 0) 59 return; 60 61 assert(OutstandingFinalizations > 0 && "All symbols already finalized"); 62 --OutstandingFinalizations; 63 if (OutstandingFinalizations == 0) 64 NotifySymbolsReady(Error::success()); 65 } 66 67 VSO::MaterializationInfo::MaterializationInfo(JITSymbolFlags Flags, 68 AsynchronousSymbolQuery &Query) 69 : Flags(std::move(Flags)), PendingResolution({&Query}) {} 70 71 JITSymbolFlags VSO::MaterializationInfo::getFlags() const { return Flags; } 72 73 JITTargetAddress VSO::MaterializationInfo::getAddress() const { 74 return Address; 75 } 76 77 void VSO::MaterializationInfo::query(SymbolStringPtr Name, 78 AsynchronousSymbolQuery &Query) { 79 if (Address != 0) { 80 Query.setDefinition(Name, JITEvaluatedSymbol(Address, Flags)); 81 PendingFinalization.push_back(&Query); 82 } else 83 PendingResolution.push_back(&Query); 84 } 85 86 void VSO::MaterializationInfo::resolve(SymbolStringPtr Name, 87 JITEvaluatedSymbol Sym) { 88 // FIXME: Sanity check flags? 89 Flags = Sym.getFlags(); 90 Address = Sym.getAddress(); 91 for (auto *Query : PendingResolution) { 92 Query->setDefinition(Name, std::move(Sym)); 93 PendingFinalization.push_back(Query); 94 } 95 PendingResolution = {}; 96 } 97 98 void VSO::MaterializationInfo::finalize() { 99 for (auto *Query : PendingFinalization) 100 Query->notifySymbolFinalized(); 101 PendingFinalization = {}; 102 } 103 104 VSO::SymbolTableEntry::SymbolTableEntry(JITSymbolFlags Flags, 105 SymbolSource &Source) 106 : Flags(JITSymbolFlags::FlagNames(Flags | JITSymbolFlags::NotMaterialized)), 107 Source(&Source) { 108 // FIXME: Assert flag sanity. 109 } 110 111 VSO::SymbolTableEntry::SymbolTableEntry(JITEvaluatedSymbol Sym) 112 : Flags(Sym.getFlags()), Address(Sym.getAddress()) { 113 // FIXME: Assert flag sanity. 114 } 115 116 VSO::SymbolTableEntry::SymbolTableEntry(SymbolTableEntry &&Other) 117 : Flags(Other.Flags), Address(0) { 118 if (Flags.isMaterializing()) 119 MatInfo = std::move(Other.MatInfo); 120 else 121 Source = Other.Source; 122 } 123 124 VSO::SymbolTableEntry::~SymbolTableEntry() { 125 assert(!Flags.isMaterializing() && 126 "Symbol table entry destroyed while symbol was being materialized"); 127 } 128 129 JITSymbolFlags VSO::SymbolTableEntry::getFlags() const { return Flags; } 130 131 void VSO::SymbolTableEntry::replaceWithSource(VSO &V, SymbolStringPtr Name, 132 JITSymbolFlags Flags, 133 SymbolSource &NewSource) { 134 assert(!this->Flags.isMaterializing() && 135 "Attempted to replace symbol with lazy definition during " 136 "materialization"); 137 if (!this->Flags.isMaterialized()) 138 Source->discard(V, Name); 139 this->Flags = Flags; 140 this->Source = &NewSource; 141 } 142 143 SymbolSource *VSO::SymbolTableEntry::query(SymbolStringPtr Name, 144 AsynchronousSymbolQuery &Query) { 145 if (Flags.isMaterializing()) { 146 MatInfo->query(std::move(Name), Query); 147 return nullptr; 148 } else if (Flags.isMaterialized()) { 149 Query.setDefinition(std::move(Name), JITEvaluatedSymbol(Address, Flags)); 150 Query.notifySymbolFinalized(); 151 return nullptr; 152 } 153 SymbolSource *S = Source; 154 new (&MatInfo) std::unique_ptr<MaterializationInfo>( 155 llvm::make_unique<MaterializationInfo>(Flags, Query)); 156 Flags |= JITSymbolFlags::Materializing; 157 return S; 158 } 159 160 void VSO::SymbolTableEntry::resolve(VSO &V, SymbolStringPtr Name, 161 JITEvaluatedSymbol Sym) { 162 if (Flags.isMaterializing()) 163 MatInfo->resolve(std::move(Name), std::move(Sym)); 164 else { 165 // If there's a layer for this symbol. 166 if (!Flags.isMaterialized()) 167 Source->discard(V, Name); 168 169 // FIXME: Should we assert flag state here (flags must match except for 170 // materialization state, overrides must be legal) or in the caller 171 // in VSO? 172 Flags = Sym.getFlags(); 173 Address = Sym.getAddress(); 174 } 175 } 176 177 void VSO::SymbolTableEntry::finalize() { 178 if (Flags.isMaterializing()) { 179 auto TmpMatInfo = std::move(MatInfo); 180 MatInfo.std::unique_ptr<MaterializationInfo>::~unique_ptr(); 181 // FIXME: Assert flag sanity? 182 Flags = TmpMatInfo->getFlags(); 183 Address = TmpMatInfo->getAddress(); 184 TmpMatInfo->finalize(); 185 } 186 assert(Flags.isMaterialized() && "Trying to finalize not-emitted symbol"); 187 } 188 189 VSO::RelativeLinkageStrength VSO::compareLinkage(Optional<JITSymbolFlags> Old, 190 JITSymbolFlags New) { 191 if (Old == None) 192 return llvm::orc::VSO::NewDefinitionIsStronger; 193 194 if (Old->isStrong()) { 195 if (New.isStrong()) 196 return llvm::orc::VSO::DuplicateDefinition; 197 else 198 return llvm::orc::VSO::ExistingDefinitionIsStronger; 199 } else { 200 if (New.isStrong()) 201 return llvm::orc::VSO::NewDefinitionIsStronger; 202 else 203 return llvm::orc::VSO::ExistingDefinitionIsStronger; 204 } 205 } 206 207 VSO::RelativeLinkageStrength 208 VSO::compareLinkage(SymbolStringPtr Name, JITSymbolFlags NewFlags) const { 209 auto I = Symbols.find(Name); 210 return compareLinkage(I == Symbols.end() 211 ? None 212 : Optional<JITSymbolFlags>(I->second.getFlags()), 213 NewFlags); 214 } 215 216 Error VSO::define(SymbolMap NewSymbols) { 217 Error Err = Error::success(); 218 for (auto &KV : NewSymbols) { 219 auto I = Symbols.find(KV.first); 220 auto LinkageResult = compareLinkage( 221 I == Symbols.end() ? None 222 : Optional<JITSymbolFlags>(I->second.getFlags()), 223 KV.second.getFlags()); 224 225 // Silently discard weaker definitions. 226 if (LinkageResult == ExistingDefinitionIsStronger) 227 continue; 228 229 // Report duplicate definition errors. 230 if (LinkageResult == DuplicateDefinition) { 231 Err = joinErrors(std::move(Err), 232 make_error<orc::DuplicateDefinition>(*KV.first)); 233 continue; 234 } 235 236 if (I != Symbols.end()) { 237 I->second.resolve(*this, KV.first, std::move(KV.second)); 238 I->second.finalize(); 239 } else 240 Symbols.insert(std::make_pair(KV.first, std::move(KV.second))); 241 } 242 return Err; 243 } 244 245 Error VSO::defineLazy(const SymbolFlagsMap &NewSymbols, SymbolSource &Source) { 246 Error Err = Error::success(); 247 for (auto &KV : NewSymbols) { 248 auto I = Symbols.find(KV.first); 249 250 auto LinkageResult = compareLinkage( 251 I == Symbols.end() ? None 252 : Optional<JITSymbolFlags>(I->second.getFlags()), 253 KV.second); 254 255 // Discard weaker definitions. 256 if (LinkageResult == ExistingDefinitionIsStronger) 257 Source.discard(*this, KV.first); 258 259 // Report duplicate definition errors. 260 if (LinkageResult == DuplicateDefinition) { 261 Err = joinErrors(std::move(Err), 262 make_error<orc::DuplicateDefinition>(*KV.first)); 263 continue; 264 } 265 266 if (I != Symbols.end()) 267 I->second.replaceWithSource(*this, KV.first, KV.second, Source); 268 else 269 Symbols.emplace( 270 std::make_pair(KV.first, SymbolTableEntry(KV.second, Source))); 271 } 272 return Err; 273 } 274 275 void VSO::resolve(SymbolMap SymbolValues) { 276 for (auto &KV : SymbolValues) { 277 auto I = Symbols.find(KV.first); 278 assert(I != Symbols.end() && "Resolving symbol not present in this dylib"); 279 I->second.resolve(*this, KV.first, std::move(KV.second)); 280 } 281 } 282 283 void VSO::finalize(SymbolNameSet SymbolsToFinalize) { 284 for (auto &S : SymbolsToFinalize) { 285 auto I = Symbols.find(S); 286 assert(I != Symbols.end() && "Finalizing symbol not present in this dylib"); 287 I->second.finalize(); 288 } 289 } 290 291 LookupFlagsResult VSO::lookupFlags(SymbolNameSet Names) { 292 SymbolFlagsMap FlagsFound; 293 294 for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) { 295 auto Tmp = I++; 296 auto SymI = Symbols.find(*Tmp); 297 298 // If the symbol isn't in this dylib then just continue. 299 if (SymI == Symbols.end()) 300 continue; 301 302 Names.erase(Tmp); 303 304 FlagsFound[SymI->first] = 305 JITSymbolFlags::stripTransientFlags(SymI->second.getFlags()); 306 } 307 308 return {std::move(FlagsFound), std::move(Names)}; 309 } 310 311 VSO::LookupResult VSO::lookup(AsynchronousSymbolQuery &Query, 312 SymbolNameSet Names) { 313 SourceWorkMap MaterializationWork; 314 315 for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) { 316 auto Tmp = I++; 317 auto SymI = Symbols.find(*Tmp); 318 319 // If the symbol isn't in this dylib then just continue. 320 if (SymI == Symbols.end()) 321 continue; 322 323 // The symbol is in the dylib. Erase it from Names and proceed. 324 Names.erase(Tmp); 325 326 // Forward the query to the given SymbolTableEntry, and if it return a 327 // layer to perform materialization with, add that to the 328 // MaterializationWork map. 329 if (auto *Source = SymI->second.query(SymI->first, Query)) 330 MaterializationWork[Source].insert(SymI->first); 331 } 332 333 return {std::move(MaterializationWork), std::move(Names)}; 334 } 335 336 ExecutionSession::ExecutionSession(SymbolStringPool &SSP) : SSP(SSP) {} 337 338 VModuleKey ExecutionSession::allocateVModule() { return ++LastKey; } 339 340 void ExecutionSession::releaseVModule(VModuleKey VMod) { 341 // FIXME: Recycle keys. 342 } 343 344 } // End namespace orc. 345 } // End namespace llvm. 346