<div dir="ltr">Whoops, I'll fix that. </div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Sep 17, 2021 at 5:40 PM Geoffrey Martin-Noble <<a href="mailto:gcmn@google.com">gcmn@google.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr">I'm seeing diagnostic failures that appear to be coming from this commit<div><br></div><div><table style="border-collapse:collapse;border-spacing:0px;background-color:rgb(23,23,23);width:1108px;table-layout:fixed;color:rgb(255,255,255);font-family:SFMono-Regular,Monaco,Menlo,Consolas,"Liberation Mono",Courier,monospace;font-size:12px"><tbody style="box-sizing:border-box"><tr style="box-sizing:border-box"><td colspan="2" style="box-sizing:border-box;padding:0px 18px 0px 0px;word-break:break-word;white-space:pre-wrap"><span style="box-sizing:border-box">llvm-project/lld/Common/Timer.cpp:29:38: </span><span style="box-sizing:border-box;color:rgb(255,112,112)">error: </span><span style="box-sizing:border-box">field 'name' will be initialized after field 'total' [-Werror,-Wreorder-ctor]</span></td></tr><tr style="box-sizing:border-box"><td style="box-sizing:border-box;padding:0px 10px 0px 18px;color:rgb(84,84,84);text-align:right;vertical-align:top;width:49px"></td><td colspan="2" style="box-sizing:border-box;padding:0px 18px 0px 0px;word-break:break-word;white-space:pre-wrap">Timer::Timer(llvm::StringRef name) : name(std::string(name)), total(0) {}</td></tr></tbody></table></div></div><div><br></div><div>Could you take a look?</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Sep 17, 2021 at 5:19 PM Amy Huang via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
Author: Amy Huang<br>
Date: 2021-09-17T17:18:42-07:00<br>
New Revision: 6f7483b1ece4747f2aafe4baa05fc07e7dc9ed9d<br>
<br>
URL: <a href="https://github.com/llvm/llvm-project/commit/6f7483b1ece4747f2aafe4baa05fc07e7dc9ed9d" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/6f7483b1ece4747f2aafe4baa05fc07e7dc9ed9d</a><br>
DIFF: <a href="https://github.com/llvm/llvm-project/commit/6f7483b1ece4747f2aafe4baa05fc07e7dc9ed9d.diff" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/6f7483b1ece4747f2aafe4baa05fc07e7dc9ed9d.diff</a><br>
<br>
LOG: Reland "[LLD] Remove global state in lld/COFF" after fixing asan and msan test failures<br>
<br>
Original commit description:<br>
<br>
  [LLD] Remove global state in lld/COFF<br>
<br>
  This patch removes globals from the lldCOFF library, by moving globals<br>
  into a context class (COFFLinkingContext) and passing it around wherever<br>
  it's needed.<br>
<br>
  See <a href="https://lists.llvm.org/pipermail/llvm-dev/2021-June/151184.html" rel="noreferrer" target="_blank">https://lists.llvm.org/pipermail/llvm-dev/2021-June/151184.html</a> for<br>
  context about removing globals from LLD.<br>
<br>
  I also haven't moved the `driver` or `config` variables yet.<br>
<br>
  Differential Revision: <a href="https://reviews.llvm.org/D109634" rel="noreferrer" target="_blank">https://reviews.llvm.org/D109634</a><br>
<br>
This reverts commit a2fd05ada9030eab2258fff25e77a05adccae128.<br>
<br>
Original commits were b4fa71eed34d967195514fe9b0a5211fca2bc5bc<br>
and e03c7e367adb8f228332e3c2ef8f45484597b719.<br>
<br>
Added: <br>
    lld/COFF/COFFLinkerContext.cpp<br>
    lld/COFF/COFFLinkerContext.h<br>
    lld/test/COFF/timers.ll<br>
<br>
Modified: <br>
    lld/COFF/CMakeLists.txt<br>
    lld/COFF/CallGraphSort.cpp<br>
    lld/COFF/CallGraphSort.h<br>
    lld/COFF/Chunks.cpp<br>
    lld/COFF/Chunks.h<br>
    lld/COFF/DLL.cpp<br>
    lld/COFF/DLL.h<br>
    lld/COFF/DebugTypes.cpp<br>
    lld/COFF/DebugTypes.h<br>
    lld/COFF/Driver.cpp<br>
    lld/COFF/Driver.h<br>
    lld/COFF/ICF.cpp<br>
    lld/COFF/ICF.h<br>
    lld/COFF/InputFiles.cpp<br>
    lld/COFF/InputFiles.h<br>
    lld/COFF/LLDMapFile.cpp<br>
    lld/COFF/LLDMapFile.h<br>
    lld/COFF/LTO.cpp<br>
    lld/COFF/LTO.h<br>
    lld/COFF/MapFile.cpp<br>
    lld/COFF/MapFile.h<br>
    lld/COFF/MarkLive.cpp<br>
    lld/COFF/MarkLive.h<br>
    lld/COFF/MinGW.cpp<br>
    lld/COFF/MinGW.h<br>
    lld/COFF/PDB.cpp<br>
    lld/COFF/PDB.h<br>
    lld/COFF/SymbolTable.cpp<br>
    lld/COFF/SymbolTable.h<br>
    lld/COFF/TypeMerger.h<br>
    lld/COFF/Writer.cpp<br>
    lld/COFF/Writer.h<br>
    lld/Common/Timer.cpp<br>
    lld/include/lld/Common/Timer.h<br>
    llvm/utils/gn/secondary/lld/COFF/BUILD.gn<br>
