[Orc][MCJIT][RuntimeDyld] Add symbol flags to symbols in RuntimeDyld. Thread the

new types through MCJIT and Orc.

In particular, add a 'weak' flag. When plumbed through RTDyldMemoryManager, this
will allow us to distinguish between weak and strong definitions and find the
right ones during symbol resolution.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@231724 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Lang Hames
2015-03-09 23:44:13 +00:00
parent 376b961126
commit 6d6178426f
11 changed files with 166 additions and 155 deletions

View File

@@ -14,6 +14,7 @@
#ifndef LLVM_EXECUTIONENGINE_ORC_JITSYMBOL_H
#define LLVM_EXECUTIONENGINE_ORC_JITSYMBOL_H
#include "llvm/ExecutionEngine/JITSymbolFlags.h"
#include "llvm/Support/DataTypes.h"
#include <cassert>
#include <functional>
@@ -25,17 +26,19 @@ namespace orc {
typedef uint64_t TargetAddress;
/// @brief Represents a symbol in the JIT.
class JITSymbol {
public:
class JITSymbol : public JITSymbolBase {
public:
typedef std::function<TargetAddress()> GetAddressFtor;
/// @brief Create a 'null' symbol that represents failure to find a symbol
/// definition.
JITSymbol(std::nullptr_t) : CachedAddr(0) {}
JITSymbol(std::nullptr_t)
: JITSymbolBase(JITSymbolFlags::None), CachedAddr(0) {}
/// @brief Create a symbol for a definition with a known address.
JITSymbol(TargetAddress Addr)
: CachedAddr(Addr) {}
JITSymbol(TargetAddress Addr, JITSymbolFlags Flags)
: JITSymbolBase(Flags), CachedAddr(Addr) {}
/// @brief Create a symbol for a definition that doesn't have a known address
/// yet.
@@ -46,8 +49,8 @@ public:
/// definition without actually materializing the definition up front. The
/// user can materialize the definition at any time by calling the getAddress
/// method.
JITSymbol(GetAddressFtor GetAddress)
: CachedAddr(0), GetAddress(std::move(GetAddress)) {}
JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags)
: JITSymbolBase(Flags), GetAddress(std::move(GetAddress)), CachedAddr(0) {}
/// @brief Returns true if the symbol exists, false otherwise.
explicit operator bool() const { return CachedAddr || GetAddress; }
@@ -64,8 +67,8 @@ public:
}
private:
TargetAddress CachedAddr;
GetAddressFtor GetAddress;
TargetAddress CachedAddr;
};
} // End namespace orc.

View File

