Subzero. Fixes memory leaks.

Adds named constructors to initialzers. Removes destructor from Inst.

BUG= None
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/1181013016.
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index f3b04eb..72c9120 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -77,11 +77,12 @@
 constexpr char BlockNameGlobalPrefix[] = ".L$profiler$block_name$";
 constexpr char BlockStatsGlobalPrefix[] = ".L$profiler$block_info$";
 
-VariableDeclaration *nodeNameDeclaration(const IceString &NodeAsmName) {
-  VariableDeclaration *Var = VariableDeclaration::create();
+VariableDeclaration *nodeNameDeclaration(GlobalContext *Ctx,
+                                         const IceString &NodeAsmName) {
+  VariableDeclaration *Var = VariableDeclaration::create(Ctx);
   Var->setName(BlockNameGlobalPrefix + NodeAsmName);
   Var->setIsConstant(true);
-  Var->addInitializer(new VariableDeclaration::DataInitializer(
+  Var->addInitializer(VariableDeclaration::DataInitializer::create(
       NodeAsmName.data(), NodeAsmName.size() + 1));
   const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64);
   Var->setAlignment(Int64ByteSize); // Wasteful, 32-bit could use 4 bytes.
@@ -89,20 +90,20 @@
 }
 
 VariableDeclaration *
-blockProfilingInfoDeclaration(const IceString &NodeAsmName,
+blockProfilingInfoDeclaration(GlobalContext *Ctx, const IceString &NodeAsmName,
                               VariableDeclaration *NodeNameDeclaration) {
-  VariableDeclaration *Var = VariableDeclaration::create();
+  VariableDeclaration *Var = VariableDeclaration::create(Ctx);
   Var->setName(BlockStatsGlobalPrefix + NodeAsmName);
   const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64);
-  Var->addInitializer(new VariableDeclaration::ZeroInitializer(Int64ByteSize));
+  Var->addInitializer(
+      VariableDeclaration::ZeroInitializer::create(Int64ByteSize));
 
   const RelocOffsetT NodeNameDeclarationOffset = 0;
-  Var->addInitializer(new VariableDeclaration::RelocInitializer(
+  Var->addInitializer(VariableDeclaration::RelocInitializer::create(
       NodeNameDeclaration, NodeNameDeclarationOffset));
   Var->setAlignment(Int64ByteSize);
   return Var;
 }
-
 } // end of anonymous namespace
 
 void Cfg::profileBlocks() {
@@ -111,9 +112,9 @@
 
   for (CfgNode *Node : Nodes) {
     IceString NodeAsmName = Node->getAsmName();
-    GlobalInits->push_back(nodeNameDeclaration(NodeAsmName));
+    GlobalInits->push_back(nodeNameDeclaration(Ctx, NodeAsmName));
     GlobalInits->push_back(
-        blockProfilingInfoDeclaration(NodeAsmName, GlobalInits->back()));
+        blockProfilingInfoDeclaration(Ctx, NodeAsmName, GlobalInits->back()));
     Node->profileExecutionCount(GlobalInits->back());
   }
 }
diff --git a/src/IceConverter.cpp b/src/IceConverter.cpp
index 6b83b15..baa8eeb 100644
--- a/src/IceConverter.cpp
+++ b/src/IceConverter.cpp
@@ -754,7 +754,7 @@
   if (const auto CDA = dyn_cast<ConstantDataArray>(Initializer)) {
     assert(!HasOffset && isa<IntegerType>(CDA->getElementType()) &&
            (cast<IntegerType>(CDA->getElementType())->getBitWidth() == 8));
-    Global.addInitializer(new Ice::VariableDeclaration::DataInitializer(
+    Global.addInitializer(Ice::VariableDeclaration::DataInitializer::create(
         CDA->getRawDataValues().data(), CDA->getNumElements()));
     return;
   }
@@ -763,8 +763,8 @@
     if (const auto AT = dyn_cast<ArrayType>(Initializer->getType())) {
       assert(!HasOffset && isa<IntegerType>(AT->getElementType()) &&
              (cast<IntegerType>(AT->getElementType())->getBitWidth() == 8));
-      Global.addInitializer(
-          new Ice::VariableDeclaration::ZeroInitializer(AT->getNumElements()));
+      Global.addInitializer(Ice::VariableDeclaration::ZeroInitializer::create(
+          AT->getNumElements()));
     } else {
       llvm_unreachable("Unhandled constant aggregate zero type");
     }
@@ -786,7 +786,7 @@
       const Ice::GlobalDeclaration *Addr =
           getConverter().getGlobalDeclaration(GV);
       Global.addInitializer(
-          new Ice::VariableDeclaration::RelocInitializer(Addr, Offset));
+          Ice::VariableDeclaration::RelocInitializer::create(Addr, Offset));
       return;
     }
     default:
@@ -867,7 +867,7 @@
           Converter.convertToIceType(FuncType->getParamType(I)));
     }
     FunctionDeclaration *IceFunc = FunctionDeclaration::create(
-        Signature, Func.getCallingConv(), Func.getLinkage(), Func.empty());
+        Ctx, Signature, Func.getCallingConv(), Func.getLinkage(), Func.empty());
     IceFunc->setName(Func.getName());
     GlobalDeclarationMap[&Func] = IceFunc;
   }
@@ -876,7 +876,7 @@
                                      E = Mod->global_end();
        I != E; ++I) {
     const GlobalVariable *GV = I;
-    VariableDeclaration *Var = VariableDeclaration::create();
+    VariableDeclaration *Var = VariableDeclaration::create(Ctx);
     Var->setName(GV->getName());
     Var->setAlignment(GV->getAlignment());
     Var->setIsConstant(GV->isConstant());
diff --git a/src/IceDefs.h b/src/IceDefs.h
index 64e70de..4531275 100644
--- a/src/IceDefs.h
+++ b/src/IceDefs.h
@@ -93,6 +93,46 @@
   return false;
 }
 
+// makeUnique should be used when memory is expected to be allocated from the
+// heap (as opposed to allocated from some Allocator.) It is intended to be used
+// instead of new.
+//
+// The expected usage is as follows
+//
+// class MyClass {
+// public:
+//   static std::unique_ptr<MyClass> create(<ctor_args>) {
+//     return makeUnique<MyClass>(<ctor_args>);
+//   }
+//
+// private:
+//   ENABLE_MAKE_UNIQUE;
+//
+//   MyClass(<ctor_args>) ...
+// }
+//
+// ENABLE_MAKE_UNIQUE is a trick that is necessary if MyClass' ctor is private.
+// Private ctors are highly encouraged when you're writing a class that you'd
+// like to have allocated with makeUnique as it would prevent users from
+// declaring stack allocated variables.
+namespace Internal {
+struct MakeUniqueEnabler {
+  template <class T, class... Args>
+  static std::unique_ptr<T> create(Args &&... TheArgs) {
+    std::unique_ptr<T> Unique(new T(std::forward<Args>(TheArgs)...));
+    return Unique;
+  }
+};
+} // end of namespace Internal
+
+template <class T, class... Args>
+static std::unique_ptr<T> makeUnique(Args &&... TheArgs) {
+  return ::Ice::Internal::MakeUniqueEnabler::create<T>(
+      std::forward<Args>(TheArgs)...);
+}
+
+#define ENABLE_MAKE_UNIQUE friend struct ::Ice::Internal::MakeUniqueEnabler
+
 typedef std::string IceString;
 typedef llvm::ilist<Inst> InstList;
 // Ideally PhiList would be llvm::ilist<InstPhi>, and similar for
