From 572a87e2aa81e1dfe677645d0d3591fc4ee8239a Mon Sep 17 00:00:00 2001 From: Pete Cooper Date: Tue, 22 Mar 2016 03:44:32 +0000 Subject: [PATCH] Use owning pointers instead of raw pointers for Atom's to fix leaks. Currently each File contains an BumpPtrAllocator in which Atom's are allocated. Some Atom's contain data structures like std::vector which leak as we don't run ~Atom when they are BumpPtrAllocate'd. Now each File actually owns its Atom's using an OwningAtomPtr. This is analygous to std::unique_ptr and may be replaced by it if possible. An Atom can therefore only be owned by a single File, so the Resolver now moves them from one File to another. The MachOLinkingContext owns the File's and so clears all the Atom's in ~MachOLinkingContext, then delete's all the File's. This makes sure all Atom's have been destructed before any of the BumpPtrAllocator's in which they run have gone away. Should hopefully fix the remaining leaks. Will keep an eye on the bots to make sure. llvm-svn: 264022 --- lld/include/lld/Core/Atom.h | 47 +++++++ lld/include/lld/Core/DefinedAtom.h | 2 + lld/include/lld/Core/File.h | 99 +++++++++++--- lld/include/lld/Core/Resolver.h | 13 +- lld/include/lld/Core/SharedLibraryAtom.h | 2 + lld/include/lld/Core/SharedLibraryFile.h | 17 ++- lld/include/lld/Core/Simple.h | 59 +++++++-- lld/include/lld/Core/UndefinedAtom.h | 2 + lld/lib/Core/File.cpp | 2 +- lld/lib/Core/Resolver.cpp | 141 ++++++++++---------- lld/lib/Driver/DarwinLdDriver.cpp | 9 +- lld/lib/ReaderWriter/FileArchive.cpp | 15 ++- lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp | 4 + lld/lib/ReaderWriter/MachO/Atoms.h | 6 + lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp | 2 + lld/lib/ReaderWriter/MachO/ExecutableAtoms.h | 15 ++- lld/lib/ReaderWriter/MachO/File.h | 26 ++-- lld/lib/ReaderWriter/MachO/FlatNamespaceFile.h | 27 ++-- lld/lib/ReaderWriter/MachO/GOTPass.cpp | 2 + lld/lib/ReaderWriter/MachO/LayoutPass.cpp | 28 ++-- lld/lib/ReaderWriter/MachO/LayoutPass.h | 14 +- lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp | 14 +- lld/lib/ReaderWriter/MachO/ObjCPass.cpp | 2 + lld/lib/ReaderWriter/MachO/SectCreateFile.h | 17 ++- lld/lib/ReaderWriter/MachO/StubsPass.cpp | 10 ++ lld/lib/ReaderWriter/MachO/TLVPass.cpp | 2 + lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp | 142 ++++++++++++++++----- 27 files changed, 516 insertions(+), 203 deletions(-) diff --git a/lld/include/lld/Core/Atom.h b/lld/include/lld/Core/Atom.h index 27fdde0..6a43089 100644 --- a/lld/include/lld/Core/Atom.h +++ b/lld/include/lld/Core/Atom.h @@ -16,6 +16,9 @@ namespace lld { class File; +template +class OwningAtomPtr; + /// /// The linker has a Graph Theory model of linking. An object file is seen /// as a set of Atoms with References to other Atoms. Each Atom is a node @@ -24,6 +27,7 @@ class File; /// undefined symbol (extern declaration). /// class Atom { + template friend class OwningAtomPtr; public: /// Whether this atom is defined or a proxy for an undefined symbol enum Definition { @@ -71,6 +75,49 @@ private: Definition _definition; }; +/// Class which owns an atom pointer and runs the atom destructor when the +/// owning pointer goes out of scope. +template +class OwningAtomPtr { +private: + OwningAtomPtr(const OwningAtomPtr &) = delete; + void operator=(const OwningAtomPtr&) = delete; +public: + OwningAtomPtr() : atom(nullptr) { } + OwningAtomPtr(T *atom) : atom(atom) { } + + ~OwningAtomPtr() { + if (atom) + atom->~Atom(); + } + + OwningAtomPtr(OwningAtomPtr &&ptr) : atom(ptr.atom) { + ptr.atom = nullptr; + } + + void operator=(OwningAtomPtr&& ptr) { + atom = ptr.atom; + ptr.atom = nullptr; + } + + T *const &get() const { + return atom; + } + + T *&get() { + return atom; + } + + T *release() { + auto *v = atom; + atom = nullptr; + return v; + } + +private: + T *atom; +}; + } // namespace lld #endif // LLD_CORE_ATOM_H diff --git a/lld/include/lld/Core/DefinedAtom.h b/lld/include/lld/Core/DefinedAtom.h index 4a4d1c7..e3193f8 100644 --- a/lld/include/lld/Core/DefinedAtom.h +++ b/lld/include/lld/Core/DefinedAtom.h @@ -363,6 +363,8 @@ protected: // constructor. DefinedAtom() : Atom(definitionRegular) { } + ~DefinedAtom() override = default; + /// \brief Returns a pointer to the Reference object that the abstract /// iterator "points" to. virtual const Reference *derefIterator(const void *iter) const = 0; diff --git a/lld/include/lld/Core/File.h b/lld/include/lld/Core/File.h index f6e7d7e..eb41fcc 100644 --- a/lld/include/lld/Core/File.h +++ b/lld/include/lld/Core/File.h @@ -15,6 +15,7 @@ #include "lld/Core/SharedLibraryAtom.h" #include "lld/Core/UndefinedAtom.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" #include @@ -39,6 +40,10 @@ class LinkingContext; /// The Atom objects in a File are owned by the File object. The Atom objects /// are destroyed when the File object is destroyed. class File { +protected: + /// The type of atom mutable container. + template using AtomVector = std::vector>; + public: virtual ~File(); @@ -104,18 +109,67 @@ public: return _allocator; } - /// The type of atom mutable container. - template using AtomVector = std::vector; - - /// The range type for the atoms. It's backed by a std::vector, but hides - /// its member functions so that you can only call begin or end. + /// The range type for the atoms. template class AtomRange { public: - AtomRange(AtomVector v) : _v(v) {} - typename AtomVector::const_iterator begin() const { return _v.begin(); } - typename AtomVector::const_iterator end() const { return _v.end(); } - typename AtomVector::iterator begin() { return _v.begin(); } - typename AtomVector::iterator end() { return _v.end(); } + AtomRange(AtomVector &v) : _v(v) {} + AtomRange(const AtomVector &v) : _v(const_cast &>(v)) {} + + typedef std::pointer_to_unary_function&, + const T*> ConstDerefFn; + + typedef std::pointer_to_unary_function&, T*> DerefFn; + + typedef llvm::mapped_iterator::const_iterator, + ConstDerefFn> ConstItTy; + typedef llvm::mapped_iterator::iterator, + DerefFn> ItTy; + + static const T* DerefConst(const OwningAtomPtr &p) { + return p.get(); + } + + static T* Deref(OwningAtomPtr &p) { + return p.get(); + } + + ConstItTy begin() const { + return ConstItTy(_v.begin(), ConstDerefFn(DerefConst)); + } + ConstItTy end() const { + return ConstItTy(_v.end(), ConstDerefFn(DerefConst)); + } + + ItTy begin() { + return ItTy(_v.begin(), DerefFn(Deref)); + } + ItTy end() { + return ItTy(_v.end(), DerefFn(Deref)); + } + + llvm::iterator_range::iterator> owning_ptrs() { + return llvm::make_range(_v.begin(), _v.end()); + } + + llvm::iterator_range::iterator> owning_ptrs() const { + return llvm::make_range(_v.begin(), _v.end()); + } + + bool empty() const { + return _v.empty(); + } + + size_t size() const { + return _v.size(); + } + + const OwningAtomPtr &operator[](size_t idx) const { + return _v[idx]; + } + + OwningAtomPtr &operator[](size_t idx) { + return _v[idx]; + } private: AtomVector &_v; @@ -123,19 +177,25 @@ public: /// \brief Must be implemented to return the AtomVector object for /// all DefinedAtoms in this File. - virtual const AtomVector &defined() const = 0; + virtual const AtomRange defined() const = 0; /// \brief Must be implemented to return the AtomVector object for /// all UndefinedAtomw in this File. - virtual const AtomVector &undefined() const = 0; + virtual const AtomRange undefined() const = 0; /// \brief Must be implemented to return the AtomVector object for /// all SharedLibraryAtoms in this File. - virtual const AtomVector &sharedLibrary() const = 0; + virtual const AtomRange sharedLibrary() const = 0; /// \brief Must be implemented to return the AtomVector object for /// all AbsoluteAtoms in this File. - virtual const AtomVector &absolute() const = 0; + virtual const AtomRange absolute() const = 0; + + /// Drop all of the atoms owned by this file. This will result in all of + /// the atoms running their destructors. + /// This is required because atoms may be allocated on a BumpPtrAllocator + /// of a different file. We need to destruct all atoms before any files. + virtual void clearAtoms() = 0; /// \brief If a file is parsed using a different method than doParse(), /// one must use this method to set the last error status, so that @@ -194,19 +254,22 @@ public: std::error_code doParse() override { return _ec; } - const AtomVector &defined() const override { + const AtomRange defined() const override { llvm_unreachable("internal error"); } - const AtomVector &undefined() const override { + const AtomRange undefined() const override { llvm_unreachable("internal error"); } - const AtomVector &sharedLibrary() const override { + const AtomRange sharedLibrary() const override { llvm_unreachable("internal error"); } - const AtomVector &absolute() const override { + const AtomRange absolute() const override { llvm_unreachable("internal error"); } + void clearAtoms() override { + } + private: std::error_code _ec; }; diff --git a/lld/include/lld/Core/Resolver.h b/lld/include/lld/Core/Resolver.h index d7b42b6..efaf19f 100644 --- a/lld/include/lld/Core/Resolver.h +++ b/lld/include/lld/Core/Resolver.h @@ -35,10 +35,10 @@ public: Resolver(LinkingContext &ctx) : _ctx(ctx), _result(new MergedFile()) {} // InputFiles::Handler methods - void doDefinedAtom(const DefinedAtom&); - bool doUndefinedAtom(const UndefinedAtom &); - void doSharedLibraryAtom(const SharedLibraryAtom &); - void doAbsoluteAtom(const AbsoluteAtom &); + void doDefinedAtom(OwningAtomPtr atom); + bool doUndefinedAtom(OwningAtomPtr atom); + void doSharedLibraryAtom(OwningAtomPtr atom); + void doAbsoluteAtom(OwningAtomPtr atom); // Handle files, this adds atoms from the current file thats // being processed by the resolver @@ -71,17 +71,16 @@ private: UndefCallback callback); void markLive(const Atom *atom); - void addAtoms(const std::vector&); class MergedFile : public SimpleFile { public: MergedFile() : SimpleFile("", kindResolverMergedObject) {} - void addAtoms(std::vector& atoms); + void addAtoms(llvm::MutableArrayRef> atoms); }; LinkingContext &_ctx; SymbolTable _symbolTable; - std::vector _atoms; + std::vector> _atoms; std::set _deadStripRoots; llvm::DenseSet _liveAtoms; llvm::DenseSet _deadAtoms; diff --git a/lld/include/lld/Core/SharedLibraryAtom.h b/lld/include/lld/Core/SharedLibraryAtom.h index 0f4648f..7fec7a3 100644 --- a/lld/include/lld/Core/SharedLibraryAtom.h +++ b/lld/include/lld/Core/SharedLibraryAtom.h @@ -44,6 +44,8 @@ public: protected: SharedLibraryAtom() : Atom(definitionSharedLibrary) {} + + ~SharedLibraryAtom() override = default; }; } // namespace lld diff --git a/lld/include/lld/Core/SharedLibraryFile.h b/lld/include/lld/Core/SharedLibraryFile.h index 2e4771f..5fa0e95 100644 --- a/lld/include/lld/Core/SharedLibraryFile.h +++ b/lld/include/lld/Core/SharedLibraryFile.h @@ -27,28 +27,35 @@ public: /// Check if the shared library exports a symbol with the specified name. /// If so, return a SharedLibraryAtom which represents that exported /// symbol. Otherwise return nullptr. - virtual const SharedLibraryAtom *exports(StringRef name, + virtual OwningAtomPtr exports(StringRef name, bool dataSymbolOnly) const = 0; // Returns the install name. virtual StringRef getDSOName() const = 0; - const AtomVector &defined() const override { + const AtomRange defined() const override { return _definedAtoms; } - const AtomVector &undefined() const override { + const AtomRange undefined() const override { return _undefinedAtoms; } - const AtomVector &sharedLibrary() const override { + const AtomRange sharedLibrary() const override { return _sharedLibraryAtoms; } - const AtomVector &absolute() const override { + const AtomRange absolute() const override { return _absoluteAtoms; } + void clearAtoms() override { + _definedAtoms.clear(); + _undefinedAtoms.clear(); + _sharedLibraryAtoms.clear(); + _absoluteAtoms.clear(); + } + protected: /// only subclasses of SharedLibraryFile can be instantiated explicit SharedLibraryFile(StringRef path) : File(path, kindSharedLibrary) {} diff --git a/lld/include/lld/Core/Simple.h b/lld/include/lld/Core/Simple.h index a06eecd..f010387 100644 --- a/lld/include/lld/Core/Simple.h +++ b/lld/include/lld/Core/Simple.h @@ -31,20 +31,35 @@ public: SimpleFile(StringRef path, File::Kind kind) : File(path, kind) {} - void addAtom(const DefinedAtom &a) { _defined.push_back(&a); } - void addAtom(const UndefinedAtom &a) { _undefined.push_back(&a); } - void addAtom(const SharedLibraryAtom &a) { _shared.push_back(&a); } - void addAtom(const AbsoluteAtom &a) { _absolute.push_back(&a); } + ~SimpleFile() override { + _defined.clear(); + _undefined.clear(); + _shared.clear(); + _absolute.clear(); + } + + void addAtom(DefinedAtom &a) { + _defined.push_back(OwningAtomPtr(&a)); + } + void addAtom(UndefinedAtom &a) { + _undefined.push_back(OwningAtomPtr(&a)); + } + void addAtom(SharedLibraryAtom &a) { + _shared.push_back(OwningAtomPtr(&a)); + } + void addAtom(AbsoluteAtom &a) { + _absolute.push_back(OwningAtomPtr(&a)); + } void addAtom(const Atom &atom) { if (auto *p = dyn_cast(&atom)) { - _defined.push_back(p); + addAtom(const_cast(*p)); } else if (auto *p = dyn_cast(&atom)) { - _undefined.push_back(p); + addAtom(const_cast(*p)); } else if (auto *p = dyn_cast(&atom)) { - _shared.push_back(p); + addAtom(const_cast(*p)); } else if (auto *p = dyn_cast(&atom)) { - _absolute.push_back(p); + addAtom(const_cast(*p)); } else { llvm_unreachable("atom has unknown definition kind"); } @@ -52,25 +67,35 @@ public: void removeDefinedAtomsIf(std::function pred) { auto &atoms = _defined; - auto newEnd = std::remove_if(atoms.begin(), atoms.end(), pred); + auto newEnd = std::remove_if(atoms.begin(), atoms.end(), + [&pred](OwningAtomPtr &p) { + return pred(p.get()); + }); atoms.erase(newEnd, atoms.end()); } - const AtomVector &defined() const override { return _defined; } + const AtomRange defined() const override { return _defined; } - const AtomVector &undefined() const override { + const AtomRange undefined() const override { return _undefined; } - const AtomVector &sharedLibrary() const override { + const AtomRange sharedLibrary() const override { return _shared; } - const AtomVector &absolute() const override { + const AtomRange absolute() const override { return _absolute; } - typedef llvm::MutableArrayRef DefinedAtomRange; + void clearAtoms() override { + _defined.clear(); + _undefined.clear(); + _shared.clear(); + _absolute.clear(); + } + + typedef AtomRange DefinedAtomRange; DefinedAtomRange definedAtoms() { return _defined; } private: @@ -169,6 +194,10 @@ public: _references.setAllocator(&f.allocator()); } + ~SimpleDefinedAtom() { + _references.clearAndLeakNodesUnsafely(); + } + const File &file() const override { return _file; } StringRef name() const override { return StringRef(); } @@ -265,6 +294,8 @@ public: assert(!name.empty() && "UndefinedAtoms must have a name"); } + ~SimpleUndefinedAtom() override = default; + /// file - returns the File that produced/owns this Atom const File &file() const override { return _file; } diff --git a/lld/include/lld/Core/UndefinedAtom.h b/lld/include/lld/Core/UndefinedAtom.h index 3e58f80..f45d6ec 100644 --- a/lld/include/lld/Core/UndefinedAtom.h +++ b/lld/include/lld/Core/UndefinedAtom.h @@ -59,6 +59,8 @@ public: protected: UndefinedAtom() : Atom(definitionUndefined) {} + + ~UndefinedAtom() override = default; }; } // namespace lld diff --git a/lld/lib/Core/File.cpp b/lld/lib/Core/File.cpp index ac95f10..b84132b 100644 --- a/lld/lib/Core/File.cpp +++ b/lld/lib/Core/File.cpp @@ -13,7 +13,7 @@ namespace lld { -File::~File() {} +File::~File() { } File::AtomVector File::_noDefinedAtoms; File::AtomVector File::_noUndefinedAtoms; diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp index b896435..d94699a 100644 --- a/lld/lib/Core/Resolver.cpp +++ b/lld/lib/Core/Resolver.cpp @@ -33,16 +33,16 @@ ErrorOr Resolver::handleFile(File &file) { if (auto ec = _ctx.handleLoadedFile(file)) return ec; bool undefAdded = false; - for (const DefinedAtom *atom : file.defined()) - doDefinedAtom(*atom); - for (const UndefinedAtom *atom : file.undefined()) { - if (doUndefinedAtom(*atom)) + for (auto &atom : file.defined().owning_ptrs()) + doDefinedAtom(std::move(atom)); + for (auto &atom : file.undefined().owning_ptrs()) { + if (doUndefinedAtom(std::move(atom))) undefAdded = true; } - for (const SharedLibraryAtom *atom : file.sharedLibrary()) - doSharedLibraryAtom(*atom); - for (const AbsoluteAtom *atom : file.absolute()) - doAbsoluteAtom(*atom); + for (auto &atom : file.sharedLibrary().owning_ptrs()) + doSharedLibraryAtom(std::move(atom)); + for (auto &atom : file.absolute().owning_ptrs()) + doAbsoluteAtom(std::move(atom)); return undefAdded; } @@ -113,9 +113,9 @@ std::error_code Resolver::handleSharedLibrary(File &file) { undefAddedOrError = forEachUndefines(file, searchForOverrides, [&](StringRef undefName, bool dataSymbolOnly)->ErrorOr { - if (const SharedLibraryAtom *atom = - sharedLibrary->exports(undefName, dataSymbolOnly)) - doSharedLibraryAtom(*atom); + auto atom = sharedLibrary->exports(undefName, dataSymbolOnly); + if (atom.get()) + doSharedLibraryAtom(std::move(atom)); return false; }); @@ -124,84 +124,79 @@ std::error_code Resolver::handleSharedLibrary(File &file) { return std::error_code(); } -bool Resolver::doUndefinedAtom(const UndefinedAtom &atom) { +bool Resolver::doUndefinedAtom(OwningAtomPtr atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " UndefinedAtom: " - << llvm::format("0x%09lX", &atom) - << ", name=" << atom.name() << "\n"); - - // add to list of known atoms - _atoms.push_back(&atom); + << llvm::format("0x%09lX", atom.get()) + << ", name=" << atom.get()->name() << "\n"); // tell symbol table - bool newUndefAdded = _symbolTable.add(atom); + bool newUndefAdded = _symbolTable.add(*atom.get()); if (newUndefAdded) - _undefines.push_back(atom.name()); + _undefines.push_back(atom.get()->name()); + + // add to list of known atoms + _atoms.push_back(OwningAtomPtr(atom.release())); return newUndefAdded; } // Called on each atom when a file is added. Returns true if a given // atom is added to the symbol table. -void Resolver::doDefinedAtom(const DefinedAtom &atom) { +void Resolver::doDefinedAtom(OwningAtomPtr atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " DefinedAtom: " - << llvm::format("0x%09lX", &atom) + << llvm::format("0x%09lX", atom.get()) << ", file=#" - << atom.file().ordinal() + << atom.get()->file().ordinal() << ", atom=#" - << atom.ordinal() + << atom.get()->ordinal() << ", name=" - << atom.name() + << atom.get()->name() << ", type=" - << atom.contentType() + << atom.get()->contentType() << "\n"); - // add to list of known atoms - _atoms.push_back(&atom); - _symbolTable.add(atom); - // An atom that should never be dead-stripped is a dead-strip root. - if (_ctx.deadStrip() && atom.deadStrip() == DefinedAtom::deadStripNever) { - _deadStripRoots.insert(&atom); + if (_ctx.deadStrip() && + atom.get()->deadStrip() == DefinedAtom::deadStripNever) { + _deadStripRoots.insert(atom.get()); } + + // add to list of known atoms + _symbolTable.add(*atom.get()); + _atoms.push_back(OwningAtomPtr(atom.release())); } -void Resolver::doSharedLibraryAtom(const SharedLibraryAtom &atom) { +void Resolver::doSharedLibraryAtom(OwningAtomPtr atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " SharedLibraryAtom: " - << llvm::format("0x%09lX", &atom) + << llvm::format("0x%09lX", atom.get()) << ", name=" - << atom.name() + << atom.get()->name() << "\n"); - // add to list of known atoms - _atoms.push_back(&atom); - // tell symbol table - _symbolTable.add(atom); + _symbolTable.add(*atom.get()); + + // add to list of known atoms + _atoms.push_back(OwningAtomPtr(atom.release())); } -void Resolver::doAbsoluteAtom(const AbsoluteAtom &atom) { +void Resolver::doAbsoluteAtom(OwningAtomPtr atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " AbsoluteAtom: " - << llvm::format("0x%09lX", &atom) + << llvm::format("0x%09lX", atom.get()) << ", name=" - << atom.name() + << atom.get()->name() << "\n"); - // add to list of known atoms - _atoms.push_back(&atom); - // tell symbol table - if (atom.scope() != Atom::scopeTranslationUnit) - _symbolTable.add(atom); -} + if (atom.get()->scope() != Atom::scopeTranslationUnit) + _symbolTable.add(*atom.get()); -// utility to add a vector of atoms -void Resolver::addAtoms(const std::vector &newAtoms) { - for (const DefinedAtom *newAtom : newAtoms) - doDefinedAtom(*newAtom); + // add to list of known atoms + _atoms.push_back(OwningAtomPtr(atom.release())); } // Returns true if at least one of N previous files has created an @@ -316,8 +311,8 @@ void Resolver::updateReferences() { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Updating references:\n"); ScopedTask task(getDefaultDomain(), "updateReferences"); - for (const Atom *atom : _atoms) { - if (const DefinedAtom *defAtom = dyn_cast(atom)) { + for (const OwningAtomPtr &atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast(atom.get())) { for (const Reference *ref : *defAtom) { // A reference of type kindAssociate should't be updated. // Instead, an atom having such reference will be removed @@ -325,7 +320,7 @@ void Resolver::updateReferences() { // go away as a group. if (ref->kindNamespace() == lld::Reference::KindNamespace::all && ref->kindValue() == lld::Reference::kindAssociate) { - if (_symbolTable.isCoalescedAway(atom)) + if (_symbolTable.isCoalescedAway(atom.get())) _deadAtoms.insert(ref->target()); continue; } @@ -373,19 +368,19 @@ void Resolver::deadStripOptimize() { // Make a reverse map of such references before traversing the graph. // While traversing the list of atoms, mark AbsoluteAtoms as live // in order to avoid reclaim. - for (const Atom *atom : _atoms) { - if (const DefinedAtom *defAtom = dyn_cast(atom)) + for (const OwningAtomPtr &atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast(atom.get())) for (const Reference *ref : *defAtom) if (isBackref(ref)) - _reverseRef.insert(std::make_pair(ref->target(), atom)); - if (const AbsoluteAtom *absAtom = dyn_cast(atom)) + _reverseRef.insert(std::make_pair(ref->target(), atom.get())); + if (const AbsoluteAtom *absAtom = dyn_cast(atom.get())) markLive(absAtom); } // By default, shared libraries are built with all globals as dead strip roots if (_ctx.globalsAreDeadStripRoots()) - for (const Atom *atom : _atoms) - if (const DefinedAtom *defAtom = dyn_cast(atom)) + for (const OwningAtomPtr &atom : _atoms) + if (const DefinedAtom *defAtom = dyn_cast(atom.get())) if (defAtom->scope() == DefinedAtom::scopeGlobal) _deadStripRoots.insert(defAtom); @@ -401,8 +396,9 @@ void Resolver::deadStripOptimize() { markLive(dsrAtom); // now remove all non-live atoms from _atoms - _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) { - return _liveAtoms.count(a) == 0; + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), + [&](OwningAtomPtr &a) { + return _liveAtoms.count(a.get()) == 0; }), _atoms.end()); } @@ -461,8 +457,10 @@ void Resolver::removeCoalescedAwayAtoms() { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Removing coalesced away atoms:\n"); ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms"); - _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) { - return _symbolTable.isCoalescedAway(a) || _deadAtoms.count(a); + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), + [&](OwningAtomPtr &a) { + return _symbolTable.isCoalescedAway(a.get()) || + _deadAtoms.count(a.get()); }), _atoms.end()); } @@ -488,15 +486,16 @@ bool Resolver::resolve() { return true; } -void Resolver::MergedFile::addAtoms(std::vector &all) { +void Resolver::MergedFile::addAtoms( + llvm::MutableArrayRef> all) { ScopedTask task(getDefaultDomain(), "addAtoms"); DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n"); - for (const Atom *atom : all) { + for (OwningAtomPtr &atom : all) { #ifndef NDEBUG - if (auto *definedAtom = dyn_cast(atom)) { + if (auto *definedAtom = dyn_cast(atom.get())) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << llvm::format(" 0x%09lX", atom) + << llvm::format(" 0x%09lX", definedAtom) << ", file=#" << definedAtom->file().ordinal() << ", atom=#" @@ -508,13 +507,13 @@ void Resolver::MergedFile::addAtoms(std::vector &all) { << "\n"); } else { DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << llvm::format(" 0x%09lX", atom) + << llvm::format(" 0x%09lX", atom.get()) << ", name=" - << atom->name() + << atom.get()->name() << "\n"); } #endif - addAtom(*atom); + addAtom(*atom.release()); } } diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp index 4a859f3..914c236 100644 --- a/lld/lib/Driver/DarwinLdDriver.cpp +++ b/lld/lib/Driver/DarwinLdDriver.cpp @@ -1169,7 +1169,14 @@ bool link(llvm::ArrayRef args, raw_ostream &diagnostics) { Resolver resolver(ctx); if (!resolver.resolve()) return false; - std::unique_ptr merged = resolver.resultFile(); + SimpleFile *merged = nullptr; + { + std::unique_ptr mergedFile = resolver.resultFile(); + merged = mergedFile.get(); + auto &members = ctx.getNodes(); + members.insert(members.begin(), + llvm::make_unique(std::move(mergedFile))); + } resolveTask.end(); // Run passes on linked atoms. diff --git a/lld/lib/ReaderWriter/FileArchive.cpp b/lld/lib/ReaderWriter/FileArchive.cpp index a47024c..73b8612 100644 --- a/lld/lib/ReaderWriter/FileArchive.cpp +++ b/lld/lib/ReaderWriter/FileArchive.cpp @@ -88,22 +88,29 @@ public: return std::error_code(); } - const AtomVector &defined() const override { + const AtomRange defined() const override { return _noDefinedAtoms; } - const AtomVector &undefined() const override { + const AtomRange undefined() const override { return _noUndefinedAtoms; } - const AtomVector &sharedLibrary() const override { + const AtomRange sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector &absolute() const override { + const AtomRange absolute() const override { return _noAbsoluteAtoms; } + void clearAtoms() override { + _noDefinedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); + } + protected: std::error_code doParse() override { // Make Archive object which will be owned by FileArchive object. diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp index cefa745..7eda42e 100644 --- a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp @@ -1429,6 +1429,8 @@ public: _name = tmp.copy(file.allocator()); } + ~Thumb2ToArmShimAtom() override = default; + StringRef name() const override { return _name; } @@ -1472,6 +1474,8 @@ public: _name = tmp.copy(file.allocator()); } + ~ArmToThumbShimAtom() override = default; + StringRef name() const override { return _name; } diff --git a/lld/lib/ReaderWriter/MachO/Atoms.h b/lld/lib/ReaderWriter/MachO/Atoms.h index f50a6cf..c3117d4 100644 --- a/lld/lib/ReaderWriter/MachO/Atoms.h +++ b/lld/lib/ReaderWriter/MachO/Atoms.h @@ -32,6 +32,8 @@ public: _contentType(type), _scope(scope), _merge(mergeNo), _thumb(false), _noDeadStrip(noDeadStrip) {} + ~MachODefinedAtom() override = default; + uint64_t size() const override { return _content.size(); } ContentType contentType() const override { return _contentType; } @@ -83,6 +85,8 @@ public: content, align), _sectionName(sectionName) {} + ~MachODefinedCustomSectionAtom() override = default; + SectionChoice sectionChoice() const override { return DefinedAtom::sectionCustomRequired; } @@ -101,6 +105,8 @@ public: : SimpleDefinedAtom(f), _name(name), _scope(scope), _size(size), _align(align) {} + ~MachOTentativeDefAtom() override = default; + uint64_t size() const override { return _size; } Merge merge() const override { return DefinedAtom::mergeAsTentative; } diff --git a/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp index d279303..088f93b 100644 --- a/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp +++ b/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp @@ -88,6 +88,8 @@ public: addSecondLevelPages(pages); } + ~UnwindInfoAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeProcessedUnwindInfo; } diff --git a/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h b/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h index e1a252b..acced33 100644 --- a/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h +++ b/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h @@ -122,21 +122,28 @@ public: ArrayRef(), DefinedAtom::Alignment(1))); } - const AtomVector &defined() const override { + const AtomRange defined() const override { return _definedAtoms; } - const AtomVector &undefined() const override { + const AtomRange undefined() const override { return _noUndefinedAtoms; } - const AtomVector &sharedLibrary() const override { + const AtomRange sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector &absolute() const override { + const AtomRange absolute() const override { return _noAbsoluteAtoms; } + void clearAtoms() override { + _definedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); + } + private: mutable AtomVector _definedAtoms; diff --git a/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h index a0d20ea..f7262bb 100644 --- a/lld/lib/ReaderWriter/MachO/File.h +++ b/lld/lib/ReaderWriter/MachO/File.h @@ -275,7 +275,8 @@ public: MachODylibFile(StringRef path) : SharedLibraryFile(path) {} - const SharedLibraryAtom *exports(StringRef name, bool isData) const override { + OwningAtomPtr exports(StringRef name, + bool isData) const override { // Pass down _installName so that if this requested symbol // is re-exported through this dylib, the SharedLibraryAtom's loadName() // is this dylib installName and not the implementation dylib's. @@ -328,25 +329,30 @@ public: } private: - const SharedLibraryAtom *exports(StringRef name, + OwningAtomPtr exports(StringRef name, StringRef installName) const { // First, check if requested symbol is directly implemented by this dylib. auto entry = _nameToAtom.find(name); if (entry != _nameToAtom.end()) { - if (!entry->second.atom) { - // Lazily create SharedLibraryAtom. - entry->second.atom = - new (allocator()) MachOSharedLibraryAtom(*this, name, installName, - entry->second.weakDef); - } - return entry->second.atom; + // FIXME: Make this map a set and only used in assert builds. + // Note, its safe to assert here as the resolver is the only client of + // this API and it only requests exports for undefined symbols. + // If we return from here we are no longer undefined so we should never + // get here again. + assert(!entry->second.atom && "Duplicate shared library export"); + bool weakDef = entry->second.weakDef; + auto *atom = new (allocator()) MachOSharedLibraryAtom(*this, name, + installName, + weakDef); + entry->second.atom = atom; + return atom; } // Next, check if symbol is implemented in some re-exported dylib. for (const ReExportedDylib &dylib : _reExportedDylibs) { assert(dylib.file); auto atom = dylib.file->exports(name, installName); - if (atom) + if (atom.get()) return atom; } diff --git a/lld/lib/ReaderWriter/MachO/FlatNamespaceFile.h b/lld/lib/ReaderWriter/MachO/FlatNamespaceFile.h index 6c6a926..08b28f4 100644 --- a/lld/lib/ReaderWriter/MachO/FlatNamespaceFile.h +++ b/lld/lib/ReaderWriter/MachO/FlatNamespaceFile.h @@ -25,34 +25,35 @@ public: FlatNamespaceFile(const MachOLinkingContext &context) : SharedLibraryFile("flat namespace") { } - const SharedLibraryAtom *exports(StringRef name, + OwningAtomPtr exports(StringRef name, bool dataSymbolOnly) const override { - _sharedLibraryAtoms.push_back( - new (allocator()) MachOSharedLibraryAtom(*this, name, getDSOName(), - false)); - - return _sharedLibraryAtoms.back(); + return new (allocator()) MachOSharedLibraryAtom(*this, name, getDSOName(), + false); } StringRef getDSOName() const override { return "flat-namespace"; } - const AtomVector &defined() const override { + const AtomRange defined() const override { return _noDefinedAtoms; } - const AtomVector &undefined() const override { + const AtomRange undefined() const override { return _noUndefinedAtoms; } - const AtomVector &sharedLibrary() const override { - return _sharedLibraryAtoms; + const AtomRange sharedLibrary() const override { + return _noSharedLibraryAtoms; } - const AtomVector &absolute() const override { + const AtomRange absolute() const override { return _noAbsoluteAtoms; } -private: - mutable AtomVector _sharedLibraryAtoms; + void clearAtoms() override { + _noDefinedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); + } }; } // namespace mach_o diff --git a/lld/lib/ReaderWriter/MachO/GOTPass.cpp b/lld/lib/ReaderWriter/MachO/GOTPass.cpp index eac4864..400dbf7 100644 --- a/lld/lib/ReaderWriter/MachO/GOTPass.cpp +++ b/lld/lib/ReaderWriter/MachO/GOTPass.cpp @@ -54,6 +54,8 @@ public: GOTEntryAtom(const File &file, bool is64, StringRef name) : SimpleDefinedAtom(file), _is64(is64), _name(name) { } + ~GOTEntryAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeGOT; } diff --git a/lld/lib/ReaderWriter/MachO/LayoutPass.cpp b/lld/lib/ReaderWriter/MachO/LayoutPass.cpp index 0c14ee9..b22bc54 100644 --- a/lld/lib/ReaderWriter/MachO/LayoutPass.cpp +++ b/lld/lib/ReaderWriter/MachO/LayoutPass.cpp @@ -146,7 +146,7 @@ static void printDefinedAtoms(const SimpleFile::DefinedAtomRange &atomRange) { /// Verify that the followon chain is sane. Should not be called in /// release binary. -void LayoutPass::checkFollowonChain(SimpleFile::DefinedAtomRange &range) { +void LayoutPass::checkFollowonChain(const SimpleFile::DefinedAtomRange &range) { ScopedTask task(getDefaultDomain(), "LayoutPass::checkFollowonChain"); // Verify that there's no cycle in follow-on chain. @@ -176,8 +176,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc, const LayoutPass::SortKey &rc, LayoutPass::SortOverride customSorter, std::string &reason) { - const DefinedAtom *left = lc._atom; - const DefinedAtom *right = rc._atom; + const DefinedAtom *left = lc._atom.get(); + const DefinedAtom *right = rc._atom.get(); if (left == right) { reason = "same"; return false; @@ -252,8 +252,9 @@ static bool compareAtoms(const LayoutPass::SortKey &lc, bool result = compareAtomsSub(lc, rc, customSorter, reason); DEBUG({ StringRef comp = result ? "<" : ">="; - llvm::dbgs() << "Layout: '" << lc._atom->name() << "' " << comp << " '" - << rc._atom->name() << "' (" << reason << ")\n"; + llvm::dbgs() << "Layout: '" << lc._atom.get()->name() + << "' " << comp << " '" + << rc._atom.get()->name() << "' (" << reason << ")\n"; }); return result; } @@ -329,7 +330,7 @@ void LayoutPass::setChainRoot(const DefinedAtom *targetAtom, /// d) If the targetAtom is part of a different chain and the root of the /// targetAtom until the targetAtom has all atoms of size 0, then chain the /// targetAtoms and its tree to the current chain -void LayoutPass::buildFollowOnTable(SimpleFile::DefinedAtomRange &range) { +void LayoutPass::buildFollowOnTable(const SimpleFile::DefinedAtomRange &range) { ScopedTask task(getDefaultDomain(), "LayoutPass::buildFollowOnTable"); // Set the initial size of the followon and the followonNext hash to the // number of atoms that we have. @@ -397,7 +398,8 @@ void LayoutPass::buildFollowOnTable(SimpleFile::DefinedAtomRange &range) { /// assigning ordinals to each atom, if the atoms have their ordinals /// already assigned skip the atom and move to the next. This is the /// main map thats used to sort the atoms while comparing two atoms together -void LayoutPass::buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range) { +void +LayoutPass::buildOrdinalOverrideMap(const SimpleFile::DefinedAtomRange &range) { ScopedTask task(getDefaultDomain(), "LayoutPass::buildOrdinalOverrideMap"); uint64_t index = 0; for (const DefinedAtom *ai : range) { @@ -419,12 +421,12 @@ void LayoutPass::buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range) { std::vector LayoutPass::decorate(SimpleFile::DefinedAtomRange &atomRange) const { std::vector ret; - for (const DefinedAtom *atom : atomRange) { - auto ri = _followOnRoots.find(atom); - auto oi = _ordinalOverrideMap.find(atom); - const DefinedAtom *root = (ri == _followOnRoots.end()) ? atom : ri->second; + for (OwningAtomPtr &atom : atomRange.owning_ptrs()) { + auto ri = _followOnRoots.find(atom.get()); + auto oi = _ordinalOverrideMap.find(atom.get()); + const auto *root = (ri == _followOnRoots.end()) ? atom.get() : ri->second; uint64_t override = (oi == _ordinalOverrideMap.end()) ? 0 : oi->second; - ret.push_back(SortKey(atom, root, override)); + ret.push_back(SortKey(std::move(atom), root, override)); } return ret; } @@ -433,7 +435,7 @@ void LayoutPass::undecorate(SimpleFile::DefinedAtomRange &atomRange, std::vector &keys) const { size_t i = 0; for (SortKey &k : keys) - atomRange[i++] = k._atom; + atomRange[i++] = std::move(k._atom); } /// Perform the actual pass diff --git a/lld/lib/ReaderWriter/MachO/LayoutPass.h b/lld/lib/ReaderWriter/MachO/LayoutPass.h index d6072b0..d254891 100644 --- a/lld/lib/ReaderWriter/MachO/LayoutPass.h +++ b/lld/lib/ReaderWriter/MachO/LayoutPass.h @@ -33,9 +33,10 @@ namespace mach_o { class LayoutPass : public Pass { public: struct SortKey { - SortKey(const DefinedAtom *atom, const DefinedAtom *root, uint64_t override) - : _atom(atom), _root(root), _override(override) {} - const DefinedAtom *_atom; + SortKey(OwningAtomPtr &&atom, + const DefinedAtom *root, uint64_t override) + : _atom(std::move(atom)), _root(root), _override(override) {} + OwningAtomPtr _atom; const DefinedAtom *_root; uint64_t _override; }; @@ -53,10 +54,10 @@ public: private: // Build the followOn atoms chain as specified by the kindLayoutAfter // reference type - void buildFollowOnTable(SimpleFile::DefinedAtomRange &range); + void buildFollowOnTable(const SimpleFile::DefinedAtomRange &range); // Build a map of Atoms to ordinals for sorting the atoms - void buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range); + void buildOrdinalOverrideMap(const SimpleFile::DefinedAtomRange &range); const Registry &_registry; SortOverride _customSorter; @@ -85,11 +86,12 @@ private: void setChainRoot(const DefinedAtom *targetAtom, const DefinedAtom *root); std::vector decorate(SimpleFile::DefinedAtomRange &atomRange) const; + void undecorate(SimpleFile::DefinedAtomRange &atomRange, std::vector &keys) const; // Check if the follow-on graph is a correct structure. For debugging only. - void checkFollowonChain(SimpleFile::DefinedAtomRange &range); + void checkFollowonChain(const SimpleFile::DefinedAtomRange &range); }; } // namespace mach_o diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index 1cc87f0..4431f34 100644 --- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -171,7 +171,19 @@ bool MachOLinkingContext::sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset, MachOLinkingContext::MachOLinkingContext() {} -MachOLinkingContext::~MachOLinkingContext() {} +MachOLinkingContext::~MachOLinkingContext() { + // Atoms are allocated on BumpPtrAllocator's on File's. + // As we transfer atoms from one file to another, we need to clear all of the + // atoms before we remove any of the BumpPtrAllocator's. + auto &nodes = getNodes(); + for (unsigned i = 0, e = nodes.size(); i != e; ++i) { + FileNode *node = dyn_cast(nodes[i].get()); + if (!node) + continue; + File *file = node->getFile(); + file->clearAtoms(); + } +} void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion, diff --git a/lld/lib/ReaderWriter/MachO/ObjCPass.cpp b/lld/lib/ReaderWriter/MachO/ObjCPass.cpp index 13fa988..f8c7310 100644 --- a/lld/lib/ReaderWriter/MachO/ObjCPass.cpp +++ b/lld/lib/ReaderWriter/MachO/ObjCPass.cpp @@ -56,6 +56,8 @@ public: Data.info.flags |= (swiftVersion << 8); } + ~ObjCImageInfoAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeObjCImageInfo; } diff --git a/lld/lib/ReaderWriter/MachO/SectCreateFile.h b/lld/lib/ReaderWriter/MachO/SectCreateFile.h index 5236071..49e65f6 100644 --- a/lld/lib/ReaderWriter/MachO/SectCreateFile.h +++ b/lld/lib/ReaderWriter/MachO/SectCreateFile.h @@ -31,6 +31,8 @@ public: _combinedName((segName + "/" + sectName).str()), _content(std::move(content)) {} + ~SectCreateAtom() override = default; + uint64_t size() const override { return _content->getBufferSize(); } Scope scope() const override { return scopeGlobal; } @@ -67,22 +69,29 @@ public: new (allocator()) SectCreateAtom(*this, seg, sect, std::move(content))); } - const AtomVector &defined() const override { + const AtomRange defined() const override { return _definedAtoms; } - const AtomVector &undefined() const override { + const AtomRange undefined() const override { return _noUndefinedAtoms; } - const AtomVector &sharedLibrary() const override { + const AtomRange sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector &absolute() const override { + const AtomRange absolute() const override { return _noAbsoluteAtoms; } + void clearAtoms() override { + _definedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); + } + private: AtomVector _definedAtoms; }; diff --git a/lld/lib/ReaderWriter/MachO/StubsPass.cpp b/lld/lib/ReaderWriter/MachO/StubsPass.cpp index e69d669..2539c26 100644 --- a/lld/lib/ReaderWriter/MachO/StubsPass.cpp +++ b/lld/lib/ReaderWriter/MachO/StubsPass.cpp @@ -37,6 +37,8 @@ public: LazyPointerAtom(const File &file, bool is64) : SimpleDefinedAtom(file), _is64(is64) { } + ~LazyPointerAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeLazyPointer; } @@ -71,6 +73,8 @@ public: NonLazyPointerAtom(const File &file, bool is64, ContentType contentType) : SimpleDefinedAtom(file), _is64(is64), _contentType(contentType) { } + ~NonLazyPointerAtom() override = default; + ContentType contentType() const override { return _contentType; } @@ -106,6 +110,8 @@ public: StubAtom(const File &file, const ArchHandler::StubInfo &stubInfo) : SimpleDefinedAtom(file), _stubInfo(stubInfo){ } + ~StubAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeStub; } @@ -138,6 +144,8 @@ public: StubHelperAtom(const File &file, const ArchHandler::StubInfo &stubInfo) : SimpleDefinedAtom(file), _stubInfo(stubInfo) { } + ~StubHelperAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeStubHelper; } @@ -171,6 +179,8 @@ public: StubHelperCommonAtom(const File &file, const ArchHandler::StubInfo &stubInfo) : SimpleDefinedAtom(file), _stubInfo(stubInfo) { } + ~StubHelperCommonAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeStubHelper; } diff --git a/lld/lib/ReaderWriter/MachO/TLVPass.cpp b/lld/lib/ReaderWriter/MachO/TLVPass.cpp index b12f006..41aa223 100644 --- a/lld/lib/ReaderWriter/MachO/TLVPass.cpp +++ b/lld/lib/ReaderWriter/MachO/TLVPass.cpp @@ -30,6 +30,8 @@ public: TLVPEntryAtom(const File &file, bool is64, StringRef name) : SimpleDefinedAtom(file), _is64(is64), _name(name) {} + ~TLVPEntryAtom() override = default; + ContentType contentType() const override { return DefinedAtom::typeTLVInitializerPtr; } diff --git a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp index 091da9c..bec2c68 100644 --- a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -195,7 +195,7 @@ private: /// Mapping of Atoms. template class AtomList { - typedef lld::File::AtomVector Ty; + using Ty = std::vector>; public: typename Ty::iterator begin() { return _atoms.begin(); } @@ -503,10 +503,20 @@ template <> struct MappingTraits { // Declare that an AtomList is a yaml sequence. template struct SequenceTraits > { static size_t size(IO &io, AtomList &seq) { return seq._atoms.size(); } - static const T *&element(IO &io, AtomList &seq, size_t index) { + static T *&element(IO &io, AtomList &seq, size_t index) { if (index >= seq._atoms.size()) seq._atoms.resize(index + 1); - return seq._atoms[index]; + return seq._atoms[index].get(); + } +}; + +// Declare that an AtomRange is a yaml sequence. +template struct SequenceTraits > { + static size_t size(IO &io, File::AtomRange &seq) { return seq.size(); } + static T *&element(IO &io, File::AtomRange &seq, size_t index) { + assert(io.outputting() && "AtomRange only used when outputting"); + assert(index < seq.size() && "Out of range access"); + return seq[index].get(); } }; @@ -558,23 +568,29 @@ template <> struct MappingTraits { const lld::File *denormalize(IO &io) { return this; } - const AtomVector &defined() const override { + const AtomRange defined() const override { return _noDefinedAtoms; } - const AtomVector &undefined() const override { + const AtomRange undefined() const override { return _noUndefinedAtoms; } - const AtomVector & - sharedLibrary() const override { + const AtomRange sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector &absolute() const override { + const AtomRange absolute() const override { return _noAbsoluteAtoms; } + void clearAtoms() override { + _noDefinedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); + } + File *find(StringRef name, bool dataSymbolOnly) override { for (const ArchMember &member : _members) { for (const lld::DefinedAtom *atom : member._content->defined()) { @@ -606,36 +622,46 @@ template <> struct MappingTraits { class NormalizedFile : public lld::File { public: NormalizedFile(IO &io) - : File("", kindNormalizedObject), _io(io), _rnb(nullptr) {} + : File("", kindNormalizedObject), _io(io), _rnb(nullptr), + _definedAtomsRef(_definedAtoms._atoms), + _undefinedAtomsRef(_undefinedAtoms._atoms), + _sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms), + _absoluteAtomsRef(_absoluteAtoms._atoms) {} NormalizedFile(IO &io, const lld::File *file) : File(file->path(), kindNormalizedObject), _io(io), - _rnb(new RefNameBuilder(*file)), _path(file->path()) { - for (const lld::DefinedAtom *a : file->defined()) - _definedAtoms._atoms.push_back(a); - for (const lld::UndefinedAtom *a : file->undefined()) - _undefinedAtoms._atoms.push_back(a); - for (const lld::SharedLibraryAtom *a : file->sharedLibrary()) - _sharedLibraryAtoms._atoms.push_back(a); - for (const lld::AbsoluteAtom *a : file->absolute()) - _absoluteAtoms._atoms.push_back(a); + _rnb(new RefNameBuilder(*file)), _path(file->path()), + _definedAtomsRef(file->defined()), + _undefinedAtomsRef(file->undefined()), + _sharedLibraryAtomsRef(file->sharedLibrary()), + _absoluteAtomsRef(file->absolute()) { + } + + ~NormalizedFile() override { } + const lld::File *denormalize(IO &io); - const AtomVector &defined() const override { - return _definedAtoms._atoms; + const AtomRange defined() const override { + return _definedAtomsRef; } - const AtomVector &undefined() const override { - return _undefinedAtoms._atoms; + const AtomRange undefined() const override { + return _undefinedAtomsRef; } - const AtomVector & - sharedLibrary() const override { - return _sharedLibraryAtoms._atoms; + const AtomRange sharedLibrary() const override { + return _sharedLibraryAtomsRef; } - const AtomVector &absolute() const override { - return _absoluteAtoms._atoms; + const AtomRange absolute() const override { + return _absoluteAtomsRef; + } + + void clearAtoms() override { + _definedAtoms._atoms.clear(); + _undefinedAtoms._atoms.clear(); + _sharedLibraryAtoms._atoms.clear(); + _absoluteAtoms._atoms.clear(); } // Allocate a new copy of this string in _storage, so the strings @@ -653,6 +679,10 @@ template <> struct MappingTraits { AtomList _undefinedAtoms; AtomList _sharedLibraryAtoms; AtomList _absoluteAtoms; + AtomRange _definedAtomsRef; + AtomRange _undefinedAtomsRef; + AtomRange _sharedLibraryAtomsRef; + AtomRange _absoluteAtomsRef; llvm::BumpPtrAllocator _storage; }; @@ -676,10 +706,18 @@ template <> struct MappingTraits { info->_file = keys.operator->(); io.mapOptional("path", keys->_path); - io.mapOptional("defined-atoms", keys->_definedAtoms); - io.mapOptional("undefined-atoms", keys->_undefinedAtoms); - io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms); - io.mapOptional("absolute-atoms", keys->_absoluteAtoms); + + if (io.outputting()) { + io.mapOptional("defined-atoms", keys->_definedAtomsRef); + io.mapOptional("undefined-atoms", keys->_undefinedAtomsRef); + io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtomsRef); + io.mapOptional("absolute-atoms", keys->_absoluteAtomsRef); + } else { + io.mapOptional("defined-atoms", keys->_definedAtoms); + io.mapOptional("undefined-atoms", keys->_undefinedAtoms); + io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms); + io.mapOptional("absolute-atoms", keys->_absoluteAtoms); + } } static void mappingArchive(IO &io, const lld::File *&file) { @@ -790,6 +828,9 @@ template <> struct MappingTraits { for (uint8_t x : cont) _content.push_back(x); } + + ~NormalizedAtom() override = default; + const lld::DefinedAtom *denormalize(IO &io) { YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); @@ -938,6 +979,14 @@ template <> struct MappingTraits { } }; +template <> struct MappingTraits { + static void mapping(IO &io, lld::DefinedAtom *&atom) { + const lld::DefinedAtom *atomPtr = atom; + MappingTraits::mapping(io, atomPtr); + atom = const_cast(atomPtr); + } +}; + // YAML conversion for const lld::UndefinedAtom* template <> struct MappingTraits { @@ -950,6 +999,8 @@ template <> struct MappingTraits { : _file(fileFromContext(io)), _name(atom->name()), _canBeNull(atom->canBeNull()) {} + ~NormalizedAtom() override = default; + const lld::UndefinedAtom *denormalize(IO &io) { YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); @@ -993,6 +1044,14 @@ template <> struct MappingTraits { } }; +template <> struct MappingTraits { + static void mapping(IO &io, lld::UndefinedAtom *&atom) { + const lld::UndefinedAtom *atomPtr = atom; + MappingTraits::mapping(io, atomPtr); + atom = const_cast(atomPtr); + } +}; + // YAML conversion for const lld::SharedLibraryAtom* template <> struct MappingTraits { @@ -1006,6 +1065,8 @@ template <> struct MappingTraits { _loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()), _type(atom->type()), _size(atom->size()) {} + ~NormalizedAtom() override = default; + const lld::SharedLibraryAtom *denormalize(IO &io) { YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); @@ -1061,6 +1122,14 @@ template <> struct MappingTraits { } }; +template <> struct MappingTraits { + static void mapping(IO &io, lld::SharedLibraryAtom *&atom) { + const lld::SharedLibraryAtom *atomPtr = atom; + MappingTraits::mapping(io, atomPtr); + atom = const_cast(atomPtr); + } +}; + // YAML conversion for const lld::AbsoluteAtom* template <> struct MappingTraits { @@ -1071,6 +1140,9 @@ template <> struct MappingTraits { NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom) : _file(fileFromContext(io)), _name(atom->name()), _scope(atom->scope()), _value(atom->value()) {} + + ~NormalizedAtom() override = default; + const lld::AbsoluteAtom *denormalize(IO &io) { YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); @@ -1129,6 +1201,14 @@ template <> struct MappingTraits { } }; +template <> struct MappingTraits { + static void mapping(IO &io, lld::AbsoluteAtom *&atom) { + const lld::AbsoluteAtom *atomPtr = atom; + MappingTraits::mapping(io, atomPtr); + atom = const_cast(atomPtr); + } +}; + } // namespace llvm } // namespace yaml -- 2.7.4