1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-23 04:52:54 +02:00
llvm-mirror/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h
Lang Hames 92f9dd24ac [Orc] Add a JITSymbol class to the Orc APIs, refactor APIs, update clients.
This patch refactors a key piece of the Orc APIs: It removes the
*::getSymbolAddress and *::lookupSymbolAddressIn methods, which returned target
addresses (uint64_ts), and replaces them with *::findSymbol and *::findSymbolIn
respectively, which return instances of the new JITSymbol type. Unlike the old
methods, calling findSymbol or findSymbolIn does not cause the symbol to be
immediately materialized when found. Instead, the symbol will be materialized
if/when the getAddress method is called on the returned JITSymbol. This allows
us to query for the existence of symbols without actually materializing them. In
the future I expect more information to be attached to the JITSymbol class, for
example whether the returned symbol is a weak or strong definition. This will
allow us to properly handle weak symbols and multiple definitions.

llvm-svn: 228557
2015-02-09 01:20:51 +00:00

272 lines
10 KiB
C++

//===- CompileOnDemandLayer.h - Compile each function on demand -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// JIT layer for breaking up modules and inserting callbacks to allow
// individual functions to be compiled on demand.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
#define LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
#include "IndirectionUtils.h"
#include "LookasideRTDyldMM.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include <list>
namespace llvm {
/// @brief Compile-on-demand layer.
///
/// Modules added to this layer have their calls indirected, and are then
/// broken up into a set of single-function modules, each of which is added
/// to the layer below in a singleton set. The lower layer can be any layer that
/// accepts IR module sets.
///
/// It is expected that this layer will frequently be used on top of a
/// LazyEmittingLayer. The combination of the two ensures that each function is
/// compiled only when it is first called.
template <typename BaseLayerT> class CompileOnDemandLayer {
public:
/// @brief Lookup helper that provides compatibility with the classic
/// static-compilation symbol resolution process.
///
/// The CompileOnDemand (COD) layer splits modules up into multiple
/// sub-modules, each held in its own llvm::Module instance, in order to
/// support lazy compilation. When a module that contains private symbols is
/// broken up symbol linkage changes may be required to enable access to
/// "private" data that now resides in a different llvm::Module instance. To
/// retain expected symbol resolution behavior for clients of the COD layer,
/// the CODScopedLookup class uses a two-tiered lookup system to resolve
/// symbols. Lookup first scans sibling modules that were split from the same
/// original module (logical-module scoped lookup), then scans all other
/// modules that have been added to the lookup scope (logical-dylib scoped
/// lookup).
class CODScopedLookup {
private:
typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
typedef std::vector<BaseLayerModuleSetHandleT> SiblingHandlesList;
typedef std::list<SiblingHandlesList> PseudoDylibModuleSetHandlesList;
public:
/// @brief Handle for a logical module.
typedef typename PseudoDylibModuleSetHandlesList::iterator LMHandle;
/// @brief Construct a scoped lookup.
CODScopedLookup(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {}
/// @brief Start a new context for a single logical module.
LMHandle createLogicalModule() {
Handles.push_back(SiblingHandlesList());
return std::prev(Handles.end());
}
/// @brief Add a concrete Module's handle to the given logical Module's
/// lookup scope.
void addToLogicalModule(LMHandle LMH, BaseLayerModuleSetHandleT H) {
LMH->push_back(H);
}
/// @brief Remove a logical Module from the CODScopedLookup entirely.
void removeLogicalModule(LMHandle LMH) { Handles.erase(LMH); }
/// @brief Look up a symbol in this context.
JITSymbol findSymbol(LMHandle LMH, const std::string &Name) {
if (auto Symbol = findSymbolIn(LMH, Name))
return Symbol;
for (auto I = Handles.begin(), E = Handles.end(); I != E; ++I)
if (I != LMH)
if (auto Symbol = findSymbolIn(I, Name))
return Symbol;
return nullptr;
}
private:
JITSymbol findSymbolIn(LMHandle LMH, const std::string &Name) {
for (auto H : *LMH)
if (auto Symbol = BaseLayer.findSymbolIn(H, Name, false))
return Symbol;
return nullptr;
}
BaseLayerT &BaseLayer;
PseudoDylibModuleSetHandlesList Handles;
};
private:
typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
typedef std::vector<BaseLayerModuleSetHandleT> BaseLayerModuleSetHandleListT;
struct ModuleSetInfo {
// Symbol lookup - just one for the whole module set.
std::shared_ptr<CODScopedLookup> Lookup;
// Logical module handles.
std::vector<typename CODScopedLookup::LMHandle> LMHandles;
// Persistent manglers - one per TU.
std::vector<PersistentMangler> PersistentManglers;
// Symbol resolution callback handlers - one per TU.
std::vector<std::unique_ptr<JITResolveCallbackHandler>>
JITResolveCallbackHandlers;
// List of vectors of module set handles:
// One vector per logical module - each vector holds the handles for the
// exploded modules for that logical module in the base layer.
BaseLayerModuleSetHandleListT BaseLayerModuleSetHandles;
ModuleSetInfo(std::shared_ptr<CODScopedLookup> Lookup)
: Lookup(std::move(Lookup)) {}
void releaseResources(BaseLayerT &BaseLayer) {
for (auto LMH : LMHandles)
Lookup->removeLogicalModule(LMH);
for (auto H : BaseLayerModuleSetHandles)
BaseLayer.removeModuleSet(H);
}
};
typedef std::list<ModuleSetInfo> ModuleSetInfoListT;
public:
/// @brief Handle to a set of loaded modules.
typedef typename ModuleSetInfoListT::iterator ModuleSetHandleT;
/// @brief Convenience typedef for callback inserter.
typedef std::function<void(Module&, JITResolveCallbackHandler&)>
InsertCallbackAsmFtor;
/// @brief Construct a compile-on-demand layer instance.
CompileOnDemandLayer(BaseLayerT &BaseLayer,
InsertCallbackAsmFtor InsertCallbackAsm)
: BaseLayer(BaseLayer), InsertCallbackAsm(InsertCallbackAsm) {}
/// @brief Add a module to the compile-on-demand layer.
template <typename ModuleSetT>
ModuleSetHandleT addModuleSet(ModuleSetT Ms,
std::unique_ptr<RTDyldMemoryManager> MM) {
const char *JITAddrSuffix = "$orc_addr";
const char *JITImplSuffix = "$orc_impl";
// Create a symbol lookup context and ModuleSetInfo for this module set.
auto DylibLookup = std::make_shared<CODScopedLookup>(BaseLayer);
ModuleSetHandleT H =
ModuleSetInfos.insert(ModuleSetInfos.end(), ModuleSetInfo(DylibLookup));
ModuleSetInfo &MSI = ModuleSetInfos.back();
// Process each of the modules in this module set. All modules share the
// same lookup context, but each will get its own TU lookup context.
for (auto &M : Ms) {
// Create a TU lookup context for this module.
auto LMH = DylibLookup->createLogicalModule();
MSI.LMHandles.push_back(LMH);
// Create a persistent mangler for this module.
MSI.PersistentManglers.emplace_back(*M->getDataLayout());
// Make all calls to functions defined in this module indirect.
JITIndirections Indirections =
makeCallsDoubleIndirect(*M, [](const Function &) { return true; },
JITImplSuffix, JITAddrSuffix);
// Then carve up the module into a bunch of single-function modules.
std::vector<std::unique_ptr<Module>> ExplodedModules =
explode(*M, Indirections);
// Add a resolve-callback handler for this module to look up symbol
// addresses when requested via a callback.
MSI.JITResolveCallbackHandlers.push_back(
createCallbackHandlerFromJITIndirections(
Indirections, MSI.PersistentManglers.back(),
[=](StringRef S) {
return DylibLookup->findSymbol(LMH, S).getAddress();
}));
// Insert callback asm code into the first module.
InsertCallbackAsm(*ExplodedModules[0],
*MSI.JITResolveCallbackHandlers.back());
// Now we need to take each of the extracted Modules and add them to
// base layer. Each Module will be added individually to make sure they
// can be compiled separately, and each will get its own lookaside
// memory manager with lookup functors that resolve symbols in sibling
// modules first.OA
for (auto &M : ExplodedModules) {
std::vector<std::unique_ptr<Module>> MSet;
MSet.push_back(std::move(M));
BaseLayerModuleSetHandleT H = BaseLayer.addModuleSet(
std::move(MSet),
createLookasideRTDyldMM<SectionMemoryManager>(
[=](const std::string &Name) {
if (auto Symbol = DylibLookup->findSymbol(LMH, Name))
return Symbol.getAddress();
return findSymbol(Name, true).getAddress();
},
[=](const std::string &Name) {
return DylibLookup->findSymbol(LMH, Name).getAddress();
}));
DylibLookup->addToLogicalModule(LMH, H);
MSI.BaseLayerModuleSetHandles.push_back(H);
}
initializeFuncAddrs(*MSI.JITResolveCallbackHandlers.back(), Indirections,
MSI.PersistentManglers.back(), [=](StringRef S) {
return DylibLookup->findSymbol(LMH, S).getAddress();
});
}
return H;
}
/// @brief Remove the module represented by the given handle.
///
/// This will remove all modules in the layers below that were derived from
/// the module represented by H.
void removeModuleSet(ModuleSetHandleT H) {
H->releaseResources(BaseLayer);
ModuleSetInfos.erase(H);
}
/// @brief Search for the given named symbol.
/// @param Name The name of the symbol to search for.
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
/// @return A handle for the given named symbol, if it exists.
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
}
/// @brief Get the address of a symbol provided by this layer, or some layer
/// below this one.
JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
bool ExportedSymbolsOnly) {
BaseLayerModuleSetHandleListT &BaseLayerHandles = H->second;
for (auto &BH : BaseLayerHandles) {
if (auto Symbol = BaseLayer.findSymbolIn(BH, Name, ExportedSymbolsOnly))
return Symbol;
}
return nullptr;
}
private:
BaseLayerT &BaseLayer;
InsertCallbackAsmFtor InsertCallbackAsm;
ModuleSetInfoListT ModuleSetInfos;
};
}
#endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H