Skip to content

Commit b6ca0c7

Browse files
committed
[ORC] Add support for custom generators to the C bindings.
C API clients can now define a custom definition generator by providing a callback function (to implement DefinitionGenerator::tryToGenerate) and context object. All arguments for the DefinitionGenerator::tryToGenerate method have been given C API counterparts, and the API allows for optionally asynchronous generation.
1 parent 19402ce commit b6ca0c7

File tree

4 files changed

+243
-9
lines changed

4 files changed

+243
-9
lines changed

llvm/include/llvm-c/Orc.h

+118-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ typedef uint64_t LLVMOrcJITTargetAddress;
4343
*/
4444
typedef struct LLVMOrcOpaqueExecutionSession *LLVMOrcExecutionSessionRef;
4545

46+
/**
47+
* Error reporter function.
48+
*/
49+
typedef void (*LLVMOrcErrorReporterFunction)(void *Ctx, LLVMErrorRef Err);
50+
4651
/**
4752
* A reference to an orc::SymbolStringPool.
4853
*/
@@ -55,9 +60,56 @@ typedef struct LLVMOrcOpaqueSymbolStringPoolEntry
5560
*LLVMOrcSymbolStringPoolEntryRef;
5661

5762
/**
58-
* Error reporter function.
63+
* Lookup kind. This can be used by definition generators when deciding whether
64+
* to produce a definition for a requested symbol.
65+
*
66+
* This enum should be kept in sync with llvm::orc::LookupKind.
5967
*/
60-
typedef void (*LLVMOrcErrorReporterFunction)(void *Ctx, LLVMErrorRef Err);
68+
typedef enum {
69+
LLVMOrcLookupKindStatic,
70+
LLVMOrcLookupKindDLSym
71+
} LLVMOrcLookupKind;
72+
73+
/**
74+
* JITDylib lookup flags. This can be used by definition generators when
75+
* deciding whether to produce a definition for a requested symbol.
76+
*
77+
* This enum should be kept in sync with llvm::orc::JITDylibLookupFlags.
78+
*/
79+
typedef enum {
80+
LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly,
81+
LLVMOrcJITDylibLookupFlagsMatchAllSymbols
82+
} LLVMOrcJITDylibLookupFlags;
83+
84+
/**
85+
* Symbol lookup flags for lookup sets. This should be kept in sync with
86+
* llvm::orc::SymbolLookupFlags.
87+
*/
88+
typedef enum {
89+
LLVMOrcSymbolLookupFlagsRequiredSymbol,
90+
LLVMOrcSymbolLookupFlagsWeaklyReferencedSymbol
91+
} LLVMOrcSymbolLookupFlags;
92+
93+
/**
94+
* An element type for a symbol lookup set.
95+
*/
96+
typedef struct {
97+
LLVMOrcSymbolStringPoolEntryRef Name;
98+
LLVMOrcSymbolLookupFlags LookupFlags;
99+
} LLVMOrcCLookupSetElement;
100+
101+
/**
102+
* A set of symbols to look up / generate.
103+
*
104+
* The list is terminated with an element containing a null pointer for the
105+
* Name field.
106+
*
107+
* If a client creates an instance of this type then they are responsible for
108+
* freeing it, and for ensuring that all strings have been retained over the
109+
* course of its life. Clients receiving a copy from a callback are not
110+
* responsible for managing lifetime or retain counts.
111+
*/
112+
typedef LLVMOrcCLookupSetElement *LLVMOrcCLookupSet;
61113