<br>
Removed: <br>
<br>
<br>
<br>
################################################################################<br>
diff  --git a/lld/COFF/CMakeLists.txt b/lld/COFF/CMakeLists.txt<br>
index bbcd337b210f3..b32b9cfcff04e 100644<br>
--- a/lld/COFF/CMakeLists.txt<br>
+++ b/lld/COFF/CMakeLists.txt<br>
@@ -5,6 +5,7 @@ add_public_tablegen_target(COFFOptionsTableGen)<br>
 add_lld_library(lldCOFF<br>
   CallGraphSort.cpp<br>
   Chunks.cpp<br>
+  COFFLinkerContext.cpp<br>
   DebugTypes.cpp<br>
   DLL.cpp<br>
   Driver.cpp<br>
<br>
diff  --git a/lld/COFF/COFFLinkerContext.cpp b/lld/COFF/COFFLinkerContext.cpp<br>
new file mode 100644<br>
index 0000000000000..a280cacb932e2<br>
--- /dev/null<br>
+++ b/lld/COFF/COFFLinkerContext.cpp<br>
@@ -0,0 +1,40 @@<br>
+//===- COFFContext.cpp ----------------------------------------------------===//<br>
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>
+// See <a href="https://llvm.org/LICENSE.txt" rel="noreferrer" target="_blank">https://llvm.org/LICENSE.txt</a> for license information.<br>
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// Description<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "COFFLinkerContext.h"<br>
+#include "lld/Common/Memory.h"<br>
+#include "llvm/DebugInfo/CodeView/TypeHashing.h"<br>
+<br>
+namespace lld {<br>
+namespace coff {<br>
+<br>
+COFFLinkerContext::COFFLinkerContext()<br>
+    : symtab(*this), rootTimer("Total Linking Time"),<br>
+      inputFileTimer("Input File Reading", rootTimer),<br>
+      ltoTimer("LTO", rootTimer), gcTimer("GC", rootTimer),<br>
+      icfTimer("ICF", rootTimer), codeLayoutTimer("Code Layout", rootTimer),<br>
+      outputCommitTimer("Commit Output File", rootTimer),<br>
+      totalMapTimer("MAP Emission (Cumulative)", rootTimer),<br>
+      symbolGatherTimer("Gather Symbols", totalMapTimer),<br>
+      symbolStringsTimer("Build Symbol Strings", totalMapTimer),<br>
+      writeTimer("Write to File", totalMapTimer),<br>
+      totalPdbLinkTimer("PDB Emission (Cumulative)", rootTimer),<br>
+      addObjectsTimer("Add Objects", totalPdbLinkTimer),<br>
+      typeMergingTimer("Type Merging", addObjectsTimer),<br>
+      loadGHashTimer("Global Type Hashing", addObjectsTimer),<br>
+      mergeGHashTimer("GHash Type Merging", addObjectsTimer),<br>
+      symbolMergingTimer("Symbol Merging", addObjectsTimer),<br>
+      publicsLayoutTimer("Publics Stream Layout", totalPdbLinkTimer),<br>
+      tpiStreamLayoutTimer("TPI Stream Layout", totalPdbLinkTimer),<br>
+      diskCommitTimer("Commit to Disk", totalPdbLinkTimer) {}<br>
+<br>
+} // namespace coff<br>
+} // namespace lld<br>
<br>
diff  --git a/lld/COFF/COFFLinkerContext.h b/lld/COFF/COFFLinkerContext.h<br>
new file mode 100644<br>
index 0000000000000..e5223da86ef83<br>
--- /dev/null<br>
+++ b/lld/COFF/COFFLinkerContext.h<br>
@@ -0,0 +1,85 @@<br>
+//===- COFFLinkerContext.h --------------------------------------*- C++ -*-===//<br>
+//<br>
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>
+// See <a href="https://llvm.org/LICENSE.txt" rel="noreferrer" target="_blank">https://llvm.org/LICENSE.txt</a> for license information.<br>
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLD_COFF_COFFLinkerContext_H<br>
+#define LLD_COFF_COFFLinkerContext_H<br>
+<br>
+#include "Chunks.h"<br>
+#include "Config.h"<br>
+#include "DebugTypes.h"<br>
+#include "InputFiles.h"<br>
+#include "SymbolTable.h"<br>
+#include "Writer.h"<br>
+#include "lld/Common/Timer.h"<br>
+<br>
+namespace lld {<br>
+namespace coff {<br>
+<br>
+class COFFLinkerContext {<br>
+public:<br>
+  COFFLinkerContext();<br>
+  COFFLinkerContext(const COFFLinkerContext &) = delete;<br>
+  COFFLinkerContext &operator=(const COFFLinkerContext &) = delete;<br>
+  ~COFFLinkerContext() = default;<br>
+<br>
+  void addTpiSource(TpiSource *tpi) { tpiSourceList.push_back(tpi); }<br>
+<br>
+  SymbolTable symtab;<br>
+<br>
+  std::vector<ObjFile *> objFileInstances;<br>
+  std::map<std::string, PDBInputFile *> pdbInputFileInstances;<br>
+  std::vector<ImportFile *> importFileInstances;<br>
+  std::vector<BitcodeFile *> bitcodeFileInstances;<br>
+<br>
+  MergeChunk *mergeChunkInstances[Log2MaxSectionAlignment + 1] = {};<br>
+<br>
+  /// All sources of type information in the program.<br>
+  std::vector<TpiSource *> tpiSourceList;<br>
+<br>
+  std::map<llvm::codeview::GUID, TpiSource *> typeServerSourceMappings;<br>
+  std::map<uint32_t, TpiSource *> precompSourceMappings;<br>
+<br>
+  /// List of all output sections. After output sections are finalized, this<br>
+  /// can be indexed by getOutputSection.<br>
+  std::vector<OutputSection *> outputSections;<br>
+<br>
+  OutputSection *getOutputSection(const Chunk *c) const {<br>
+    return c->osidx == 0 ? nullptr : outputSections[c->osidx - 1];<br>
+  }<br>
+<br>
+  // All timers used in the COFF linker.<br>
+  Timer rootTimer;<br>
+  Timer inputFileTimer;<br>
+  Timer ltoTimer;<br>
+  Timer gcTimer;<br>
+  Timer icfTimer;<br>
+<br>
+  // Writer timers.<br>
+  Timer codeLayoutTimer;<br>
+  Timer outputCommitTimer;<br>
+  Timer totalMapTimer;<br>
+  Timer symbolGatherTimer;<br>
+  Timer symbolStringsTimer;<br>
+  Timer writeTimer;<br>
+<br>
+  // PDB timers.<br>
+  Timer totalPdbLinkTimer;<br>
+  Timer addObjectsTimer;<br>
+  Timer typeMergingTimer;<br>
+  Timer loadGHashTimer;<br>
+  Timer mergeGHashTimer;<br>
+  Timer symbolMergingTimer;<br>
+  Timer publicsLayoutTimer;<br>
+  Timer tpiStreamLayoutTimer;<br>
+  Timer diskCommitTimer;<br>
+};<br>
+<br>
+} // namespace coff<br>
+} // namespace lld<br>
+<br>
+#endif<br>
<br>
diff  --git a/lld/COFF/CallGraphSort.cpp b/lld/COFF/CallGraphSort.cpp<br>
index d3e5312ce7fdd..709e69b24914b 100644<br>
--- a/lld/COFF/CallGraphSort.cpp<br>
+++ b/lld/COFF/CallGraphSort.cpp<br>
@@ -12,6 +12,7 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "CallGraphSort.h"<br>
+#include "COFFLinkerContext.h"<br>
 #include "InputFiles.h"<br>
 #include "SymbolTable.h"<br>
 #include "Symbols.h"<br>
@@ -48,7 +49,7 @@ struct Cluster {<br>
<br>
 class CallGraphSort {<br>
 public:<br>
-  CallGraphSort();<br>
+  CallGraphSort(const COFFLinkerContext &ctx);<br>
<br>
   DenseMap<const SectionChunk *, int> run();<br>
<br>
@@ -70,7 +71,7 @@ using SectionPair = std::pair<const SectionChunk *, const SectionChunk *>;<br>
 // Take the edge list in Config->CallGraphProfile, resolve symbol names to<br>
 // Symbols, and generate a graph between InputSections with the provided<br>
 // weights.<br>
-CallGraphSort::CallGraphSort() {<br>
+CallGraphSort::CallGraphSort(const COFFLinkerContext &ctx) {<br>
   MapVector<SectionPair, uint64_t> &profile = config->callGraphProfile;<br>
   DenseMap<const SectionChunk *, int> secToCluster;<br>
<br>
@@ -95,7 +96,7 @@ CallGraphSort::CallGraphSort() {<br>
     // output.  This messes with the cluster size and density calculations.  We<br>
     // would also end up moving input sections in other output sections without<br>
     // moving them closer to what calls them.<br>
-    if (fromSec->getOutputSection() != toSec->getOutputSection())<br>
+    if (ctx.getOutputSection(fromSec) != ctx.getOutputSection(toSec))<br>
       continue;<br>
<br>
     int from = getOrCreateNode(fromSec);<br>
@@ -240,6 +241,7 @@ DenseMap<const SectionChunk *, int> CallGraphSort::run() {<br>
 // This first builds a call graph based on the profile data then merges sections<br>
 // according to the C³ heuristic. All clusters are then sorted by a density<br>
 // metric to further improve locality.<br>
-DenseMap<const SectionChunk *, int> coff::computeCallGraphProfileOrder() {<br>
-  return CallGraphSort().run();<br>
+DenseMap<const SectionChunk *, int><br>
+coff::computeCallGraphProfileOrder(const COFFLinkerContext &ctx) {<br>
+  return CallGraphSort(ctx).run();<br>
 }<br>
<br>
diff  --git a/lld/COFF/CallGraphSort.h b/lld/COFF/CallGraphSort.h<br>
index e4f372137448c..99f35d6b62762 100644<br>
--- a/lld/COFF/CallGraphSort.h<br>
+++ b/lld/COFF/CallGraphSort.h<br>
@@ -14,8 +14,10 @@<br>
 namespace lld {<br>
 namespace coff {<br>
 class SectionChunk;<br>
+class COFFLinkerContext;<br>
<br>
-llvm::DenseMap<const SectionChunk *, int> computeCallGraphProfileOrder();<br>
+llvm::DenseMap<const SectionChunk *, int><br>
+computeCallGraphProfileOrder(const COFFLinkerContext &ctx);<br>
 } // namespace coff<br>
 } // namespace lld<br>
<br>
<br>
diff  --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp<br>
index 36d5f371326fe..9f6dbd1725096 100644<br>
--- a/lld/COFF/Chunks.cpp<br>
+++ b/lld/COFF/Chunks.cpp<br>
@@ -7,10 +7,11 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "Chunks.h"<br>
+#include "COFFLinkerContext.h"<br>
 #include "InputFiles.h"<br>
+#include "SymbolTable.h"<br>
 #include "Symbols.h"<br>
 #include "Writer.h"<br>
-#include "SymbolTable.h"<br>
 #include "lld/Common/ErrorHandler.h"<br>
 #include "llvm/ADT/Twine.h"<br>
 #include "llvm/BinaryFormat/COFF.h"<br>
@@ -385,7 +386,7 @@ void SectionChunk::applyRelocation(uint8_t *off,<br>
   // section is needed to compute SECREL and SECTION relocations used in debug<br>
   // info.<br>
   Chunk *c = sym ? sym->getChunk() : nullptr;<br>
-  OutputSection *os = c ? c->getOutputSection() : nullptr;<br>
+  OutputSection *os = c ? file->ctx.getOutputSection(c) : nullptr;<br>
<br>
   // Skip the relocation if it refers to a discarded section, and diagnose it<br>
   // as an error if appropriate. If a symbol was discarded early, it may be<br>
@@ -938,18 +939,16 @@ uint8_t Baserel::getDefaultType() {<br>
   }<br>
 }<br>
<br>
-MergeChunk *MergeChunk::instances[Log2MaxSectionAlignment + 1] = {};<br>
-<br>
 MergeChunk::MergeChunk(uint32_t alignment)<br>
     : builder(StringTableBuilder::RAW, alignment) {<br>
   setAlignment(alignment);<br>
 }<br>
<br>
-void MergeChunk::addSection(SectionChunk *c) {<br>
+void MergeChunk::addSection(COFFLinkerContext &ctx, SectionChunk *c) {<br>
   assert(isPowerOf2_32(c->getAlignment()));<br>
   uint8_t p2Align = llvm::Log2_32(c->getAlignment());<br>
-  assert(p2Align < array_lengthof(instances));<br>
-  auto *&mc = instances[p2Align];<br>
+  assert(p2Align < array_lengthof(ctx.mergeChunkInstances));<br>
+  auto *&mc = ctx.mergeChunkInstances[p2Align];<br>
   if (!mc)<br>
     mc = make<MergeChunk>(c->getAlignment());<br>
   mc->sections.push_back(c);<br>
<br>
diff  --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h<br>
index bdd3faa179a8a..daaa043ffaceb 100644<br>
--- a/lld/COFF/Chunks.h<br>
+++ b/lld/COFF/Chunks.h<br>
@@ -101,7 +101,6 @@ class Chunk {<br>
   // chunk has a back pointer to an output section.<br>
   void setOutputSectionIdx(uint16_t o) { osidx = o; }<br>
   uint16_t getOutputSectionIdx() const { return osidx; }<br>
-  OutputSection *getOutputSection() const;<br>
<br>
   // Windows-specific.<br>
   // Collect all locations that contain absolute addresses for base relocations.<br>
@@ -415,7 +414,7 @@ inline StringRef Chunk::getDebugName() const {<br>
 class MergeChunk : public NonSectionChunk {<br>
 public:<br>
   MergeChunk(uint32_t alignment);<br>
-  static void addSection(SectionChunk *c);<br>
+  static void addSection(COFFLinkerContext &ctx, SectionChunk *c);<br>
   void finalizeContents();<br>
   void assignSubsectionRVAs();<br>
<br>
@@ -424,7 +423,6 @@ class MergeChunk : public NonSectionChunk {<br>
   size_t getSize() const override;<br>
   void writeTo(uint8_t *buf) const override;<br>
<br>
-  static MergeChunk *instances[Log2MaxSectionAlignment + 1];<br>
   std::vector<SectionChunk *> sections;<br>
<br>
 private:<br>
<br>
diff  --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp<br>
index b9e12ef4b34dd..6fec9df5617db 100644<br>
--- a/lld/COFF/DLL.cpp<br>
+++ b/lld/COFF/DLL.cpp<br>
@@ -18,6 +18,7 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "DLL.h"<br>
+#include "COFFLinkerContext.h"<br>
 #include "Chunks.h"<br>
 #include "SymbolTable.h"<br>
 #include "llvm/Object/COFF.h"<br>
@@ -631,7 +632,7 @@ uint64_t DelayLoadContents::getDirSize() {<br>
   return dirs.size() * sizeof(delay_import_directory_table_entry);<br>
 }<br>
<br>
-void DelayLoadContents::create(Defined *h) {<br>
+void DelayLoadContents::create(COFFLinkerContext &ctx, Defined *h) {<br>
   helper = h;<br>
   std::vector<std::vector<DefinedImportData *>> v = binImports(imports);<br>
<br>
@@ -660,13 +661,13 @@ void DelayLoadContents::create(Defined *h) {<br>
         // call targets for Control Flow Guard.<br>
         StringRef symName = saver.save("__imp_load_" + extName);<br>
         s->loadThunkSym =<br>
-            cast<DefinedSynthetic>(symtab->addSynthetic(symName, t));<br>
+            cast<DefinedSynthetic>(ctx.symtab.addSynthetic(symName, t));<br>
       }<br>
     }<br>
     thunks.push_back(tm);<br>
     StringRef tmName =<br>
         saver.save("__tailMerge_" + syms[0]->getDLLName().lower());<br>
-    symtab->addSynthetic(tmName, tm);<br>
+    ctx.symtab.addSynthetic(tmName, tm);<br>
     // Terminate with null values.<br>
     addresses.push_back(make<NullChunk>(8));<br>
     names.push_back(make<NullChunk>(8));<br>
<br>
diff  --git a/lld/COFF/DLL.h b/lld/COFF/DLL.h<br>
index ce0ee01c4a3df..0d594e675bd23 100644<br>
--- a/lld/COFF/DLL.h<br>
+++ b/lld/COFF/DLL.h<br>
@@ -40,7 +40,7 @@ class DelayLoadContents {<br>
 public:<br>
   void add(DefinedImportData *sym) { imports.push_back(sym); }<br>
   bool empty() { return imports.empty(); }<br>
-  void create(Defined *helper);<br>
+  void create(COFFLinkerContext &ctx, Defined *helper);<br>
   std::vector<Chunk *> getChunks();<br>
   std::vector<Chunk *> getDataChunks();<br>
   ArrayRef<Chunk *> getCodeChunks() { return thunks; }<br>
<br>
diff  --git a/lld/COFF/DebugTypes.cpp b/lld/COFF/DebugTypes.cpp<br>
index 97be5bc79ac34..115b66c34332d 100644<br>
--- a/lld/COFF/DebugTypes.cpp<br>
+++ b/lld/COFF/DebugTypes.cpp<br>
@@ -7,6 +7,7 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "DebugTypes.h"<br>
+#include "COFFLinkerContext.h"<br>
 #include "Chunks.h"<br>
 #include "Driver.h"<br>
 #include "InputFiles.h"<br>
@@ -14,7 +15,6 @@<br>
 #include "TypeMerger.h"<br>
 #include "lld/Common/ErrorHandler.h"<br>
 #include "lld/Common/Memory.h"<br>
-#include "lld/Common/Timer.h"<br>
 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"<br>
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"<br>
 #include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"<br>
@@ -46,8 +46,8 @@ class TypeServerIpiSource;<br>
 // before any dependent OBJ.<br>
 class TypeServerSource : public TpiSource {<br>
 public:<br>
-  explicit TypeServerSource(PDBInputFile *f)<br>
-      : TpiSource(PDB, nullptr), pdbInputFile(f) {<br>
+  explicit TypeServerSource(COFFLinkerContext &ctx, PDBInputFile *f)<br>
+      : TpiSource(ctx, PDB, nullptr), pdbInputFile(f) {<br>
     if (f->loadErr && *f->loadErr)<br>
       return;<br>
     pdb::PDBFile &file = f->session->getPDBFile();<br>
@@ -55,7 +55,7 @@ class TypeServerSource : public TpiSource {<br>
     if (!expectedInfo)<br>
       return;<br>
     Guid = expectedInfo->getGuid();<br>
-    auto it = mappings.emplace(Guid, this);<br>
+    auto it = ctx.typeServerSourceMappings.emplace(Guid, this);<br>
     assert(it.second);<br>
     (void)it;<br>
   }<br>
@@ -74,8 +74,6 @@ class TypeServerSource : public TpiSource {<br>
<br>
   // The PDB signature GUID.<br>
   codeview::GUID Guid;<br>
-<br>
-  static std::map<codeview::GUID, TypeServerSource *> mappings;<br>
 };<br>
<br>
 // Companion to TypeServerSource. Stores the index map for the IPI stream in the<br>
@@ -83,7 +81,8 @@ class TypeServerSource : public TpiSource {<br>
 // invariant of one type index space per source.<br>
 class TypeServerIpiSource : public TpiSource {<br>
 public:<br>
-  explicit TypeServerIpiSource() : TpiSource(PDBIpi, nullptr) {}<br>
+  explicit TypeServerIpiSource(COFFLinkerContext &ctx)<br>
+      : TpiSource(ctx, PDBIpi, nullptr) {}<br>
<br>
   friend class TypeServerSource;<br>
<br>
@@ -101,8 +100,8 @@ class UseTypeServerSource : public TpiSource {<br>
   Expected<TypeServerSource *> getTypeServerSource();<br>
<br>
 public:<br>
-  UseTypeServerSource(ObjFile *f, TypeServer2Record ts)<br>
-      : TpiSource(UsingPDB, f), typeServerDependency(ts) {}<br>
+  UseTypeServerSource(COFFLinkerContext &ctx, ObjFile *f, TypeServer2Record ts)<br>
+      : TpiSource(ctx, UsingPDB, f), typeServerDependency(ts) {}<br>
<br>
   Error mergeDebugT(TypeMerger *m) override;<br>
<br>
@@ -121,11 +120,11 @@ class UseTypeServerSource : public TpiSource {<br>
 // such files, clang does not.<br>
 class PrecompSource : public TpiSource {<br>
 public:<br>
-  PrecompSource(ObjFile *f) : TpiSource(PCH, f) {<br>
+  PrecompSource(COFFLinkerContext &ctx, ObjFile *f) : TpiSource(ctx, PCH, f) {<br>
     if (!f->pchSignature || !*f->pchSignature)<br>
       fatal(toString(f) +<br>
             " claims to be a PCH object, but does not have a valid signature");<br>
-    auto it = mappings.emplace(*f->pchSignature, this);<br>
+    auto it = ctx.precompSourceMappings.emplace(*f->pchSignature, this);<br>
     if (!it.second)<br>
       fatal("a PCH object with the same signature has already been provided (" +<br>
             toString(it.first->second->file) + " and " + toString(file) + ")");<br>
@@ -134,16 +133,14 @@ class PrecompSource : public TpiSource {<br>
   void loadGHashes() override;<br>
<br>
   bool isDependency() const override { return true; }<br>
-<br>
-  static std::map<uint32_t, PrecompSource *> mappings;<br>
 };<br>
<br>
 // This class represents the debug type stream of an OBJ file that depends on a<br>
 // Microsoft precompiled headers OBJ (see PrecompSource).<br>
 class UsePrecompSource : public TpiSource {<br>
 public:<br>
-  UsePrecompSource(ObjFile *f, PrecompRecord precomp)<br>
-      : TpiSource(UsingPCH, f), precompDependency(precomp) {}<br>
+  UsePrecompSource(COFFLinkerContext &ctx, ObjFile *f, PrecompRecord precomp)<br>
+      : TpiSource(ctx, UsingPCH, f), precompDependency(precomp) {}<br>
<br>
   Error mergeDebugT(TypeMerger *m) override;<br>
<br>
@@ -153,6 +150,10 @@ class UsePrecompSource : public TpiSource {<br>
 private:<br>
   Error mergeInPrecompHeaderObj();<br>
<br>
+  PrecompSource *findObjByName(StringRef fileNameOnly);<br>
+  PrecompSource *findPrecompSource(ObjFile *file, PrecompRecord &pr);<br>
+  Expected<PrecompSource *> findPrecompMap(ObjFile *file, PrecompRecord &pr);<br>
+<br>
 public:<br>
   // Information about the Precomp OBJ dependency, that needs to be loaded in<br>
   // before merging this OBJ.<br>
@@ -160,13 +161,9 @@ class UsePrecompSource : public TpiSource {<br>
 };<br>
 } // namespace<br>
<br>
-std::vector<TpiSource *> TpiSource::instances;<br>
-ArrayRef<TpiSource *> TpiSource::dependencySources;<br>
-ArrayRef<TpiSource *> TpiSource::objectSources;<br>
-<br>
-TpiSource::TpiSource(TpiKind k, ObjFile *f)<br>
-    : kind(k), tpiSrcIdx(instances.size()), file(f) {<br>
-  instances.push_back(this);<br>
+TpiSource::TpiSource(COFFLinkerContext &ctx, TpiKind k, ObjFile *f)<br>
+    : ctx(ctx), kind(k), tpiSrcIdx(ctx.tpiSourceList.size()), file(f) {<br>
+  ctx.addTpiSource(this);<br>
 }<br>
<br>
 // Vtable key method.<br>
@@ -175,52 +172,35 @@ TpiSource::~TpiSource() {<br>
   consumeError(std::move(typeMergingError));<br>
 }<br>
<br>
-void TpiSource::sortDependencies() {<br>
-  // Order dependencies first, but preserve the existing order.<br>
-  std::vector<TpiSource *> deps;<br>
-  std::vector<TpiSource *> objs;<br>
-  for (TpiSource *s : instances)<br>
-    (s->isDependency() ? deps : objs).push_back(s);<br>
-  uint32_t numDeps = deps.size();<br>
-  uint32_t numObjs = objs.size();<br>
-  instances = std::move(deps);<br>
-  instances.insert(instances.end(), objs.begin(), objs.end());<br>
-  for (uint32_t i = 0, e = instances.size(); i < e; ++i)<br>
-    instances[i]->tpiSrcIdx = i;<br>
-  dependencySources = makeArrayRef(instances.data(), numDeps);<br>
-  objectSources = makeArrayRef(instances.data() + numDeps, numObjs);<br>
-}<br>
-<br>
-TpiSource *lld::coff::makeTpiSource(ObjFile *file) {<br>
-  return make<TpiSource>(TpiSource::Regular, file);<br>
+TpiSource *lld::coff::makeTpiSource(COFFLinkerContext &ctx, ObjFile *file) {<br>
+  return make<TpiSource>(ctx, TpiSource::Regular, file);<br>
 }<br>
<br>
-TpiSource *lld::coff::makeTypeServerSource(PDBInputFile *pdbInputFile) {<br>
+TpiSource *lld::coff::makeTypeServerSource(COFFLinkerContext &ctx,<br>
+                                           PDBInputFile *pdbInputFile) {<br>
   // Type server sources come in pairs: the TPI stream, and the IPI stream.<br>
-  auto *tpiSource = make<TypeServerSource>(pdbInputFile);<br>
+  auto *tpiSource = make<TypeServerSource>(ctx, pdbInputFile);<br>
   if (pdbInputFile->session->getPDBFile().hasPDBIpiStream())<br>
-    tpiSource->ipiSrc = make<TypeServerIpiSource>();<br>
+    tpiSource->ipiSrc = make<TypeServerIpiSource>(ctx);<br>
   return tpiSource;<br>
 }<br>
<br>
-TpiSource *lld::coff::makeUseTypeServerSource(ObjFile *file,<br>
+TpiSource *lld::coff::makeUseTypeServerSource(COFFLinkerContext &ctx,<br>
+                                              ObjFile *file,<br>
                                               TypeServer2Record ts) {<br>
-  return make<UseTypeServerSource>(file, ts);<br>
+  return make<UseTypeServerSource>(ctx, file, ts);<br>
 }<br>
<br>
-TpiSource *lld::coff::makePrecompSource(ObjFile *file) {<br>
-  return make<PrecompSource>(file);<br>
+TpiSource *lld::coff::makePrecompSource(COFFLinkerContext &ctx, ObjFile *file) {<br>
+  return make<PrecompSource>(ctx, file);<br>
 }<br>
<br>
-TpiSource *lld::coff::makeUsePrecompSource(ObjFile *file,<br>
+TpiSource *lld::coff::makeUsePrecompSource(COFFLinkerContext &ctx,<br>
+                                           ObjFile *file,<br>
                                            PrecompRecord precomp) {<br>
-  return make<UsePrecompSource>(file, precomp);<br>
+  return make<UsePrecompSource>(ctx, file, precomp);<br>
 }<br>
<br>
-std::map<codeview::GUID, TypeServerSource *> TypeServerSource::mappings;<br>
-<br>
-std::map<uint32_t, PrecompSource *> PrecompSource::mappings;<br>
-<br>
 bool TpiSource::remapTypeIndex(TypeIndex &ti, TiRefKind refKind) const {<br>
   if (ti.isSimple())<br>
     return true;<br>
@@ -419,12 +399,12 @@ Expected<TypeServerSource *> UseTypeServerSource::getTypeServerSource() {<br>
   StringRef tsPath = typeServerDependency.getName();<br>
<br>
   TypeServerSource *tsSrc;<br>
-  auto it = TypeServerSource::mappings.find(tsId);<br>
-  if (it != TypeServerSource::mappings.end()) {<br>
-    tsSrc = it->second;<br>
+  auto it = ctx.typeServerSourceMappings.find(tsId);<br>
+  if (it != ctx.typeServerSourceMappings.end()) {<br>
+    tsSrc = (TypeServerSource *)it->second;<br>
   } else {<br>
     // The file failed to load, lookup by name<br>
-    PDBInputFile *pdb = PDBInputFile::findFromRecordPath(tsPath, file);<br>
+    PDBInputFile *pdb = PDBInputFile::findFromRecordPath(ctx, tsPath, file);<br>
     if (!pdb)<br>
       return createFileError(tsPath, errorCodeToError(std::error_code(<br>
                                          ENOENT, std::generic_category())));<br>
@@ -471,36 +451,37 @@ static bool equalsPath(StringRef path1, StringRef path2) {<br>
 }<br>
<br>
 // Find by name an OBJ provided on the command line<br>
-static PrecompSource *findObjByName(StringRef fileNameOnly) {<br>
+PrecompSource *UsePrecompSource::findObjByName(StringRef fileNameOnly) {<br>
   SmallString<128> currentPath;<br>
-  for (auto kv : PrecompSource::mappings) {<br>
+  for (auto kv : ctx.precompSourceMappings) {<br>
     StringRef currentFileName = sys::path::filename(kv.second->file->getName(),<br>
                                                     sys::path::Style::windows);<br>
<br>
     // Compare based solely on the file name (link.exe behavior)<br>
     if (equalsPath(currentFileName, fileNameOnly))<br>
-      return kv.second;<br>
+      return (PrecompSource *)kv.second;<br>
   }<br>
   return nullptr;<br>
 }<br>
<br>
-static PrecompSource *findPrecompSource(ObjFile *file, PrecompRecord &pr) {<br>
+PrecompSource *UsePrecompSource::findPrecompSource(ObjFile *file,<br>
+                                                   PrecompRecord &pr) {<br>
   // Cross-compile warning: given that Clang doesn't generate LF_PRECOMP<br>
   // records, we assume the OBJ comes from a Windows build of cl.exe. Thusly,<br>
   // the paths embedded in the OBJs are in the Windows format.<br>
   SmallString<128> prFileName =<br>
       sys::path::filename(pr.getPrecompFilePath(), sys::path::Style::windows);<br>
<br>
-  auto it = PrecompSource::mappings.find(pr.getSignature());<br>
-  if (it != PrecompSource::mappings.end()) {<br>
-    return it->second;<br>
+  auto it = ctx.precompSourceMappings.find(pr.getSignature());<br>
+  if (it != ctx.precompSourceMappings.end()) {<br>
+    return (PrecompSource *)it->second;<br>
   }<br>
   // Lookup by name<br>
   return findObjByName(prFileName);<br>
 }<br>
<br>
-static Expected<PrecompSource *> findPrecompMap(ObjFile *file,<br>
-                                                PrecompRecord &pr) {<br>
+Expected<PrecompSource *> UsePrecompSource::findPrecompMap(ObjFile *file,<br>
+                                                           PrecompRecord &pr) {<br>
   PrecompSource *precomp = findPrecompSource(file, pr);<br>
<br>
   if (!precomp)<br>
@@ -555,22 +536,6 @@ Error UsePrecompSource::mergeDebugT(TypeMerger *m) {<br>
   return TpiSource::mergeDebugT(m);<br>
 }<br>
<br>
-uint32_t TpiSource::countTypeServerPDBs() {<br>
-  return TypeServerSource::mappings.size();<br>
-}<br>
-<br>
-uint32_t TpiSource::countPrecompObjs() {<br>
-  return PrecompSource::mappings.size();<br>
-}<br>
-<br>
-void TpiSource::clear() {<br>
-  // Clean up any owned ghash allocations.<br>
-  clearGHashes();<br>
-  TpiSource::instances.clear();<br>
-  TypeServerSource::mappings.clear();<br>
-  PrecompSource::mappings.clear();<br>
-}<br>
-<br>
 //===----------------------------------------------------------------------===//<br>
 // Parellel GHash type merging implementation.<br>
 //===----------------------------------------------------------------------===//<br>
@@ -926,7 +891,8 @@ struct GHashTable {<br>
   /// Insert the cell with the given ghash into the table. Return the insertion<br>
   /// position in the table. It is safe for the caller to store the insertion<br>
   /// position because the table cannot be resized.<br>
-  uint32_t insert(GloballyHashedType ghash, GHashCell newCell);<br>
+  uint32_t insert(COFFLinkerContext &ctx, GloballyHashedType ghash,<br>
+                  GHashCell newCell);<br>
 };<br>
<br>
 /// A ghash table cell for deduplicating types from TpiSources.<br>
@@ -965,8 +931,8 @@ class GHashCell {<br>
   bool isItem() const { return data & (1ULL << 63U); }<br>
<br>
   /// Get the ghash key for this cell.<br>
-  GloballyHashedType getGHash() const {<br>
-    return TpiSource::instances[getTpiSrcIdx()]->ghashes[getGHashIdx()];<br>
+  GloballyHashedType getGHash(const COFFLinkerContext &ctx) const {<br>
+    return ctx.tpiSourceList[getTpiSrcIdx()]->ghashes[getGHashIdx()];<br>
   }<br>
<br>
   /// The priority function for the cell. The data is stored such that lower<br>
@@ -996,7 +962,8 @@ void GHashTable::init(uint32_t newTableSize) {<br>
   tableSize = newTableSize;<br>
 }<br>
<br>
-uint32_t GHashTable::insert(GloballyHashedType ghash, GHashCell newCell) {<br>
+uint32_t GHashTable::insert(COFFLinkerContext &ctx, GloballyHashedType ghash,<br>
+                            GHashCell newCell) {<br>
   assert(!newCell.isEmpty() && "cannot insert empty cell value");<br>
<br>
   // FIXME: The low bytes of SHA1 have low entropy for short records, which<br>
@@ -1015,7 +982,7 @@ uint32_t GHashTable::insert(GloballyHashedType ghash, GHashCell newCell) {<br>
     // - cell has non-matching key: hash collision, probe next cell<br>
     auto *cellPtr = reinterpret_cast<std::atomic<GHashCell> *>(&table[idx]);<br>
     GHashCell oldCell(cellPtr->load());<br>
-    while (oldCell.isEmpty() || oldCell.getGHash() == ghash) {<br>
+    while (oldCell.isEmpty() || oldCell.getGHash(ctx) == ghash) {<br>
       // Check if there is an existing ghash entry with a higher priority<br>
       // (earlier ordering). If so, this is a duplicate, we are done.<br>
       if (!oldCell.isEmpty() && oldCell < newCell)<br>
@@ -1040,22 +1007,22 @@ uint32_t GHashTable::insert(GloballyHashedType ghash, GHashCell newCell) {<br>
   llvm_unreachable("left infloop");<br>
 }<br>
<br>
-TypeMerger::TypeMerger(llvm::BumpPtrAllocator &alloc)<br>
-    : typeTable(alloc), idTable(alloc) {}<br>
+TypeMerger::TypeMerger(COFFLinkerContext &c, llvm::BumpPtrAllocator &alloc)<br>
+    : typeTable(alloc), idTable(alloc), ctx(c) {}<br>
<br>
 TypeMerger::~TypeMerger() = default;<br>
<br>
 void TypeMerger::mergeTypesWithGHash() {<br>
   // Load ghashes. Do type servers and PCH objects first.<br>
   {<br>
-    ScopedTimer t1(loadGHashTimer);<br>
-    parallelForEach(TpiSource::dependencySources,<br>
+    ScopedTimer t1(ctx.loadGHashTimer);<br>
+    parallelForEach(dependencySources,<br>
                     [&](TpiSource *source) { source->loadGHashes(); });<br>
-    parallelForEach(TpiSource::objectSources,<br>
+    parallelForEach(objectSources,<br>
                     [&](TpiSource *source) { source->loadGHashes(); });<br>
   }<br>
<br>
-  ScopedTimer t2(mergeGHashTimer);<br>
+  ScopedTimer t2(ctx.mergeGHashTimer);<br>
   GHashState ghashState;<br>
<br>
   // Estimate the size of hash table needed to deduplicate ghashes. This *must*<br>
@@ -1066,7 +1033,7 @@ void TypeMerger::mergeTypesWithGHash() {<br>
   // small compared to total memory usage, at eight bytes per input type record,<br>
   // and most input type records are larger than eight bytes.<br>
   size_t tableSize = 0;<br>
-  for (TpiSource *source : TpiSource::instances)<br>
+  for (TpiSource *source : ctx.tpiSourceList)<br>
     tableSize += source->ghashes.size();<br>
<br>
   // Cap the table size so that we can use 32-bit cell indices. Type indices are<br>
@@ -1080,8 +1047,8 @@ void TypeMerger::mergeTypesWithGHash() {<br>
   // position. Because the table does not rehash, the position will not change<br>
   // under insertion. After insertion is done, the value of the cell can be read<br>
   // to retrieve the final PDB type index.<br>
-  parallelForEachN(0, TpiSource::instances.size(), [&](size_t tpiSrcIdx) {<br>
-    TpiSource *source = TpiSource::instances[tpiSrcIdx];<br>
+  parallelForEachN(0, ctx.tpiSourceList.size(), [&](size_t tpiSrcIdx) {<br>
+    TpiSource *source = ctx.tpiSourceList[tpiSrcIdx];<br>
     source->indexMapStorage.resize(source->ghashes.size());<br>
     for (uint32_t i = 0, e = source->ghashes.size(); i < e; i++) {<br>
       if (source->shouldOmitFromPdb(i)) {<br>
@@ -1091,7 +1058,7 @@ void TypeMerger::mergeTypesWithGHash() {<br>
       GloballyHashedType ghash = source->ghashes[i];<br>
       bool isItem = source->isItemIndex.test(i);<br>
       uint32_t cellIdx =<br>
-          ghashState.table.insert(ghash, GHashCell(isItem, tpiSrcIdx, i));<br>
+          ghashState.table.insert(ctx, ghash, GHashCell(isItem, tpiSrcIdx, i));<br>
<br>
       // Store the ghash cell index as a type index in indexMapStorage. Later<br>
       // we will replace it with the PDB type index.<br>
@@ -1137,7 +1104,7 @@ void TypeMerger::mergeTypesWithGHash() {<br>
   for (uint32_t i = 0, e = entries.size(); i < e; ++i) {<br>
     auto &cell = entries[i];<br>
     uint32_t tpiSrcIdx = cell.getTpiSrcIdx();<br>
-    TpiSource *source = TpiSource::instances[tpiSrcIdx];<br>
+    TpiSource *source = ctx.tpiSourceList[tpiSrcIdx];<br>
     source->uniqueTypes.push_back(cell.getGHashIdx());<br>
<br>
     // Update the ghash table to store the destination PDB type index in the<br>
@@ -1150,21 +1117,37 @@ void TypeMerger::mergeTypesWithGHash() {<br>
   }<br>
<br>
   // In parallel, remap all types.<br>
-  for_each(TpiSource::dependencySources, [&](TpiSource *source) {<br>
+  for_each(dependencySources, [&](TpiSource *source) {<br>
     source->remapTpiWithGHashes(&ghashState);<br>
   });<br>
-  parallelForEach(TpiSource::objectSources, [&](TpiSource *source) {<br>
+  parallelForEach(objectSources, [&](TpiSource *source) {<br>
     source->remapTpiWithGHashes(&ghashState);<br>
   });<br>
<br>
   // Build a global map of from function ID to function type.<br>
-  for (TpiSource *source : TpiSource::instances) {<br>
+  for (TpiSource *source : ctx.tpiSourceList) {<br>
     for (auto idToType : source->funcIdToType)<br>
       funcIdToType.insert(idToType);<br>
     source->funcIdToType.clear();<br>
   }<br>
<br>
-  TpiSource::clearGHashes();<br>
+  clearGHashes();<br>
+}<br>
+<br>
+void TypeMerger::sortDependencies() {<br>
+  // Order dependencies first, but preserve the existing order.<br>
+  std::vector<TpiSource *> deps;<br>
+  std::vector<TpiSource *> objs;<br>
+  for (TpiSource *s : ctx.tpiSourceList)<br>
+    (s->isDependency() ? deps : objs).push_back(s);<br>
+  uint32_t numDeps = deps.size();<br>
+  uint32_t numObjs = objs.size();<br>
+  ctx.tpiSourceList = std::move(deps);<br>
+  ctx.tpiSourceList.insert(ctx.tpiSourceList.end(), objs.begin(), objs.end());<br>
+  for (uint32_t i = 0, e = ctx.tpiSourceList.size(); i < e; ++i)<br>
+    ctx.tpiSourceList[i]->tpiSrcIdx = i;<br>
+  dependencySources = makeArrayRef(ctx.tpiSourceList.data(), numDeps);<br>
+  objectSources = makeArrayRef(ctx.tpiSourceList.data() + numDeps, numObjs);<br>
 }<br>
<br>
 /// Given the index into the ghash table for a particular type, return the type<br>
@@ -1175,6 +1158,17 @@ static TypeIndex loadPdbTypeIndexFromCell(GHashState *g,<br>
   return TypeIndex::fromArrayIndex(cell.getGHashIdx());<br>
 }<br>
<br>
+/// Free heap allocated ghashes.<br>
+void TypeMerger::clearGHashes() {<br>
+  for (TpiSource *src : ctx.tpiSourceList) {<br>
+    if (src->ownedGHashes)<br>
+      delete[] src->ghashes.data();<br>
+    src->ghashes = {};<br>
+    src->isItemIndex.clear();<br>
+    src->uniqueTypes.clear();<br>
+  }<br>
+}<br>
+<br>
 // Fill in a TPI or IPI index map using ghashes. For each source type, use its<br>
 // ghash to lookup its final type index in the PDB, and store that in the map.<br>
 void TpiSource::fillMapFromGHashes(GHashState *g) {<br>
@@ -1187,13 +1181,3 @@ void TpiSource::fillMapFromGHashes(GHashState *g) {<br>
           loadPdbTypeIndexFromCell(g, fakeCellIndex.toArrayIndex());<br>
   }<br>
 }<br>
-<br>
-void TpiSource::clearGHashes() {<br>
-  for (TpiSource *src : TpiSource::instances) {<br>
-    if (src->ownedGHashes)<br>
-      delete[] src->ghashes.data();<br>
-    src->ghashes = {};<br>
-    src->isItemIndex.clear();<br>
-    src->uniqueTypes.clear();<br>
-  }<br>
-}<br>
<br>
diff  --git a/lld/COFF/DebugTypes.h b/lld/COFF/DebugTypes.h<br>
index faad30b141e92..b02b5b884cf7e 100644<br>
--- a/lld/COFF/DebugTypes.h<br>
+++ b/lld/COFF/DebugTypes.h<br>
@@ -37,12 +37,13 @@ class ObjFile;<br>
 class PDBInputFile;<br>
 class TypeMerger;<br>
 struct GHashState;<br>
+class COFFLinkerContext;<br>
<br>
 class TpiSource {<br>
 public:<br>
   enum TpiKind : uint8_t { Regular, PCH, UsingPCH, PDB, PDBIpi, UsingPDB };<br>
<br>
-  TpiSource(TpiKind k, ObjFile *f);<br>
+  TpiSource(COFFLinkerContext &ctx, TpiKind k, ObjFile *f);<br>
   virtual ~TpiSource();<br>
<br>
   /// Produce a mapping from the type and item indices used in the object<br>
@@ -93,6 +94,8 @@ class TpiSource {<br>
   // Walk over file->debugTypes and fill in the isItemIndex bit vector.<br>
   void fillIsItemIndexFromDebugT();<br>
<br>
+  COFFLinkerContext &ctx;<br>
+<br>
 public:<br>
   bool remapTypesInSymbolRecord(MutableArrayRef<uint8_t> rec);<br>
<br>
@@ -109,29 +112,6 @@ class TpiSource {<br>
     return ghashIdx == endPrecompGHashIdx;<br>
   }<br>
<br>
-  /// All sources of type information in the program.<br>
-  static std::vector<TpiSource *> instances;<br>
-<br>
-  /// Dependency type sources, such as type servers or PCH object files. These<br>
-  /// must be processed before objects that rely on them. Set by<br>
-  /// TpiSources::sortDependencies.<br>
-  static ArrayRef<TpiSource *> dependencySources;<br>
-<br>
-  /// Object file sources. These must be processed after dependencySources.<br>
-  static ArrayRef<TpiSource *> objectSources;<br>
-<br>
-  /// Sorts the dependencies and reassigns TpiSource indices.<br>
-  static void sortDependencies();<br>
-<br>
-  static uint32_t countTypeServerPDBs();<br>
-  static uint32_t countPrecompObjs();<br>
-<br>
-  /// Free heap allocated ghashes.<br>
-  static void clearGHashes();<br>
-<br>
-  /// Clear global data structures for TpiSources.<br>
-  static void clear();<br>
-<br>
   const TpiKind kind;<br>
   bool ownedGHashes = true;<br>
   uint32_t tpiSrcIdx = 0;<br>
@@ -186,12 +166,13 @@ class TpiSource {<br>
   uint64_t nbTypeRecordsBytes = 0;<br>
 };<br>
<br>
-TpiSource *makeTpiSource(ObjFile *file);<br>
-TpiSource *makeTypeServerSource(PDBInputFile *pdbInputFile);<br>
-TpiSource *makeUseTypeServerSource(ObjFile *file,<br>
+TpiSource *makeTpiSource(COFFLinkerContext &ctx, ObjFile *f);<br>
+TpiSource *makeTypeServerSource(COFFLinkerContext &ctx,<br>
+                                PDBInputFile *pdbInputFile);<br>
+TpiSource *makeUseTypeServerSource(COFFLinkerContext &ctx, ObjFile *file,<br>
                                    llvm::codeview::TypeServer2Record ts);<br>
-TpiSource *makePrecompSource(ObjFile *file);<br>
-TpiSource *makeUsePrecompSource(ObjFile *file,<br>
+TpiSource *makePrecompSource(COFFLinkerContext &ctx, ObjFile *file);<br>
+TpiSource *makeUsePrecompSource(COFFLinkerContext &ctx, ObjFile *file,<br>
                                 llvm::codeview::PrecompRecord ts);<br>
<br>
 } // namespace coff<br>
<br>
diff  --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp<br>
index fd9ae7f47bf87..9ebd1c336c594 100644<br>
--- a/lld/COFF/Driver.cpp<br>
+++ b/lld/COFF/Driver.cpp<br>
@@ -7,6 +7,7 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "Driver.h"<br>
+#include "COFFLinkerContext.h"<br>
 #include "Config.h"<br>
 #include "DebugTypes.h"<br>
 #include "ICF.h"<br>
@@ -59,8 +60,6 @@ using namespace llvm::sys;<br>
 namespace lld {<br>
 namespace coff {<br>
<br>
-static Timer inputFileTimer("Input File Reading", Timer::root());<br>
-<br>
 Configuration *config;<br>
 LinkerDriver *driver;<br>
<br>
@@ -70,14 +69,7 @@ bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,<br>
   lld::stderrOS = &stderrOS;<br>
<br>
   errorHandler().cleanupCallback = []() {<br>
-    TpiSource::clear();<br>
     freeArena();<br>
-    ObjFile::instances.clear();<br>
-    PDBInputFile::instances.clear();<br>
-    ImportFile::instances.clear();<br>
-    BitcodeFile::instances.clear();<br>
-    memset(MergeChunk::instances, 0, sizeof(MergeChunk::instances));<br>
-    OutputSection::clear();<br>
   };<br>
<br>
   errorHandler().logName = args::getFilenameWithoutExe(args[0]);<br>
@@ -87,9 +79,9 @@ bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,<br>
   errorHandler().exitEarly = canExitEarly;<br>
   stderrOS.enable_colors(stderrOS.has_colors());<br>
<br>
+  COFFLinkerContext ctx;<br>
   config = make<Configuration>();<br>
-  symtab = make<SymbolTable>();<br>
-  driver = make<LinkerDriver>();<br>
+  driver = make<LinkerDriver>(ctx);<br>
<br>
   driver->linkerMain(args);<br>
<br>
@@ -174,8 +166,8 @@ static StringRef mangle(StringRef sym) {<br>
   return sym;<br>
 }<br>
<br>
-static bool findUnderscoreMangle(StringRef sym) {<br>
-  Symbol *s = symtab->findMangle(mangle(sym));<br>
+bool LinkerDriver::findUnderscoreMangle(StringRef sym) {<br>
+  Symbol *s = ctx.symtab.findMangle(mangle(sym));<br>
   return s && !isa<Undefined>(s);<br>
 }<br>
<br>
@@ -213,30 +205,30 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,<br>
         addArchiveBuffer(m, "<whole-archive>", filename, memberIndex++);<br>
       return;<br>
     }<br>
-    symtab->addFile(make<ArchiveFile>(mbref));<br>
+    ctx.symtab.addFile(make<ArchiveFile>(ctx, mbref));<br>
     break;<br>
   case file_magic::bitcode:<br>
     if (lazy)<br>
-      symtab->addFile(make<LazyObjFile>(mbref));<br>
+      ctx.symtab.addFile(make<LazyObjFile>(ctx, mbref));<br>
     else<br>
-      symtab->addFile(make<BitcodeFile>(mbref, "", 0));<br>
+      ctx.symtab.addFile(make<BitcodeFile>(ctx, mbref, "", 0));<br>
     break;<br>
   case file_magic::coff_object:<br>
   case file_magic::coff_import_library:<br>
     if (lazy)<br>
-      symtab->addFile(make<LazyObjFile>(mbref));<br>
+      ctx.symtab.addFile(make<LazyObjFile>(ctx, mbref));<br>
     else<br>
-      symtab->addFile(make<ObjFile>(mbref));<br>
+      ctx.symtab.addFile(make<ObjFile>(ctx, mbref));<br>
     break;<br>
   case file_magic::pdb:<br>
-    symtab->addFile(make<PDBInputFile>(mbref));<br>
+    ctx.symtab.addFile(make<PDBInputFile>(ctx, mbref));<br>
     break;<br>
   case file_magic::coff_cl_gl_object:<br>
     error(filename + ": is not a native COFF file. Recompile without /GL");<br>
     break;<br>
   case file_magic::pecoff_executable:<br>
     if (config->mingw) {<br>
-      symtab->addFile(make<DLLFile>(mbref));<br>
+      ctx.symtab.addFile(make<DLLFile>(ctx, mbref));<br>
       break;<br>
     }<br>
     if (filename.endswith_insensitive(".dll")) {<br>
@@ -280,24 +272,24 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName,<br>
                                     uint64_t offsetInArchive) {<br>
   file_magic magic = identify_magic(mb.getBuffer());<br>
   if (magic == file_magic::coff_import_library) {<br>
-    InputFile *imp = make<ImportFile>(mb);<br>
+    InputFile *imp = make<ImportFile>(ctx, mb);<br>
     imp->parentName = parentName;<br>
-    symtab->addFile(imp);<br>
+    ctx.symtab.addFile(imp);<br>
     return;<br>
   }<br>
<br>
   InputFile *obj;<br>
   if (magic == file_magic::coff_object) {<br>
-    obj = make<ObjFile>(mb);<br>
+    obj = make<ObjFile>(ctx, mb);<br>
   } else if (magic == file_magic::bitcode) {<br>
-    obj = make<BitcodeFile>(mb, parentName, offsetInArchive);<br>
+    obj = make<BitcodeFile>(ctx, mb, parentName, offsetInArchive);<br>
   } else {<br>
     error("unknown file type: " + mb.getBufferIdentifier());<br>
     return;<br>
   }<br>
<br>
   obj->parentName = parentName;<br>
-  symtab->addFile(obj);<br>
+  ctx.symtab.addFile(obj);<br>
   log("Loaded " + toString(obj) + " for " + symName);<br>
 }<br>
<br>
@@ -547,7 +539,7 @@ void LinkerDriver::addLibSearchPaths() {<br>
 }<br>
<br>
 Symbol *LinkerDriver::addUndefined(StringRef name) {<br>
-  Symbol *b = symtab->addUndefined(name);<br>
+  Symbol *b = ctx.symtab.addUndefined(name);<br>
   if (!b->isGCRoot) {<br>
     b->isGCRoot = true;<br>
     config->gcroot.push_back(b);<br>
@@ -562,14 +554,14 @@ StringRef LinkerDriver::mangleMaybe(Symbol *s) {<br>
     return "";<br>
<br>
   // Otherwise, see if a similar, mangled symbol exists in the symbol table.<br>
-  Symbol *mangled = symtab->findMangle(unmangled->getName());<br>
+  Symbol *mangled = ctx.symtab.findMangle(unmangled->getName());<br>
   if (!mangled)<br>
     return "";<br>
<br>
   // If we find a similar mangled symbol, make this an alias to it and return<br>
   // its name.<br>
   log(unmangled->getName() + " aliased to " + mangled->getName());<br>
-  unmangled->weakAlias = symtab->addUndefined(mangled->getName());<br>
+  unmangled->weakAlias = ctx.symtab.addUndefined(mangled->getName());<br>
   return mangled->getName();<br>
 }<br>
<br>
@@ -939,7 +931,7 @@ void LinkerDriver::enqueueTask(std::function<void()> task) {<br>
 }<br>
<br>
 bool LinkerDriver::run() {<br>
-  ScopedTimer t(inputFileTimer);<br>
+  ScopedTimer t(ctx.inputFileTimer);<br>
<br>
   bool didWork = !taskQueue.empty();<br>
   while (!taskQueue.empty()) {<br>
@@ -952,7 +944,7 @@ bool LinkerDriver::run() {<br>
 // Parse an /order file. If an option is given, the linker places<br>
 // COMDAT sections in the same order as their names appear in the<br>
 // given file.<br>
-static void parseOrderFile(StringRef arg) {<br>
+static void parseOrderFile(COFFLinkerContext &ctx, StringRef arg) {<br>
   // For some reason, the MSVC linker requires a filename to be<br>
   // preceded by "@".<br>
   if (!arg.startswith("@")) {<br>
@@ -962,7 +954,7 @@ static void parseOrderFile(StringRef arg) {<br>
<br>
   // Get a list of all comdat sections for error checking.<br>
   DenseSet<StringRef> set;<br>
-  for (Chunk *c : symtab->getChunks())<br>
+  for (Chunk *c : ctx.symtab.getChunks())<br>
     if (auto *sec = dyn_cast<SectionChunk>(c))<br>
       if (sec->sym)<br>
         set.insert(sec->sym->getName());<br>
@@ -996,7 +988,7 @@ static void parseOrderFile(StringRef arg) {<br>
   driver->takeBuffer(std::move(mb));<br>
 }<br>
<br>
-static void parseCallGraphFile(StringRef path) {<br>
+static void parseCallGraphFile(COFFLinkerContext &ctx, StringRef path) {<br>
   std::unique_ptr<MemoryBuffer> mb =<br>
       CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,<br>
                                   /*RequiresNullTerminator=*/false,<br>
@@ -1005,7 +997,7 @@ static void parseCallGraphFile(StringRef path) {<br>
<br>
   // Build a map from symbol name to section.<br>
   DenseMap<StringRef, Symbol *> map;<br>
-  for (ObjFile *file : ObjFile::instances)<br>
+  for (ObjFile *file : ctx.objFileInstances)<br>
     for (Symbol *sym : file->getSymbols())<br>
       if (sym)<br>
         map[sym->getName()] = sym;<br>
@@ -1042,8 +1034,8 @@ static void parseCallGraphFile(StringRef path) {<br>
   driver->takeBuffer(std::move(mb));<br>
 }<br>
<br>
-static void readCallGraphsFromObjectFiles() {<br>
-  for (ObjFile *obj : ObjFile::instances) {<br>
+static void readCallGraphsFromObjectFiles(COFFLinkerContext &ctx) {<br>
+  for (ObjFile *obj : ctx.objFileInstances) {<br>
     if (obj->callgraphSec) {<br>
       ArrayRef<uint8_t> contents;<br>
       cantFail(<br>
@@ -1077,7 +1069,7 @@ static void markAddrsig(Symbol *s) {<br>
       c->keepUnique = true;<br>
 }<br>
<br>
-static void findKeepUniqueSections() {<br>
+static void findKeepUniqueSections(COFFLinkerContext &ctx) {<br>
   // Exported symbols could be address-significant in other executables or DSOs,<br>
   // so we conservatively mark them as address-significant.<br>
   for (Export &r : config->exports)<br>
@@ -1085,7 +1077,7 @@ static void findKeepUniqueSections() {<br>
<br>
   // Visit the address-significance table in each object file and mark each<br>
   // referenced symbol as address-significant.<br>
-  for (ObjFile *obj : ObjFile::instances) {<br>
+  for (ObjFile *obj : ctx.objFileInstances) {<br>
     ArrayRef<Symbol *> syms = obj->getSymbols();<br>
     if (obj->addrsigSec) {<br>
       ArrayRef<uint8_t> contents;<br>
@@ -1169,7 +1161,7 @@ static void parsePDBAltPath(StringRef altPath) {<br>
 void LinkerDriver::convertResources() {<br>
   std::vector<ObjFile *> resourceObjFiles;<br>
<br>
-  for (ObjFile *f : ObjFile::instances) {<br>
+  for (ObjFile *f : ctx.objFileInstances) {<br>
     if (f->isResourceObjFile())<br>
       resourceObjFiles.push_back(f);<br>
   }<br>
@@ -1191,8 +1183,9 @@ void LinkerDriver::convertResources() {<br>
       f->includeResourceChunks();<br>
     return;<br>
   }<br>
-  ObjFile *f = make<ObjFile>(convertResToCOFF(resources, resourceObjFiles));<br>
-  symtab->addFile(f);<br>
+  ObjFile *f =<br>
+      make<ObjFile>(ctx, convertResToCOFF(resources, resourceObjFiles));<br>
+  ctx.symtab.addFile(f);<br>
   f->includeResourceChunks();<br>
 }<br>
<br>
@@ -1219,9 +1212,9 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {<br>
     if (Optional<StringRef> path = doFindFile(arg->getValue()))<br>
       exporter.addWholeArchive(*path);<br>
<br>
-  symtab->forEachSymbol([&](Symbol *s) {<br>
+  ctx.symtab.forEachSymbol([&](Symbol *s) {<br>
     auto *def = dyn_cast<Defined>(s);<br>
-    if (!exporter.shouldExport(def))<br>
+    if (!exporter.shouldExport(ctx, def))<br>
       return;<br>
<br>
     if (!def->isGCRoot) {<br>
@@ -1266,7 +1259,7 @@ Optional<std::string> getReproduceFile(const opt::InputArgList &args) {<br>
 }<br>
<br>
 void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
-  ScopedTimer rootTimer(Timer::root());<br>
+  ScopedTimer rootTimer(ctx.rootTimer);<br>
<br>
   // Needed for LTO.<br>
   InitializeAllTargetInfos();<br>
@@ -2018,32 +2011,32 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
   if (config->imageBase == uint64_t(-1))<br>
     config->imageBase = getDefaultImageBase();<br>
<br>
-  symtab->addSynthetic(mangle("__ImageBase"), nullptr);<br>
+  ctx.symtab.addSynthetic(mangle("__ImageBase"), nullptr);<br>
   if (config->machine == I386) {<br>
-    symtab->addAbsolute("___safe_se_handler_table", 0);<br>
-    symtab->addAbsolute("___safe_se_handler_count", 0);<br>
+    ctx.symtab.addAbsolute("___safe_se_handler_table", 0);<br>
+    ctx.symtab.addAbsolute("___safe_se_handler_count", 0);<br>
   }<br>
<br>
-  symtab->addAbsolute(mangle("__guard_fids_count"), 0);<br>
-  symtab->addAbsolute(mangle("__guard_fids_table"), 0);<br>
-  symtab->addAbsolute(mangle("__guard_flags"), 0);<br>
-  symtab->addAbsolute(mangle("__guard_iat_count"), 0);<br>
-  symtab->addAbsolute(mangle("__guard_iat_table"), 0);<br>
-  symtab->addAbsolute(mangle("__guard_longjmp_count"), 0);<br>
-  symtab->addAbsolute(mangle("__guard_longjmp_table"), 0);<br>
+  ctx.symtab.addAbsolute(mangle("__guard_fids_count"), 0);<br>
+  ctx.symtab.addAbsolute(mangle("__guard_fids_table"), 0);<br>
+  ctx.symtab.addAbsolute(mangle("__guard_flags"), 0);<br>
+  ctx.symtab.addAbsolute(mangle("__guard_iat_count"), 0);<br>
+  ctx.symtab.addAbsolute(mangle("__guard_iat_table"), 0);<br>
+  ctx.symtab.addAbsolute(mangle("__guard_longjmp_count"), 0);<br>
+  ctx.symtab.addAbsolute(mangle("__guard_longjmp_table"), 0);<br>
   // Needed for MSVC 2017 15.5 CRT.<br>
-  symtab->addAbsolute(mangle("__enclave_config"), 0);<br>
+  ctx.symtab.addAbsolute(mangle("__enclave_config"), 0);<br>
   // Needed for MSVC 2019 16.8 CRT.<br>
-  symtab->addAbsolute(mangle("__guard_eh_cont_count"), 0);<br>
-  symtab->addAbsolute(mangle("__guard_eh_cont_table"), 0);<br>
+  ctx.symtab.addAbsolute(mangle("__guard_eh_cont_count"), 0);<br>
+  ctx.symtab.addAbsolute(mangle("__guard_eh_cont_table"), 0);<br>
<br>
   if (config->pseudoRelocs) {<br>
-    symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);<br>
-    symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);<br>
+    ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);<br>
+    ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);<br>
   }<br>
   if (config->mingw) {<br>
-    symtab->addAbsolute(mangle("__CTOR_LIST__"), 0);<br>
-    symtab->addAbsolute(mangle("__DTOR_LIST__"), 0);<br>
+    ctx.symtab.addAbsolute(mangle("__CTOR_LIST__"), 0);<br>
+    ctx.symtab.addAbsolute(mangle("__DTOR_LIST__"), 0);<br>
   }<br>
<br>
   // This code may add new undefined symbols to the link, which may enqueue more<br>
@@ -2069,12 +2062,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
     for (auto pair : config->alternateNames) {<br>
       StringRef from = pair.first;<br>
       StringRef to = pair.second;<br>
-      Symbol *sym = symtab->find(from);<br>
+      Symbol *sym = ctx.symtab.find(from);<br>
       if (!sym)<br>
         continue;<br>
       if (auto *u = dyn_cast<Undefined>(sym))<br>
         if (!u->weakAlias)<br>
-          u->weakAlias = symtab->addUndefined(to);<br>
+          u->weakAlias = ctx.symtab.addUndefined(to);<br>
     }<br>
<br>
     // If any inputs are bitcode files, the LTO code generator may create<br>
@@ -2082,25 +2075,25 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
     // file's symbol table. If any of those library functions are defined in a<br>
     // bitcode file in an archive member, we need to arrange to use LTO to<br>
     // compile those archive members by adding them to the link beforehand.<br>
-    if (!BitcodeFile::instances.empty())<br>
+    if (!ctx.bitcodeFileInstances.empty())<br>
       for (auto *s : lto::LTO::getRuntimeLibcallSymbols())<br>
-        symtab->addLibcall(s);<br>
+        ctx.symtab.addLibcall(s);<br>
<br>
     // Windows specific -- if __load_config_used can be resolved, resolve it.<br>
-    if (symtab->findUnderscore("_load_config_used"))<br>
+    if (ctx.symtab.findUnderscore("_load_config_used"))<br>
       addUndefined(mangle("_load_config_used"));<br>
   } while (run());<br>
<br>
   if (args.hasArg(OPT_include_optional)) {<br>
     // Handle /includeoptional<br>
     for (auto *arg : args.filtered(OPT_include_optional))<br>
-      if (dyn_cast_or_null<LazyArchive>(symtab->find(arg->getValue())))<br>
+      if (dyn_cast_or_null<LazyArchive>(ctx.symtab.find(arg->getValue())))<br>
         addUndefined(arg->getValue());<br>
     while (run());<br>
   }<br>
<br>
   // Create wrapped symbols for -wrap option.<br>
-  std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args);<br>
+  std::vector<WrappedSymbol> wrapped = addWrappedSymbols(ctx, args);<br>
   // Load more object files that might be needed for wrapped symbols.<br>
   if (!wrapped.empty())<br>
     while (run());<br>
@@ -2126,7 +2119,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
     // If it ends up pulling in more object files from static libraries,<br>
     // (and maybe doing more stdcall fixups along the way), this would need<br>
     // to loop these two calls.<br>
-    symtab->loadMinGWSymbols();<br>
+    ctx.symtab.loadMinGWSymbols();<br>
     run();<br>
   }<br>
<br>
@@ -2134,8 +2127,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
   // If we are going to do codegen for link-time optimization, check for<br>
   // unresolvable symbols first, so we don't spend time generating code that<br>
   // will fail to link anyway.<br>
-  if (!BitcodeFile::instances.empty() && !config->forceUnresolved)<br>
-    symtab->reportUnresolvable();<br>
+  if (!ctx.bitcodeFileInstances.empty() && !config->forceUnresolved)<br>
+    ctx.symtab.reportUnresolvable();<br>
   if (errorCount())<br>
     return;<br>
<br>
@@ -2149,7 +2142,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
   // Do LTO by compiling bitcode input files to a set of native COFF files then<br>
   // link those files (unless -thinlto-index-only was given, in which case we<br>
   // resolve symbols and write indices, but don't generate native code or link).<br>
-  symtab->addCombinedLTOObjects();<br>
+  ctx.symtab.addCombinedLTOObjects();<br>
<br>
   // If -thinlto-index-only is given, we should create only "index<br>
   // files" and not object files. Index file creation is already done<br>
@@ -2163,10 +2156,10 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
<br>
   // Apply symbol renames for -wrap.<br>
   if (!wrapped.empty())<br>
-    wrapSymbols(wrapped);<br>
+    wrapSymbols(ctx, wrapped);<br>
<br>
   // Resolve remaining undefined symbols and warn about imported locals.<br>
-  symtab->resolveRemainingUndefines();<br>
+  ctx.symtab.resolveRemainingUndefines();<br>
   if (errorCount())<br>
     return;<br>
<br>
@@ -2177,12 +2170,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
     // order provided on the command line, while lld will pull in needed<br>
     // files from static libraries only after the last object file on the<br>
     // command line.<br>
-    for (auto i = ObjFile::instances.begin(), e = ObjFile::instances.end();<br>
+    for (auto i = ctx.objFileInstances.begin(), e = ctx.objFileInstances.end();<br>
          i != e; i++) {<br>
       ObjFile *file = *i;<br>
       if (isCrtend(file->getName())) {<br>
-        ObjFile::instances.erase(i);<br>
-        ObjFile::instances.push_back(file);<br>
+        ctx.objFileInstances.erase(i);<br>
+        ctx.objFileInstances.push_back(file);<br>
         break;<br>
       }<br>
     }<br>
@@ -2207,7 +2200,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
     StringRef name = pair.first;<br>
     uint32_t alignment = pair.second;<br>
<br>
-    Symbol *sym = symtab->find(name);<br>
+    Symbol *sym = ctx.symtab.find(name);<br>
     if (!sym) {<br>
       warn("/aligncomm symbol " + name + " not found");<br>
       continue;<br>
@@ -2239,16 +2232,16 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
   if (auto *arg = args.getLastArg(OPT_order)) {<br>
     if (args.hasArg(OPT_call_graph_ordering_file))<br>
       error("/order and /call-graph-order-file may not be used together");<br>
-    parseOrderFile(arg->getValue());<br>
+    parseOrderFile(ctx, arg->getValue());<br>
     config->callGraphProfileSort = false;<br>
   }<br>
<br>
   // Handle /call-graph-ordering-file and /call-graph-profile-sort (default on).<br>
   if (config->callGraphProfileSort) {<br>
     if (auto *arg = args.getLastArg(OPT_call_graph_ordering_file)) {<br>
-      parseCallGraphFile(arg->getValue());<br>
+      parseCallGraphFile(ctx, arg->getValue());<br>
     }<br>
-    readCallGraphsFromObjectFiles();<br>
+    readCallGraphsFromObjectFiles(ctx);<br>
   }<br>
<br>
   // Handle /print-symbol-order.<br>
@@ -2265,7 +2258,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
       // functions. This doesn't bring in more object files, but only marks<br>
       // functions that already have been included to be retained.<br>
       for (const char *n : {"__gxx_personality_v0", "__gcc_personality_v0"}) {<br>
-        Defined *d = dyn_cast_or_null<Defined>(symtab->findUnderscore(n));<br>
+        Defined *d = dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore(n));<br>
         if (d && !d->isGCRoot) {<br>
           d->isGCRoot = true;<br>
           config->gcroot.push_back(d);<br>
@@ -2273,7 +2266,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
       }<br>
     }<br>
<br>
-    markLive(symtab->getChunks());<br>
+    markLive(ctx);<br>
   }<br>
<br>
   // Needs to happen after the last call to addFile().<br>
@@ -2281,17 +2274,17 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {<br>
<br>
   // Identify identical COMDAT sections to merge them.<br>
   if (config->doICF != ICFLevel::None) {<br>
-    findKeepUniqueSections();<br>
-    doICF(symtab->getChunks(), config->doICF);<br>
+    findKeepUniqueSections(ctx);<br>
+    doICF(ctx, config->doICF);<br>
   }<br>
<br>
   // Write the result.<br>
-  writeResult();<br>
+  writeResult(ctx);<br>
<br>
   // Stop early so we can print the results.<br>
   rootTimer.stop();<br>
   if (config->showTiming)<br>
-    Timer::root().print();<br>
+    ctx.rootTimer.print();<br>
 }<br>
<br>
 } // namespace coff<br>
<br>
diff  --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h<br>
index 5729bed69528b..7c2fbe3c7d64c 100644<br>
--- a/lld/COFF/Driver.h<br>
+++ b/lld/COFF/Driver.h<br>
@@ -9,6 +9,7 @@<br>
 #ifndef LLD_COFF_DRIVER_H<br>
 #define LLD_COFF_DRIVER_H<br>
<br>
+#include "COFFLinkerContext.h"<br>
 #include "Config.h"<br>
 #include "SymbolTable.h"<br>
 #include "lld/Common/LLVM.h"<br>
@@ -78,6 +79,8 @@ class ArgParser {<br>
<br>
 class LinkerDriver {<br>
 public:<br>
+  LinkerDriver(COFFLinkerContext &c) : ctx(c) {}<br>
+<br>
   void linkerMain(llvm::ArrayRef<const char *> args);<br>
<br>
   // Used by the resolver to parse .drectve section contents.<br>
@@ -103,6 +106,8 @@ class LinkerDriver {<br>
   StringRef doFindLib(StringRef filename);<br>
   StringRef doFindLibMinGW(StringRef filename);<br>
<br>
+  bool findUnderscoreMangle(StringRef sym);<br>
+<br>
   // Parses LIB environment which contains a list of search paths.<br>
   void addLibSearchPaths();<br>
<br>
@@ -148,6 +153,8 @@ class LinkerDriver {<br>
   std::vector<MemoryBufferRef> resources;<br>
<br>
   llvm::StringSet<> directivesExports;<br>
+<br>
+  COFFLinkerContext &ctx;<br>
 };<br>
<br>
 // Functions below this line are defined in DriverUtils.cpp.<br>
<br>
diff  --git a/lld/COFF/ICF.cpp b/lld/COFF/ICF.cpp<br>
index 7326469672968..8323626623948 100644<br>
--- a/lld/COFF/ICF.cpp<br>
+++ b/lld/COFF/ICF.cpp<br>
@@ -18,6 +18,7 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "ICF.h"<br>
+#include "COFFLinkerContext.h"<br>
 #include "Chunks.h"<br>
 #include "Symbols.h"<br>
 #include "lld/Common/ErrorHandler.h"<br>
@@ -36,12 +37,10 @@ using namespace llvm;<br>
 namespace lld {<br>
 namespace coff {<br>
<br>
-static Timer icfTimer("ICF", Timer::root());<br>
-<br>
 class ICF {<br>
 public:<br>
-  ICF(ICFLevel icfLevel) : icfLevel(icfLevel){};<br>
-  void run(ArrayRef<Chunk *> v);<br>
+  ICF(COFFLinkerContext &c, ICFLevel icfLevel) : icfLevel(icfLevel), ctx(c){};<br>
+  void run();<br>
<br>
 private:<br>
   void segregate(size_t begin, size_t end, bool constant);<br>
@@ -64,6 +63,8 @@ class ICF {<br>
   int cnt = 0;<br>
   std::atomic<bool> repeat = {false};<br>
   ICFLevel icfLevel = ICFLevel::All;<br>
+<br>
+  COFFLinkerContext &ctx;<br>
 };<br>
<br>
 // Returns true if section S is subject of ICF.<br>
@@ -246,12 +247,12 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> fn) {<br>
 // Merge identical COMDAT sections.<br>
 // Two sections are considered the same if their section headers,<br>
 // contents and relocations are all the same.<br>
-void ICF::run(ArrayRef<Chunk *> vec) {<br>
-  ScopedTimer t(icfTimer);<br>
+void ICF::run() {<br>
+  ScopedTimer t(ctx.icfTimer);<br>
<br>
   // Collect only mergeable sections and group by hash value.<br>
   uint32_t nextId = 1;<br>
-  for (Chunk *c : vec) {<br>
+  for (Chunk *c : ctx.symtab.getChunks()) {<br>
     if (auto *sc = dyn_cast<SectionChunk>(c)) {<br>
       if (isEligible(sc))<br>
         chunks.push_back(sc);<br>
@@ -262,7 +263,7 @@ void ICF::run(ArrayRef<Chunk *> vec) {<br>
<br>
   // Make sure that ICF doesn't merge sections that are being handled by string<br>
   // tail merging.<br>
-  for (MergeChunk *mc : MergeChunk::instances)<br>
+  for (MergeChunk *mc : ctx.mergeChunkInstances)<br>
     if (mc)<br>
       for (SectionChunk *sc : mc->sections)<br>
         sc->eqClass[0] = nextId++;<br>
@@ -317,8 +318,8 @@ void ICF::run(ArrayRef<Chunk *> vec) {<br>
 }<br>
<br>
 // Entry point to ICF.<br>
-void doICF(ArrayRef<Chunk *> chunks, ICFLevel icfLevel) {<br>
-  ICF(icfLevel).run(chunks);<br>
+void doICF(COFFLinkerContext &ctx, ICFLevel icfLevel) {<br>
+  ICF(ctx, icfLevel).run();<br>
 }<br>
<br>
 } // namespace coff<br>
<br>
diff  --git a/lld/COFF/ICF.h b/lld/COFF/ICF.h<br>
index f8cc8071f9eb7..10e6792a5418f 100644<br>
--- a/lld/COFF/ICF.h<br>
+++ b/lld/COFF/ICF.h<br>
@@ -17,8 +17,9 @@ namespace lld {<br>
 namespace coff {<br>
<br>
 class Chunk;<br>
+class COFFLinkerContext;<br>
<br>
-void doICF(ArrayRef<Chunk *> chunks, ICFLevel);<br>
+void doICF(COFFLinkerContext &ctx, ICFLevel);<br>
<br>
 } // namespace coff<br>
 } // namespace lld<br>
<br>
diff  --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp<br>
index f32353ca4f94a..4b38e3d1a99bc 100644<br>
--- a/lld/COFF/InputFiles.cpp<br>
+++ b/lld/COFF/InputFiles.cpp<br>
@@ -7,6 +7,7 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "InputFiles.h"<br>
+#include "COFFLinkerContext.h"<br>
 #include "Chunks.h"<br>
 #include "Config.h"<br>
 #include "DebugTypes.h"<br>
@@ -69,11 +70,6 @@ std::string lld::toString(const coff::InputFile *file) {<br>
       .str();<br>
 }<br>
<br>
-std::vector<ObjFile *> ObjFile::instances;<br>
-std::map<std::string, PDBInputFile *> PDBInputFile::instances;<br>
-std::vector<ImportFile *> ImportFile::instances;<br>
-std::vector<BitcodeFile *> BitcodeFile::instances;<br>
-<br>
 /// Checks that Source is compatible with being a weak alias to Target.<br>
 /// If Source is Undefined and has no weak alias set, makes it a weak<br>
 /// alias to Target.<br>
@@ -98,7 +94,8 @@ static bool ignoredSymbolName(StringRef name) {<br>
   return name == "@feat.00" || name == "@<a href="http://comp.id" rel="noreferrer" target="_blank">comp.id</a>";<br>
 }<br>
<br>
-ArchiveFile::ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}<br>
+ArchiveFile::ArchiveFile(COFFLinkerContext &ctx, MemoryBufferRef m)<br>
+    : InputFile(ctx, ArchiveKind, m) {}<br>
<br>
 void ArchiveFile::parse() {<br>
   // Parse a MemoryBufferRef as an archive file.<br>
@@ -106,7 +103,7 @@ void ArchiveFile::parse() {<br>
<br>
   // Read the symbol table to construct Lazy objects.<br>
   for (const Archive::Symbol &sym : file->symbols())<br>
-    symtab->addLazyArchive(this, sym);<br>
+    ctx.symtab.addLazyArchive(this, sym);<br>
 }<br>
<br>
 // Returns a buffer pointing to a member file containing a given symbol.<br>
@@ -144,11 +141,11 @@ void LazyObjFile::fetch() {<br>
<br>
   InputFile *file;<br>
   if (isBitcode(mb))<br>
-    file = make<BitcodeFile>(mb, "", 0, std::move(symbols));<br>
+    file = make<BitcodeFile>(ctx, mb, "", 0, std::move(symbols));<br>
   else<br>
-    file = make<ObjFile>(mb, std::move(symbols));<br>
+    file = make<ObjFile>(ctx, mb, std::move(symbols));<br>
   mb = {};<br>
-  symtab->addFile(file);<br>
+  ctx.symtab.addFile(file);<br>
 }<br>
<br>
 void LazyObjFile::parse() {<br>
@@ -158,7 +155,7 @@ void LazyObjFile::parse() {<br>
         CHECK(lto::InputFile::create(this->mb), this);<br>
     for (const lto::InputFile::Symbol &sym : obj->symbols()) {<br>
       if (!sym.isUndefined())<br>
-        symtab->addLazyObject(this, sym.getName());<br>
+        ctx.symtab.addLazyObject(this, sym.getName());<br>
     }<br>
     return;<br>
   }<br>
@@ -175,7 +172,7 @@ void LazyObjFile::parse() {<br>
     StringRef name = check(coffObj->getSymbolName(coffSym));<br>
     if (coffSym.isAbsolute() && ignoredSymbolName(name))<br>
       continue;<br>
-    symtab->addLazyObject(this, name);<br>
+    ctx.symtab.addLazyObject(this, name);<br>
     i += coffSym.getNumberOfAuxSymbols();<br>
   }<br>
 }<br>
@@ -293,7 +290,7 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber,<br>
     // COFF sections that look like string literal sections (i.e. no<br>
     // relocations, in .rdata, leader symbol name matches the MSVC name mangling<br>
     // for string literals) are subject to string tail merging.<br>
-    MergeChunk::addSection(c);<br>
+    MergeChunk::addSection(ctx, c);<br>
   else if (name == ".rsrc" || name.startswith(".rsrc$"))<br>
     resourceChunks.push_back(c);<br>
   else<br>
@@ -387,8 +384,8 @@ Symbol *ObjFile::createRegular(COFFSymbolRef sym) {<br>
   if (sym.isExternal()) {<br>
     StringRef name = check(coffObj->getSymbolName(sym));<br>
     if (sc)<br>
-      return symtab->addRegular(this, name, sym.getGeneric(), sc,<br>
-                                sym.getValue());<br>
+      return ctx.symtab.addRegular(this, name, sym.getGeneric(), sc,<br>
+                                   sym.getValue());<br>
     // For MinGW symbols named .weak.* that point to a discarded section,<br>
     // don't create an Undefined symbol. If nothing ever refers to the symbol,<br>
     // everything should be fine. If something actually refers to the symbol<br>
@@ -396,7 +393,7 @@ Symbol *ObjFile::createRegular(COFFSymbolRef sym) {<br>
     // references at the end.<br>
     if (config->mingw && name.startswith(".weak."))<br>
       return nullptr;<br>
-    return symtab->addUndefined(name, this, false);<br>
+    return ctx.symtab.addUndefined(name, this, false);<br>
   }<br>
   if (sc)<br>
     return make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,<br>
@@ -464,7 +461,7 @@ void ObjFile::initializeSymbols() {<br>
   for (auto &kv : weakAliases) {<br>
     Symbol *sym = kv.first;<br>
     uint32_t idx = kv.second;<br>
-    checkAndSetWeakAlias(symtab, this, sym, symbols[idx]);<br>
+    checkAndSetWeakAlias(&ctx.symtab, this, sym, symbols[idx]);<br>
   }<br>
<br>
   // Free the memory used by sparseChunks now that symbol loading is finished.<br>
@@ -473,7 +470,7 @@ void ObjFile::initializeSymbols() {<br>
<br>
 Symbol *ObjFile::createUndefined(COFFSymbolRef sym) {<br>
   StringRef name = check(coffObj->getSymbolName(sym));<br>
-  return symtab->addUndefined(name, this, sym.isWeakExternal());<br>
+  return ctx.symtab.addUndefined(name, this, sym.isWeakExternal());<br>
 }<br>
<br>
 static const coff_aux_section_definition *findSectionDef(COFFObjectFile *obj,<br>
@@ -543,13 +540,13 @@ void ObjFile::handleComdatSelection(<br>
          Twine((int)leaderSelection) + " in " + toString(leader->getFile()) +<br>
          " and " + Twine((int)selection) + " in " + toString(this))<br>
             .str());<br>
-    symtab->reportDuplicate(leader, this);<br>
+    ctx.symtab.reportDuplicate(leader, this);<br>
     return;<br>
   }<br>
<br>
   switch (selection) {<br>
   case IMAGE_COMDAT_SELECT_NODUPLICATES:<br>
-    symtab->reportDuplicate(leader, this);<br>
+    ctx.symtab.reportDuplicate(leader, this);<br>
     break;<br>
<br>
   case IMAGE_COMDAT_SELECT_ANY:<br>
@@ -559,14 +556,14 @@ void ObjFile::handleComdatSelection(<br>
   case IMAGE_COMDAT_SELECT_SAME_SIZE:<br>
     if (leaderChunk->getSize() != getSection(sym)->SizeOfRawData) {<br>
       if (!config->mingw) {<br>
-        symtab->reportDuplicate(leader, this);<br>
+        ctx.symtab.reportDuplicate(leader, this);<br>
       } else {<br>
         const coff_aux_section_definition *leaderDef = nullptr;<br>
         if (leaderChunk->file)<br>
           leaderDef = findSectionDef(leaderChunk->file->getCOFFObj(),<br>
                                      leaderChunk->getSectionNumber());<br>
         if (!leaderDef || leaderDef->Length != def->Length)<br>
-          symtab->reportDuplicate(leader, this);<br>
+          ctx.symtab.reportDuplicate(leader, this);<br>
       }<br>
     }<br>
     break;<br>
@@ -577,7 +574,7 @@ void ObjFile::handleComdatSelection(<br>
     // if the two comdat sections have e.g. <br>
diff erent alignment.<br>
     // Match that.<br>
     if (leaderChunk->getContents() != newChunk.getContents())<br>
-      symtab->reportDuplicate(leader, this, &newChunk, sym.getValue());<br>
+      ctx.symtab.reportDuplicate(leader, this, &newChunk, sym.getValue());<br>
     break;<br>
   }<br>
<br>
@@ -620,8 +617,8 @@ Optional<Symbol *> ObjFile::createDefined(<br>
   if (sym.isCommon()) {<br>
     auto *c = make<CommonChunk>(sym);<br>
     chunks.push_back(c);<br>
-    return symtab->addCommon(this, getName(), sym.getValue(), sym.getGeneric(),<br>
-                             c);<br>
+    return ctx.symtab.addCommon(this, getName(), sym.getValue(),<br>
+                                sym.getGeneric(), c);<br>
   }<br>
<br>
   if (sym.isAbsolute()) {<br>
@@ -634,7 +631,7 @@ Optional<Symbol *> ObjFile::createDefined(<br>
       return nullptr;<br>
<br>
     if (sym.isExternal())<br>
-      return symtab->addAbsolute(name, sym);<br>
+      return ctx.symtab.addAbsolute(name, sym);<br>
     return make<DefinedAbsolute>(name, sym);<br>
   }<br>
<br>
@@ -667,7 +664,7 @@ Optional<Symbol *> ObjFile::createDefined(<br>
<br>
     if (sym.isExternal()) {<br>
       std::tie(leader, prevailing) =<br>
-          symtab->addComdat(this, getName(), sym.getGeneric());<br>
+          ctx.symtab.addComdat(this, getName(), sym.getGeneric());<br>
     } else {<br>
       leader = make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,<br>
                                     /*IsExternal*/ false, sym.getGeneric());<br>
@@ -789,12 +786,11 @@ void ObjFile::initializeDependencies() {<br>
   else<br>
     data = getDebugSection(".debug$T");<br>
<br>
-  // Don't make a TpiSource for objects with no debug info. If the object has<br>
   // symbols but no types, make a plain, empty TpiSource anyway, because it<br>
   // simplifies adding the symbols later.<br>
   if (data.empty()) {<br>
     if (!debugChunks.empty())<br>
-      debugTypesObj = makeTpiSource(this);<br>
+      debugTypesObj = makeTpiSource(ctx, this);<br>
     return;<br>
   }<br>
<br>
@@ -812,7 +808,7 @@ void ObjFile::initializeDependencies() {<br>
<br>
   // This object file is a PCH file that others will depend on.<br>
   if (isPCH) {<br>
-    debugTypesObj = makePrecompSource(this);<br>
+    debugTypesObj = makePrecompSource(ctx, this);<br>
     return;<br>
   }<br>
<br>
@@ -820,8 +816,8 @@ void ObjFile::initializeDependencies() {<br>
   if (firstType->kind() == LF_TYPESERVER2) {<br>
     TypeServer2Record ts = cantFail(<br>
         TypeDeserializer::deserializeAs<TypeServer2Record>(firstType->data()));<br>
-    debugTypesObj = makeUseTypeServerSource(this, ts);<br>
-    PDBInputFile::enqueue(ts.getName(), this);<br>
+    debugTypesObj = makeUseTypeServerSource(ctx, this, ts);<br>
+    enqueuePdbFile(ts.getName(), this);<br>
     return;<br>
   }<br>
<br>
@@ -830,14 +826,14 @@ void ObjFile::initializeDependencies() {<br>
   if (firstType->kind() == LF_PRECOMP) {<br>
     PrecompRecord precomp = cantFail(<br>
         TypeDeserializer::deserializeAs<PrecompRecord>(firstType->data()));<br>
-    debugTypesObj = makeUsePrecompSource(this, precomp);<br>
+    debugTypesObj = makeUsePrecompSource(ctx, this, precomp);<br>
     // Drop the LF_PRECOMP record from the input stream.<br>
     debugTypes = debugTypes.drop_front(firstType->RecordData.size());<br>
     return;<br>
   }<br>
<br>
   // This is a plain old object file.<br>
-  debugTypesObj = makeTpiSource(this);<br>
+  debugTypesObj = makeTpiSource(ctx, this);<br>
 }<br>
<br>
 // Make a PDB path assuming the PDB is in the same folder as the OBJ<br>
@@ -855,7 +851,7 @@ static std::string getPdbBaseName(ObjFile *file, StringRef tSPath) {<br>
<br>
 // The casing of the PDB path stamped in the OBJ can <br>
diff er from the actual path<br>
 // on disk. With this, we ensure to always use lowercase as a key for the<br>
-// PDBInputFile::instances map, at least on Windows.<br>
+// pdbInputFileInstances map, at least on Windows.<br>
 static std::string normalizePdbPath(StringRef path) {<br>
 #if defined(_WIN32)<br>
   return path.lower();<br>
@@ -879,33 +875,25 @@ static Optional<std::string> findPdbPath(StringRef pdbPath,<br>
   return None;<br>
 }<br>
<br>
-PDBInputFile::PDBInputFile(MemoryBufferRef m) : InputFile(PDBKind, m) {}<br>
+PDBInputFile::PDBInputFile(COFFLinkerContext &ctx, MemoryBufferRef m)<br>
+    : InputFile(ctx, PDBKind, m) {}<br>
<br>
 PDBInputFile::~PDBInputFile() = default;<br>
<br>
-PDBInputFile *PDBInputFile::findFromRecordPath(StringRef path,<br>
+PDBInputFile *PDBInputFile::findFromRecordPath(const COFFLinkerContext &ctx,<br>
+                                               StringRef path,<br>
                                                ObjFile *fromFile) {<br>
   auto p = findPdbPath(path.str(), fromFile);<br>
   if (!p)<br>
     return nullptr;<br>
-  auto it = PDBInputFile::instances.find(*p);<br>
-  if (it != PDBInputFile::instances.end())<br>
+  auto it = ctx.pdbInputFileInstances.find(*p);<br>
+  if (it != ctx.pdbInputFileInstances.end())<br>
     return it->second;<br>
   return nullptr;<br>
 }<br>
<br>
-void PDBInputFile::enqueue(StringRef path, ObjFile *fromFile) {<br>
-  auto p = findPdbPath(path.str(), fromFile);<br>
-  if (!p)<br>
-    return;<br>
-  auto it = PDBInputFile::instances.emplace(*p, nullptr);<br>
-  if (!it.second)<br>
-    return; // already scheduled for load<br>
-  driver->enqueuePDB(*p);<br>
-}<br>
-<br>
 void PDBInputFile::parse() {<br>
-  PDBInputFile::instances[mb.getBufferIdentifier().str()] = this;<br>
+  ctx.pdbInputFileInstances[mb.getBufferIdentifier().str()] = this;<br>
<br>
   std::unique_ptr<pdb::IPDBSession> thisSession;<br>
   loadErr.emplace(pdb::NativeSession::createFromPdb(<br>
@@ -923,7 +911,7 @@ void PDBInputFile::parse() {<br>
     loadErr.emplace(expectedInfo.takeError());<br>
     return;<br>
   }<br>
-  debugTypesObj = makeTypeServerSource(this);<br>
+  debugTypesObj = makeTypeServerSource(ctx, this);<br>
 }<br>
<br>
 // Used only for DWARF debug info, which is not common (except in MinGW<br>
@@ -957,6 +945,16 @@ Optional<DILineInfo> ObjFile::getDILineInfo(uint32_t offset,<br>
   return dwarf->getDILineInfo(offset, sectionIndex);<br>
 }<br>
<br>
+void ObjFile::enqueuePdbFile(StringRef path, ObjFile *fromFile) {<br>
+  auto p = findPdbPath(path.str(), fromFile);<br>
+  if (!p)<br>
+    return;<br>
+  auto it = ctx.pdbInputFileInstances.emplace(*p, nullptr);<br>
+  if (!it.second)<br>
+    return; // already scheduled for load<br>
+  driver->enqueuePDB(*p);<br>
+}<br>
+<br>
 void ImportFile::parse() {<br>
   const char *buf = mb.getBufferStart();<br>
   const auto *hdr = reinterpret_cast<const coff_import_header *>(buf);<br>
@@ -990,31 +988,31 @@ void ImportFile::parse() {<br>
   this->hdr = hdr;<br>
   externalName = extName;<br>
<br>
-  impSym = symtab->addImportData(impName, this);<br>
+  impSym = ctx.symtab.addImportData(impName, this);<br>
   // If this was a duplicate, we logged an error but may continue;<br>
   // in this case, impSym is nullptr.<br>
   if (!impSym)<br>
     return;<br>
<br>
   if (hdr->getType() == llvm::COFF::IMPORT_CONST)<br>
-    static_cast<void>(symtab->addImportData(name, this));<br>
+    static_cast<void>(ctx.symtab.addImportData(name, this));<br>
<br>
   // If type is function, we need to create a thunk which jump to an<br>
   // address pointed by the __imp_ symbol. (This allows you to call<br>
   // DLL functions just like regular non-DLL functions.)<br>
   if (hdr->getType() == llvm::COFF::IMPORT_CODE)<br>
-    thunkSym = symtab->addImportThunk(<br>
+    thunkSym = ctx.symtab.addImportThunk(<br>
         name, cast_or_null<DefinedImportData>(impSym), hdr->Machine);<br>
 }<br>
<br>
-BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,<br>
-                         uint64_t offsetInArchive)<br>
-    : BitcodeFile(mb, archiveName, offsetInArchive, {}) {}<br>
+BitcodeFile::BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,<br>
+                         StringRef archiveName, uint64_t offsetInArchive)<br>
+    : BitcodeFile(ctx, mb, archiveName, offsetInArchive, {}) {}<br>
<br>
-BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,<br>
-                         uint64_t offsetInArchive,<br>
+BitcodeFile::BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,<br>
+                         StringRef archiveName, uint64_t offsetInArchive,<br>
                          std::vector<Symbol *> &&symbols)<br>
-    : InputFile(BitcodeKind, mb), symbols(std::move(symbols)) {<br>
+    : InputFile(ctx, BitcodeKind, mb), symbols(std::move(symbols)) {<br>
   std::string path = mb.getBufferIdentifier().str();<br>
   if (config->thinLTOIndexOnly)<br>
     path = replaceThinLTOSuffix(mb.getBufferIdentifier());<br>
@@ -1069,7 +1067,7 @@ void BitcodeFile::parse() {<br>
   for (size_t i = 0; i != obj->getComdatTable().size(); ++i)<br>
     // FIXME: Check nodeduplicate<br>
     comdat[i] =<br>
-        symtab->addComdat(this, saver.save(obj->getComdatTable()[i].first));<br>
+        ctx.symtab.addComdat(this, saver.save(obj->getComdatTable()[i].first));<br>
   for (const lto::InputFile::Symbol &objSym : obj->symbols()) {<br>
     StringRef symName = saver.save(objSym.getName());<br>
     int comdatIndex = objSym.getComdatIndex();<br>
@@ -1080,27 +1078,27 @@ void BitcodeFile::parse() {<br>
     else<br>
       fakeSC = &ltoDataSectionChunk.chunk;<br>
     if (objSym.isUndefined()) {<br>
-      sym = symtab->addUndefined(symName, this, false);<br>
+      sym = ctx.symtab.addUndefined(symName, this, false);<br>
     } else if (objSym.isCommon()) {<br>
-      sym = symtab->addCommon(this, symName, objSym.getCommonSize());<br>
+      sym = ctx.symtab.addCommon(this, symName, objSym.getCommonSize());<br>
     } else if (objSym.isWeak() && objSym.isIndirect()) {<br>
       // Weak external.<br>
-      sym = symtab->addUndefined(symName, this, true);<br>
+      sym = ctx.symtab.addUndefined(symName, this, true);<br>
       std::string fallback = std::string(objSym.getCOFFWeakExternalFallback());<br>
-      Symbol *alias = symtab->addUndefined(saver.save(fallback));<br>
-      checkAndSetWeakAlias(symtab, this, sym, alias);<br>
+      Symbol *alias = ctx.symtab.addUndefined(saver.save(fallback));<br>
+      checkAndSetWeakAlias(&ctx.symtab, this, sym, alias);<br>
     } else if (comdatIndex != -1) {<br>
       if (symName == obj->getComdatTable()[comdatIndex].first) {<br>
         sym = comdat[comdatIndex].first;<br>
         if (cast<DefinedRegular>(sym)->data == nullptr)<br>
           cast<DefinedRegular>(sym)->data = &fakeSC->repl;<br>
       } else if (comdat[comdatIndex].second) {<br>
-        sym = symtab->addRegular(this, symName, nullptr, fakeSC);<br>
+        sym = ctx.symtab.addRegular(this, symName, nullptr, fakeSC);<br>
       } else {<br>
-        sym = symtab->addUndefined(symName, this, false);<br>
+        sym = ctx.symtab.addUndefined(symName, this, false);<br>
       }<br>
     } else {<br>
-      sym = symtab->addRegular(this, symName, nullptr, fakeSC);<br>
+      sym = ctx.symtab.addRegular(this, symName, nullptr, fakeSC);<br>
     }<br>
     symbols.push_back(sym);<br>
     if (objSym.isUsed())<br>
@@ -1185,9 +1183,9 @@ void DLLFile::parse() {<br>
     }<br>
<br>
     StringRef impName = saver.save("__imp_" + symbolName);<br>
-    symtab->addLazyDLLSymbol(this, s, impName);<br>
+    ctx.symtab.addLazyDLLSymbol(this, s, impName);<br>
     if (code)<br>
-      symtab->addLazyDLLSymbol(this, s, symbolName);<br>
+      ctx.symtab.addLazyDLLSymbol(this, s, symbolName);<br>
   }<br>
 }<br>
<br>
@@ -1219,6 +1217,6 @@ void DLLFile::makeImport(DLLFile::Symbol *s) {<br>
   p += s->symbolName.size() + 1;<br>
   memcpy(p, s->dllName.data(), s->dllName.size());<br>
   MemoryBufferRef mbref = MemoryBufferRef(StringRef(buf, size), s->dllName);<br>
-  ImportFile *impFile = make<ImportFile>(mbref);<br>
-  symtab->addFile(impFile);<br>
+  ImportFile *impFile = make<ImportFile>(ctx, mbref);<br>
+  ctx.symtab.addFile(impFile);<br>
 }<br>
<br>
diff  --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h<br>
index 47b5c588c5af7..801c668d3ae45 100644<br>
--- a/lld/COFF/InputFiles.h<br>
+++ b/lld/COFF/InputFiles.h<br>
@@ -38,6 +38,7 @@ namespace lld {<br>
 class DWARFCache;<br>
<br>
 namespace coff {<br>
+class COFFLinkerContext;<br>
<br>
 std::vector<MemoryBufferRef> getArchiveMembers(llvm::object::Archive *file);<br>
<br>
@@ -91,8 +92,11 @@ class InputFile {<br>
   // Returns .drectve section contents if exist.<br>
   StringRef getDirectives() { return directives; }<br>
<br>
+  COFFLinkerContext &ctx;<br>
+<br>
 protected:<br>
-  InputFile(Kind k, MemoryBufferRef m) : mb(m), fileKind(k) {}<br>
+  InputFile(COFFLinkerContext &c, Kind k, MemoryBufferRef m)<br>
+      : mb(m), ctx(c), fileKind(k) {}<br>
<br>
   StringRef directives;<br>
<br>
@@ -103,7 +107,7 @@ class InputFile {<br>
 // .lib or .a file.<br>
 class ArchiveFile : public InputFile {<br>
 public:<br>
-  explicit ArchiveFile(MemoryBufferRef m);<br>
+  explicit ArchiveFile(COFFLinkerContext &ctx, MemoryBufferRef m);<br>
   static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }<br>
   void parse() override;<br>
<br>
@@ -120,7 +124,8 @@ class ArchiveFile : public InputFile {<br>
 // .obj or .o file between -start-lib and -end-lib.<br>
 class LazyObjFile : public InputFile {<br>
 public:<br>
-  explicit LazyObjFile(MemoryBufferRef m) : InputFile(LazyObjectKind, m) {}<br>
+  explicit LazyObjFile(COFFLinkerContext &ctx, MemoryBufferRef m)<br>
+      : InputFile(ctx, LazyObjectKind, m) {}<br>
   static bool classof(const InputFile *f) {<br>
     return f->kind() == LazyObjectKind;<br>
   }<br>
@@ -136,9 +141,11 @@ class LazyObjFile : public InputFile {<br>
 // .obj or .o file. This may be a member of an archive file.<br>
 class ObjFile : public InputFile {<br>
 public:<br>
-  explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {}<br>
-  explicit ObjFile(MemoryBufferRef m, std::vector<Symbol *> &&symbols)<br>
-      : InputFile(ObjectKind, m), symbols(std::move(symbols)) {}<br>
+  explicit ObjFile(COFFLinkerContext &ctx, MemoryBufferRef m)<br>
+      : InputFile(ctx, ObjectKind, m) {}<br>
+  explicit ObjFile(COFFLinkerContext &ctx, MemoryBufferRef m,<br>
+                   std::vector<Symbol *> &&symbols)<br>
+      : InputFile(ctx, ObjectKind, m), symbols(std::move(symbols)) {}<br>
   static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }<br>
   void parse() override;<br>
   MachineTypes getMachineType() override;<br>
@@ -175,8 +182,6 @@ class ObjFile : public InputFile {<br>
<br>
   bool isResourceObjFile() const { return !resourceChunks.empty(); }<br>
<br>
-  static std::vector<ObjFile *> instances;<br>
-<br>
   // Flags in the absolute @feat.00 symbol if it is present. These usually<br>
   // indicate if an object was compiled with certain security features enabled<br>
   // like stack guard, safeseh, /guard:cf, or other things.<br>
@@ -228,6 +233,8 @@ class ObjFile : public InputFile {<br>
     return getSection(sym.getSectionNumber());<br>
   }<br>
<br>
+  void enqueuePdbFile(StringRef path, ObjFile *fromFile);<br>
+<br>
   void initializeChunks();<br>
   void initializeSymbols();<br>
   void initializeFlags();<br>
@@ -318,16 +325,13 @@ class ObjFile : public InputFile {<br>
 // stream.<br>
 class PDBInputFile : public InputFile {<br>
 public:<br>
-  explicit PDBInputFile(MemoryBufferRef m);<br>
+  explicit PDBInputFile(COFFLinkerContext &ctx, MemoryBufferRef m);<br>
   ~PDBInputFile();<br>
   static bool classof(const InputFile *f) { return f->kind() == PDBKind; }<br>
   void parse() override;<br>
<br>
-  static void enqueue(StringRef path, ObjFile *fromFile);<br>
-<br>
-  static PDBInputFile *findFromRecordPath(StringRef path, ObjFile *fromFile);<br>
-<br>
-  static std::map<std::string, PDBInputFile *> instances;<br>
+  static PDBInputFile *findFromRecordPath(const COFFLinkerContext &ctx,<br>
+                                          StringRef path, ObjFile *fromFile);<br>
<br>
   // Record possible errors while opening the PDB file<br>
   llvm::Optional<Error> loadErr;<br>
@@ -344,12 +348,11 @@ class PDBInputFile : public InputFile {<br>
 // for details about the format.<br>
 class ImportFile : public InputFile {<br>
 public:<br>
-  explicit ImportFile(MemoryBufferRef m) : InputFile(ImportKind, m) {}<br>
+  explicit ImportFile(COFFLinkerContext &ctx, MemoryBufferRef m)<br>
+      : InputFile(ctx, ImportKind, m) {}<br>
<br>
   static bool classof(const InputFile *f) { return f->kind() == ImportKind; }<br>
<br>
-  static std::vector<ImportFile *> instances;<br>
-<br>
   Symbol *impSym = nullptr;<br>
   Symbol *thunkSym = nullptr;<br>
   std::string dllName;<br>
@@ -377,16 +380,15 @@ class ImportFile : public InputFile {<br>
 // Used for LTO.<br>
 class BitcodeFile : public InputFile {<br>
 public:<br>
-  BitcodeFile(MemoryBufferRef mb, StringRef archiveName,<br>
+  BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb, StringRef archiveName,<br>
               uint64_t offsetInArchive);<br>
-  explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName,<br>
-                       uint64_t offsetInArchive,<br>
+  explicit BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef m,<br>
+                       StringRef archiveName, uint64_t offsetInArchive,<br>
                        std::vector<Symbol *> &&symbols);<br>
   ~BitcodeFile();<br>
   static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }<br>
   ArrayRef<Symbol *> getSymbols() { return symbols; }<br>
   MachineTypes getMachineType() override;<br>
-  static std::vector<BitcodeFile *> instances;<br>
   std::unique_ptr<llvm::lto::InputFile> obj;<br>
<br>
 private:<br>
@@ -398,7 +400,8 @@ class BitcodeFile : public InputFile {<br>
 // .dll file. MinGW only.<br>
 class DLLFile : public InputFile {<br>
 public:<br>
-  explicit DLLFile(MemoryBufferRef m) : InputFile(DLLKind, m) {}<br>
+  explicit DLLFile(COFFLinkerContext &ctx, MemoryBufferRef m)<br>
+      : InputFile(ctx, DLLKind, m) {}<br>
   static bool classof(const InputFile *f) { return f->kind() == DLLKind; }<br>
   void parse() override;<br>
   MachineTypes getMachineType() override;<br>
<br>
diff  --git a/lld/COFF/LLDMapFile.cpp b/lld/COFF/LLDMapFile.cpp<br>
index 79df33a3535fd..639b186dbb6f9 100644<br>
--- a/lld/COFF/LLDMapFile.cpp<br>
+++ b/lld/COFF/LLDMapFile.cpp<br>
@@ -19,6 +19,7 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "LLDMapFile.h"<br>
+#include "COFFLinkerContext.h"<br>
 #include "SymbolTable.h"<br>
 #include "Symbols.h"<br>
 #include "Writer.h"<br>
@@ -44,9 +45,9 @@ static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size,<br>
 }<br>
<br>
 // Returns a list of all symbols that we want to print out.<br>
-static std::vector<DefinedRegular *> getSymbols() {<br>
+static std::vector<DefinedRegular *> getSymbols(const COFFLinkerContext &ctx) {<br>
   std::vector<DefinedRegular *> v;<br>
-  for (ObjFile *file : ObjFile::instances)<br>
+  for (ObjFile *file : ctx.objFileInstances)<br>
     for (Symbol *b : file->getSymbols())<br>
       if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))<br>
         if (sym && !sym->getCOFFSymbol().isSectionDefinition())<br>
@@ -86,7 +87,7 @@ getSymbolStrings(ArrayRef<DefinedRegular *> syms) {<br>
   return ret;<br>
 }<br>
<br>
-void lld::coff::writeLLDMapFile(ArrayRef<OutputSection *> outputSections) {<br>
+void lld::coff::writeLLDMapFile(const COFFLinkerContext &ctx) {<br>
   if (config->lldmapFile.empty())<br>
     return;<br>
<br>
@@ -96,7 +97,7 @@ void lld::coff::writeLLDMapFile(ArrayRef<OutputSection *> outputSections) {<br>
     fatal("cannot open " + config->lldmapFile + ": " + ec.message());<br>
<br>
   // Collect symbol info that we want to print out.<br>
-  std::vector<DefinedRegular *> syms = getSymbols();<br>
+  std::vector<DefinedRegular *> syms = getSymbols(ctx);<br>
   SymbolMapTy sectionSyms = getSectionSyms(syms);<br>
   DenseMap<DefinedRegular *, std::string> symStr = getSymbolStrings(syms);<br>
<br>
@@ -104,7 +105,7 @@ void lld::coff::writeLLDMapFile(ArrayRef<OutputSection *> outputSections) {<br>
   os << "Address  Size     Align Out     In      Symbol\n";<br>
<br>
   // Print out file contents.<br>
-  for (OutputSection *sec : outputSections) {<br>
+  for (OutputSection *sec : ctx.outputSections) {<br>
     writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*align=*/pageSize);<br>
     os << sec->name << '\n';<br>
<br>
<br>
diff  --git a/lld/COFF/LLDMapFile.h b/lld/COFF/LLDMapFile.h<br>
index b731293a8625d..72e999a61900a 100644<br>
--- a/lld/COFF/LLDMapFile.h<br>
+++ b/lld/COFF/LLDMapFile.h<br>
@@ -9,12 +9,10 @@<br>
 #ifndef LLD_COFF_LLDMAPFILE_H<br>
 #define LLD_COFF_LLDMAPFILE_H<br>
<br>
-#include "llvm/ADT/ArrayRef.h"<br>
-<br>
 namespace lld {<br>
 namespace coff {<br>
-class OutputSection;<br>
-void writeLLDMapFile(llvm::ArrayRef<OutputSection *> outputSections);<br>
+class COFFLinkerContext;<br>
+void writeLLDMapFile(const COFFLinkerContext &ctx);<br>
 }<br>
 }<br>
<br>
<br>
diff  --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp<br>
index 6e38f53f21362..ce9c4fd0d51b2 100644<br>
--- a/lld/COFF/LTO.cpp<br>
+++ b/lld/COFF/LTO.cpp<br>
@@ -156,7 +156,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {<br>
<br>
 // Merge all the bitcode files we have seen, codegen the</blockquote></div></div>
</blockquote></div>