[llvm] b4fa71e - [LLD] Remove global state in lld/COFF

Amy Huang via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 16 11:02:36 PDT 2021


Author: Amy Huang
Date: 2021-09-16T11:00:23-07:00
New Revision: b4fa71eed34d967195514fe9b0a5211fca2bc5bc

URL: https://github.com/llvm/llvm-project/commit/b4fa71eed34d967195514fe9b0a5211fca2bc5bc
DIFF: https://github.com/llvm/llvm-project/commit/b4fa71eed34d967195514fe9b0a5211fca2bc5bc.diff

LOG: [LLD] Remove global state in lld/COFF

This patch removes globals from the lldCOFF library, by moving globals
into a context class (COFFLinkingContext) and passing it around wherever
it's needed.

See https://lists.llvm.org/pipermail/llvm-dev/2021-June/151184.html for
context about removing globals from LLD.

I also haven't moved the `driver` or `config` variables yet.

Differential Revision: https://reviews.llvm.org/D109634

Added: 
    lld/COFF/COFFLinkerContext.cpp
    lld/COFF/COFFLinkerContext.h

Modified: 
    lld/COFF/CMakeLists.txt
    lld/COFF/CallGraphSort.cpp
    lld/COFF/CallGraphSort.h
    lld/COFF/Chunks.cpp
    lld/COFF/Chunks.h
    lld/COFF/DLL.cpp
    lld/COFF/DLL.h
    lld/COFF/DebugTypes.cpp
    lld/COFF/DebugTypes.h
    lld/COFF/Driver.cpp
    lld/COFF/Driver.h
    lld/COFF/ICF.cpp
    lld/COFF/ICF.h
    lld/COFF/InputFiles.cpp
    lld/COFF/InputFiles.h
    lld/COFF/LLDMapFile.cpp
    lld/COFF/LLDMapFile.h
    lld/COFF/LTO.cpp
    lld/COFF/LTO.h
    lld/COFF/MapFile.cpp
    lld/COFF/MapFile.h
    lld/COFF/MarkLive.cpp
    lld/COFF/MarkLive.h
    lld/COFF/MinGW.cpp
    lld/COFF/MinGW.h
    lld/COFF/PDB.cpp
    lld/COFF/PDB.h
    lld/COFF/SymbolTable.cpp
    lld/COFF/SymbolTable.h
    lld/COFF/TypeMerger.h
    lld/COFF/Writer.cpp
    lld/COFF/Writer.h
    lld/Common/Timer.cpp
    lld/include/lld/Common/Timer.h
    llvm/utils/gn/secondary/lld/COFF/BUILD.gn

Removed: 
    