62114
/**
63115
* A reference to an orc::JITDylib instance.
@@ -75,6 +127,59 @@ typedef struct LLVMOrcOpaqueResourceTracker *LLVMOrcResourceTrackerRef;
75127
typedef struct LLVMOrcOpaqueDefinitionGenerator
76128
*LLVMOrcDefinitionGeneratorRef;
77129

130+
/**
131+
* An opaque lookup state object. Instances of this type can be captured to
132+
* suspend a lookup while a custom generator function attempts to produce a
133+
* definition.
134+
*
135+
* If a client captures a lookup state object then they must eventually call
136+
* LLVMOrcLookupStateContinueLookup to restart the lookup. This is required
137+
* in order to release memory allocated for the lookup state, even if errors
138+
* have occurred while the lookup was suspended (if these errors have made the
139+
* lookup impossible to complete then it will issue its own error before
140+
* destruction).
141+
*/
142+
typedef struct LLVMOrcOpaqueLookupState *LLVMOrcLookupStateRef;
143+
144+
/**
145+
* A custom generator function. This can be used to create a custom generator
146+
* object using LLVMOrcCreateCustomCAPIDefinitionGenerator. The resulting
147+
* object can be attached to a JITDylib, via LLVMOrcJITDylibAddGenerator, to
148+
* receive callbacks when lookups fail to match existing definitions.
149+
*
150+
* GeneratorObj will contain the address of the custom generator object.
151+
*
152+
* Ctx will contain the context object passed to
153+
* LLVMOrcCreateCustomCAPIDefinitionGenerator.
154+
*
155+
* LookupState will contain a pointer to an LLVMOrcLookupStateRef object. This
156+
* can optionally be modified to make the definition generation process
157+
* asynchronous: If the LookupStateRef value is copied, and the original
158+
* LLVMOrcLookupStateRef set to null, the lookup will be suspended. Once the
159+
* asynchronous definition process has been completed clients must call
160+
* LLVMOrcLookupStateContinueLookup to continue the lookup (this should be
161+
* done unconditionally, even if errors have occurred in the mean time, to
162+
* free the lookup state memory and notify the query object of the failures. If
163+
* LookupState is captured this function must return LLVMErrorSuccess.
164+
*
165+
* The Kind argument can be inspected to determine the lookup kind (e.g.
166+
* as-if-during-static-link, or as-if-during-dlsym).
167+
*
168+
* The JD argument specifies which JITDylib the definitions should be generated
169+
* into.
170+
*
171+
* The JDLookupFlags argument can be inspected to determine whether the original
172+
* lookup included non-exported symobls.
173+
*
174+
* Finally, the LookupSet argument contains the set of symbols that could not
175+
* be found in JD already (the set of generation candidates).
176+
*/
177+
typedef LLVMErrorRef (*LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction)(
178+
LLVMOrcDefinitionGeneratorRef GeneratorObj, void *Ctx,
179+
LLVMOrcLookupStateRef *LookupState, LLVMOrcLookupKind Kind,
180+
LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags JDLookupFlags,
181+
LLVMOrcCLookupSet LookupSet);
182+
78183
/**
79184
* Predicate function for SymbolStringPoolEntries.
80185
*/
@@ -156,6 +261,11 @@ void LLVMOrcSymbolStringPoolClearDeadEntries(LLVMOrcSymbolStringPoolRef SSP);
156261
LLVMOrcSymbolStringPoolEntryRef
157262
LLVMOrcExecutionSessionIntern(LLVMOrcExecutionSessionRef ES, const char *Name);
158263

264+
/**
265+
* Increments the ref-count for a SymbolStringPool entry.
266+
*/
267+
void LLVMOrcRetainSymbolStringPoolEntry(LLVMOrcSymbolStringPoolEntryRef S);
268+
159269
/**
160270
* Reduces the ref-count for of a SymbolStringPool entry.
161271
*/
@@ -254,6 +364,12 @@ LLVMErrorRef LLVMOrcJITDylibClear(LLVMOrcJITDylibRef JD);
254364
void LLVMOrcJITDylibAddGenerator(LLVMOrcJITDylibRef JD,
255365
LLVMOrcDefinitionGeneratorRef DG);
256366

