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
20namespace llvm {
21namespace 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.
30class SymbolResolver {
31public:
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
43private:
44 virtual void anchor();
45};
46
47/// Implements SymbolResolver with a pair of supplied function objects
48/// for convenience. See createSymbolResolver.
49template <typename GetResponsibilitySetFn, typename LookupFn>
50class LambdaSymbolResolver final : public SymbolResolver {
51public:
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
68private:
69 GetResponsibilitySetFn GetResponsibilitySet;
70 LookupFn Lookup;
71};
72
73/// Creates a SymbolResolver implementation from the pair of supplied
74/// function objects.
75template <typename GetResponsibilitySetFn, typename LookupFn>
76std::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>>
81createSymbolResolver(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.
94class JITSymbolResolverAdapter : public JITSymbolResolver {
95public:
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
101private:
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.
116template <typename FindSymbolFn>
117Expected<SymbolNameSet>
118getResponsibilitySetWithLegacyFn(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.
142template <typename FindSymbolFn>
143SymbolNameSet
144lookupWithLegacyFn(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;
177template <typename LegacyLookupFn>
178class LegacyLookupFnResolver final : public SymbolResolver {
179public:
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
202private:
203 ExecutionSession &ES;
204 LegacyLookupFn LegacyLookup;
205 ErrorReporter ReportError;
206};
207
208template <typename LegacyLookupFn>
209std::shared_ptr<LegacyLookupFnResolver<LegacyLookupFn>>
210createLegacyLookupResolver(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