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