ART: Introduce individual HInstruction cloning.

Introduce API for HInstruction cloning, support it for a few
instructions. add a gtest.

Test: cloner_test.cc, test-art-target, test-art-host.

Change-Id: I8b6299be5d04a26390d9ef13a20ce82ee5ae4afe
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 8599471..249aaf5 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -323,6 +323,7 @@
         "linker/method_bss_mapping_encoder_test.cc",
         "linker/output_stream_test.cc",
         "optimizing/bounds_check_elimination_test.cc",
+        "optimizing/cloner_test.cc",
         "optimizing/data_type_test.cc",
         "optimizing/dominator_test.cc",
         "optimizing/find_loops_test.cc",
diff --git a/compiler/optimizing/cloner_test.cc b/compiler/optimizing/cloner_test.cc
new file mode 100644
index 0000000..d34dd81
--- /dev/null
+++ b/compiler/optimizing/cloner_test.cc
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "graph_checker.h"
+#include "nodes.h"
+#include "optimizing_unit_test.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+// This class provides methods and helpers for testing various cloning and copying routines:
+// individual instruction cloning and cloning of the more coarse-grain structures.
+class ClonerTest : public OptimizingUnitTest {
+ public:
+  ClonerTest()
+      : graph_(CreateGraph()), entry_block_(nullptr), exit_block_(nullptr), parameter_(nullptr) {}
+
+  void CreateBasicLoopControlFlow(/* out */ HBasicBlock** header_p,
+                                  /* out */ HBasicBlock** body_p) {
+    entry_block_ = new (GetAllocator()) HBasicBlock(graph_);
+    graph_->AddBlock(entry_block_);
+    graph_->SetEntryBlock(entry_block_);
+
+    HBasicBlock* loop_preheader = new (GetAllocator()) HBasicBlock(graph_);
+    HBasicBlock* loop_header = new (GetAllocator()) HBasicBlock(graph_);
+    HBasicBlock* loop_body = new (GetAllocator()) HBasicBlock(graph_);
+    HBasicBlock* loop_exit = new (GetAllocator()) HBasicBlock(graph_);
+
+    graph_->AddBlock(loop_preheader);
+    graph_->AddBlock(loop_header);
+    graph_->AddBlock(loop_body);
+    graph_->AddBlock(loop_exit);
+
+    exit_block_ = new (GetAllocator()) HBasicBlock(graph_);
+    graph_->AddBlock(exit_block_);
+    graph_->SetExitBlock(exit_block_);
+
+    entry_block_->AddSuccessor(loop_preheader);
+    loop_preheader->AddSuccessor(loop_header);
+    // Loop exit first to have a proper exit condition/target for HIf.
+    loop_header->AddSuccessor(loop_exit);
+    loop_header->AddSuccessor(loop_body);
+    loop_body->AddSuccessor(loop_header);
+    loop_exit->AddSuccessor(exit_block_);
+
+    *header_p = loop_header;
+    *body_p = loop_body;
+
+    parameter_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
+                                                      dex::TypeIndex(0),
+                                                      0,
+                                                      DataType::Type::kInt32);
+    entry_block_->AddInstruction(parameter_);
+    loop_exit->AddInstruction(new (GetAllocator()) HReturnVoid());
+    exit_block_->AddInstruction(new (GetAllocator()) HExit());
+  }
+
+  void CreateBasicLoopDataFlow(HBasicBlock* loop_header, HBasicBlock* loop_body) {
+    uint32_t dex_pc = 0;
+
+    // Entry block.
+    HIntConstant* const_0 = graph_->GetIntConstant(0);
+    HIntConstant* const_1 = graph_->GetIntConstant(1);
+    HIntConstant* const_128 = graph_->GetIntConstant(128);
+
+    // Header block.
+    HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
+    HInstruction* suspend_check = new (GetAllocator()) HSuspendCheck();
+
+    loop_header->AddPhi(phi);
+    loop_header->AddInstruction(suspend_check);
+    loop_header->AddInstruction(new (GetAllocator()) HGreaterThanOrEqual(phi, const_128));
+    loop_header->AddInstruction(new (GetAllocator()) HIf(parameter_));
+
+    // Loop body block.
+    HInstruction* null_check = new (GetAllocator()) HNullCheck(parameter_, dex_pc);
+    HInstruction* array_length = new (GetAllocator()) HArrayLength(null_check, dex_pc);
+    HInstruction* bounds_check = new (GetAllocator()) HBoundsCheck(phi, array_length, dex_pc);
+    HInstruction* array_get =
+        new (GetAllocator()) HArrayGet(null_check, bounds_check, DataType::Type::kInt32, dex_pc);
+    HInstruction* add =  new (GetAllocator()) HAdd(DataType::Type::kInt32, array_get, const_1);
+    HInstruction* array_set =
+        new (GetAllocator()) HArraySet(null_check, bounds_check, add, DataType::Type::kInt32, dex_pc);
+    HInstruction* induction_inc = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi, const_1);
+
+    loop_body->AddInstruction(null_check);
+    loop_body->AddInstruction(array_length);
+    loop_body->AddInstruction(bounds_check);
+    loop_body->AddInstruction(array_get);
+    loop_body->AddInstruction(add);
+    loop_body->AddInstruction(array_set);
+    loop_body->AddInstruction(induction_inc);
+    loop_body->AddInstruction(new (GetAllocator()) HGoto());
+
+    phi->AddInput(const_0);
+    phi->AddInput(induction_inc);
+
+    graph_->SetHasBoundsChecks(true);
+
+    // Adjust HEnvironment for each instruction which require that.
+    ArenaVector<HInstruction*> current_locals({phi, const_128, parameter_},
+                                              GetAllocator()->Adapter(kArenaAllocInstruction));
+
+    HEnvironment* env = ManuallyBuildEnvFor(suspend_check, &current_locals);
+    null_check->CopyEnvironmentFrom(env);
+    bounds_check->CopyEnvironmentFrom(env);
+  }
+
+  HEnvironment* ManuallyBuildEnvFor(HInstruction* instruction,
+                                    ArenaVector<HInstruction*>* current_locals) {
+    HEnvironment* environment = new (GetAllocator()) HEnvironment(
+        (GetAllocator()),
+        current_locals->size(),
+        graph_->GetArtMethod(),
+        instruction->GetDexPc(),
+        instruction);
+
+    environment->CopyFrom(ArrayRef<HInstruction* const>(*current_locals));
+    instruction->SetRawEnvironment(environment);
+    return environment;
+  }
+
+  bool CheckGraph() {
+    GraphChecker checker(graph_);
+    checker.Run();
+    if (!checker.IsValid()) {
+      for (const std::string& error : checker.GetErrors()) {
+        std::cout << error << std::endl;
+      }
+      return false;
+    }
+    return true;
+  }
+
+  HGraph* graph_;
+
+  HBasicBlock* entry_block_;
+  HBasicBlock* exit_block_;
+
+  HInstruction* parameter_;
+};
+
+TEST_F(ClonerTest, IndividualInstrCloner) {
+  HBasicBlock* header = nullptr;
+  HBasicBlock* loop_body = nullptr;
+
+  CreateBasicLoopControlFlow(&header, &loop_body);
+  CreateBasicLoopDataFlow(header, loop_body);
+  graph_->BuildDominatorTree();
+  ASSERT_TRUE(CheckGraph());
+
+  HSuspendCheck* old_suspend_check = header->GetLoopInformation()->GetSuspendCheck();
+  CloneAndReplaceInstructionVisitor visitor(graph_);
+  // Do instruction cloning and replacement twice with different visiting order.
+
+  visitor.VisitInsertionOrder();
+  size_t instr_replaced_by_clones_count = visitor.GetInstrReplacedByClonesCount();
+  EXPECT_EQ(instr_replaced_by_clones_count, 12u);
+  EXPECT_TRUE(CheckGraph());
+
+  visitor.VisitReversePostOrder();
+  instr_replaced_by_clones_count = visitor.GetInstrReplacedByClonesCount();
+  EXPECT_EQ(instr_replaced_by_clones_count, 24u);
+  EXPECT_TRUE(CheckGraph());
+
+  HSuspendCheck* new_suspend_check = header->GetLoopInformation()->GetSuspendCheck();
+  EXPECT_NE(new_suspend_check, old_suspend_check);
+  EXPECT_NE(new_suspend_check, nullptr);
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2bd2d5f..7a1659e 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -27,6 +27,10 @@
 
 namespace art {
 
+// Whether to run an exhaustive test of individual HInstructions cloning when each instruction
+// is replaced with its copy if it is clonable.
+static constexpr bool kTestInstructionClonerExhaustively = false;
+
 class InstructionSimplifierVisitor : public HGraphDelegateVisitor {
  public:
   InstructionSimplifierVisitor(HGraph* graph,
@@ -130,6 +134,11 @@
 };
 
 void InstructionSimplifier::Run() {
+  if (kTestInstructionClonerExhaustively) {
+    CloneAndReplaceInstructionVisitor visitor(graph_);
+    visitor.VisitReversePostOrder();
+  }
+
   InstructionSimplifierVisitor visitor(graph_, codegen_, compiler_driver_, stats_);
   visitor.Run();
 }
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index f4f6434..b90ff59 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -845,6 +845,13 @@
   DCHECK(!instruction->HasEnvironment());
 }
 
+void HBasicBlock::ReplaceAndRemovePhiWith(HPhi* initial, HPhi* replacement) {
+  DCHECK(initial->GetBlock() == this);
+  InsertPhiAfter(replacement, initial);
+  initial->ReplaceWith(replacement);
+  RemovePhi(initial);
+}
+
 void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
                                                   HInstruction* replacement) {
   DCHECK(initial->GetBlock() == this);
@@ -2902,6 +2909,28 @@
   env_uses_.clear();
 }
 
+HInstruction* ReplaceInstrOrPhiByClone(HInstruction* instr) {
+  HInstruction* clone = instr->Clone(instr->GetBlock()->GetGraph()->GetAllocator());
+  HBasicBlock* block = instr->GetBlock();
+
+  if (instr->IsPhi()) {
+    HPhi* phi = instr->AsPhi();
+    DCHECK(!phi->HasEnvironment());
+    HPhi* phi_clone = clone->AsPhi();
+    block->ReplaceAndRemovePhiWith(phi, phi_clone);
+  } else {
+    block->ReplaceAndRemoveInstructionWith(instr, clone);
+    if (instr->HasEnvironment()) {
+      clone->CopyEnvironmentFrom(instr->GetEnvironment());
+      HLoopInformation* loop_info = block->GetLoopInformation();
+      if (instr->IsSuspendCheck() && loop_info != nullptr) {
+        loop_info->SetSuspendCheck(clone->AsSuspendCheck());
+      }
+    }
+  }
+  return clone;
+}
+
 // Returns an instruction with the opposite Boolean value from 'cond'.
 HInstruction* HGraph::InsertOppositeCondition(HInstruction* cond, HInstruction* cursor) {
   ArenaAllocator* allocator = GetAllocator();
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 29c78a1..5392ba6 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1159,6 +1159,8 @@
   // Insert `instruction` before/after an existing instruction `cursor`.
   void InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor);
   void InsertInstructionAfter(HInstruction* instruction, HInstruction* cursor);
+  // Replace phi `initial` with `replacement` within this block.
+  void ReplaceAndRemovePhiWith(HPhi* initial, HPhi* replacement);
   // Replace instruction `initial` with `replacement` within this block.
   void ReplaceAndRemoveInstructionWith(HInstruction* initial,
                                        HInstruction* replacement);
@@ -1479,18 +1481,31 @@
 #undef FORWARD_DECLARATION
 
 #define DECLARE_INSTRUCTION(type)                                         \
+  private:                                                                \
+  H##type& operator=(const H##type&) = delete;                            \
+  public:                                                                 \
   InstructionKind GetKindInternal() const OVERRIDE { return k##type; }    \
   const char* DebugName() const OVERRIDE { return #type; }                \
   bool InstructionTypeEquals(const HInstruction* other) const OVERRIDE {  \
     return other->Is##type();                                             \
   }                                                                       \
+  HInstruction* Clone(ArenaAllocator* arena) const OVERRIDE {             \
+    DCHECK(IsClonable());                                                 \
+    return new (arena) H##type(*this->As##type());                        \
+  }                                                                       \
   void Accept(HGraphVisitor* visitor) OVERRIDE
 
 #define DECLARE_ABSTRACT_INSTRUCTION(type)                              \
+  private:                                                              \
+  H##type& operator=(const H##type&) = delete;                          \
+  public:                                                               \
   bool Is##type() const { return As##type() != nullptr; }               \
   const H##type* As##type() const { return this; }                      \
   H##type* As##type() { return this; }
 
+#define DEFAULT_COPY_CONSTRUCTOR(type)                                  \
+  explicit H##type(const H##type& other) = default;
+
 template <typename T>
 class HUseListNode : public ArenaObject<kArenaAllocUseListNode>,
                      public IntrusiveForwardListNode<HUseListNode<T>> {
@@ -2181,6 +2196,25 @@
   FOR_EACH_ABSTRACT_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
 #undef INSTRUCTION_TYPE_CHECK
 
+  // Return a clone of the instruction if it is clonable (shallow copy by default, custom copy
+  // if a custom copy-constructor is provided for a particular type). If IsClonable() is false for
+  // the instruction then the behaviour of this function is undefined.
+  //
+  // Note: It is semantically valid to create a clone of the instruction only until
+  // prepare_for_register_allocator phase as lifetime, intervals and codegen info are not
+  // copied.
+  //
+  // Note: HEnvironment and some other fields are not copied and are set to default values, see
+  // 'explicit HInstruction(const HInstruction& other)' for details.
+  virtual HInstruction* Clone(ArenaAllocator* arena ATTRIBUTE_UNUSED) const {
+    LOG(FATAL) << "Cloning is not implemented for the instruction " <<
+                  DebugName() << " " << GetId();
+    UNREACHABLE();
+  }
+
+  // Return whether instruction can be cloned (copied).
+  virtual bool IsClonable() const { return false; }
+
   // Returns whether the instruction can be moved within the graph.
   // TODO: this method is used by LICM and GVN with possibly different
   //       meanings? split and rename?
@@ -2297,6 +2331,30 @@
     packed_fields_ = BitFieldType::Update(value, packed_fields_);
   }
 
+  // Copy construction for the instruction (used for Clone function).
+  //
+  // Fields (e.g. lifetime, intervals and codegen info) associated with phases starting from
+  // prepare_for_register_allocator are not copied (set to default values).
+  //
+  // Copy constructors must be provided for every HInstruction type; default copy constructor is
+  // fine for most of them. However for some of the instructions a custom copy constructor must be
+  // specified (when instruction has non-trivially copyable fields and must have a special behaviour
+  // for copying them).
+  explicit HInstruction(const HInstruction& other)
+      : previous_(nullptr),
+        next_(nullptr),
+        block_(nullptr),
+        dex_pc_(other.dex_pc_),
+        id_(-1),
+        ssa_index_(-1),
+        packed_fields_(other.packed_fields_),
+        environment_(nullptr),
+        locations_(nullptr),
+        live_interval_(nullptr),
+        lifetime_position_(kNoLifetime),
+        side_effects_(other.side_effects_),
+        reference_type_handle_(other.reference_type_handle_) {}
+
  private:
   void FixUpUserRecordsAfterUseInsertion(HUseList<HInstruction*>::iterator fixup_end) {
     auto before_use_node = uses_.before_begin();
@@ -2386,8 +2444,6 @@
   friend class HEnvironment;
   friend class HGraph;
   friend class HInstructionList;
-
-  DISALLOW_COPY_AND_ASSIGN(HInstruction);
 };
 std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs);
 
@@ -2483,10 +2539,9 @@
       : HInstruction(side_effects, dex_pc),
         inputs_(number_of_inputs, allocator->Adapter(kind)) {}
 
-  ArenaVector<HUserRecord<HInstruction*>> inputs_;
+  DEFAULT_COPY_CONSTRUCTOR(VariableInputSizeInstruction);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVariableInputSizeInstruction);
+  ArenaVector<HUserRecord<HInstruction*>> inputs_;
 };
 
 template<size_t N>