diff --git a/src/IceELFObjectWriter.cpp b/src/IceELFObjectWriter.cpp
index d24144c..0549754 100644
--- a/src/IceELFObjectWriter.cpp
+++ b/src/IceELFObjectWriter.cpp
@@ -386,12 +386,12 @@
         Section->setSize(Section->getCurrentSize() + SymbolSize);
     } else {
       assert(ST != BSS);
-      for (VariableDeclaration::Initializer *Init : Var->getInitializers()) {
+      for (const std::unique_ptr<VariableDeclaration::Initializer> &Init :
+           Var->getInitializers()) {
         switch (Init->getKind()) {
         case VariableDeclaration::Initializer::DataInitializerKind: {
-          const auto Data =
-              llvm::cast<VariableDeclaration::DataInitializer>(Init)
-                  ->getContents();
+          const auto Data = llvm::cast<VariableDeclaration::DataInitializer>(
+                                Init.get())->getContents();
           Section->appendData(Str, llvm::StringRef(Data.data(), Data.size()));
           break;
         }
@@ -400,7 +400,7 @@
           break;
         case VariableDeclaration::Initializer::RelocInitializerKind: {
           const auto Reloc =
-              llvm::cast<VariableDeclaration::RelocInitializer>(Init);
+              llvm::cast<VariableDeclaration::RelocInitializer>(Init.get());
           AssemblerFixup NewFixup;
           NewFixup.set_position(Section->getCurrentSize());
           NewFixup.set_kind(RelocationKind);
diff --git a/src/IceELFSection.h b/src/IceELFSection.h
index ecbf555..a79a9fb 100644
--- a/src/IceELFSection.h
+++ b/src/IceELFSection.h
@@ -33,6 +33,8 @@
   ELFSection &operator=(const ELFSection &) = delete;
 
 public:
+  virtual ~ELFSection() = default;
+
   // Sentinel value for a section number/index for before the final
   // section index is actually known. The dummy NULL section will be assigned
   // number 0, and it is referenced by the dummy 0-th symbol in the symbol
@@ -81,8 +83,6 @@
   template <bool IsELF64> void writeHeader(ELFStreamer &Str);
 
 protected:
-  ~ELFSection() = default;
-
   // Name of the section in convenient string form (instead of a index
   // into the Section Header String Table, which is not known till later).
   const IceString Name;
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 187ebd5..38d1457 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -223,8 +223,7 @@
            /*MaxSize=*/Flags.getNumTranslationThreads()),
       // EmitQ is allowed unlimited size.
       EmitQ(/*Sequential=*/Flags.isSequential()),
-      DataLowering(TargetDataLowering::createLowering(this)),
-      ProfileBlockInfoVarDecl(VariableDeclaration::create()) {
+      DataLowering(TargetDataLowering::createLowering(this)) {
   assert(OsDump && "OsDump is not defined for GlobalContext");
   assert(OsEmit && "OsEmit is not defined for GlobalContext");
   assert(OsError && "OsError is not defined for GlobalContext");
@@ -256,6 +255,11 @@
   case FT_Iasm:
     break;
   }
+
+  // ProfileBlockInfoVarDecl is initialized here because it takes this as a
+  // parameter -- we want to
+  // ensure that at least this' member variables are initialized.
+  ProfileBlockInfoVarDecl = VariableDeclaration::create(this);
   ProfileBlockInfoVarDecl->setAlignment(typeWidthInBytes(IceType_i64));
   ProfileBlockInfoVarDecl->setIsConstant(true);
 
@@ -346,7 +350,7 @@
     if (Cfg::isProfileGlobal(*Global)) {
       constexpr RelocOffsetT BlockExecutionCounterOffset = 0;
       ProfileBlockInfo->addInitializer(
-          new VariableDeclaration::RelocInitializer(
+          VariableDeclaration::RelocInitializer::create(
               Global, BlockExecutionCounterOffset));
     }
   }
@@ -387,20 +391,28 @@
   if (Flags.getDisableTranslation())
     return;
 
-  addBlockInfoPtrs(Globals, ProfileBlockInfoVarDecl.get());
+  addBlockInfoPtrs(Globals, ProfileBlockInfoVarDecl);
   DataLowering->lowerGlobals(Globals, SectionSuffix);
+  for (VariableDeclaration *Var : Globals) {
+    Var->discardInitializers();
+  }
   Globals.clear();
 }
 
 void GlobalContext::lowerProfileData() {
+  // ProfileBlockInfoVarDecl is initialized in the constructor, and will only
+  // ever be nullptr after this method completes. This assertion is a convoluted
+  // way of ensuring lowerProfileData is invoked a single time.
+  assert(ProfileBlockInfoVarDecl != nullptr);
   // This adds a 64-bit sentinel entry to the end of our array. For 32-bit
   // architectures this will waste 4 bytes.
   const SizeT Sizeof64BitNullPtr = typeWidthInBytes(IceType_i64);
   ProfileBlockInfoVarDecl->addInitializer(
-      new VariableDeclaration::ZeroInitializer(Sizeof64BitNullPtr));
-  Globals.push_back(ProfileBlockInfoVarDecl.get());
+      VariableDeclaration::ZeroInitializer::create(Sizeof64BitNullPtr));
+  Globals.push_back(ProfileBlockInfoVarDecl);
   constexpr char ProfileDataSection[] = "$sz_profiler$";
   lowerGlobals(ProfileDataSection);
+  ProfileBlockInfoVarDecl = nullptr;
 }
 
 void GlobalContext::emitItems() {
@@ -649,6 +661,12 @@
 
 GlobalContext::~GlobalContext() {
   llvm::DeleteContainerPointers(AllThreadContexts);
+  LockedPtr<DestructorArray> Dtors = getDestructors();
+  // Destructors are invoked in the opposite object construction order.
+  for (auto DtorIter = Dtors->crbegin(); DtorIter != Dtors->crend();
+       ++DtorIter) {
+    (*DtorIter)();
+  }
 }
 
 // TODO(stichnot): Consider adding thread-local caches of constant
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index 7adde9f..8854f69 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -16,8 +16,11 @@
 #define SUBZERO_SRC_ICEGLOBALCONTEXT_H
 
 #include <array>
+#include <functional>
 #include <mutex>
 #include <thread>
+#include <type_traits>
+#include <vector>
 
 #include "IceDefs.h"
 #include "IceClFlags.h"
@@ -211,8 +214,24 @@
     return getFlags().getDisableIRGeneration();
   }
 
-  // Allocate data of type T using the global allocator.
-  template <typename T> T *allocate() { return getAllocator()->Allocate<T>(); }
+  // Allocate data of type T using the global allocator. We allow entities
+  // allocated from this global allocator to be either trivially or
+  // non-trivially destructible. We optimize the case when T is trivially
+  // destructible by not registering a destructor. Destructors will be invoked
+  // during GlobalContext destruction in the reverse object creation order.
+  template <typename T>
+  typename std::enable_if<std::is_trivially_destructible<T>::value, T>::type *
+  allocate() {
+    return getAllocator()->Allocate<T>();
+  }
+
+  template <typename T>
+  typename std::enable_if<!std::is_trivially_destructible<T>::value, T>::type *
+  allocate() {
+    T *Ret = getAllocator()->Allocate<T>();
+    getDestructors()->emplace_back([Ret]() { Ret->~T(); });
+    return Ret;
+  }
 
   const Intrinsics &getIntrinsicsInfo() const { return IntrinsicsInfo; }
 
@@ -392,8 +411,9 @@
   // until the queue is empty.
   void emitItems();
 
-  // Uses DataLowering to lower Globals. As a side effect, clears the Globals
-  // array.
+  // Uses DataLowering to lower Globals. Side effects:
+  //  - discards the initializer list for the global variable in Globals.
+  //  - clears the Globals array.
   void lowerGlobals(const IceString &SectionSuffix);
 
   // Lowers the profile information.
@@ -417,12 +437,19 @@
 private:
   // Try to ensure mutexes are allocated on separate cache lines.
 
+  // Destructors collaborate with Allocator
   ICE_CACHELINE_BOUNDARY;
   // Managed by getAllocator()
   GlobalLockType AllocLock;
   ArenaAllocator<> Allocator;
 
   ICE_CACHELINE_BOUNDARY;
+  // Managed by getDestructors()
+  typedef std::vector<std::function<void()>> DestructorArray;
+  GlobalLockType DestructorsLock;
+  DestructorArray Destructors;
+
+  ICE_CACHELINE_BOUNDARY;
   // Managed by getConstantPool()
   GlobalLockType ConstPoolLock;
   std::unique_ptr<ConstantPool> ConstPool;
@@ -470,7 +497,7 @@
   // TODO(jpp): move to EmitterContext.
   VariableDeclarationList Globals;
   // TODO(jpp): move to EmitterContext.
-  std::unique_ptr<VariableDeclaration> ProfileBlockInfoVarDecl;
+  VariableDeclaration *ProfileBlockInfoVarDecl;
 
   LockedPtr<ArenaAllocator<>> getAllocator() {
     return LockedPtr<ArenaAllocator<>>(&Allocator, &AllocLock);
@@ -484,6 +511,9 @@
   LockedPtr<TimerList> getTimers() {
     return LockedPtr<TimerList>(&Timers, &TimerLock);
   }
+  LockedPtr<DestructorArray> getDestructors() {
+    return LockedPtr<DestructorArray>(&Destructors, &DestructorsLock);
+  }
 
   void accumulateGlobals(std::unique_ptr<VariableDeclarationList> Globls) {
     if (Globls != nullptr)
diff --git a/src/IceGlobalInits.cpp b/src/IceGlobalInits.cpp
index c9bdf99..2ee5e62 100644
--- a/src/IceGlobalInits.cpp
+++ b/src/IceGlobalInits.cpp
@@ -60,12 +60,6 @@
 
 namespace Ice {
 
-FunctionDeclaration *FunctionDeclaration::create(
-    const FuncSigType &Signature, llvm::CallingConv::ID CallingConv,
-    llvm::GlobalValue::LinkageTypes Linkage, bool IsProto) {
-  return new FunctionDeclaration(Signature, CallingConv, Linkage, IsProto);
-}
-
 void FunctionDeclaration::dumpType(Ostream &Stream) const {
   if (!ALLOW_DUMP)
     return;
@@ -92,23 +86,15 @@
   Stream << ")";
 }
 
-VariableDeclaration *VariableDeclaration::create() {
-  return new VariableDeclaration();
-}
-
-VariableDeclaration::~VariableDeclaration() {
-  llvm::DeleteContainerPointers(Initializers);
-}
-
 void VariableDeclaration::dumpType(Ostream &Stream) const {
   if (!ALLOW_DUMP)
     return;
-  if (Initializers.size() == 1) {
-    Initializers.front()->dumpType(Stream);
+  if (Initializers->size() == 1) {
+    Initializers->front()->dumpType(Stream);
   } else {
     Stream << "<{ ";
     bool IsFirst = true;
-    for (Initializer *Init : Initializers) {
+    for (const std::unique_ptr<Initializer> &Init : *Initializers) {
       if (IsFirst) {
         IsFirst = false;
       } else {
@@ -130,13 +116,13 @@
   Stream << " " << (IsConstant ? "constant" : "global") << " ";
 
   // Add initializer.
-  if (Initializers.size() == 1) {
-    Initializers.front()->dump(Stream);
+  if (Initializers->size() == 1) {
+    Initializers->front()->dump(Stream);
   } else {
     dumpType(Stream);
     Stream << " <{ ";
     bool IsFirst = true;
-    for (Initializer *Init : Initializers) {
+    for (const std::unique_ptr<Initializer> &Init : *Initializers) {
       if (IsFirst) {
         IsFirst = false;
       } else {
diff --git a/src/IceGlobalInits.h b/src/IceGlobalInits.h
index 824f704..cd66500 100644
--- a/src/IceGlobalInits.h
+++ b/src/IceGlobalInits.h
@@ -17,8 +17,12 @@
 #ifndef SUBZERO_SRC_ICEGLOBALINITS_H
 #define SUBZERO_SRC_ICEGLOBALINITS_H
 
+#include <memory>
+#include <utility>
+
+#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" // for NaClBitcodeRecord.
 #include "llvm/IR/CallingConv.h"
-#include "llvm/IR/GlobalValue.h" // for GlobalValue::LinkageTypes
+#include "llvm/IR/GlobalValue.h" // for GlobalValue::LinkageTypes.
 
 #include "IceDefs.h"
 #include "IceTypes.h"
@@ -95,11 +99,14 @@
   FunctionDeclaration &operator=(const FunctionDeclaration &) = delete;
 
 public:
-  static FunctionDeclaration *create(const FuncSigType &Signature,
+  static FunctionDeclaration *create(GlobalContext *Context,
+                                     const FuncSigType &Signature,
                                      llvm::CallingConv::ID CallingConv,
                                      llvm::GlobalValue::LinkageTypes Linkage,
-                                     bool IsProto);
-  ~FunctionDeclaration() final {}
+                                     bool IsProto) {
+    return new (Context->allocate<FunctionDeclaration>())
+        FunctionDeclaration(Signature, CallingConv, Linkage, IsProto);
+  }
   const FuncSigType &getSignature() const { return Signature; }
   llvm::CallingConv::ID getCallingConv() const { return CallingConv; }
   // isProto implies that there isn't a (local) definition for the function.
@@ -167,21 +174,11 @@
     DataInitializer &operator=(const DataInitializer &) = delete;
 
   public:
-    template <class IntContainer>
-    DataInitializer(const IntContainer &Values)
-        : Initializer(DataInitializerKind), Contents(Values.size()) {
-      size_t i = 0;
-      for (auto &V : Values) {
-        Contents[i] = static_cast<int8_t>(V);
-        ++i;
-      }
+    template <class... Args>
+    static std::unique_ptr<DataInitializer> create(Args &&... TheArgs) {
+      return makeUnique<DataInitializer>(std::forward<Args>(TheArgs)...);
     }
-    DataInitializer(const char *Str, size_t StrLen)
-        : Initializer(DataInitializerKind), Contents(StrLen) {
-      for (size_t i = 0; i < StrLen; ++i)
-        Contents[i] = Str[i];
-    }
-    ~DataInitializer() override {}
+
     const DataVecType &getContents() const { return Contents; }
     SizeT getNumBytes() const final { return Contents.size(); }
     void dump(GlobalContext *Ctx, Ostream &Stream) const final;
@@ -190,6 +187,20 @@
     }
 
   private:
+    ENABLE_MAKE_UNIQUE;
+
+    DataInitializer(const llvm::NaClBitcodeRecord::RecordVector &Values)
+        : Initializer(DataInitializerKind), Contents(Values.size()) {
+      for (SizeT I = 0; I < Values.size(); ++I)
+        Contents[I] = static_cast<int8_t>(Values[I]);
+    }
+
+    DataInitializer(const char *Str, size_t StrLen)
+        : Initializer(DataInitializerKind), Contents(StrLen) {
+      for (size_t i = 0; i < StrLen; ++i)
+        Contents[i] = Str[i];
+    }
+
     // The byte contents of the data initializer.
     DataVecType Contents;
   };
@@ -200,9 +211,9 @@
     ZeroInitializer &operator=(const ZeroInitializer &) = delete;
 
   public:
-    explicit ZeroInitializer(SizeT Size)
-        : Initializer(ZeroInitializerKind), Size(Size) {}
-    ~ZeroInitializer() override {}
+    static std::unique_ptr<ZeroInitializer> create(SizeT Size) {
+      return makeUnique<ZeroInitializer>(Size);
+    }
     SizeT getNumBytes() const final { return Size; }
     void dump(GlobalContext *Ctx, Ostream &Stream) const final;
     static bool classof(const Initializer *Z) {
@@ -210,6 +221,11 @@
     }
 
   private:
+    ENABLE_MAKE_UNIQUE;
+
+    explicit ZeroInitializer(SizeT Size)
+        : Initializer(ZeroInitializerKind), Size(Size) {}
+
     // The number of bytes to be zero initialized.
     SizeT Size;
   };
@@ -220,10 +236,11 @@
     RelocInitializer &operator=(const RelocInitializer &) = delete;
 
   public:
-    RelocInitializer(const GlobalDeclaration *Declaration, RelocOffsetT Offset)
-        : Initializer(RelocInitializerKind), Declaration(Declaration),
-          Offset(Offset) {}
-    ~RelocInitializer() override {}
+    static std::unique_ptr<RelocInitializer>
+    create(const GlobalDeclaration *Declaration, RelocOffsetT Offset) {
+      return makeUnique<RelocInitializer>(Declaration, Offset);
+    }
+
     RelocOffsetT getOffset() const { return Offset; }
     const GlobalDeclaration *getDeclaration() const { return Declaration; }
     SizeT getNumBytes() const final { return RelocAddrSize; }
@@ -234,34 +251,40 @@
     }
 
   private:
-    // The global declaration used in the relocation.
+    ENABLE_MAKE_UNIQUE;
+
+    RelocInitializer(const GlobalDeclaration *Declaration, RelocOffsetT Offset)
+        : Initializer(RelocInitializerKind), Declaration(Declaration),
+          Offset(Offset) {} // The global declaration used in the relocation.
+
     const GlobalDeclaration *Declaration;
     // The offset to add to the relocation.
     const RelocOffsetT Offset;
   };
 
   /// Models the list of initializers.
-  typedef std::vector<Initializer *> InitializerListType;
+  typedef std::vector<std::unique_ptr<Initializer>> InitializerListType;
 
-  static VariableDeclaration *create();
-  ~VariableDeclaration() final;
+  static VariableDeclaration *create(GlobalContext *Context) {
+    return new (Context->allocate<VariableDeclaration>()) VariableDeclaration();
+  }
 
-  const InitializerListType &getInitializers() const { return Initializers; }
+  const InitializerListType &getInitializers() const { return *Initializers; }
   bool getIsConstant() const { return IsConstant; }
   void setIsConstant(bool NewValue) { IsConstant = NewValue; }
   uint32_t getAlignment() const { return Alignment; }
   void setAlignment(uint32_t NewAlignment) { Alignment = NewAlignment; }
-  bool hasInitializer() const { return !Initializers.empty(); }
+  bool hasInitializer() const { return HasInitializer; }
   bool hasNonzeroInitializer() const {
-    return !(Initializers.size() == 1 &&
-             llvm::isa<ZeroInitializer>(Initializers[0]));
+    return !(Initializers->size() == 1 &&
+             llvm::isa<ZeroInitializer>((*Initializers)[0].get()));
   }
 
   /// Returns the number of bytes for the initializer of the global
   /// address.
   SizeT getNumBytes() const {
     SizeT Count = 0;
-    for (Initializer *Init : Initializers) {
+    for (const std::unique_ptr<Initializer> &Init : *Initializers) {
       Count += Init->getNumBytes();
     }
     return Count;
@@ -269,8 +292,9 @@
 
   /// Adds Initializer to the list of initializers. Takes ownership of
   /// the initializer.
-  void addInitializer(Initializer *Initializer) {
-    Initializers.push_back(Initializer);
+  void addInitializer(std::unique_ptr<Initializer> Initializer) {
+    Initializers->emplace_back(std::move(Initializer));
+    HasInitializer = true;
   }
 
   /// Prints out type for initializer associated with the declaration
@@ -293,9 +317,12 @@
 
   void setSuppressMangling() { ForceSuppressMangling = true; }
 
+  void discardInitializers() { Initializers = nullptr; }
+
 private:
   // list of initializers for the declared variable.
-  InitializerListType Initializers;
+  std::unique_ptr<InitializerListType> Initializers;
+  bool HasInitializer;
   // The alignment of the declared variable.
   uint32_t Alignment;
   // True if a declared (global) constant.
@@ -306,6 +333,7 @@
   VariableDeclaration()
       : GlobalDeclaration(VariableDeclarationKind,
                           llvm::GlobalValue::InternalLinkage),
+        Initializers(new InitializerListType), HasInitializer(false),
         Alignment(0), IsConstant(false), ForceSuppressMangling(false) {}
 };
 
diff --git a/src/IceInst.h b/src/IceInst.h
index 84bd83d..2b5adc6 100644
--- a/src/IceInst.h
+++ b/src/IceInst.h
@@ -161,6 +161,9 @@
   void dumpDest(const Cfg *Func) const;
   virtual bool isRedundantAssign() const { return false; }
 
+  // TODO(jpp): Insts should not have non-trivial destructors, but they
+  // currently do. This dtor is marked final as a multi-step refactor that
+  // will eventually fix this problem.
   virtual ~Inst() = default;
 
 protected:
@@ -229,7 +232,6 @@
   void emitIAS(const Cfg * /*Func*/) const override {
     llvm_unreachable("emitIAS() called on a non-lowered instruction");
   }
-  ~InstHighLevel() override {}
 };
 
 // Alloca instruction.  This captures the size in bytes as getSrc(0),
@@ -254,7 +256,7 @@
 private:
   InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes,
              Variable *Dest);
-  ~InstAlloca() override {}
+
   const uint32_t AlignInBytes;
 };
 
@@ -289,7 +291,6 @@
 private:
   InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, Operand *Source1,
                  Operand *Source2);
-  ~InstArithmetic() override {}
 
   const OpKind Op;
 };
@@ -315,7 +316,6 @@
 
 private:
   InstAssign(Cfg *Func, Variable *Dest, Operand *Source);
-  ~InstAssign() override {}
 };
 
 // Branch instruction.  This represents both conditional and
@@ -359,7 +359,6 @@
   InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, CfgNode *TargetFalse);
   // Unconditional branch
   InstBr(Cfg *Func, CfgNode *Target);
-  ~InstBr() override {}
 
   CfgNode *TargetFalse; // Doubles as unconditional branch target
   CfgNode *TargetTrue;  // nullptr if unconditional branch
@@ -399,7 +398,6 @@
     HasSideEffects = HasSideEff;
     addSource(CallTarget);
   }
-  ~InstCall() override {}
 
 private:
   bool HasTailCall;
@@ -432,7 +430,7 @@
 
 private:
   InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source);
-  ~InstCast() override {}
+
   const OpKind CastKind;
 };
 
@@ -457,7 +455,6 @@
 private:
   InstExtractElement(Cfg *Func, Variable *Dest, Operand *Source1,
                      Operand *Source2);
-  ~InstExtractElement() override {}
 };
 
 // Floating-point comparison instruction.  The source operands are
@@ -487,7 +484,7 @@
 private:
   InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1,
            Operand *Source2);
-  ~InstFcmp() override {}
+
   const FCond Condition;
 };
 
@@ -518,7 +515,7 @@
 private:
   InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1,
            Operand *Source2);
-  ~InstIcmp() override {}
+
   const ICond Condition;
 };
 