@@ -45,23 +45,25 @@ private:
JITSymbol find(StringRef Name, bool ExportedSymbolsOnly, BaseLayerT &B) {
switch (EmitState) {
case NotEmitted:
if (provides(Name, ExportedSymbolsOnly)) {
if (auto GV = searchGVs(Name, ExportedSymbolsOnly)) {
// Create a std::string version of Name to capture here - the argument
// (a StringRef) may go away before the lambda is executed.
// FIXME: Use capture-init when we move to C++14.
std::string PName = Name;
return JITSymbol(
[this, ExportedSymbolsOnly, PName, &B]() -> TargetAddress {
if (this->EmitState == Emitting)
return 0;
else if (this->EmitState == NotEmitted) {
this->EmitState = Emitting;
Handle = this->emitToBaseLayer(B);
this->EmitState = Emitted;
}
return B.findSymbolIn(Handle, PName, ExportedSymbolsOnly)
.getAddress();
});
auto PName = Name;
JITSymbolFlags Flags = JITSymbolBase::flagsFromGlobalValue(*GV);
auto GetAddress =
[this, ExportedSymbolsOnly, PName, &B]() -> TargetAddress {
if (this->EmitState == Emitting)
return 0;
else if (this->EmitState == NotEmitted) {
this->EmitState = Emitting;
Handle = this->emitToBaseLayer(B);
this->EmitState = Emitted;
}
auto Sym = B.findSymbolIn(Handle, PName, ExportedSymbolsOnly);
return Sym.getAddress();
};
return JITSymbol(std::move(GetAddress), Flags);
} else
return nullptr;
case Emitting:
@@ -98,7 +100,8 @@ private:
std::unique_ptr<RTDyldMemoryManager> MM);
protected:
virtual bool provides(StringRef Name, bool ExportedSymbolsOnly) const = 0;
virtual const GlobalValue* searchGVs(StringRef Name,
bool ExportedSymbolsOnly) const = 0;
virtual BaseLayerHandleT emitToBaseLayer(BaseLayerT &BaseLayer) = 0;
private:
@@ -115,46 +118,48 @@ private:
protected:
BaseLayerHandleT emitToBaseLayer(BaseLayerT &BaseLayer) override {
// We don't need the mangled names set any more: Once we've emitted this
// to the base layer we'll just look for symbols there.
MangledNames.reset();
return BaseLayer.addModuleSet(std::move(Ms), std::move(MM));
}
bool provides(StringRef Name, bool ExportedSymbolsOnly) const override {
const GlobalValue* searchGVs(StringRef Name,
bool ExportedSymbolsOnly) const override {
// FIXME: We could clean all this up if we had a way to reliably demangle
// names: We could just demangle name and search, rather than
// mangling everything else.
// If we have already built the mangled name set then just search it.
if (MangledNames) {
auto VI = MangledNames->find(Name);
if (VI == MangledNames->end())
return false;
return !ExportedSymbolsOnly || VI->second;
if (MangledSymbols) {
auto VI = MangledSymbols->find(Name);
if (VI == MangledSymbols->end())
return nullptr;
auto GV = VI->second;
if (!ExportedSymbolsOnly || GV->hasDefaultVisibility())
return GV;
return nullptr;
}
// If we haven't built the mangled name set yet, try to build it. As an
// optimization this will leave MangledNames set to nullptr if we find
// Name in the process of building the set.
buildMangledNames(Name, ExportedSymbolsOnly);
if (!MangledNames)
return true;
return false;
return buildMangledSymbols(Name, ExportedSymbolsOnly);
}
BaseLayerHandleT emitToBaseLayer(BaseLayerT &BaseLayer) override {
// We don't need the mangled names set any more: Once we've emitted this
// to the base layer we'll just look for symbols there.
MangledSymbols.reset();
return BaseLayer.addModuleSet(std::move(Ms), std::move(MM));
}
private:
// If the mangled name of the given GlobalValue matches the given search
// name (and its visibility conforms to the ExportedSymbolsOnly flag) then
// just return 'true'. Otherwise, add the mangled name to the Names map and
// return 'false'.
bool addGlobalValue(StringMap<bool> &Names, const GlobalValue &GV,
const Mangler &Mang, StringRef SearchName,
bool ExportedSymbolsOnly) const {
// return the symbol. Otherwise, add the mangled name to the Names map and
// return nullptr.
const GlobalValue* addGlobalValue(StringMap<const GlobalValue*> &Names,
const GlobalValue &GV,
const Mangler &Mang, StringRef SearchName,
bool ExportedSymbolsOnly) const {
// Modules don't "provide" decls or common symbols.
if (GV.isDeclaration() || GV.hasCommonLinkage())
return false;
return nullptr;
// Mangle the GV name.
std::string MangledName;
@@ -167,39 +172,42 @@ private:
// bail out early.
if (MangledName == SearchName)
if (!ExportedSymbolsOnly || GV.hasDefaultVisibility())
return true;
return &GV;
// Otherwise add this to the map for later.
Names[MangledName] = GV.hasDefaultVisibility();
return false;
Names[MangledName] = &GV;
return nullptr;
}
// Build the MangledNames map. Bails out early (with MangledNames left set
// Build the MangledSymbols map. Bails out early (with MangledSymbols left set
// to nullptr) if the given SearchName is found while building the map.
void buildMangledNames(StringRef SearchName,
bool ExportedSymbolsOnly) const {
assert(!MangledNames && "Mangled names map already exists?");
const GlobalValue* buildMangledSymbols(StringRef SearchName,
bool ExportedSymbolsOnly) const {
assert(!MangledSymbols && "Mangled symbols map already exists?");
auto Names = llvm::make_unique<StringMap<bool>>();
auto Symbols = llvm::make_unique<StringMap<const GlobalValue*>>();
for (const auto &M : Ms) {
Mangler Mang(&M->getDataLayout());
for (const auto &GV : M->globals())
if (addGlobalValue(*Names, GV, Mang, SearchName, ExportedSymbolsOnly))
return;
for (const auto &V : M->globals())
if (auto GV = addGlobalValue(*Symbols, V, Mang, SearchName,
ExportedSymbolsOnly))
return GV;
for (const auto &F : *M)
if (addGlobalValue(*Names, F, Mang, SearchName, ExportedSymbolsOnly))
return;
if (auto GV = addGlobalValue(*Symbols, F, Mang, SearchName,
ExportedSymbolsOnly))
return GV;
}
MangledNames = std::move(Names);
MangledSymbols = std::move(Symbols);
return nullptr;
}
ModuleSetT Ms;
std::unique_ptr<RTDyldMemoryManager> MM;
mutable std::unique_ptr<StringMap<bool>> MangledNames;
mutable std::unique_ptr<StringMap<const GlobalValue*>> MangledSymbols;
};
typedef std::list<std::unique_ptr<EmissionDeferredSet>> ModuleSetListT;

View File

@@ -51,10 +51,8 @@ protected:
return RTDyld->loadObject(Obj);
}
TargetAddress getSymbolAddress(StringRef Name, bool ExportedSymbolsOnly) {
if (ExportedSymbolsOnly)
return RTDyld->getExportedSymbolLoadAddress(Name);
return RTDyld->getSymbolLoadAddress(Name);
RuntimeDyld::SymbolInfo getSymbol(StringRef Name) const {
return RTDyld->getSymbol(Name);
}
bool NeedsFinalization() const { return (State == Raw); }
@@ -214,28 +212,32 @@ public:
/// given object set.
JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name,
bool ExportedSymbolsOnly) {
if (auto Addr = H->getSymbolAddress(Name, ExportedSymbolsOnly)) {
if (!H->NeedsFinalization()) {
// If this instance has already been finalized then we can just return
// the address.
return JITSymbol(Addr);
} else {
// If this instance needs finalization return a functor that will do it.
// The functor still needs to double-check whether finalization is
// required, in case someone else finalizes this set before the functor
// is called.
return JITSymbol(
[this, Addr, H]() {
if (H->NeedsFinalization()) {
H->Finalize();
if (NotifyFinalized)
NotifyFinalized(H);
}
return Addr;
});
if (auto Sym = H->getSymbol(Name)) {
if (Sym.isExported() || !ExportedSymbolsOnly) {
auto Addr = Sym.getAddress();
auto Flags = Sym.getFlags();
if (!H->NeedsFinalization()) {
// If this instance has already been finalized then we can just return
// the address.
return JITSymbol(Addr, Flags);
} else {
// If this instance needs finalization return a functor that will do
// it. The functor still needs to double-check whether finalization is
// required, in case someone else finalizes this set before the
// functor is called.
auto GetAddress =
[this, Addr, H]() {
if (H->NeedsFinalization()) {
H->Finalize();
if (NotifyFinalized)
NotifyFinalized(H);
}
return Addr;
};
return JITSymbol(std::move(GetAddress), Flags);
}
}
}
return nullptr;
}