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