@@ -543,7 +540,6 @@
 private:
   InstInsertElement(Cfg *Func, Variable *Dest, Operand *Source1,
                     Operand *Source2, Operand *Source3);
-  ~InstInsertElement() override {}
 };
 
 // Call to an intrinsic function.  The call target is captured as getSrc(0),
@@ -572,7 +568,7 @@
       : InstCall(Func, NumArgs, Dest, CallTarget, false, Info.HasSideEffects,
                  Inst::IntrinsicCall),
         Info(Info) {}
-  ~InstIntrinsicCall() override {}
+
   const Intrinsics::IntrinsicInfo Info;
 };
 
@@ -595,7 +591,6 @@
 
 private:
   InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr);
-  ~InstLoad() override {}
 };
 
 // Phi instruction.  For incoming edge I, the node is Labels[I] and
@@ -624,7 +619,6 @@
     Func->deallocateArrayOf<CfgNode *>(Labels);
     Inst::destroy(Func);
   }
-  ~InstPhi() override {}
 
   // Labels[] duplicates the InEdges[] information in the enclosing
   // CfgNode, but the Phi instruction is created before InEdges[]
@@ -655,7 +649,6 @@
 
 private:
   InstRet(Cfg *Func, Operand *RetValue);
-  ~InstRet() override {}
 };
 
 // Select instruction.  The condition, true, and false operands are captured.
