1 | //===--- Legacy.h -- Adapters for ExecutionEngine API interop ---*- C++ -*-===// |
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 | // Contains core ORC APIs. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_EXECUTIONENGINE_ORC_LEGACY_H |
15 | #define LLVM_EXECUTIONENGINE_ORC_LEGACY_H |
16 | |
17 | #include "llvm/ExecutionEngine/JITSymbol.h" |
18 | #include "llvm/ExecutionEngine/Orc/Core.h" |
19 | |
20 | namespace llvm { |
21 | namespace orc { |
22 | |
23 | /// SymbolResolver is a composable interface for looking up symbol flags |
24 | /// and addresses using the AsynchronousSymbolQuery type. It will |
25 | /// eventually replace the LegacyJITSymbolResolver interface as the |
26 | /// stardard ORC symbol resolver type. |
27 | /// |
28 | /// FIXME: SymbolResolvers should go away and be replaced with VSOs with |
29 | /// defenition generators. |
30 | class SymbolResolver { |
31 | public: |
32 | virtual ~SymbolResolver() = default; |
33 | |
34 | /// Returns the subset of the given symbols that the caller is responsible for |
35 | /// materializing. |
36 | virtual SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) = 0; |
37 | |
38 | /// For each symbol in Symbols that can be found, assigns that symbols |
39 | /// value in Query. Returns the set of symbols that could not be found. |
40 | virtual SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query, |
41 | SymbolNameSet Symbols) = 0; |
42 | |
43 | private: |
44 | virtual void anchor(); |
45 | }; |
46 | |
47 | /// Implements SymbolResolver with a pair of supplied function objects |
48 | /// for convenience. See createSymbolResolver. |
49 | template <typename GetResponsibilitySetFn, typename LookupFn> |
50 | class LambdaSymbolResolver final : public SymbolResolver { |
51 | public: |
52 | template <typename GetResponsibilitySetFnRef, typename LookupFnRef> |
53 | LambdaSymbolResolver(GetResponsibilitySetFnRef &&GetResponsibilitySet, |
54 | LookupFnRef &&Lookup) |
55 | : GetResponsibilitySet( |
56 | std::forward<GetResponsibilitySetFnRef>(GetResponsibilitySet)), |
57 | Lookup(std::forward<LookupFnRef>(Lookup)) {} |
58 | |
59 | SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) final { |
60 | return GetResponsibilitySet(Symbols); |
61 | } |
62 | |
63 | SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query, |
64 | SymbolNameSet Symbols) final { |
65 | return Lookup(std::move(Query), std::move(Symbols)); |
66 | } |
67 | |
68 | private: |
69 | GetResponsibilitySetFn GetResponsibilitySet; |
70 | LookupFn Lookup; |
71 | }; |
72 | |
73 | /// Creates a SymbolResolver implementation from the pair of supplied |
74 | /// function objects. |
75 | template <typename GetResponsibilitySetFn, typename LookupFn> |
76 | std::unique_ptr<LambdaSymbolResolver< |
77 | typename std::remove_cv< |
78 | typename std::remove_reference<GetResponsibilitySetFn>::type>::type, |
79 | typename std::remove_cv< |
80 | typename std::remove_reference<LookupFn>::type>::type>> |
81 | createSymbolResolver(GetResponsibilitySetFn &&GetResponsibilitySet, |
82 | LookupFn &&Lookup) { |
83 | using LambdaSymbolResolverImpl = LambdaSymbolResolver< |
84 | typename std::remove_cv< |
85 | typename std::remove_reference<GetResponsibilitySetFn>::type>::type, |
86 | typename std::remove_cv< |
87 | typename std::remove_reference<LookupFn>::type>::type>; |
88 | return llvm::make_unique<LambdaSymbolResolverImpl>( |
89 | std::forward<GetResponsibilitySetFn>(GetResponsibilitySet), |
90 | std::forward<LookupFn>(Lookup)); |
91 | } |
92 | |
93 | /// Legacy adapter. Remove once we kill off the old ORC layers. |
94 | class JITSymbolResolverAdapter : public JITSymbolResolver { |
95 | public: |
96 | JITSymbolResolverAdapter(ExecutionSession &ES, SymbolResolver &R, |
97 | MaterializationResponsibility *MR); |
98 | Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) override; |
99 | void lookup(const LookupSet &Symbols, OnResolvedFunction OnResolved) override; |
100 | |
101 | private: |
102 | ExecutionSession &ES; |
103 | std::set<SymbolStringPtr> ResolvedStrings; |
104 | SymbolResolver &R; |
105 | MaterializationResponsibility *MR; |
106 | }; |
107 | |
108 | /// Use the given legacy-style FindSymbol function (i.e. a function that takes |
109 | /// a const std::string& or StringRef and returns a JITSymbol) to get the |
110 | /// subset of symbols that the caller is responsible for materializing. If any |
111 | /// JITSymbol returned by FindSymbol is in an error state the function returns |
112 | /// immediately with that error. |
113 | /// |
114 | /// Useful for implementing getResponsibilitySet bodies that query legacy |
115 | /// resolvers. |
116 | template <typename FindSymbolFn> |
117 | Expected<SymbolNameSet> |
118 | getResponsibilitySetWithLegacyFn(const SymbolNameSet &Symbols, |
119 | FindSymbolFn FindSymbol) { |
120 | SymbolNameSet Result; |
121 | |
122 | for (auto &S : Symbols) { |
123 | if (JITSymbol Sym = FindSymbol(*S)) { |
124 | if (!Sym.getFlags().isStrong()) |
125 | Result.insert(S); |
126 | } else if (auto Err = Sym.takeError()) |
127 | return std::move(Err); |
128 | } |
129 | |
130 | return Result; |
131 | } |
132 | |
133 | /// Use the given legacy-style FindSymbol function (i.e. a function that |
134 | /// takes a const std::string& or StringRef and returns a JITSymbol) to |
135 | /// find the address and flags for each symbol in Symbols and store the |
136 | /// result in Query. If any JITSymbol returned by FindSymbol is in an |
137 | /// error then Query.notifyFailed(...) is called with that error and the |
138 | /// function returns immediately. On success, returns the set of symbols |
139 | /// not found. |
140 | /// |
141 | /// Useful for implementing lookup bodies that query legacy resolvers. |
142 | template <typename FindSymbolFn> |
143 | SymbolNameSet |
144 | lookupWithLegacyFn(ExecutionSession &ES, AsynchronousSymbolQuery &Query, |
145 | const SymbolNameSet &Symbols, FindSymbolFn FindSymbol) { |
146 | SymbolNameSet SymbolsNotFound; |
147 | bool NewSymbolsResolved = false; |
148 | |
149 | for (auto &S : Symbols) { |
150 | if (JITSymbol Sym = FindSymbol(*S)) { |
151 | if (auto Addr = Sym.getAddress()) { |
152 | Query.resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags())); |
153 | Query.notifySymbolReady(); |
154 | NewSymbolsResolved = true; |
155 | } else { |
156 | ES.legacyFailQuery(Query, Addr.takeError()); |
157 | return SymbolNameSet(); |
158 | } |
159 | } else if (auto Err = Sym.takeError()) { |
160 | ES.legacyFailQuery(Query, std::move(Err)); |
161 | return SymbolNameSet(); |
162 | } else |
163 | SymbolsNotFound.insert(S); |
164 | } |
165 | |
166 | if (NewSymbolsResolved && Query.isFullyResolved()) |
167 | Query.handleFullyResolved(); |
168 | |
169 | if (NewSymbolsResolved && Query.isFullyReady()) |
170 | Query.handleFullyReady(); |
171 | |
172 | return SymbolsNotFound; |
173 | } |
174 | |
175 | /// An ORC SymbolResolver implementation that uses a legacy |
176 | /// findSymbol-like function to perform lookup; |
177 | template <typename LegacyLookupFn> |
178 | class LegacyLookupFnResolver final : public SymbolResolver { |
179 | public: |
180 | using ErrorReporter = std::function<void(Error)>; |
181 | |
182 | LegacyLookupFnResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup, |
183 | ErrorReporter ReportError) |
184 | : ES(ES), LegacyLookup(std::move(LegacyLookup)), |
185 | ReportError(std::move(ReportError)) {} |
186 | |
187 | SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) final { |
188 | if (auto ResponsibilitySet = |
189 | getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup)) |
190 | return std::move(*ResponsibilitySet); |
191 | else { |
192 | ReportError(ResponsibilitySet.takeError()); |
193 | return SymbolNameSet(); |
194 | } |
195 | } |
196 | |
197 | SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query, |
198 | SymbolNameSet Symbols) final { |
199 | return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup); |
200 | } |
201 | |
202 | private: |
203 | ExecutionSession &ES; |
204 | LegacyLookupFn LegacyLookup; |
205 | ErrorReporter ReportError; |
206 | }; |
207 | |
208 | template <typename LegacyLookupFn> |
209 | std::shared_ptr<LegacyLookupFnResolver<LegacyLookupFn>> |
210 | createLegacyLookupResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup, |
211 | std::function<void(Error)> ErrorReporter) { |
212 | return std::make_shared<LegacyLookupFnResolver<LegacyLookupFn>>( |
213 | ES, std::move(LegacyLookup), std::move(ErrorReporter)); |
214 | } |
215 | |
216 | } // End namespace orc |
217 | } // End namespace llvm |
218 | |
219 | #endif // LLVM_EXECUTIONENGINE_ORC_LEGACY_H |
220 | |