|
30 | 30 | #include "clang/Sema/TemplateDeduction.h" |
31 | 31 |
|
32 | 32 | #include "llvm/ADT/StringRef.h" |
| 33 | +#include "llvm/ExecutionEngine/Orc/Core.h" |
33 | 34 | #include "llvm/Support/Casting.h" |
34 | 35 | #include "llvm/Support/Debug.h" |
35 | 36 | #include "llvm/Support/raw_os_ostream.h" |
@@ -3356,4 +3357,175 @@ namespace Cpp { |
3356 | 3357 | complete_column); |
3357 | 3358 | } |
3358 | 3359 |
|
| 3360 | +#define DEBUG_TYPE "autoload" |
| 3361 | + |
| 3362 | + static inline std::string DemangleNameForDlsym(const std::string& name) { |
| 3363 | + std::string nameForDlsym = name; |
| 3364 | + |
| 3365 | +#if defined(R__MACOSX) || defined(R__WIN32) |
| 3366 | + // The JIT gives us a mangled name which has an additional leading underscore |
| 3367 | + // on macOS and Windows, for instance __ZN8TRandom34RndmEv. However, dlsym |
| 3368 | + // requires us to remove it. |
| 3369 | + // FIXME: get this information from the DataLayout via getGlobalPrefix()! |
| 3370 | + if (nameForDlsym[0] == '_') |
| 3371 | + nameForDlsym.erase(0, 1); |
| 3372 | +#endif //R__MACOSX |
| 3373 | + |
| 3374 | + return nameForDlsym; |
| 3375 | + } |
| 3376 | + |
| 3377 | + class AutoLoadLibrarySearchGenerator; |
| 3378 | + static AutoLoadLibrarySearchGenerator *ALLSG = nullptr; |
| 3379 | + |
| 3380 | + class AutoLoadLibrarySearchGenerator : public llvm::orc::DefinitionGenerator { |
| 3381 | + public: |
| 3382 | + bool Enabled = false; |
| 3383 | + |
| 3384 | + // Lazy materialization unit class helper |
| 3385 | + class AutoloadLibraryMU : public llvm::orc::MaterializationUnit { |
| 3386 | + std::string lib; |
| 3387 | + llvm::orc::SymbolNameVector syms; |
| 3388 | + public: |
| 3389 | + AutoloadLibraryMU(const std::string &Library, const llvm::orc::SymbolNameVector &Symbols) |
| 3390 | + : MaterializationUnit({getSymbolFlagsMap(Symbols), nullptr}), lib(Library), syms(Symbols) {} |
| 3391 | + |
| 3392 | + StringRef getName() const override { |
| 3393 | + return "<Symbols from Autoloaded Library>"; |
| 3394 | + } |
| 3395 | + |
| 3396 | + void materialize(std::unique_ptr<llvm::orc::MaterializationResponsibility> R) override { |
| 3397 | + if (!ALLSG || !ALLSG->Enabled) { |
| 3398 | + R->failMaterialization(); |
| 3399 | + return; |
| 3400 | + } |
| 3401 | + |
| 3402 | + LLVM_DEBUG(dbgs() << "Materialize " << lib << " syms=" << syms); |
| 3403 | + |
| 3404 | + auto& I = getInterp(); |
| 3405 | + auto DLM = I.getDynamicLibraryManager(); |
| 3406 | + |
| 3407 | + llvm::orc::SymbolMap loadedSymbols; |
| 3408 | + llvm::orc::SymbolNameSet failedSymbols; |
| 3409 | + bool loadedLibrary = false; |
| 3410 | + |
| 3411 | + for (auto symbol : syms) { |
| 3412 | + std::string symbolStr = (*symbol).str(); |
| 3413 | + std::string nameForDlsym = DemangleNameForDlsym(symbolStr); |
| 3414 | + |
| 3415 | + // Check if the symbol is available without loading the library. |
| 3416 | + void *addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(nameForDlsym); |
| 3417 | + |
| 3418 | + if (!addr && !loadedLibrary) { |
| 3419 | + // Try to load the library which should provide the symbol definition. |
| 3420 | + if (DLM->loadLibrary(lib, false) != DynamicLibraryManager::LoadLibResult::kLoadLibSuccess) { |
| 3421 | + LLVM_DEBUG(dbgs() << "MU: Failed to load library " << lib); |
| 3422 | + string err = "MU: Failed to load library! " + lib; |
| 3423 | + perror(err.c_str()); |
| 3424 | + } else { |
| 3425 | + LLVM_DEBUG(dbgs() << "MU: Autoload library " << lib); |
| 3426 | + } |
| 3427 | + |
| 3428 | + // Only try loading the library once. |
| 3429 | + loadedLibrary = true; |
| 3430 | + |
| 3431 | + addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(nameForDlsym); |
| 3432 | + } |
| 3433 | + |
| 3434 | + if (addr) { |
| 3435 | + loadedSymbols[symbol] = |
| 3436 | + llvm::orc::ExecutorSymbolDef(llvm::orc::ExecutorAddr::fromPtr(addr), JITSymbolFlags::Exported); |
| 3437 | + } else { |
| 3438 | + // Collect all failing symbols, delegate their responsibility and then |
| 3439 | + // fail their materialization. R->defineNonExistent() sounds like it |
| 3440 | + // should do that, but it's not implemented?! |
| 3441 | + failedSymbols.insert(symbol); |
| 3442 | + } |
| 3443 | + } |
| 3444 | + |
| 3445 | + if (!failedSymbols.empty()) { |
| 3446 | + auto failingMR = R->delegate(failedSymbols); |
| 3447 | + if (failingMR) { |
| 3448 | + (*failingMR)->failMaterialization(); |
| 3449 | + } |
| 3450 | + } |
| 3451 | + |
| 3452 | + if (!loadedSymbols.empty()) { |
| 3453 | + llvm::cantFail(R->notifyResolved(loadedSymbols)); |
| 3454 | + llvm::cantFail(R->notifyEmitted()); |
| 3455 | + } |
| 3456 | + } |
| 3457 | + |
| 3458 | + void discard(const llvm::orc::JITDylib &JD, const llvm::orc::SymbolStringPtr &Name) override {} |
| 3459 | + |
| 3460 | + private: |
| 3461 | + static llvm::orc::SymbolFlagsMap getSymbolFlagsMap(const llvm::orc::SymbolNameVector &Symbols) { |
| 3462 | + llvm::orc::SymbolFlagsMap map; |
| 3463 | + for (auto symbolName : Symbols) |
| 3464 | + map[symbolName] = llvm::JITSymbolFlags::Exported; |
| 3465 | + return map; |
| 3466 | + } |
| 3467 | + }; |
| 3468 | + |
| 3469 | + llvm::Error tryToGenerate(llvm::orc::LookupState &LS, llvm::orc::LookupKind K, llvm::orc::JITDylib &JD, |
| 3470 | + llvm::orc::JITDylibLookupFlags JDLookupFlags, const llvm::orc::SymbolLookupSet &Symbols) override { |
| 3471 | + if (Enabled) { |
| 3472 | + LLVM_DEBUG(dbgs() << "tryToGenerate"); |
| 3473 | + |
| 3474 | + auto& I = getInterp(); |
| 3475 | + auto DLM = I.getDynamicLibraryManager(); |
| 3476 | + |
| 3477 | + std::unordered_map<std::string, llvm::orc::SymbolNameVector> found; |
| 3478 | + llvm::orc::SymbolMap NewSymbols; |
| 3479 | + for (auto &KV : Symbols) { |
| 3480 | + auto &Name = KV.first; |
| 3481 | + if ((*Name).empty()) |
| 3482 | + continue; |
| 3483 | + |
| 3484 | + auto lib = DLM->searchLibrariesForSymbol(*Name, /*searchSystem=*/true); // false? |
| 3485 | + if (lib.empty()) |
| 3486 | + continue; |
| 3487 | + |
| 3488 | + found[lib].push_back(Name); |
| 3489 | + |
| 3490 | + // Workaround: This getAddressOfGlobal call make first symbol search |
| 3491 | + // to work, immediatelly after library auto load. This approach do not |
| 3492 | + // use MU |
| 3493 | + //DLM->loadLibrary(lib, true); |
| 3494 | + //I.getAddressOfGlobal(*Name); |
| 3495 | + } |
| 3496 | + |
| 3497 | + for (auto &&KV : found) { |
| 3498 | + auto MU = std::make_unique<AutoloadLibraryMU>(KV.first, std::move(KV.second)); |
| 3499 | + if (auto Err = JD.define(MU)) |
| 3500 | + return Err; |
| 3501 | + } |
| 3502 | + } |
| 3503 | + |
| 3504 | + return llvm::Error::success(); |
| 3505 | + } |
| 3506 | + }; |
| 3507 | + |
| 3508 | + void SetLibrariesAutoload(bool autoload /* = true */) { |
| 3509 | + auto& I = getInterp(); |
| 3510 | + llvm::orc::LLJIT& EE = *compat::getExecutionEngine(I); |
| 3511 | +#if CLANG_VERSION_MAJOR < 17 |
| 3512 | + llvm::orc::JITDylib& DyLib = EE.getMainJITDylib(); |
| 3513 | +#else |
| 3514 | + llvm::orc::JITDylib& DyLib = *EE.getProcessSymbolsJITDylib().get(); |
| 3515 | +#endif // CLANG_VERSION_MAJOR |
| 3516 | + |
| 3517 | + if (!ALLSG) |
| 3518 | + ALLSG = &DyLib.addGenerator(std::make_unique<AutoLoadLibrarySearchGenerator>()); |
| 3519 | + ALLSG->Enabled = autoload; |
| 3520 | + |
| 3521 | + LLVM_DEBUG(dbgs() << "Autoload=" << (ALLSG && ALLSG->Enabled ? "ON" : "OFF")); |
| 3522 | + } |
| 3523 | + |
| 3524 | + bool GetLibrariesAutoload() { |
| 3525 | + LLVM_DEBUG(dbgs() << "Autoload is " << (ALLSG && ALLSG->Enabled ? "ON" : "OFF")); |
| 3526 | + return ALLSG && ALLSG->Enabled; |
| 3527 | + } |
| 3528 | + |
| 3529 | +#undef DEBUG_TYPE |
| 3530 | + |
3359 | 3531 | } // end namespace Cpp |
0 commit comments