@@ -679,7 +672,6 @@
 private:
   InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, Operand *Source1,
              Operand *Source2);
-  ~InstSelect() override {}
 };
 
 // Store instruction.  The address operand is captured, along with the
@@ -705,7 +697,6 @@
 
 private:
   InstStore(Cfg *Func, Operand *Data, Operand *Addr);
-  ~InstStore() override {}
 };
 
 // Switch instruction.  The single source operand is captured as
@@ -745,7 +736,6 @@
     Func->deallocateArrayOf<CfgNode *>(Labels);
     Inst::destroy(Func);
   }
-  ~InstSwitch() override {}
 
   CfgNode *LabelDefault;
   SizeT NumCases;   // not including the default case
@@ -772,7 +762,6 @@
 
 private:
   explicit InstUnreachable(Cfg *Func);
-  ~InstUnreachable() override {}
 };
 
 // BundleLock instruction.  There are no operands.  Contains an option
@@ -799,7 +788,6 @@
 private:
   Option BundleOption;
   InstBundleLock(Cfg *Func, Option BundleOption);
-  ~InstBundleLock() override {}
 };
 
 // BundleUnlock instruction.  There are no operands.
@@ -821,7 +809,6 @@
 
 private:
   explicit InstBundleUnlock(Cfg *Func);
