[ELF] Make InputFile smaller
authorFangrui Song <i@maskray.me>
Wed, 15 Dec 2021 04:55:32 +0000 (20:55 -0800)
committerFangrui Song <i@maskray.me>
Wed, 15 Dec 2021 04:55:32 +0000 (20:55 -0800)
sizeof(ObjFile<ELF64LE>) is decreased from 344 to 272 on an ELF64 system.
In a large link with 30000 ObjFiles, this may be 2+MiB saving.

Change std::vector members to SmallVector, and std::string members to
SmallString<0> (these members typically don't benefit from small string optimization).
On Linux x86-64 the lld executable is ~6k smaller.

lld/ELF/Config.h
lld/ELF/InputFiles.cpp
lld/ELF/InputFiles.h
lld/ELF/InputSection.cpp

index c660a8e..f0f8eb8 100644 (file)
@@ -30,7 +30,7 @@ namespace elf {
 class InputFile;
 class InputSectionBase;
 
-enum ELFKind {
+enum ELFKind : uint8_t {
   ELFNoneKind,
   ELF32LEKind,
   ELF32BEKind,
index 90a4eb0..63f83a4 100644 (file)
@@ -59,11 +59,11 @@ std::string lld::toString(const InputFile *f) {
 
   if (f->toStringCache.empty()) {
     if (f->archiveName.empty())
-      f->toStringCache = std::string(f->getName());
+      f->toStringCache = f->getName();
     else
-      f->toStringCache = (f->archiveName + "(" + f->getName() + ")").str();
+      (f->archiveName + "(" + f->getName() + ")").toVector(f->toStringCache);
   }
-  return f->toStringCache;
+  return std::string(f->toStringCache);
 }
 
 static ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) {
@@ -384,7 +384,7 @@ template <class ELFT> void ELFFileBase::init() {
     fatal(toString(this) + ": invalid sh_info in symbol table");
 
   elfSyms = reinterpret_cast<const void *>(eSyms.data());
-  numELFSyms = eSyms.size();
+  numELFSyms = uint32_t(eSyms.size());
   stringTable = CHECK(obj.getStringTableForSymtab(*symtabSec, sections), this);
 }
 
@@ -1642,7 +1642,7 @@ static uint8_t getOsAbi(const Triple &t) {
 BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
                          uint64_t offsetInArchive)
     : InputFile(BitcodeKind, mb) {
-  this->archiveName = std::string(archiveName);
+  this->archiveName = archiveName;
 
   std::string path = mb.getBufferIdentifier().str();
   if (config->thinLTOIndexOnly)
index 5bbfb76..ec6f1a7 100644 (file)
@@ -54,8 +54,15 @@ void parseFile(InputFile *file);
 
 // The root class of input files.
 class InputFile {
+private:
+  // Cache for getNameForScript().
+  mutable SmallString<0> nameForScriptCache;
+
+protected:
+  SmallVector<InputSectionBase *, 0> sections;
+
 public:
-  enum Kind {
+  enum Kind : uint8_t {
     ObjKind,
     SharedKind,
     LazyObjKind,
@@ -96,27 +103,40 @@ public:
 
   // If not empty, this stores the name of the archive containing this file.
   // We use this string for creating error messages.
-  std::string archiveName;
+  SmallString<0> archiveName;
+
+  // Cache for toString(). Only toString() should use this member.
+  mutable SmallString<0> toStringCache;
+
+  SmallVector<Symbol *, 0> symbols;
+
+  // Index of MIPS GOT built for this file.
+  llvm::Optional<uint32_t> mipsGotIndex;
+
+  // outSecOff of .got2 in the current file. This is used by PPC32 -fPIC/-fPIE
+  // to compute offsets in PLT call stubs.
+  uint32_t ppc32Got2OutSecOff = 0;
+
+  // groupId is used for --warn-backrefs which is an optional error
+  // checking feature. All files within the same --{start,end}-group or
+  // --{start,end}-lib get the same group ID. Otherwise, each file gets a new
+  // group ID. For more info, see checkDependency() in SymbolTable.cpp.
+  uint32_t groupId;
+  static bool isInGroup;
+  static uint32_t nextGroupId;
 
   // If this is an architecture-specific file, the following members
   // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
-  ELFKind ekind = ELFNoneKind;
   uint16_t emachine = llvm::ELF::EM_NONE;
+  const Kind fileKind;
+  ELFKind ekind = ELFNoneKind;
   uint8_t osabi = 0;
   uint8_t abiVersion = 0;
-
-  // Cache for toString(). Only toString() should use this member.
-  mutable std::string toStringCache;
-
-  std::string getSrcMsg(const Symbol &sym, InputSectionBase &sec,
-                        uint64_t offset);
-
   // True if this is an argument for --just-symbols. Usually false.
   bool justSymbols = false;
 
-  // outSecOff of .got2 in the current file. This is used by PPC32 -fPIC/-fPIE
-  // to compute offsets in PLT call stubs.
-  uint32_t ppc32Got2OutSecOff = 0;
+  std::string getSrcMsg(const Symbol &sym, InputSectionBase &sec,
+                        uint64_t offset);
 
   // On PPC64 we need to keep track of which files contain small code model
   // relocations that access the .toc section. To minimize the chance of a
@@ -133,28 +153,8 @@ public:
   // R_PPC64_TLSLD. Disable TLS relaxation to avoid bad code generation.
   bool ppc64DisableTLSRelax = false;
 
-  // groupId is used for --warn-backrefs which is an optional error
-  // checking feature. All files within the same --{start,end}-group or
-  // --{start,end}-lib get the same group ID. Otherwise, each file gets a new
-  // group ID. For more info, see checkDependency() in SymbolTable.cpp.
-  uint32_t groupId;
-  static bool isInGroup;
-  static uint32_t nextGroupId;
-
-  // Index of MIPS GOT built for this file.
-  llvm::Optional<size_t> mipsGotIndex;
-
-  std::vector<Symbol *> symbols;
-
 protected:
   InputFile(Kind k, MemoryBufferRef m);
-  std::vector<InputSectionBase *> sections;
-
-private:
-  const Kind fileKind;
-
-  // Cache for getNameForScript().
-  mutable std::string nameForScriptCache;
 };
 
 class ELFFileBase : public InputFile {
@@ -190,7 +190,7 @@ protected:
   template <typename ELFT> void init();
 
   const void *elfSyms = nullptr;
-  size_t numELFSyms = 0;
+  uint32_t numELFSyms = 0;
   uint32_t firstGlobal = 0;
   StringRef stringTable;
 };
@@ -207,7 +207,7 @@ public:
   }
 
   ObjFile(MemoryBufferRef m, StringRef archiveName) : ELFFileBase(ObjKind, m) {
-    this->archiveName = std::string(archiveName);
+    this->archiveName = archiveName;
   }
 
   void parse(bool ignoreComdats = false);
@@ -231,6 +231,17 @@ public:
   llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
   llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef name);
 
+  // Name of source file obtained from STT_FILE symbol value,
+  // or empty string if there is no such symbol in object file
+  // symbol table.
+  StringRef sourceFile;
+
+  // Pointer to this input file's .llvm_addrsig section, if it has one.
+  const Elf_Shdr *addrsigSec = nullptr;
+
+  // SHT_LLVM_CALL_GRAPH_PROFILE section index.
+  uint32_t cgProfileSectionIndex = 0;
+
   // MIPS GP0 value defined by this file. This value represents the gp value
   // used to create the relocatable object and required to support
   // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
@@ -238,11 +249,6 @@ public:
 
   uint32_t andFeatures = 0;
 
-  // Name of source file obtained from STT_FILE symbol value,
-  // or empty string if there is no such symbol in object file
-  // symbol table.
-  StringRef sourceFile;
-
   // True if the file defines functions compiled with
   // -fsplit-stack. Usually false.
   bool splitStack = false;
@@ -251,12 +257,6 @@ public:
   // but had one or more functions with the no_split_stack attribute.
   bool someNoSplitStack = false;
 
-  // Pointer to this input file's .llvm_addrsig section, if it has one.
-  const Elf_Shdr *addrsigSec = nullptr;
-
-  // SHT_LLVM_CALL_GRAPH_PROFILE section index.
-  uint32_t cgProfileSectionIndex = 0;
-
   // Get cached DWARF information.
   DWARFCache *getDwarf();
 
@@ -306,7 +306,7 @@ public:
   LazyObjFile(MemoryBufferRef m, StringRef archiveName,
               uint64_t offsetInArchive)
       : InputFile(LazyObjKind, m), offsetInArchive(offsetInArchive) {
-    this->archiveName = std::string(archiveName);
+    this->archiveName = archiveName;
   }
 
   static bool classof(const InputFile *f) { return f->kind() == LazyObjKind; }
index a9185f8..b2f6379 100644 (file)
@@ -325,7 +325,7 @@ std::string InputSectionBase::getObjMsg(uint64_t off) {
 
   std::string archive;
   if (!file->archiveName.empty())
-    archive = " in archive " + file->archiveName;
+    archive = (" in archive " + file->archiveName).str();
 
   // Find a symbol that encloses a given location.
   for (Symbol *b : file->getSymbols())