mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 11:02:59 +02:00
[ORC] Plumb error notifications through the VSO interface.
This allows materializers to notify the VSO that they were unable to resolve or finalize symbols. llvm-svn: 329934
This commit is contained in:
parent
42742ad477
commit
7a54926cb9
@ -52,11 +52,12 @@ public:
|
|||||||
Common = 1U << 2,
|
Common = 1U << 2,
|
||||||
Absolute = 1U << 3,
|
Absolute = 1U << 3,
|
||||||
Exported = 1U << 4,
|
Exported = 1U << 4,
|
||||||
NotMaterialized = 1U << 5
|
Lazy = 1U << 5,
|
||||||
|
Materializing = 1U << 6
|
||||||
};
|
};
|
||||||
|
|
||||||
static JITSymbolFlags stripTransientFlags(JITSymbolFlags Orig) {
|
static JITSymbolFlags stripTransientFlags(JITSymbolFlags Orig) {
|
||||||
return static_cast<FlagNames>(Orig.Flags & ~NotMaterialized);
|
return static_cast<FlagNames>(Orig.Flags & ~Lazy & ~Materializing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Default-construct a JITSymbolFlags instance.
|
/// @brief Default-construct a JITSymbolFlags instance.
|
||||||
@ -75,9 +76,18 @@ public:
|
|||||||
return (Flags & HasError) == HasError;
|
return (Flags & HasError) == HasError;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Returns true if this symbol has been fully materialized (i.e. is
|
/// @brief Returns true if this is a lazy symbol.
|
||||||
/// callable).
|
/// This flag is used internally by the JIT APIs to track
|
||||||
bool isMaterialized() const { return !(Flags & NotMaterialized); }
|
/// materialization states.
|
||||||
|
bool isLazy() const { return Flags & Lazy; }
|
||||||
|
|
||||||
|
/// @brief Returns true if this symbol is in the process of being
|
||||||
|
/// materialized.
|
||||||
|
bool isMaterializing() const { return Flags & Materializing; }
|
||||||
|
|
||||||
|
/// @brief Returns true if this symbol is fully materialized.
|
||||||
|
/// (i.e. neither lazy, nor materializing).
|
||||||
|
bool isMaterialized() const { return !(Flags & (Lazy | Materializing)); }
|
||||||
|
|
||||||
/// @brief Returns true if the Weak flag is set.
|
/// @brief Returns true if the Weak flag is set.
|
||||||
bool isWeak() const {
|
bool isWeak() const {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||||
#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
|
#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -25,23 +26,71 @@
|
|||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace orc {
|
namespace orc {
|
||||||
|
|
||||||
|
// Forward declare some classes.
|
||||||
|
class VSO;
|
||||||
|
|
||||||
/// VModuleKey provides a unique identifier (allocated and managed by
|
/// VModuleKey provides a unique identifier (allocated and managed by
|
||||||
/// ExecutionSessions) for a module added to the JIT.
|
/// ExecutionSessions) for a module added to the JIT.
|
||||||
using VModuleKey = uint64_t;
|
using VModuleKey = uint64_t;
|
||||||
|
|
||||||
class VSO;
|
|
||||||
|
|
||||||
/// @brief A set of symbol names (represented by SymbolStringPtrs for
|
/// @brief A set of symbol names (represented by SymbolStringPtrs for
|
||||||
// efficiency).
|
// efficiency).
|
||||||
using SymbolNameSet = std::set<SymbolStringPtr>;
|
using SymbolNameSet = std::set<SymbolStringPtr>;
|
||||||
|
|
||||||
|
/// @brief Render a SymbolNameSet to an ostream.
|
||||||
|
raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
|
||||||
|
|
||||||
/// @brief A map from symbol names (as SymbolStringPtrs) to JITSymbols
|
/// @brief A map from symbol names (as SymbolStringPtrs) to JITSymbols
|
||||||
/// (address/flags pairs).
|
/// (address/flags pairs).
|
||||||
using SymbolMap = std::map<SymbolStringPtr, JITEvaluatedSymbol>;
|
using SymbolMap = std::map<SymbolStringPtr, JITEvaluatedSymbol>;
|
||||||
|
|
||||||
|
/// @brief Render a SymbolMap to an ostream.
|
||||||
|
raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
|
||||||
|
|
||||||
/// @brief A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
|
/// @brief A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
|
||||||
using SymbolFlagsMap = std::map<SymbolStringPtr, JITSymbolFlags>;
|
using SymbolFlagsMap = std::map<SymbolStringPtr, JITSymbolFlags>;
|
||||||
|
|
||||||
|
/// @brief Render a SymbolMap to an ostream.
|
||||||
|
raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &Symbols);
|
||||||
|
|
||||||
|
/// @brief A base class for materialization failures that allows the failing
|
||||||
|
/// symbols to be obtained for logging.
|
||||||
|
class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
virtual const SymbolNameSet &getSymbols() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Used to notify a VSO that the given set of symbols failed to resolve.
|
||||||
|
class FailedToResolve : public ErrorInfo<FailedToResolve, FailedToMaterialize> {
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
|
||||||
|
FailedToResolve(SymbolNameSet Symbols);
|
||||||
|
std::error_code convertToErrorCode() const override;
|
||||||
|
void log(raw_ostream &OS) const override;
|
||||||
|
const SymbolNameSet &getSymbols() const override { return Symbols; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SymbolNameSet Symbols;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Used to notify a VSO that the given set of symbols failed to
|
||||||
|
/// finalize.
|
||||||
|
class FailedToFinalize
|
||||||
|
: public ErrorInfo<FailedToFinalize, FailedToMaterialize> {
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
|
||||||
|
FailedToFinalize(SymbolNameSet Symbols);
|
||||||
|
std::error_code convertToErrorCode() const override;
|
||||||
|
void log(raw_ostream &OS) const override;
|
||||||
|
const SymbolNameSet &getSymbols() const override { return Symbols; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SymbolNameSet Symbols;
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief A symbol query that returns results via a callback when results are
|
/// @brief A symbol query that returns results via a callback when results are
|
||||||
/// ready.
|
/// ready.
|
||||||
///
|
///
|
||||||
@ -69,20 +118,20 @@ public:
|
|||||||
/// notify-finalized callback is called with the given error.
|
/// notify-finalized callback is called with the given error.
|
||||||
///
|
///
|
||||||
/// It is illegal to call setFailed after both callbacks have been made.
|
/// It is illegal to call setFailed after both callbacks have been made.
|
||||||
void setFailed(Error Err);
|
void notifyFailed(Error Err);
|
||||||
|
|
||||||
/// @brief Set the resolved symbol information for the given symbol name.
|
/// @brief Set the resolved symbol information for the given symbol name.
|
||||||
///
|
///
|
||||||
/// If this symbol was the last one not resolved, this will trigger a call to
|
/// If this symbol was the last one not resolved, this will trigger a call to
|
||||||
/// the notify-finalized callback passing the completed sybol map.
|
/// the notify-finalized callback passing the completed sybol map.
|
||||||
void setDefinition(SymbolStringPtr Name, JITEvaluatedSymbol Sym);
|
void resolve(SymbolStringPtr Name, JITEvaluatedSymbol Sym);
|
||||||
|
|
||||||
/// @brief Notify the query that a requested symbol is ready for execution.
|
/// @brief Notify the query that a requested symbol is ready for execution.
|
||||||
///
|
///
|
||||||
/// This decrements the query's internal count of not-yet-ready symbols. If
|
/// This decrements the query's internal count of not-yet-ready symbols. If
|
||||||
/// this call to notifySymbolFinalized sets the counter to zero, it will call
|
/// this call to notifySymbolFinalized sets the counter to zero, it will call
|
||||||
/// the notify-finalized callback with Error::success as the value.
|
/// the notify-finalized callback with Error::success as the value.
|
||||||
void notifySymbolFinalized();
|
void finalizeSymbol();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SymbolMap Symbols;
|
SymbolMap Symbols;
|
||||||
@ -240,10 +289,16 @@ public:
|
|||||||
|
|
||||||
/// @brief Add the given symbol/address mappings to the dylib, but do not
|
/// @brief Add the given symbol/address mappings to the dylib, but do not
|
||||||
/// mark the symbols as finalized yet.
|
/// mark the symbols as finalized yet.
|
||||||
void resolve(SymbolMap SymbolValues);
|
void resolve(const SymbolMap &SymbolValues);
|
||||||
|
|
||||||
|
/// @brief Notify the VSO that the given symbols failed to finalize.
|
||||||
|
void notifyResolutionFailed(const SymbolNameSet &Names);
|
||||||
|
|
||||||
/// @brief Finalize the given symbols.
|
/// @brief Finalize the given symbols.
|
||||||
void finalize(SymbolNameSet SymbolsToFinalize);
|
void finalize(const SymbolNameSet &SymbolsToFinalize);
|
||||||
|
|
||||||
|
/// @brief Notify the VSO that the given symbols failed to finalize.
|
||||||
|
void notifyFinalizationFailed(const SymbolNameSet &Names);
|
||||||
|
|
||||||
/// @brief Look up the flags for the given symbols.
|
/// @brief Look up the flags for the given symbols.
|
||||||
///
|
///
|
||||||
@ -267,56 +322,72 @@ public:
|
|||||||
SymbolNameSet Symbols);
|
SymbolNameSet Symbols);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class MaterializationInfo {
|
class UnmaterializedInfo {
|
||||||
public:
|
public:
|
||||||
using QueryList = std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
|
UnmaterializedInfo(size_t SymbolsRemaining,
|
||||||
|
std::unique_ptr<MaterializationUnit> MU);
|
||||||
MaterializationInfo(size_t SymbolsRemaining,
|
|
||||||
std::unique_ptr<MaterializationUnit> MU);
|
|
||||||
|
|
||||||
uint64_t SymbolsRemaining;
|
uint64_t SymbolsRemaining;
|
||||||
std::unique_ptr<MaterializationUnit> MU;
|
std::unique_ptr<MaterializationUnit> MU;
|
||||||
SymbolMap Symbols;
|
|
||||||
std::map<SymbolStringPtr, QueryList> PendingResolution;
|
|
||||||
std::map<SymbolStringPtr, QueryList> PendingFinalization;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using MaterializationInfoSet = std::set<std::unique_ptr<MaterializationInfo>>;
|
using UnmaterializedInfoList = std::list<UnmaterializedInfo>;
|
||||||
|
|
||||||
using MaterializationInfoIterator = MaterializationInfoSet::iterator;
|
using UnmaterializedInfoIterator = UnmaterializedInfoList::iterator;
|
||||||
|
|
||||||
|
class MaterializingInfo {
|
||||||
|
public:
|
||||||
|
using QueryList = std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
|
||||||
|
|
||||||
|
QueryList PendingResolution;
|
||||||
|
QueryList PendingFinalization;
|
||||||
|
};
|
||||||
|
|
||||||
|
using MaterializingInfoMap = std::map<SymbolStringPtr, MaterializingInfo>;
|
||||||
|
|
||||||
|
using MaterializingInfoIterator = MaterializingInfoMap::iterator;
|
||||||
|
|
||||||
class SymbolTableEntry {
|
class SymbolTableEntry {
|
||||||
public:
|
public:
|
||||||
SymbolTableEntry(JITSymbolFlags SymbolFlags,
|
SymbolTableEntry(JITSymbolFlags SymbolFlags,
|
||||||
MaterializationInfoIterator MaterializationInfoItr);
|
UnmaterializedInfoIterator UnmaterializedInfoItr);
|
||||||
SymbolTableEntry(JITEvaluatedSymbol Sym);
|
SymbolTableEntry(JITEvaluatedSymbol Sym);
|
||||||
SymbolTableEntry(SymbolTableEntry &&Other);
|
// SymbolTableEntry(SymbolTableEntry &&Other);
|
||||||
|
// SymbolTableEntry &operator=(SymbolTableEntry &&Other);
|
||||||
~SymbolTableEntry();
|
~SymbolTableEntry();
|
||||||
|
|
||||||
SymbolTableEntry &operator=(JITEvaluatedSymbol Sym);
|
// Change definition due to override. Only usable prior to materialization.
|
||||||
|
void replaceWith(VSO &V, SymbolStringPtr Name, JITEvaluatedSymbol Sym);
|
||||||
|
|
||||||
JITSymbolFlags getFlags() const;
|
// Change definition due to override. Only usable prior to materialization.
|
||||||
void replaceWith(VSO &V, SymbolStringPtr Name, JITSymbolFlags Flags,
|
void replaceWith(VSO &V, SymbolStringPtr Name, JITSymbolFlags Flags,
|
||||||
MaterializationInfoIterator NewMaterializationInfoItr);
|
UnmaterializedInfoIterator NewUMII);
|
||||||
std::unique_ptr<MaterializationUnit>
|
|
||||||
query(SymbolStringPtr Name, std::shared_ptr<AsynchronousSymbolQuery> Query);
|
// Move entry to materializing state, detach from UMII.
|
||||||
void resolve(VSO &V, SymbolStringPtr Name, JITEvaluatedSymbol Sym);
|
std::unique_ptr<MaterializationUnit> initMaterialize(VSO &V);
|
||||||
void finalize(VSO &V, SymbolStringPtr Name);
|
|
||||||
void discard(VSO &V, SymbolStringPtr Name);
|
// Move entry to resolved state.
|
||||||
|
void resolve(VSO &V, JITEvaluatedSymbol Sym);
|
||||||
|
|
||||||
|
// Move entry to finalized state.
|
||||||
|
void finalize();
|
||||||
|
|
||||||
|
JITSymbolFlags Flags;
|
||||||
|
|
||||||
|
union {
|
||||||
|
JITTargetAddress Address;
|
||||||
|
UnmaterializedInfoIterator UMII;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
JITSymbolFlags Flags;
|
|
||||||
MaterializationInfoIterator MII;
|
|
||||||
union {
|
|
||||||
JITTargetAddress Address;
|
|
||||||
MaterializationInfoIterator MaterializationInfoItr;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void detach(UnmaterializedInfoIterator UMII);
|
||||||
|
|
||||||
std::map<SymbolStringPtr, SymbolTableEntry> Symbols;
|
std::map<SymbolStringPtr, SymbolTableEntry> Symbols;
|
||||||
MaterializationInfoSet MaterializationInfos;
|
UnmaterializedInfoList UnmaterializedInfos;
|
||||||
|
MaterializingInfoMap MaterializingInfos;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief An ExecutionSession represents a running JIT program.
|
/// @brief An ExecutionSession represents a running JIT program.
|
||||||
|
@ -62,7 +62,7 @@ Expected<SymbolNameSet> lookupFlagsWithLegacyFn(SymbolFlagsMap &SymbolFlags,
|
|||||||
/// takes a const std::string& or StringRef and returns a JITSymbol) to
|
/// takes a const std::string& or StringRef and returns a JITSymbol) to
|
||||||
/// find the address and flags for each symbol in Symbols and store the
|
/// find the address and flags for each symbol in Symbols and store the
|
||||||
/// result in Query. If any JITSymbol returned by FindSymbol is in an
|
/// result in Query. If any JITSymbol returned by FindSymbol is in an
|
||||||
/// error then Query.setFailed(...) is called with that error and the
|
/// error then Query.notifyFailed(...) is called with that error and the
|
||||||
/// function returns immediately. On success, returns the set of symbols
|
/// function returns immediately. On success, returns the set of symbols
|
||||||
/// not found.
|
/// not found.
|
||||||
///
|
///
|
||||||
@ -76,14 +76,14 @@ SymbolNameSet lookupWithLegacyFn(AsynchronousSymbolQuery &Query,
|
|||||||
for (auto &S : Symbols) {
|
for (auto &S : Symbols) {
|
||||||
if (JITSymbol Sym = FindSymbol(*S)) {
|
if (JITSymbol Sym = FindSymbol(*S)) {
|
||||||
if (auto Addr = Sym.getAddress()) {
|
if (auto Addr = Sym.getAddress()) {
|
||||||
Query.setDefinition(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
|
Query.resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
|
||||||
Query.notifySymbolFinalized();
|
Query.finalizeSymbol();
|
||||||
} else {
|
} else {
|
||||||
Query.setFailed(Addr.takeError());
|
Query.notifyFailed(Addr.takeError());
|
||||||
return SymbolNameSet();
|
return SymbolNameSet();
|
||||||
}
|
}
|
||||||
} else if (auto Err = Sym.takeError()) {
|
} else if (auto Err = Sym.takeError()) {
|
||||||
Query.setFailed(std::move(Err));
|
Query.notifyFailed(std::move(Err));
|
||||||
return SymbolNameSet();
|
return SymbolNameSet();
|
||||||
} else
|
} else
|
||||||
SymbolsNotFound.insert(S);
|
SymbolsNotFound.insert(S);
|
||||||
|
@ -22,7 +22,8 @@ namespace orc {
|
|||||||
|
|
||||||
enum class OrcErrorCode : int {
|
enum class OrcErrorCode : int {
|
||||||
// RPC Errors
|
// RPC Errors
|
||||||
DuplicateDefinition = 1,
|
UnknownORCError = 1,
|
||||||
|
DuplicateDefinition,
|
||||||
JITSymbolNotFound,
|
JITSymbolNotFound,
|
||||||
RemoteAllocatorDoesNotExist,
|
RemoteAllocatorDoesNotExist,
|
||||||
RemoteAllocatorIdAlreadyInUse,
|
RemoteAllocatorIdAlreadyInUse,
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||||
#include "llvm/ExecutionEngine/Orc/OrcError.h"
|
#include "llvm/ExecutionEngine/Orc/OrcError.h"
|
||||||
|
#include "llvm/Support/Format.h"
|
||||||
|
|
||||||
#if LLVM_ENABLE_THREADS
|
#if LLVM_ENABLE_THREADS
|
||||||
#include <future>
|
#include <future>
|
||||||
@ -17,9 +18,100 @@
|
|||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace orc {
|
namespace orc {
|
||||||
|
|
||||||
|
char FailedToMaterialize::ID = 0;
|
||||||
|
char FailedToResolve::ID = 0;
|
||||||
|
char FailedToFinalize::ID = 0;
|
||||||
|
|
||||||
void MaterializationUnit::anchor() {}
|
void MaterializationUnit::anchor() {}
|
||||||
void SymbolResolver::anchor() {}
|
void SymbolResolver::anchor() {}
|
||||||
|
|
||||||
|
raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) {
|
||||||
|
if (Flags.isWeak())
|
||||||
|
OS << 'W';
|
||||||
|
else if (Flags.isCommon())
|
||||||
|
OS << 'C';
|
||||||
|
else
|
||||||
|
OS << 'S';
|
||||||
|
|
||||||
|
if (Flags.isExported())
|
||||||
|
OS << 'E';
|
||||||
|
else
|
||||||
|
OS << 'H';
|
||||||
|
|
||||||
|
return OS;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_ostream &operator<<(raw_ostream &OS, const JITEvaluatedSymbol &Sym) {
|
||||||
|
OS << format("0x%016x", Sym.getAddress()) << " " << Sym.getFlags();
|
||||||
|
return OS;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV) {
|
||||||
|
OS << "\"" << *KV.first << "\": " << KV.second;
|
||||||
|
return OS;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) {
|
||||||
|
OS << "{";
|
||||||
|
if (!Symbols.empty()) {
|
||||||
|
OS << " \"" << **Symbols.begin() << "\"";
|
||||||
|
for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end()))
|
||||||
|
OS << ", \"" << *Sym << "\"";
|
||||||
|
}
|
||||||
|
OS << " }";
|
||||||
|
return OS;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) {
|
||||||
|
OS << "{";
|
||||||
|
if (!Symbols.empty()) {
|
||||||
|
OS << " {" << *Symbols.begin() << "}";
|
||||||
|
for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end()))
|
||||||
|
OS << ", {" << Sym << "}";
|
||||||
|
}
|
||||||
|
OS << " }";
|
||||||
|
return OS;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) {
|
||||||
|
OS << "{";
|
||||||
|
if (SymbolFlags.empty()) {
|
||||||
|
OS << " {\"" << *SymbolFlags.begin()->first
|
||||||
|
<< "\": " << SymbolFlags.begin()->second << "}";
|
||||||
|
for (auto &KV :
|
||||||
|
make_range(std::next(SymbolFlags.begin()), SymbolFlags.end()))
|
||||||
|
OS << ", {\"" << *KV.first << "\": " << KV.second << "}";
|
||||||
|
}
|
||||||
|
OS << " }";
|
||||||
|
return OS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FailedToResolve::FailedToResolve(SymbolNameSet Symbols)
|
||||||
|
: Symbols(std::move(Symbols)) {
|
||||||
|
assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code FailedToResolve::convertToErrorCode() const {
|
||||||
|
return orcError(OrcErrorCode::UnknownORCError);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FailedToResolve::log(raw_ostream &OS) const {
|
||||||
|
OS << "Failed to resolve symbols: " << Symbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
FailedToFinalize::FailedToFinalize(SymbolNameSet Symbols)
|
||||||
|
: Symbols(std::move(Symbols)) {
|
||||||
|
assert(!this->Symbols.empty() && "Can not fail to finalize an empty set");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code FailedToFinalize::convertToErrorCode() const {
|
||||||
|
return orcError(OrcErrorCode::UnknownORCError);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FailedToFinalize::log(raw_ostream &OS) const {
|
||||||
|
OS << "Failed to finalize symbols: " << Symbols;
|
||||||
|
}
|
||||||
|
|
||||||
AsynchronousSymbolQuery::AsynchronousSymbolQuery(
|
AsynchronousSymbolQuery::AsynchronousSymbolQuery(
|
||||||
const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
|
const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
|
||||||
SymbolsReadyCallback NotifySymbolsReady)
|
SymbolsReadyCallback NotifySymbolsReady)
|
||||||
@ -31,16 +123,18 @@ AsynchronousSymbolQuery::AsynchronousSymbolQuery(
|
|||||||
OutstandingResolutions = OutstandingFinalizations = Symbols.size();
|
OutstandingResolutions = OutstandingFinalizations = Symbols.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsynchronousSymbolQuery::setFailed(Error Err) {
|
void AsynchronousSymbolQuery::notifyFailed(Error Err) {
|
||||||
OutstandingResolutions = OutstandingFinalizations = 0;
|
if (OutstandingResolutions != 0)
|
||||||
if (NotifySymbolsResolved)
|
|
||||||
NotifySymbolsResolved(std::move(Err));
|
NotifySymbolsResolved(std::move(Err));
|
||||||
else
|
else if (OutstandingFinalizations != 0)
|
||||||
NotifySymbolsReady(std::move(Err));
|
NotifySymbolsReady(std::move(Err));
|
||||||
|
else
|
||||||
|
consumeError(std::move(Err));
|
||||||
|
OutstandingResolutions = OutstandingFinalizations = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsynchronousSymbolQuery::setDefinition(SymbolStringPtr Name,
|
void AsynchronousSymbolQuery::resolve(SymbolStringPtr Name,
|
||||||
JITEvaluatedSymbol Sym) {
|
JITEvaluatedSymbol Sym) {
|
||||||
// If OutstandingResolutions is zero we must have errored out already. Just
|
// If OutstandingResolutions is zero we must have errored out already. Just
|
||||||
// ignore this.
|
// ignore this.
|
||||||
if (OutstandingResolutions == 0)
|
if (OutstandingResolutions == 0)
|
||||||
@ -49,14 +143,11 @@ void AsynchronousSymbolQuery::setDefinition(SymbolStringPtr Name,
|
|||||||
assert(!Symbols.count(Name) && "Symbol has already been assigned an address");
|
assert(!Symbols.count(Name) && "Symbol has already been assigned an address");
|
||||||
Symbols.insert(std::make_pair(std::move(Name), std::move(Sym)));
|
Symbols.insert(std::make_pair(std::move(Name), std::move(Sym)));
|
||||||
--OutstandingResolutions;
|
--OutstandingResolutions;
|
||||||
if (OutstandingResolutions == 0) {
|
if (OutstandingResolutions == 0)
|
||||||
NotifySymbolsResolved(std::move(Symbols));
|
NotifySymbolsResolved(std::move(Symbols));
|
||||||
// Null out NotifySymbolsResolved to indicate that we've already called it.
|
|
||||||
NotifySymbolsResolved = {};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsynchronousSymbolQuery::notifySymbolFinalized() {
|
void AsynchronousSymbolQuery::finalizeSymbol() {
|
||||||
// If OutstandingFinalizations is zero we must have errored out already. Just
|
// If OutstandingFinalizations is zero we must have errored out already. Just
|
||||||
// ignore this.
|
// ignore this.
|
||||||
if (OutstandingFinalizations == 0)
|
if (OutstandingFinalizations == 0)
|
||||||
@ -68,173 +159,115 @@ void AsynchronousSymbolQuery::notifySymbolFinalized() {
|
|||||||
NotifySymbolsReady(Error::success());
|
NotifySymbolsReady(Error::success());
|
||||||
}
|
}
|
||||||
|
|
||||||
VSO::MaterializationInfo::MaterializationInfo(
|
VSO::UnmaterializedInfo::UnmaterializedInfo(
|
||||||
size_t SymbolsRemaining, std::unique_ptr<MaterializationUnit> MU)
|
size_t SymbolsRemaining, std::unique_ptr<MaterializationUnit> MU)
|
||||||
: SymbolsRemaining(SymbolsRemaining), MU(std::move(MU)) {}
|
: SymbolsRemaining(SymbolsRemaining), MU(std::move(MU)) {}
|
||||||
|
|
||||||
VSO::SymbolTableEntry::SymbolTableEntry(
|
VSO::SymbolTableEntry::SymbolTableEntry(JITSymbolFlags Flags,
|
||||||
JITSymbolFlags Flags, MaterializationInfoIterator MaterializationInfoItr)
|
UnmaterializedInfoIterator UMII)
|
||||||
: Flags(JITSymbolFlags::FlagNames(Flags | JITSymbolFlags::NotMaterialized)),
|
: Flags(Flags), UMII(std::move(UMII)) {
|
||||||
MaterializationInfoItr(std::move(MaterializationInfoItr)) {
|
// We *don't* expect isLazy to be set here. That's for the VSO to do.
|
||||||
// FIXME: Assert flag sanity.
|
assert(!Flags.isLazy() && "Initial flags include lazy?");
|
||||||
|
assert(!Flags.isMaterializing() && "Initial flags include materializing");
|
||||||
|
this->Flags |= JITSymbolFlags::Lazy;
|
||||||
}
|
}
|
||||||
|
|
||||||
VSO::SymbolTableEntry::SymbolTableEntry(JITEvaluatedSymbol Sym)
|
VSO::SymbolTableEntry::SymbolTableEntry(JITEvaluatedSymbol Sym)
|
||||||
: Flags(Sym.getFlags()), Address(Sym.getAddress()) {
|
: Flags(Sym.getFlags()), Address(Sym.getAddress()) {
|
||||||
// FIXME: Assert flag sanity.
|
assert(!Flags.isLazy() && !Flags.isMaterializing() &&
|
||||||
|
"This constructor is for final symbols only");
|
||||||
}
|
}
|
||||||
|
|
||||||
VSO::SymbolTableEntry::SymbolTableEntry(SymbolTableEntry &&Other)
|
// VSO::SymbolTableEntry::SymbolTableEntry(SymbolTableEntry &&Other)
|
||||||
: Flags(Other.Flags), Address(0) {
|
// : Flags(Other.Flags), Address(0) {
|
||||||
if (Flags.isMaterialized())
|
// if (this->Flags.isLazy())
|
||||||
Address = Other.Address;
|
// UMII = std::move(Other.UMII);
|
||||||
else
|
// else
|
||||||
MaterializationInfoItr = std::move(Other.MaterializationInfoItr);
|
// Address = Other.Address;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
// VSO::SymbolTableEntry &VSO::SymbolTableEntry::
|
||||||
|
// operator=(SymbolTableEntry &&Other) {
|
||||||
|
// destroy();
|
||||||
|
// Flags = std::move(Other.Flags);
|
||||||
|
// if (Other.Flags.isLazy()) {
|
||||||
|
// UMII = std::move(Other.UMII);
|
||||||
|
// } else
|
||||||
|
// Address = Other.Address;
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
|
||||||
VSO::SymbolTableEntry::~SymbolTableEntry() { destroy(); }
|
VSO::SymbolTableEntry::~SymbolTableEntry() { destroy(); }
|
||||||
|
|
||||||
VSO::SymbolTableEntry &VSO::SymbolTableEntry::
|
void VSO::SymbolTableEntry::replaceWith(VSO &V, SymbolStringPtr Name,
|
||||||
operator=(JITEvaluatedSymbol Sym) {
|
JITEvaluatedSymbol Sym) {
|
||||||
|
assert(!Flags.isMaterializing() &&
|
||||||
|
"Attempting to replace definition during materialization?");
|
||||||
|
if (Flags.isLazy()) {
|
||||||
|
if (UMII->MU)
|
||||||
|
UMII->MU->discard(V, Name);
|
||||||
|
V.detach(UMII);
|
||||||
|
}
|
||||||
destroy();
|
destroy();
|
||||||
Flags = Sym.getFlags();
|
Flags = Sym.getFlags();
|
||||||
Address = Sym.getAddress();
|
Address = Sym.getAddress();
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VSO::SymbolTableEntry::destroy() {
|
void VSO::SymbolTableEntry::replaceWith(VSO &V, SymbolStringPtr Name,
|
||||||
if (!Flags.isMaterialized())
|
JITSymbolFlags NewFlags,
|
||||||
MaterializationInfoItr.~MaterializationInfoIterator();
|
UnmaterializedInfoIterator NewUMII) {
|
||||||
}
|
assert(!Flags.isMaterializing() &&
|
||||||
|
"Attempting to replace definition during materialization?");
|
||||||
JITSymbolFlags VSO::SymbolTableEntry::getFlags() const { return Flags; }
|
if (Flags.isLazy()) {
|
||||||
|
if (UMII->MU)
|
||||||
void VSO::SymbolTableEntry::replaceWith(
|
UMII->MU->discard(V, Name);
|
||||||
VSO &V, SymbolStringPtr Name, JITSymbolFlags NewFlags,
|
V.detach(UMII);
|
||||||
MaterializationInfoIterator NewMaterializationInfoItr) {
|
|
||||||
bool ReplaceExistingLazyDefinition = !Flags.isMaterialized();
|
|
||||||
Flags = NewFlags;
|
|
||||||
if (ReplaceExistingLazyDefinition) {
|
|
||||||
// If we are replacing an existing lazy definition with a stronger one,
|
|
||||||
// we need to notify the old lazy definition to discard its definition.
|
|
||||||
assert((*MaterializationInfoItr)->MU != nullptr &&
|
|
||||||
(*MaterializationInfoItr)->Symbols.count(Name) == 0 &&
|
|
||||||
(*MaterializationInfoItr)->PendingResolution.count(Name) == 0 &&
|
|
||||||
(*MaterializationInfoItr)->PendingFinalization.count(Name) == 0 &&
|
|
||||||
"Attempt to replace materializer during materialization");
|
|
||||||
|
|
||||||
if (--(*MaterializationInfoItr)->SymbolsRemaining == 0)
|
|
||||||
V.MaterializationInfos.erase(MaterializationInfoItr);
|
|
||||||
}
|
}
|
||||||
MaterializationInfoItr = std::move(NewMaterializationInfoItr);
|
destroy();
|
||||||
|
Flags = NewFlags;
|
||||||
|
UMII = std::move(NewUMII);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<MaterializationUnit>
|
std::unique_ptr<MaterializationUnit>
|
||||||
VSO::SymbolTableEntry::query(SymbolStringPtr Name,
|
VSO::SymbolTableEntry::initMaterialize(VSO &V) {
|
||||||
std::shared_ptr<AsynchronousSymbolQuery> Query) {
|
assert(Flags.isLazy() && "Can't materialize non-lazy symbol");
|
||||||
if (Flags.isMaterialized()) {
|
auto TmpMU = std::move(UMII->MU);
|
||||||
Query->setDefinition(std::move(Name), JITEvaluatedSymbol(Address, Flags));
|
V.detach(UMII);
|
||||||
Query->notifySymbolFinalized();
|
destroy();
|
||||||
return nullptr;
|
Flags &= ~JITSymbolFlags::Lazy;
|
||||||
} else {
|
Flags |= JITSymbolFlags::Materializing;
|
||||||
if ((*MaterializationInfoItr)->MU) {
|
Address = 0;
|
||||||
assert((*MaterializationInfoItr)->PendingResolution.count(Name) == 0 &&
|
return TmpMU;
|
||||||
(*MaterializationInfoItr)->PendingFinalization.count(Name) == 0 &&
|
|
||||||
"Materializer should have been activated on first query");
|
|
||||||
(*MaterializationInfoItr)
|
|
||||||
->PendingResolution[Name]
|
|
||||||
.push_back(std::move(Query));
|
|
||||||
return std::move((*MaterializationInfoItr)->MU);
|
|
||||||
} else {
|
|
||||||
assert((*MaterializationInfoItr)->MU == nullptr &&
|
|
||||||
"Materializer should have been activated on first query");
|
|
||||||
auto SymValueItr = (*MaterializationInfoItr)->Symbols.find(Name);
|
|
||||||
if (SymValueItr == (*MaterializationInfoItr)->Symbols.end()) {
|
|
||||||
// Symbol has not been resolved yet.
|
|
||||||
(*MaterializationInfoItr)
|
|
||||||
->PendingResolution[Name]
|
|
||||||
.push_back(std::move(Query));
|
|
||||||
return nullptr;
|
|
||||||
} else {
|
|
||||||
// Symbol has already resolved, is just waiting on finalization.
|
|
||||||
Query->setDefinition(Name, SymValueItr->second);
|
|
||||||
(*MaterializationInfoItr)
|
|
||||||
->PendingFinalization[Name]
|
|
||||||
.push_back(std::move(Query));
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VSO::SymbolTableEntry::resolve(VSO &V, SymbolStringPtr Name,
|
void VSO::SymbolTableEntry::resolve(VSO &V, JITEvaluatedSymbol Sym) {
|
||||||
JITEvaluatedSymbol Sym) {
|
if (Flags.isLazy()) {
|
||||||
if (Flags.isMaterialized()) {
|
assert(!UMII->MU && "Resolving with MaterializationUnit still attached?");
|
||||||
// FIXME: Should we assert flag state here (flags must match except for
|
V.detach(UMII);
|
||||||
// materialization state, overrides must be legal) or in the caller
|
|
||||||
// in VSO?
|
|
||||||
Flags = Sym.getFlags();
|
|
||||||
Address = Sym.getAddress();
|
|
||||||
} else {
|
|
||||||
assert((*MaterializationInfoItr)->MU == nullptr &&
|
|
||||||
"Can not resolve a symbol that has not been materialized");
|
|
||||||
assert((*MaterializationInfoItr)->Symbols.count(Name) == 0 &&
|
|
||||||
"Symbol resolved more than once");
|
|
||||||
|
|
||||||
// Add the symbol to the MaterializationInfo Symbols table.
|
|
||||||
(*MaterializationInfoItr)->Symbols[Name] = Sym;
|
|
||||||
|
|
||||||
// If there are any queries waiting on this symbol then notify them that it
|
|
||||||
// has been resolved, then move them to the PendingFinalization list.
|
|
||||||
auto I = (*MaterializationInfoItr)->PendingResolution.find(Name);
|
|
||||||
if (I != (*MaterializationInfoItr)->PendingResolution.end()) {
|
|
||||||
assert((*MaterializationInfoItr)->PendingFinalization.count(Name) == 0 &&
|
|
||||||
"Queries already pending finalization on newly resolved symbol");
|
|
||||||
auto &PendingFinalization =
|
|
||||||
(*MaterializationInfoItr)->PendingFinalization[Name];
|
|
||||||
|
|
||||||
for (auto &Query : I->second) {
|
|
||||||
Query->setDefinition(Name, Sym);
|
|
||||||
PendingFinalization.push_back(Query);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the PendingResolution list for this symbol.
|
|
||||||
(*MaterializationInfoItr)->PendingResolution.erase(I);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
destroy();
|
||||||
|
Flags = Sym.getFlags();
|
||||||
|
Flags |= JITSymbolFlags::Materializing;
|
||||||
|
Address = Sym.getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VSO::SymbolTableEntry::finalize(VSO &V, SymbolStringPtr Name) {
|
void VSO::SymbolTableEntry::finalize() {
|
||||||
if (!Flags.isMaterialized()) {
|
assert(Flags.isMaterializing() && !Flags.isLazy() &&
|
||||||
auto SymI = (*MaterializationInfoItr)->Symbols.find(Name);
|
"Symbol should be in materializing state");
|
||||||
assert(SymI != (*MaterializationInfoItr)->Symbols.end() &&
|
Flags &= ~JITSymbolFlags::Materializing;
|
||||||
"Finalizing an unresolved symbol");
|
|
||||||
auto Sym = SymI->second;
|
|
||||||
(*MaterializationInfoItr)->Symbols.erase(SymI);
|
|
||||||
auto I = (*MaterializationInfoItr)->PendingFinalization.find(Name);
|
|
||||||
if (I != (*MaterializationInfoItr)->PendingFinalization.end()) {
|
|
||||||
for (auto &Query : I->second)
|
|
||||||
Query->notifySymbolFinalized();
|
|
||||||
(*MaterializationInfoItr)->PendingFinalization.erase(I);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (--(*MaterializationInfoItr)->SymbolsRemaining == 0)
|
|
||||||
V.MaterializationInfos.erase(MaterializationInfoItr);
|
|
||||||
|
|
||||||
// Destruct the iterator and re-define this entry using the final symbol
|
|
||||||
// value.
|
|
||||||
destroy();
|
|
||||||
Flags = Sym.getFlags();
|
|
||||||
Address = Sym.getAddress();
|
|
||||||
}
|
|
||||||
assert(Flags.isMaterialized() && "Trying to finalize not-emitted symbol");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VSO::SymbolTableEntry::discard(VSO &V, SymbolStringPtr Name) {
|
void VSO::SymbolTableEntry::destroy() {
|
||||||
assert((*MaterializationInfoItr)->MU != nullptr &&
|
if (Flags.isLazy())
|
||||||
"Can not override a symbol after it has been materialized");
|
UMII.~UnmaterializedInfoIterator();
|
||||||
(*MaterializationInfoItr)->MU->discard(V, Name);
|
}
|
||||||
--(*MaterializationInfoItr)->SymbolsRemaining;
|
|
||||||
|
void VSO::detach(UnmaterializedInfoIterator UMII) {
|
||||||
|
assert(UMII->SymbolsRemaining > 0 &&
|
||||||
|
"Detaching from empty UnmaterializedInfo?");
|
||||||
|
--UMII->SymbolsRemaining;
|
||||||
|
if (UMII->SymbolsRemaining == 0)
|
||||||
|
UnmaterializedInfos.erase(UMII);
|
||||||
}
|
}
|
||||||
|
|
||||||
VSO::RelativeLinkageStrength VSO::compareLinkage(Optional<JITSymbolFlags> Old,
|
VSO::RelativeLinkageStrength VSO::compareLinkage(Optional<JITSymbolFlags> Old,
|
||||||
@ -258,10 +291,9 @@ VSO::RelativeLinkageStrength VSO::compareLinkage(Optional<JITSymbolFlags> Old,
|
|||||||
VSO::RelativeLinkageStrength
|
VSO::RelativeLinkageStrength
|
||||||
VSO::compareLinkage(SymbolStringPtr Name, JITSymbolFlags NewFlags) const {
|
VSO::compareLinkage(SymbolStringPtr Name, JITSymbolFlags NewFlags) const {
|
||||||
auto I = Symbols.find(Name);
|
auto I = Symbols.find(Name);
|
||||||
return compareLinkage(I == Symbols.end()
|
return compareLinkage(
|
||||||
? None
|
I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags),
|
||||||
: Optional<JITSymbolFlags>(I->second.getFlags()),
|
NewFlags);
|
||||||
NewFlags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error VSO::define(SymbolMap NewSymbols) {
|
Error VSO::define(SymbolMap NewSymbols) {
|
||||||
@ -269,8 +301,7 @@ Error VSO::define(SymbolMap NewSymbols) {
|
|||||||
for (auto &KV : NewSymbols) {
|
for (auto &KV : NewSymbols) {
|
||||||
auto I = Symbols.find(KV.first);
|
auto I = Symbols.find(KV.first);
|
||||||
auto LinkageResult = compareLinkage(
|
auto LinkageResult = compareLinkage(
|
||||||
I == Symbols.end() ? None
|
I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags),
|
||||||
: Optional<JITSymbolFlags>(I->second.getFlags()),
|
|
||||||
KV.second.getFlags());
|
KV.second.getFlags());
|
||||||
|
|
||||||
// Silently discard weaker definitions.
|
// Silently discard weaker definitions.
|
||||||
@ -284,11 +315,9 @@ Error VSO::define(SymbolMap NewSymbols) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (I != Symbols.end()) {
|
if (I != Symbols.end())
|
||||||
// This is an override -- discard the overridden definition and overwrite.
|
I->second.replaceWith(*this, I->first, KV.second);
|
||||||
I->second.discard(*this, KV.first);
|
else
|
||||||
I->second = std::move(KV.second);
|
|
||||||
} else
|
|
||||||
Symbols.insert(std::make_pair(KV.first, std::move(KV.second)));
|
Symbols.insert(std::make_pair(KV.first, std::move(KV.second)));
|
||||||
}
|
}
|
||||||
return Err;
|
return Err;
|
||||||
@ -298,27 +327,26 @@ Error VSO::defineLazy(std::unique_ptr<MaterializationUnit> MU) {
|
|||||||
|
|
||||||
auto NewSymbols = MU->getSymbols();
|
auto NewSymbols = MU->getSymbols();
|
||||||
|
|
||||||
auto MaterializationInfoItr =
|
auto UMII = UnmaterializedInfos.insert(
|
||||||
MaterializationInfos
|
UnmaterializedInfos.end(),
|
||||||
.insert(llvm::make_unique<MaterializationInfo>(NewSymbols.size(),
|
UnmaterializedInfo(NewSymbols.size(), std::move(MU)));
|
||||||
std::move(MU)))
|
|
||||||
.first;
|
|
||||||
|
|
||||||
Error Err = Error::success();
|
Error Err = Error::success();
|
||||||
for (auto &KV : NewSymbols) {
|
for (auto &KV : NewSymbols) {
|
||||||
auto I = Symbols.find(KV.first);
|
auto I = Symbols.find(KV.first);
|
||||||
|
|
||||||
|
assert(I == Symbols.end() ||
|
||||||
|
!I->second.Flags.isMaterializing() &&
|
||||||
|
"Attempt to replace materializing symbol definition");
|
||||||
|
|
||||||
auto LinkageResult = compareLinkage(
|
auto LinkageResult = compareLinkage(
|
||||||
I == Symbols.end() ? None
|
I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags),
|
||||||
: Optional<JITSymbolFlags>(I->second.getFlags()),
|
|
||||||
KV.second);
|
KV.second);
|
||||||
|
|
||||||
// Discard weaker definitions.
|
// Discard weaker definitions.
|
||||||
if (LinkageResult == ExistingDefinitionIsStronger) {
|
if (LinkageResult == ExistingDefinitionIsStronger) {
|
||||||
(*MaterializationInfoItr)->MU->discard(*this, KV.first);
|
UMII->MU->discard(*this, KV.first);
|
||||||
assert((*MaterializationInfoItr)->SymbolsRemaining > 0 &&
|
detach(UMII);
|
||||||
"Discarding non-existant symbols?");
|
|
||||||
--(*MaterializationInfoItr)->SymbolsRemaining;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,43 +356,109 @@ Error VSO::defineLazy(std::unique_ptr<MaterializationUnit> MU) {
|
|||||||
make_error<orc::DuplicateDefinition>(*KV.first));
|
make_error<orc::DuplicateDefinition>(*KV.first));
|
||||||
// Duplicate definitions are discarded, so remove the duplicates from
|
// Duplicate definitions are discarded, so remove the duplicates from
|
||||||
// materializer.
|
// materializer.
|
||||||
assert((*MaterializationInfoItr)->SymbolsRemaining > 0 &&
|
detach(UMII);
|
||||||
"Discarding non-existant symbols?");
|
|
||||||
--(*MaterializationInfoItr)->SymbolsRemaining;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Existing definition was weaker. Replace it.
|
||||||
if (I != Symbols.end())
|
if (I != Symbols.end())
|
||||||
I->second.replaceWith(*this, KV.first, KV.second, MaterializationInfoItr);
|
I->second.replaceWith(*this, KV.first, KV.second, UMII);
|
||||||
else
|
else
|
||||||
Symbols.emplace(std::make_pair(
|
Symbols.emplace(
|
||||||
KV.first, SymbolTableEntry(KV.second, MaterializationInfoItr)));
|
std::make_pair(KV.first, SymbolTableEntry(KV.second, UMII)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we ended up overriding all definitions in this materializer then delete
|
|
||||||
// it.
|
|
||||||
if ((*MaterializationInfoItr)->SymbolsRemaining == 0)
|
|
||||||
MaterializationInfos.erase(MaterializationInfoItr);
|
|
||||||
|
|
||||||
return Err;
|
return Err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VSO::resolve(SymbolMap SymbolValues) {
|
void VSO::resolve(const SymbolMap &SymbolValues) {
|
||||||
for (auto &KV : SymbolValues) {
|
for (auto &KV : SymbolValues) {
|
||||||
auto I = Symbols.find(KV.first);
|
auto I = Symbols.find(KV.first);
|
||||||
assert(I != Symbols.end() && "Resolving symbol not present in this dylib");
|
assert(I != Symbols.end() && "Resolving symbol not present in this dylib");
|
||||||
I->second.resolve(*this, KV.first, std::move(KV.second));
|
I->second.resolve(*this, KV.second);
|
||||||
|
|
||||||
|
auto J = MaterializingInfos.find(KV.first);
|
||||||
|
if (J == MaterializingInfos.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
assert(J->second.PendingFinalization.empty() &&
|
||||||
|
"Queries already pending finalization?");
|
||||||
|
for (auto &Q : J->second.PendingResolution)
|
||||||
|
Q->resolve(KV.first, KV.second);
|
||||||
|
J->second.PendingFinalization = std::move(J->second.PendingResolution);
|
||||||
|
J->second.PendingResolution = MaterializingInfo::QueryList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VSO::finalize(SymbolNameSet SymbolsToFinalize) {
|
void VSO::notifyResolutionFailed(const SymbolNameSet &Names) {
|
||||||
|
assert(!Names.empty() && "Failed to resolve empty set?");
|
||||||
|
|
||||||
|
std::map<std::shared_ptr<AsynchronousSymbolQuery>, SymbolNameSet>
|
||||||
|
QueriesToFail;
|
||||||
|
|
||||||
|
for (auto &S : Names) {
|
||||||
|
auto I = Symbols.find(S);
|
||||||
|
assert(I != Symbols.end() && "Symbol not present in this VSO");
|
||||||
|
|
||||||
|
auto J = MaterializingInfos.find(S);
|
||||||
|
if (J != MaterializingInfos.end()) {
|
||||||
|
assert(J->second.PendingFinalization.empty() &&
|
||||||
|
"Failed during resolution, but queries pending finalization?");
|
||||||
|
for (auto &Q : J->second.PendingResolution)
|
||||||
|
QueriesToFail[Q].insert(S);
|
||||||
|
MaterializingInfos.erase(J);
|
||||||
|
}
|
||||||
|
Symbols.erase(I);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &KV : QueriesToFail)
|
||||||
|
KV.first->notifyFailed(make_error<FailedToResolve>(std::move(KV.second)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSO::finalize(const SymbolNameSet &SymbolsToFinalize) {
|
||||||
for (auto &S : SymbolsToFinalize) {
|
for (auto &S : SymbolsToFinalize) {
|
||||||
auto I = Symbols.find(S);
|
auto I = Symbols.find(S);
|
||||||
assert(I != Symbols.end() && "Finalizing symbol not present in this dylib");
|
assert(I != Symbols.end() && "Finalizing symbol not present in this dylib");
|
||||||
I->second.finalize(*this, S);
|
|
||||||
|
auto J = MaterializingInfos.find(S);
|
||||||
|
if (J != MaterializingInfos.end()) {
|
||||||
|
assert(J->second.PendingResolution.empty() &&
|
||||||
|
"Queries still pending resolution?");
|
||||||
|
for (auto &Q : J->second.PendingFinalization)
|
||||||
|
Q->finalizeSymbol();
|
||||||
|
MaterializingInfos.erase(J);
|
||||||
|
}
|
||||||
|
I->second.finalize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VSO::notifyFinalizationFailed(const SymbolNameSet &Names) {
|
||||||
|
assert(!Names.empty() && "Failed to finalize empty set?");
|
||||||
|
|
||||||
|
std::map<std::shared_ptr<AsynchronousSymbolQuery>, SymbolNameSet>
|
||||||
|
QueriesToFail;
|
||||||
|
|
||||||
|
for (auto &S : Names) {
|
||||||
|
auto I = Symbols.find(S);
|
||||||
|
assert(I != Symbols.end() && "Symbol not present in this VSO");
|
||||||
|
assert((I->second.Flags & JITSymbolFlags::Materializing) &&
|
||||||
|
"Failed to finalize symbol that was not materializing");
|
||||||
|
|
||||||
|
auto J = MaterializingInfos.find(S);
|
||||||
|
if (J != MaterializingInfos.end()) {
|
||||||
|
assert(J->second.PendingResolution.empty() &&
|
||||||
|
"Failed during finalization, but queries pending resolution?");
|
||||||
|
for (auto &Q : J->second.PendingFinalization)
|
||||||
|
QueriesToFail[Q].insert(S);
|
||||||
|
MaterializingInfos.erase(J);
|
||||||
|
}
|
||||||
|
Symbols.erase(I);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &KV : QueriesToFail)
|
||||||
|
KV.first->notifyFailed(make_error<FailedToFinalize>(std::move(KV.second)));
|
||||||
|
}
|
||||||
|
|
||||||
SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Names) {
|
SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Names) {
|
||||||
|
|
||||||
for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) {
|
for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) {
|
||||||
@ -378,7 +472,7 @@ SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Names) {
|
|||||||
Names.erase(Tmp);
|
Names.erase(Tmp);
|
||||||
|
|
||||||
Flags[SymI->first] =
|
Flags[SymI->first] =
|
||||||
JITSymbolFlags::stripTransientFlags(SymI->second.getFlags());
|
JITSymbolFlags::stripTransientFlags(SymI->second.Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Names;
|
return Names;
|
||||||
@ -396,14 +490,43 @@ VSO::LookupResult VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
|
|||||||
if (SymI == Symbols.end())
|
if (SymI == Symbols.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// The symbol is in the dylib. Erase it from Names and proceed.
|
// The symbol is in the VSO. Erase it from Names and proceed.
|
||||||
Names.erase(Tmp);
|
Names.erase(Tmp);
|
||||||
|
|
||||||
// Forward the query to the given SymbolTableEntry, and if it return a
|
// If this symbol has not been materialized yet, move it to materializing,
|
||||||
// layer to perform materialization with, add that to the
|
// then fall through to the materializing case below.
|
||||||
// MaterializationWork map.
|
if (SymI->second.Flags.isLazy()) {
|
||||||
if (auto MU = SymI->second.query(SymI->first, Query))
|
if (auto MU = SymI->second.initMaterialize(*this))
|
||||||
MaterializationUnits.push_back(std::move(MU));
|
MaterializationUnits.push_back(std::move(MU));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this symbol already has a fully materialized value, just use it.
|
||||||
|
if (!SymI->second.Flags.isMaterializing()) {
|
||||||
|
Query->resolve(SymI->first, JITEvaluatedSymbol(SymI->second.Address,
|
||||||
|
SymI->second.Flags));
|
||||||
|
Query->finalizeSymbol();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this symbol is materializing, then get (or create) its
|
||||||
|
// MaterializingInfo struct and appaend the query.
|
||||||
|
auto J = MaterializingInfos.find(SymI->first);
|
||||||
|
if (J == MaterializingInfos.end())
|
||||||
|
J = MaterializingInfos
|
||||||
|
.insert(std::make_pair(SymI->first, MaterializingInfo()))
|
||||||
|
.first;
|
||||||
|
|
||||||
|
if (SymI->second.Address) {
|
||||||
|
auto Sym = JITEvaluatedSymbol(SymI->second.Address, SymI->second.Flags);
|
||||||
|
Query->resolve(SymI->first, Sym);
|
||||||
|
assert(J->second.PendingResolution.empty() &&
|
||||||
|
"Queries still pending resolution on resolved symbol?");
|
||||||
|
J->second.PendingFinalization.push_back(Query);
|
||||||
|
} else {
|
||||||
|
assert(J->second.PendingFinalization.empty() &&
|
||||||
|
"Queries pendiing finalization on unresolved symbol?");
|
||||||
|
J->second.PendingResolution.push_back(Query);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {std::move(MaterializationUnits), std::move(Names)};
|
return {std::move(MaterializationUnits), std::move(Names)};
|
||||||
|
@ -153,13 +153,13 @@ private:
|
|||||||
for (auto &S : Symbols) {
|
for (auto &S : Symbols) {
|
||||||
if (auto Sym = findSymbol(*S)) {
|
if (auto Sym = findSymbol(*S)) {
|
||||||
if (auto Addr = Sym.getAddress())
|
if (auto Addr = Sym.getAddress())
|
||||||
Query->setDefinition(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
|
Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
|
||||||
else {
|
else {
|
||||||
Query->setFailed(Addr.takeError());
|
Query->notifyFailed(Addr.takeError());
|
||||||
return orc::SymbolNameSet();
|
return orc::SymbolNameSet();
|
||||||
}
|
}
|
||||||
} else if (auto Err = Sym.takeError()) {
|
} else if (auto Err = Sym.takeError()) {
|
||||||
Query->setFailed(std::move(Err));
|
Query->notifyFailed(std::move(Err));
|
||||||
return orc::SymbolNameSet();
|
return orc::SymbolNameSet();
|
||||||
} else
|
} else
|
||||||
UnresolvedSymbols.insert(S);
|
UnresolvedSymbols.insert(S);
|
||||||
|
@ -29,6 +29,8 @@ public:
|
|||||||
|
|
||||||
std::string message(int condition) const override {
|
std::string message(int condition) const override {
|
||||||
switch (static_cast<OrcErrorCode>(condition)) {
|
switch (static_cast<OrcErrorCode>(condition)) {
|
||||||
|
case OrcErrorCode::UnknownORCError:
|
||||||
|
return "Unknown ORC error";
|
||||||
case OrcErrorCode::DuplicateDefinition:
|
case OrcErrorCode::DuplicateDefinition:
|
||||||
return "Duplicate symbol definition";
|
return "Duplicate symbol definition";
|
||||||
case OrcErrorCode::JITSymbolNotFound:
|
case OrcErrorCode::JITSymbolNotFound:
|
||||||
|
@ -175,25 +175,24 @@ class OrcMCJITReplacement : public ExecutionEngine {
|
|||||||
for (auto &S : Symbols) {
|
for (auto &S : Symbols) {
|
||||||
if (auto Sym = M.findMangledSymbol(*S)) {
|
if (auto Sym = M.findMangledSymbol(*S)) {
|
||||||
if (auto Addr = Sym.getAddress())
|
if (auto Addr = Sym.getAddress())
|
||||||
Query->setDefinition(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
|
Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
|
||||||
else {
|
else {
|
||||||
Query->setFailed(Addr.takeError());
|
Query->notifyFailed(Addr.takeError());
|
||||||
return SymbolNameSet();
|
return SymbolNameSet();
|
||||||
}
|
}
|
||||||
} else if (auto Err = Sym.takeError()) {
|
} else if (auto Err = Sym.takeError()) {
|
||||||
Query->setFailed(std::move(Err));
|
Query->notifyFailed(std::move(Err));
|
||||||
return SymbolNameSet();
|
return SymbolNameSet();
|
||||||
} else {
|
} else {
|
||||||
if (auto Sym2 = M.ClientResolver->findSymbol(*S)) {
|
if (auto Sym2 = M.ClientResolver->findSymbol(*S)) {
|
||||||
if (auto Addr = Sym2.getAddress())
|
if (auto Addr = Sym2.getAddress())
|
||||||
Query->setDefinition(S,
|
Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym2.getFlags()));
|
||||||
JITEvaluatedSymbol(*Addr, Sym2.getFlags()));
|
|
||||||
else {
|
else {
|
||||||
Query->setFailed(Addr.takeError());
|
Query->notifyFailed(Addr.takeError());
|
||||||
return SymbolNameSet();
|
return SymbolNameSet();
|
||||||
}
|
}
|
||||||
} else if (auto Err = Sym2.takeError()) {
|
} else if (auto Err = Sym2.takeError()) {
|
||||||
Query->setFailed(std::move(Err));
|
Query->notifyFailed(std::move(Err));
|
||||||
return SymbolNameSet();
|
return SymbolNameSet();
|
||||||
} else
|
} else
|
||||||
UnresolvedSymbols.insert(S);
|
UnresolvedSymbols.insert(S);
|
||||||
|
@ -24,12 +24,19 @@ public:
|
|||||||
using GetSymbolsFunction = std::function<SymbolFlagsMap()>;
|
using GetSymbolsFunction = std::function<SymbolFlagsMap()>;
|
||||||
using MaterializeFunction = std::function<Error(VSO &)>;
|
using MaterializeFunction = std::function<Error(VSO &)>;
|
||||||
using DiscardFunction = std::function<void(VSO &, SymbolStringPtr)>;
|
using DiscardFunction = std::function<void(VSO &, SymbolStringPtr)>;
|
||||||
|
using DestructorFunction = std::function<void()>;
|
||||||
|
|
||||||
SimpleMaterializationUnit(GetSymbolsFunction GetSymbols,
|
SimpleMaterializationUnit(
|
||||||
MaterializeFunction Materialize,
|
GetSymbolsFunction GetSymbols, MaterializeFunction Materialize,
|
||||||
DiscardFunction Discard)
|
DiscardFunction Discard,
|
||||||
|
DestructorFunction Destructor = DestructorFunction())
|
||||||
: GetSymbols(std::move(GetSymbols)), Materialize(std::move(Materialize)),
|
: GetSymbols(std::move(GetSymbols)), Materialize(std::move(Materialize)),
|
||||||
Discard(std::move(Discard)) {}
|
Discard(std::move(Discard)), Destructor(std::move(Destructor)) {}
|
||||||
|
|
||||||
|
~SimpleMaterializationUnit() override {
|
||||||
|
if (Destructor)
|
||||||
|
Destructor();
|
||||||
|
}
|
||||||
|
|
||||||
SymbolFlagsMap getSymbols() override { return GetSymbols(); }
|
SymbolFlagsMap getSymbols() override { return GetSymbols(); }
|
||||||
|
|
||||||
@ -43,6 +50,7 @@ private:
|
|||||||
GetSymbolsFunction GetSymbols;
|
GetSymbolsFunction GetSymbols;
|
||||||
MaterializeFunction Materialize;
|
MaterializeFunction Materialize;
|
||||||
DiscardFunction Discard;
|
DiscardFunction Discard;
|
||||||
|
DestructorFunction Destructor;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(CoreAPIsTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) {
|
TEST(CoreAPIsTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) {
|
||||||
@ -68,7 +76,7 @@ TEST(CoreAPIsTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) {
|
|||||||
|
|
||||||
AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
|
AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
|
||||||
|
|
||||||
Q.setDefinition(Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported));
|
Q.resolve(Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported));
|
||||||
|
|
||||||
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
||||||
EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
|
EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
|
||||||
@ -95,7 +103,7 @@ TEST(CoreAPIsTest, AsynchronousSymbolQueryResolutionErrorOnly) {
|
|||||||
|
|
||||||
AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
|
AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
|
||||||
|
|
||||||
Q.setFailed(make_error<StringError>("xyz", inconvertibleErrorCode()));
|
Q.notifyFailed(make_error<StringError>("xyz", inconvertibleErrorCode()));
|
||||||
|
|
||||||
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
||||||
EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
|
EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
|
||||||
@ -186,6 +194,44 @@ TEST(CoreAPIsTest, LookupFlagsTest) {
|
|||||||
EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar";
|
EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(CoreAPIsTest, DropMaterializerWhenEmpty) {
|
||||||
|
SymbolStringPool SP;
|
||||||
|
auto Foo = SP.intern("foo");
|
||||||
|
auto Bar = SP.intern("bar");
|
||||||
|
|
||||||
|
bool DestructorRun = false;
|
||||||
|
|
||||||
|
auto MU = llvm::make_unique<SimpleMaterializationUnit>(
|
||||||
|
[=]() {
|
||||||
|
return SymbolFlagsMap(
|
||||||
|
{{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
|
||||||
|
},
|
||||||
|
[](VSO &V) -> Error {
|
||||||
|
llvm_unreachable("Unexpected call to materialize");
|
||||||
|
},
|
||||||
|
[&](VSO &V, SymbolStringPtr Name) {
|
||||||
|
EXPECT_TRUE(Name == Foo || Name == Bar)
|
||||||
|
<< "Discard of unexpected symbol?";
|
||||||
|
},
|
||||||
|
[&]() { DestructorRun = true; });
|
||||||
|
|
||||||
|
VSO V;
|
||||||
|
|
||||||
|
cantFail(V.defineLazy(std::move(MU)));
|
||||||
|
|
||||||
|
auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported);
|
||||||
|
auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported);
|
||||||
|
cantFail(V.define(SymbolMap({{Foo, FooSym}})));
|
||||||
|
|
||||||
|
EXPECT_FALSE(DestructorRun)
|
||||||
|
<< "MaterializationUnit should not have been destroyed yet";
|
||||||
|
|
||||||
|
cantFail(V.define(SymbolMap({{Bar, BarSym}})));
|
||||||
|
|
||||||
|
EXPECT_TRUE(DestructorRun)
|
||||||
|
<< "MaterializationUnit should have been destroyed";
|
||||||
|
}
|
||||||
|
|
||||||
TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
|
TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
|
||||||
|
|
||||||
constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
|
constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
|
||||||
@ -264,6 +310,121 @@ TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
|
|||||||
EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
|
EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(CoreAPIsTest, FailResolution) {
|
||||||
|
SymbolStringPool SP;
|
||||||
|
auto Foo = SP.intern("foo");
|
||||||
|
auto Bar = SP.intern("bar");
|
||||||
|
|
||||||
|
SymbolNameSet Names({Foo, Bar});
|
||||||
|
|
||||||
|
auto MU = llvm::make_unique<SimpleMaterializationUnit>(
|
||||||
|
[=]() {
|
||||||
|
return SymbolFlagsMap(
|
||||||
|
{{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
|
||||||
|
},
|
||||||
|
[&](VSO &V) -> Error {
|
||||||
|
V.notifyResolutionFailed(Names);
|
||||||
|
return Error::success();
|
||||||
|
},
|
||||||
|
[&](VSO &V, SymbolStringPtr Name) {
|
||||||
|
llvm_unreachable("Unexpected call to discard");
|
||||||
|
});
|
||||||
|
|
||||||
|
VSO V;
|
||||||
|
|
||||||
|
cantFail(V.defineLazy(std::move(MU)));
|
||||||
|
|
||||||
|
auto OnResolution = [&](Expected<SymbolMap> Result) {
|
||||||
|
handleAllErrors(Result.takeError(),
|
||||||
|
[&](FailedToResolve &F) {
|
||||||
|
EXPECT_EQ(F.getSymbols(), Names)
|
||||||
|
<< "Expected to fail on symbols in Names";
|
||||||
|
},
|
||||||
|
[](ErrorInfoBase &EIB) {
|
||||||
|
std::string ErrMsg;
|
||||||
|
{
|
||||||
|
raw_string_ostream ErrOut(ErrMsg);
|
||||||
|
EIB.log(ErrOut);
|
||||||
|
}
|
||||||
|
ADD_FAILURE()
|
||||||
|
<< "Expected a FailedToResolve error. Got:\n"
|
||||||
|
<< ErrMsg;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
auto OnReady = [](Error Err) {
|
||||||
|
cantFail(std::move(Err));
|
||||||
|
ADD_FAILURE() << "OnReady should never be called";
|
||||||
|
};
|
||||||
|
|
||||||
|
auto Q =
|
||||||
|
std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
|
||||||
|
|
||||||
|
auto LR = V.lookup(std::move(Q), Names);
|
||||||
|
for (auto &SWKV : LR.MaterializationUnits)
|
||||||
|
cantFail(SWKV->materialize(V));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CoreAPIsTest, FailFinalization) {
|
||||||
|
SymbolStringPool SP;
|
||||||
|
auto Foo = SP.intern("foo");
|
||||||
|
auto Bar = SP.intern("bar");
|
||||||
|
|
||||||
|
SymbolNameSet Names({Foo, Bar});
|
||||||
|
|
||||||
|
auto MU = llvm::make_unique<SimpleMaterializationUnit>(
|
||||||
|
[=]() {
|
||||||
|
return SymbolFlagsMap(
|
||||||
|
{{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
|
||||||
|
},
|
||||||
|
[&](VSO &V) -> Error {
|
||||||
|
constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
|
||||||
|
constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
|
||||||
|
|
||||||
|
auto FooSym = JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
|
||||||
|
auto BarSym = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
|
||||||
|
V.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
|
||||||
|
V.notifyFinalizationFailed(Names);
|
||||||
|
return Error::success();
|
||||||
|
},
|
||||||
|
[&](VSO &V, SymbolStringPtr Name) {
|
||||||
|
llvm_unreachable("Unexpected call to discard");
|
||||||
|
});
|
||||||
|
|
||||||
|
VSO V;
|
||||||
|
|
||||||
|
cantFail(V.defineLazy(std::move(MU)));
|
||||||
|
|
||||||
|
auto OnResolution = [](Expected<SymbolMap> Result) {
|
||||||
|
cantFail(std::move(Result));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto OnReady = [&](Error Err) {
|
||||||
|
handleAllErrors(std::move(Err),
|
||||||
|
[&](FailedToFinalize &F) {
|
||||||
|
EXPECT_EQ(F.getSymbols(), Names)
|
||||||
|
<< "Expected to fail on symbols in Names";
|
||||||
|
},
|
||||||
|
[](ErrorInfoBase &EIB) {
|
||||||
|
std::string ErrMsg;
|
||||||
|
{
|
||||||
|
raw_string_ostream ErrOut(ErrMsg);
|
||||||
|
EIB.log(ErrOut);
|
||||||
|
}
|
||||||
|
ADD_FAILURE()
|
||||||
|
<< "Expected a FailedToFinalize error. Got:\n"
|
||||||
|
<< ErrMsg;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
auto Q =
|
||||||
|
std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
|
||||||
|
|
||||||
|
auto LR = V.lookup(std::move(Q), Names);
|
||||||
|
for (auto &SWKV : LR.MaterializationUnits)
|
||||||
|
cantFail(SWKV->materialize(V));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(CoreAPIsTest, TestLambdaSymbolResolver) {
|
TEST(CoreAPIsTest, TestLambdaSymbolResolver) {
|
||||||
JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
|
JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
|
||||||
JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported);
|
JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported);
|
||||||
|
Loading…
Reference in New Issue
Block a user