-  ~InstBundleUnlock() override {}
 };
 
 // FakeDef instruction.  This creates a fake definition of a variable,
@@ -853,7 +840,6 @@
 
 private:
   InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src);
-  ~InstFakeDef() override {}
 };
 
 // FakeUse instruction.  This creates a fake use of a variable, to
@@ -877,7 +863,6 @@
 
 private:
   InstFakeUse(Cfg *Func, Variable *Src);
-  ~InstFakeUse() override {}
 };
 
 // FakeKill instruction.  This "kills" a set of variables by modeling
@@ -907,7 +892,6 @@
 
 private:
   InstFakeKill(Cfg *Func, const Inst *Linked);
-  ~InstFakeKill() override {}
 
   // This instruction is ignored if Linked->isDeleted() is true.
   const Inst *Linked;
@@ -930,7 +914,6 @@
       : Inst(Func, Kind, MaxSrcs, Dest) {
     assert(Kind >= Target);
   }
-  ~InstTarget() override {}
 };
 
 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source);
diff --git a/src/IceInstARM32.h b/src/IceInstARM32.h
index b9ed01e..2ec1356 100644
--- a/src/IceInstARM32.h
+++ b/src/IceInstARM32.h
@@ -59,7 +59,6 @@
 protected:
   OperandARM32(OperandKindARM32 Kind, Type Ty)
       : Operand(static_cast<OperandKind>(Kind), Ty) {}
-  ~OperandARM32() override {}
 };
 
 // OperandARM32Mem represents a memory operand in any of the various ARM32
@@ -141,7 +140,7 @@
                   ConstantInteger32 *ImmOffset, AddrMode Mode);
   OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, Variable *Index,
                   ShiftKind ShiftOp, uint16_t ShiftAmt, AddrMode Mode);
-  ~OperandARM32Mem() override {}
+
   Variable *Base;
   ConstantInteger32 *ImmOffset;
   Variable *Index;
@@ -167,7 +166,6 @@
 
 protected:
   OperandARM32Flex(OperandKindARM32 Kind, Type Ty) : OperandARM32(Kind, Ty) {}
-  ~OperandARM32Flex() override {}
 };
 
 // Rotated immediate variant.
@@ -202,7 +200,6 @@
 
 private:
   OperandARM32FlexImm(Cfg *Func, Type Ty, uint32_t Imm, uint32_t RotateAmt);
-  ~OperandARM32FlexImm() override {}
 
   uint32_t Imm;
   uint32_t RotateAmt;
@@ -238,7 +235,6 @@
 private:
   OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, ShiftKind ShiftOp,
                       Operand *ShiftAmt);
-  ~OperandARM32FlexReg() override {}
 
   Variable *Reg;
   ShiftKind ShiftOp;
@@ -296,7 +292,7 @@
 protected:
   InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest)
       : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {}
-  ~InstARM32() override {}
+
   static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) {
     return Inst->getKind() == static_cast<InstKind>(MyKind);
   }
