Skip to content

Commit bdf5f9c

Browse files
committed
[ORC] Introduce SetUpExecutorNativePlatform utility.
Simplifies the process of building an LLJIT instance that supports the native platform features (initializers, TLV, etc.). SetUpExecutorNativePlatform can be passed to LLJITBuilder::setPlatformSetUp method. It takes a reference to the ORC runtime (as a path or an in-memory archive) and automatically sets the platform for LLJIT's ExecutionSession based on the executor process's triple. Differential Revision: https://reviews.llvm.org/D144276
1 parent 0aeaec3 commit bdf5f9c

File tree

8 files changed

+381
-140
lines changed

8 files changed

+381
-140
lines changed

llvm/include/llvm/ExecutionEngine/Orc/COFFPlatform.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ class COFFPlatform : public Platform {
3939

4040
/// Try to create a COFFPlatform instance, adding the ORC runtime to the
4141
/// given JITDylib.
42+
static Expected<std::unique_ptr<COFFPlatform>>
43+
Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
44+
JITDylib &PlatformJD,
45+
std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
46+
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime = false,
47+
const char *VCRuntimePath = nullptr,
48+
std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
49+
4250
static Expected<std::unique_ptr<COFFPlatform>>
4351
Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
4452
JITDylib &PlatformJD, const char *OrcRuntimePath,
@@ -136,10 +144,14 @@ class COFFPlatform : public Platform {
136144

137145
static bool supportedTarget(const Triple &TT);
138146

139-
COFFPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
140-
JITDylib &PlatformJD, const char *OrcRuntimePath,
141-
LoadDynamicLibrary LoadDynamicLibrary, bool StaticVCRuntime,
142-
const char *VCRuntimePath, Error &Err);
147+
COFFPlatform(
148+
ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
149+
JITDylib &PlatformJD,
150+
std::unique_ptr<StaticLibraryDefinitionGenerator> OrcRuntimeGenerator,
151+
std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
152+
std::unique_ptr<object::Archive> OrcRuntimeArchive,
153+
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
154+
const char *VCRuntimePath, Error &Err);
143155

144156
// Associate COFFPlatform JIT-side runtime support functions with handlers.
145157
Error associateRuntimeSupportFunctions(JITDylib &PlatformJD);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,10 @@ class JITDylib : public ThreadSafeRefCountedBase<JITDylib>,
10541054
void setLinkOrder(JITDylibSearchOrder NewSearchOrder,
10551055
bool LinkAgainstThisJITDylibFirst = true);
10561056

1057+
/// Append the given JITDylibSearchOrder to the link order for this
1058+
/// JITDylib.
1059+
void addToLinkOrder(const JITDylibSearchOrder &NewLinks);
1060+
10571061
/// Add the given JITDylib to the link order for definitions in this
10581062
/// JITDylib.
10591063
///

llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class ExecutorProcessControl;
3737
class LLJIT {
3838
template <typename, typename, typename> friend class LLJITBuilderSetters;
3939

40-
friend void setUpGenericLLVMIRPlatform(LLJIT &J);
40+
friend Expected<JITDylibSP> setUpGenericLLVMIRPlatform(LLJIT &J);
4141

4242
public:
4343
/// Initializer support for LLJIT.
@@ -70,6 +70,20 @@ class LLJIT {
7070
/// Returns a reference to the JITDylib representing the JIT'd main program.
7171
JITDylib &getMainJITDylib() { return *Main; }
7272

73+
/// Returns the ProcessSymbols JITDylib, which by default reflects non-JIT'd
74+
/// symbols in the host process.
75+
///
76+
/// Note: JIT'd code should not be added to the ProcessSymbols JITDylib. Use
77+
/// the main JITDylib or a custom JITDylib instead.
78+
JITDylibSP getProcessSymbolsJITDylib();
79+
80+
/// Returns the Platform JITDylib, which will contain the ORC runtime (if
81+
/// given) and any platform symbols.
82+
///
83+
/// Note: JIT'd code should not be added to the Platform JITDylib. Use the
84+
/// main JITDylib or a custom JITDylib instead.
85+
JITDylibSP getPlatformJITDylib();
86+
7387
/// Returns the JITDylib with the given name, or nullptr if no JITDylib with
7488
/// that name exists.
7589
JITDylib *getJITDylibByName(StringRef Name) {
@@ -82,9 +96,12 @@ class LLJIT {
8296
/// input or elsewhere in the environment then the client should check
8397
/// (e.g. by calling getJITDylibByName) that the given name is not already in
8498
/// use.
85-
Expected<JITDylib &> createJITDylib(std::string Name) {
86-
return ES->createJITDylib(std::move(Name));
87-
}
99+
Expected<JITDylib &> createJITDylib(std::string Name);
100+
101+
/// Returns the default link order for this LLJIT instance. This link order
102+
/// will be appended to the link order of JITDylibs created by LLJIT's
103+
/// createJITDylib method.
104+
JITDylibSearchOrder defaultLinkOrder() { return DefaultLinks; }
88105

89106
/// Adds an IR module with the given ResourceTracker.
90107
Error addIRModule(ResourceTrackerSP RT, ThreadSafeModule TSM);
@@ -203,6 +220,10 @@ class LLJIT {
203220
std::unique_ptr<PlatformSupport> PS;
204221

205222
JITDylib *Main = nullptr;
223+
JITDylib *ProcessSymbols = nullptr;
224+
JITDylib *Platform = nullptr;
225+
226+
JITDylibSearchOrder DefaultLinks;
206227

207228
DataLayout DL;
208229
Triple TT;
@@ -258,12 +279,17 @@ class LLJITBuilderState {
258279
std::function<Expected<std::unique_ptr<IRCompileLayer::IRCompiler>>(
259280
JITTargetMachineBuilder JTMB)>;
260281

261-
using PlatformSetupFunction = std::function<Error(LLJIT &J)>;
282+
using ProcessSymbolsJITDylibSetupFunction =
283+
std::function<Error(JITDylib &JD)>;
284+
285+
using PlatformSetupFunction = unique_function<Expected<JITDylibSP>(LLJIT &J)>;
262286

263287
std::unique_ptr<ExecutorProcessControl> EPC;
264288
std::unique_ptr<ExecutionSession> ES;
265289
std::optional<JITTargetMachineBuilder> JTMB;
266290
std::optional<DataLayout> DL;
291+
bool LinkProcessSymbolsJITDylibByDefault = true;
292+
ProcessSymbolsJITDylibSetupFunction SetupProcessSymbolsJITDylib;
267293
ObjectLinkingLayerCreator CreateObjectLinkingLayer;
268294
CompileFunctionCreator CreateCompileFunction;
269295
PlatformSetupFunction SetUpPlatform;
@@ -316,6 +342,29 @@ class LLJITBuilderSetters {
316342
return impl();
317343
}
318344

345+
/// The LinkProcessSymbolsJITDylibDyDefault flag determines whether the
346+
/// "Process" JITDylib will be added to the default link order at LLJIT
347+
/// construction time. If true, the Process JITDylib will be added as the last
348+
/// item in the default link order. If false (or if the Process JITDylib is
349+
/// disabled via setProcessSymbolsJITDylibSetup) then the Process JITDylib
350+
/// will not appear in the default link order.
351+
SetterImpl &
352+
setLinkProcessSymbolsJITDylibByDefault(bool LinkProcessSymsByDefault) {
353+
impl().LinkProcessSymbolsJITDylibByDefault = LinkProcessSymsByDefault;
354+
return impl();
355+
}
356+
357+
/// Set a setup function for the process symbols dylib. If not provided,
358+
/// but LinkProcessSymbolsJITDylibByDefault is true, then the process-symbols
359+
/// JITDylib will be configured with a DynamicLibrarySearchGenerator with a
360+
/// default symbol filter.
361+
SetterImpl &setProcessSymbolsJITDylibSetup(
362+
LLJITBuilderState::ProcessSymbolsJITDylibSetupFunction
363+
SetupProcessSymbolsJITDylib) {
364+
impl().SetupProcessSymbolsJITDylib = std::move(SetupProcessSymbolsJITDylib);
365+
return impl();
366+
}
367+
319368
/// Set an ObjectLinkingLayer creation function.
320369
///
321370
/// If this method is not called, a default creation function will be used
@@ -447,20 +496,52 @@ class LLLazyJITBuilder
447496
public LLLazyJITBuilderSetters<LLLazyJIT, LLLazyJITBuilder,
448497
LLLazyJITBuilderState> {};
449498

450-
/// Configure the LLJIT instance to use orc runtime support.
451-
Error setUpOrcPlatform(LLJIT& J);
499+
/// Configure the LLJIT instance to use orc runtime support. This overload
500+
/// assumes that the client has manually configured a Platform object.
501+
Error setUpOrcPlatformManually(LLJIT &J);
502+
503+
/// Configure the LLJIT instance to use the ORC runtime and the detected
504+
/// native target for the executor.
505+
class SetUpExecutorNativePlatform {
506+
public:
507+
/// Set up using path to Orc runtime. CreatePlatformJD will be run before
508+
/// attempting to construct the platform instance. It should be used (if
509+
/// needed) to provide the offers an opportunity
510+
/// to load process symbols.
511+
SetUpExecutorNativePlatform(std::string OrcRuntimePath)
512+
: OrcRuntime(std::move(OrcRuntimePath)) {}
513+
514+
/// Set up using the given memory buffer.
515+
SetUpExecutorNativePlatform(std::unique_ptr<MemoryBuffer> OrcRuntimeMB)
516+
: OrcRuntime(std::move(OrcRuntimeMB)) {}
517+
518+
// TODO: add compiler-rt.
519+
520+
/// Add a path to the VC runtime.
521+
SetUpExecutorNativePlatform &addVCRuntime(std::string VCRuntimePath,
522+
bool StaticVCRuntime) {
523+
VCRuntime = {std::move(VCRuntimePath), StaticVCRuntime};
524+
return *this;
525+
}
526+
527+
Expected<JITDylibSP> operator()(LLJIT &J);
528+
529+
private:
530+
std::variant<std::string, std::unique_ptr<MemoryBuffer>> OrcRuntime;
531+
std::optional<std::pair<std::string, bool>> VCRuntime;
532+
};
452533

453534
/// Configure the LLJIT instance to scrape modules for llvm.global_ctors and
454535
/// llvm.global_dtors variables and (if present) build initialization and
455536
/// deinitialization functions. Platform specific initialization configurations
456537
/// should be preferred where available.
457-
void setUpGenericLLVMIRPlatform(LLJIT &J);
538+
Expected<JITDylibSP> setUpGenericLLVMIRPlatform(LLJIT &J);
458539

459540
/// Configure the LLJIT instance to disable platform support explicitly. This is
460541
/// useful in two cases: for platforms that don't have such requirements and for
461542
/// platforms, that we have no explicit support yet and that don't work well
462543
/// with the generic IR platform.
463-
Error setUpInactivePlatform(LLJIT &J);
544+
Expected<JITDylibSP> setUpInactivePlatform(LLJIT &J);
464545

465546
} // End namespace orc
466547
} // End namespace llvm

llvm/lib/ExecutionEngine/Orc/COFFPlatform.cpp

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,11 @@ class COFFHeaderMaterializationUnit : public MaterializationUnit {
159159
namespace llvm {
160160
namespace orc {
161161

162-
Expected<std::unique_ptr<COFFPlatform>>
163-
COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
164-
JITDylib &PlatformJD, const char *OrcRuntimePath,
165-
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
166-
const char *VCRuntimePath,
167-
std::optional<SymbolAliasMap> RuntimeAliases) {
162+
Expected<std::unique_ptr<COFFPlatform>> COFFPlatform::Create(
163+
ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
164+
JITDylib &PlatformJD, std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
165+
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
166+
const char *VCRuntimePath, std::optional<SymbolAliasMap> RuntimeAliases) {
168167

169168
// If the target is not supported then bail out immediately.
170169
if (!supportedTarget(ES.getTargetTriple()))
@@ -174,6 +173,22 @@ COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
174173

175174
auto &EPC = ES.getExecutorProcessControl();
176175

176+
auto GeneratorArchive =
177+
object::Archive::create(OrcRuntimeArchiveBuffer->getMemBufferRef());
178+
if (!GeneratorArchive)
179+
return GeneratorArchive.takeError();
180+
181+
auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Create(
182+
ObjLinkingLayer, nullptr, std::move(*GeneratorArchive));
183+
if (!OrcRuntimeArchiveGenerator)
184+
return OrcRuntimeArchiveGenerator.takeError();
185+
186+
// We need a second instance of the archive (for now) for the Platform. We
187+
// can `cantFail` this call, since if it were going to fail it would have
188+
// failed above.
189+
auto RuntimeArchive = cantFail(
190+
object::Archive::create(OrcRuntimeArchiveBuffer->getMemBufferRef()));
191+
177192
// Create default aliases if the caller didn't supply any.
178193
if (!RuntimeAliases)
179194
RuntimeAliases = standardPlatformAliases(ES);
@@ -199,13 +214,30 @@ COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
199214
// Create the instance.
200215
Error Err = Error::success();
201216
auto P = std::unique_ptr<COFFPlatform>(new COFFPlatform(
202-
ES, ObjLinkingLayer, PlatformJD, OrcRuntimePath,
217+
ES, ObjLinkingLayer, PlatformJD, std::move(*OrcRuntimeArchiveGenerator),
218+
std::move(OrcRuntimeArchiveBuffer), std::move(RuntimeArchive),
203219
std::move(LoadDynLibrary), StaticVCRuntime, VCRuntimePath, Err));
204220
if (Err)
205221
return std::move(Err);
206222
return std::move(P);
207223
}
208224

225+
Expected<std::unique_ptr<COFFPlatform>>
226+
COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
227+
JITDylib &PlatformJD, const char *OrcRuntimePath,
228+
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
229+
const char *VCRuntimePath,
230+
std::optional<SymbolAliasMap> RuntimeAliases) {
231+
232+
auto ArchiveBuffer = MemoryBuffer::getFile(OrcRuntimePath);
233+
if (!ArchiveBuffer)
234+
return createFileError(OrcRuntimePath, ArchiveBuffer.getError());
235+
236+
return Create(ES, ObjLinkingLayer, PlatformJD, std::move(*ArchiveBuffer),
237+
std::move(LoadDynLibrary), StaticVCRuntime, VCRuntimePath,
238+
std::move(RuntimeAliases));
239+
}
240+
209241
Expected<MemoryBufferRef> COFFPlatform::getPerJDObjectFile() {
210242
auto PerJDObj = OrcRuntimeArchive->findSym("__orc_rt_coff_per_jd_marker");
211243
if (!PerJDObj)
@@ -349,37 +381,22 @@ bool COFFPlatform::supportedTarget(const Triple &TT) {
349381
}
350382
}
351383

352-
COFFPlatform::COFFPlatform(ExecutionSession &ES,
353-
ObjectLinkingLayer &ObjLinkingLayer,
354-
JITDylib &PlatformJD, const char *OrcRuntimePath,
355-
LoadDynamicLibrary LoadDynamicLibrary,
356-
bool StaticVCRuntime, const char *VCRuntimePath,
357-
Error &Err)
384+
COFFPlatform::COFFPlatform(
385+
ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
386+
JITDylib &PlatformJD,
387+
std::unique_ptr<StaticLibraryDefinitionGenerator> OrcRuntimeGenerator,
388+
std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
389+
std::unique_ptr<object::Archive> OrcRuntimeArchive,
390+
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
391+
const char *VCRuntimePath, Error &Err)
358392
: ES(ES), ObjLinkingLayer(ObjLinkingLayer),
359-
LoadDynLibrary(std::move(LoadDynamicLibrary)),
393+
LoadDynLibrary(std::move(LoadDynLibrary)),
394+
OrcRuntimeArchiveBuffer(std::move(OrcRuntimeArchiveBuffer)),
395+
OrcRuntimeArchive(std::move(OrcRuntimeArchive)),
360396
StaticVCRuntime(StaticVCRuntime),
361397
COFFHeaderStartSymbol(ES.intern("__ImageBase")) {
362398
ErrorAsOutParameter _(&Err);
363399

364-
// Create a generator for the ORC runtime archive.
365-
auto OrcRuntimeArchiveGenerator =
366-
StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);
367-
if (!OrcRuntimeArchiveGenerator) {
368-
Err = OrcRuntimeArchiveGenerator.takeError();
369-
return;
370-
}
371-
372-
auto ArchiveBuffer = MemoryBuffer::getFile(OrcRuntimePath);
373-
if (!ArchiveBuffer) {
374-
Err = createFileError(OrcRuntimePath, ArchiveBuffer.getError());
375-
return;
376-
}
377-
OrcRuntimeArchiveBuffer = std::move(*ArchiveBuffer);
378-
OrcRuntimeArchive =
379-
std::make_unique<object::Archive>(*OrcRuntimeArchiveBuffer, Err);
380-
if (Err)
381-
return;
382-
383400
Bootstrapping.store(true);
384401
ObjLinkingLayer.addPlugin(std::make_unique<COFFPlatformPlugin>(*this));
385402

@@ -392,7 +409,7 @@ COFFPlatform::COFFPlatform(ExecutionSession &ES,
392409
}
393410
VCRuntimeBootstrap = std::move(*VCRT);
394411

395-
for (auto &Lib : (*OrcRuntimeArchiveGenerator)->getImportedDynamicLibraries())
412+
for (auto &Lib : OrcRuntimeGenerator->getImportedDynamicLibraries())
396413
DylibsToPreload.insert(Lib);
397414

398415
auto ImportedLibs =
@@ -406,7 +423,7 @@ COFFPlatform::COFFPlatform(ExecutionSession &ES,
406423
for (auto &Lib : *ImportedLibs)
407424
DylibsToPreload.insert(Lib);
408425

409-
PlatformJD.addGenerator(std::move(*OrcRuntimeArchiveGenerator));
426+
PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
410427

411428
// PlatformJD hasn't been set up by the platform yet (since we're creating
412429
// the platform now), so set it up.
@@ -416,10 +433,10 @@ COFFPlatform::COFFPlatform(ExecutionSession &ES,
416433
}
417434

418435
for (auto& Lib : DylibsToPreload)
419-
if (auto E2 = LoadDynLibrary(PlatformJD, Lib)) {
420-
Err = std::move(E2);
421-
return;
422-
}
436+
if (auto E2 = this->LoadDynLibrary(PlatformJD, Lib)) {
437+
Err = std::move(E2);
438+
return;
439+
}
423440

424441
if (StaticVCRuntime)
425442
if (auto E2 = VCRuntimeBootstrap->initializeStaticVCRuntime(PlatformJD)) {

llvm/lib/ExecutionEngine/Orc/Core.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,13 @@ void JITDylib::setLinkOrder(JITDylibSearchOrder NewLinkOrder,
13291329
});
13301330
}
13311331

1332+
void JITDylib::addToLinkOrder(const JITDylibSearchOrder &NewLinks) {
1333+
ES.runSessionLocked([&]() {
1334+
LinkOrder.reserve(LinkOrder.size() + NewLinks.size());
1335+
llvm::append_range(LinkOrder, NewLinks);
1336+
});
1337+
}
1338+
13321339
void JITDylib::addToLinkOrder(JITDylib &JD, JITDylibLookupFlags JDLookupFlags) {
13331340
ES.runSessionLocked([&]() { LinkOrder.push_back({&JD, JDLookupFlags}); });
13341341
}

0 commit comments

Comments
 (0)