@@ -2501,6 +2556,9 @@
     return ArrayRef<HUserRecord<HInstruction*>>(inputs_);
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(TemplateInstruction<N>);
+
  private:
   std::array<HUserRecord<HInstruction*>, N> inputs_;
 
@@ -2521,6 +2579,9 @@
     return ArrayRef<HUserRecord<HInstruction*>>();
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(TemplateInstruction<0>);
+
  private:
   friend class SsaBuilder;
 };
@@ -2546,6 +2607,7 @@
   static_assert(kNumberOfExpressionPackedBits <= HInstruction::kMaxNumberOfPackedBits,
                 "Too many packed fields.");
   using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>;
+  DEFAULT_COPY_CONSTRUCTOR(Expression<N>);
 };
 
 // Represents dex's RETURN_VOID opcode. A HReturnVoid is a control flow
@@ -2559,8 +2621,8 @@
 
   DECLARE_INSTRUCTION(ReturnVoid);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HReturnVoid);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(ReturnVoid);
 };
 
 // Represents dex's RETURN opcodes. A HReturn is a control flow
@@ -2576,8 +2638,8 @@
 
   DECLARE_INSTRUCTION(Return);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HReturn);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Return);
 };
 
 class HPhi FINAL : public HVariableInputSizeInstruction {
@@ -2603,6 +2665,8 @@
     SetPackedFlag<kFlagCanBeNull>(true);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   // Returns a type equivalent to the given `type`, but that a `HPhi` can hold.
   static DataType::Type ToPhiType(DataType::Type type) {
     return DataType::Kind(type);
@@ -2665,6 +2729,9 @@
 
   DECLARE_INSTRUCTION(Phi);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Phi);
+
  private:
   static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits;
   static constexpr size_t kFieldTypeSize =
@@ -2676,8 +2743,6 @@
   using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>;
 
   const uint32_t reg_number_;
-
-  DISALLOW_COPY_AND_ASSIGN(HPhi);
 };
 
 // The exit instruction is the only instruction of the exit block.
@@ -2691,8 +2756,8 @@
 
   DECLARE_INSTRUCTION(Exit);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HExit);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Exit);
 };
 
 // Jumps from one block to another.