################################################################################
diff  --git a/lld/COFF/CMakeLists.txt b/lld/COFF/CMakeLists.txt
index bbcd337b210f3..b32b9cfcff04e 100644
--- a/lld/COFF/CMakeLists.txt
+++ b/lld/COFF/CMakeLists.txt
@@ -5,6 +5,7 @@ add_public_tablegen_target(COFFOptionsTableGen)
 add_lld_library(lldCOFF
   CallGraphSort.cpp
   Chunks.cpp
+  COFFLinkerContext.cpp
   DebugTypes.cpp
   DLL.cpp
   Driver.cpp

diff  --git a/lld/COFF/COFFLinkerContext.cpp b/lld/COFF/COFFLinkerContext.cpp
new file mode 100644
index 0000000000000..39da96a9ecf17
--- /dev/null
+++ b/lld/COFF/COFFLinkerContext.cpp
@@ -0,0 +1,53 @@
+//===- COFFContext.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Description
+//
+//===----------------------------------------------------------------------===//
+
+#include "COFFLinkerContext.h"
+#include "lld/Common/Memory.h"
+#include "llvm/DebugInfo/CodeView/TypeHashing.h"
+
+namespace lld {
+namespace coff {
+
+COFFLinkerContext::COFFLinkerContext()
+    : symtab(*this), rootTimer("Total Linking Time"),
+      inputFileTimer("Input File Reading", rootTimer),
+      ltoTimer("LTO", rootTimer), gcTimer("GC", rootTimer),
+      icfTimer("ICF", rootTimer), codeLayoutTimer("Code Layout", rootTimer),
+      outputCommitTimer("Commit Output File", rootTimer),
+      totalMapTimer("MAP Emission (Cumulative)", rootTimer),
+      symbolGatherTimer("Gather Symbols", totalMapTimer),
+      symbolStringsTimer("Build Symbol strings", totalMapTimer),
+      writeTimer("Write to File", totalMapTimer),
+      totalPdbLinkTimer("PDB Emission (Cumulative)", rootTimer),
+      addObjectsTimer("Add Objects", totalPdbLinkTimer),
+      symbolMergingTimer("Symbol Merging", addObjectsTimer),
+      typeMergingTimer("Type Merging", addObjectsTimer),
+      tpiStreamLayoutTimer("TPI Stream Layout", totalPdbLinkTimer),
+      publicsLayoutTimer("Publics Stream Layout", totalPdbLinkTimer),
+      diskCommitTimer("Commit to Disk", totalPdbLinkTimer),
+      loadGHashTimer("Global Type Hashing", addObjectsTimer),
+      mergeGHashTimer("GHash Type Merging", addObjectsTimer) {}
+
+COFFLinkerContext::~COFFLinkerContext() { clearGHashes(); }
+
+void COFFLinkerContext::clearGHashes() {
+  for (TpiSource *src : tpiSourceList) {
+    if (src->ownedGHashes)
+      delete[] src->ghashes.data();
+    src->ghashes = {};
+    src->isItemIndex.clear();
+    src->uniqueTypes.clear();
+  }
+}
+
+} // namespace coff
+} // namespace lld

diff  --git a/lld/COFF/COFFLinkerContext.h b/lld/COFF/COFFLinkerContext.h
new file mode 100644
index 0000000000000..594c9fde89a2d
--- /dev/null
+++ b/lld/COFF/COFFLinkerContext.h
@@ -0,0 +1,88 @@
+//===- COFFLinkerContext.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_COFFLinkerContext_H
+#define LLD_COFF_COFFLinkerContext_H
+
+#include "Chunks.h"
+#include "Config.h"
+#include "DebugTypes.h"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Writer.h"
+#include "lld/Common/Timer.h"
+
+namespace lld {
+namespace coff {
+
+class COFFLinkerContext {
+public:
+  COFFLinkerContext();
+  COFFLinkerContext(const COFFLinkerContext &) = delete;
+  COFFLinkerContext &operator=(const COFFLinkerContext &) = delete;
+  ~COFFLinkerContext();
+
+  void addTpiSource(TpiSource *tpi) { tpiSourceList.push_back(tpi); }
+
+  /// Free heap allocated ghashes.
+  void clearGHashes();
+
+  SymbolTable symtab;
+
+  std::vector<ObjFile *> objFileInstances;
+  std::map<std::string, PDBInputFile *> pdbInputFileInstances;
+  std::vector<ImportFile *> importFileInstances;
+  std::vector<BitcodeFile *> bitcodeFileInstances;
+
+  MergeChunk *mergeChunkInstances[Log2MaxSectionAlignment + 1] = {};
+
+  /// All sources of type information in the program.
+  std::vector<TpiSource *> tpiSourceList;
+
+  std::map<llvm::codeview::GUID, TpiSource *> typeServerSourceMappings;
+  std::map<uint32_t, TpiSource *> precompSourceMappings;
+
+  /// List of all output sections. After output sections are finalized, this
+  /// can be indexed by getOutputSection.
+  std::vector<OutputSection *> outputSections;
+
+  OutputSection *getOutputSection(const Chunk *c) const {
+    return c->osidx == 0 ? nullptr : outputSections[c->osidx - 1];
+  }
+
+  // All timers used in the COFF linker.
+  Timer rootTimer;
+  Timer inputFileTimer;
+  Timer ltoTimer;
+  Timer gcTimer;
+  Timer icfTimer;
+
+  // Writer timers.
+  Timer codeLayoutTimer;
+  Timer outputCommitTimer;
+  Timer totalMapTimer;
+  Timer symbolGatherTimer;
+  Timer symbolStringsTimer;
+  Timer writeTimer;
+
+  // PDB timers.
+  Timer totalPdbLinkTimer;
+  Timer addObjectsTimer;
+  Timer symbolMergingTimer;
+  Timer typeMergingTimer;
+  Timer tpiStreamLayoutTimer;
+  Timer publicsLayoutTimer;
+  Timer diskCommitTimer;
+  Timer loadGHashTimer;
+  Timer mergeGHashTimer;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif

diff  --git a/lld/COFF/CallGraphSort.cpp b/lld/COFF/CallGraphSort.cpp
index d3e5312ce7fdd..709e69b24914b 100644
--- a/lld/COFF/CallGraphSort.cpp
+++ b/lld/COFF/CallGraphSort.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CallGraphSort.h"
+#include "COFFLinkerContext.h"
 #include "InputFiles.h"
 #include "SymbolTable.h"
 #include "Symbols.h"
@@ -48,7 +49,7 @@ struct Cluster {
 
 class CallGraphSort {
 public:
-  CallGraphSort();
+  CallGraphSort(const COFFLinkerContext &ctx);
 
   DenseMap<const SectionChunk *, int> run();
 
@@ -70,7 +71,7 @@ using SectionPair = std::pair<const SectionChunk *, const SectionChunk *>;
 // Take the edge list in Config->CallGraphProfile, resolve symbol names to
 // Symbols, and generate a graph between InputSections with the provided
 // weights.
-CallGraphSort::CallGraphSort() {
+CallGraphSort::CallGraphSort(const COFFLinkerContext &ctx) {
   MapVector<SectionPair, uint64_t> &profile = config->callGraphProfile;
   DenseMap<const SectionChunk *, int> secToCluster;
 
@@ -95,7 +96,7 @@ CallGraphSort::CallGraphSort() {
     // output.  This messes with the cluster size and density calculations.  We
     // would also end up moving input sections in other output sections without
     // moving them closer to what calls them.
-    if (fromSec->getOutputSection() != toSec->getOutputSection())
+    if (ctx.getOutputSection(fromSec) != ctx.getOutputSection(toSec))
       continue;
 
     int from = getOrCreateNode(fromSec);
@@ -240,6 +241,7 @@ DenseMap<const SectionChunk *, int> CallGraphSort::run() {
 // This first builds a call graph based on the profile data then merges sections
 // according to the C³ heuristic. All clusters are then sorted by a density
 // metric to further improve locality.
-DenseMap<const SectionChunk *, int> coff::computeCallGraphProfileOrder() {
-  return CallGraphSort().run();
+DenseMap<const SectionChunk *, int>
+coff::computeCallGraphProfileOrder(const COFFLinkerContext &ctx) {
+  return CallGraphSort(ctx).run();
 }

diff  --git a/lld/COFF/CallGraphSort.h b/lld/COFF/CallGraphSort.h
index e4f372137448c..99f35d6b62762 100644
--- a/lld/COFF/CallGraphSort.h
+++ b/lld/COFF/CallGraphSort.h
@@ -14,8 +14,10 @@
 namespace lld {
 namespace coff {
 class SectionChunk;
+class COFFLinkerContext;
 
-llvm::DenseMap<const SectionChunk *, int> computeCallGraphProfileOrder();
+llvm::DenseMap<const SectionChunk *, int>
+computeCallGraphProfileOrder(const COFFLinkerContext &ctx);
 } // namespace coff
 } // namespace lld
 

diff  --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 36d5f371326fe..9f6dbd1725096 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -7,10 +7,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "Chunks.h"
+#include "COFFLinkerContext.h"
 #include "InputFiles.h"
+#include "SymbolTable.h"
 #include "Symbols.h"
 #include "Writer.h"
-#include "SymbolTable.h"
 #include "lld/Common/ErrorHandler.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/COFF.h"
@@ -385,7 +386,7 @@ void SectionChunk::applyRelocation(uint8_t *off,
   // section is needed to compute SECREL and SECTION relocations used in debug
   // info.
   Chunk *c = sym ? sym->getChunk() : nullptr;
-  OutputSection *os = c ? c->getOutputSection() : nullptr;
+  OutputSection *os = c ? file->ctx.getOutputSection(c) : nullptr;
 
   // Skip the relocation if it refers to a discarded section, and diagnose it
   // as an error if appropriate. If a symbol was discarded early, it may be
@@ -938,18 +939,16 @@ uint8_t Baserel::getDefaultType() {
   }
 }
 
-MergeChunk *MergeChunk::instances[Log2MaxSectionAlignment + 1] = {};
-
 MergeChunk::MergeChunk(uint32_t alignment)
     : builder(StringTableBuilder::RAW, alignment) {
   setAlignment(alignment);
 }
 
-void MergeChunk::addSection(SectionChunk *c) {
+void MergeChunk::addSection(COFFLinkerContext &ctx, SectionChunk *c) {
   assert(isPowerOf2_32(c->getAlignment()));
   uint8_t p2Align = llvm::Log2_32(c->getAlignment());
-  assert(p2Align < array_lengthof(instances));
-  auto *&mc = instances[p2Align];
+  assert(p2Align < array_lengthof(ctx.mergeChunkInstances));
+  auto *&mc = ctx.mergeChunkInstances[p2Align];
   if (!mc)
     mc = make<MergeChunk>(c->getAlignment());
   mc->sections.push_back(c);

diff  --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index bdd3faa179a8a..daaa043ffaceb 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -101,7 +101,6 @@ class Chunk {
   // chunk has a back pointer to an output section.
   void setOutputSectionIdx(uint16_t o) { osidx = o; }
   uint16_t getOutputSectionIdx() const { return osidx; }
-  OutputSection *getOutputSection() const;
 
   // Windows-specific.
   // Collect all locations that contain absolute addresses for base relocations.
@@ -415,7 +414,7 @@ inline StringRef Chunk::getDebugName() const {
 class MergeChunk : public NonSectionChunk {
 public:
   MergeChunk(uint32_t alignment);
-  static void addSection(SectionChunk *c);
+  static void addSection(COFFLinkerContext &ctx, SectionChunk *c);
   void finalizeContents();
   void assignSubsectionRVAs();
 
@@ -424,7 +423,6 @@ class MergeChunk : public NonSectionChunk {
   size_t getSize() const override;
   void writeTo(uint8_t *buf) const override;
 
-  static MergeChunk *instances[Log2MaxSectionAlignment + 1];
   std::vector<SectionChunk *> sections;
 
 private:

diff  --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp
index b9e12ef4b34dd..6fec9df5617db 100644
--- a/lld/COFF/DLL.cpp
+++ b/lld/COFF/DLL.cpp
@@ -18,6 +18,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "DLL.h"
+#include "COFFLinkerContext.h"
 #include "Chunks.h"
 #include "SymbolTable.h"
 #include "llvm/Object/COFF.h"
@@ -631,7 +632,7 @@ uint64_t DelayLoadContents::getDirSize() {
   return dirs.size() * sizeof(delay_import_directory_table_entry);
 }
 
-void DelayLoadContents::create(Defined *h) {
+void DelayLoadContents::create(COFFLinkerContext &ctx, Defined *h) {
   helper = h;
   std::vector<std::vector<DefinedImportData *>> v = binImports(imports);
 
@@ -660,13 +661,13 @@ void DelayLoadContents::create(Defined *h) {
         // call targets for Control Flow Guard.
         StringRef symName = saver.save("__imp_load_" + extName);
         s->loadThunkSym =
-            cast<DefinedSynthetic>(symtab->addSynthetic(symName, t));
+            cast<DefinedSynthetic>(ctx.symtab.addSynthetic(symName, t));
       }
     }
     thunks.push_back(tm);
     StringRef tmName =
         saver.save("__tailMerge_" + syms[0]->getDLLName().lower());
-    symtab->addSynthetic(tmName, tm);
+    ctx.symtab.addSynthetic(tmName, tm);
     // Terminate with null values.
     addresses.push_back(make<NullChunk>(8));
     names.push_back(make<NullChunk>(8));

diff  --git a/lld/COFF/DLL.h b/lld/COFF/DLL.h
index ce0ee01c4a3df..0d594e675bd23 100644
--- a/lld/COFF/DLL.h
+++ b/lld/COFF/DLL.h
@@ -40,7 +40,7 @@ class DelayLoadContents {
 public:
   void add(DefinedImportData *sym) { imports.push_back(sym); }
   bool empty() { return imports.empty(); }
-  void create(Defined *helper);
+  void create(COFFLinkerContext &ctx, Defined *helper);
   std::vector<Chunk *> getChunks();
   std::vector<Chunk *> getDataChunks();
   ArrayRef<Chunk *> getCodeChunks() { return thunks; }

diff  --git a/lld/COFF/DebugTypes.cpp b/lld/COFF/DebugTypes.cpp
index 97be5bc79ac34..548b7c6325e61 100644
--- a/lld/COFF/DebugTypes.cpp
+++ b/lld/COFF/DebugTypes.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "DebugTypes.h"
+#include "COFFLinkerContext.h"
 #include "Chunks.h"
 #include "Driver.h"
 #include "InputFiles.h"
@@ -14,7 +15,6 @@
 #include "TypeMerger.h"
 #include "lld/Common/ErrorHandler.h"
 #include "lld/Common/Memory.h"
-#include "lld/Common/Timer.h"
 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
@@ -46,8 +46,8 @@ class TypeServerIpiSource;
 // before any dependent OBJ.
 class TypeServerSource : public TpiSource {
 public:
-  explicit TypeServerSource(PDBInputFile *f)
-      : TpiSource(PDB, nullptr), pdbInputFile(f) {
+  explicit TypeServerSource(COFFLinkerContext &ctx, PDBInputFile *f)
+      : TpiSource(ctx, PDB, nullptr), pdbInputFile(f) {
     if (f->loadErr && *f->loadErr)
       return;
     pdb::PDBFile &file = f->session->getPDBFile();
@@ -55,7 +55,7 @@ class TypeServerSource : public TpiSource {
     if (!expectedInfo)
       return;
     Guid = expectedInfo->getGuid();
-    auto it = mappings.emplace(Guid, this);
+    auto it = ctx.typeServerSourceMappings.emplace(Guid, this);
     assert(it.second);
     (void)it;
   }
@@ -74,8 +74,6 @@ class TypeServerSource : public TpiSource {
 
   // The PDB signature GUID.
   codeview::GUID Guid;
-
-  static std::map<codeview::GUID, TypeServerSource *> mappings;
 };
 
 // Companion to TypeServerSource. Stores the index map for the IPI stream in the
@@ -83,7 +81,8 @@ class TypeServerSource : public TpiSource {
 // invariant of one type index space per source.
 class TypeServerIpiSource : public TpiSource {
 public:
-  explicit TypeServerIpiSource() : TpiSource(PDBIpi, nullptr) {}
+  explicit TypeServerIpiSource(COFFLinkerContext &ctx)
+      : TpiSource(ctx, PDBIpi, nullptr) {}
 
   friend class TypeServerSource;
 
@@ -101,8 +100,8 @@ class UseTypeServerSource : public TpiSource {
   Expected<TypeServerSource *> getTypeServerSource();
 
 public:
-  UseTypeServerSource(ObjFile *f, TypeServer2Record ts)
-      : TpiSource(UsingPDB, f), typeServerDependency(ts) {}
+  UseTypeServerSource(COFFLinkerContext &ctx, ObjFile *f, TypeServer2Record ts)
+      : TpiSource(ctx, UsingPDB, f), typeServerDependency(ts) {}
 
   Error mergeDebugT(TypeMerger *m) override;
 
@@ -121,11 +120,11 @@ class UseTypeServerSource : public TpiSource {
 // such files, clang does not.
 class PrecompSource : public TpiSource {
 public:
-  PrecompSource(ObjFile *f) : TpiSource(PCH, f) {
+  PrecompSource(COFFLinkerContext &ctx, ObjFile *f) : TpiSource(ctx, PCH, f) {
     if (!f->pchSignature || !*f->pchSignature)
       fatal(toString(f) +
             " claims to be a PCH object, but does not have a valid signature");
-    auto it = mappings.emplace(*f->pchSignature, this);
+    auto it = ctx.precompSourceMappings.emplace(*f->pchSignature, this);
     if (!it.second)
       fatal("a PCH object with the same signature has already been provided (" +
             toString(it.first->second->file) + " and " + toString(file) + ")");
@@ -134,16 +133,14 @@ class PrecompSource : public TpiSource {
   void loadGHashes() override;
 
   bool isDependency() const override { return true; }
-
-  static std::map<uint32_t, PrecompSource *> mappings;
 };
 
 // This class represents the debug type stream of an OBJ file that depends on a
 // Microsoft precompiled headers OBJ (see PrecompSource).
 class UsePrecompSource : public TpiSource {
 public:
-  UsePrecompSource(ObjFile *f, PrecompRecord precomp)
-      : TpiSource(UsingPCH, f), precompDependency(precomp) {}
+  UsePrecompSource(COFFLinkerContext &ctx, ObjFile *f, PrecompRecord precomp)
+      : TpiSource(ctx, UsingPCH, f), precompDependency(precomp) {}
 
   Error mergeDebugT(TypeMerger *m) override;
 
@@ -153,6 +150,10 @@ class UsePrecompSource : public TpiSource {
 private:
   Error mergeInPrecompHeaderObj();
 
+  PrecompSource *findObjByName(StringRef fileNameOnly);
+  PrecompSource *findPrecompSource(ObjFile *file, PrecompRecord &pr);
+  Expected<PrecompSource *> findPrecompMap(ObjFile *file, PrecompRecord &pr);
+
 public:
   // Information about the Precomp OBJ dependency, that needs to be loaded in
   // before merging this OBJ.
@@ -160,13 +161,9 @@ class UsePrecompSource : public TpiSource {
 };
 } // namespace
 
-std::vector<TpiSource *> TpiSource::instances;
-ArrayRef<TpiSource *> TpiSource::dependencySources;
-ArrayRef<TpiSource *> TpiSource::objectSources;
-
-TpiSource::TpiSource(TpiKind k, ObjFile *f)
-    : kind(k), tpiSrcIdx(instances.size()), file(f) {
-  instances.push_back(this);
+TpiSource::TpiSource(COFFLinkerContext &ctx, TpiKind k, ObjFile *f)
+    : ctx(ctx), kind(k), tpiSrcIdx(ctx.tpiSourceList.size()), file(f) {
+  ctx.addTpiSource(this);
 }
 
 // Vtable key method.
@@ -175,52 +172,35 @@ TpiSource::~TpiSource() {
   consumeError(std::move(typeMergingError));
 }
 
-void TpiSource::sortDependencies() {
-  // Order dependencies first, but preserve the existing order.
-  std::vector<TpiSource *> deps;
-  std::vector<TpiSource *> objs;
-  for (TpiSource *s : instances)
-    (s->isDependency() ? deps : objs).push_back(s);
-  uint32_t numDeps = deps.size();
-  uint32_t numObjs = objs.size();
-  instances = std::move(deps);
-  instances.insert(instances.end(), objs.begin(), objs.end());
-  for (uint32_t i = 0, e = instances.size(); i < e; ++i)
-    instances[i]->tpiSrcIdx = i;
-  dependencySources = makeArrayRef(instances.data(), numDeps);
-  objectSources = makeArrayRef(instances.data() + numDeps, numObjs);
-}
-
-TpiSource *lld::coff::makeTpiSource(ObjFile *file) {
-  return make<TpiSource>(TpiSource::Regular, file);
+TpiSource *lld::coff::makeTpiSource(COFFLinkerContext &ctx, ObjFile *file) {
+  return make<TpiSource>(ctx, TpiSource::Regular, file);
 }
 
-TpiSource *lld::coff::makeTypeServerSource(PDBInputFile *pdbInputFile) {
+TpiSource *lld::coff::makeTypeServerSource(COFFLinkerContext &ctx,
+                                           PDBInputFile *pdbInputFile) {
   // Type server sources come in pairs: the TPI stream, and the IPI stream.
-  auto *tpiSource = make<TypeServerSource>(pdbInputFile);
+  auto *tpiSource = make<TypeServerSource>(ctx, pdbInputFile);
   if (pdbInputFile->session->getPDBFile().hasPDBIpiStream())
-    tpiSource->ipiSrc = make<TypeServerIpiSource>();
+    tpiSource->ipiSrc = make<TypeServerIpiSource>(ctx);
   return tpiSource;
 }
 
-TpiSource *lld::coff::makeUseTypeServerSource(ObjFile *file,
+TpiSource *lld::coff::makeUseTypeServerSource(COFFLinkerContext &ctx,
+                                              ObjFile *file,
                                               TypeServer2Record ts) {
-  return make<UseTypeServerSource>(file, ts);
+  return make<UseTypeServerSource>(ctx, file, ts);
 }
 
-TpiSource *lld::coff::makePrecompSource(ObjFile *file) {
-  return make<PrecompSource>(file);
+TpiSource *lld::coff::makePrecompSource(COFFLinkerContext &ctx, ObjFile *file) {
+  return make<PrecompSource>(ctx, file);
 }
 
-TpiSource *lld::coff::makeUsePrecompSource(ObjFile *file,
+TpiSource *lld::coff::makeUsePrecompSource(COFFLinkerContext &ctx,
+                                           ObjFile *file,
                                            PrecompRecord precomp) {
-  return make<UsePrecompSource>(file, precomp);
+  return make<UsePrecompSource>(ctx, file, precomp);
 }
 
-std::map<codeview::GUID, TypeServerSource *> TypeServerSource::mappings;
-
-std::map<uint32_t, PrecompSource *> PrecompSource::mappings;
-
 bool TpiSource::remapTypeIndex(TypeIndex &ti, TiRefKind refKind) const {
   if (ti.isSimple())
     return true;
@@ -419,12 +399,12 @@ Expected<TypeServerSource *> UseTypeServerSource::getTypeServerSource() {
   StringRef tsPath = typeServerDependency.getName();
 
   TypeServerSource *tsSrc;
-  auto it = TypeServerSource::mappings.find(tsId);
-  if (it != TypeServerSource::mappings.end()) {
-    tsSrc = it->second;
+  auto it = ctx.typeServerSourceMappings.find(tsId);
+  if (it != ctx.typeServerSourceMappings.end()) {
+    tsSrc = (TypeServerSource *)it->second;
   } else {
     // The file failed to load, lookup by name
-    PDBInputFile *pdb = PDBInputFile::findFromRecordPath(tsPath, file);
+    PDBInputFile *pdb = PDBInputFile::findFromRecordPath(ctx, tsPath, file);
     if (!pdb)
       return createFileError(tsPath, errorCodeToError(std::error_code(
                                          ENOENT, std::generic_category())));
@@ -471,36 +451,37 @@ static bool equalsPath(StringRef path1, StringRef path2) {
 }
 
 // Find by name an OBJ provided on the command line
-static PrecompSource *findObjByName(StringRef fileNameOnly) {
+PrecompSource *UsePrecompSource::findObjByName(StringRef fileNameOnly) {
   SmallString<128> currentPath;
-  for (auto kv : PrecompSource::mappings) {
+  for (auto kv : ctx.precompSourceMappings) {
     StringRef currentFileName = sys::path::filename(kv.second->file->getName(),
                                                     sys::path::Style::windows);
 
     // Compare based solely on the file name (link.exe behavior)
     if (equalsPath(currentFileName, fileNameOnly))
-      return kv.second;
+      return (PrecompSource *)kv.second;
   }
   return nullptr;
 }
 
-static PrecompSource *findPrecompSource(ObjFile *file, PrecompRecord &pr) {
+PrecompSource *UsePrecompSource::findPrecompSource(ObjFile *file,
+                                                   PrecompRecord &pr) {
   // Cross-compile warning: given that Clang doesn't generate LF_PRECOMP
   // records, we assume the OBJ comes from a Windows build of cl.exe. Thusly,
   // the paths embedded in the OBJs are in the Windows format.
   SmallString<128> prFileName =
       sys::path::filename(pr.getPrecompFilePath(), sys::path::Style::windows);
 
-  auto it = PrecompSource::mappings.find(pr.getSignature());
-  if (it != PrecompSource::mappings.end()) {
-    return it->second;
+  auto it = ctx.precompSourceMappings.find(pr.getSignature());
+  if (it != ctx.precompSourceMappings.end()) {
+    return (PrecompSource *)it->second;
   }
   // Lookup by name
   return findObjByName(prFileName);
 }
 
-static Expected<PrecompSource *> findPrecompMap(ObjFile *file,
-                                                PrecompRecord &pr) {
+Expected<PrecompSource *> UsePrecompSource::findPrecompMap(ObjFile *file,
+                                                           PrecompRecord &pr) {
   PrecompSource *precomp = findPrecompSource(file, pr);
 
   if (!precomp)
@@ -555,22 +536,6 @@ Error UsePrecompSource::mergeDebugT(TypeMerger *m) {
   return TpiSource::mergeDebugT(m);
 }
 
-uint32_t TpiSource::countTypeServerPDBs() {
-  return TypeServerSource::mappings.size();
-}
-
-uint32_t TpiSource::countPrecompObjs() {
-  return PrecompSource::mappings.size();
-}
-
-void TpiSource::clear() {
-  // Clean up any owned ghash allocations.
-  clearGHashes();
-  TpiSource::instances.clear();
-  TypeServerSource::mappings.clear();
-  PrecompSource::mappings.clear();
-}
-
 //===----------------------------------------------------------------------===//
 // Parellel GHash type merging implementation.
 //===----------------------------------------------------------------------===//
@@ -926,7 +891,8 @@ struct GHashTable {
   /// Insert the cell with the given ghash into the table. Return the insertion
   /// position in the table. It is safe for the caller to store the insertion
   /// position because the table cannot be resized.
-  uint32_t insert(GloballyHashedType ghash, GHashCell newCell);
+  uint32_t insert(COFFLinkerContext &ctx, GloballyHashedType ghash,
+                  GHashCell newCell);
 };
 
 /// A ghash table cell for deduplicating types from TpiSources.
@@ -965,8 +931,8 @@ class GHashCell {
   bool isItem() const { return data & (1ULL << 63U); }
 
   /// Get the ghash key for this cell.
-  GloballyHashedType getGHash() const {
-    return TpiSource::instances[getTpiSrcIdx()]->ghashes[getGHashIdx()];
+  GloballyHashedType getGHash(const COFFLinkerContext &ctx) const {
+    return ctx.tpiSourceList[getTpiSrcIdx()]->ghashes[getGHashIdx()];
   }
 
   /// The priority function for the cell. The data is stored such that lower
@@ -996,7 +962,8 @@ void GHashTable::init(uint32_t newTableSize) {
   tableSize = newTableSize;
 }
 
-uint32_t GHashTable::insert(GloballyHashedType ghash, GHashCell newCell) {
+uint32_t GHashTable::insert(COFFLinkerContext &ctx, GloballyHashedType ghash,
+                            GHashCell newCell) {
   assert(!newCell.isEmpty() && "cannot insert empty cell value");
 
   // FIXME: The low bytes of SHA1 have low entropy for short records, which
@@ -1015,7 +982,7 @@ uint32_t GHashTable::insert(GloballyHashedType ghash, GHashCell newCell) {
     // - cell has non-matching key: hash collision, probe next cell
     auto *cellPtr = reinterpret_cast<std::atomic<GHashCell> *>(&table[idx]);
     GHashCell oldCell(cellPtr->load());
-    while (oldCell.isEmpty() || oldCell.getGHash() == ghash) {
+    while (oldCell.isEmpty() || oldCell.getGHash(ctx) == ghash) {
       // Check if there is an existing ghash entry with a higher priority
       // (earlier ordering). If so, this is a duplicate, we are done.
       if (!oldCell.isEmpty() && oldCell < newCell)
@@ -1040,22 +1007,22 @@ uint32_t GHashTable::insert(GloballyHashedType ghash, GHashCell newCell) {
   llvm_unreachable("left infloop");
 }
 
-TypeMerger::TypeMerger(llvm::BumpPtrAllocator &alloc)
-    : typeTable(alloc), idTable(alloc) {}
+TypeMerger::TypeMerger(COFFLinkerContext &c, llvm::BumpPtrAllocator &alloc)
+    : typeTable(alloc), idTable(alloc), ctx(c) {}
 
 TypeMerger::~TypeMerger() = default;
 
 void TypeMerger::mergeTypesWithGHash() {
   // Load ghashes. Do type servers and PCH objects first.
   {
-    ScopedTimer t1(loadGHashTimer);
-    parallelForEach(TpiSource::dependencySources,
+    ScopedTimer t1(ctx.loadGHashTimer);
+    parallelForEach(dependencySources,
                     [&](TpiSource *source) { source->loadGHashes(); });
-    parallelForEach(TpiSource::objectSources,
+    parallelForEach(objectSources,
                     [&](TpiSource *source) { source->loadGHashes(); });
   }
 
-  ScopedTimer t2(mergeGHashTimer);
+  ScopedTimer t2(ctx.mergeGHashTimer);
   GHashState ghashState;
 
   // Estimate the size of hash table needed to deduplicate ghashes. This *must*
@@ -1066,7 +1033,7 @@ void TypeMerger::mergeTypesWithGHash() {
   // small compared to total memory usage, at eight bytes per input type record,
   // and most input type records are larger than eight bytes.
   size_t tableSize = 0;
-  for (TpiSource *source : TpiSource::instances)
+  for (TpiSource *source : ctx.tpiSourceList)
     tableSize += source->ghashes.size();
 
   // Cap the table size so that we can use 32-bit cell indices. Type indices are
@@ -1080,8 +1047,8 @@ void TypeMerger::mergeTypesWithGHash() {
   // position. Because the table does not rehash, the position will not change
   // under insertion. After insertion is done, the value of the cell can be read
   // to retrieve the final PDB type index.
-  parallelForEachN(0, TpiSource::instances.size(), [&](size_t tpiSrcIdx) {
-    TpiSource *source = TpiSource::instances[tpiSrcIdx];
+  parallelForEachN(0, ctx.tpiSourceList.size(), [&](size_t tpiSrcIdx) {
+    TpiSource *source = ctx.tpiSourceList[tpiSrcIdx];
     source->indexMapStorage.resize(source->ghashes.size());
     for (uint32_t i = 0, e = source->ghashes.size(); i < e; i++) {
       if (source->shouldOmitFromPdb(i)) {
@@ -1091,7 +1058,7 @@ void TypeMerger::mergeTypesWithGHash() {
       GloballyHashedType ghash = source->ghashes[i];
       bool isItem = source->isItemIndex.test(i);
       uint32_t cellIdx =
-          ghashState.table.insert(ghash, GHashCell(isItem, tpiSrcIdx, i));
+          ghashState.table.insert(ctx, ghash, GHashCell(isItem, tpiSrcIdx, i));
 
       // Store the ghash cell index as a type index in indexMapStorage. Later
       // we will replace it with the PDB type index.
@@ -1137,7 +1104,7 @@ void TypeMerger::mergeTypesWithGHash() {
   for (uint32_t i = 0, e = entries.size(); i < e; ++i) {
     auto &cell = entries[i];
     uint32_t tpiSrcIdx = cell.getTpiSrcIdx();
-    TpiSource *source = TpiSource::instances[tpiSrcIdx];
+    TpiSource *source = ctx.tpiSourceList[tpiSrcIdx];
     source->uniqueTypes.push_back(cell.getGHashIdx());
 
     // Update the ghash table to store the destination PDB type index in the
@@ -1150,21 +1117,37 @@ void TypeMerger::mergeTypesWithGHash() {
   }
 
   // In parallel, remap all types.
-  for_each(TpiSource::dependencySources, [&](TpiSource *source) {
+  for_each(dependencySources, [&](TpiSource *source) {
     source->remapTpiWithGHashes(&ghashState);
   });
-  parallelForEach(TpiSource::objectSources, [&](TpiSource *source) {
+  parallelForEach(objectSources, [&](TpiSource *source) {
     source->remapTpiWithGHashes(&ghashState);
   });
 
   // Build a global map of from function ID to function type.
-  for (TpiSource *source : TpiSource::instances) {
+  for (TpiSource *source : ctx.tpiSourceList) {
     for (auto idToType : source->funcIdToType)
       funcIdToType.insert(idToType);
     source->funcIdToType.clear();
   }
 
-  TpiSource::clearGHashes();
+  ctx.clearGHashes();
+}
+
+void TypeMerger::sortDependencies() {
+  // Order dependencies first, but preserve the existing order.
+  std::vector<TpiSource *> deps;
+  std::vector<TpiSource *> objs;
+  for (TpiSource *s : ctx.tpiSourceList)
+    (s->isDependency() ? deps : objs).push_back(s);
+  uint32_t numDeps = deps.size();
+  uint32_t numObjs = objs.size();
+  ctx.tpiSourceList = std::move(deps);
+  ctx.tpiSourceList.insert(ctx.tpiSourceList.end(), objs.begin(), objs.end());
+  for (uint32_t i = 0, e = ctx.tpiSourceList.size(); i < e; ++i)
+    ctx.tpiSourceList[i]->tpiSrcIdx = i;
+  dependencySources = makeArrayRef(ctx.tpiSourceList.data(), numDeps);
+  objectSources = makeArrayRef(ctx.tpiSourceList.data() + numDeps, numObjs);
 }
 
 /// Given the index into the ghash table for a particular type, return the type
@@ -1187,13 +1170,3 @@ void TpiSource::fillMapFromGHashes(GHashState *g) {
           loadPdbTypeIndexFromCell(g, fakeCellIndex.toArrayIndex());
   }
 }
-
-void TpiSource::clearGHashes() {
-  for (TpiSource *src : TpiSource::instances) {
-    if (src->ownedGHashes)
-      delete[] src->ghashes.data();
-    src->ghashes = {};
-    src->isItemIndex.clear();
-    src->uniqueTypes.clear();
-  }
-}

diff  --git a/lld/COFF/DebugTypes.h b/lld/COFF/DebugTypes.h
index faad30b141e92..b02b5b884cf7e 100644
--- a/lld/COFF/DebugTypes.h
+++ b/lld/COFF/DebugTypes.h
@@ -37,12 +37,13 @@ class ObjFile;
 class PDBInputFile;
 class TypeMerger;
 struct GHashState;
+class COFFLinkerContext;
 
 class TpiSource {
 public:
   enum TpiKind : uint8_t { Regular, PCH, UsingPCH, PDB, PDBIpi, UsingPDB };
 
-  TpiSource(TpiKind k, ObjFile *f);
+  TpiSource(COFFLinkerContext &ctx, TpiKind k, ObjFile *f);
   virtual ~TpiSource();
 
   /// Produce a mapping from the type and item indices used in the object
@@ -93,6 +94,8 @@ class TpiSource {
   // Walk over file->debugTypes and fill in the isItemIndex bit vector.
   void fillIsItemIndexFromDebugT();
 
+  COFFLinkerContext &ctx;
+
 public:
   bool remapTypesInSymbolRecord(MutableArrayRef<uint8_t> rec);
 
@@ -109,29 +112,6 @@ class TpiSource {
     return ghashIdx == endPrecompGHashIdx;
   }
 
-  /// All sources of type information in the program.
-  static std::vector<TpiSource *> instances;
-
-  /// Dependency type sources, such as type servers or PCH object files. These
-  /// must be processed before objects that rely on them. Set by
-  /// TpiSources::sortDependencies.
-  static ArrayRef<TpiSource *> dependencySources;
-
-  /// Object file sources. These must be processed after dependencySources.
-  static ArrayRef<TpiSource *> objectSources;
-
-  /// Sorts the dependencies and reassigns TpiSource indices.
-  static void sortDependencies();
-
-  static uint32_t countTypeServerPDBs();
-  static uint32_t countPrecompObjs();
-
-  /// Free heap allocated ghashes.
-  static void clearGHashes();
-
-  /// Clear global data structures for TpiSources.
-  static void clear();
-
   const TpiKind kind;
   bool ownedGHashes = true;
   uint32_t tpiSrcIdx = 0;
@@ -186,12 +166,13 @@ class TpiSource {
   uint64_t nbTypeRecordsBytes = 0;
 };
 
-TpiSource *makeTpiSource(ObjFile *file);
-TpiSource *makeTypeServerSource(PDBInputFile *pdbInputFile);
-TpiSource *makeUseTypeServerSource(ObjFile *file,
+TpiSource *makeTpiSource(COFFLinkerContext &ctx, ObjFile *f);
+TpiSource *makeTypeServerSource(COFFLinkerContext &ctx,
+                                PDBInputFile *pdbInputFile);
+TpiSource *makeUseTypeServerSource(COFFLinkerContext &ctx, ObjFile *file,
                                    llvm::codeview::TypeServer2Record ts);
-TpiSource *makePrecompSource(ObjFile *file);
-TpiSource *makeUsePrecompSource(ObjFile *file,
+TpiSource *makePrecompSource(COFFLinkerContext &ctx, ObjFile *file);
+TpiSource *makeUsePrecompSource(COFFLinkerContext &ctx, ObjFile *file,
                                 llvm::codeview::PrecompRecord ts);
 
 } // namespace coff

diff  --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index fd9ae7f47bf87..9ebd1c336c594 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Driver.h"
+#include "COFFLinkerContext.h"
 #include "Config.h"
 #include "DebugTypes.h"
 #include "ICF.h"
@@ -59,8 +60,6 @@ using namespace llvm::sys;
 namespace lld {
 namespace coff {
 
-static Timer inputFileTimer("Input File Reading", Timer::root());
-
 Configuration *config;
 LinkerDriver *driver;
 
@@ -70,14 +69,7 @@ bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
   lld::stderrOS = &stderrOS;
 
   errorHandler().cleanupCallback = []() {
-    TpiSource::clear();
     freeArena();
-    ObjFile::instances.clear();
-    PDBInputFile::instances.clear();
-    ImportFile::instances.clear();
-    BitcodeFile::instances.clear();
-    memset(MergeChunk::instances, 0, sizeof(MergeChunk::instances));
-    OutputSection::clear();
   };
 
   errorHandler().logName = args::getFilenameWithoutExe(args[0]);
@@ -87,9 +79,9 @@ bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
   errorHandler().exitEarly = canExitEarly;
   stderrOS.enable_colors(stderrOS.has_colors());
 
+  COFFLinkerContext ctx;
   config = make<Configuration>();
-  symtab = make<SymbolTable>();
-  driver = make<LinkerDriver>();
+  driver = make<LinkerDriver>(ctx);
 
   driver->linkerMain(args);
 
@@ -174,8 +166,8 @@ static StringRef mangle(StringRef sym) {
   return sym;
 }
 
-static bool findUnderscoreMangle(StringRef sym) {
-  Symbol *s = symtab->findMangle(mangle(sym));
+bool LinkerDriver::findUnderscoreMangle(StringRef sym) {
+  Symbol *s = ctx.symtab.findMangle(mangle(sym));
   return s && !isa<Undefined>(s);
 }
 
@@ -213,30 +205,30 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
         addArchiveBuffer(m, "<whole-archive>", filename, memberIndex++);
       return;
     }
-    symtab->addFile(make<ArchiveFile>(mbref));
+    ctx.symtab.addFile(make<ArchiveFile>(ctx, mbref));
     break;
   case file_magic::bitcode:
     if (lazy)
-      symtab->addFile(make<LazyObjFile>(mbref));
+      ctx.symtab.addFile(make<LazyObjFile>(ctx, mbref));
     else
-      symtab->addFile(make<BitcodeFile>(mbref, "", 0));
+      ctx.symtab.addFile(make<BitcodeFile>(ctx, mbref, "", 0));
     break;
   case file_magic::coff_object:
   case file_magic::coff_import_library:
     if (lazy)
-      symtab->addFile(make<LazyObjFile>(mbref));
+      ctx.symtab.addFile(make<LazyObjFile>(ctx, mbref));
     else
-      symtab->addFile(make<ObjFile>(mbref));
+      ctx.symtab.addFile(make<ObjFile>(ctx, mbref));
     break;
   case file_magic::pdb:
-    symtab->addFile(make<PDBInputFile>(mbref));
+    ctx.symtab.addFile(make<PDBInputFile>(ctx, mbref));
     break;
   case file_magic::coff_cl_gl_object:
     error(filename + ": is not a native COFF file. Recompile without /GL");
     break;
   case file_magic::pecoff_executable:
     if (config->mingw) {
-      symtab->addFile(make<DLLFile>(mbref));
+      ctx.symtab.addFile(make<DLLFile>(ctx, mbref));
       break;
     }
     if (filename.endswith_insensitive(".dll")) {
@@ -280,24 +272,24 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName,
                                     uint64_t offsetInArchive) {
   file_magic magic = identify_magic(mb.getBuffer());
   if (magic == file_magic::coff_import_library) {
-    InputFile *imp = make<ImportFile>(mb);
+    InputFile *imp = make<ImportFile>(ctx, mb);
     imp->parentName = parentName;
-    symtab->addFile(imp);
+    ctx.symtab.addFile(imp);
     return;
   }
 
   InputFile *obj;
   if (magic == file_magic::coff_object) {
-    obj = make<ObjFile>(mb);
+    obj = make<ObjFile>(ctx, mb);
   } else if (magic == file_magic::bitcode) {
-    obj = make<BitcodeFile>(mb, parentName, offsetInArchive);
+    obj = make<BitcodeFile>(ctx, mb, parentName, offsetInArchive);
   } else {
     error("unknown file type: " + mb.getBufferIdentifier());
     return;
   }
 
   obj->parentName = parentName;
-  symtab->addFile(obj);
+  ctx.symtab.addFile(obj);
   log("Loaded " + toString(obj) + " for " + symName);
 }
 
@@ -547,7 +539,7 @@ void LinkerDriver::addLibSearchPaths() {
 }
 
 Symbol *LinkerDriver::addUndefined(StringRef name) {
-  Symbol *b = symtab->addUndefined(name);
+  Symbol *b = ctx.symtab.addUndefined(name);
   if (!b->isGCRoot) {
     b->isGCRoot = true;
     config->gcroot.push_back(b);
@@ -562,14 +554,14 @@ StringRef LinkerDriver::mangleMaybe(Symbol *s) {
     return "";
 
   // Otherwise, see if a similar, mangled symbol exists in the symbol table.
-  Symbol *mangled = symtab->findMangle(unmangled->getName());
+  Symbol *mangled = ctx.symtab.findMangle(unmangled->getName());
   if (!mangled)
     return "";
 
   // If we find a similar mangled symbol, make this an alias to it and return
   // its name.
   log(unmangled->getName() + " aliased to " + mangled->getName());
-  unmangled->weakAlias = symtab->addUndefined(mangled->getName());
+  unmangled->weakAlias = ctx.symtab.addUndefined(mangled->getName());
   return mangled->getName();
 }
 
@@ -939,7 +931,7 @@ void LinkerDriver::enqueueTask(std::function<void()> task) {
 }
 
 bool LinkerDriver::run() {
-  ScopedTimer t(inputFileTimer);
+  ScopedTimer t(ctx.inputFileTimer);
 
   bool didWork = !taskQueue.empty();
   while (!taskQueue.empty()) {
@@ -952,7 +944,7 @@ bool LinkerDriver::run() {
 // Parse an /order file. If an option is given, the linker places
 // COMDAT sections in the same order as their names appear in the
 // given file.
-static void parseOrderFile(StringRef arg) {
+static void parseOrderFile(COFFLinkerContext &ctx, StringRef arg) {
   // For some reason, the MSVC linker requires a filename to be
   // preceded by "@".
   if (!arg.startswith("@")) {
@@ -962,7 +954,7 @@ static void parseOrderFile(StringRef arg) {
 
   // Get a list of all comdat sections for error checking.
   DenseSet<StringRef> set;
-  for (Chunk *c : symtab->getChunks())
+  for (Chunk *c : ctx.symtab.getChunks())
     if (auto *sec = dyn_cast<SectionChunk>(c))
       if (sec->sym)
         set.insert(sec->sym->getName());
@@ -996,7 +988,7 @@ static void parseOrderFile(StringRef arg) {
   driver->takeBuffer(std::move(mb));
 }
 
-static void parseCallGraphFile(StringRef path) {
+static void parseCallGraphFile(COFFLinkerContext &ctx, StringRef path) {
   std::unique_ptr<MemoryBuffer> mb =
       CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,
                                   /*RequiresNullTerminator=*/false,
@@ -1005,7 +997,7 @@ static void parseCallGraphFile(StringRef path) {
 
   // Build a map from symbol name to section.
   DenseMap<StringRef, Symbol *> map;
-  for (ObjFile *file : ObjFile::instances)
+  for (ObjFile *file : ctx.objFileInstances)
     for (Symbol *sym : file->getSymbols())
       if (sym)
         map[sym->getName()] = sym;
@@ -1042,8 +1034,8 @@ static void parseCallGraphFile(StringRef path) {
   driver->takeBuffer(std::move(mb));
 }
 
-static void readCallGraphsFromObjectFiles() {
-  for (ObjFile *obj : ObjFile::instances) {
+static void readCallGraphsFromObjectFiles(COFFLinkerContext &ctx) {
+  for (ObjFile *obj : ctx.objFileInstances) {
     if (obj->callgraphSec) {
       ArrayRef<uint8_t> contents;
       cantFail(
@@ -1077,7 +1069,7 @@ static void markAddrsig(Symbol *s) {
       c->keepUnique = true;
 }
 
-static void findKeepUniqueSections() {
+static void findKeepUniqueSections(COFFLinkerContext &ctx) {
   // Exported symbols could be address-significant in other executables or DSOs,
   // so we conservatively mark them as address-significant.
   for (Export &r : config->exports)
@@ -1085,7 +1077,7 @@ static void findKeepUniqueSections() {
 
   // Visit the address-significance table in each object file and mark each
   // referenced symbol as address-significant.
-  for (ObjFile *obj : ObjFile::instances) {
+  for (ObjFile *obj : ctx.objFileInstances) {
     ArrayRef<Symbol *> syms = obj->getSymbols();
     if (obj->addrsigSec) {
       ArrayRef<uint8_t> contents;
@@ -1169,7 +1161,7 @@ static void parsePDBAltPath(StringRef altPath) {
 void LinkerDriver::convertResources() {
   std::vector<ObjFile *> resourceObjFiles;
 
-  for (ObjFile *f : ObjFile::instances) {
+  for (ObjFile *f : ctx.objFileInstances) {
     if (f->isResourceObjFile())
       resourceObjFiles.push_back(f);
   }
@@ -1191,8 +1183,9 @@ void LinkerDriver::convertResources() {
       f->includeResourceChunks();
     return;
   }
-  ObjFile *f = make<ObjFile>(convertResToCOFF(resources, resourceObjFiles));
-  symtab->addFile(f);
+  ObjFile *f =
+      make<ObjFile>(ctx, convertResToCOFF(resources, resourceObjFiles));
+  ctx.symtab.addFile(f);
   f->includeResourceChunks();
 }
 
@@ -1219,9 +1212,9 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {
     if (Optional<StringRef> path = doFindFile(arg->getValue()))
       exporter.addWholeArchive(*path);
 
-  symtab->forEachSymbol([&](Symbol *s) {
+  ctx.symtab.forEachSymbol([&](Symbol *s) {
     auto *def = dyn_cast<Defined>(s);
-    if (!exporter.shouldExport(def))
+    if (!exporter.shouldExport(ctx, def))
       return;
 
     if (!def->isGCRoot) {
@@ -1266,7 +1259,7 @@ Optional<std::string> getReproduceFile(const opt::InputArgList &args) {
 }
 
 void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
-  ScopedTimer rootTimer(Timer::root());
+  ScopedTimer rootTimer(ctx.rootTimer);
 
   // Needed for LTO.
   InitializeAllTargetInfos();
@@ -2018,32 +2011,32 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
   if (config->imageBase == uint64_t(-1))
     config->imageBase = getDefaultImageBase();
 
-  symtab->addSynthetic(mangle("__ImageBase"), nullptr);
+  ctx.symtab.addSynthetic(mangle("__ImageBase"), nullptr);
   if (config->machine == I386) {
-    symtab->addAbsolute("___safe_se_handler_table", 0);
-    symtab->addAbsolute("___safe_se_handler_count", 0);
+    ctx.symtab.addAbsolute("___safe_se_handler_table", 0);
+    ctx.symtab.addAbsolute("___safe_se_handler_count", 0);
   }
 
-  symtab->addAbsolute(mangle("__guard_fids_count"), 0);
-  symtab->addAbsolute(mangle("__guard_fids_table"), 0);
-  symtab->addAbsolute(mangle("__guard_flags"), 0);
-  symtab->addAbsolute(mangle("__guard_iat_count"), 0);
-  symtab->addAbsolute(mangle("__guard_iat_table"), 0);
-  symtab->addAbsolute(mangle("__guard_longjmp_count"), 0);
-  symtab->addAbsolute(mangle("__guard_longjmp_table"), 0);
+  ctx.symtab.addAbsolute(mangle("__guard_fids_count"), 0);
+  ctx.symtab.addAbsolute(mangle("__guard_fids_table"), 0);
+  ctx.symtab.addAbsolute(mangle("__guard_flags"), 0);
+  ctx.symtab.addAbsolute(mangle("__guard_iat_count"), 0);
+  ctx.symtab.addAbsolute(mangle("__guard_iat_table"), 0);
+  ctx.symtab.addAbsolute(mangle("__guard_longjmp_count"), 0);
+  ctx.symtab.addAbsolute(mangle("__guard_longjmp_table"), 0);
   // Needed for MSVC 2017 15.5 CRT.
-  symtab->addAbsolute(mangle("__enclave_config"), 0);
+  ctx.symtab.addAbsolute(mangle("__enclave_config"), 0);
   // Needed for MSVC 2019 16.8 CRT.
-  symtab->addAbsolute(mangle("__guard_eh_cont_count"), 0);
-  symtab->addAbsolute(mangle("__guard_eh_cont_table"), 0);
+  ctx.symtab.addAbsolute(mangle("__guard_eh_cont_count"), 0);
+  ctx.symtab.addAbsolute(mangle("__guard_eh_cont_table"), 0);
 
   if (config->pseudoRelocs) {
-    symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);
-    symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);
+    ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);
+    ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);
   }
   if (config->mingw) {
-    symtab->addAbsolute(mangle("__CTOR_LIST__"), 0);
-    symtab->addAbsolute(mangle("__DTOR_LIST__"), 0);
+    ctx.symtab.addAbsolute(mangle("__CTOR_LIST__"), 0);
+    ctx.symtab.addAbsolute(mangle("__DTOR_LIST__"), 0);
   }
 
   // This code may add new undefined symbols to the link, which may enqueue more
@@ -2069,12 +2062,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
     for (auto pair : config->alternateNames) {
       StringRef from = pair.first;
       StringRef to = pair.second;
-      Symbol *sym = symtab->find(from);
+      Symbol *sym = ctx.symtab.find(from);
       if (!sym)
         continue;
       if (auto *u = dyn_cast<Undefined>(sym))
         if (!u->weakAlias)
-          u->weakAlias = symtab->addUndefined(to);
+          u->weakAlias = ctx.symtab.addUndefined(to);
     }
 
     // If any inputs are bitcode files, the LTO code generator may create
@@ -2082,25 +2075,25 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
     // file's symbol table. If any of those library functions are defined in a
     // bitcode file in an archive member, we need to arrange to use LTO to
     // compile those archive members by adding them to the link beforehand.
-    if (!BitcodeFile::instances.empty())
+    if (!ctx.bitcodeFileInstances.empty())
       for (auto *s : lto::LTO::getRuntimeLibcallSymbols())
-        symtab->addLibcall(s);
+        ctx.symtab.addLibcall(s);
 
     // Windows specific -- if __load_config_used can be resolved, resolve it.
-    if (symtab->findUnderscore("_load_config_used"))
+    if (ctx.symtab.findUnderscore("_load_config_used"))
       addUndefined(mangle("_load_config_used"));
   } while (run());
 
   if (args.hasArg(OPT_include_optional)) {
     // Handle /includeoptional
     for (auto *arg : args.filtered(OPT_include_optional))
-      if (dyn_cast_or_null<LazyArchive>(symtab->find(arg->getValue())))
+      if (dyn_cast_or_null<LazyArchive>(ctx.symtab.find(arg->getValue())))
         addUndefined(arg->getValue());
     while (run());
   }
 
   // Create wrapped symbols for -wrap option.
-  std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args);
+  std::vector<WrappedSymbol> wrapped = addWrappedSymbols(ctx, args);
   // Load more object files that might be needed for wrapped symbols.
   if (!wrapped.empty())
     while (run());
@@ -2126,7 +2119,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
     // If it ends up pulling in more object files from static libraries,
     // (and maybe doing more stdcall fixups along the way), this would need
     // to loop these two calls.
-    symtab->loadMinGWSymbols();
+    ctx.symtab.loadMinGWSymbols();
     run();
   }
 
@@ -2134,8 +2127,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
   // If we are going to do codegen for link-time optimization, check for
   // unresolvable symbols first, so we don't spend time generating code that
   // will fail to link anyway.
-  if (!BitcodeFile::instances.empty() && !config->forceUnresolved)
-    symtab->reportUnresolvable();
+  if (!ctx.bitcodeFileInstances.empty() && !config->forceUnresolved)
+    ctx.symtab.reportUnresolvable();
   if (errorCount())
     return;
 
@@ -2149,7 +2142,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
   // Do LTO by compiling bitcode input files to a set of native COFF files then
   // link those files (unless -thinlto-index-only was given, in which case we
   // resolve symbols and write indices, but don't generate native code or link).
-  symtab->addCombinedLTOObjects();
+  ctx.symtab.addCombinedLTOObjects();
 
   // If -thinlto-index-only is given, we should create only "index
   // files" and not object files. Index file creation is already done
@@ -2163,10 +2156,10 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
 
   // Apply symbol renames for -wrap.
   if (!wrapped.empty())
-    wrapSymbols(wrapped);
+    wrapSymbols(ctx, wrapped);
 
   // Resolve remaining undefined symbols and warn about imported locals.
-  symtab->resolveRemainingUndefines();
+  ctx.symtab.resolveRemainingUndefines();
   if (errorCount())
     return;
 
@@ -2177,12 +2170,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
     // order provided on the command line, while lld will pull in needed
     // files from static libraries only after the last object file on the
     // command line.
-    for (auto i = ObjFile::instances.begin(), e = ObjFile::instances.end();
+    for (auto i = ctx.objFileInstances.begin(), e = ctx.objFileInstances.end();
          i != e; i++) {
       ObjFile *file = *i;
       if (isCrtend(file->getName())) {
-        ObjFile::instances.erase(i);
-        ObjFile::instances.push_back(file);
+        ctx.objFileInstances.erase(i);
+        ctx.objFileInstances.push_back(file);
         break;
       }
     }
@@ -2207,7 +2200,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
     StringRef name = pair.first;
     uint32_t alignment = pair.second;
 
-    Symbol *sym = symtab->find(name);
+    Symbol *sym = ctx.symtab.find(name);
     if (!sym) {
       warn("/aligncomm symbol " + name + " not found");
       continue;
@@ -2239,16 +2232,16 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
   if (auto *arg = args.getLastArg(OPT_order)) {
     if (args.hasArg(OPT_call_graph_ordering_file))
       error("/order and /call-graph-order-file may not be used together");
-    parseOrderFile(arg->getValue());
+    parseOrderFile(ctx, arg->getValue());
     config->callGraphProfileSort = false;
   }
 
   // Handle /call-graph-ordering-file and /call-graph-profile-sort (default on).
   if (config->callGraphProfileSort) {
     if (auto *arg = args.getLastArg(OPT_call_graph_ordering_file)) {
-      parseCallGraphFile(arg->getValue());
+      parseCallGraphFile(ctx, arg->getValue());
     }
-    readCallGraphsFromObjectFiles();
+    readCallGraphsFromObjectFiles(ctx);
   }
 
   // Handle /print-symbol-order.
@@ -2265,7 +2258,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
       // functions. This doesn't bring in more object files, but only marks
       // functions that already have been included to be retained.
       for (const char *n : {"__gxx_personality_v0", "__gcc_personality_v0"}) {
-        Defined *d = dyn_cast_or_null<Defined>(symtab->findUnderscore(n));
+        Defined *d = dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore(n));
         if (d && !d->isGCRoot) {
           d->isGCRoot = true;
           config->gcroot.push_back(d);
@@ -2273,7 +2266,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
       }
     }
 
-    markLive(symtab->getChunks());
+    markLive(ctx);
   }
 
   // Needs to happen after the last call to addFile().
@@ -2281,17 +2274,17 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
 
   // Identify identical COMDAT sections to merge them.
   if (config->doICF != ICFLevel::None) {
-    findKeepUniqueSections();
-    doICF(symtab->getChunks(), config->doICF);
+    findKeepUniqueSections(ctx);
+    doICF(ctx, config->doICF);
   }
 
   // Write the result.
-  writeResult();
+  writeResult(ctx);
 
   // Stop early so we can print the results.
   rootTimer.stop();
   if (config->showTiming)
-    Timer::root().print();
+    ctx.rootTimer.print();
 }
 
 } // namespace coff

diff  --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h
index 5729bed69528b..7c2fbe3c7d64c 100644
--- a/lld/COFF/Driver.h
+++ b/lld/COFF/Driver.h
@@ -9,6 +9,7 @@
 #ifndef LLD_COFF_DRIVER_H
 #define LLD_COFF_DRIVER_H
 
+#include "COFFLinkerContext.h"
 #include "Config.h"
 #include "SymbolTable.h"
 #include "lld/Common/LLVM.h"
@@ -78,6 +79,8 @@ class ArgParser {
 
 class LinkerDriver {
 public:
+  LinkerDriver(COFFLinkerContext &c) : ctx(c) {}
+
   void linkerMain(llvm::ArrayRef<const char *> args);
 
   // Used by the resolver to parse .drectve section contents.
@@ -103,6 +106,8 @@ class LinkerDriver {
   StringRef doFindLib(StringRef filename);
   StringRef doFindLibMinGW(StringRef filename);
 
+  bool findUnderscoreMangle(StringRef sym);
+
   // Parses LIB environment which contains a list of search paths.
   void addLibSearchPaths();
 
@@ -148,6 +153,8 @@ class LinkerDriver {
   std::vector<MemoryBufferRef> resources;
 
   llvm::StringSet<> directivesExports;
+
+  COFFLinkerContext &ctx;
 };
 
 // Functions below this line are defined in DriverUtils.cpp.

diff  --git a/lld/COFF/ICF.cpp b/lld/COFF/ICF.cpp
index 7326469672968..8323626623948 100644
--- a/lld/COFF/ICF.cpp
+++ b/lld/COFF/ICF.cpp
@@ -18,6 +18,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ICF.h"
+#include "COFFLinkerContext.h"
 #include "Chunks.h"
 #include "Symbols.h"
 #include "lld/Common/ErrorHandler.h"
@@ -36,12 +37,10 @@ using namespace llvm;
 namespace lld {
 namespace coff {
 
-static Timer icfTimer("ICF", Timer::root());
-
 class ICF {
 public:
-  ICF(ICFLevel icfLevel) : icfLevel(icfLevel){};
-  void run(ArrayRef<Chunk *> v);
+  ICF(COFFLinkerContext &c, ICFLevel icfLevel) : icfLevel(icfLevel), ctx(c){};
+  void run();
 
 private:
   void segregate(size_t begin, size_t end, bool constant);
@@ -64,6 +63,8 @@ class ICF {
   int cnt = 0;
   std::atomic<bool> repeat = {false};
   ICFLevel icfLevel = ICFLevel::All;
+
+  COFFLinkerContext &ctx;
 };
 
 // Returns true if section S is subject of ICF.
@@ -246,12 +247,12 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> fn) {
 // Merge identical COMDAT sections.
 // Two sections are considered the same if their section headers,
 // contents and relocations are all the same.
-void ICF::run(ArrayRef<Chunk *> vec) {
-  ScopedTimer t(icfTimer);
+void ICF::run() {
+  ScopedTimer t(ctx.icfTimer);
 
   // Collect only mergeable sections and group by hash value.
   uint32_t nextId = 1;
-  for (Chunk *c : vec) {
+  for (Chunk *c : ctx.symtab.getChunks()) {
     if (auto *sc = dyn_cast<SectionChunk>(c)) {
       if (isEligible(sc))
         chunks.push_back(sc);
@@ -262,7 +263,7 @@ void ICF::run(ArrayRef<Chunk *> vec) {
 
   // Make sure that ICF doesn't merge sections that are being handled by string
   // tail merging.
-  for (MergeChunk *mc : MergeChunk::instances)
+  for (MergeChunk *mc : ctx.mergeChunkInstances)
     if (mc)
       for (SectionChunk *sc : mc->sections)
         sc->eqClass[0] = nextId++;
@@ -317,8 +318,8 @@ void ICF::run(ArrayRef<Chunk *> vec) {
 }
 
 // Entry point to ICF.
-void doICF(ArrayRef<Chunk *> chunks, ICFLevel icfLevel) {
-  ICF(icfLevel).run(chunks);
+void doICF(COFFLinkerContext &ctx, ICFLevel icfLevel) {
+  ICF(ctx, icfLevel).run();
 }
 
 } // namespace coff

diff  --git a/lld/COFF/ICF.h b/lld/COFF/ICF.h
index f8cc8071f9eb7..10e6792a5418f 100644
--- a/lld/COFF/ICF.h
+++ b/lld/COFF/ICF.h
@@ -17,8 +17,9 @@ namespace lld {
 namespace coff {
 
 class Chunk;
+class COFFLinkerContext;
 
-void doICF(ArrayRef<Chunk *> chunks, ICFLevel);
+void doICF(COFFLinkerContext &ctx, ICFLevel);
 
 } // namespace coff
 } // namespace lld

diff  --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index f32353ca4f94a..4b38e3d1a99bc 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "InputFiles.h"
+#include "COFFLinkerContext.h"
 #include "Chunks.h"
 #include "Config.h"
 #include "DebugTypes.h"
@@ -69,11 +70,6 @@ std::string lld::toString(const coff::InputFile *file) {
       .str();
 }
 
-std::vector<ObjFile *> ObjFile::instances;
-std::map<std::string, PDBInputFile *> PDBInputFile::instances;
-std::vector<ImportFile *> ImportFile::instances;
-std::vector<BitcodeFile *> BitcodeFile::instances;
-
 /// Checks that Source is compatible with being a weak alias to Target.
 /// If Source is Undefined and has no weak alias set, makes it a weak
 /// alias to Target.
@@ -98,7 +94,8 @@ static bool ignoredSymbolName(StringRef name) {
   return name == "@feat.00" || name == "@comp.id";
 }
 
-ArchiveFile::ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}
+ArchiveFile::ArchiveFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+    : InputFile(ctx, ArchiveKind, m) {}
 
 void ArchiveFile::parse() {
   // Parse a MemoryBufferRef as an archive file.
@@ -106,7 +103,7 @@ void ArchiveFile::parse() {
 
   // Read the symbol table to construct Lazy objects.
   for (const Archive::Symbol &sym : file->symbols())
-    symtab->addLazyArchive(this, sym);
+    ctx.symtab.addLazyArchive(this, sym);
 }
 
 // Returns a buffer pointing to a member file containing a given symbol.
@@ -144,11 +141,11 @@ void LazyObjFile::fetch() {
 
   InputFile *file;
   if (isBitcode(mb))
-    file = make<BitcodeFile>(mb, "", 0, std::move(symbols));
+    file = make<BitcodeFile>(ctx, mb, "", 0, std::move(symbols));
   else
-    file = make<ObjFile>(mb, std::move(symbols));
+    file = make<ObjFile>(ctx, mb, std::move(symbols));
   mb = {};
-  symtab->addFile(file);
+  ctx.symtab.addFile(file);
 }
 
 void LazyObjFile::parse() {
@@ -158,7 +155,7 @@ void LazyObjFile::parse() {
         CHECK(lto::InputFile::create(this->mb), this);
     for (const lto::InputFile::Symbol &sym : obj->symbols()) {
       if (!sym.isUndefined())
-        symtab->addLazyObject(this, sym.getName());
+        ctx.symtab.addLazyObject(this, sym.getName());
     }
     return;
   }
@@ -175,7 +172,7 @@ void LazyObjFile::parse() {
     StringRef name = check(coffObj->getSymbolName(coffSym));
     if (coffSym.isAbsolute() && ignoredSymbolName(name))
       continue;
-    symtab->addLazyObject(this, name);
+    ctx.symtab.addLazyObject(this, name);
     i += coffSym.getNumberOfAuxSymbols();
   }
 }
@@ -293,7 +290,7 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber,
     // COFF sections that look like string literal sections (i.e. no
     // relocations, in .rdata, leader symbol name matches the MSVC name mangling
     // for string literals) are subject to string tail merging.
-    MergeChunk::addSection(c);
+    MergeChunk::addSection(ctx, c);
   else if (name == ".rsrc" || name.startswith(".rsrc$"))
     resourceChunks.push_back(c);
   else
@@ -387,8 +384,8 @@ Symbol *ObjFile::createRegular(COFFSymbolRef sym) {
   if (sym.isExternal()) {
     StringRef name = check(coffObj->getSymbolName(sym));
     if (sc)
-      return symtab->addRegular(this, name, sym.getGeneric(), sc,
-                                sym.getValue());
+      return ctx.symtab.addRegular(this, name, sym.getGeneric(), sc,
+                                   sym.getValue());
     // For MinGW symbols named .weak.* that point to a discarded section,
     // don't create an Undefined symbol. If nothing ever refers to the symbol,
     // everything should be fine. If something actually refers to the symbol
@@ -396,7 +393,7 @@ Symbol *ObjFile::createRegular(COFFSymbolRef sym) {
     // references at the end.
     if (config->mingw && name.startswith(".weak."))
       return nullptr;
-    return symtab->addUndefined(name, this, false);
+    return ctx.symtab.addUndefined(name, this, false);
   }
   if (sc)
     return make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
@@ -464,7 +461,7 @@ void ObjFile::initializeSymbols() {
   for (auto &kv : weakAliases) {
     Symbol *sym = kv.first;
     uint32_t idx = kv.second;
-    checkAndSetWeakAlias(symtab, this, sym, symbols[idx]);
+    checkAndSetWeakAlias(&ctx.symtab, this, sym, symbols[idx]);
   }
 
   // Free the memory used by sparseChunks now that symbol loading is finished.
@@ -473,7 +470,7 @@ void ObjFile::initializeSymbols() {
 
 Symbol *ObjFile::createUndefined(COFFSymbolRef sym) {
   StringRef name = check(coffObj->getSymbolName(sym));
-  return symtab->addUndefined(name, this, sym.isWeakExternal());
+  return ctx.symtab.addUndefined(name, this, sym.isWeakExternal());
 }
 
 static const coff_aux_section_definition *findSectionDef(COFFObjectFile *obj,
@@ -543,13 +540,13 @@ void ObjFile::handleComdatSelection(
          Twine((int)leaderSelection) + " in " + toString(leader->getFile()) +
          " and " + Twine((int)selection) + " in " + toString(this))
             .str());
-    symtab->reportDuplicate(leader, this);
+    ctx.symtab.reportDuplicate(leader, this);
     return;
   }
 
   switch (selection) {
   case IMAGE_COMDAT_SELECT_NODUPLICATES:
-    symtab->reportDuplicate(leader, this);
+    ctx.symtab.reportDuplicate(leader, this);
     break;
 
   case IMAGE_COMDAT_SELECT_ANY:
@@ -559,14 +556,14 @@ void ObjFile::handleComdatSelection(
   case IMAGE_COMDAT_SELECT_SAME_SIZE:
     if (leaderChunk->getSize() != getSection(sym)->SizeOfRawData) {
       if (!config->mingw) {
-        symtab->reportDuplicate(leader, this);
+        ctx.symtab.reportDuplicate(leader, this);
       } else {
         const coff_aux_section_definition *leaderDef = nullptr;
         if (leaderChunk->file)
           leaderDef = findSectionDef(leaderChunk->file->getCOFFObj(),
                                      leaderChunk->getSectionNumber());
         if (!leaderDef || leaderDef->Length != def->Length)
-          symtab->reportDuplicate(leader, this);
+          ctx.symtab.reportDuplicate(leader, this);
       }
     }
     break;
@@ -577,7 +574,7 @@ void ObjFile::handleComdatSelection(
     // if the two comdat sections have e.g. 
diff erent alignment.
     // Match that.
     if (leaderChunk->getContents() != newChunk.getContents())
-      symtab->reportDuplicate(leader, this, &newChunk, sym.getValue());
+      ctx.symtab.reportDuplicate(leader, this, &newChunk, sym.getValue());
     break;
   }
 
@@ -620,8 +617,8 @@ Optional<Symbol *> ObjFile::createDefined(
   if (sym.isCommon()) {
     auto *c = make<CommonChunk>(sym);
     chunks.push_back(c);
-    return symtab->addCommon(this, getName(), sym.getValue(), sym.getGeneric(),
-                             c);
+    return ctx.symtab.addCommon(this, getName(), sym.getValue(),
+                                sym.getGeneric(), c);
   }
 
   if (sym.isAbsolute()) {
@@ -634,7 +631,7 @@ Optional<Symbol *> ObjFile::createDefined(
       return nullptr;
 
     if (sym.isExternal())
-      return symtab->addAbsolute(name, sym);
+      return ctx.symtab.addAbsolute(name, sym);
     return make<DefinedAbsolute>(name, sym);
   }
 
@@ -667,7 +664,7 @@ Optional<Symbol *> ObjFile::createDefined(
 
     if (sym.isExternal()) {
       std::tie(leader, prevailing) =
-          symtab->addComdat(this, getName(), sym.getGeneric());
+          ctx.symtab.addComdat(this, getName(), sym.getGeneric());
     } else {
       leader = make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
                                     /*IsExternal*/ false, sym.getGeneric());
@@ -789,12 +786,11 @@ void ObjFile::initializeDependencies() {
   else
     data = getDebugSection(".debug$T");
 
-  // Don't make a TpiSource for objects with no debug info. If the object has
   // symbols but no types, make a plain, empty TpiSource anyway, because it
   // simplifies adding the symbols later.
   if (data.empty()) {
     if (!debugChunks.empty())
-      debugTypesObj = makeTpiSource(this);
+      debugTypesObj = makeTpiSource(ctx, this);
     return;
   }
 
@@ -812,7 +808,7 @@ void ObjFile::initializeDependencies() {
 
   // This object file is a PCH file that others will depend on.
   if (isPCH) {
-    debugTypesObj = makePrecompSource(this);
+    debugTypesObj = makePrecompSource(ctx, this);
     return;
   }
 
@@ -820,8 +816,8 @@ void ObjFile::initializeDependencies() {
   if (firstType->kind() == LF_TYPESERVER2) {
     TypeServer2Record ts = cantFail(
         TypeDeserializer::deserializeAs<TypeServer2Record>(firstType->data()));
-    debugTypesObj = makeUseTypeServerSource(this, ts);
-    PDBInputFile::enqueue(ts.getName(), this);
+    debugTypesObj = makeUseTypeServerSource(ctx, this, ts);
+    enqueuePdbFile(ts.getName(), this);
     return;
   }
 
@@ -830,14 +826,14 @@ void ObjFile::initializeDependencies() {
   if (firstType->kind() == LF_PRECOMP) {
     PrecompRecord precomp = cantFail(
         TypeDeserializer::deserializeAs<PrecompRecord>(firstType->data()));
-    debugTypesObj = makeUsePrecompSource(this, precomp);
+    debugTypesObj = makeUsePrecompSource(ctx, this, precomp);
     // Drop the LF_PRECOMP record from the input stream.
     debugTypes = debugTypes.drop_front(firstType->RecordData.size());
     return;
   }
 
   // This is a plain old object file.
-  debugTypesObj = makeTpiSource(this);
+  debugTypesObj = makeTpiSource(ctx, this);
 }
 
 // Make a PDB path assuming the PDB is in the same folder as the OBJ
@@ -855,7 +851,7 @@ static std::string getPdbBaseName(ObjFile *file, StringRef tSPath) {
 
 // The casing of the PDB path stamped in the OBJ can 
diff er from the actual path
 // on disk. With this, we ensure to always use lowercase as a key for the
-// PDBInputFile::instances map, at least on Windows.
+// pdbInputFileInstances map, at least on Windows.
 static std::string normalizePdbPath(StringRef path) {
 #if defined(_WIN32)
   return path.lower();
@@ -879,33 +875,25 @@ static Optional<std::string> findPdbPath(StringRef pdbPath,
   return None;
 }
 
-PDBInputFile::PDBInputFile(MemoryBufferRef m) : InputFile(PDBKind, m) {}
+PDBInputFile::PDBInputFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+    : InputFile(ctx, PDBKind, m) {}
 
 PDBInputFile::~PDBInputFile() = default;
 
-PDBInputFile *PDBInputFile::findFromRecordPath(StringRef path,
+PDBInputFile *PDBInputFile::findFromRecordPath(const COFFLinkerContext &ctx,
+                                               StringRef path,
                                                ObjFile *fromFile) {
   auto p = findPdbPath(path.str(), fromFile);
   if (!p)
     return nullptr;
-  auto it = PDBInputFile::instances.find(*p);
-  if (it != PDBInputFile::instances.end())
+  auto it = ctx.pdbInputFileInstances.find(*p);
+  if (it != ctx.pdbInputFileInstances.end())
     return it->second;
   return nullptr;
 }
 
-void PDBInputFile::enqueue(StringRef path, ObjFile *fromFile) {
-  auto p = findPdbPath(path.str(), fromFile);
-  if (!p)
-    return;
-  auto it = PDBInputFile::instances.emplace(*p, nullptr);
-  if (!it.second)
-    return; // already scheduled for load
-  driver->enqueuePDB(*p);
-}
-
 void PDBInputFile::parse() {
-  PDBInputFile::instances[mb.getBufferIdentifier().str()] = this;
+  ctx.pdbInputFileInstances[mb.getBufferIdentifier().str()] = this;
 
   std::unique_ptr<pdb::IPDBSession> thisSession;
   loadErr.emplace(pdb::NativeSession::createFromPdb(
@@ -923,7 +911,7 @@ void PDBInputFile::parse() {
     loadErr.emplace(expectedInfo.takeError());
     return;
   }
-  debugTypesObj = makeTypeServerSource(this);
+  debugTypesObj = makeTypeServerSource(ctx, this);
 }
 
 // Used only for DWARF debug info, which is not common (except in MinGW
@@ -957,6 +945,16 @@ Optional<DILineInfo> ObjFile::getDILineInfo(uint32_t offset,
   return dwarf->getDILineInfo(offset, sectionIndex);
 }
 
+void ObjFile::enqueuePdbFile(StringRef path, ObjFile *fromFile) {
+  auto p = findPdbPath(path.str(), fromFile);
+  if (!p)
+    return;
+  auto it = ctx.pdbInputFileInstances.emplace(*p, nullptr);
+  if (!it.second)
+    return; // already scheduled for load
+  driver->enqueuePDB(*p);
+}
+
 void ImportFile::parse() {
   const char *buf = mb.getBufferStart();
   const auto *hdr = reinterpret_cast<const coff_import_header *>(buf);
@@ -990,31 +988,31 @@ void ImportFile::parse() {
   this->hdr = hdr;
   externalName = extName;
 
-  impSym = symtab->addImportData(impName, this);
+  impSym = ctx.symtab.addImportData(impName, this);
   // If this was a duplicate, we logged an error but may continue;
   // in this case, impSym is nullptr.
   if (!impSym)
     return;
 
   if (hdr->getType() == llvm::COFF::IMPORT_CONST)
-    static_cast<void>(symtab->addImportData(name, this));
+    static_cast<void>(ctx.symtab.addImportData(name, this));
 
   // If type is function, we need to create a thunk which jump to an
   // address pointed by the __imp_ symbol. (This allows you to call
   // DLL functions just like regular non-DLL functions.)
   if (hdr->getType() == llvm::COFF::IMPORT_CODE)
-    thunkSym = symtab->addImportThunk(
+    thunkSym = ctx.symtab.addImportThunk(
         name, cast_or_null<DefinedImportData>(impSym), hdr->Machine);
 }
 
-BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
-                         uint64_t offsetInArchive)
-    : BitcodeFile(mb, archiveName, offsetInArchive, {}) {}
+BitcodeFile::BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,
+                         StringRef archiveName, uint64_t offsetInArchive)
+    : BitcodeFile(ctx, mb, archiveName, offsetInArchive, {}) {}
 
-BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
-                         uint64_t offsetInArchive,
+BitcodeFile::BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,
+                         StringRef archiveName, uint64_t offsetInArchive,
                          std::vector<Symbol *> &&symbols)
-    : InputFile(BitcodeKind, mb), symbols(std::move(symbols)) {
+    : InputFile(ctx, BitcodeKind, mb), symbols(std::move(symbols)) {
   std::string path = mb.getBufferIdentifier().str();
   if (config->thinLTOIndexOnly)
     path = replaceThinLTOSuffix(mb.getBufferIdentifier());
@@ -1069,7 +1067,7 @@ void BitcodeFile::parse() {
   for (size_t i = 0; i != obj->getComdatTable().size(); ++i)
     // FIXME: Check nodeduplicate
     comdat[i] =
-        symtab->addComdat(this, saver.save(obj->getComdatTable()[i].first));
+        ctx.symtab.addComdat(this, saver.save(obj->getComdatTable()[i].first));
   for (const lto::InputFile::Symbol &objSym : obj->symbols()) {
     StringRef symName = saver.save(objSym.getName());
     int comdatIndex = objSym.getComdatIndex();
@@ -1080,27 +1078,27 @@ void BitcodeFile::parse() {
     else
       fakeSC = &ltoDataSectionChunk.chunk;
     if (objSym.isUndefined()) {
-      sym = symtab->addUndefined(symName, this, false);
+      sym = ctx.symtab.addUndefined(symName, this, false);
     } else if (objSym.isCommon()) {
-      sym = symtab->addCommon(this, symName, objSym.getCommonSize());
+      sym = ctx.symtab.addCommon(this, symName, objSym.getCommonSize());
     } else if (objSym.isWeak() && objSym.isIndirect()) {
       // Weak external.
-      sym = symtab->addUndefined(symName, this, true);
+      sym = ctx.symtab.addUndefined(symName, this, true);
       std::string fallback = std::string(objSym.getCOFFWeakExternalFallback());
-      Symbol *alias = symtab->addUndefined(saver.save(fallback));
-      checkAndSetWeakAlias(symtab, this, sym, alias);
+      Symbol *alias = ctx.symtab.addUndefined(saver.save(fallback));
+      checkAndSetWeakAlias(&ctx.symtab, this, sym, alias);
     } else if (comdatIndex != -1) {
       if (symName == obj->getComdatTable()[comdatIndex].first) {
         sym = comdat[comdatIndex].first;
         if (cast<DefinedRegular>(sym)->data == nullptr)
           cast<DefinedRegular>(sym)->data = &fakeSC->repl;
       } else if (comdat[comdatIndex].second) {
-        sym = symtab->addRegular(this, symName, nullptr, fakeSC);
+        sym = ctx.symtab.addRegular(this, symName, nullptr, fakeSC);
       } else {
-        sym = symtab->addUndefined(symName, this, false);
+        sym = ctx.symtab.addUndefined(symName, this, false);
       }
     } else {
-      sym = symtab->addRegular(this, symName, nullptr, fakeSC);
+      sym = ctx.symtab.addRegular(this, symName, nullptr, fakeSC);
     }
     symbols.push_back(sym);
     if (objSym.isUsed())
@@ -1185,9 +1183,9 @@ void DLLFile::parse() {
     }
 
     StringRef impName = saver.save("__imp_" + symbolName);
-    symtab->addLazyDLLSymbol(this, s, impName);
+    ctx.symtab.addLazyDLLSymbol(this, s, impName);
     if (code)
-      symtab->addLazyDLLSymbol(this, s, symbolName);
+      ctx.symtab.addLazyDLLSymbol(this, s, symbolName);
   }
 }
 
@@ -1219,6 +1217,6 @@ void DLLFile::makeImport(DLLFile::Symbol *s) {
   p += s->symbolName.size() + 1;
   memcpy(p, s->dllName.data(), s->dllName.size());
   MemoryBufferRef mbref = MemoryBufferRef(StringRef(buf, size), s->dllName);
-  ImportFile *impFile = make<ImportFile>(mbref);
-  symtab->addFile(impFile);
+  ImportFile *impFile = make<ImportFile>(ctx, mbref);
+  ctx.symtab.addFile(impFile);
 }

diff  --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h
index 47b5c588c5af7..801c668d3ae45 100644
--- a/lld/COFF/InputFiles.h
+++ b/lld/COFF/InputFiles.h
@@ -38,6 +38,7 @@ namespace lld {
 class DWARFCache;
 
 namespace coff {
+class COFFLinkerContext;
 
 std::vector<MemoryBufferRef> getArchiveMembers(llvm::object::Archive *file);
 
@@ -91,8 +92,11 @@ class InputFile {
   // Returns .drectve section contents if exist.
   StringRef getDirectives() { return directives; }
 
+  COFFLinkerContext &ctx;
+
 protected:
-  InputFile(Kind k, MemoryBufferRef m) : mb(m), fileKind(k) {}
+  InputFile(COFFLinkerContext &c, Kind k, MemoryBufferRef m)
+      : mb(m), ctx(c), fileKind(k) {}
 
   StringRef directives;
 
@@ -103,7 +107,7 @@ class InputFile {
 // .lib or .a file.
 class ArchiveFile : public InputFile {
 public:
-  explicit ArchiveFile(MemoryBufferRef m);
+  explicit ArchiveFile(COFFLinkerContext &ctx, MemoryBufferRef m);
   static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
   void parse() override;
 
@@ -120,7 +124,8 @@ class ArchiveFile : public InputFile {
 // .obj or .o file between -start-lib and -end-lib.
 class LazyObjFile : public InputFile {
 public:
-  explicit LazyObjFile(MemoryBufferRef m) : InputFile(LazyObjectKind, m) {}
+  explicit LazyObjFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+      : InputFile(ctx, LazyObjectKind, m) {}
   static bool classof(const InputFile *f) {
     return f->kind() == LazyObjectKind;
   }
@@ -136,9 +141,11 @@ class LazyObjFile : public InputFile {
 // .obj or .o file. This may be a member of an archive file.
 class ObjFile : public InputFile {
 public:
-  explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {}
-  explicit ObjFile(MemoryBufferRef m, std::vector<Symbol *> &&symbols)
-      : InputFile(ObjectKind, m), symbols(std::move(symbols)) {}
+  explicit ObjFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+      : InputFile(ctx, ObjectKind, m) {}
+  explicit ObjFile(COFFLinkerContext &ctx, MemoryBufferRef m,
+                   std::vector<Symbol *> &&symbols)
+      : InputFile(ctx, ObjectKind, m), symbols(std::move(symbols)) {}
   static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }
   void parse() override;
   MachineTypes getMachineType() override;
@@ -175,8 +182,6 @@ class ObjFile : public InputFile {
 
   bool isResourceObjFile() const { return !resourceChunks.empty(); }
 
-  static std::vector<ObjFile *> instances;
-
   // Flags in the absolute @feat.00 symbol if it is present. These usually
   // indicate if an object was compiled with certain security features enabled
   // like stack guard, safeseh, /guard:cf, or other things.
@@ -228,6 +233,8 @@ class ObjFile : public InputFile {
     return getSection(sym.getSectionNumber());
   }
 
+  void enqueuePdbFile(StringRef path, ObjFile *fromFile);
+
   void initializeChunks();
   void initializeSymbols();
   void initializeFlags();
@@ -318,16 +325,13 @@ class ObjFile : public InputFile {
 // stream.
 class PDBInputFile : public InputFile {
 public:
-  explicit PDBInputFile(MemoryBufferRef m);
+  explicit PDBInputFile(COFFLinkerContext &ctx, MemoryBufferRef m);
   ~PDBInputFile();
   static bool classof(const InputFile *f) { return f->kind() == PDBKind; }
   void parse() override;
 
-  static void enqueue(StringRef path, ObjFile *fromFile);
-
-  static PDBInputFile *findFromRecordPath(StringRef path, ObjFile *fromFile);
-
-  static std::map<std::string, PDBInputFile *> instances;
+  static PDBInputFile *findFromRecordPath(const COFFLinkerContext &ctx,
+                                          StringRef path, ObjFile *fromFile);
 
   // Record possible errors while opening the PDB file
   llvm::Optional<Error> loadErr;
@@ -344,12 +348,11 @@ class PDBInputFile : public InputFile {
 // for details about the format.
 class ImportFile : public InputFile {
 public:
-  explicit ImportFile(MemoryBufferRef m) : InputFile(ImportKind, m) {}
+  explicit ImportFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+      : InputFile(ctx, ImportKind, m) {}
 
   static bool classof(const InputFile *f) { return f->kind() == ImportKind; }
 
-  static std::vector<ImportFile *> instances;
-
   Symbol *impSym = nullptr;
   Symbol *thunkSym = nullptr;
   std::string dllName;
@@ -377,16 +380,15 @@ class ImportFile : public InputFile {
 // Used for LTO.
 class BitcodeFile : public InputFile {
 public:
-  BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
+  BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb, StringRef archiveName,
               uint64_t offsetInArchive);
-  explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName,
-                       uint64_t offsetInArchive,
+  explicit BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef m,
+                       StringRef archiveName, uint64_t offsetInArchive,
                        std::vector<Symbol *> &&symbols);
   ~BitcodeFile();
   static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
   ArrayRef<Symbol *> getSymbols() { return symbols; }
   MachineTypes getMachineType() override;
-  static std::vector<BitcodeFile *> instances;
   std::unique_ptr<llvm::lto::InputFile> obj;
 
 private:
@@ -398,7 +400,8 @@ class BitcodeFile : public InputFile {
 // .dll file. MinGW only.
 class DLLFile : public InputFile {
 public:
-  explicit DLLFile(MemoryBufferRef m) : InputFile(DLLKind, m) {}
+  explicit DLLFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+      : InputFile(ctx, DLLKind, m) {}
   static bool classof(const InputFile *f) { return f->kind() == DLLKind; }
   void parse() override;
   MachineTypes getMachineType() override;

diff  --git a/lld/COFF/LLDMapFile.cpp b/lld/COFF/LLDMapFile.cpp
index 79df33a3535fd..639b186dbb6f9 100644
--- a/lld/COFF/LLDMapFile.cpp
+++ b/lld/COFF/LLDMapFile.cpp
@@ -19,6 +19,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "LLDMapFile.h"
+#include "COFFLinkerContext.h"
 #include "SymbolTable.h"
 #include "Symbols.h"
 #include "Writer.h"
@@ -44,9 +45,9 @@ static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size,
 }
 
 // Returns a list of all symbols that we want to print out.
-static std::vector<DefinedRegular *> getSymbols() {
+static std::vector<DefinedRegular *> getSymbols(const COFFLinkerContext &ctx) {
   std::vector<DefinedRegular *> v;
-  for (ObjFile *file : ObjFile::instances)
+  for (ObjFile *file : ctx.objFileInstances)
     for (Symbol *b : file->getSymbols())
       if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))
         if (sym && !sym->getCOFFSymbol().isSectionDefinition())
@@ -86,7 +87,7 @@ getSymbolStrings(ArrayRef<DefinedRegular *> syms) {
   return ret;
 }
 
-void lld::coff::writeLLDMapFile(ArrayRef<OutputSection *> outputSections) {
+void lld::coff::writeLLDMapFile(const COFFLinkerContext &ctx) {
   if (config->lldmapFile.empty())
     return;
 
@@ -96,7 +97,7 @@ void lld::coff::writeLLDMapFile(ArrayRef<OutputSection *> outputSections) {
     fatal("cannot open " + config->lldmapFile + ": " + ec.message());
 
   // Collect symbol info that we want to print out.
-  std::vector<DefinedRegular *> syms = getSymbols();
+  std::vector<DefinedRegular *> syms = getSymbols(ctx);
   SymbolMapTy sectionSyms = getSectionSyms(syms);
   DenseMap<DefinedRegular *, std::string> symStr = getSymbolStrings(syms);
 
@@ -104,7 +105,7 @@ void lld::coff::writeLLDMapFile(ArrayRef<OutputSection *> outputSections) {
   os << "Address  Size     Align Out     In      Symbol\n";
 
   // Print out file contents.
-  for (OutputSection *sec : outputSections) {
+  for (OutputSection *sec : ctx.outputSections) {
     writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*align=*/pageSize);
     os << sec->name << '\n';
 

diff  --git a/lld/COFF/LLDMapFile.h b/lld/COFF/LLDMapFile.h
index b731293a8625d..72e999a61900a 100644
--- a/lld/COFF/LLDMapFile.h
+++ b/lld/COFF/LLDMapFile.h
@@ -9,12 +9,10 @@
 #ifndef LLD_COFF_LLDMAPFILE_H
 #define LLD_COFF_LLDMAPFILE_H
 
-#include "llvm/ADT/ArrayRef.h"
-
 namespace lld {
 namespace coff {
-class OutputSection;
-void writeLLDMapFile(llvm::ArrayRef<OutputSection *> outputSections);
+class COFFLinkerContext;
+void writeLLDMapFile(const COFFLinkerContext &ctx);
 }
 }
 

diff  --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp
index 6e38f53f21362..ce9c4fd0d51b2 100644
--- a/lld/COFF/LTO.cpp
+++ b/lld/COFF/LTO.cpp
@@ -156,7 +156,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
 
 // Merge all the bitcode files we have seen, codegen the result
 // and return the resulting objects.
-std::vector<InputFile *> BitcodeCompiler::compile() {
+std::vector<InputFile *> BitcodeCompiler::compile(COFFLinkerContext &ctx) {
   unsigned maxTasks = ltoObj->getMaxTasks();
   buf.resize(maxTasks);
   files.resize(maxTasks);
@@ -224,7 +224,7 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
 
     if (config->saveTemps)
       saveBuffer(buf[i], ltoObjName);
-    ret.push_back(make<ObjFile>(MemoryBufferRef(objBuf, ltoObjName)));
+    ret.push_back(make<ObjFile>(ctx, MemoryBufferRef(objBuf, ltoObjName)));
   }
 
   return ret;

diff  --git a/lld/COFF/LTO.h b/lld/COFF/LTO.h
index a2b321df7901b..b05befc7146aa 100644
--- a/lld/COFF/LTO.h
+++ b/lld/COFF/LTO.h
@@ -38,6 +38,7 @@ namespace coff {
 
 class BitcodeFile;
 class InputFile;
+class COFFLinkerContext;
 
 class BitcodeCompiler {
 public:
@@ -45,7 +46,7 @@ class BitcodeCompiler {
   ~BitcodeCompiler();
 
   void add(BitcodeFile &f);
-  std::vector<InputFile *> compile();
+  std::vector<InputFile *> compile(COFFLinkerContext &ctx);
 
 private:
   std::unique_ptr<llvm::lto::LTO> ltoObj;

diff  --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp
index 41e169ef56e22..d7b7de43f3f64 100644
--- a/lld/COFF/MapFile.cpp
+++ b/lld/COFF/MapFile.cpp
@@ -28,6 +28,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "MapFile.h"
+#include "COFFLinkerContext.h"
 #include "SymbolTable.h"
 #include "Symbols.h"
 #include "Writer.h"
@@ -42,11 +43,6 @@ using namespace llvm::object;
 using namespace lld;
 using namespace lld::coff;
 
-static Timer totalMapTimer("MAP emission (Cumulative)", Timer::root());
-static Timer symbolGatherTimer("Gather symbols", totalMapTimer);
-static Timer symbolStringsTimer("Build symbol strings", totalMapTimer);
-static Timer writeTimer("Write to file", totalMapTimer);
-
 // Print out the first two columns of a line.
 static void writeHeader(raw_ostream &os, uint32_t sec, uint64_t addr) {
   os << format(" %04x:%08llx", sec, addr);
@@ -99,9 +95,10 @@ static void sortUniqueSymbols(std::vector<Defined *> &syms) {
 
 // Returns the lists of all symbols that we want to print out.
 static void getSymbols(std::vector<Defined *> &syms,
-                       std::vector<Defined *> &staticSyms) {
+                       std::vector<Defined *> &staticSyms,
+                       const COFFLinkerContext &ctx) {
 
-  for (ObjFile *file : ObjFile::instances)
+  for (ObjFile *file : ctx.objFileInstances)
     for (Symbol *b : file->getSymbols()) {
       if (!b || !b->isLive())
         continue;
@@ -119,7 +116,7 @@ static void getSymbols(std::vector<Defined *> &syms,
       }
     }
 
-  for (ImportFile *file : ImportFile::instances) {
+  for (ImportFile *file : ctx.importFileInstances) {
     if (!file->live)
       continue;
 
@@ -142,7 +139,7 @@ static void getSymbols(std::vector<Defined *> &syms,
 
 // Construct a map from symbols to their stringified representations.
 static DenseMap<Defined *, std::string>
-getSymbolStrings(ArrayRef<Defined *> syms) {
+getSymbolStrings(const COFFLinkerContext &ctx, ArrayRef<Defined *> syms) {
   std::vector<std::string> str(syms.size());
   parallelForEachN((size_t)0, syms.size(), [&](size_t i) {
     raw_string_ostream os(str[i]);
@@ -161,7 +158,7 @@ getSymbolStrings(ArrayRef<Defined *> syms) {
       fileDescr = "<common>";
     } else if (Chunk *chunk = sym->getChunk()) {
       address = sym->getRVA();
-      if (OutputSection *sec = chunk->getOutputSection())
+      if (OutputSection *sec = ctx.getOutputSection(chunk))
         address -= sec->header.VirtualAddress;
 
       sectionIdx = chunk->getOutputSectionIdx();
@@ -201,7 +198,7 @@ getSymbolStrings(ArrayRef<Defined *> syms) {
   return ret;
 }
 
-void lld::coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
+void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
   if (config->mapFile.empty())
     return;
 
@@ -210,21 +207,22 @@ void lld::coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
   if (ec)
     fatal("cannot open " + config->mapFile + ": " + ec.message());
 
-  ScopedTimer t1(totalMapTimer);
+  ScopedTimer t1(ctx.totalMapTimer);
 
   // Collect symbol info that we want to print out.
-  ScopedTimer t2(symbolGatherTimer);
+  ScopedTimer t2(ctx.symbolGatherTimer);
   std::vector<Defined *> syms;
   std::vector<Defined *> staticSyms;
-  getSymbols(syms, staticSyms);
+  getSymbols(syms, staticSyms, ctx);
   t2.stop();
 
-  ScopedTimer t3(symbolStringsTimer);
-  DenseMap<Defined *, std::string> symStr = getSymbolStrings(syms);
-  DenseMap<Defined *, std::string> staticSymStr = getSymbolStrings(staticSyms);
+  ScopedTimer t3(ctx.symbolStringsTimer);
+  DenseMap<Defined *, std::string> symStr = getSymbolStrings(ctx, syms);
+  DenseMap<Defined *, std::string> staticSymStr =
+      getSymbolStrings(ctx, staticSyms);
   t3.stop();
 
-  ScopedTimer t4(writeTimer);
+  ScopedTimer t4(ctx.writeTimer);
   SmallString<128> AppName = sys::path::filename(config->outputFile);
   sys::path::replace_extension(AppName, "");
 
@@ -248,7 +246,7 @@ void lld::coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
   // Print out section table.
   os << " Start         Length     Name                   Class\n";
 
-  for (OutputSection *sec : outputSections) {
+  for (OutputSection *sec : ctx.outputSections) {
     // Merge display of chunks with same sectionName
     std::vector<std::pair<SectionChunk *, SectionChunk *>> ChunkRanges;
     for (Chunk *c : sec->chunks) {
@@ -303,7 +301,7 @@ void lld::coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
       Chunk *chunk = entry->getChunk();
       entrySecIndex = chunk->getOutputSectionIdx();
       entryAddress =
-          entry->getRVA() - chunk->getOutputSection()->header.VirtualAddress;
+          entry->getRVA() - ctx.getOutputSection(chunk)->header.VirtualAddress;
     }
   }
   os << " entry point at         ";

diff  --git a/lld/COFF/MapFile.h b/lld/COFF/MapFile.h
index 2bf01bd072856..d4572332b8b82 100644
--- a/lld/COFF/MapFile.h
+++ b/lld/COFF/MapFile.h
@@ -9,12 +9,10 @@
 #ifndef LLD_COFF_MAPFILE_H
 #define LLD_COFF_MAPFILE_H
 
-#include "llvm/ADT/ArrayRef.h"
-
 namespace lld {
 namespace coff {
-class OutputSection;
-void writeMapFile(llvm::ArrayRef<OutputSection *> outputSections);
+class COFFLinkerContext;
+void writeMapFile(COFFLinkerContext &ctx);
 }
 }
 

diff  --git a/lld/COFF/MarkLive.cpp b/lld/COFF/MarkLive.cpp
index 0afa615a1933e..f53005278e222 100644
--- a/lld/COFF/MarkLive.cpp
+++ b/lld/COFF/MarkLive.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "COFFLinkerContext.h"
 #include "Chunks.h"
 #include "Symbols.h"
 #include "lld/Common/Timer.h"
@@ -15,13 +16,11 @@
 namespace lld {
 namespace coff {
 
-static Timer gctimer("GC", Timer::root());
-
 // Set live bit on for each reachable chunk. Unmarked (unreachable)
 // COMDAT chunks will be ignored by Writer, so they will be excluded
 // from the final output.
-void markLive(ArrayRef<Chunk *> chunks) {
-  ScopedTimer t(gctimer);
+void markLive(COFFLinkerContext &ctx) {
+  ScopedTimer t(ctx.gcTimer);
 
   // We build up a worklist of sections which have been marked as live. We only
   // push into the worklist when we discover an unmarked section, and we mark
@@ -31,7 +30,7 @@ void markLive(ArrayRef<Chunk *> chunks) {
   // COMDAT section chunks are dead by default. Add non-COMDAT chunks. Do not
   // traverse DWARF sections. They are live, but they should not keep other
   // sections alive.
-  for (Chunk *c : chunks)
+  for (Chunk *c : ctx.symtab.getChunks())
     if (auto *sc = dyn_cast<SectionChunk>(c))
       if (sc->live && !sc->isDWARF())
         worklist.push_back(sc);
@@ -70,6 +69,5 @@ void markLive(ArrayRef<Chunk *> chunks) {
       enqueue(&c);
   }
 }
-
 }
 }

diff  --git a/lld/COFF/MarkLive.h b/lld/COFF/MarkLive.h
index e4e4c31c7c796..6f211487236cc 100644
--- a/lld/COFF/MarkLive.h
+++ b/lld/COFF/MarkLive.h
@@ -10,14 +10,13 @@
 #define LLD_COFF_MARKLIVE_H
 
 #include "lld/Common/LLVM.h"
-#include "llvm/ADT/ArrayRef.h"
 
 namespace lld {
 namespace coff {
 
-class Chunk;
+class COFFLinkerContext;
 
-void markLive(ArrayRef<Chunk *> chunks);
+void markLive(COFFLinkerContext &ctx);
 
 } // namespace coff
 } // namespace lld

diff  --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp
index 7c1891e67d45e..148ebe5eea66d 100644
--- a/lld/COFF/MinGW.cpp
+++ b/lld/COFF/MinGW.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "MinGW.h"
+#include "COFFLinkerContext.h"
 #include "Driver.h"
 #include "InputFiles.h"
 #include "SymbolTable.h"
@@ -122,7 +123,8 @@ void AutoExporter::addWholeArchive(StringRef path) {
   excludeLibs.erase(libName);
 }
 
-bool AutoExporter::shouldExport(Defined *sym) const {
+bool AutoExporter::shouldExport(const COFFLinkerContext &ctx,
+                                Defined *sym) const {
   if (!sym || !sym->getChunk())
     return false;
 
@@ -141,7 +143,7 @@ bool AutoExporter::shouldExport(Defined *sym) const {
       return false;
 
   // If a corresponding __imp_ symbol exists and is defined, don't export it.
-  if (symtab->find(("__imp_" + sym->getName()).str()))
+  if (ctx.symtab.find(("__imp_" + sym->getName()).str()))
     return false;
 
   // Check that file is non-null before dereferencing it, symbols not
@@ -192,7 +194,7 @@ static StringRef mangle(Twine sym) {
 // like they are not being used at all, so we explicitly set some flags so
 // that LTO won't eliminate them.
 std::vector<WrappedSymbol>
-lld::coff::addWrappedSymbols(opt::InputArgList &args) {
+lld::coff::addWrappedSymbols(COFFLinkerContext &ctx, opt::InputArgList &args) {
   std::vector<WrappedSymbol> v;
   DenseSet<StringRef> seen;
 
@@ -201,18 +203,18 @@ lld::coff::addWrappedSymbols(opt::InputArgList &args) {
     if (!seen.insert(name).second)
       continue;
 
-    Symbol *sym = symtab->findUnderscore(name);
+    Symbol *sym = ctx.symtab.findUnderscore(name);
     if (!sym)
       continue;
 
-    Symbol *real = symtab->addUndefined(mangle("__real_" + name));
-    Symbol *wrap = symtab->addUndefined(mangle("__wrap_" + name));
+    Symbol *real = ctx.symtab.addUndefined(mangle("__real_" + name));
+    Symbol *wrap = ctx.symtab.addUndefined(mangle("__wrap_" + name));
     v.push_back({sym, real, wrap});
 
     // These symbols may seem undefined initially, but don't bail out
-    // at symtab->reportUnresolvable() due to them, but let wrapSymbols
+    // at symtab.reportUnresolvable() due to them, but let wrapSymbols
     // below sort things out before checking finally with
-    // symtab->resolveRemainingUndefines().
+    // symtab.resolveRemainingUndefines().
     sym->deferUndefined = true;
     real->deferUndefined = true;
     // We want to tell LTO not to inline symbols to be overwritten
@@ -233,13 +235,14 @@ lld::coff::addWrappedSymbols(opt::InputArgList &args) {
 // When this function is executed, only InputFiles and symbol table
 // contain pointers to symbol objects. We visit them to replace pointers,
 // so that wrapped symbols are swapped as instructed by the command line.
-void lld::coff::wrapSymbols(ArrayRef<WrappedSymbol> wrapped) {
+void lld::coff::wrapSymbols(COFFLinkerContext &ctx,
+                            ArrayRef<WrappedSymbol> wrapped) {
   DenseMap<Symbol *, Symbol *> map;
   for (const WrappedSymbol &w : wrapped) {
     map[w.sym] = w.wrap;
     map[w.real] = w.sym;
     if (Defined *d = dyn_cast<Defined>(w.wrap)) {
-      Symbol *imp = symtab->find(("__imp_" + w.sym->getName()).str());
+      Symbol *imp = ctx.symtab.find(("__imp_" + w.sym->getName()).str());
       // Create a new defined local import for the wrap symbol. If
       // no imp prefixed symbol existed, there's no need for it.
       // (We can't easily distinguish whether any object file actually
@@ -247,14 +250,14 @@ void lld::coff::wrapSymbols(ArrayRef<WrappedSymbol> wrapped) {
       if (imp) {
         DefinedLocalImport *wrapimp = make<DefinedLocalImport>(
             saver.save("__imp_" + w.wrap->getName()), d);
-        symtab->localImportChunks.push_back(wrapimp->getChunk());
+        ctx.symtab.localImportChunks.push_back(wrapimp->getChunk());
         map[imp] = wrapimp;
       }
     }
   }
 
   // Update pointers in input files.
-  parallelForEach(ObjFile::instances, [&](ObjFile *file) {
+  parallelForEach(ctx.objFileInstances, [&](ObjFile *file) {
     MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
     for (size_t i = 0, e = syms.size(); i != e; ++i)
       if (Symbol *s = map.lookup(syms[i]))

diff  --git a/lld/COFF/MinGW.h b/lld/COFF/MinGW.h
index 2f2bd119c33d2..8f9343784fa07 100644
--- a/lld/COFF/MinGW.h
+++ b/lld/COFF/MinGW.h
@@ -19,6 +19,7 @@
 
 namespace lld {
 namespace coff {
+class COFFLinkerContext;
 
 // Logic for deciding what symbols to export, when exporting all
 // symbols for MinGW.
@@ -34,7 +35,7 @@ class AutoExporter {
   llvm::StringSet<> excludeLibs;
   llvm::StringSet<> excludeObjects;
 
-  bool shouldExport(Defined *sym) const;
+  bool shouldExport(const COFFLinkerContext &ctx, Defined *sym) const;
 };
 
 void writeDefFile(StringRef name);
@@ -53,9 +54,10 @@ struct WrappedSymbol {
   Symbol *wrap;
 };
 
-std::vector<WrappedSymbol> addWrappedSymbols(llvm::opt::InputArgList &args);
+std::vector<WrappedSymbol> addWrappedSymbols(COFFLinkerContext &ctx,
+                                             llvm::opt::InputArgList &args);
 
-void wrapSymbols(ArrayRef<WrappedSymbol> wrapped);
+void wrapSymbols(COFFLinkerContext &ctx, ArrayRef<WrappedSymbol> wrapped);
 
 } // namespace coff
 } // namespace lld

diff  --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp
index 189bf6038c7d3..73feddaa202d8 100644
--- a/lld/COFF/PDB.cpp
+++ b/lld/COFF/PDB.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "PDB.h"
+#include "COFFLinkerContext.h"
 #include "Chunks.h"
 #include "Config.h"
 #include "DebugTypes.h"
@@ -66,16 +67,6 @@ using llvm::pdb::StringTableFixup;
 
 static ExitOnError exitOnErr;
 
-static Timer totalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root());
-static Timer addObjectsTimer("Add Objects", totalPdbLinkTimer);
-Timer lld::coff::loadGHashTimer("Global Type Hashing", addObjectsTimer);
-Timer lld::coff::mergeGHashTimer("GHash Type Merging", addObjectsTimer);
-static Timer typeMergingTimer("Type Merging", addObjectsTimer);
-static Timer symbolMergingTimer("Symbol Merging", addObjectsTimer);
-static Timer publicsLayoutTimer("Publics Stream Layout", totalPdbLinkTimer);
-static Timer tpiStreamLayoutTimer("TPI Stream Layout", totalPdbLinkTimer);
-static Timer diskCommitTimer("Commit to Disk", totalPdbLinkTimer);
-
 namespace {
 class DebugSHandler;
 
@@ -83,8 +74,8 @@ class PDBLinker {
   friend DebugSHandler;
 
 public:
-  PDBLinker(SymbolTable *symtab)
-      : symtab(symtab), builder(bAlloc), tMerger(bAlloc) {
+  PDBLinker(COFFLinkerContext &ctx)
+      : builder(bAlloc), tMerger(ctx, bAlloc), ctx(ctx) {
     // This isn't strictly necessary, but link.exe usually puts an empty string
     // as the first "valid" string in the string table, so we do the same in
     // order to maintain as much byte-for-byte compatibility as possible.
@@ -107,7 +98,7 @@ class PDBLinker {
   void addPublicsToPDB();
 
   /// Link info for each import file in the symbol table into the PDB.
-  void addImportFilesToPDB(ArrayRef<OutputSection *> outputSections);
+  void addImportFilesToPDB();
 
   void createModuleDBI(ObjFile *file);
 
@@ -144,8 +135,7 @@ class PDBLinker {
                          std::vector<uint8_t> &storage);
 
   /// Add the section map and section contributions to the PDB.
-  void addSections(ArrayRef<OutputSection *> outputSections,
-                   ArrayRef<uint8_t> sectionTable);
+  void addSections(ArrayRef<uint8_t> sectionTable);
 
   /// Write the PDB to disk and store the Guid generated for it in *Guid.
   void commit(codeview::GUID *guid);
@@ -154,12 +144,13 @@ class PDBLinker {
   void printStats();
 
 private:
-  SymbolTable *symtab;
 
   pdb::PDBFileBuilder builder;
 
   TypeMerger tMerger;
 
+  COFFLinkerContext &ctx;
+
   /// PDBs use a single global string table for filenames in the file checksum
   /// table.
   DebugStringTableSubsection pdbStrTab;
@@ -299,11 +290,12 @@ static void addTypeInfo(pdb::TpiStreamBuilder &tpiBuilder,
   });
 }
 
-static void addGHashTypeInfo(pdb::PDBFileBuilder &builder) {
+static void addGHashTypeInfo(COFFLinkerContext &ctx,
+                             pdb::PDBFileBuilder &builder) {
   // Start the TPI or IPI stream header.
   builder.getTpiBuilder().setVersionHeader(pdb::PdbTpiV80);
   builder.getIpiBuilder().setVersionHeader(pdb::PdbTpiV80);
-  for_each(TpiSource::instances, [&](TpiSource *source) {
+  for_each(ctx.tpiSourceList, [&](TpiSource *source) {
     builder.getTpiBuilder().addTypeRecords(source->mergedTpi.recs,
                                            source->mergedTpi.recSizes,
                                            source->mergedTpi.recHashes);
@@ -719,8 +711,9 @@ Error PDBLinker::commitSymbolsForObject(void *ctx, void *obj,
       static_cast<ObjFile *>(obj), writer);
 }
 
-static pdb::SectionContrib createSectionContrib(const Chunk *c, uint32_t modi) {
-  OutputSection *os = c ? c->getOutputSection() : nullptr;
+static pdb::SectionContrib createSectionContrib(COFFLinkerContext &ctx,
+                                                const Chunk *c, uint32_t modi) {
+  OutputSection *os = c ? ctx.getOutputSection(c) : nullptr;
   pdb::SectionContrib sc;
   memset(&sc, 0, sizeof(sc));
   sc.ISect = os ? os->sectionIndex : llvm::pdb::kInvalidStreamIndex;
@@ -1023,7 +1016,7 @@ void PDBLinker::addDebugSymbols(TpiSource *source) {
   if (!source->file)
     return;
 
-  ScopedTimer t(symbolMergingTimer);
+  ScopedTimer t(ctx.symbolMergingTimer);
   pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
   DebugSHandler dsh(*this, *source->file, source);
   // Now do all live .debug$S and .debug$F sections.
@@ -1082,7 +1075,7 @@ void PDBLinker::createModuleDBI(ObjFile *file) {
     auto *secChunk = dyn_cast<SectionChunk>(c);
     if (!secChunk || !secChunk->live)
       continue;
-    pdb::SectionContrib sc = createSectionContrib(secChunk, modi);
+    pdb::SectionContrib sc = createSectionContrib(ctx, secChunk, modi);
     file->moduleDBI->setFirstSectionContrib(sc);
     break;
   }
@@ -1095,7 +1088,7 @@ void PDBLinker::addDebug(TpiSource *source) {
   // indices to PDB type and item indices.  If we are using ghashes, types have
   // already been merged.
   if (!config->debugGHashes) {
-    ScopedTimer t(typeMergingTimer);
+    ScopedTimer t(ctx.typeMergingTimer);
     if (Error e = source->mergeDebugT(&tMerger)) {
       // If type merging failed, ignore the symbols.
       warnUnusable(source->file, std::move(e));
@@ -1113,7 +1106,7 @@ void PDBLinker::addDebug(TpiSource *source) {
   addDebugSymbols(source);
 }
 
-static pdb::BulkPublic createPublic(Defined *def) {
+static pdb::BulkPublic createPublic(COFFLinkerContext &ctx, Defined *def) {
   pdb::BulkPublic pub;
   pub.Name = def->getName().data();
   pub.NameLen = def->getName().size();
@@ -1127,7 +1120,7 @@ static pdb::BulkPublic createPublic(Defined *def) {
   }
   pub.setFlags(flags);
 
-  OutputSection *os = def->getChunk()->getOutputSection();
+  OutputSection *os = ctx.getOutputSection(def->getChunk());
   assert(os && "all publics should be in final image");
   pub.Offset = def->getRVA() - os->getRVA();
   pub.Segment = os->sectionIndex;
@@ -1137,32 +1130,31 @@ static pdb::BulkPublic createPublic(Defined *def) {
 // Add all object files to the PDB. Merge .debug$T sections into IpiData and
 // TpiData.
 void PDBLinker::addObjectsToPDB() {
-  ScopedTimer t1(addObjectsTimer);
+  ScopedTimer t1(ctx.addObjectsTimer);
 
   // Create module descriptors
-  for_each(ObjFile::instances, [&](ObjFile *obj) { createModuleDBI(obj); });
+  for_each(ctx.objFileInstances, [&](ObjFile *obj) { createModuleDBI(obj); });
 
   // Reorder dependency type sources to come first.
-  TpiSource::sortDependencies();
+  tMerger.sortDependencies();
 
   // Merge type information from input files using global type hashing.
   if (config->debugGHashes)
     tMerger.mergeTypesWithGHash();
 
   // Merge dependencies and then regular objects.
-  for_each(TpiSource::dependencySources,
-           [&](TpiSource *source) { addDebug(source); });
-  for_each(TpiSource::objectSources,
+  for_each(tMerger.dependencySources,
            [&](TpiSource *source) { addDebug(source); });
+  for_each(tMerger.objectSources, [&](TpiSource *source) { addDebug(source); });
 
   builder.getStringTableBuilder().setStrings(pdbStrTab);
   t1.stop();
 
   // Construct TPI and IPI stream contents.
-  ScopedTimer t2(tpiStreamLayoutTimer);
+  ScopedTimer t2(ctx.tpiStreamLayoutTimer);
   // Collect all the merged types.
   if (config->debugGHashes) {
-    addGHashTypeInfo(builder);
+    addGHashTypeInfo(ctx, builder);
   } else {
     addTypeInfo(builder.getTpiBuilder(), tMerger.getTypeTable());
     addTypeInfo(builder.getIpiBuilder(), tMerger.getIDTable());
@@ -1170,7 +1162,7 @@ void PDBLinker::addObjectsToPDB() {
   t2.stop();
 
   if (config->showSummary) {
-    for_each(TpiSource::instances, [&](TpiSource *source) {
+    for_each(ctx.tpiSourceList, [&](TpiSource *source) {
       nbTypeRecords += source->nbTypeRecords;
       nbTypeRecordsBytes += source->nbTypeRecordsBytes;
     });
@@ -1178,11 +1170,11 @@ void PDBLinker::addObjectsToPDB() {
 }
 
 void PDBLinker::addPublicsToPDB() {
-  ScopedTimer t3(publicsLayoutTimer);
+  ScopedTimer t3(ctx.publicsLayoutTimer);
   // Compute the public symbols.
   auto &gsiBuilder = builder.getGsiBuilder();
   std::vector<pdb::BulkPublic> publics;
-  symtab->forEachSymbol([&publics](Symbol *s) {
+  ctx.symtab.forEachSymbol([&publics, this](Symbol *s) {
     // Only emit external, defined, live symbols that have a chunk. Static,
     // non-external symbols do not appear in the symbol table.
     auto *def = dyn_cast<Defined>(s);
@@ -1203,7 +1195,7 @@ void PDBLinker::addPublicsToPDB() {
           return;
         }
       }
-      publics.push_back(createPublic(def));
+      publics.push_back(createPublic(ctx, def));
     }
   });
 
@@ -1227,10 +1219,10 @@ void PDBLinker::printStats() {
     stream << format_decimal(v, 15) << " " << s << '\n';
   };
 
-  print(ObjFile::instances.size(),
+  print(ctx.objFileInstances.size(),
         "Input OBJ files (expanded from all cmd-line inputs)");
-  print(TpiSource::countTypeServerPDBs(), "PDB type server dependencies");
-  print(TpiSource::countPrecompObjs(), "Precomp OBJ dependencies");
+  print(ctx.typeServerSourceMappings.size(), "PDB type server dependencies");
+  print(ctx.precompSourceMappings.size(), "Precomp OBJ dependencies");
   print(nbTypeRecords, "Input type records");
   print(nbTypeRecordsBytes, "Input type records bytes");
   print(builder.getTpiBuilder().getRecordCount(), "Merged TPI records");
@@ -1483,13 +1475,13 @@ static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &mod,
 }
 
 // Add all import files as modules to the PDB.
-void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) {
-  if (ImportFile::instances.empty())
+void PDBLinker::addImportFilesToPDB() {
+  if (ctx.importFileInstances.empty())
     return;
 
   std::map<std::string, llvm::pdb::DbiModuleDescriptorBuilder *> dllToModuleDbi;
 
-  for (ImportFile *file : ImportFile::instances) {
+  for (ImportFile *file : ctx.importFileInstances) {
     if (!file->live)
       continue;
 
@@ -1513,7 +1505,7 @@ void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) {
           exitOnErr(dbiBuilder.addModuleInfo(file->dllName));
       firstMod.setObjFileName(libPath);
       pdb::SectionContrib sc =
-          createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex);
+          createSectionContrib(ctx, nullptr, llvm::pdb::kInvalidStreamIndex);
       firstMod.setFirstSectionContrib(sc);
 
       // The second module is where the import stream goes.
@@ -1523,7 +1515,7 @@ void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) {
 
     DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym);
     Chunk *thunkChunk = thunk->getChunk();
-    OutputSection *thunkOS = thunkChunk->getOutputSection();
+    OutputSection *thunkOS = ctx.getOutputSection(thunkChunk);
 
     ObjNameSym ons(SymbolRecordKind::ObjNameSym);
     Compile3Sym cs(SymbolRecordKind::Compile3Sym);
@@ -1565,28 +1557,27 @@ void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) {
     mod->addSymbol(newSym);
 
     pdb::SectionContrib sc =
-        createSectionContrib(thunk->getChunk(), mod->getModuleIndex());
+        createSectionContrib(ctx, thunk->getChunk(), mod->getModuleIndex());
     mod->setFirstSectionContrib(sc);
   }
 }
 
 // Creates a PDB file.
-void lld::coff::createPDB(SymbolTable *symtab,
-                          ArrayRef<OutputSection *> outputSections,
+void lld::coff::createPDB(COFFLinkerContext &ctx,
                           ArrayRef<uint8_t> sectionTable,
                           llvm::codeview::DebugInfo *buildId) {
-  ScopedTimer t1(totalPdbLinkTimer);
-  PDBLinker pdb(symtab);
+  ScopedTimer t1(ctx.totalPdbLinkTimer);
+  PDBLinker pdb(ctx);
 
   pdb.initialize(buildId);
   pdb.addObjectsToPDB();
-  pdb.addImportFilesToPDB(outputSections);
-  pdb.addSections(outputSections, sectionTable);
+  pdb.addImportFilesToPDB();
+  pdb.addSections(sectionTable);
   pdb.addNatvisFiles();
   pdb.addNamedStreams();
   pdb.addPublicsToPDB();
 
-  ScopedTimer t2(diskCommitTimer);
+  ScopedTimer t2(ctx.diskCommitTimer);
   codeview::GUID guid;
   pdb.commit(&guid);
   memcpy(&buildId->PDB70.Signature, &guid, 16);
@@ -1626,8 +1617,7 @@ void PDBLinker::initialize(llvm::codeview::DebugInfo *buildId) {
   dbiBuilder.setBuildNumber(14, 11);
 }
 
-void PDBLinker::addSections(ArrayRef<OutputSection *> outputSections,
-                            ArrayRef<uint8_t> sectionTable) {
+void PDBLinker::addSections(ArrayRef<uint8_t> sectionTable) {
   // It's not entirely clear what this is, but the * Linker * module uses it.
   pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
   nativePath = config->pdbPath;
@@ -1638,11 +1628,11 @@ void PDBLinker::addSections(ArrayRef<OutputSection *> outputSections,
   addCommonLinkerModuleSymbols(nativePath, linkerModule);
 
   // Add section contributions. They must be ordered by ascending RVA.
-  for (OutputSection *os : outputSections) {
+  for (OutputSection *os : ctx.outputSections) {
     addLinkerModuleSectionSymbol(linkerModule, *os);
     for (Chunk *c : os->chunks) {
       pdb::SectionContrib sc =
-          createSectionContrib(c, linkerModule.getModuleIndex());
+          createSectionContrib(ctx, c, linkerModule.getModuleIndex());
       builder.getDbiBuilder().addSectionContrib(sc);
     }
   }
@@ -1651,7 +1641,7 @@ void PDBLinker::addSections(ArrayRef<OutputSection *> outputSections,
   // to provide trampolines thunks for incremental function patching. Set this
   // as "unused" because LLD doesn't support /INCREMENTAL link.
   pdb::SectionContrib sc =
-      createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex);
+      createSectionContrib(ctx, nullptr, llvm::pdb::kInvalidStreamIndex);
   linkerModule.setFirstSectionContrib(sc);
 
   // Add Section Map stream.

diff  --git a/lld/COFF/PDB.h b/lld/COFF/PDB.h
index 53506d40baef4..8381374dcc8a6 100644
--- a/lld/COFF/PDB.h
+++ b/lld/COFF/PDB.h
@@ -23,21 +23,15 @@ namespace lld {
 class Timer;
 
 namespace coff {
-class OutputSection;
 class SectionChunk;
-class SymbolTable;
+class COFFLinkerContext;
 
-void createPDB(SymbolTable *symtab,
-               llvm::ArrayRef<OutputSection *> outputSections,
-               llvm::ArrayRef<uint8_t> sectionTable,
+void createPDB(COFFLinkerContext &ctx, llvm::ArrayRef<uint8_t> sectionTable,
                llvm::codeview::DebugInfo *buildId);
 
 llvm::Optional<std::pair<llvm::StringRef, uint32_t>>
 getFileLineCodeView(const SectionChunk *c, uint32_t addr);
 
-extern Timer loadGHashTimer;
-extern Timer mergeGHashTimer;
-
 } // namespace coff
 } // namespace lld
 

diff  --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 536f343507243..47b339b981fd6 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "SymbolTable.h"
+#include "COFFLinkerContext.h"
 #include "Config.h"
 #include "Driver.h"
 #include "LTO.h"
@@ -34,10 +35,6 @@ StringRef ltrim1(StringRef s, const char *chars) {
   return s;
 }
 
-static Timer ltoTimer("LTO", Timer::root());
-
-SymbolTable *symtab;
-
 void SymbolTable::addFile(InputFile *file) {
   log("Reading " + toString(file));
   file->parse();
@@ -52,11 +49,11 @@ void SymbolTable::addFile(InputFile *file) {
   }
 
   if (auto *f = dyn_cast<ObjFile>(file)) {
-    ObjFile::instances.push_back(f);
+    ctx.objFileInstances.push_back(f);
   } else if (auto *f = dyn_cast<BitcodeFile>(file)) {
-    BitcodeFile::instances.push_back(f);
+    ctx.bitcodeFileInstances.push_back(f);
   } else if (auto *f = dyn_cast<ImportFile>(file)) {
-    ImportFile::instances.push_back(f);
+    ctx.importFileInstances.push_back(f);
   }
 
   driver->parseDirectives(file);
@@ -372,12 +369,9 @@ bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
 /// defined symbol imported" diagnostic for symbols in localImports.
 /// objFiles and bitcodeFiles (if not nullptr) are used to report where
 /// undefined symbols are referenced.
-static void
-reportProblemSymbols(const SmallPtrSetImpl<Symbol *> &undefs,
-                     const DenseMap<Symbol *, Symbol *> *localImports,
-                     const std::vector<ObjFile *> objFiles,
-                     const std::vector<BitcodeFile *> *bitcodeFiles) {
-
+static void reportProblemSymbols(
+    const COFFLinkerContext &ctx, const SmallPtrSetImpl<Symbol *> &undefs,
+    const DenseMap<Symbol *, Symbol *> *localImports, bool needBitcodeFiles) {
   // Return early if there is nothing to report (which should be
   // the common case).
   if (undefs.empty() && (!localImports || localImports->empty()))
@@ -418,11 +412,11 @@ reportProblemSymbols(const SmallPtrSetImpl<Symbol *> &undefs,
     }
   };
 
-  for (ObjFile *file : objFiles)
+  for (ObjFile *file : ctx.objFileInstances)
     processFile(file, file->getSymbols());
 
-  if (bitcodeFiles)
-    for (BitcodeFile *file : *bitcodeFiles)
+  if (needBitcodeFiles)
+    for (BitcodeFile *file : ctx.bitcodeFileInstances)
       processFile(file, file->getSymbols());
 
   for (const UndefinedDiag &undefDiag : undefDiags)
@@ -451,9 +445,8 @@ void SymbolTable::reportUnresolvable() {
     undefs.insert(sym);
   }
 
-  reportProblemSymbols(undefs,
-                       /* localImports */ nullptr, ObjFile::instances,
-                       &BitcodeFile::instances);
+  reportProblemSymbols(ctx, undefs,
+                       /* localImports */ nullptr, true);
 }
 
 void SymbolTable::resolveRemainingUndefines() {
@@ -515,8 +508,8 @@ void SymbolTable::resolveRemainingUndefines() {
   }
 
   reportProblemSymbols(
-      undefs, config->warnLocallyDefinedImported ? &localImports : nullptr,
-      ObjFile::instances, /* bitcode files no longer needed */ nullptr);
+      ctx, undefs, config->warnLocallyDefinedImported ? &localImports : nullptr,
+      false);
 }
 
 std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
@@ -797,20 +790,20 @@ void SymbolTable::addLibcall(StringRef name) {
   }
 }
 
-std::vector<Chunk *> SymbolTable::getChunks() {
+std::vector<Chunk *> SymbolTable::getChunks() const {
   std::vector<Chunk *> res;
-  for (ObjFile *file : ObjFile::instances) {
+  for (ObjFile *file : ctx.objFileInstances) {
     ArrayRef<Chunk *> v = file->getChunks();
     res.insert(res.end(), v.begin(), v.end());
   }
   return res;
 }
 
-Symbol *SymbolTable::find(StringRef name) {
+Symbol *SymbolTable::find(StringRef name) const {
   return symMap.lookup(CachedHashStringRef(name));
 }
 
-Symbol *SymbolTable::findUnderscore(StringRef name) {
+Symbol *SymbolTable::findUnderscore(StringRef name) const {
   if (config->machine == I386)
     return find(("_" + name).str());
   return find(name);
@@ -873,17 +866,17 @@ Symbol *SymbolTable::addUndefined(StringRef name) {
 }
 
 void SymbolTable::addCombinedLTOObjects() {
-  if (BitcodeFile::instances.empty())
+  if (ctx.bitcodeFileInstances.empty())
     return;
 
-  ScopedTimer t(ltoTimer);
-  lto.reset(new BitcodeCompiler);
-  for (BitcodeFile *f : BitcodeFile::instances)
+  ScopedTimer t(ctx.ltoTimer);
+  lto.reset(new BitcodeCompiler());
+  for (BitcodeFile *f : ctx.bitcodeFileInstances)
     lto->add(*f);
-  for (InputFile *newObj : lto->compile()) {
+  for (InputFile *newObj : lto->compile(ctx)) {
     ObjFile *obj = cast<ObjFile>(newObj);
     obj->parse();
-    ObjFile::instances.push_back(obj);
+    ctx.objFileInstances.push_back(obj);
   }
 }
 

diff  --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index e88002c883101..03bc7f90e82ec 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -25,6 +25,7 @@ namespace coff {
 
 class Chunk;
 class CommonChunk;
+class COFFLinkerContext;
 class Defined;
 class DefinedAbsolute;
 class DefinedRegular;
@@ -47,6 +48,8 @@ class Symbol;
 // There is one add* function per symbol type.
 class SymbolTable {
 public:
+  SymbolTable(COFFLinkerContext &ctx) : ctx(ctx) {}
+
   void addFile(InputFile *file);
 
   // Emit errors for symbols that cannot be resolved.
@@ -63,11 +66,11 @@ class SymbolTable {
   bool handleMinGWAutomaticImport(Symbol *sym, StringRef name);
 
   // Returns a list of chunks of selected symbols.
-  std::vector<Chunk *> getChunks();
+  std::vector<Chunk *> getChunks() const;
 
   // Returns a symbol for a given name. Returns a nullptr if not found.
-  Symbol *find(StringRef name);
-  Symbol *findUnderscore(StringRef name);
+  Symbol *find(StringRef name) const;
+  Symbol *findUnderscore(StringRef name) const;
 
   // Occasionally we have to resolve an undefined symbol to its
   // mangled symbol. This function tries to find a mangled name
@@ -131,9 +134,9 @@ class SymbolTable {
 
   llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> symMap;
   std::unique_ptr<BitcodeCompiler> lto;
-};
 
-extern SymbolTable *symtab;
+  COFFLinkerContext &ctx;
+};
 
 std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex);
 

diff  --git a/lld/COFF/TypeMerger.h b/lld/COFF/TypeMerger.h
index 72fd5fc72b011..8cb9433c4bf6b 100644
--- a/lld/COFF/TypeMerger.h
+++ b/lld/COFF/TypeMerger.h
@@ -10,6 +10,8 @@
 #define LLD_COFF_TYPEMERGER_H
 
 #include "Config.h"
+#include "DebugTypes.h"
+#include "lld/Common/Timer.h"
 #include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
 #include "llvm/DebugInfo/CodeView/TypeHashing.h"
 #include "llvm/Support/Allocator.h"
@@ -25,7 +27,7 @@ struct GHashState;
 
 class TypeMerger {
 public:
-  TypeMerger(llvm::BumpPtrAllocator &alloc);
+  TypeMerger(COFFLinkerContext &ctx, llvm::BumpPtrAllocator &alloc);
 
   ~TypeMerger();
 
@@ -59,6 +61,20 @@ class TypeMerger {
   // keyed by type index.
   SmallVector<uint32_t, 0> tpiCounts;
   SmallVector<uint32_t, 0> ipiCounts;
+
+  /// Dependency type sources, such as type servers or PCH object files. These
+  /// must be processed before objects that rely on them. Set by
+  /// sortDependencies.
+  ArrayRef<TpiSource *> dependencySources;
+
+  /// Object file sources. These must be processed after dependencySources.
+  ArrayRef<TpiSource *> objectSources;
+
+  /// Sorts the dependencies and reassigns TpiSource indices.
+  void sortDependencies();
+
+private:
+  COFFLinkerContext &ctx;
 };
 
 } // namespace coff

diff  --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 37cbe2bb96a80..6641db119064f 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Writer.h"
+#include "COFFLinkerContext.h"
 #include "CallGraphSort.h"
 #include "Config.h"
 #include "DLL.h"
@@ -80,23 +81,14 @@ static_assert(dosStubSize % 8 == 0, "DOSStub size must be multiple of 8");
 
 static const int numberOfDataDirectory = 16;
 
-// Global vector of all output sections. After output sections are finalized,
-// this can be indexed by Chunk::getOutputSection.
-static std::vector<OutputSection *> outputSections;
-
-OutputSection *Chunk::getOutputSection() const {
-  return osidx == 0 ? nullptr : outputSections[osidx - 1];
-}
-
-void OutputSection::clear() { outputSections.clear(); }
-
 namespace {
 
 class DebugDirectoryChunk : public NonSectionChunk {
 public:
-  DebugDirectoryChunk(const std::vector<std::pair<COFF::DebugType, Chunk *>> &r,
+  DebugDirectoryChunk(COFFLinkerContext &c,
+                      const std::vector<std::pair<COFF::DebugType, Chunk *>> &r,
                       bool writeRepro)
-      : records(r), writeRepro(writeRepro) {}
+      : records(r), writeRepro(writeRepro), ctx(c) {}
 
   size_t getSize() const override {
     return (records.size() + int(writeRepro)) * sizeof(debug_directory);
@@ -107,7 +99,7 @@ class DebugDirectoryChunk : public NonSectionChunk {
 
     for (const std::pair<COFF::DebugType, Chunk *>& record : records) {
       Chunk *c = record.second;
-      OutputSection *os = c->getOutputSection();
+      OutputSection *os = ctx.getOutputSection(c);
       uint64_t offs = os->getFileOff() + (c->getRVA() - os->getRVA());
       fillEntry(d, record.first, c->getSize(), c->getRVA(), offs);
       ++d;
@@ -146,6 +138,8 @@ class DebugDirectoryChunk : public NonSectionChunk {
   mutable std::vector<support::ulittle32_t *> timeDateStamps;
   const std::vector<std::pair<COFF::DebugType, Chunk *>> &records;
   bool writeRepro;
+
+  COFFLinkerContext &ctx;
 };
 
 class CVDebugRecordChunk : public NonSectionChunk {
@@ -201,7 +195,7 @@ class PartialSectionKey {
 // The writer writes a SymbolTable result to a file.
 class Writer {
 public:
-  Writer() : buffer(errorHandler().outputBuffer) {}
+  Writer(COFFLinkerContext &c) : buffer(errorHandler().outputBuffer), ctx(c) {}
   void run();
 
 private:
@@ -304,13 +298,12 @@ class Writer {
   // files, so we need to keep track of them separately.
   Chunk *firstPdata = nullptr;
   Chunk *lastPdata;
+
+  COFFLinkerContext &ctx;
 };
 } // anonymous namespace
 
-static Timer codeLayoutTimer("Code Layout", Timer::root());
-static Timer diskCommitTimer("Commit Output File", Timer::root());
-
-void lld::coff::writeResult() { Writer().run(); }
+void lld::coff::writeResult(COFFLinkerContext &ctx) { Writer(ctx).run(); }
 
 void OutputSection::addChunk(Chunk *c) {
   chunks.push_back(c);
@@ -549,7 +542,7 @@ void Writer::finalizeAddresses() {
     return;
 
   size_t origNumChunks = 0;
-  for (OutputSection *sec : outputSections) {
+  for (OutputSection *sec : ctx.outputSections) {
     sec->origChunks = sec->chunks;
     origNumChunks += sec->chunks.size();
   }
@@ -561,7 +554,7 @@ void Writer::finalizeAddresses() {
     // adding them turned out ok.
     bool rangesOk = true;
     size_t numChunks = 0;
-    for (OutputSection *sec : outputSections) {
+    for (OutputSection *sec : ctx.outputSections) {
       if (!verifyRanges(sec->chunks)) {
         rangesOk = false;
         break;
@@ -582,7 +575,7 @@ void Writer::finalizeAddresses() {
       // If the previous pass didn't work out, reset everything back to the
       // original conditions before retrying with a wider margin. This should
       // ideally never happen under real circumstances.
-      for (OutputSection *sec : outputSections)
+      for (OutputSection *sec : ctx.outputSections)
         sec->chunks = sec->origChunks;
       margin *= 2;
     }
@@ -590,7 +583,7 @@ void Writer::finalizeAddresses() {
     // Try adding thunks everywhere where it is needed, with a margin
     // to avoid things going out of range due to the added thunks.
     bool addressesChanged = false;
-    for (OutputSection *sec : outputSections)
+    for (OutputSection *sec : ctx.outputSections)
       addressesChanged |= createThunks(sec, margin);
     // If the verification above thought we needed thunks, we should have
     // added some.
@@ -607,7 +600,7 @@ void Writer::finalizeAddresses() {
 
 // The main function of the writer.
 void Writer::run() {
-  ScopedTimer t1(codeLayoutTimer);
+  ScopedTimer t1(ctx.codeLayoutTimer);
 
   createImportTables();
   createSections();
@@ -645,17 +638,17 @@ void Writer::run() {
 
   if (!config->pdbPath.empty() && config->debug) {
     assert(buildId);
-    createPDB(symtab, outputSections, sectionTable, buildId->buildId);
+    createPDB(ctx, sectionTable, buildId->buildId);
   }
   writeBuildId();
 
-  writeLLDMapFile(outputSections);
-  writeMapFile(outputSections);
+  writeLLDMapFile(ctx);
+  writeMapFile(ctx);
 
   if (errorCount())
     return;
 
-  ScopedTimer t2(diskCommitTimer);
+  ScopedTimer t2(ctx.outputCommitTimer);
   if (auto e = buffer->commit())
     fatal("failed to write the output file: " + toString(std::move(e)));
 }
@@ -816,7 +809,8 @@ static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) {
 
 void Writer::sortSections() {
   if (!config->callGraphProfile.empty()) {
-    DenseMap<const SectionChunk *, int> order = computeCallGraphProfileOrder();
+    DenseMap<const SectionChunk *, int> order =
+        computeCallGraphProfileOrder(ctx);
     for (auto it : order) {
       if (DefinedRegular *sym = it.first->sym)
         config->order[sym->getName()] = it.second;
@@ -843,7 +837,7 @@ void Writer::createSections() {
     OutputSection *&sec = sections[{name, outChars}];
     if (!sec) {
       sec = make<OutputSection>(name, outChars);
-      outputSections.push_back(sec);
+      ctx.outputSections.push_back(sec);
     }
     return sec;
   };
@@ -864,7 +858,7 @@ void Writer::createSections() {
   dtorsSec = createSection(".dtors", data | r | w);
 
   // Then bin chunks by name and output characteristics.
-  for (Chunk *c : symtab->getChunks()) {
+  for (Chunk *c : ctx.symtab.getChunks()) {
     auto *sc = dyn_cast<SectionChunk>(c);
     if (sc && !sc->live) {
       if (config->verbose)
@@ -941,14 +935,14 @@ void Writer::createSections() {
       return 1;
     return 0;
   };
-  llvm::stable_sort(outputSections,
+  llvm::stable_sort(ctx.outputSections,
                     [&](const OutputSection *s, const OutputSection *t) {
                       return sectionOrder(s) < sectionOrder(t);
                     });
 }
 
 void Writer::createMiscChunks() {
-  for (MergeChunk *p : MergeChunk::instances) {
+  for (MergeChunk *p : ctx.mergeChunkInstances) {
     if (p) {
       p->finalizeContents();
       rdataSec->addChunk(p);
@@ -956,15 +950,16 @@ void Writer::createMiscChunks() {
   }
 
   // Create thunks for locally-dllimported symbols.
-  if (!symtab->localImportChunks.empty()) {
-    for (Chunk *c : symtab->localImportChunks)
+  if (!ctx.symtab.localImportChunks.empty()) {
+    for (Chunk *c : ctx.symtab.localImportChunks)
       rdataSec->addChunk(c);
   }
 
   // Create Debug Information Chunks
   OutputSection *debugInfoSec = config->mingw ? buildidSec : rdataSec;
   if (config->debug || config->repro || config->cetCompat) {
-    debugDirectory = make<DebugDirectoryChunk>(debugRecords, config->repro);
+    debugDirectory =
+        make<DebugDirectoryChunk>(ctx, debugRecords, config->repro);
     debugDirectory->setAlignment(4);
     debugInfoSec->addChunk(debugDirectory);
   }
@@ -1013,7 +1008,7 @@ void Writer::createImportTables() {
   // Initialize DLLOrder so that import entries are ordered in
   // the same order as in the command line. (That affects DLL
   // initialization order, and this ordering is MSVC-compatible.)
-  for (ImportFile *file : ImportFile::instances) {
+  for (ImportFile *file : ctx.importFileInstances) {
     if (!file->live)
       continue;
 
@@ -1036,10 +1031,10 @@ void Writer::createImportTables() {
 }
 
 void Writer::appendImportThunks() {
-  if (ImportFile::instances.empty())
+  if (ctx.importFileInstances.empty())
     return;
 
-  for (ImportFile *file : ImportFile::instances) {
+  for (ImportFile *file : ctx.importFileInstances) {
     if (!file->live)
       continue;
 
@@ -1055,7 +1050,7 @@ void Writer::appendImportThunks() {
 
   if (!delayIdata.empty()) {
     Defined *helper = cast<Defined>(config->delayLoadHelper);
-    delayIdata.create(helper);
+    delayIdata.create(ctx, helper);
     for (Chunk *c : delayIdata.getChunks())
       didatSec->addChunk(c);
     for (Chunk *c : delayIdata.getDataChunks())
@@ -1095,25 +1090,25 @@ void Writer::removeUnusedSections() {
     // later. Only remove sections that have no Chunks at all.
     return s->chunks.empty();
   };
-  outputSections.erase(
-      std::remove_if(outputSections.begin(), outputSections.end(), isUnused),
-      outputSections.end());
+  ctx.outputSections.erase(std::remove_if(ctx.outputSections.begin(),
+                                          ctx.outputSections.end(), isUnused),
+                           ctx.outputSections.end());
 }
 
 // The Windows loader doesn't seem to like empty sections,
 // so we remove them if any.
 void Writer::removeEmptySections() {
   auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; };
-  outputSections.erase(
-      std::remove_if(outputSections.begin(), outputSections.end(), isEmpty),
-      outputSections.end());
+  ctx.outputSections.erase(std::remove_if(ctx.outputSections.begin(),
+                                          ctx.outputSections.end(), isEmpty),
+                           ctx.outputSections.end());
 }
 
 void Writer::assignOutputSectionIndices() {
   // Assign final output section indices, and assign each chunk to its output
   // section.
   uint32_t idx = 1;
-  for (OutputSection *os : outputSections) {
+  for (OutputSection *os : ctx.outputSections) {
     os->sectionIndex = idx;
     for (Chunk *c : os->chunks)
       c->setOutputSectionIdx(idx);
@@ -1122,7 +1117,7 @@ void Writer::assignOutputSectionIndices() {
 
   // Merge chunks are containers of chunks, so assign those an output section
   // too.
-  for (MergeChunk *mc : MergeChunk::instances)
+  for (MergeChunk *mc : ctx.mergeChunkInstances)
     if (mc)
       for (SectionChunk *sc : mc->sections)
         if (sc && sc->live)
@@ -1153,7 +1148,7 @@ Optional<coff_symbol16> Writer::createSymbol(Defined *def) {
     Chunk *c = def->getChunk();
     if (!c)
       return None;
-    OutputSection *os = c->getOutputSection();
+    OutputSection *os = ctx.getOutputSection(c);
     if (!os)
       return None;
 
@@ -1200,7 +1195,7 @@ void Writer::createSymbolAndStringTable() {
   // solution where discardable sections have long names preserved and
   // non-discardable sections have their names truncated, to ensure that any
   // section which is mapped at runtime also has its name mapped at runtime.
-  for (OutputSection *sec : outputSections) {
+  for (OutputSection *sec : ctx.outputSections) {
     if (sec->name.size() <= COFF::NameSize)
       continue;
     if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
@@ -1214,7 +1209,7 @@ void Writer::createSymbolAndStringTable() {
   }
 
   if (config->debugDwarf || config->debugSymtab) {
-    for (ObjFile *file : ObjFile::instances) {
+    for (ObjFile *file : ctx.objFileInstances) {
       for (Symbol *b : file->getSymbols()) {
         auto *d = dyn_cast_or_null<Defined>(b);
         if (!d || d->writtenToSymtab)
@@ -1274,7 +1269,7 @@ void Writer::mergeSections() {
 void Writer::assignAddresses() {
   sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +
                   sizeof(data_directory) * numberOfDataDirectory +
-                  sizeof(coff_section) * outputSections.size();
+                  sizeof(coff_section) * ctx.outputSections.size();
   sizeOfHeaders +=
       config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
   sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign);
@@ -1283,7 +1278,7 @@ void Writer::assignAddresses() {
   // The first page is kept unmapped.
   uint64_t rva = alignTo(sizeOfHeaders, config->align);
 
-  for (OutputSection *sec : outputSections) {
+  for (OutputSection *sec : ctx.outputSections) {
     if (sec == relocSec)
       addBaserels();
     uint64_t rawSize = 0, virtualSize = 0;
@@ -1318,7 +1313,7 @@ void Writer::assignAddresses() {
   sizeOfImage = alignTo(rva, config->align);
 
   // Assign addresses to sections in MergeChunks.
-  for (MergeChunk *mc : MergeChunk::instances)
+  for (MergeChunk *mc : ctx.mergeChunkInstances)
     if (mc)
       mc->assignSubsectionRVAs();
 }
@@ -1353,7 +1348,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
   auto *coff = reinterpret_cast<coff_file_header *>(buf);
   buf += sizeof(*coff);
   coff->Machine = config->machine;
-  coff->NumberOfSections = outputSections.size();
+  coff->NumberOfSections = ctx.outputSections.size();
   coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
   if (config->largeAddressAware)
     coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
@@ -1466,7 +1461,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
     dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA();
     dir[BASE_RELOCATION_TABLE].Size = relocSec->getVirtualSize();
   }
-  if (Symbol *sym = symtab->findUnderscore("_tls_used")) {
+  if (Symbol *sym = ctx.symtab.findUnderscore("_tls_used")) {
     if (Defined *b = dyn_cast<Defined>(sym)) {
       dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA();
       dir[TLS_TABLE].Size = config->is64()
@@ -1478,7 +1473,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
     dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA();
     dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize();
   }
-  if (Symbol *sym = symtab->findUnderscore("_load_config_used")) {
+  if (Symbol *sym = ctx.symtab.findUnderscore("_load_config_used")) {
     if (auto *b = dyn_cast<DefinedRegular>(sym)) {
       SectionChunk *sc = b->getChunk();
       assert(b->getRVA() >= sc->getRVA());
@@ -1502,12 +1497,12 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
   }
 
   // Write section table
-  for (OutputSection *sec : outputSections) {
+  for (OutputSection *sec : ctx.outputSections) {
     sec->writeHeaderTo(buf);
     buf += sizeof(coff_section);
   }
   sectionTable = ArrayRef<uint8_t>(
-      buf - outputSections.size() * sizeof(coff_section), buf);
+      buf - ctx.outputSections.size() * sizeof(coff_section), buf);
 
   if (outputSymtab.empty() && strtab.empty())
     return;
@@ -1535,7 +1530,7 @@ void Writer::openFile(StringRef path) {
 
 void Writer::createSEHTable() {
   SymbolRVASet handlers;
-  for (ObjFile *file : ObjFile::instances) {
+  for (ObjFile *file : ctx.objFileInstances) {
     if (!file->hasSafeSEH())
       error("/safeseh: " + file->getName() + " is not compatible with SEH");
     markSymbolsForRVATable(file, file->getSXDataChunks(), handlers);
@@ -1544,7 +1539,7 @@ void Writer::createSEHTable() {
   // Set the "no SEH" characteristic if there really were no handlers, or if
   // there is no load config object to point to the table of handlers.
   setNoSEHCharacteristic =
-      handlers.empty() || !symtab->findUnderscore("_load_config_used");
+      handlers.empty() || !ctx.symtab.findUnderscore("_load_config_used");
 
   maybeAddRVATable(std::move(handlers), "__safe_se_handler_table",
                    "__safe_se_handler_count");
@@ -1642,7 +1637,7 @@ void Writer::createGuardCFTables() {
   std::vector<Symbol *> giatsSymbols;
   SymbolRVASet longJmpTargets;
   SymbolRVASet ehContTargets;
-  for (ObjFile *file : ObjFile::instances) {
+  for (ObjFile *file : ctx.objFileInstances) {
     // If the object was compiled with /guard:cf, the address taken symbols
     // are in .gfids$y sections, the longjmp targets are in .gljmp$y sections,
     // and ehcont targets are in .gehcont$y sections. If the object was not
@@ -1708,7 +1703,7 @@ void Writer::createGuardCFTables() {
     guardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable);
   if (config->guardCF & GuardCFLevel::EHCont)
     guardFlags |= uint32_t(coff_guard_flags::HasEHContTable);
-  Symbol *flagSym = symtab->findUnderscore("__guard_flags");
+  Symbol *flagSym = ctx.symtab.findUnderscore("__guard_flags");
   cast<DefinedAbsolute>(flagSym)->setVA(guardFlags);
 }
 
@@ -1780,8 +1775,8 @@ void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
     tableChunk = make<RVATableChunk>(std::move(tableSymbols));
   rdataSec->addChunk(tableChunk);
 
-  Symbol *t = symtab->findUnderscore(tableSym);
-  Symbol *c = symtab->findUnderscore(countSym);
+  Symbol *t = ctx.symtab.findUnderscore(tableSym);
+  Symbol *c = ctx.symtab.findUnderscore(countSym);
   replaceSymbol<DefinedSynthetic>(t, t->getName(), tableChunk);
   cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / (hasFlag ? 5 : 4));
 }
@@ -1793,7 +1788,7 @@ void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
 void Writer::createRuntimePseudoRelocs() {
   std::vector<RuntimePseudoReloc> rels;
 
-  for (Chunk *c : symtab->getChunks()) {
+  for (Chunk *c : ctx.symtab.getChunks()) {
     auto *sc = dyn_cast<SectionChunk>(c);
     if (!sc || !sc->live)
       continue;
@@ -1816,8 +1811,9 @@ void Writer::createRuntimePseudoRelocs() {
   EmptyChunk *endOfList = make<EmptyChunk>();
   rdataSec->addChunk(endOfList);
 
-  Symbol *headSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");
-  Symbol *endSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");
+  Symbol *headSym = ctx.symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");
+  Symbol *endSym =
+      ctx.symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");
   replaceSymbol<DefinedSynthetic>(headSym, headSym->getName(), table);
   replaceSymbol<DefinedSynthetic>(endSym, endSym->getName(), endOfList);
 }
@@ -1837,8 +1833,8 @@ void Writer::insertCtorDtorSymbols() {
   dtorsSec->insertChunkAtStart(dtorListHead);
   dtorsSec->addChunk(dtorListEnd);
 
-  Symbol *ctorListSym = symtab->findUnderscore("__CTOR_LIST__");
-  Symbol *dtorListSym = symtab->findUnderscore("__DTOR_LIST__");
+  Symbol *ctorListSym = ctx.symtab.findUnderscore("__CTOR_LIST__");
+  Symbol *dtorListSym = ctx.symtab.findUnderscore("__DTOR_LIST__");
   replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(),
                                   ctorListHead);
   replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(),
@@ -1851,7 +1847,7 @@ void Writer::setSectionPermissions() {
   for (auto &p : config->section) {
     StringRef name = p.first;
     uint32_t perm = p.second;
-    for (OutputSection *sec : outputSections)
+    for (OutputSection *sec : ctx.outputSections)
       if (sec->name == name)
         sec->setPermissions(perm);
   }
@@ -1861,10 +1857,10 @@ void Writer::setSectionPermissions() {
 void Writer::writeSections() {
   // Record the number of sections to apply section index relocations
   // against absolute symbols. See applySecIdx in Chunks.cpp..
-  DefinedAbsolute::numOutputSections = outputSections.size();
+  DefinedAbsolute::numOutputSections = ctx.outputSections.size();
 
   uint8_t *buf = buffer->getBufferStart();
-  for (OutputSection *sec : outputSections) {
+  for (OutputSection *sec : ctx.outputSections) {
     uint8_t *secBuf = buf + sec->getFileOff();
     // Fill gaps between functions in .text with INT3 instructions
     // instead of leaving as NUL bytes (which can be interpreted as
@@ -1934,7 +1930,7 @@ void Writer::sortExceptionTable() {
     return;
   // We assume .pdata contains function table entries only.
   auto bufAddr = [&](Chunk *c) {
-    OutputSection *os = c->getOutputSection();
+    OutputSection *os = ctx.getOutputSection(c);
     return buffer->getBufferStart() + os->getFileOff() + c->getRVA() -
            os->getRVA();
   };
@@ -2002,7 +1998,7 @@ void Writer::sortCRTSectionChunks(std::vector<Chunk *> &chunks) {
 }
 
 OutputSection *Writer::findSection(StringRef name) {
-  for (OutputSection *sec : outputSections)
+  for (OutputSection *sec : ctx.outputSections)
     if (sec->name == name)
       return sec;
   return nullptr;
@@ -2010,7 +2006,7 @@ OutputSection *Writer::findSection(StringRef name) {
 
 uint32_t Writer::getSizeOfInitializedData() {
   uint32_t res = 0;
-  for (OutputSection *s : outputSections)
+  for (OutputSection *s : ctx.outputSections)
     if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
       res += s->getRawSize();
   return res;
@@ -2022,7 +2018,7 @@ void Writer::addBaserels() {
     return;
   relocSec->chunks.clear();
   std::vector<Baserel> v;
-  for (OutputSection *sec : outputSections) {
+  for (OutputSection *sec : ctx.outputSections) {
     if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
       continue;
     // Collect all locations for base relocations.
@@ -2071,11 +2067,11 @@ PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) {
 
 void Writer::fixTlsAlignment() {
   Defined *tlsSym =
-      dyn_cast_or_null<Defined>(symtab->findUnderscore("_tls_used"));
+      dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore("_tls_used"));
   if (!tlsSym)
     return;
 
-  OutputSection *sec = tlsSym->getChunk()->getOutputSection();
+  OutputSection *sec = ctx.getOutputSection(tlsSym->getChunk());
   assert(sec && tlsSym->getRVA() >= sec->getRVA() &&
          "no output section for _tls_used");
 

diff  --git a/lld/COFF/Writer.h b/lld/COFF/Writer.h
index 2bb26da7d428a..d2b3b4b81d3cf 100644
--- a/lld/COFF/Writer.h
+++ b/lld/COFF/Writer.h
@@ -19,8 +19,9 @@
 namespace lld {
 namespace coff {
 static const int pageSize = 4096;
+class COFFLinkerContext;
 
-void writeResult();
+void writeResult(COFFLinkerContext &ctx);
 
 class PartialSection {
 public:
@@ -50,9 +51,6 @@ class OutputSection {
   void writeHeaderTo(uint8_t *buf);
   void addContributingPartialSection(PartialSection *sec);
 
-  // Clear the output sections static container.
-  static void clear();
-
   // Returns the size of this section in an executable memory image.
   // This may be smaller than the raw size (the raw size is multiple
   // of disk sector size, so there may be padding at end), or may be

diff  --git a/lld/Common/Timer.cpp b/lld/Common/Timer.cpp
index 16c518e4bf841..a61f000e8c070 100644
--- a/lld/Common/Timer.cpp
+++ b/lld/Common/Timer.cpp
@@ -31,13 +31,8 @@ Timer::Timer(llvm::StringRef name, Timer &parent) : name(std::string(name)) {
   parent.children.push_back(this);
 }
 
-Timer &Timer::root() {
-  static Timer rootTimer("Total Link Time");
-  return rootTimer;
-}
-
 void Timer::print() {
-  double totalDuration = static_cast<double>(root().millis());
+  double totalDuration = static_cast<double>(millis());
 
   // We want to print the grand total under all the intermediate phases, so we
   // print all children first, then print the total under that.
@@ -47,7 +42,7 @@ void Timer::print() {
 
   message(std::string(50, '-'));
 
-  root().print(0, root().millis(), false);
+  print(0, millis(), false);
 }
 
 double Timer::millis() const {

diff  --git a/lld/include/lld/Common/Timer.h b/lld/include/lld/Common/Timer.h
index b37388cd38c43..7aca966f663c0 100644
--- a/lld/include/lld/Common/Timer.h
+++ b/lld/include/lld/Common/Timer.h
@@ -38,7 +38,8 @@ class Timer {
 public:
   Timer(llvm::StringRef name, Timer &parent);
 
-  static Timer &root();
+  // Creates the root timer.
+  explicit Timer(llvm::StringRef name);
 
   void addToTotal(std::chrono::nanoseconds time) { total += time.count(); }
   void print();
@@ -46,7 +47,6 @@ class Timer {
   double millis() const;
 
 private:
-  explicit Timer(llvm::StringRef name);
   void print(int depth, double totalDuration, bool recurse = true) const;
 
   std::atomic<std::chrono::nanoseconds::rep> total;

diff  --git a/llvm/utils/gn/secondary/lld/COFF/BUILD.gn b/llvm/utils/gn/secondary/lld/COFF/BUILD.gn
index 0f19a77741b03..78c79844bb2a7 100644
--- a/llvm/utils/gn/secondary/lld/COFF/BUILD.gn
+++ b/llvm/utils/gn/secondary/lld/COFF/BUILD.gn
@@ -29,6 +29,7 @@ static_library("COFF") {
   sources = [
     "CallGraphSort.cpp",
     "Chunks.cpp",
+    "COFFLinkerContext.cpp",
     "DLL.cpp",
     "DebugTypes.cpp",
     "Driver.cpp",


        


More information about the llvm-commits mailing list