[PATCH] D58704: Initial (incomplete) implementation of JITLink - A replacement for RuntimeDyld.
Lang Hames via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 6 16:03:26 PST 2019
lhames marked 13 inline comments as done.
lhames added a comment.
Thanks Dave! I've got a patch that addresses your feedback that I will post from the bus in a minute.
================
Comment at: include/llvm/ExecutionEngine/JITLink/JITLink.h:223-224
+
+ edge_iterator edges_begin() { return Edges.begin(); }
+ edge_iterator edges_end() { return Edges.end(); }
+ iterator_range<edge_iterator> edges() {
----------------
dblaikie wrote:
> Might be able to get away without having specific begin/end accessors - everyone can use the range accessor instead?
>
> (similar feedback for other range accessors in this patch)
Yeah — I like that idea.
================
Comment at: include/llvm/ExecutionEngine/JITLink/JITLink.h:252-253
+ ~AtomGraph() {
+ for (auto *DA : DefinedAtoms)
+ DA->~DefinedAtom();
+ }
----------------
dblaikie wrote:
> Any chance this container could be one of unique_ptr? I guess DenseSet doesn't support that? Could it?
I had not thought of that. I can’t see any reason that would not work. I will try it out.
================
Comment at: include/llvm/ExecutionEngine/JITLink/JITLink.h:454
+ DefinedAtomSet DefinedAtoms;
+ Optional<AddressToAtomMap> AddrToAtomCache;
+};
----------------
dblaikie wrote:
> Should this be 'mutable' (since it's modified from a const member function like "getAddrToAtomMap() const")?
>
> Also, I'd tend to implement the non-const version of a function in terms of the const version, rather than the other way around. That way if the object is actually const, the code doesn't hit UB.
>
> (currently calling getAddrToAtomMap() on an actually const object would be UB)
Good call.
================
Comment at: lib/ExecutionEngine/JITLink/JITLink.cpp:57-59
+JITLinkMemoryManager::~JITLinkMemoryManager() {}
+
+JITLinkMemoryManager::Allocation::~Allocation() {}
----------------
dblaikie wrote:
> Could use
> = default?
> here. No big deal, but might give the frontend extra info about the triviality, etc.
It had never occurred to me to use =default in an out-of-line definition before. :P
Good call.
================
Comment at: lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp:230-234
+ auto *UnownedSelf = Self.release();
+ auto Phase2Continuation =
+ [UnownedSelf](
+ Expected<DenseMap<StringRef, JITEvaluatedSymbol>> LookupResult) {
+ std::unique_ptr<JITLinkerBase> Self(UnownedSelf);
----------------
dblaikie wrote:
> This leaks or double frees if this lambda is either not called, or called more than once.
>
> Perhaps it'd be worth using shared_ptr here for simplicity/robustness?
>
> (fixme would still apply and worth migrating to a unique_ptr captured by move at that point)
Yep. The problem is that once you convert to shared_ptr you cannot convert back. I think I opted to keep this as a raw pointer for ease of conversion, on the assumption that we're switching to c++14 *reasonably* soon.
================
Comment at: lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp:282-288
+ auto &LHSP = LHS->getSection();
+ auto &RHSP = RHS->getSection();
+ if (LHSP.getSectionOrdinal() < RHSP.getSectionOrdinal())
+ return true;
+ if (LHSP.getSectionOrdinal() > RHSP.getSectionOrdinal())
+ return false;
+ return LHS->getOrdinal() < RHS->getOrdinal();
----------------
dblaikie wrote:
> might be easier written as:
>
> return std::tie(LHSP.getSectionOrdinal(), LHS->getOrdinal()) < std::tie(RHSP.getSectionOrdinal(), RHS->getOrdinal());
That's a neat trick, but once formatted for 80 columns I am not sure it's any more readable.
================
Comment at: lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp:293-297
+ for (auto &KV : Layout) {
+ dbgs() << " Segment "
+ << static_cast<sys::Memory::ProtectionFlags>(KV.first) << ":\n";
+ for (auto *DA : KV.second)
+ dbgs() << " " << *DA << "\n";
----------------
dblaikie wrote:
> Indentation seems off here
Hrm. Clang format is doing awful things to this. Will hand-format.
================
Comment at: lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp:381-382
+
+ assert(!std::any_of(G->external_atoms_begin(), G->external_atoms_end(),
+ [](Atom *A) { return !A->isResolved(); }) &&
+ "All atoms should have been resolved by this point");
----------------
dblaikie wrote:
> Seem to be a few negatives in here, maybe:
>
> assert(std::all_of(... isResolved()); ...
>
> would be a more direct expression/match the phrasing of the assertion text below?
>
> Oh, and there's probably llvm::all_of that takes a range directly rather than needing to decompose into begin/end
There is! Thanks. :)
================
Comment at: lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp:408
+ continue;
+ auto &Target = reinterpret_cast<DefinedAtom &>(R.getTarget());
+ if (Target.isDefined() && !LiveAtoms.count(&Target)) {
----------------
dblaikie wrote:
> reinterpret_casts (especially of references, I think - I'd worry about potentially turning a non-reference/pointer/thing into a reference with such a cast) make me a bit twitchy - any chance of wrapping the reinterpret_casting up in something more type safe at both ends?
Huh. This was a think-o: it should have been a static_cast. Fixed in the latest iteration of the dead-stripping code.
================
Comment at: lib/ExecutionEngine/JITLink/JITLinkMachO_x86_64.cpp:232-238
+ else if (&AtomToFix == &*ToAtom)
+ return PairRelocInfo {
+ SubRI.r_length == 3 ? NegDelta64 : NegDelta32,
+ &*FromAtom,
+ FixupValue - (FixupAddress - ToAtom->getAddress()) };
+ else
+ return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
----------------
dblaikie wrote:
> elses-after-returns can be removed, I think
Indeed.
================
Comment at: lib/ExecutionEngine/JITLink/MachOAtomGraphBuilder.cpp:121-127
+ continue;
+ } else if (Flags & object::SymbolRef::SF_Absolute) {
+ LLVM_DEBUG(dbgs() << "Adding absolute \"" << *Name << "\" addr: "
+ << format("0x%016" PRIx64, *Addr) << "\n");
+ G->addAbsoluteAtom(*Name, *Addr);
+ continue;
+ } else {
----------------
dblaikie wrote:
> else-after-continues can be removed
Updated.
================
Comment at: unittests/ExecutionEngine/JITLink/JITLinkTestCommon.cpp:44-45
+JITLinkTestCommon::TestResources::getExternalsResolver() {
+ return [&](const DenseSet<StringRef> &Symbols,
+ jitlink::JITLinkAsyncLookupContinuation LookupContinuation) {
+ jitlink::AsyncLookupResult LookupResult;
----------------
dblaikie wrote:
> Using '&' capture for a lambda that escapes the current scope makes me a bit twitchy - would it be worth enumerating the things being captured here? I guess they're all members, so it's capturing 'this' by value, but still - I'd be more comfortable with that spelled out.
Yep -- 'this' would be better here. Fixed.
================
Comment at: unittests/ExecutionEngine/JITLink/JITLinkTestCommon.h:97-99
+ return support::endian::read<T, 1>(DA->getContent().data() + Offset,
+ G.getEndianness());
+ else
----------------
dblaikie wrote:
> else-after-return
>
> Ah, I see, scoping because of "DA" - I'd probably move DA out of the condition and early return for the error case instead:
>
> auto DA = G.find...;
> if (!DA)
> return DA.takeError();
> return support::endian::read<>(...);
>
> Reduces indentation of the main path
Interesting. I tend to prefer the if/else framing because it feels like the "success/failure" state on each path is more obvious. I only switch to early outs for Expected values if I think the indentation will make things really unreadable.
Repository:
rL LLVM
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D58704/new/
https://reviews.llvm.org/D58704
More information about the llvm-commits
mailing list