@@ -2700,6 +2765,7 @@
  public:
   explicit HGoto(uint32_t dex_pc = kNoDexPc) : HTemplateInstruction(SideEffects::None(), dex_pc) {}
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool IsControlFlow() const OVERRIDE { return true; }
 
   HBasicBlock* GetSuccessor() const {
@@ -2708,8 +2774,8 @@
 
   DECLARE_INSTRUCTION(Goto);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HGoto);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Goto);
 };
 
 class HConstant : public HExpression<0> {
@@ -2732,8 +2798,8 @@
 
   DECLARE_ABSTRACT_INSTRUCTION(Constant);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HConstant);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Constant);
 };
 
 class HNullConstant FINAL : public HConstant {
@@ -2751,12 +2817,14 @@
 
   DECLARE_INSTRUCTION(NullConstant);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(NullConstant);
+
  private:
   explicit HNullConstant(uint32_t dex_pc = kNoDexPc)
       : HConstant(DataType::Type::kReference, dex_pc) {}
 
   friend class HGraph;
-  DISALLOW_COPY_AND_ASSIGN(HNullConstant);
 };
 
 // Constants of the type int. Those can be from Dex instructions, or
@@ -2788,6 +2856,9 @@
 
   DECLARE_INSTRUCTION(IntConstant);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(IntConstant);
+
  private:
   explicit HIntConstant(int32_t value, uint32_t dex_pc = kNoDexPc)
       : HConstant(DataType::Type::kInt32, dex_pc), value_(value) {}
@@ -2799,7 +2870,6 @@
   friend class HGraph;
   ART_FRIEND_TEST(GraphTest, InsertInstructionBefore);
   ART_FRIEND_TYPED_TEST(ParallelMoveTest, ConstantLast);
-  DISALLOW_COPY_AND_ASSIGN(HIntConstant);
 };
 
 class HLongConstant FINAL : public HConstant {
@@ -2822,6 +2892,9 @@
 
   DECLARE_INSTRUCTION(LongConstant);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(LongConstant);
+
  private:
   explicit HLongConstant(int64_t value, uint32_t dex_pc = kNoDexPc)
       : HConstant(DataType::Type::kInt64, dex_pc), value_(value) {}
@@ -2829,7 +2902,6 @@
   const int64_t value_;
 
   friend class HGraph;
-  DISALLOW_COPY_AND_ASSIGN(HLongConstant);
 };
 
 class HFloatConstant FINAL : public HConstant {
@@ -2871,6 +2943,9 @@
 
   DECLARE_INSTRUCTION(FloatConstant);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(FloatConstant);
+
  private:
   explicit HFloatConstant(float value, uint32_t dex_pc = kNoDexPc)
       : HConstant(DataType::Type::kFloat32, dex_pc), value_(value) {}
@@ -2882,7 +2957,6 @@
   // Only the SsaBuilder and HGraph can create floating-point constants.
   friend class SsaBuilder;
   friend class HGraph;
-  DISALLOW_COPY_AND_ASSIGN(HFloatConstant);
 };
 
 class HDoubleConstant FINAL : public HConstant {
@@ -2922,6 +2996,9 @@
 
   DECLARE_INSTRUCTION(DoubleConstant);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(DoubleConstant);
+
  private:
   explicit HDoubleConstant(double value, uint32_t dex_pc = kNoDexPc)
       : HConstant(DataType::Type::kFloat64, dex_pc), value_(value) {}
@@ -2933,7 +3010,6 @@
   // Only the SsaBuilder and HGraph can create floating-point constants.
   friend class SsaBuilder;
   friend class HGraph;
-  DISALLOW_COPY_AND_ASSIGN(HDoubleConstant);
 };
 
 // Conditional branch. A block ending with an HIf instruction must have
@@ -2945,6 +3021,7 @@
     SetRawInputAt(0, input);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool IsControlFlow() const OVERRIDE { return true; }
 
   HBasicBlock* IfTrueSuccessor() const {
@@ -2957,8 +3034,8 @@
 
   DECLARE_INSTRUCTION(If);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HIf);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(If);
 };
 
 
@@ -3011,6 +3088,9 @@
 
   DECLARE_INSTRUCTION(TryBoundary);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(TryBoundary);
+
  private:
   static constexpr size_t kFieldBoundaryKind = kNumberOfGenericPackedBits;
   static constexpr size_t kFieldBoundaryKindSize =
@@ -3020,8 +3100,6 @@
   static_assert(kNumberOfTryBoundaryPackedBits <= kMaxNumberOfPackedBits,
                 "Too many packed fields.");
   using BoundaryKindField = BitField<BoundaryKind, kFieldBoundaryKind, kFieldBoundaryKindSize>;
-
-  DISALLOW_COPY_AND_ASSIGN(HTryBoundary);
 };
 
 // Deoptimize to interpreter, upon checking a condition.
@@ -3044,6 +3122,8 @@
     SetRawInputAt(0, cond);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   // Use this constructor when the `HDeoptimize` guards an instruction, and any user
   // that relies on the deoptimization to pass should have its input be the `HDeoptimize`
   // instead of `guard`.
@@ -3097,6 +3177,9 @@
 
   DECLARE_INSTRUCTION(Deoptimize);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Deoptimize);
+
  private:
   static constexpr size_t kFieldCanBeMoved = kNumberOfGenericPackedBits;
   static constexpr size_t kFieldDeoptimizeKind = kNumberOfGenericPackedBits + 1;
@@ -3108,8 +3191,6 @@
                 "Too many packed fields.");
   using DeoptimizeKindField =
       BitField<DeoptimizationKind, kFieldDeoptimizeKind, kFieldDeoptimizeKindSize>;
-
-  DISALLOW_COPY_AND_ASSIGN(HDeoptimize);
 };
 
 // Represents a should_deoptimize flag. Currently used for CHA-based devirtualization.
@@ -3135,8 +3216,8 @@
 
   DECLARE_INSTRUCTION(ShouldDeoptimizeFlag);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HShouldDeoptimizeFlag);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(ShouldDeoptimizeFlag);
 };
 
 // Represents the ArtMethod that was passed as a first argument to
@@ -3149,8 +3230,8 @@
 
   DECLARE_INSTRUCTION(CurrentMethod);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HCurrentMethod);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(CurrentMethod);
 };
 
 // Fetches an ArtMethod from the virtual table or the interface method table
@@ -3173,6 +3254,7 @@
     SetRawInputAt(0, cls);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
     return other->AsClassTableGet()->GetIndex() == index_ &&
@@ -3184,6 +3266,9 @@
 
   DECLARE_INSTRUCTION(ClassTableGet);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(ClassTableGet);
+
  private:
   static constexpr size_t kFieldTableKind = kNumberOfExpressionPackedBits;
   static constexpr size_t kFieldTableKindSize =
@@ -3195,8 +3280,6 @@
 
   // The index of the ArtMethod in the table.
   const size_t index_;
-
-  DISALLOW_COPY_AND_ASSIGN(HClassTableGet);
 };
 
 // PackedSwitch (jump table). A block ending with a PackedSwitch instruction will
@@ -3214,6 +3297,8 @@
     SetRawInputAt(0, input);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   bool IsControlFlow() const OVERRIDE { return true; }
 
   int32_t GetStartValue() const { return start_value_; }
@@ -3226,11 +3311,12 @@
   }
   DECLARE_INSTRUCTION(PackedSwitch);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(PackedSwitch);
+
  private:
   const int32_t start_value_;
   const uint32_t num_entries_;
-
-  DISALLOW_COPY_AND_ASSIGN(HPackedSwitch);
 };
 
 class HUnaryOperation : public HExpression<1> {
@@ -3240,6 +3326,9 @@
     SetRawInputAt(0, input);
   }
 
+  // All of the UnaryOperation instructions are clonable.
+  bool IsClonable() const OVERRIDE { return true; }
+
   HInstruction* GetInput() const { return InputAt(0); }
   DataType::Type GetResultType() const { return GetType(); }
 
@@ -3261,8 +3350,8 @@
 
   DECLARE_ABSTRACT_INSTRUCTION(UnaryOperation);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HUnaryOperation);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(UnaryOperation);
 };
 
 class HBinaryOperation : public HExpression<2> {
@@ -3277,6 +3366,9 @@
     SetRawInputAt(1, right);
   }
 
+  // All of the BinaryOperation instructions are clonable.
+  bool IsClonable() const OVERRIDE { return true; }
+
   HInstruction* GetLeft() const { return InputAt(0); }
   HInstruction* GetRight() const { return InputAt(1); }
   DataType::Type GetResultType() const { return GetType(); }
@@ -3351,8 +3443,8 @@
 
   DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HBinaryOperation);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(BinaryOperation);
 };
 
 // The comparison bias applies for floating point operations and indicates how NaN
@@ -3442,8 +3534,7 @@
     return GetBlock()->GetGraph()->GetIntConstant(value, dex_pc);
   }
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HCondition);
+  DEFAULT_COPY_CONSTRUCTOR(Condition);
 };
 
 // Instruction to check if two inputs are equal to each other.
@@ -3485,10 +3576,11 @@
     return kCondNE;
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Equal);
+
  private:
   template <typename T> static bool Compute(T x, T y) { return x == y; }
