|
48 | 48 | #include "llvm/Support/Casting.h" |
49 | 49 | #include "llvm/Support/CommandLine.h" |
50 | 50 | #include "llvm/Support/Debug.h" |
| 51 | +#include "llvm/Support/ManagedStatic.h" |
51 | 52 | #include "llvm/Support/raw_os_ostream.h" |
52 | 53 |
|
53 | 54 | #include <algorithm> |
54 | 55 | #include <cassert> |
| 56 | +#include <deque> |
55 | 57 | #include <iterator> |
56 | 58 | #include <map> |
57 | 59 | #include <memory> |
@@ -84,20 +86,47 @@ using namespace std; |
84 | 86 | struct InterpreterInfo { |
85 | 87 | compat::Interpreter* Interpreter = nullptr; |
86 | 88 | bool isOwned = true; |
| 89 | + InterpreterInfo(compat::Interpreter* I, bool Owned) |
| 90 | + : Interpreter(I), isOwned(Owned) {} |
| 91 | + |
| 92 | + // Enable move constructors. |
| 93 | + InterpreterInfo(InterpreterInfo&& other) noexcept |
| 94 | + : Interpreter(other.Interpreter), isOwned(other.isOwned) { |
| 95 | + other.Interpreter = nullptr; |
| 96 | + other.isOwned = false; |
| 97 | + } |
| 98 | + InterpreterInfo& operator=(InterpreterInfo&& other) noexcept { |
| 99 | + if (this != &other) { |
| 100 | + // Delete current resource if owned |
| 101 | + if (isOwned) |
| 102 | + delete Interpreter; |
| 103 | + |
| 104 | + Interpreter = other.Interpreter; |
| 105 | + isOwned = other.isOwned; |
| 106 | + |
| 107 | + other.Interpreter = nullptr; |
| 108 | + other.isOwned = false; |
| 109 | + } |
| 110 | + return *this; |
| 111 | + } |
87 | 112 |
|
88 | | - // Valgrind complains about __cxa_pure_virtual called when deleting |
89 | | - // llvm::SectionMemoryManager::~SectionMemoryManager as part of the dtor |
90 | | - // chain of the Interpreter. |
91 | | - // This might fix the issue https://reviews.llvm.org/D107087 |
92 | | - // FIXME: For now we just leak the Interpreter. |
93 | | - ~InterpreterInfo() = default; |
| 113 | + ~InterpreterInfo() { |
| 114 | + if (isOwned) |
| 115 | + delete Interpreter; |
| 116 | + } |
| 117 | + |
| 118 | + // Disable copy semantics (to avoid accidental double deletes) |
| 119 | + InterpreterInfo(const InterpreterInfo&) = delete; |
| 120 | + InterpreterInfo& operator=(const InterpreterInfo&) = delete; |
94 | 121 | }; |
95 | | -static llvm::SmallVector<InterpreterInfo, 8> sInterpreters; |
| 122 | + |
| 123 | +// std::deque avoids relocations and calling the dtor of InterpreterInfo. |
| 124 | +static llvm::ManagedStatic<std::deque<InterpreterInfo>> sInterpreters; |
96 | 125 |
|
97 | 126 | static compat::Interpreter& getInterp() { |
98 | | - assert(!sInterpreters.empty() && |
| 127 | + assert(!sInterpreters->empty() && |
99 | 128 | "Interpreter instance must be set before calling this!"); |
100 | | - return *sInterpreters.back().Interpreter; |
| 129 | + return *sInterpreters->back().Interpreter; |
101 | 130 | } |
102 | 131 | static clang::Sema& getSema() { return getInterp().getCI()->getSema(); } |
103 | 132 | static clang::ASTContext& getASTContext() { return getSema().getASTContext(); } |
@@ -2934,53 +2963,53 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/, |
2934 | 2963 | llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get()); |
2935 | 2964 | } |
2936 | 2965 |
|
2937 | | - sInterpreters.push_back({I, /*isOwned=*/true}); |
| 2966 | + sInterpreters->emplace_back(I, /*Owned=*/true); |
2938 | 2967 |
|
2939 | 2968 | return I; |
2940 | 2969 | } |
2941 | 2970 |
|
2942 | 2971 | bool DeleteInterpreter(TInterp_t I /*=nullptr*/) { |
2943 | 2972 | if (!I) { |
2944 | | - sInterpreters.pop_back(); |
| 2973 | + sInterpreters->pop_back(); |
2945 | 2974 | return true; |
2946 | 2975 | } |
2947 | 2976 |
|
2948 | | - auto* found = |
2949 | | - std::find_if(sInterpreters.begin(), sInterpreters.end(), |
| 2977 | + auto found = |
| 2978 | + std::find_if(sInterpreters->begin(), sInterpreters->end(), |
2950 | 2979 | [&I](const auto& Info) { return Info.Interpreter == I; }); |
2951 | | - if (found == sInterpreters.end()) |
| 2980 | + if (found == sInterpreters->end()) |
2952 | 2981 | return false; // failure |
2953 | 2982 |
|
2954 | | - sInterpreters.erase(found); |
| 2983 | + sInterpreters->erase(found); |
2955 | 2984 | return true; |
2956 | 2985 | } |
2957 | 2986 |
|
2958 | 2987 | bool ActivateInterpreter(TInterp_t I) { |
2959 | 2988 | if (!I) |
2960 | 2989 | return false; |
2961 | 2990 |
|
2962 | | - auto* found = |
2963 | | - std::find_if(sInterpreters.begin(), sInterpreters.end(), |
| 2991 | + auto found = |
| 2992 | + std::find_if(sInterpreters->begin(), sInterpreters->end(), |
2964 | 2993 | [&I](const auto& Info) { return Info.Interpreter == I; }); |
2965 | | - if (found == sInterpreters.end()) |
| 2994 | + if (found == sInterpreters->end()) |
2966 | 2995 | return false; |
2967 | 2996 |
|
2968 | | - if (std::next(found) != sInterpreters.end()) // if not already last element. |
2969 | | - std::rotate(found, found + 1, sInterpreters.end()); |
| 2997 | + if (std::next(found) != sInterpreters->end()) // if not already last element. |
| 2998 | + std::rotate(found, found + 1, sInterpreters->end()); |
2970 | 2999 |
|
2971 | 3000 | return true; // success |
2972 | 3001 | } |
2973 | 3002 |
|
2974 | 3003 | TInterp_t GetInterpreter() { |
2975 | | - if (sInterpreters.empty()) |
| 3004 | + if (sInterpreters->empty()) |
2976 | 3005 | return nullptr; |
2977 | | - return sInterpreters.back().Interpreter; |
| 3006 | + return sInterpreters->back().Interpreter; |
2978 | 3007 | } |
2979 | 3008 |
|
2980 | 3009 | void UseExternalInterpreter(TInterp_t I) { |
2981 | | - assert(sInterpreters.empty() && "sInterpreter already in use!"); |
2982 | | - sInterpreters.push_back( |
2983 | | - {static_cast<compat::Interpreter*>(I), /*isOwned=*/false}); |
| 3010 | + assert(sInterpreters->empty() && "sInterpreter already in use!"); |
| 3011 | + sInterpreters->emplace_back(static_cast<compat::Interpreter*>(I), |
| 3012 | + /*isOwned=*/false); |
2984 | 3013 | } |
2985 | 3014 |
|
2986 | 3015 | void AddSearchPath(const char* dir, bool isUser, bool prepend) { |
|
0 commit comments