Index: lld/trunk/COFF/Chunks.h =================================================================== --- lld/trunk/COFF/Chunks.h +++ lld/trunk/COFF/Chunks.h @@ -50,7 +50,7 @@ // doesn't even have actual data (if common or bss). class Chunk { public: - enum Kind { SectionKind, OtherKind }; + enum Kind : uint8_t { SectionKind, OtherKind }; Kind kind() const { return ChunkKind; } virtual ~Chunk() = default; @@ -107,6 +107,12 @@ Chunk(Kind K = OtherKind) : ChunkKind(K) {} const Kind ChunkKind; +public: + // Whether this section needs to be kept distinct from other sections during + // ICF. This is set by the driver using address-significance tables. + bool KeepUnique = false; + +protected: // The RVA of this chunk in the output. The writer sets a value. uint64_t RVA = 0; @@ -116,10 +122,6 @@ public: // The offset from beginning of the output section. The writer sets a value. uint64_t OutputSectionOff = 0; - - // Whether this section needs to be kept distinct from other sections during - // ICF. This is set by the driver using address-significance tables. - bool KeepUnique = false; }; // A chunk corresponding a section of an input file. @@ -192,8 +194,34 @@ symbol_iterator(File, Relocs.end())); } + // Single linked list iterator for associated comdat children. + class AssociatedIterator + : public llvm::iterator_facade_base< + AssociatedIterator, std::forward_iterator_tag, SectionChunk> { + public: + AssociatedIterator() = default; + AssociatedIterator(SectionChunk *Head) : Cur(Head) {} + AssociatedIterator &operator=(const AssociatedIterator &R) { + Cur = R.Cur; + return *this; + } + bool operator==(const AssociatedIterator &R) const { return Cur == R.Cur; } + const SectionChunk &operator*() const { return *Cur; } + SectionChunk &operator*() { return *Cur; } + AssociatedIterator &operator++() { + Cur = Cur->AssocChildren; + return *this; + } + + private: + SectionChunk *Cur = nullptr; + }; + // Allow iteration over the associated child chunks for this section. - ArrayRef children() const { return AssocChildren; } + llvm::iterator_range children() const { + return llvm::make_range(AssociatedIterator(AssocChildren), + AssociatedIterator(nullptr)); + } // The section ID this chunk belongs to in its Obj. uint32_t getSectionNumber() const; @@ -208,35 +236,37 @@ bool isHotPatchable() const override { return File->HotPatchable; } - // A pointer pointing to a replacement for this chunk. - // Initially it points to "this" object. If this chunk is merged - // with other chunk by ICF, it points to another chunk, - // and this chunk is considered as dead. - SectionChunk *Repl; - - // The CRC of the contents as described in the COFF spec 4.5.5. - // Auxiliary Format 5: Section Definitions. Used for ICF. - uint32_t Checksum = 0; - - const coff_section *Header; - // The file that this chunk was created from. ObjFile *File; + // Pointer to the COFF section header in the input file. + const coff_section *Header; + // The COMDAT leader symbol if this is a COMDAT chunk. DefinedRegular *Sym = nullptr; - // The COMDAT selection if this is a COMDAT chunk. - llvm::COFF::COMDATType Selection = (llvm::COFF::COMDATType)0; - + // Relocations for this section. ArrayRef Relocs; + // The CRC of the contents as described in the COFF spec 4.5.5. + // Auxiliary Format 5: Section Definitions. Used for ICF. + uint32_t Checksum = 0; + // Used by the garbage collector. bool Live; + // The COMDAT selection if this is a COMDAT chunk. + llvm::COFF::COMDATType Selection = (llvm::COFF::COMDATType)0; + + // A pointer pointing to a replacement for this chunk. + // Initially it points to "this" object. If this chunk is merged + // with other chunk by ICF, it points to another chunk, + // and this chunk is considered as dead. + SectionChunk *Repl; + private: StringRef SectionName; - std::vector AssocChildren; + SectionChunk *AssocChildren = nullptr; // Used for ICF (Identical COMDAT Folding) void replace(SectionChunk *Other); Index: lld/trunk/COFF/Chunks.cpp =================================================================== --- lld/trunk/COFF/Chunks.cpp +++ lld/trunk/COFF/Chunks.cpp @@ -30,8 +30,8 @@ namespace coff { SectionChunk::SectionChunk(ObjFile *F, const coff_section *H) - : Chunk(SectionKind), Repl(this), Header(H), File(F), - Relocs(File->getCOFFObj()->getRelocations(Header)) { + : Chunk(SectionKind), File(F), Header(H), + Relocs(File->getCOFFObj()->getRelocations(Header)), Repl(this) { // Initialize SectionName. File->getCOFFObj()->getSectionName(Header, SectionName); @@ -44,6 +44,11 @@ Live = !Config->DoGC || !isCOMDAT(); } +// SectionChunk is one of the most frequently allocated classes, so it is +// important to keep it as compact as possible. As of this writing, the number +// below is the size of this class on x64 platforms. +static_assert(sizeof(SectionChunk) <= 128, "SectionChunk grew unexpectedly"); + static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } @@ -394,7 +399,11 @@ } void SectionChunk::addAssociative(SectionChunk *Child) { - AssocChildren.push_back(Child); + // Insert this child at the head of the list. + assert(Child->AssocChildren == nullptr && + "associated sections cannot have their own associated children"); + Child->AssocChildren = AssocChildren; + AssocChildren = Child; } static uint8_t getBaserelType(const coff_relocation &Rel) { Index: lld/trunk/COFF/ICF.cpp =================================================================== --- lld/trunk/COFF/ICF.cpp +++ lld/trunk/COFF/ICF.cpp @@ -129,10 +129,10 @@ bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) { auto ChildClasses = [&](const SectionChunk *SC) { std::vector Classes; - for (const SectionChunk *C : SC->children()) - if (!C->SectionName.startswith(".debug") && - C->SectionName != ".gfids$y" && C->SectionName != ".gljmp$y") - Classes.push_back(C->Class[Cnt % 2]); + for (const SectionChunk &C : SC->children()) + if (!C.SectionName.startswith(".debug") && + C.SectionName != ".gfids$y" && C.SectionName != ".gljmp$y") + Classes.push_back(C.Class[Cnt % 2]); return Classes; }; return ChildClasses(A) == ChildClasses(B); Index: lld/trunk/COFF/MarkLive.cpp =================================================================== --- lld/trunk/COFF/MarkLive.cpp +++ lld/trunk/COFF/MarkLive.cpp @@ -64,8 +64,8 @@ AddSym(B); // Mark associative sections if any. - for (SectionChunk *C : SC->children()) - Enqueue(C); + for (SectionChunk &C : SC->children()) + Enqueue(&C); } } Index: llvm/trunk/include/llvm/BinaryFormat/COFF.h =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/COFF.h +++ llvm/trunk/include/llvm/BinaryFormat/COFF.h @@ -402,7 +402,7 @@ IMAGE_REL_ARM64_REL32 = 0x0011, }; -enum COMDATType : unsigned { +enum COMDATType : uint8_t { IMAGE_COMDAT_SELECT_NODUPLICATES = 1, IMAGE_COMDAT_SELECT_ANY, IMAGE_COMDAT_SELECT_SAME_SIZE,