-
-  DISALLOW_COPY_AND_ASSIGN(HEqual);
 };
 
 class HNotEqual FINAL : public HCondition {
@@ -3528,10 +3620,11 @@
     return kCondEQ;
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(NotEqual);
+
  private:
   template <typename T> static bool Compute(T x, T y) { return x != y; }
-
-  DISALLOW_COPY_AND_ASSIGN(HNotEqual);
 };
 
 class HLessThan FINAL : public HCondition {
@@ -3565,10 +3658,11 @@
     return kCondGE;
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(LessThan);
+
  private:
   template <typename T> static bool Compute(T x, T y) { return x < y; }
-
-  DISALLOW_COPY_AND_ASSIGN(HLessThan);
 };
 
 class HLessThanOrEqual FINAL : public HCondition {
@@ -3602,10 +3696,11 @@
     return kCondGT;
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(LessThanOrEqual);
+
  private:
   template <typename T> static bool Compute(T x, T y) { return x <= y; }
-
-  DISALLOW_COPY_AND_ASSIGN(HLessThanOrEqual);
 };
 
 class HGreaterThan FINAL : public HCondition {
@@ -3639,10 +3734,11 @@
     return kCondLE;
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(GreaterThan);
+
  private:
   template <typename T> static bool Compute(T x, T y) { return x > y; }
-
-  DISALLOW_COPY_AND_ASSIGN(HGreaterThan);
 };
 
 class HGreaterThanOrEqual FINAL : public HCondition {
@@ -3676,10 +3772,11 @@
     return kCondLT;
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(GreaterThanOrEqual);
+
  private:
   template <typename T> static bool Compute(T x, T y) { return x >= y; }
-
-  DISALLOW_COPY_AND_ASSIGN(HGreaterThanOrEqual);
 };
 
 class HBelow FINAL : public HCondition {
@@ -3714,12 +3811,13 @@
     return kCondAE;
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Below);
+
  private:
   template <typename T> static bool Compute(T x, T y) {
     return MakeUnsigned(x) < MakeUnsigned(y);
   }
-
-  DISALLOW_COPY_AND_ASSIGN(HBelow);
 };
 
 class HBelowOrEqual FINAL : public HCondition {
@@ -3754,12 +3852,13 @@
     return kCondA;
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(BelowOrEqual);
+
  private:
   template <typename T> static bool Compute(T x, T y) {
     return MakeUnsigned(x) <= MakeUnsigned(y);
   }
-
-  DISALLOW_COPY_AND_ASSIGN(HBelowOrEqual);
 };
 
 class HAbove FINAL : public HCondition {
@@ -3794,12 +3893,13 @@
     return kCondBE;
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Above);
+
  private:
   template <typename T> static bool Compute(T x, T y) {
     return MakeUnsigned(x) > MakeUnsigned(y);
   }
-
-  DISALLOW_COPY_AND_ASSIGN(HAbove);
 };
 
 class HAboveOrEqual FINAL : public HCondition {
@@ -3834,12 +3934,13 @@
     return kCondB;
   }
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(AboveOrEqual);
+
  private:
   template <typename T> static bool Compute(T x, T y) {
     return MakeUnsigned(x) >= MakeUnsigned(y);
   }
-
-  DISALLOW_COPY_AND_ASSIGN(HAboveOrEqual);
 };
 
 // Instruction to check how two inputs compare to each other.
@@ -3929,8 +4030,7 @@
     return GetBlock()->GetGraph()->GetIntConstant(value, dex_pc);
   }
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HCompare);
+  DEFAULT_COPY_CONSTRUCTOR(Compare);
 };
 
 class HNewInstance FINAL : public HExpression<1> {
@@ -3949,6 +4049,8 @@
     SetRawInputAt(0, cls);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   dex::TypeIndex GetTypeIndex() const { return type_index_; }
   const DexFile& GetDexFile() const { return dex_file_; }
 
@@ -3985,6 +4087,9 @@
 
   DECLARE_INSTRUCTION(NewInstance);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(NewInstance);
+
  private:
   static constexpr size_t kFlagFinalizable = kNumberOfExpressionPackedBits;
   static constexpr size_t kNumberOfNewInstancePackedBits = kFlagFinalizable + 1;
@@ -3994,8 +4099,6 @@
   const dex::TypeIndex type_index_;
   const DexFile& dex_file_;
   QuickEntrypointEnum entrypoint_;
-
-  DISALLOW_COPY_AND_ASSIGN(HNewInstance);
 };
 
 enum IntrinsicNeedsEnvironmentOrCache {
@@ -4113,6 +4216,8 @@
     SetPackedFlag<kFlagCanThrow>(true);
   }
 
+  DEFAULT_COPY_CONSTRUCTOR(Invoke);
+
   uint32_t number_of_arguments_;
   ArtMethod* resolved_method_;
   const uint32_t dex_method_index_;
@@ -4120,9 +4225,6 @@
 
   // A magic word holding optimizations for intrinsics. See intrinsics.h.
   uint32_t intrinsic_optimizations_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(HInvoke);
 };
 
 class HInvokeUnresolved FINAL : public HInvoke {
@@ -4143,10 +4245,12 @@
                 invoke_type) {
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   DECLARE_INSTRUCTION(InvokeUnresolved);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HInvokeUnresolved);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(InvokeUnresolved);
 };
 
 class HInvokePolymorphic FINAL : public HInvoke {
@@ -4165,10 +4269,12 @@
                 nullptr,
                 kVirtual) {}
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   DECLARE_INSTRUCTION(InvokePolymorphic);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HInvokePolymorphic);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(InvokePolymorphic);
 };
 
 class HInvokeStaticOrDirect FINAL : public HInvoke {
@@ -4255,6 +4361,8 @@
     SetPackedField<ClinitCheckRequirementField>(clinit_check_requirement);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   void SetDispatchInfo(const DispatchInfo& dispatch_info) {
     bool had_current_method_input = HasCurrentMethodInput();
     bool needs_current_method_input = NeedsCurrentMethodInput(dispatch_info.method_load_kind);
@@ -4400,6 +4508,9 @@
 
   DECLARE_INSTRUCTION(InvokeStaticOrDirect);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(InvokeStaticOrDirect);
+
  private:
   static constexpr size_t kFieldClinitCheckRequirement = kNumberOfInvokePackedBits;
   static constexpr size_t kFieldClinitCheckRequirementSize =
@@ -4415,8 +4526,6 @@
   // Cached values of the resolved method, to avoid needing the mutator lock.
   MethodReference target_method_;
   DispatchInfo dispatch_info_;
-
-  DISALLOW_COPY_AND_ASSIGN(HInvokeStaticOrDirect);
 };
 std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::MethodLoadKind rhs);
 std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::ClinitCheckRequirement rhs);
@@ -4440,6 +4549,8 @@
                 kVirtual),
         vtable_index_(vtable_index) {}
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   bool CanBeNull() const OVERRIDE {
     switch (GetIntrinsic()) {
       case Intrinsics::kThreadCurrentThread:
@@ -4462,11 +4573,12 @@
 
   DECLARE_INSTRUCTION(InvokeVirtual);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(InvokeVirtual);
+
  private:
   // Cached value of the resolved method, to avoid needing the mutator lock.
   const uint32_t vtable_index_;
-
-  DISALLOW_COPY_AND_ASSIGN(HInvokeVirtual);
 };
 
 class HInvokeInterface FINAL : public HInvoke {
@@ -4488,6 +4600,8 @@
                 kInterface),
         imt_index_(imt_index) {}
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
     // TODO: Add implicit null checks in intrinsics.
     return (obj == InputAt(0)) && !GetLocations()->Intrinsified();
@@ -4503,11 +4617,12 @@
 
   DECLARE_INSTRUCTION(InvokeInterface);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(InvokeInterface);
+
  private:
   // Cached value of the resolved method, to avoid needing the mutator lock.
   const uint32_t imt_index_;
-
-  DISALLOW_COPY_AND_ASSIGN(HInvokeInterface);
 };
 
 class HNeg FINAL : public HUnaryOperation {
@@ -4534,8 +4649,8 @@
 
   DECLARE_INSTRUCTION(Neg);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HNeg);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Neg);
 };
 
 class HNewArray FINAL : public HExpression<2> {
@@ -4546,6 +4661,8 @@
     SetRawInputAt(1, length);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   // Calls runtime so needs an environment.
   bool NeedsEnvironment() const OVERRIDE { return true; }
 
@@ -4565,8 +4682,8 @@
 
   DECLARE_INSTRUCTION(NewArray);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HNewArray);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(NewArray);
 };
 
 class HAdd FINAL : public HBinaryOperation {
@@ -4600,8 +4717,8 @@
 
   DECLARE_INSTRUCTION(Add);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HAdd);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Add);
 };
 
 class HSub FINAL : public HBinaryOperation {
@@ -4633,8 +4750,8 @@
 
   DECLARE_INSTRUCTION(Sub);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HSub);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Sub);
 };
 
 class HMul FINAL : public HBinaryOperation {
@@ -4668,8 +4785,8 @@
 
   DECLARE_INSTRUCTION(Mul);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HMul);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Mul);
 };
 
 class HDiv FINAL : public HBinaryOperation {
@@ -4715,8 +4832,8 @@
 
   DECLARE_INSTRUCTION(Div);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HDiv);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Div);
 };
 
 class HRem FINAL : public HBinaryOperation {
@@ -4762,8 +4879,8 @@
 
   DECLARE_INSTRUCTION(Rem);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HRem);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Rem);
 };
 
 class HDivZeroCheck FINAL : public HExpression<1> {
@@ -4788,8 +4905,8 @@
 
   DECLARE_INSTRUCTION(DivZeroCheck);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HDivZeroCheck);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(DivZeroCheck);
 };
 
 class HShl FINAL : public HBinaryOperation {
@@ -4834,8 +4951,8 @@
 
   DECLARE_INSTRUCTION(Shl);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HShl);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Shl);
 };
 
 class HShr FINAL : public HBinaryOperation {
@@ -4880,8 +4997,8 @@
 
   DECLARE_INSTRUCTION(Shr);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HShr);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Shr);
 };
 
 class HUShr FINAL : public HBinaryOperation {
@@ -4928,8 +5045,8 @@
 
   DECLARE_INSTRUCTION(UShr);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HUShr);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(UShr);
 };
 
 class HAnd FINAL : public HBinaryOperation {
@@ -4965,8 +5082,8 @@
 
   DECLARE_INSTRUCTION(And);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HAnd);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(And);
 };
 
 class HOr FINAL : public HBinaryOperation {
@@ -5002,8 +5119,8 @@
 
   DECLARE_INSTRUCTION(Or);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HOr);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Or);
 };
 
 class HXor FINAL : public HBinaryOperation {
@@ -5039,8 +5156,8 @@
 
   DECLARE_INSTRUCTION(Xor);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HXor);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Xor);
 };
 
 class HRor FINAL : public HBinaryOperation {
@@ -5090,8 +5207,8 @@
 
   DECLARE_INSTRUCTION(Ror);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HRor);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Ror);
 };
 
 // The value of a parameter in this method. Its location depends on
