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 flags for each symbol in Symbols that can be found,
35   ///        along with the set of symbol that could not be found.
36   virtual SymbolFlagsMap lookupFlags(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 LookupFlagsFn, typename LookupFn>
50 class LambdaSymbolResolver final : public SymbolResolver {
51 public:
52   template <typename LookupFlagsFnRef, typename LookupFnRef>
LambdaSymbolResolver(LookupFlagsFnRef && LookupFlags,LookupFnRef && Lookup)53   LambdaSymbolResolver(LookupFlagsFnRef &&LookupFlags, LookupFnRef &&Lookup)
54       : LookupFlags(std::forward<LookupFlagsFnRef>(LookupFlags)),
55         Lookup(std::forward<LookupFnRef>(Lookup)) {}
56 
lookupFlags(const SymbolNameSet & Symbols)57   SymbolFlagsMap lookupFlags(const SymbolNameSet &Symbols) final {
58     return LookupFlags(Symbols);
59   }
60 
lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,SymbolNameSet Symbols)61   SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
62                        SymbolNameSet Symbols) final {
63     return Lookup(std::move(Query), std::move(Symbols));
64   }
65 
66 private:
67   LookupFlagsFn LookupFlags;
68   LookupFn Lookup;
69 };
70 
71 /// Creates a SymbolResolver implementation from the pair of supplied
72 ///        function objects.
73 template <typename LookupFlagsFn, typename LookupFn>
74 std::unique_ptr<LambdaSymbolResolver<
75     typename std::remove_cv<
76         typename std::remove_reference<LookupFlagsFn>::type>::type,
77     typename std::remove_cv<
78         typename std::remove_reference<LookupFn>::type>::type>>
createSymbolResolver(LookupFlagsFn && LookupFlags,LookupFn && Lookup)79 createSymbolResolver(LookupFlagsFn &&LookupFlags, LookupFn &&Lookup) {
80   using LambdaSymbolResolverImpl = LambdaSymbolResolver<
81       typename std::remove_cv<
82           typename std::remove_reference<LookupFlagsFn>::type>::type,
83       typename std::remove_cv<
84           typename std::remove_reference<LookupFn>::type>::type>;
85   return llvm::make_unique<LambdaSymbolResolverImpl>(
86       std::forward<LookupFlagsFn>(LookupFlags), std::forward<LookupFn>(Lookup));
87 }
88 
89 class JITSymbolResolverAdapter : public JITSymbolResolver {
90 public:
91   JITSymbolResolverAdapter(ExecutionSession &ES, SymbolResolver &R,
92                            MaterializationResponsibility *MR);
93   Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) override;
94   Expected<LookupResult> lookup(const LookupSet &Symbols) override;
95 
96 private:
97   ExecutionSession &ES;
98   std::set<SymbolStringPtr> ResolvedStrings;
99   SymbolResolver &R;
100   MaterializationResponsibility *MR;
101 };
102 
103 /// Use the given legacy-style FindSymbol function (i.e. a function that
104 ///        takes a const std::string& or StringRef and returns a JITSymbol) to
105 ///        find the flags for each symbol in Symbols and store their flags in
106 ///        SymbolFlags. If any JITSymbol returned by FindSymbol is in an error
107 ///        state the function returns immediately with that error, otherwise it
108 ///        returns the set of symbols not found.
109 ///
110 /// Useful for implementing lookupFlags bodies that query legacy resolvers.
111 template <typename FindSymbolFn>
lookupFlagsWithLegacyFn(const SymbolNameSet & Symbols,FindSymbolFn FindSymbol)112 Expected<SymbolFlagsMap> lookupFlagsWithLegacyFn(const SymbolNameSet &Symbols,
113                                                  FindSymbolFn FindSymbol) {
114   SymbolFlagsMap SymbolFlags;
115 
116   for (auto &S : Symbols) {
117     if (JITSymbol Sym = FindSymbol(*S))
118       SymbolFlags[S] = Sym.getFlags();
119     else if (auto Err = Sym.takeError())
120       return std::move(Err);
121   }
122 
123   return SymbolFlags;
124 }
125 
126 /// Use the given legacy-style FindSymbol function (i.e. a function that
127 ///        takes a const std::string& or StringRef and returns a JITSymbol) to
128 ///        find the address and flags for each symbol in Symbols and store the
129 ///        result in Query. If any JITSymbol returned by FindSymbol is in an
130 ///        error then Query.notifyFailed(...) is called with that error and the
131 ///        function returns immediately. On success, returns the set of symbols
132 ///        not found.
133 ///
134 /// Useful for implementing lookup bodies that query legacy resolvers.
135 template <typename FindSymbolFn>
136 SymbolNameSet
lookupWithLegacyFn(ExecutionSession & ES,AsynchronousSymbolQuery & Query,const SymbolNameSet & Symbols,FindSymbolFn FindSymbol)137 lookupWithLegacyFn(ExecutionSession &ES, AsynchronousSymbolQuery &Query,
138                    const SymbolNameSet &Symbols, FindSymbolFn FindSymbol) {
139   SymbolNameSet SymbolsNotFound;
140   bool NewSymbolsResolved = false;
141 
142   for (auto &S : Symbols) {
143     if (JITSymbol Sym = FindSymbol(*S)) {
144       if (auto Addr = Sym.getAddress()) {
145         Query.resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
146         Query.notifySymbolReady();
147         NewSymbolsResolved = true;
148       } else {
149         ES.legacyFailQuery(Query, Addr.takeError());
150         return SymbolNameSet();
151       }
152     } else if (auto Err = Sym.takeError()) {
153       ES.legacyFailQuery(Query, std::move(Err));
154       return SymbolNameSet();
155     } else
156       SymbolsNotFound.insert(S);
157   }
158 
159   if (NewSymbolsResolved && Query.isFullyResolved())
160     Query.handleFullyResolved();
161 
162   if (NewSymbolsResolved && Query.isFullyReady())
163     Query.handleFullyReady();
164 
165   return SymbolsNotFound;
166 }
167 
168 /// An ORC SymbolResolver implementation that uses a legacy
169 ///        findSymbol-like function to perform lookup;
170 template <typename LegacyLookupFn>
171 class LegacyLookupFnResolver final : public SymbolResolver {
172 public:
173   using ErrorReporter = std::function<void(Error)>;
174 
LegacyLookupFnResolver(ExecutionSession & ES,LegacyLookupFn LegacyLookup,ErrorReporter ReportError)175   LegacyLookupFnResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup,
176                          ErrorReporter ReportError)
177       : ES(ES), LegacyLookup(std::move(LegacyLookup)),
178         ReportError(std::move(ReportError)) {}
179 
lookupFlags(const SymbolNameSet & Symbols)180   SymbolFlagsMap lookupFlags(const SymbolNameSet &Symbols) final {
181     if (auto SymbolFlags = lookupFlagsWithLegacyFn(Symbols, LegacyLookup))
182       return std::move(*SymbolFlags);
183     else {
184       ReportError(SymbolFlags.takeError());
185       return SymbolFlagsMap();
186     }
187   }
188 
lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,SymbolNameSet Symbols)189   SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
190                        SymbolNameSet Symbols) final {
191     return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
192   }
193 
194 private:
195   ExecutionSession &ES;
196   LegacyLookupFn LegacyLookup;
197   ErrorReporter ReportError;
198 };
199 
200 template <typename LegacyLookupFn>
201 std::shared_ptr<LegacyLookupFnResolver<LegacyLookupFn>>
createLegacyLookupResolver(ExecutionSession & ES,LegacyLookupFn LegacyLookup,std::function<void (Error)> ErrorReporter)202 createLegacyLookupResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup,
203                            std::function<void(Error)> ErrorReporter) {
204   return std::make_shared<LegacyLookupFnResolver<LegacyLookupFn>>(
205       ES, std::move(LegacyLookup), std::move(ErrorReporter));
206 }
207 
208 } // End namespace orc
209 } // End namespace llvm
210 
211 #endif // LLVM_EXECUTIONENGINE_ORC_LEGACY_H
212