@@ -377,7 +373,7 @@
       : InstARM32Pred(Func, K, 1, Dest, Predicate) {
     addSource(Src);
   }
-  ~InstARM32UnaryopGPR() override {}
+
   static const char *Opcode;
 };
 
@@ -423,7 +419,7 @@
     addSource(Dest);
     addSource(Src);
   }
-  ~InstARM32TwoAddrGPR() override {}
+
   static const char *Opcode;
 };
 
@@ -465,7 +461,6 @@
       : InstARM32Pred(Func, K, 1, Dest, Predicate) {
     addSource(Source);
   }
-  ~InstARM32Movlike() override {}
 
   static const char *Opcode;
 };
@@ -516,7 +511,7 @@
     addSource(Src1);
     addSource(Src2);
   }
-  ~InstARM32ThreeAddrGPR() override {}
+
   static const char *Opcode;
   bool SetFlags;
 };
@@ -602,7 +597,7 @@
 private:
   InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
               CondARM32::Cond Predicate);
-  ~InstARM32Br() override {}
+
   const CfgNode *TargetTrue;
   const CfgNode *TargetFalse;
 };
@@ -656,7 +651,6 @@
 
 private:
   InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget);
-  ~InstARM32Call() override {}
 };
 
 // Integer compare instruction.
@@ -679,7 +673,6 @@
 private:
   InstARM32Cmp(Cfg *Func, Variable *Src1, Operand *Src2,
                CondARM32::Cond Predicate);
-  ~InstARM32Cmp() override {}
 };
 
 // Load instruction.
@@ -703,7 +696,6 @@
 private:
   InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem,
                CondARM32::Cond Predicate);
-  ~InstARM32Ldr() override {}
 };
 
 // Multiply Accumulate: d := x * y + a
@@ -728,7 +720,6 @@
 private:
   InstARM32Mla(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1,
                Variable *Acc, CondARM32::Cond Predicate);
-  ~InstARM32Mla() override {}
 };
 
 // Pop into a list of GPRs. Technically this can be predicated, but we don't
@@ -749,7 +740,7 @@
 
 private:
   InstARM32Pop(Cfg *Func, const VarList &Dests);
-  ~InstARM32Pop() override {}
+
   VarList Dests;
 };
 
@@ -771,7 +762,6 @@
 
 private:
   InstARM32Push(Cfg *Func, const VarList &Srcs);
-  ~InstARM32Push() override {}
 };
 
 // Ret pseudo-instruction.  This is actually a "bx" instruction with
@@ -800,7 +790,6 @@
 
 private:
   InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source);
-  ~InstARM32Ret() override {}
 };
 
 // Store instruction. It's important for liveness that there is no Dest
@@ -825,7 +814,6 @@
 private:
   InstARM32Str(Cfg *Func, Variable *Value, OperandARM32Mem *Mem,
                CondARM32::Cond Predicate);
-  ~InstARM32Str() override {}
 };
 
 // Unsigned Multiply Long: d.lo, d.hi := x * y
@@ -850,7 +838,7 @@
 private:
   InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, Variable *Src0,
                  Variable *Src1, CondARM32::Cond Predicate);
-  ~InstARM32Umull() override {}
+
   Variable *DestHi;
 };
 
diff --git a/src/IceInstX8632.h b/src/IceInstX8632.h
index ec8c39d..d64952b 100644
--- a/src/IceInstX8632.h
+++ b/src/IceInstX8632.h
@@ -45,7 +45,6 @@
 protected:
   OperandX8632(OperandKindX8632 Kind, Type Ty)
       : Operand(static_cast<OperandKind>(Kind), Ty) {}
-  ~OperandX8632() override {}
 };
 
 // OperandX8632Mem represents the m32 addressing mode, with optional
@@ -93,7 +92,7 @@
 private:
   OperandX8632Mem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
                   Variable *Index, uint16_t Shift, SegmentRegisters SegmentReg);
-  ~OperandX8632Mem() override {}
+
   Variable *Base;
   Constant *Offset;
   Variable *Index;
@@ -134,14 +133,13 @@
 
 private:
   VariableSplit(Cfg *Func, Variable *Var, Portion Part)
-      : OperandX8632(kSplit, IceType_i32), Func(Func), Var(Var), Part(Part) {
+      : OperandX8632(kSplit, IceType_i32), Var(Var), Part(Part) {
     assert(Var->getType() == IceType_f64);
     Vars = Func->allocateArrayOf<Variable *>(1);
     Vars[0] = Var;
     NumVars = 1;
   }
-  ~VariableSplit() override { Func->deallocateArrayOf<Variable *>(Vars); }
-  Cfg *Func; // Held only for the destructor.
+
   Variable *Var;
   Portion Part;
 };
@@ -298,7 +296,7 @@
 protected:
   InstX8632(Cfg *Func, InstKindX8632 Kind, SizeT Maxsrcs, Variable *Dest)
       : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {}
-  ~InstX8632() override {}
+
   static bool isClassof(const Inst *Inst, InstKindX8632 MyKind) {
     return Inst->getKind() == static_cast<InstKind>(MyKind);
   }
@@ -359,7 +357,6 @@
   InstArithmetic::OpKind Op;
   InstX8632FakeRMW(Cfg *Func, Operand *Data, Operand *Addr,
                    InstArithmetic::OpKind Op, Variable *Beacon);
-  ~InstX8632FakeRMW() override {}
 };
 
 // InstX8632Label represents an intra-block label that is the target
@@ -418,7 +415,7 @@
 
 private:
   InstX8632Label(Cfg *Func, TargetX8632 *Target);
-  ~InstX8632Label() override {}
+
   SizeT Number; // used for unique label generation.
 };
 
@@ -489,7 +486,7 @@
 private:
   InstX8632Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
               const InstX8632Label *Label, CondX86::BrCond Condition);
-  ~InstX8632Br() override {}
+
   CondX86::BrCond Condition;
   const CfgNode *TargetTrue;
   const CfgNode *TargetFalse;
@@ -559,7 +556,6 @@
 
 private:
   InstX8632Call(Cfg *Func, Variable *Dest, Operand *CallTarget);
-  ~InstX8632Call() override {}
 };
 
 // Emit a one-operand (GPR) instruction.
@@ -610,7 +606,7 @@
       : InstX8632(Func, K, 1, llvm::dyn_cast<Variable>(SrcDest)) {
     addSource(SrcDest);
   }
-  ~InstX8632InplaceopGPR() override {}
+
   static const char *Opcode;
   static const X8632::AssemblerX8632::GPREmitterOneOp Emitter;
 };
@@ -674,7 +670,7 @@
       : InstX8632(Func, K, 1, Dest) {
     addSource(Src);
   }
-  ~InstX8632UnaryopGPR() override {}
+
   static const char *Opcode;
   static const X8632::AssemblerX8632::GPREmitterRegOp Emitter;
 };
@@ -724,7 +720,7 @@
       : InstX8632(Func, K, 1, Dest) {
     addSource(Src);
   }
-  ~InstX8632UnaryopXmm() override {}
+
   static const char *Opcode;
   static const X8632::AssemblerX8632::XmmEmitterRegOp Emitter;
 };
@@ -769,7 +765,7 @@
     addSource(Dest);
     addSource(Source);
   }