367+
/**
368+
* Create a custom generator.
369+
*/
370+
LLVMOrcDefinitionGeneratorRef LLVMOrcCreateCustomCAPIDefinitionGenerator(
371+
void *Ctx, LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction F);
372+
257373
/**
258374
* Get a DynamicLibrarySearchGenerator that will reflect process symbols into
259375
* the JITDylib. On success the resulting generator is owned by the client.

llvm/include/llvm/ExecutionEngine/Orc/Core.h

+7
Original file line numberDiff line numberDiff line change
@@ -845,15 +845,22 @@ class AsynchronousSymbolQuery {
845845
/// DefinitionGenerators can optionally take ownership of a LookupState object
846846
/// to suspend a lookup-in-progress while they search for definitions.
847847
class LookupState {
848+
friend class OrcV2CAPIHelper;
848849
friend class ExecutionSession;
849850

850851
public:
852+
~LookupState();
853+
851854
/// Continue the lookup. This can be called by DefinitionGenerators
852855
/// to re-start a captured query-application operation.
853856
void continueLookup(Error Err);
854857

855858
private:
856859
LookupState(std::unique_ptr<InProgressLookupState> IPLS);
860+
861+
// For C API.
862+
void reset(InProgressLookupState *IPLS);
863+
857864
std::unique_ptr<InProgressLookupState> IPLS;
858865
};
859866

llvm/lib/ExecutionEngine/Orc/Core.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,10 @@ Error ReexportsGenerator::tryToGenerate(LookupState &LS, LookupKind K,
577577
LookupState::LookupState(std::unique_ptr<InProgressLookupState> IPLS)
578578
: IPLS(std::move(IPLS)) {}
579579

580+
void LookupState::reset(InProgressLookupState *IPLS) { this->IPLS.reset(IPLS); }
581+
582+
LookupState::~LookupState() {}
583+
580584
void LookupState::continueLookup(Error Err) {
581585
assert(IPLS && "Cannot call continueLookup on empty LookupState");
582586
auto &ES = IPLS->SearchOrder.begin()->first->getExecutionSession();

llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp

+114-7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ using namespace llvm::orc;
1818
namespace llvm {
1919
namespace orc {
2020

21+
class InProgressLookupState;
22+
2123
class OrcV2CAPIHelper {
2224
public:
2325
using PoolEntry = SymbolStringPtr::PoolEntry;
@@ -33,14 +35,27 @@ class OrcV2CAPIHelper {
3335
return S.S;
3436
}
3537

38+
static void retainPoolEntry(PoolEntryPtr P) {
39+
SymbolStringPtr S(P);
40+
S.S = nullptr;
41+
}
42+
3643
static void releasePoolEntry(PoolEntryPtr P) {
3744
SymbolStringPtr S;
3845
S.S = P;
3946
}
47+
48+
static InProgressLookupState *extractLookupState(LookupState &LS) {
49+
return LS.IPLS.release();
50+
}
51+
52+
static void resetLookupState(LookupState &LS, InProgressLookupState *IPLS) {
53+
return LS.reset(IPLS);
54+
}
4055
};
4156

42-
} // end namespace orc
43-
} // end namespace llvm
57+
} // namespace orc
58+
} // namespace llvm
4459

4560
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ExecutionSession, LLVMOrcExecutionSessionRef)
4661
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SymbolStringPool, LLVMOrcSymbolStringPoolRef)
@@ -50,6 +65,7 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITDylib, LLVMOrcJITDylibRef)
5065
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ResourceTracker, LLVMOrcResourceTrackerRef)
5166
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DefinitionGenerator,
5267
LLVMOrcDefinitionGeneratorRef)
68+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(InProgressLookupState, LLVMOrcLookupStateRef)
5369
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeContext,
5470
LLVMOrcThreadSafeContextRef)
5571
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef)
@@ -60,6 +76,83 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJIT, LLVMOrcLLJITRef)
6076

6177
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
6278

79+
namespace llvm {
80+
namespace orc {
81+
82+
class CAPIDefinitionGenerator final : public DefinitionGenerator {
83+
public:
84+
CAPIDefinitionGenerator(
85+
void *Ctx,
86+
LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction TryToGenerate)
87+
: Ctx(Ctx), TryToGenerate(TryToGenerate) {}
88+
89+
Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
90+
JITDylibLookupFlags JDLookupFlags,
91+
const SymbolLookupSet &LookupSet) override {
92+
93+
// Take the lookup state.
94+
LLVMOrcLookupStateRef LSR = ::wrap(OrcV2CAPIHelper::extractLookupState(LS));
95+
96+
// Translate the lookup kind.
97+
LLVMOrcLookupKind CLookupKind;
98+
switch (K) {
99+
case LookupKind::Static:
100+
CLookupKind = LLVMOrcLookupKindStatic;
101+
break;
102+
case LookupKind::DLSym:
103+
CLookupKind = LLVMOrcLookupKindDLSym;
104+
break;
105+
}
106+
107+
// Translate the JITDylibSearchFlags.
108+
LLVMOrcJITDylibLookupFlags CJDLookupFlags;
109+
switch (JDLookupFlags) {
110+
case JITDylibLookupFlags::MatchExportedSymbolsOnly:
111+
CJDLookupFlags = LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly;
112+
break;
113+
case JITDylibLookupFlags::MatchAllSymbols:
114+
CJDLookupFlags = LLVMOrcJITDylibLookupFlagsMatchAllSymbols;
115+
break;
116+
}
117+
118+
// Translate the lookup set.
119+
std::vector<LLVMOrcCLookupSetElement> CLookupSet;
120+
CLookupSet.reserve(LookupSet.size());
121+
for (auto &KV : LookupSet) {
122+
LLVMOrcSymbolLookupFlags SLF;
123+
switch (KV.second) {
124+
case SymbolLookupFlags::RequiredSymbol:
125+
SLF = LLVMOrcSymbolLookupFlagsRequiredSymbol;
126+
break;
127+
case SymbolLookupFlags::WeaklyReferencedSymbol:
128+
SLF = LLVMOrcSymbolLookupFlagsWeaklyReferencedSymbol;
129+
break;
130+
}
131+
132+
CLookupSet.push_back(
133+
{::wrap(OrcV2CAPIHelper::getRawPoolEntryPtr(KV.first)), SLF});
134+
}
135+
CLookupSet.push_back({nullptr, LLVMOrcSymbolLookupFlagsRequiredSymbol});
136+
137+
// Run the C TryToGenerate function.
138+
auto Err =
139+
unwrap(TryToGenerate(::wrap(this), Ctx, &LSR, CLookupKind, ::wrap(&JD),
140+
CJDLookupFlags, CLookupSet.data()));
141+
142+
// Restore the lookup state.
143+
OrcV2CAPIHelper::resetLookupState(LS, ::unwrap(LSR));
144+
145+
return Err;
146+
}
147+
148+
private:
149+
void *Ctx;
150+
LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction TryToGenerate;
151+
};
152+
153+
} // end namespace orc
154+
} // end namespace llvm
155+
63156
void LLVMOrcExecutionSessionSetErrorReporter(
64157
LLVMOrcExecutionSessionRef ES, LLVMOrcErrorReporterFunction ReportError,
65158
void *Ctx) {
@@ -82,6 +175,10 @@ LLVMOrcExecutionSessionIntern(LLVMOrcExecutionSessionRef ES, const char *Name) {
82175
OrcV2CAPIHelper::releaseSymbolStringPtr(unwrap(ES)->intern(Name)));
83176
}
84177

178+
void LLVMOrcRetainSymbolStringPoolEntry(LLVMOrcSymbolStringPoolEntryRef S) {
179+
OrcV2CAPIHelper::retainPoolEntry(unwrap(S));
180+
}
181+
85182
void LLVMOrcReleaseSymbolStringPoolEntry(LLVMOrcSymbolStringPoolEntryRef S) {
86183
OrcV2CAPIHelper::releasePoolEntry(unwrap(S));
87184
}
@@ -117,6 +214,11 @@ LLVMErrorRef LLVMOrcResourceTrackerRemove(LLVMOrcResourceTrackerRef RT) {
117214
return wrap(TmpRT->remove());
118215
}
119216

217+
void LLVMOrcDisposeDefinitionGenerator(
218+
LLVMOrcDefinitionGeneratorRef DG) {
219+
delete unwrap(DG);
220+
}
221+
120222
LLVMOrcJITDylibRef
121223
LLVMOrcExecutionSessionCreateBareJITDylib(LLVMOrcExecutionSessionRef ES,
122224
const char *Name) {
@@ -140,11 +242,6 @@ LLVMOrcExecutionSessionGetJITDylibByName(LLVMOrcExecutionSessionRef ES,
140242
return wrap(unwrap(ES)->getJITDylibByName(Name));
141243
}
142244

143-
void LLVMOrcDisposeDefinitionGenerator(
144-
LLVMOrcDefinitionGeneratorRef DG) {
145-
delete unwrap(DG);
146-
}
147-
148245
LLVMErrorRef LLVMOrcJITDylibClear(LLVMOrcJITDylibRef JD) {
149246
return wrap(unwrap(JD)->clear());
150247
}
@@ -154,6 +251,16 @@ void LLVMOrcJITDylibAddGenerator(LLVMOrcJITDylibRef JD,
154251
unwrap(JD)->addGenerator(std::unique_ptr<DefinitionGenerator>(unwrap(DG)));
155252
}
156253

254+
void LLVMOrcDisposeDefinitionGenerator(LLVMOrcDefinitionGeneratorRef DG) {
255+
std::unique_ptr<DefinitionGenerator> TmpDG(unwrap(DG));
256+
}
257+
258+
LLVMOrcDefinitionGeneratorRef LLVMOrcCreateCustomCAPIDefinitionGenerator(
259+
void *Ctx, LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction F) {
260+
auto DG = std::make_unique<CAPIDefinitionGenerator>(Ctx, F);
261+
return wrap(DG.release());
262+
}
263+
157264
LLVMErrorRef LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(
158265
LLVMOrcDefinitionGeneratorRef *Result, char GlobalPrefix,
159266
LLVMOrcSymbolPredicate Filter, void *FilterCtx) {

0 commit comments

Comments
 (0)