@@ -5121,6 +5238,9 @@
 
   DECLARE_INSTRUCTION(ParameterValue);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(ParameterValue);
+
  private:
   // Whether or not the parameter value corresponds to 'this' argument.
   static constexpr size_t kFlagIsThis = kNumberOfExpressionPackedBits;
@@ -5134,8 +5254,6 @@
   // The index of this parameter in the parameters list. Must be less
   // than HGraph::number_of_in_vregs_.
   const uint8_t index_;
-
-  DISALLOW_COPY_AND_ASSIGN(HParameterValue);
 };
 
 class HNot FINAL : public HUnaryOperation {
@@ -5167,8 +5285,8 @@
 
   DECLARE_INSTRUCTION(Not);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HNot);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Not);
 };
 
 class HBooleanNot FINAL : public HUnaryOperation {
@@ -5204,8 +5322,8 @@
 
   DECLARE_INSTRUCTION(BooleanNot);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HBooleanNot);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(BooleanNot);
 };
 
 class HTypeConversion FINAL : public HExpression<1> {
@@ -5233,8 +5351,8 @@
 
   DECLARE_INSTRUCTION(TypeConversion);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HTypeConversion);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(TypeConversion);
 };
 
 static constexpr uint32_t kNoRegNumber = -1;
@@ -5248,6 +5366,7 @@
     SetRawInputAt(0, value);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
     return true;
@@ -5259,11 +5378,10 @@
 
   bool CanBeNull() const OVERRIDE { return false; }
 
-
   DECLARE_INSTRUCTION(NullCheck);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HNullCheck);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(NullCheck);
 };
 
 // Embeds an ArtField and all the information required by the compiler. We cache
@@ -5325,6 +5443,7 @@
     SetRawInputAt(0, value);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return !IsVolatile(); }
 
   bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
@@ -5354,10 +5473,11 @@
 
   DECLARE_INSTRUCTION(InstanceFieldGet);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(InstanceFieldGet);
+
  private:
   const FieldInfo field_info_;
-
-  DISALLOW_COPY_AND_ASSIGN(HInstanceFieldGet);
 };
 
 class HInstanceFieldSet FINAL : public HTemplateInstruction<2> {
@@ -5385,6 +5505,8 @@
     SetRawInputAt(1, value);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
     return (obj == InputAt(0)) && art::CanDoImplicitNullCheckOn(GetFieldOffset().Uint32Value());
   }
@@ -5399,6 +5521,9 @@
 
   DECLARE_INSTRUCTION(InstanceFieldSet);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(InstanceFieldSet);
+
  private:
   static constexpr size_t kFlagValueCanBeNull = kNumberOfGenericPackedBits;
   static constexpr size_t kNumberOfInstanceFieldSetPackedBits = kFlagValueCanBeNull + 1;
@@ -5406,8 +5531,6 @@
                 "Too many packed fields.");
 
   const FieldInfo field_info_;
