|
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" |
@@ -3430,4 +3431,175 @@ namespace Cpp { |
3430 | 3431 | complete_column); |
3431 | 3432 | } |
3432 | 3433 |
|
| 3434 | +#define DEBUG_TYPE "autoload" |
| 3435 | + |
| 3436 | + static inline std::string DemangleNameForDlsym(const std::string& name) { |
| 3437 | + std::string nameForDlsym = name; |
| 3438 | + |
| 3439 | +#if defined(R__MACOSX) || defined(R__WIN32) |
| 3440 | + // The JIT gives us a mangled name which has an additional leading underscore |
| 3441 | + // on macOS and Windows, for instance __ZN8TRandom34RndmEv. However, dlsym |
| 3442 | + // requires us to remove it. |
| 3443 | + // FIXME: get this information from the DataLayout via getGlobalPrefix()! |
| 3444 | + if (nameForDlsym[0] == '_') |
| 3445 | + nameForDlsym.erase(0, 1); |
| 3446 | +#endif //R__MACOSX |
| 3447 | + |
| 3448 | + return nameForDlsym; |
| 3449 | + } |
| 3450 | + |
| 3451 | + class AutoLoadLibrarySearchGenerator; |
| 3452 | + static AutoLoadLibrarySearchGenerator *ALLSG = nullptr; |
| 3453 | + |
| 3454 | + class AutoLoadLibrarySearchGenerator : public llvm::orc::DefinitionGenerator { |
| 3455 | + public: |
| 3456 | + bool Enabled = false; |
| 3457 | + |
| 3458 | + // Lazy materialization unit class helper |
| 3459 | + class AutoloadLibraryMU : public llvm::orc::MaterializationUnit { |
| 3460 | + std::string lib; |
| 3461 | + llvm::orc::SymbolNameVector syms; |
| 3462 | + public: |
| 3463 | + AutoloadLibraryMU(const std::string &Library, const llvm::orc::SymbolNameVector &Symbols) |
| 3464 | + : MaterializationUnit({getSymbolFlagsMap(Symbols), nullptr}), lib(Library), syms(Symbols) {} |
| 3465 | + |
| 3466 | + StringRef getName() const override { |
| 3467 | + return "<Symbols from Autoloaded Library>"; |
| 3468 | + } |
| 3469 | + |
| 3470 | + void materialize(std::unique_ptr<llvm::orc::MaterializationResponsibility> R) override { |
| 3471 | + if (!ALLSG || !ALLSG->Enabled) { |
| 3472 | + R->failMaterialization(); |
| 3473 | + return; |
| 3474 | + } |
| 3475 | + |
| 3476 | + LLVM_DEBUG(dbgs() << "Materialize " << lib << " syms=" << syms); |
| 3477 | + |
| 3478 | + auto& I = getInterp(); |
| 3479 | + auto DLM = I.getDynamicLibraryManager(); |
| 3480 | + |
| 3481 | + llvm::orc::SymbolMap loadedSymbols; |
| 3482 | + llvm::orc::SymbolNameSet failedSymbols; |
| 3483 | + bool loadedLibrary = false; |
| 3484 | + |
| 3485 | + for (auto symbol : syms) { |
| 3486 | + std::string symbolStr = (*symbol).str(); |
| 3487 | + std::string nameForDlsym = DemangleNameForDlsym(symbolStr); |
| 3488 | + |
| 3489 | + // Check if the symbol is available without loading the library. |
| 3490 | + void *addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(nameForDlsym); |
| 3491 | + |
| 3492 | + if (!addr && !loadedLibrary) { |
| 3493 | + // Try to load the library which should provide the symbol definition. |
| 3494 | + if (DLM->loadLibrary(lib, false) != DynamicLibraryManager::LoadLibResult::kLoadLibSuccess) { |
| 3495 | + LLVM_DEBUG(dbgs() << "MU: Failed to load library " << lib); |
| 3496 | + string err = "MU: Failed to load library! " + lib; |
| 3497 | + perror(err.c_str()); |
| 3498 | + } else { |
| 3499 | + LLVM_DEBUG(dbgs() << "MU: Autoload library " << lib); |
| 3500 | + } |
| 3501 | + |
| 3502 | + // Only try loading the library once. |
| 3503 | + loadedLibrary = true; |
| 3504 | + |
| 3505 | + addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(nameForDlsym); |
| 3506 | + } |
| 3507 | + |
| 3508 | + if (addr) { |
| 3509 | + loadedSymbols[symbol] = |
| 3510 | + llvm::orc::ExecutorSymbolDef(llvm::orc::ExecutorAddr::fromPtr(addr), JITSymbolFlags::Exported); |
| 3511 | + } else { |
| 3512 | + // Collect all failing symbols, delegate their responsibility and then |
| 3513 | + // fail their materialization. R->defineNonExistent() sounds like it |
| 3514 | + // should do that, but it's not implemented?! |
| 3515 | + failedSymbols.insert(symbol); |
| 3516 | + } |
| 3517 | + } |
| 3518 | + |
| 3519 | + if (!failedSymbols.empty()) { |
| 3520 | + auto failingMR = R->delegate(failedSymbols); |
| 3521 | + if (failingMR) { |
| 3522 | + (*failingMR)->failMaterialization(); |
| 3523 | + } |
| 3524 | + } |
| 3525 | + |
| 3526 | + if (!loadedSymbols.empty()) { |
| 3527 | + llvm::cantFail(R->notifyResolved(loadedSymbols)); |
| 3528 | + llvm::cantFail(R->notifyEmitted()); |
| 3529 | + } |
| 3530 | + } |
| 3531 | + |
| 3532 | + void discard(const llvm::orc::JITDylib &JD, const llvm::orc::SymbolStringPtr &Name) override {} |
| 3533 | + |
| 3534 | + private: |
| 3535 | + static llvm::orc::SymbolFlagsMap getSymbolFlagsMap(const llvm::orc::SymbolNameVector &Symbols) { |
| 3536 | + llvm::orc::SymbolFlagsMap map; |
| 3537 | + for (auto symbolName : Symbols) |
| 3538 | + map[symbolName] = llvm::JITSymbolFlags::Exported; |
| 3539 | + return map; |
| 3540 | + } |
| 3541 | + }; |
| 3542 | + |
| 3543 | + llvm::Error tryToGenerate(llvm::orc::LookupState &LS, llvm::orc::LookupKind K, llvm::orc::JITDylib &JD, |
| 3544 | + llvm::orc::JITDylibLookupFlags JDLookupFlags, const llvm::orc::SymbolLookupSet &Symbols) override { |
| 3545 | + if (Enabled) { |
| 3546 | + LLVM_DEBUG(dbgs() << "tryToGenerate"); |
| 3547 | + |
| 3548 | + auto& I = getInterp(); |
| 3549 | + auto DLM = I.getDynamicLibraryManager(); |
| 3550 | + |
| 3551 | + std::unordered_map<std::string, llvm::orc::SymbolNameVector> found; |
| 3552 | + llvm::orc::SymbolMap NewSymbols; |
| 3553 | + for (auto &KV : Symbols) { |
| 3554 | + auto &Name = KV.first; |
| 3555 | + if ((*Name).empty()) |
| 3556 | + continue; |
| 3557 | + |
| 3558 | + auto lib = DLM->searchLibrariesForSymbol(*Name, /*searchSystem=*/true); // false? |
| 3559 | + if (lib.empty()) |
| 3560 | + continue; |
| 3561 | + |
| 3562 | + found[lib].push_back(Name); |
| 3563 | + |
| 3564 | + // Workaround: This getAddressOfGlobal call make first symbol search |
| 3565 | + // to work, immediatelly after library auto load. This approach do not |
| 3566 | + // use MU |
| 3567 | + //DLM->loadLibrary(lib, true); |
| 3568 | + //I.getAddressOfGlobal(*Name); |
| 3569 | + } |
| 3570 | + |
| 3571 | + for (auto &&KV : found) { |
| 3572 | + auto MU = std::make_unique<AutoloadLibraryMU>(KV.first, std::move(KV.second)); |
| 3573 | + if (auto Err = JD.define(MU)) |
| 3574 | + return Err; |
| 3575 | + } |
| 3576 | + } |
| 3577 | + |
| 3578 | + return llvm::Error::success(); |
| 3579 | + } |
| 3580 | + }; |
| 3581 | + |
| 3582 | + void SetLibrariesAutoload(bool autoload /* = true */) { |
| 3583 | + auto& I = getInterp(); |
| 3584 | + llvm::orc::LLJIT& EE = *compat::getExecutionEngine(I); |
| 3585 | +#if CLANG_VERSION_MAJOR < 17 |
| 3586 | + llvm::orc::JITDylib& DyLib = EE.getMainJITDylib(); |
| 3587 | +#else |
| 3588 | + llvm::orc::JITDylib& DyLib = *EE.getProcessSymbolsJITDylib().get(); |
| 3589 | +#endif // CLANG_VERSION_MAJOR |
| 3590 | + |
| 3591 | + if (!ALLSG) |
| 3592 | + ALLSG = &DyLib.addGenerator(std::make_unique<AutoLoadLibrarySearchGenerator>()); |
| 3593 | + ALLSG->Enabled = autoload; |
| 3594 | + |
| 3595 | + LLVM_DEBUG(dbgs() << "Autoload=" << (ALLSG && ALLSG->Enabled ? "ON" : "OFF")); |
| 3596 | + } |
| 3597 | + |
| 3598 | + bool GetLibrariesAutoload() { |
| 3599 | + LLVM_DEBUG(dbgs() << "Autoload is " << (ALLSG && ALLSG->Enabled ? "ON" : "OFF")); |
| 3600 | + return ALLSG && ALLSG->Enabled; |
| 3601 | + } |
| 3602 | + |
| 3603 | +#undef DEBUG_TYPE |
| 3604 | + |
3433 | 3605 | } // end namespace Cpp |
0 commit comments