-  ~InstX8632BinopGPRShift() override {}
+
   static const char *Opcode;
   static const X8632::AssemblerX8632::GPREmitterShiftOp Emitter;
 };
@@ -813,7 +809,7 @@
     addSource(Dest);
     addSource(Source);
   }
-  ~InstX8632BinopGPR() override {}
+
   static const char *Opcode;
   static const X8632::AssemblerX8632::GPREmitterRegOp Emitter;
 };
@@ -857,7 +853,6 @@
     addSource(DestSrc0);
     addSource(Src1);
   }
-  ~InstX8632BinopRMW() override {}
   static const char *Opcode;
   static const X8632::AssemblerX8632::GPREmitterAddrOp Emitter;
 };
@@ -905,7 +900,7 @@
     addSource(Dest);
     addSource(Source);
   }
-  ~InstX8632BinopXmm() override {}
+
   static const char *Opcode;
   static const X8632::AssemblerX8632::XmmEmitterRegOp Emitter;
 };
@@ -958,7 +953,7 @@
     addSource(Dest);
     addSource(Source);
   }
-  ~InstX8632BinopXmmShift() override {}
+
   static const char *Opcode;
   static const X8632::AssemblerX8632::XmmEmitterShiftOp Emitter;
 };
@@ -1005,7 +1000,7 @@
     addSource(Source1);
     addSource(Source2);
   }
-  ~InstX8632Ternop() override {}
+
   static const char *Opcode;
 };
 
@@ -1052,7 +1047,7 @@
     addSource(Source0);
     addSource(Source1);
   }
-  ~InstX8632ThreeAddressop() override {}
+
   static const char *Opcode;
 };
 
@@ -1090,7 +1085,6 @@
       : InstX8632(Func, K, 1, Dest) {
     addSource(Source);
   }
-  ~InstX8632Movlike() override {}
 
   static const char *Opcode;
 };
@@ -1187,7 +1181,6 @@
     // with optimizations.
     HasSideEffects = Locked;
   }
-  ~InstX8632Lockable() override {}
 };
 
 // Mul instruction - unsigned multiply.
@@ -1209,7 +1202,6 @@
 
 private:
   InstX8632Mul(Cfg *Func, Variable *Dest, Variable *Source1, Operand *Source2);
-  ~InstX8632Mul() override {}
 };
 
 // Shld instruction - shift across a pair of operands.
@@ -1232,7 +1224,6 @@
 private:
   InstX8632Shld(Cfg *Func, Variable *Dest, Variable *Source1,
                 Variable *Source2);
-  ~InstX8632Shld() override {}
 };
 
 // Shrd instruction - shift across a pair of operands.
@@ -1255,7 +1246,6 @@
 private:
   InstX8632Shrd(Cfg *Func, Variable *Dest, Variable *Source1,
                 Variable *Source2);
-  ~InstX8632Shrd() override {}
 };
 
 // Conditional move instruction.
@@ -1278,7 +1268,6 @@
 private:
   InstX8632Cmov(Cfg *Func, Variable *Dest, Operand *Source,
                 CondX86::BrCond Cond);
-  ~InstX8632Cmov() override {}
 
   CondX86::BrCond Condition;
 };
@@ -1304,7 +1293,6 @@
 private:
   InstX8632Cmpps(Cfg *Func, Variable *Dest, Operand *Source,
                  CondX86::CmppsCond Cond);
-  ~InstX8632Cmpps() override {}
 
   CondX86::CmppsCond Condition;
 };
@@ -1333,7 +1321,6 @@
 private:
   InstX8632Cmpxchg(Cfg *Func, Operand *DestOrAddr, Variable *Eax,
                    Variable *Desired, bool Locked);
-  ~InstX8632Cmpxchg() override {}
 };
 
 // Cmpxchg8b instruction - cmpxchg8b <m64> will compare if <m64>
@@ -1362,7 +1349,6 @@
 private:
   InstX8632Cmpxchg8b(Cfg *Func, OperandX8632Mem *Dest, Variable *Edx,
                      Variable *Eax, Variable *Ecx, Variable *Ebx, bool Locked);
-  ~InstX8632Cmpxchg8b() override {}
 };
 
 // Cvt instruction - wrapper for cvtsX2sY where X and Y are in {s,d,i}
@@ -1390,7 +1376,6 @@
 private:
   CvtVariant Variant;
   InstX8632Cvt(Cfg *Func, Variable *Dest, Operand *Source, CvtVariant Variant);
-  ~InstX8632Cvt() override {}
 };
 
 // cmp - Integer compare instruction.
@@ -1411,7 +1396,6 @@
 
 private:
   InstX8632Icmp(Cfg *Func, Operand *Src1, Operand *Src2);
-  ~InstX8632Icmp() override {}
 };
 
 // ucomiss/ucomisd - floating-point compare instruction.
@@ -1432,7 +1416,6 @@
 
 private:
   InstX8632Ucomiss(Cfg *Func, Operand *Src1, Operand *Src2);
-  ~InstX8632Ucomiss() override {}
 };
 
 // UD2 instruction.
@@ -1452,7 +1435,6 @@
 
 private:
   explicit InstX8632UD2(Cfg *Func);
-  ~InstX8632UD2() override {}
 };
 
 // Test instruction.
@@ -1473,7 +1455,6 @@
 
 private:
   InstX8632Test(Cfg *Func, Operand *Source1, Operand *Source2);
-  ~InstX8632Test() override {}
 };
 
 // Mfence instruction.
@@ -1493,7 +1474,6 @@
 
 private:
   explicit InstX8632Mfence(Cfg *Func);
-  ~InstX8632Mfence() override {}
 };
 
 // This is essentially a "mov" instruction with an OperandX8632Mem
@@ -1516,7 +1496,6 @@
 
 private:
   InstX8632Store(Cfg *Func, Operand *Value, OperandX8632 *Mem);
-  ~InstX8632Store() override {}
 };
 
 // This is essentially a vector "mov" instruction with an OperandX8632Mem
@@ -1541,7 +1520,6 @@
 
 private:
   InstX8632StoreP(Cfg *Func, Variable *Value, OperandX8632Mem *Mem);
-  ~InstX8632StoreP() override {}
 };
 
 class InstX8632StoreQ : public InstX8632 {
@@ -1562,7 +1540,6 @@
 
 private:
   InstX8632StoreQ(Cfg *Func, Variable *Value, OperandX8632Mem *Mem);
-  ~InstX8632StoreQ() override {}
 };
 
 // Nop instructions of varying length
@@ -1585,7 +1562,6 @@
 
 private:
   InstX8632Nop(Cfg *Func, SizeT Length);
-  ~InstX8632Nop() override {}
 
   NopVariant Variant;
 };
@@ -1607,7 +1583,6 @@
 
 private:
   InstX8632Fld(Cfg *Func, Operand *Src);
-  ~InstX8632Fld() override {}
 };
 
 // Fstp - store x87 st(0) into memory and pop st(0).
@@ -1627,7 +1602,6 @@
 
 private:
   InstX8632Fstp(Cfg *Func, Variable *Dest);
