
Use SymbolStringPtr for Symbol names in LinkGraph. This reduces string interning on the boundary between JITLink and ORC, and allows pointer comparisons (rather than string comparisons) between Symbol names. This should improve the performance and readability of code that bridges between JITLink and ORC (e.g. ObjectLinkingLayer and ObjectLinkingLayer::Plugins). To enable use of SymbolStringPtr a std::shared_ptr<SymbolStringPool> is added to LinkGraph and threaded through to its construction sites in LLVM and Bolt. All LinkGraphs that are to have symbol names compared by pointer equality must point to the same SymbolStringPool instance, which in ORC sessions should be the pool attached to the ExecutionSession. --------- Co-authored-by: Lang Hames <lhames@gmail.com>
127 lines
4.3 KiB
C++
127 lines
4.3 KiB
C++
//===--------------- PerGraphGOTAndPLTStubBuilder.h -------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Construct GOT and PLT entries for each graph.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H
|
|
#define LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H
|
|
|
|
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#define DEBUG_TYPE "jitlink"
|
|
|
|
namespace llvm {
|
|
namespace jitlink {
|
|
|
|
/// Per-object GOT and PLT Stub builder.
|
|
///
|
|
/// Constructs GOT entries and PLT stubs in every graph for referenced symbols.
|
|
/// Building these blocks in every graph is likely to lead to duplicate entries
|
|
/// in the JITLinkDylib, but allows graphs to be trivially removed independently
|
|
/// without affecting other graphs (since those other graphs will have their own
|
|
/// copies of any required entries).
|
|
template <typename BuilderImplT>
|
|
class PerGraphGOTAndPLTStubsBuilder {
|
|
public:
|
|
PerGraphGOTAndPLTStubsBuilder(LinkGraph &G) : G(G) {}
|
|
|
|
static Error asPass(LinkGraph &G) { return BuilderImplT(G).run(); }
|
|
|
|
Error run() {
|
|
LLVM_DEBUG(dbgs() << "Running Per-Graph GOT and Stubs builder:\n");
|
|
|
|
// We're going to be adding new blocks, but we don't want to iterate over
|
|
// the new ones, so build a worklist.
|
|
std::vector<Block *> Worklist(G.blocks().begin(), G.blocks().end());
|
|
|
|
for (auto *B : Worklist)
|
|
for (auto &E : B->edges()) {
|
|
if (impl().isGOTEdgeToFix(E)) {
|
|
LLVM_DEBUG({
|
|
dbgs() << " Fixing " << G.getEdgeKindName(E.getKind())
|
|
<< " edge at " << B->getFixupAddress(E) << " ("
|
|
<< B->getAddress() << " + "
|
|
<< formatv("{0:x}", E.getOffset()) << ")\n";
|
|
});
|
|
impl().fixGOTEdge(E, getGOTEntry(E.getTarget()));
|
|
} else if (impl().isExternalBranchEdge(E)) {
|
|
LLVM_DEBUG({
|
|
dbgs() << " Fixing " << G.getEdgeKindName(E.getKind())
|
|
<< " edge at " << B->getFixupAddress(E) << " ("
|
|
<< B->getAddress() << " + "
|
|
<< formatv("{0:x}", E.getOffset()) << ")\n";
|
|
});
|
|
impl().fixPLTEdge(E, getPLTStub(E.getTarget()));
|
|
}
|
|
}
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
protected:
|
|
Symbol &getGOTEntry(Symbol &Target) {
|
|
assert(Target.hasName() && "GOT edge cannot point to anonymous target");
|
|
|
|
auto GOTEntryI = GOTEntries.find(Target.getName());
|
|
|
|
// Build the entry if it doesn't exist.
|
|
if (GOTEntryI == GOTEntries.end()) {
|
|
auto &GOTEntry = impl().createGOTEntry(Target);
|
|
LLVM_DEBUG({
|
|
dbgs() << " Created GOT entry for " << Target.getName() << ": "
|
|
<< GOTEntry << "\n";
|
|
});
|
|
GOTEntryI =
|
|
GOTEntries.insert(std::make_pair(Target.getName(), &GOTEntry)).first;
|
|
}
|
|
|
|
assert(GOTEntryI != GOTEntries.end() && "Could not get GOT entry symbol");
|
|
LLVM_DEBUG(
|
|
{ dbgs() << " Using GOT entry " << *GOTEntryI->second << "\n"; });
|
|
return *GOTEntryI->second;
|
|
}
|
|
|
|
Symbol &getPLTStub(Symbol &Target) {
|
|
assert(Target.hasName() &&
|
|
"External branch edge can not point to an anonymous target");
|
|
auto StubI = PLTStubs.find(Target.getName());
|
|
|
|
if (StubI == PLTStubs.end()) {
|
|
auto &StubSymbol = impl().createPLTStub(Target);
|
|
LLVM_DEBUG({
|
|
dbgs() << " Created PLT stub for " << Target.getName() << ": "
|
|
<< StubSymbol << "\n";
|
|
});
|
|
StubI =
|
|
PLTStubs.insert(std::make_pair(Target.getName(), &StubSymbol)).first;
|
|
}
|
|
|
|
assert(StubI != PLTStubs.end() && "Count not get stub symbol");
|
|
LLVM_DEBUG({ dbgs() << " Using PLT stub " << *StubI->second << "\n"; });
|
|
return *StubI->second;
|
|
}
|
|
|
|
LinkGraph &G;
|
|
|
|
private:
|
|
BuilderImplT &impl() { return static_cast<BuilderImplT &>(*this); }
|
|
|
|
DenseMap<orc::SymbolStringPtr, Symbol *> GOTEntries;
|
|
DenseMap<orc::SymbolStringPtr, Symbol *> PLTStubs;
|
|
};
|
|
|
|
} // end namespace jitlink
|
|
} // end namespace llvm
|
|
|
|
#undef DEBUG_TYPE
|
|
|
|
#endif // LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H
|