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