diff options
author | Pete Cooper <peter_cooper@apple.com> | 2016-03-22 03:44:32 +0000 |
---|---|---|
committer | Pete Cooper <peter_cooper@apple.com> | 2016-03-22 03:44:32 +0000 |
commit | 572a87e2aa81e1dfe677645d0d3591fc4ee8239a (patch) | |
tree | a789a963f53e66884c9043df0d25c125e6270f6f | |
parent | b6f7efa71fa63d8e910723b67b0a8430c3ebe4fc (diff) | |
download | bcm5719-llvm-572a87e2aa81e1dfe677645d0d3591fc4ee8239a.tar.gz bcm5719-llvm-572a87e2aa81e1dfe677645d0d3591fc4ee8239a.zip |
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
27 files changed, 516 insertions, 203 deletions
diff --git a/lld/include/lld/Core/Atom.h b/lld/include/lld/Core/Atom.h index 27fdde022ba..6a4308918c2 100644 --- a/lld/include/lld/Core/Atom.h +++ b/lld/include/lld/Core/Atom.h @@ -16,6 +16,9 @@ namespace lld { class File; +template<typename T> +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<typename T> 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<typename T> +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 4a4d1c757fd..e3193f8aaf2 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 f6e7d7eac10..eb41fcc38d9 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 <functional> @@ -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 <typename T> using AtomVector = std::vector<OwningAtomPtr<T>>; + public: virtual ~File(); @@ -104,18 +109,67 @@ public: return _allocator; } - /// The type of atom mutable container. - template <typename T> using AtomVector = std::vector<const T *>; - - /// 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 <typename T> class AtomRange { public: - AtomRange(AtomVector<T> v) : _v(v) {} - typename AtomVector<T>::const_iterator begin() const { return _v.begin(); } - typename AtomVector<T>::const_iterator end() const { return _v.end(); } - typename AtomVector<T>::iterator begin() { return _v.begin(); } - typename AtomVector<T>::iterator end() { return _v.end(); } + AtomRange(AtomVector<T> &v) : _v(v) {} + AtomRange(const AtomVector<T> &v) : _v(const_cast<AtomVector<T> &>(v)) {} + + typedef std::pointer_to_unary_function<const OwningAtomPtr<T>&, + const T*> ConstDerefFn; + + typedef std::pointer_to_unary_function<OwningAtomPtr<T>&, T*> DerefFn; + + typedef llvm::mapped_iterator<typename AtomVector<T>::const_iterator, + ConstDerefFn> ConstItTy; + typedef llvm::mapped_iterator<typename AtomVector<T>::iterator, + DerefFn> ItTy; + + static const T* DerefConst(const OwningAtomPtr<T> &p) { + return p.get(); + } + + static T* Deref(OwningAtomPtr<T> &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<typename AtomVector<T>::iterator> owning_ptrs() { + return llvm::make_range(_v.begin(), _v.end()); + } + + llvm::iterator_range<typename AtomVector<T>::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<T> &operator[](size_t idx) const { + return _v[idx]; + } + + OwningAtomPtr<T> &operator[](size_t idx) { + return _v[idx]; + } private: AtomVector<T> &_v; @@ -123,19 +177,25 @@ public: /// \brief Must be implemented to return the AtomVector object for /// all DefinedAtoms in this File. - virtual const AtomVector<DefinedAtom> &defined() const = 0; + virtual const AtomRange<DefinedAtom> defined() const = 0; /// \brief Must be implemented to return the AtomVector object for /// all UndefinedAtomw in this File. - virtual const AtomVector<UndefinedAtom> &undefined() const = 0; + virtual const AtomRange<UndefinedAtom> undefined() const = 0; /// \brief Must be implemented to return the AtomVector object for /// all SharedLibraryAtoms in this File. - virtual const AtomVector<SharedLibraryAtom> &sharedLibrary() const = 0; + virtual const AtomRange<SharedLibraryAtom> sharedLibrary() const = 0; /// \brief Must be implemented to return the AtomVector object for /// all AbsoluteAtoms in this File. - virtual const AtomVector<AbsoluteAtom> &absolute() const = 0; + virtual const AtomRange<AbsoluteAtom> 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<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { llvm_unreachable("internal error"); } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { llvm_unreachable("internal error"); } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { llvm_unreachable("internal error"); } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> 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 d7b42b6e26e..efaf19ff119 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<DefinedAtom> atom); + bool doUndefinedAtom(OwningAtomPtr<UndefinedAtom> atom); + void doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> atom); + void doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> 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<const DefinedAtom *>&); class MergedFile : public SimpleFile { public: MergedFile() : SimpleFile("<linker-internal>", kindResolverMergedObject) {} - void addAtoms(std::vector<const Atom*>& atoms); + void addAtoms(llvm::MutableArrayRef<OwningAtomPtr<Atom>> atoms); }; LinkingContext &_ctx; SymbolTable _symbolTable; - std::vector<const Atom *> _atoms; + std::vector<OwningAtomPtr<Atom>> _atoms; std::set<const Atom *> _deadStripRoots; llvm::DenseSet<const Atom *> _liveAtoms; llvm::DenseSet<const Atom *> _deadAtoms; diff --git a/lld/include/lld/Core/SharedLibraryAtom.h b/lld/include/lld/Core/SharedLibraryAtom.h index 0f4648fa357..7fec7a3e3d2 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 2e4771f614e..5fa0e9574f0 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<SharedLibraryAtom> exports(StringRef name, bool dataSymbolOnly) const = 0; // Returns the install name. virtual StringRef getDSOName() const = 0; - const AtomVector<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { return _definedAtoms; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _undefinedAtoms; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { return _sharedLibraryAtoms; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> 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 a06eecd9be1..f010387d5bd 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<DefinedAtom>(&a)); + } + void addAtom(UndefinedAtom &a) { + _undefined.push_back(OwningAtomPtr<UndefinedAtom>(&a)); + } + void addAtom(SharedLibraryAtom &a) { + _shared.push_back(OwningAtomPtr<SharedLibraryAtom>(&a)); + } + void addAtom(AbsoluteAtom &a) { + _absolute.push_back(OwningAtomPtr<AbsoluteAtom>(&a)); + } void addAtom(const Atom &atom) { if (auto *p = dyn_cast<DefinedAtom>(&atom)) { - _defined.push_back(p); + addAtom(const_cast<DefinedAtom &>(*p)); } else if (auto *p = dyn_cast<UndefinedAtom>(&atom)) { - _undefined.push_back(p); + addAtom(const_cast<UndefinedAtom &>(*p)); } else if (auto *p = dyn_cast<SharedLibraryAtom>(&atom)) { - _shared.push_back(p); + addAtom(const_cast<SharedLibraryAtom &>(*p)); } else if (auto *p = dyn_cast<AbsoluteAtom>(&atom)) { - _absolute.push_back(p); + addAtom(const_cast<AbsoluteAtom &>(*p)); } else { llvm_unreachable("atom has unknown definition kind"); } @@ -52,25 +67,35 @@ public: void removeDefinedAtomsIf(std::function<bool(const DefinedAtom *)> 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<DefinedAtom> &p) { + return pred(p.get()); + }); atoms.erase(newEnd, atoms.end()); } - const AtomVector<DefinedAtom> &defined() const override { return _defined; } + const AtomRange<DefinedAtom> defined() const override { return _defined; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _undefined; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { return _shared; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> absolute() const override { return _absolute; } - typedef llvm::MutableArrayRef<const DefinedAtom *> DefinedAtomRange; + void clearAtoms() override { + _defined.clear(); + _undefined.clear(); + _shared.clear(); + _absolute.clear(); + } + + typedef AtomRange<DefinedAtom> 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 3e58f800ea1..f45d6ecda6b 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 ac95f101679..b84132bfecd 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<DefinedAtom> File::_noDefinedAtoms; File::AtomVector<UndefinedAtom> File::_noUndefinedAtoms; diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp index b8964358c0e..d94699a9f13 100644 --- a/lld/lib/Core/Resolver.cpp +++ b/lld/lib/Core/Resolver.cpp @@ -33,16 +33,16 @@ ErrorOr<bool> 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<bool> { - 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<UndefinedAtom> 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>(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<DefinedAtom> 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>(atom.release())); } -void Resolver::doSharedLibraryAtom(const SharedLibraryAtom &atom) { +void Resolver::doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> 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>(atom.release())); } -void Resolver::doAbsoluteAtom(const AbsoluteAtom &atom) { +void Resolver::doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> 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<const DefinedAtom *> &newAtoms) { - for (const DefinedAtom *newAtom : newAtoms) - doDefinedAtom(*newAtom); + // add to list of known atoms + _atoms.push_back(OwningAtomPtr<Atom>(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<DefinedAtom>(atom)) { + for (const OwningAtomPtr<Atom> &atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(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<DefinedAtom>(atom)) + for (const OwningAtomPtr<Atom> &atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get())) for (const Reference *ref : *defAtom) if (isBackref(ref)) - _reverseRef.insert(std::make_pair(ref->target(), atom)); - if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom)) + _reverseRef.insert(std::make_pair(ref->target(), atom.get())); + if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(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<DefinedAtom>(atom)) + for (const OwningAtomPtr<Atom> &atom : _atoms) + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(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<Atom> &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<Atom> &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<const Atom *> &all) { +void Resolver::MergedFile::addAtoms( + llvm::MutableArrayRef<OwningAtomPtr<Atom>> all) { ScopedTask task(getDefaultDomain(), "addAtoms"); DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n"); - for (const Atom *atom : all) { + for (OwningAtomPtr<Atom> &atom : all) { #ifndef NDEBUG - if (auto *definedAtom = dyn_cast<DefinedAtom>(atom)) { + if (auto *definedAtom = dyn_cast<DefinedAtom>(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<const Atom *> &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 4a859f3d605..914c23642ac 100644 --- a/lld/lib/Driver/DarwinLdDriver.cpp +++ b/lld/lib/Driver/DarwinLdDriver.cpp @@ -1169,7 +1169,14 @@ bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) { Resolver resolver(ctx); if (!resolver.resolve()) return false; - std::unique_ptr<SimpleFile> merged = resolver.resultFile(); + SimpleFile *merged = nullptr; + { + std::unique_ptr<SimpleFile> mergedFile = resolver.resultFile(); + merged = mergedFile.get(); + auto &members = ctx.getNodes(); + members.insert(members.begin(), + llvm::make_unique<FileNode>(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 a47024ca4f6..73b86127797 100644 --- a/lld/lib/ReaderWriter/FileArchive.cpp +++ b/lld/lib/ReaderWriter/FileArchive.cpp @@ -88,22 +88,29 @@ public: return std::error_code(); } - const AtomVector<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { return _noDefinedAtoms; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _noUndefinedAtoms; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> 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 cefa745add9..7eda42ef7a0 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 f50a6cffe18..c3117d4ac89 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 d2793033b5f..088f93bf630 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 e1a252bbf9b..acced33b7e7 100644 --- a/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h +++ b/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h @@ -122,21 +122,28 @@ public: ArrayRef<uint8_t>(), DefinedAtom::Alignment(1))); } - const AtomVector<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { return _definedAtoms; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _noUndefinedAtoms; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> absolute() const override { return _noAbsoluteAtoms; } + void clearAtoms() override { + _definedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); + } + private: mutable AtomVector<DefinedAtom> _definedAtoms; diff --git a/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h index a0d20ea540f..f7262bbfaef 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<SharedLibraryAtom> 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<SharedLibraryAtom> 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 6c6a9262ba2..08b28f43a15 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<SharedLibraryAtom> 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<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { return _noDefinedAtoms; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _noUndefinedAtoms; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { - return _sharedLibraryAtoms; + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { + return _noSharedLibraryAtoms; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> absolute() const override { return _noAbsoluteAtoms; } -private: - mutable AtomVector<SharedLibraryAtom> _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 eac48644f6b..400dbf7de9d 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 0c14ee9d39a..b22bc5482ca 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::SortKey> LayoutPass::decorate(SimpleFile::DefinedAtomRange &atomRange) const { std::vector<SortKey> 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<DefinedAtom> &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<SortKey> &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 d6072b0ca4f..d254891a789 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<DefinedAtom> &&atom, + const DefinedAtom *root, uint64_t override) + : _atom(std::move(atom)), _root(root), _override(override) {} + OwningAtomPtr<DefinedAtom> _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<SortKey> decorate(SimpleFile::DefinedAtomRange &atomRange) const; + void undecorate(SimpleFile::DefinedAtomRange &atomRange, std::vector<SortKey> &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 1cc87f0fac4..4431f347b27 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<FileNode>(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 13fa9888cec..f8c7310d4ae 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 5236071e0e0..49e65f63151 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<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { return _definedAtoms; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _noUndefinedAtoms; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> absolute() const override { return _noAbsoluteAtoms; } + void clearAtoms() override { + _definedAtoms.clear(); + _noUndefinedAtoms.clear(); + _noSharedLibraryAtoms.clear(); + _noAbsoluteAtoms.clear(); + } + private: AtomVector<DefinedAtom> _definedAtoms; }; diff --git a/lld/lib/ReaderWriter/MachO/StubsPass.cpp b/lld/lib/ReaderWriter/MachO/StubsPass.cpp index e69d6698cb6..2539c26c4ea 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 b12f006d7a1..41aa223d3c5 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 091da9ca82b..bec2c68af31 100644 --- a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -195,7 +195,7 @@ private: /// Mapping of Atoms. template <typename T> class AtomList { - typedef lld::File::AtomVector<T> Ty; + using Ty = std::vector<OwningAtomPtr<T>>; public: typename Ty::iterator begin() { return _atoms.begin(); } @@ -503,10 +503,20 @@ template <> struct MappingTraits<ArchMember> { // Declare that an AtomList is a yaml sequence. template <typename T> struct SequenceTraits<AtomList<T> > { static size_t size(IO &io, AtomList<T> &seq) { return seq._atoms.size(); } - static const T *&element(IO &io, AtomList<T> &seq, size_t index) { + static T *&element(IO &io, AtomList<T> &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 <typename T> struct SequenceTraits<File::AtomRange<T> > { + static size_t size(IO &io, File::AtomRange<T> &seq) { return seq.size(); } + static T *&element(IO &io, File::AtomRange<T> &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 *> { const lld::File *denormalize(IO &io) { return this; } - const AtomVector<lld::DefinedAtom> &defined() const override { + const AtomRange<lld::DefinedAtom> defined() const override { return _noDefinedAtoms; } - const AtomVector<lld::UndefinedAtom> &undefined() const override { + const AtomRange<lld::UndefinedAtom> undefined() const override { return _noUndefinedAtoms; } - const AtomVector<lld::SharedLibraryAtom> & - sharedLibrary() const override { + const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override { return _noSharedLibraryAtoms; } - const AtomVector<lld::AbsoluteAtom> &absolute() const override { + const AtomRange<lld::AbsoluteAtom> 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<const lld::File *> { 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<lld::DefinedAtom> &defined() const override { - return _definedAtoms._atoms; + const AtomRange<lld::DefinedAtom> defined() const override { + return _definedAtomsRef; } - const AtomVector<lld::UndefinedAtom> &undefined() const override { - return _undefinedAtoms._atoms; + const AtomRange<lld::UndefinedAtom> undefined() const override { + return _undefinedAtomsRef; } - const AtomVector<lld::SharedLibraryAtom> & - sharedLibrary() const override { - return _sharedLibraryAtoms._atoms; + const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override { + return _sharedLibraryAtomsRef; } - const AtomVector<lld::AbsoluteAtom> &absolute() const override { - return _absoluteAtoms._atoms; + const AtomRange<lld::AbsoluteAtom> 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<const lld::File *> { AtomList<lld::UndefinedAtom> _undefinedAtoms; AtomList<lld::SharedLibraryAtom> _sharedLibraryAtoms; AtomList<lld::AbsoluteAtom> _absoluteAtoms; + AtomRange<lld::DefinedAtom> _definedAtomsRef; + AtomRange<lld::UndefinedAtom> _undefinedAtomsRef; + AtomRange<lld::SharedLibraryAtom> _sharedLibraryAtomsRef; + AtomRange<lld::AbsoluteAtom> _absoluteAtomsRef; llvm::BumpPtrAllocator _storage; }; @@ -676,10 +706,18 @@ template <> struct MappingTraits<const lld::File *> { 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<const lld::DefinedAtom *> { for (uint8_t x : cont) _content.push_back(x); } + + ~NormalizedAtom() override = default; + const lld::DefinedAtom *denormalize(IO &io) { YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); assert(info != nullptr); @@ -938,6 +979,14 @@ template <> struct MappingTraits<const lld::DefinedAtom *> { } }; +template <> struct MappingTraits<lld::DefinedAtom *> { + static void mapping(IO &io, lld::DefinedAtom *&atom) { + const lld::DefinedAtom *atomPtr = atom; + MappingTraits<const lld::DefinedAtom *>::mapping(io, atomPtr); + atom = const_cast<lld::DefinedAtom *>(atomPtr); + } +}; + // YAML conversion for const lld::UndefinedAtom* template <> struct MappingTraits<const lld::UndefinedAtom *> { @@ -950,6 +999,8 @@ template <> struct MappingTraits<const lld::UndefinedAtom *> { : _file(fileFromContext(io)), _name(atom->name()), _canBeNull(atom->canBeNull()) {} + ~NormalizedAtom() override = default; + const lld::UndefinedAtom *denormalize(IO &io) { YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); assert(info != nullptr); @@ -993,6 +1044,14 @@ template <> struct MappingTraits<const lld::UndefinedAtom *> { } }; +template <> struct MappingTraits<lld::UndefinedAtom *> { + static void mapping(IO &io, lld::UndefinedAtom *&atom) { + const lld::UndefinedAtom *atomPtr = atom; + MappingTraits<const lld::UndefinedAtom *>::mapping(io, atomPtr); + atom = const_cast<lld::UndefinedAtom *>(atomPtr); + } +}; + // YAML conversion for const lld::SharedLibraryAtom* template <> struct MappingTraits<const lld::SharedLibraryAtom *> { @@ -1006,6 +1065,8 @@ template <> struct MappingTraits<const lld::SharedLibraryAtom *> { _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<YamlContext *>(io.getContext()); assert(info != nullptr); @@ -1061,6 +1122,14 @@ template <> struct MappingTraits<const lld::SharedLibraryAtom *> { } }; +template <> struct MappingTraits<lld::SharedLibraryAtom *> { + static void mapping(IO &io, lld::SharedLibraryAtom *&atom) { + const lld::SharedLibraryAtom *atomPtr = atom; + MappingTraits<const lld::SharedLibraryAtom *>::mapping(io, atomPtr); + atom = const_cast<lld::SharedLibraryAtom *>(atomPtr); + } +}; + // YAML conversion for const lld::AbsoluteAtom* template <> struct MappingTraits<const lld::AbsoluteAtom *> { @@ -1071,6 +1140,9 @@ template <> struct MappingTraits<const lld::AbsoluteAtom *> { 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<YamlContext *>(io.getContext()); assert(info != nullptr); @@ -1129,6 +1201,14 @@ template <> struct MappingTraits<const lld::AbsoluteAtom *> { } }; +template <> struct MappingTraits<lld::AbsoluteAtom *> { + static void mapping(IO &io, lld::AbsoluteAtom *&atom) { + const lld::AbsoluteAtom *atomPtr = atom; + MappingTraits<const lld::AbsoluteAtom *>::mapping(io, atomPtr); + atom = const_cast<lld::AbsoluteAtom *>(atomPtr); + } +}; + } // namespace llvm } // namespace yaml |