diff options
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 |