|
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 O) |
| 90 | + : Interpreter(I), isOwned(O) {} |
| 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,52 +2963,52 @@ 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, /*isOwned=*/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( |
| 3010 | + assert(sInterpreters->empty() && "sInterpreter already in use!"); |
| 3011 | + sInterpreters->push_back( |
2983 | 3012 | {static_cast<compat::Interpreter*>(I), /*isOwned=*/false});
|
2984 | 3013 | }
|
2985 | 3014 |
|
|
0 commit comments