-
-  DISALLOW_COPY_AND_ASSIGN(HInstanceFieldSet);
 };
 
 class HArrayGet FINAL : public HExpression<2> {
@@ -5435,6 +5558,7 @@
     SetRawInputAt(1, index);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
     return true;
@@ -5484,6 +5608,9 @@
 
   DECLARE_INSTRUCTION(ArrayGet);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(ArrayGet);
+
  private:
   // We treat a String as an array, creating the HArrayGet from String.charAt()
   // intrinsic in the instruction simplifier. We can always determine whether
@@ -5494,8 +5621,6 @@
   static constexpr size_t kNumberOfArrayGetPackedBits = kFlagIsStringCharAt + 1;
   static_assert(kNumberOfArrayGetPackedBits <= HInstruction::kMaxNumberOfPackedBits,
                 "Too many packed fields.");
-
-  DISALLOW_COPY_AND_ASSIGN(HArrayGet);
 };
 
 class HArraySet FINAL : public HTemplateInstruction<3> {
@@ -5529,6 +5654,8 @@
     SetRawInputAt(2, value);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   bool NeedsEnvironment() const OVERRIDE {
     // We call a runtime method to throw ArrayStoreException.
     return NeedsTypeCheck();
@@ -5594,6 +5721,9 @@
 
   DECLARE_INSTRUCTION(ArraySet);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(ArraySet);
+
  private:
   static constexpr size_t kFieldExpectedComponentType = kNumberOfGenericPackedBits;
   static constexpr size_t kFieldExpectedComponentTypeSize =
@@ -5609,8 +5739,6 @@
   static_assert(kNumberOfArraySetPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
   using ExpectedComponentTypeField =
       BitField<DataType::Type, kFieldExpectedComponentType, kFieldExpectedComponentTypeSize>;
-
-  DISALLOW_COPY_AND_ASSIGN(HArraySet);
 };
 
 class HArrayLength FINAL : public HExpression<1> {
@@ -5623,6 +5751,7 @@
     SetRawInputAt(0, array);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
     return true;
@@ -5635,6 +5764,9 @@
 
   DECLARE_INSTRUCTION(ArrayLength);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(ArrayLength);
+
  private:
   // We treat a String as an array, creating the HArrayLength from String.length()
   // or String.isEmpty() intrinsic in the instruction simplifier. We can always
@@ -5645,8 +5777,6 @@
   static constexpr size_t kNumberOfArrayLengthPackedBits = kFlagIsStringLength + 1;
   static_assert(kNumberOfArrayLengthPackedBits <= HInstruction::kMaxNumberOfPackedBits,
                 "Too many packed fields.");
-
-  DISALLOW_COPY_AND_ASSIGN(HArrayLength);
 };
 
 class HBoundsCheck FINAL : public HExpression<2> {
@@ -5664,6 +5794,7 @@
     SetRawInputAt(1, length);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
     return true;
@@ -5679,10 +5810,11 @@
 
   DECLARE_INSTRUCTION(BoundsCheck);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(BoundsCheck);
+
  private:
   static constexpr size_t kFlagIsStringCharAt = kNumberOfExpressionPackedBits;
-
-  DISALLOW_COPY_AND_ASSIGN(HBoundsCheck);
 };
 
 class HSuspendCheck FINAL : public HTemplateInstruction<0> {
@@ -5690,6 +5822,8 @@
   explicit HSuspendCheck(uint32_t dex_pc = kNoDexPc)
       : HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc), slow_path_(nullptr) {}
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   bool NeedsEnvironment() const OVERRIDE {
     return true;
   }
@@ -5699,12 +5833,13 @@
 
   DECLARE_INSTRUCTION(SuspendCheck);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(SuspendCheck);
+
  private:
   // Only used for code generation, in order to share the same slow path between back edges
   // of a same loop.
   SlowPathCode* slow_path_;
-
-  DISALLOW_COPY_AND_ASSIGN(HSuspendCheck);
 };
 
 // Pseudo-instruction which provides the native debugger with mapping information.
@@ -5720,8 +5855,8 @@
 
   DECLARE_INSTRUCTION(NativeDebugInfo);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HNativeDebugInfo);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(NativeDebugInfo);
 };
 
 /**
@@ -5787,6 +5922,8 @@
     SetPackedFlag<kFlagGenerateClInitCheck>(false);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   void SetLoadKind(LoadKind load_kind);
 
   LoadKind GetLoadKind() const {
@@ -5878,6 +6015,9 @@
 
   DECLARE_INSTRUCTION(LoadClass);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(LoadClass);
+
  private:
   static constexpr size_t kFlagNeedsAccessCheck    = kNumberOfGenericPackedBits;
   static constexpr size_t kFlagIsInBootImage       = kFlagNeedsAccessCheck + 1;
@@ -5917,8 +6057,6 @@
   Handle<mirror::Class> klass_;
 
   ReferenceTypeInfo loaded_class_rti_;
-
-  DISALLOW_COPY_AND_ASSIGN(HLoadClass);
 };
 std::ostream& operator<<(std::ostream& os, HLoadClass::LoadKind rhs);
 
@@ -5976,6 +6114,8 @@
     SetPackedField<LoadKindField>(LoadKind::kRuntimeCall);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   void SetLoadKind(LoadKind load_kind);
 
   LoadKind GetLoadKind() const {
@@ -6042,6 +6182,9 @@
 
   DECLARE_INSTRUCTION(LoadString);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(LoadString);
+
  private:
   static constexpr size_t kFieldLoadKind = kNumberOfGenericPackedBits;
   static constexpr size_t kFieldLoadKindSize =
@@ -6061,8 +6204,6 @@
   const DexFile& dex_file_;
 
   Handle<mirror::String> string_;
-
-  DISALLOW_COPY_AND_ASSIGN(HLoadString);
 };
 std::ostream& operator<<(std::ostream& os, HLoadString::LoadKind rhs);
 
@@ -6094,6 +6235,7 @@
     SetRawInputAt(0, constant);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
     return true;
@@ -6113,8 +6255,9 @@
 
   DECLARE_INSTRUCTION(ClinitCheck);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HClinitCheck);
+
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(ClinitCheck);
 };
 
 class HStaticFieldGet FINAL : public HExpression<1> {
@@ -6140,6 +6283,7 @@
   }
 
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return !IsVolatile(); }
 
   bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
@@ -6165,10 +6309,11 @@
 
   DECLARE_INSTRUCTION(StaticFieldGet);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(StaticFieldGet);
+
  private:
   const FieldInfo field_info_;
-
-  DISALLOW_COPY_AND_ASSIGN(HStaticFieldGet);
 };
 
 class HStaticFieldSet FINAL : public HTemplateInstruction<2> {
@@ -6196,6 +6341,7 @@
     SetRawInputAt(1, value);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   const FieldInfo& GetFieldInfo() const { return field_info_; }
   MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
   DataType::Type GetFieldType() const { return field_info_.GetFieldType(); }
@@ -6207,6 +6353,9 @@
 
   DECLARE_INSTRUCTION(StaticFieldSet);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(StaticFieldSet);
+
  private:
   static constexpr size_t kFlagValueCanBeNull = kNumberOfGenericPackedBits;
   static constexpr size_t kNumberOfStaticFieldSetPackedBits = kFlagValueCanBeNull + 1;
@@ -6214,8 +6363,6 @@
                 "Too many packed fields.");
 
   const FieldInfo field_info_;
-
-  DISALLOW_COPY_AND_ASSIGN(HStaticFieldSet);
 };
 
 class HUnresolvedInstanceFieldGet FINAL : public HExpression<1> {
@@ -6229,6 +6376,7 @@
     SetRawInputAt(0, obj);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool NeedsEnvironment() const OVERRIDE { return true; }
   bool CanThrow() const OVERRIDE { return true; }
 
@@ -6237,10 +6385,11 @@
 
   DECLARE_INSTRUCTION(UnresolvedInstanceFieldGet);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(UnresolvedInstanceFieldGet);
+
  private:
   const uint32_t field_index_;
-
-  DISALLOW_COPY_AND_ASSIGN(HUnresolvedInstanceFieldGet);
 };
 
 class HUnresolvedInstanceFieldSet FINAL : public HTemplateInstruction<2> {
@@ -6258,6 +6407,7 @@
     SetRawInputAt(1, value);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool NeedsEnvironment() const OVERRIDE { return true; }
   bool CanThrow() const OVERRIDE { return true; }
 
@@ -6266,6 +6416,9 @@
 
   DECLARE_INSTRUCTION(UnresolvedInstanceFieldSet);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(UnresolvedInstanceFieldSet);
+
  private:
   static constexpr size_t kFieldFieldType = HInstruction::kNumberOfGenericPackedBits;
   static constexpr size_t kFieldFieldTypeSize =
@@ -6277,8 +6430,6 @@
   using FieldTypeField = BitField<DataType::Type, kFieldFieldType, kFieldFieldTypeSize>;
 
   const uint32_t field_index_;
-
-  DISALLOW_COPY_AND_ASSIGN(HUnresolvedInstanceFieldSet);
 };
 
 class HUnresolvedStaticFieldGet FINAL : public HExpression<0> {
@@ -6290,6 +6441,7 @@
         field_index_(field_index) {
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool NeedsEnvironment() const OVERRIDE { return true; }
   bool CanThrow() const OVERRIDE { return true; }
 
@@ -6298,10 +6450,11 @@
 
   DECLARE_INSTRUCTION(UnresolvedStaticFieldGet);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(UnresolvedStaticFieldGet);
+
  private:
   const uint32_t field_index_;
-
-  DISALLOW_COPY_AND_ASSIGN(HUnresolvedStaticFieldGet);
 };
 
 class HUnresolvedStaticFieldSet FINAL : public HTemplateInstruction<1> {
@@ -6317,6 +6470,7 @@
     SetRawInputAt(0, value);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool NeedsEnvironment() const OVERRIDE { return true; }
   bool CanThrow() const OVERRIDE { return true; }
 
@@ -6325,6 +6479,9 @@
 
   DECLARE_INSTRUCTION(UnresolvedStaticFieldSet);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(UnresolvedStaticFieldSet);
+
  private:
   static constexpr size_t kFieldFieldType = HInstruction::kNumberOfGenericPackedBits;
   static constexpr size_t kFieldFieldTypeSize =
@@ -6336,8 +6493,6 @@
   using FieldTypeField = BitField<DataType::Type, kFieldFieldType, kFieldFieldTypeSize>;
 
   const uint32_t field_index_;
-
-  DISALLOW_COPY_AND_ASSIGN(HUnresolvedStaticFieldSet);
 };
 
 // Implement the move-exception DEX instruction.
@@ -6350,8 +6505,8 @@
 
   DECLARE_INSTRUCTION(LoadException);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HLoadException);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(LoadException);
 };
 
 // Implicit part of move-exception which clears thread-local exception storage.
@@ -6363,8 +6518,8 @@
 
   DECLARE_INSTRUCTION(ClearException);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HClearException);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(ClearException);
 };
 
 class HThrow FINAL : public HTemplateInstruction<1> {
@@ -6380,11 +6535,10 @@
 
   bool CanThrow() const OVERRIDE { return true; }
 
-
   DECLARE_INSTRUCTION(Throw);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HThrow);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Throw);
 };
 
 /**
@@ -6419,6 +6573,7 @@
     SetRawInputAt(1, constant);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
 
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
@@ -6446,6 +6601,9 @@
 
   DECLARE_INSTRUCTION(InstanceOf);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(InstanceOf);
+
  private:
   static constexpr size_t kFieldTypeCheckKind = kNumberOfExpressionPackedBits;
   static constexpr size_t kFieldTypeCheckKindSize =
@@ -6454,8 +6612,6 @@
   static constexpr size_t kNumberOfInstanceOfPackedBits = kFlagMustDoNullCheck + 1;
   static_assert(kNumberOfInstanceOfPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
   using TypeCheckKindField = BitField<TypeCheckKind, kFieldTypeCheckKind, kFieldTypeCheckKindSize>;
-
-  DISALLOW_COPY_AND_ASSIGN(HInstanceOf);
 };
 
 class HBoundType FINAL : public HExpression<1> {
@@ -6469,6 +6625,8 @@
     SetRawInputAt(0, input);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   // {Get,Set}Upper* should only be used in reference type propagation.
   const ReferenceTypeInfo& GetUpperBound() const { return upper_bound_; }
   bool GetUpperCanBeNull() const { return GetPackedFlag<kFlagUpperCanBeNull>(); }
@@ -6483,6 +6641,9 @@
 
   DECLARE_INSTRUCTION(BoundType);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(BoundType);
+
  private:
   // Represents the top constraint that can_be_null_ cannot exceed (i.e. if this
   // is false then CanBeNull() cannot be true).
@@ -6498,8 +6659,6 @@
   //     // uper_bound_ will be ClassX
   //   }
   ReferenceTypeInfo upper_bound_;
-
-  DISALLOW_COPY_AND_ASSIGN(HBoundType);
 };
 
 class HCheckCast FINAL : public HTemplateInstruction<2> {
@@ -6515,6 +6674,7 @@
     SetRawInputAt(1, constant);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
 
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
@@ -6535,6 +6695,9 @@
 
   DECLARE_INSTRUCTION(CheckCast);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(CheckCast);
+
  private:
   static constexpr size_t kFieldTypeCheckKind = kNumberOfGenericPackedBits;
   static constexpr size_t kFieldTypeCheckKindSize =
@@ -6543,8 +6706,6 @@
   static constexpr size_t kNumberOfCheckCastPackedBits = kFlagMustDoNullCheck + 1;
   static_assert(kNumberOfCheckCastPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
   using TypeCheckKindField = BitField<TypeCheckKind, kFieldTypeCheckKind, kFieldTypeCheckKindSize>;
-
-  DISALLOW_COPY_AND_ASSIGN(HCheckCast);
 };
 
 /**
@@ -6581,10 +6742,15 @@
     SetPackedField<BarrierKindField>(barrier_kind);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   MemBarrierKind GetBarrierKind() { return GetPackedField<BarrierKindField>(); }
 
   DECLARE_INSTRUCTION(MemoryBarrier);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(MemoryBarrier);
+
  private:
   static constexpr size_t kFieldBarrierKind = HInstruction::kNumberOfGenericPackedBits;
   static constexpr size_t kFieldBarrierKindSize =
@@ -6594,8 +6760,6 @@
   static_assert(kNumberOfMemoryBarrierPackedBits <= kMaxNumberOfPackedBits,
                 "Too many packed fields.");
   using BarrierKindField = BitField<MemBarrierKind, kFieldBarrierKind, kFieldBarrierKindSize>;
-
-  DISALLOW_COPY_AND_ASSIGN(HMemoryBarrier);
 };
 
 // A constructor fence orders all prior stores to fields that could be accessed via a final field of
@@ -6746,8 +6910,8 @@
 
   DECLARE_INSTRUCTION(ConstructorFence);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HConstructorFence);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(ConstructorFence);
 };
 
 class HMonitorOperation FINAL : public HTemplateInstruction<1> {
@@ -6781,6 +6945,9 @@
 
   DECLARE_INSTRUCTION(MonitorOperation);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(MonitorOperation);
+
  private:
   static constexpr size_t kFieldOperationKind = HInstruction::kNumberOfGenericPackedBits;
   static constexpr size_t kFieldOperationKindSize =
@@ -6790,9 +6957,6 @@
   static_assert(kNumberOfMonitorOperationPackedBits <= HInstruction::kMaxNumberOfPackedBits,
                 "Too many packed fields.");
   using OperationKindField = BitField<OperationKind, kFieldOperationKind, kFieldOperationKindSize>;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(HMonitorOperation);
 };
 
 class HSelect FINAL : public HExpression<3> {
@@ -6813,6 +6977,7 @@
     SetRawInputAt(2, condition);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   HInstruction* GetFalseValue() const { return InputAt(0); }
   HInstruction* GetTrueValue() const { return InputAt(1); }
   HInstruction* GetCondition() const { return InputAt(2); }
@@ -6828,8 +6993,8 @@
 
   DECLARE_INSTRUCTION(Select);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HSelect);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(Select);
 };
 
 class MoveOperands : public ArenaObject<kArenaAllocMoveOperands> {
@@ -6960,10 +7125,11 @@
 
   DECLARE_INSTRUCTION(ParallelMove);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(ParallelMove);
+
  private:
   ArenaVector<MoveOperands> moves_;
-
-  DISALLOW_COPY_AND_ASSIGN(HParallelMove);
 };
 
 // This instruction computes an intermediate address pointing in the 'middle' of an object. The
@@ -6982,6 +7148,7 @@
     SetRawInputAt(1, offset);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
     return true;
@@ -6993,8 +7160,8 @@
 
   DECLARE_INSTRUCTION(IntermediateAddress);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HIntermediateAddress);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(IntermediateAddress);
 };
 
 
@@ -7069,6 +7236,33 @@
   DISALLOW_COPY_AND_ASSIGN(HGraphDelegateVisitor);
 };
 
+// Create a clone of the instruction, insert it into the graph; replace the old one with a new
+// and remove the old instruction.
+HInstruction* ReplaceInstrOrPhiByClone(HInstruction* instr);
+
+// Create a clone for each clonable instructions/phis and replace the original with the clone.
+//
+// Used for testing individual instruction cloner.
+class CloneAndReplaceInstructionVisitor : public HGraphDelegateVisitor {
+ public:
+  explicit CloneAndReplaceInstructionVisitor(HGraph* graph)
+      : HGraphDelegateVisitor(graph), instr_replaced_by_clones_count(0) {}
+
+  void VisitInstruction(HInstruction* instruction) OVERRIDE {
+    if (instruction->IsClonable()) {
+      ReplaceInstrOrPhiByClone(instruction);
+      instr_replaced_by_clones_count++;
+    }
+  }
+
+  size_t GetInstrReplacedByClonesCount() const { return instr_replaced_by_clones_count; }
+
+ private:
+  size_t instr_replaced_by_clones_count;
+
+  DISALLOW_COPY_AND_ASSIGN(CloneAndReplaceInstructionVisitor);
+};
+
 // Iterator over the blocks that art part of the loop. Includes blocks part
 // of an inner loop. The order in which the blocks are iterated is on their
 // block id.
diff --git a/compiler/optimizing/nodes_mips.h b/compiler/optimizing/nodes_mips.h
index ef388c3..2c0595e 100644
--- a/compiler/optimizing/nodes_mips.h
+++ b/compiler/optimizing/nodes_mips.h
@@ -30,8 +30,8 @@
 
   DECLARE_INSTRUCTION(MipsComputeBaseMethodAddress);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HMipsComputeBaseMethodAddress);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(MipsComputeBaseMethodAddress);
 };
 
 // Mips version of HPackedSwitch that holds a pointer to the base method address.
@@ -62,11 +62,12 @@
 
   DECLARE_INSTRUCTION(MipsPackedSwitch);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(MipsPackedSwitch);
+
  private:
   const int32_t start_value_;
   const int32_t num_entries_;
-
-  DISALLOW_COPY_AND_ASSIGN(HMipsPackedSwitch);
 };
 
 // This instruction computes part of the array access offset (index offset).
@@ -105,8 +106,8 @@
 
   DECLARE_INSTRUCTION(IntermediateArrayAddressIndex);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HIntermediateArrayAddressIndex);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(IntermediateArrayAddressIndex);
 };
 
 }  // namespace art
diff --git a/compiler/optimizing/nodes_shared.h b/compiler/optimizing/nodes_shared.h
index 7b4f5f7..e837f1e 100644
--- a/compiler/optimizing/nodes_shared.h
+++ b/compiler/optimizing/nodes_shared.h
@@ -38,6 +38,8 @@
     SetRawInputAt(kInputMulRightIndex, mul_right);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   static constexpr int kInputAccumulatorIndex = 0;
   static constexpr int kInputMulLeftIndex = 1;
   static constexpr int kInputMulRightIndex = 2;
@@ -51,11 +53,12 @@
 
   DECLARE_INSTRUCTION(MultiplyAccumulate);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(MultiplyAccumulate);
+
  private:
   // Indicates if this is a MADD or MSUB.
   const InstructionKind op_kind_;
-
-  DISALLOW_COPY_AND_ASSIGN(HMultiplyAccumulate);
 };
 
 class HBitwiseNegatedRight FINAL : public HBinaryOperation {
@@ -111,11 +114,12 @@
 
   DECLARE_INSTRUCTION(BitwiseNegatedRight);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(BitwiseNegatedRight);
+
  private:
   // Specifies the bitwise operation, which will be then negated.
   const InstructionKind op_kind_;
-
-  DISALLOW_COPY_AND_ASSIGN(HBitwiseNegatedRight);
 };
 
 // This instruction computes part of the array access offset (data and index offset).
@@ -145,6 +149,7 @@
     SetRawInputAt(2, shift);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
     return true;
@@ -157,8 +162,8 @@
 
   DECLARE_INSTRUCTION(IntermediateAddressIndex);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HIntermediateAddressIndex);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(IntermediateAddressIndex);
 };
 
 class HDataProcWithShifterOp FINAL : public HExpression<2> {
@@ -198,6 +203,7 @@
     SetRawInputAt(1, right);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other_instr) const OVERRIDE {
     const HDataProcWithShifterOp* other = other_instr->AsDataProcWithShifterOp();
@@ -225,14 +231,15 @@
 
   DECLARE_INSTRUCTION(DataProcWithShifterOp);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(DataProcWithShifterOp);
+
  private:
   InstructionKind instr_kind_;
   OpKind op_kind_;
   int shift_amount_;
 
   friend std::ostream& operator<<(std::ostream& os, OpKind op);
-
-  DISALLOW_COPY_AND_ASSIGN(HDataProcWithShifterOp);
 };
 
 std::ostream& operator<<(std::ostream& os, const HDataProcWithShifterOp::OpKind op);
diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h
index 17540b9..59d5b9f 100644
--- a/compiler/optimizing/nodes_vector.h
+++ b/compiler/optimizing/nodes_vector.h
@@ -161,10 +161,10 @@
   static_assert(kNumberOfVectorOpPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
   using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>;
 
+  DEFAULT_COPY_CONSTRUCTOR(VecOperation);
+
  private:
   const size_t vector_length_;
-
-  DISALLOW_COPY_AND_ASSIGN(HVecOperation);
 };
 
 // Abstraction of a unary vector operation.
@@ -188,8 +188,8 @@
 
   DECLARE_ABSTRACT_INSTRUCTION(VecUnaryOperation);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecUnaryOperation);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecUnaryOperation);
 };
 
 // Abstraction of a binary vector operation.
@@ -216,8 +216,8 @@
 
   DECLARE_ABSTRACT_INSTRUCTION(VecBinaryOperation);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecBinaryOperation);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecBinaryOperation);
 };
 
 // Abstraction of a vector operation that references memory, with an alignment.
@@ -255,10 +255,11 @@
 
   DECLARE_ABSTRACT_INSTRUCTION(VecMemoryOperation);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecMemoryOperation);
+
  private:
   Alignment alignment_;
-
-  DISALLOW_COPY_AND_ASSIGN(HVecMemoryOperation);
 };
 
 // Packed type consistency checker ("same vector length" integral types may mix freely).
@@ -296,8 +297,8 @@
 
   DECLARE_INSTRUCTION(VecReplicateScalar);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecReplicateScalar);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecReplicateScalar);
 };
 
 // Extracts a particular scalar from the given vector,
@@ -329,8 +330,8 @@
 
   DECLARE_INSTRUCTION(VecExtractScalar);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecExtractScalar);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecExtractScalar);
 };
 
 // Reduces the given vector into the first element as sum/min/max,
@@ -367,10 +368,11 @@
 
   DECLARE_INSTRUCTION(VecReduce);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecReduce);
+
  private:
   const ReductionKind kind_;
-
-  DISALLOW_COPY_AND_ASSIGN(HVecReduce);
 };
 
 // Converts every component in the vector,
@@ -394,8 +396,8 @@
 
   DECLARE_INSTRUCTION(VecCnv);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecCnv);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecCnv);
 };
 
 // Negates every component in the vector,
@@ -415,8 +417,8 @@
 
   DECLARE_INSTRUCTION(VecNeg);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecNeg);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecNeg);
 };
 
 // Takes absolute value of every component in the vector,
@@ -437,8 +439,8 @@
 
   DECLARE_INSTRUCTION(VecAbs);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecAbs);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecAbs);
 };
 
 // Bitwise- or boolean-nots every component in the vector,
@@ -459,8 +461,8 @@
 
   DECLARE_INSTRUCTION(VecNot);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecNot);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecNot);
 };
 
 //
@@ -486,8 +488,8 @@
 
   DECLARE_INSTRUCTION(VecAdd);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecAdd);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecAdd);
 };
 
 // Performs halving add on every component in the two vectors, viz.
@@ -531,14 +533,15 @@
 
   DECLARE_INSTRUCTION(VecHalvingAdd);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecHalvingAdd);
+
  private:
   // Additional packed bits.
   static constexpr size_t kFieldHAddIsUnsigned = HVecOperation::kNumberOfVectorOpPackedBits;
   static constexpr size_t kFieldHAddIsRounded = kFieldHAddIsUnsigned + 1;
   static constexpr size_t kNumberOfHAddPackedBits = kFieldHAddIsRounded + 1;
   static_assert(kNumberOfHAddPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
-
-  DISALLOW_COPY_AND_ASSIGN(HVecHalvingAdd);
 };
 
 // Subtracts every component in the two vectors,
@@ -560,8 +563,8 @@
 
   DECLARE_INSTRUCTION(VecSub);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecSub);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecSub);
 };
 
 // Multiplies every component in the two vectors,
@@ -583,8 +586,8 @@
 
   DECLARE_INSTRUCTION(VecMul);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecMul);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecMul);
 };
 
 // Divides every component in the two vectors,
@@ -606,8 +609,8 @@
 
   DECLARE_INSTRUCTION(VecDiv);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecDiv);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecDiv);
 };
 
 // Takes minimum of every component in the two vectors,
@@ -645,13 +648,14 @@
 
   DECLARE_INSTRUCTION(VecMin);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecMin);
+
  private:
   // Additional packed bits.
   static constexpr size_t kFieldMinOpIsUnsigned = HVecOperation::kNumberOfVectorOpPackedBits;
   static constexpr size_t kNumberOfMinOpPackedBits = kFieldMinOpIsUnsigned + 1;
   static_assert(kNumberOfMinOpPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
-
-  DISALLOW_COPY_AND_ASSIGN(HVecMin);
 };
 
 // Takes maximum of every component in the two vectors,
@@ -689,13 +693,14 @@
 
   DECLARE_INSTRUCTION(VecMax);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecMax);
+
  private:
   // Additional packed bits.
   static constexpr size_t kFieldMaxOpIsUnsigned = HVecOperation::kNumberOfVectorOpPackedBits;
   static constexpr size_t kNumberOfMaxOpPackedBits = kFieldMaxOpIsUnsigned + 1;
   static_assert(kNumberOfMaxOpPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
-
-  DISALLOW_COPY_AND_ASSIGN(HVecMax);
 };
 
 // Bitwise-ands every component in the two vectors,
@@ -716,8 +721,8 @@
 
   DECLARE_INSTRUCTION(VecAnd);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecAnd);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecAnd);
 };
 
 // Bitwise-and-nots every component in the two vectors,
@@ -738,8 +743,8 @@
 
   DECLARE_INSTRUCTION(VecAndNot);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecAndNot);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecAndNot);
 };
 
 // Bitwise-ors every component in the two vectors,
@@ -760,8 +765,8 @@
 
   DECLARE_INSTRUCTION(VecOr);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecOr);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecOr);
 };
 
 // Bitwise-xors every component in the two vectors,
@@ -782,8 +787,8 @@
 
   DECLARE_INSTRUCTION(VecXor);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecXor);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecXor);
 };
 
 // Logically shifts every component in the vector left by the given distance,
@@ -804,8 +809,8 @@
 
   DECLARE_INSTRUCTION(VecShl);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecShl);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecShl);
 };
 
 // Arithmetically shifts every component in the vector right by the given distance,
@@ -826,8 +831,8 @@
 
   DECLARE_INSTRUCTION(VecShr);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecShr);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecShr);
 };
 
 // Logically shifts every component in the vector right by the given distance,
@@ -848,8 +853,8 @@
 
   DECLARE_INSTRUCTION(VecUShr);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecUShr);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecUShr);
 };
 
 //
@@ -885,8 +890,8 @@
 
   DECLARE_INSTRUCTION(VecSetScalars);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecSetScalars);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecSetScalars);
 };
 
 // Multiplies every component in the two vectors, adds the result vector to the accumulator vector,
@@ -929,11 +934,12 @@
 
   DECLARE_INSTRUCTION(VecMultiplyAccumulate);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecMultiplyAccumulate);
+
  private:
   // Indicates if this is a MADD or MSUB.
   const InstructionKind op_kind_;
-
-  DISALLOW_COPY_AND_ASSIGN(HVecMultiplyAccumulate);
 };
 
 // Takes the absolute difference of two vectors, and adds the results to
@@ -968,8 +974,8 @@
 
   DECLARE_INSTRUCTION(VecSADAccumulate);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecSADAccumulate);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecSADAccumulate);
 };
 
 // Loads a vector from memory, viz. load(mem, 1)
@@ -1007,13 +1013,14 @@
 
   DECLARE_INSTRUCTION(VecLoad);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecLoad);
+
  private:
   // Additional packed bits.
   static constexpr size_t kFieldIsStringCharAt = HVecOperation::kNumberOfVectorOpPackedBits;
   static constexpr size_t kNumberOfVecLoadPackedBits = kFieldIsStringCharAt + 1;
   static_assert(kNumberOfVecLoadPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
-
-  DISALLOW_COPY_AND_ASSIGN(HVecLoad);
 };
 
 // Stores a vector to memory, viz. store(m, 1, [x1, .. , xn] )
@@ -1045,8 +1052,8 @@
 
   DECLARE_INSTRUCTION(VecStore);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HVecStore);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(VecStore)
 };
 
 }  // namespace art
diff --git a/compiler/optimizing/nodes_x86.h b/compiler/optimizing/nodes_x86.h
index 22e92ea..6326065 100644
--- a/compiler/optimizing/nodes_x86.h
+++ b/compiler/optimizing/nodes_x86.h
@@ -30,8 +30,8 @@
 
   DECLARE_INSTRUCTION(X86ComputeBaseMethodAddress);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HX86ComputeBaseMethodAddress);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(X86ComputeBaseMethodAddress);
 };
 
 // Load a constant value from the constant table.
@@ -54,8 +54,8 @@
 
   DECLARE_INSTRUCTION(X86LoadFromConstantTable);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HX86LoadFromConstantTable);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(X86LoadFromConstantTable);
 };
 
 // Version of HNeg with access to the constant table for FP types.
@@ -77,8 +77,8 @@
 
   DECLARE_INSTRUCTION(X86FPNeg);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(HX86FPNeg);
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(X86FPNeg);
 };
 
 // X86 version of HPackedSwitch that holds a pointer to the base method address.
@@ -113,11 +113,12 @@
 
   DECLARE_INSTRUCTION(X86PackedSwitch);
 
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(X86PackedSwitch);
+
  private:
   const int32_t start_value_;
   const int32_t num_entries_;
-
-  DISALLOW_COPY_AND_ASSIGN(HX86PackedSwitch);
 };
 
 }  // namespace art