-  ~InstX8632Fstp() override {}
 };
 
 class InstX8632Pop : public InstX8632 {
@@ -1646,7 +1620,6 @@
 
 private:
   InstX8632Pop(Cfg *Func, Variable *Dest);
-  ~InstX8632Pop() override {}
 };
 
 class InstX8632Push : public InstX8632 {
@@ -1665,7 +1638,6 @@
 
 private:
   InstX8632Push(Cfg *Func, Variable *Source);
-  ~InstX8632Push() override {}
 };
 
 // Ret instruction.  Currently only supports the "ret" version that
@@ -1688,7 +1660,6 @@
 
 private:
   InstX8632Ret(Cfg *Func, Variable *Source);
-  ~InstX8632Ret() override {}
 };
 
 // Conditional set-byte instruction.
@@ -1710,7 +1681,6 @@
 
 private:
   InstX8632Setcc(Cfg *Func, Variable *Dest, CondX86::BrCond Cond);
-  ~InstX8632Setcc() override {}
 
   const CondX86::BrCond Condition;
 };
@@ -1740,7 +1710,6 @@
 
 private:
   InstX8632Xadd(Cfg *Func, Operand *Dest, Variable *Source, bool Locked);
-  ~InstX8632Xadd() override {}
 };
 
 // Exchange instruction.  Exchanges the first operand (destination
@@ -1766,7 +1735,6 @@
 
 private:
   InstX8632Xchg(Cfg *Func, Operand *Dest, Variable *Source);
-  ~InstX8632Xchg() override {}
 };
 
 // Declare partial template specializations of emit() methods that
diff --git a/src/IceOperand.h b/src/IceOperand.h
index 9e0ff7d..35342fa 100644
--- a/src/IceOperand.h
+++ b/src/IceOperand.h
@@ -79,8 +79,6 @@
       dump(nullptr, Str);
   }
 
-  virtual ~Operand() = default;
-
 protected:
   Operand(OperandKind Kind, Type Ty) : Ty(Ty), Kind(Kind) {}
 
@@ -134,7 +132,6 @@
     Vars = nullptr;
     NumVars = 0;
   }
-  ~Constant() override {}
   // PoolEntryID is an integer that uniquely identifies the constant
   // within its constant pool.  It is used for building the constant
   // pool in the object code and for referencing its entries.
@@ -182,7 +179,6 @@
 private:
   ConstantPrimitive(Type Ty, PrimType Value, uint32_t PoolEntryID)
       : Constant(K, Ty, PoolEntryID), Value(Value) {}
-  ~ConstantPrimitive() override {}
   const PrimType Value;
 };
 
@@ -271,7 +267,6 @@
                       bool SuppressMangling, uint32_t PoolEntryID)
       : Constant(kConstRelocatable, Ty, PoolEntryID), Offset(Offset),
         Name(Name), SuppressMangling(SuppressMangling) {}
-  ~ConstantRelocatable() override {}
   const RelocOffsetT Offset; // fixed offset to add
   const IceString Name;      // optional for debug/dump
   bool SuppressMangling;
@@ -308,7 +303,6 @@
 private:
   ConstantUndef(Type Ty, uint32_t PoolEntryID)
       : Constant(kConstUndef, Ty, PoolEntryID) {}
-  ~ConstantUndef() override {}
 };
 
 // RegWeight is a wrapper for a uint32_t weight value, with a
@@ -514,7 +508,6 @@
     Vars[0] = this;
     NumVars = 1;
   }
-  ~Variable() override {}
   // Number is unique across all variables, and is used as a
   // (bit)vector index for liveness analysis.
   const SizeT Number;
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 35ab024..62c459b 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -512,12 +512,12 @@
   Str << MangledName << ":\n";
 
   if (HasNonzeroInitializer) {
-    for (VariableDeclaration::Initializer *Init : Var.getInitializers()) {
+    for (const std::unique_ptr<VariableDeclaration::Initializer> &Init :
+         Var.getInitializers()) {
       switch (Init->getKind()) {
       case VariableDeclaration::Initializer::DataInitializerKind: {
-        const auto &Data =
-            llvm::cast<VariableDeclaration::DataInitializer>(Init)
-                ->getContents();
+        const auto &Data = llvm::cast<VariableDeclaration::DataInitializer>(
+                               Init.get())->getContents();
         for (SizeT i = 0; i < Init->getNumBytes(); ++i) {
           Str << "\t.byte\t" << (((unsigned)Data[i]) & 0xff) << "\n";
         }
@@ -528,7 +528,7 @@
         break;
       case VariableDeclaration::Initializer::RelocInitializerKind: {
         const auto *Reloc =
-            llvm::cast<VariableDeclaration::RelocInitializer>(Init);
+            llvm::cast<VariableDeclaration::RelocInitializer>(Init.get());
         Str << "\t" << getEmit32Directive() << "\t";
         Str << Reloc->getDeclaration()->mangleName(Ctx);
         if (RelocOffsetT Offset = Reloc->getOffset()) {
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index afe3ebc..11a1f27 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -293,7 +293,8 @@
     assert(VariableDeclarations);
     assert(VariableDeclarations->empty());
     for (size_t i = 0; i < Count; ++i) {
-      VariableDeclarations->push_back(Ice::VariableDeclaration::create());
+      VariableDeclarations->push_back(
+          Ice::VariableDeclaration::create(getTranslator().getContext()));
     }
   }
 
@@ -904,7 +905,8 @@
   GlobalsParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser)
       : BlockParserBaseClass(BlockID, EnclosingParser),
         Timer(Ice::TimerStack::TT_parseGlobals, getTranslator().getContext()),
-        DummyGlobalVar(Ice::VariableDeclaration::create()),
+        DummyGlobalVar(
+            Ice::VariableDeclaration::create(getTranslator().getContext())),
         CurGlobalVar(DummyGlobalVar) {}
 
   ~GlobalsParser() final {}
@@ -1017,7 +1019,7 @@
     if (isIRGenerationDisabled())
       return;
     CurGlobalVar->addInitializer(
-        new Ice::VariableDeclaration::ZeroInitializer(Values[0]));
+        Ice::VariableDeclaration::ZeroInitializer::create(Values[0]));
     return;
   }
   case naclbitc::GLOBALVAR_DATA: {
@@ -1027,7 +1029,7 @@
     if (isIRGenerationDisabled())
       return;
     CurGlobalVar->addInitializer(
-        new Ice::VariableDeclaration::DataInitializer(Values));
+        Ice::VariableDeclaration::DataInitializer::create(Values));
     return;
   }
   case naclbitc::GLOBALVAR_RELOC: {
@@ -1040,8 +1042,9 @@
     Ice::SizeT Offset = 0;
     if (Values.size() == 2)
       Offset = Values[1];
-    CurGlobalVar->addInitializer(new Ice::VariableDeclaration::RelocInitializer(
-        Context->getGlobalDeclarationByID(Index), Offset));
+    CurGlobalVar->addInitializer(
+        Ice::VariableDeclaration::RelocInitializer::create(
+            Context->getGlobalDeclarationByID(Index), Offset));
     return;
   }
   default:
@@ -2945,7 +2948,8 @@
     }
     bool IsProto = Values[2] == 1;
     Ice::FunctionDeclaration *Func = Ice::FunctionDeclaration::create(
-        Signature, CallingConv, Linkage, IsProto);
+        Context->getTranslator().getContext(), Signature, CallingConv, Linkage,
+        IsProto);
     Context->setNextFunctionID(Func);
     return;
   }