From e420dd4d844ad3358bbaeed3b322a61838a6d986 Mon Sep 17 00:00:00 2001 From: Pete Cooper Date: Mon, 25 Jan 2016 21:50:54 +0000 Subject: [PATCH] Use an ilist instead of std::list. NFC. The TrieNode/TrieEdge data structures here are allocated in a bumpptrallocator. Unfortunately, TrieNode contained a std::list and as the allocator doesn't call the TrieNode destructor, we ended up leaking the memory allocated by the std::list itself. Instead we can use an intrusive list as then we save the extra allocations anyway. llvm-svn: 258725 --- .../MachO/MachONormalizedFileBinaryWriter.cpp | 193 +++++++++++------- 1 file changed, 115 insertions(+), 78 deletions(-) diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp index 4a54e4bb7278..4fc989f031f0 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp @@ -25,6 +25,8 @@ #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -50,6 +52,112 @@ namespace lld { namespace mach_o { namespace normalized { +class ByteBuffer { +public: + ByteBuffer() : _ostream(_bytes) { } + + void append_byte(uint8_t b) { + _ostream << b; + } + void append_uleb128(uint64_t value) { + llvm::encodeULEB128(value, _ostream); + } + void append_uleb128Fixed(uint64_t value, unsigned byteCount) { + unsigned min = llvm::getULEB128Size(value); + assert(min <= byteCount); + unsigned pad = byteCount - min; + llvm::encodeULEB128(value, _ostream, pad); + } + void append_sleb128(int64_t value) { + llvm::encodeSLEB128(value, _ostream); + } + void append_string(StringRef str) { + _ostream << str; + append_byte(0); + } + void align(unsigned alignment) { + while ( (_ostream.tell() % alignment) != 0 ) + append_byte(0); + } + size_t size() { + return _ostream.tell(); + } + const uint8_t *bytes() { + return reinterpret_cast(_ostream.str().data()); + } + +private: + SmallVector _bytes; + // Stream ivar must be after SmallVector ivar to construct properly. + llvm::raw_svector_ostream _ostream; +}; + +struct TrieNode; // Forward declaration. + +struct TrieEdge : public llvm::ilist_node { + TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {} + + StringRef _subString; + struct TrieNode *_child; +}; + +} // namespace normalized +} // namespace mach_o +} // namespace lld + + +namespace llvm { + using lld::mach_o::normalized::TrieEdge; + template <> + struct ilist_traits + : public ilist_default_traits { + private: + mutable ilist_half_node Sentinel; + public: + TrieEdge *createSentinel() const { + return static_cast(&Sentinel); + } + void destroySentinel(TrieEdge *) const {} + + TrieEdge *provideInitialHead() const { return createSentinel(); } + TrieEdge *ensureHead(TrieEdge*) const { return createSentinel(); } + static void noteHead(TrieEdge*, TrieEdge*) {} + void deleteNode(TrieEdge *N) {} + + private: + void createNode(const TrieEdge &); + }; +} // namespace llvm + + +namespace lld { +namespace mach_o { +namespace normalized { + +struct TrieNode { + typedef llvm::ilist TrieEdgeList; + + TrieNode(StringRef s) + : _cummulativeString(s), _address(0), _flags(0), _other(0), + _trieOffset(0), _hasExportInfo(false) {} + ~TrieNode() = default; + + void addSymbol(const Export &entry, BumpPtrAllocator &allocator, + std::vector &allNodes); + bool updateOffset(uint32_t &offset); + void appendToByteBuffer(ByteBuffer &out); + +private: + StringRef _cummulativeString; + TrieEdgeList _children; + uint64_t _address; + uint64_t _flags; + uint64_t _other; + StringRef _importedName; + uint32_t _trieOffset; + bool _hasExportInfo; +}; + /// Utility class for writing a mach-o binary file given an in-memory /// normalized file. class MachOFileLayout { @@ -116,77 +224,6 @@ private: uint32_t pointerAlign(uint32_t value); static StringRef dyldPath(); - class ByteBuffer { - public: - ByteBuffer() : _ostream(_bytes) { } - - void append_byte(uint8_t b) { - _ostream << b; - } - void append_uleb128(uint64_t value) { - llvm::encodeULEB128(value, _ostream); - } - void append_uleb128Fixed(uint64_t value, unsigned byteCount) { - unsigned min = llvm::getULEB128Size(value); - assert(min <= byteCount); - unsigned pad = byteCount - min; - llvm::encodeULEB128(value, _ostream, pad); - } - void append_sleb128(int64_t value) { - llvm::encodeSLEB128(value, _ostream); - } - void append_string(StringRef str) { - _ostream << str; - append_byte(0); - } - void align(unsigned alignment) { - while ( (_ostream.tell() % alignment) != 0 ) - append_byte(0); - } - size_t size() { - return _ostream.tell(); - } - const uint8_t *bytes() { - return reinterpret_cast(_ostream.str().data()); - } - - private: - SmallVector _bytes; - // Stream ivar must be after SmallVector ivar to construct properly. - llvm::raw_svector_ostream _ostream; - }; - - struct TrieNode; // Forward declaration. - - struct TrieEdge { - TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {} - - StringRef _subString; - struct TrieNode *_child; - }; - - struct TrieNode { - TrieNode(StringRef s) - : _cummulativeString(s), _address(0), _flags(0), _other(0), - _trieOffset(0), _hasExportInfo(false) {} - ~TrieNode() = default; - - void addSymbol(const Export &entry, BumpPtrAllocator &allocator, - std::vector &allNodes); - bool updateOffset(uint32_t &offset); - void appendToByteBuffer(ByteBuffer &out); - - private: - StringRef _cummulativeString; - std::list _children; - uint64_t _address; - uint64_t _flags; - uint64_t _other; - StringRef _importedName; - uint32_t _trieOffset; - bool _hasExportInfo; - }; - struct SegExtraInfo { uint32_t fileOffset; uint32_t fileSize; @@ -1077,9 +1114,9 @@ void MachOFileLayout::buildLazyBindInfo() { _lazyBindingInfo.align(_is64 ? 8 : 4); } -void MachOFileLayout::TrieNode::addSymbol(const Export& entry, - BumpPtrAllocator &allocator, - std::vector &allNodes) { +void TrieNode::addSymbol(const Export& entry, + BumpPtrAllocator &allocator, + std::vector &allNodes) { StringRef partialStr = entry.name.drop_front(_cummulativeString.size()); for (TrieEdge &edge : _children) { StringRef edgeStr = edge._subString; @@ -1108,7 +1145,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry, abEdge._subString = abEdgeStr; abEdge._child = bNode; auto *bcEdge = new (allocator) TrieEdge(bcEdgeStr, cNode); - bNode->_children.push_back(std::move(*bcEdge)); + bNode->_children.insert(bNode->_children.end(), bcEdge); bNode->addSymbol(entry, allocator, allNodes); return; } @@ -1123,7 +1160,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry, // No commonality with any existing child, make a new edge. auto *newNode = new (allocator) TrieNode(entry.name.copy(allocator)); auto *newEdge = new (allocator) TrieEdge(partialStr, newNode); - _children.push_back(std::move(*newEdge)); + _children.insert(_children.end(), newEdge); DEBUG_WITH_TYPE("trie-builder", llvm::dbgs() << "new TrieNode('" << entry.name << "') with edge '" << partialStr << "' from node='" @@ -1137,7 +1174,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry, allNodes.push_back(newNode); } -bool MachOFileLayout::TrieNode::updateOffset(uint32_t& offset) { +bool TrieNode::updateOffset(uint32_t& offset) { uint32_t nodeSize = 1; // Length when no export info if (_hasExportInfo) { if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) { @@ -1169,7 +1206,7 @@ bool MachOFileLayout::TrieNode::updateOffset(uint32_t& offset) { return result; } -void MachOFileLayout::TrieNode::appendToByteBuffer(ByteBuffer &out) { +void TrieNode::appendToByteBuffer(ByteBuffer &out) { if (_hasExportInfo) { if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) { if (!_importedName.empty()) {