Minor object store optimizations.

- Avoid emitting write barrier when the value is null.
- Do not do a typecheck on an arraystore when storing something that
  was loaded from the same array.

Change-Id: I902492928692e4553b5af0fc99cce3c2186c442a
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index ac4fc67..a046ade 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -168,6 +168,15 @@
 
   void EmitParallelMoves(Location from1, Location to1, Location from2, Location to2);
 
+  static bool StoreNeedsWriteBarrier(Primitive::Type type, HInstruction* value) {
+    if (kIsDebugBuild) {
+      if (type == Primitive::kPrimNot && value->IsIntConstant()) {
+        CHECK(value->AsIntConstant()->GetValue() == 0);
+      }
+    }
+    return type == Primitive::kPrimNot && !value->IsIntConstant();
+  }
+
  protected:
   CodeGenerator(HGraph* graph,
                 size_t number_of_core_registers,
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 6f5a3cb..9745eda 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1918,11 +1918,12 @@
 void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(instruction->GetFieldType(), instruction->GetValue());
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
   // Temporary registers for the write barrier.
-  if (is_object_type) {
+  if (needs_write_barrier) {
     locations->AddTemp(Location::RequiresRegister());
     locations->AddTemp(Location::RequiresRegister());
   }
@@ -1953,7 +1954,7 @@
     case Primitive::kPrimNot: {
       Register value = locations->InAt(1).As<Register>();
       __ StoreToOffset(kStoreWord, value, obj, offset);
-      if (field_type == Primitive::kPrimNot) {
+      if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
         Register temp = locations->GetTemp(0).As<Register>();
         Register card = locations->GetTemp(1).As<Register>();
         codegen_->MarkGCCard(temp, card, obj, value);
@@ -2186,10 +2187,14 @@
 
 void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
   Primitive::Type value_type = instruction->GetComponentType();
-  bool is_object = value_type == Primitive::kPrimNot;
+
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+  bool needs_runtime_call = instruction->NeedsTypeCheck();
+
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
-      instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
-  if (is_object) {
+      instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
+  if (needs_runtime_call) {
     InvokeRuntimeCallingConvention calling_convention;
     locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
     locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
@@ -2198,6 +2203,12 @@
     locations->SetInAt(0, Location::RequiresRegister());
     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
     locations->SetInAt(2, Location::RequiresRegister());
+
+    if (needs_write_barrier) {
+      // Temporary registers for the write barrier.
+      locations->AddTemp(Location::RequiresRegister());
+      locations->AddTemp(Location::RequiresRegister());
+    }
   }
 }
 
@@ -2206,6 +2217,9 @@
   Register obj = locations->InAt(0).As<Register>();
   Location index = locations->InAt(1);
   Primitive::Type value_type = instruction->GetComponentType();
+  bool needs_runtime_call = locations->WillCall();
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
 
   switch (value_type) {
     case Primitive::kPrimBoolean:
@@ -2236,21 +2250,29 @@
       break;
     }
 
-    case Primitive::kPrimInt: {
-      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
-      Register value = locations->InAt(2).As<Register>();
-      if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
-        __ StoreToOffset(kStoreWord, value, obj, offset);
-      } else {
-        __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
-        __ StoreToOffset(kStoreWord, value, IP, data_offset);
-      }
-      break;
-    }
-
+    case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
+      if (!needs_runtime_call) {
+        uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+        Register value = locations->InAt(2).As<Register>();
+        if (index.IsConstant()) {
+          size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+          __ StoreToOffset(kStoreWord, value, obj, offset);
+        } else {
+          DCHECK(index.IsRegister()) << index;
+          __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
+          __ StoreToOffset(kStoreWord, value, IP, data_offset);
+        }
+        if (needs_write_barrier) {
+          DCHECK_EQ(value_type, Primitive::kPrimNot);
+          Register temp = locations->GetTemp(0).As<Register>();
+          Register card = locations->GetTemp(1).As<Register>();
+          codegen_->MarkGCCard(temp, card, obj, value);
+        }
+      } else {
+        DCHECK_EQ(value_type, Primitive::kPrimNot);
+        codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
+      }
       break;
     }
 
@@ -2602,11 +2624,12 @@
 void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(instruction->GetFieldType(), instruction->GetValue());
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
   // Temporary registers for the write barrier.
-  if (is_object_type) {
+  if (needs_write_barrier) {
     locations->AddTemp(Location::RequiresRegister());
     locations->AddTemp(Location::RequiresRegister());
   }
@@ -2637,7 +2660,7 @@
     case Primitive::kPrimNot: {
       Register value = locations->InAt(1).As<Register>();
       __ StoreToOffset(kStoreWord, value, cls, offset);
-      if (field_type == Primitive::kPrimNot) {
+      if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
         Register temp = locations->GetTemp(0).As<Register>();
         Register card = locations->GetTemp(1).As<Register>();
         codegen_->MarkGCCard(temp, card, cls, value);
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 100f380..b8518f1 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -42,6 +42,9 @@
 static constexpr XmmRegister kRuntimeParameterFpuRegisters[] = { };
 static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
 
+// Marker for places that can be updated once we don't follow the quick ABI.
+static constexpr bool kFollowsQuickABI = true;
+
 class InvokeRuntimeCallingConvention : public CallingConvention<Register, XmmRegister> {
  public:
   InvokeRuntimeCallingConvention()
@@ -427,6 +430,7 @@
   blocked_core_registers_[ESP] = true;
 
   // TODO: We currently don't use Quick's callee saved registers.
+  DCHECK(kFollowsQuickABI);
   blocked_core_registers_[EBP] = true;
   blocked_core_registers_[ESI] = true;
   blocked_core_registers_[EDI] = true;
@@ -1931,7 +1935,9 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   Primitive::Type field_type = instruction->GetFieldType();
-  bool is_object_type = field_type == Primitive::kPrimNot;
+  bool needs_write_barrier =
+    CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
+
   bool is_byte_type = (field_type == Primitive::kPrimBoolean)
       || (field_type == Primitive::kPrimByte);
   // The register allocator does not support multiple
@@ -1943,7 +1949,7 @@
     locations->SetInAt(1, Location::RequiresRegister());
   }
   // Temporary registers for the write barrier.
-  if (is_object_type) {
+  if (needs_write_barrier) {
     locations->AddTemp(Location::RequiresRegister());
     // Ensure the card is in a byte register.
     locations->AddTemp(Location::RegisterLocation(ECX));
@@ -1976,7 +1982,7 @@
       Register value = locations->InAt(1).As<Register>();
       __ movl(Address(obj, offset), value);
 
-      if (field_type == Primitive::kPrimNot) {
+      if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
         Register temp = locations->GetTemp(0).As<Register>();
         Register card = locations->GetTemp(1).As<Register>();
         codegen_->MarkGCCard(temp, card, obj, value);
@@ -2222,11 +2228,20 @@
 
 void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
   Primitive::Type value_type = instruction->GetComponentType();
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+
+  DCHECK(kFollowsQuickABI);
+  bool not_enough_registers = needs_write_barrier
+      && !instruction->GetValue()->IsConstant()
+      && !instruction->GetIndex()->IsConstant();
+  bool needs_runtime_call = instruction->NeedsTypeCheck() || not_enough_registers;
+
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
       instruction,
-      value_type == Primitive::kPrimNot ? LocationSummary::kCall : LocationSummary::kNoCall);
+      needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
 
-  if (value_type == Primitive::kPrimNot) {
+  if (needs_runtime_call) {
     InvokeRuntimeCallingConvention calling_convention;
     locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
     locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
@@ -2245,6 +2260,12 @@
     } else {
       locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
     }
+    // Temporary registers for the write barrier.
+    if (needs_write_barrier) {
+      locations->AddTemp(Location::RequiresRegister());
+      // Ensure the card is in a byte register.
+      locations->AddTemp(Location::RegisterLocation(ECX));
+    }
   }
 }
 
@@ -2254,6 +2275,9 @@
   Location index = locations->InAt(1);
   Location value = locations->InAt(2);
   Primitive::Type value_type = instruction->GetComponentType();
+  bool needs_runtime_call = locations->WillCall();
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
 
   switch (value_type) {
     case Primitive::kPrimBoolean:
@@ -2302,34 +2326,45 @@
       break;
     }
 
-    case Primitive::kPrimInt: {
-      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
-      if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
-        if (value.IsRegister()) {
-          __ movl(Address(obj, offset), value.As<Register>());
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot: {
+      if (!needs_runtime_call) {
+        uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+        if (index.IsConstant()) {
+          size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+          if (value.IsRegister()) {
+            __ movl(Address(obj, offset), value.As<Register>());
+          } else {
+            DCHECK(value.IsConstant()) << value;
+            __ movl(Address(obj, offset),
+                    Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+          }
         } else {
-          __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+          DCHECK(index.IsRegister()) << index;
+          if (value.IsRegister()) {
+            __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
+                    value.As<Register>());
+          } else {
+            DCHECK(value.IsConstant()) << value;
+            __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
+                    Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+          }
+        }
+
+        if (needs_write_barrier) {
+          Register temp = locations->GetTemp(0).As<Register>();
+          Register card = locations->GetTemp(1).As<Register>();
+          codegen_->MarkGCCard(temp, card, obj, value.As<Register>());
         }
       } else {
-        if (value.IsRegister()) {
-          __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
-                  value.As<Register>());
-        } else {
-          __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
-                  Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
-        }
+        DCHECK_EQ(value_type, Primitive::kPrimNot);
+        DCHECK(!codegen_->IsLeafMethod());
+        __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
+        codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
       }
       break;
     }
 
-    case Primitive::kPrimNot: {
-      DCHECK(!codegen_->IsLeafMethod());
-      __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
-      codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
-      break;
-    }
-
     case Primitive::kPrimLong: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
       if (index.IsConstant()) {
@@ -2694,7 +2729,8 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   Primitive::Type field_type = instruction->GetFieldType();
-  bool is_object_type = field_type == Primitive::kPrimNot;
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
   bool is_byte_type = (field_type == Primitive::kPrimBoolean)
       || (field_type == Primitive::kPrimByte);
   // The register allocator does not support multiple
@@ -2706,7 +2742,7 @@
     locations->SetInAt(1, Location::RequiresRegister());
   }
   // Temporary registers for the write barrier.
-  if (is_object_type) {
+  if (needs_write_barrier) {
     locations->AddTemp(Location::RequiresRegister());
     // Ensure the card is in a byte register.
     locations->AddTemp(Location::RegisterLocation(ECX));
@@ -2739,7 +2775,7 @@
       Register value = locations->InAt(1).As<Register>();
       __ movl(Address(cls, offset), value);
 
-      if (field_type == Primitive::kPrimNot) {
+      if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
         Register temp = locations->GetTemp(0).As<Register>();
         Register card = locations->GetTemp(1).As<Register>();
         codegen_->MarkGCCard(temp, card, cls, value);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 6f3b161..23b8bd7 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1825,10 +1825,11 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   Primitive::Type field_type = instruction->GetFieldType();
-  bool is_object_type = field_type == Primitive::kPrimNot;
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue());
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
-  if (is_object_type) {
+  if (needs_write_barrier) {
     // Temporary registers for the write barrier.
     locations->AddTemp(Location::RequiresRegister());
     locations->AddTemp(Location::RequiresRegister());
@@ -1860,7 +1861,7 @@
     case Primitive::kPrimNot: {
       CpuRegister value = locations->InAt(1).As<CpuRegister>();
       __ movl(Address(obj, offset), value);
-      if (field_type == Primitive::kPrimNot) {
+      if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
         CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
         CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
         codegen_->MarkGCCard(temp, card, obj, value);
@@ -2110,10 +2111,14 @@
 
 void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
   Primitive::Type value_type = instruction->GetComponentType();
-  bool is_object = value_type == Primitive::kPrimNot;
+
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+  bool needs_runtime_call = instruction->NeedsTypeCheck();
+
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
-      instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
-  if (is_object) {
+      instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
+  if (needs_runtime_call) {
     InvokeRuntimeCallingConvention calling_convention;
     locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
     locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
@@ -2130,6 +2135,12 @@
     } else {
       locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
     }
+
+    if (needs_write_barrier) {
+      // Temporary registers for the write barrier.
+      locations->AddTemp(Location::RequiresRegister());
+      locations->AddTemp(Location::RequiresRegister());
+    }
   }
 }
 
@@ -2139,6 +2150,9 @@
   Location index = locations->InAt(1);
   Location value = locations->InAt(2);
   Primitive::Type value_type = instruction->GetComponentType();
+  bool needs_runtime_call = locations->WillCall();
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
 
   switch (value_type) {
     case Primitive::kPrimBoolean:
@@ -2171,46 +2185,61 @@
         if (value.IsRegister()) {
           __ movw(Address(obj, offset), value.As<CpuRegister>());
         } else {
+          DCHECK(value.IsConstant()) << value;
           __ movw(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
         }
       } else {
+        DCHECK(index.IsRegister()) << index;
         if (value.IsRegister()) {
           __ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
                   value.As<CpuRegister>());
         } else {
-          __ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
-                  Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
-        }
-      }
-      break;
-    }
-
-    case Primitive::kPrimInt: {
-      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
-      if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
-        if (value.IsRegister()) {
-          __ movl(Address(obj, offset), value.As<CpuRegister>());
-        } else {
-          __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
-        }
-      } else {
-        if (value.IsRegister()) {
-          __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
-                  value.As<CpuRegister>());
-        } else {
           DCHECK(value.IsConstant()) << value;
-          __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
+          __ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
                   Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
         }
       }
       break;
     }
 
+    case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
-      DCHECK(!codegen_->IsLeafMethod());
-      codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+      if (!needs_runtime_call) {
+        uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+        if (index.IsConstant()) {
+          size_t offset =
+              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+          if (value.IsRegister()) {
+            __ movl(Address(obj, offset), value.As<CpuRegister>());
+          } else {
+            DCHECK(value.IsConstant()) << value;
+            __ movl(Address(obj, offset),
+                    Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+          }
+        } else {
+          DCHECK(index.IsRegister()) << index;
+          if (value.IsRegister()) {
+            __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
+                    value.As<CpuRegister>());
+          } else {
+            DCHECK(value.IsConstant()) << value;
+            __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
+                    Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+          }
+        }
+
+        if (needs_write_barrier) {
+          DCHECK_EQ(value_type, Primitive::kPrimNot);
+          CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
+          CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
+          codegen_->MarkGCCard(temp, card, obj, value.As<CpuRegister>());
+        }
+      } else {
+        DCHECK_EQ(value_type, Primitive::kPrimNot);
+        __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
+        DCHECK(!codegen_->IsLeafMethod());
+        codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+      }
       break;
     }
 
@@ -2692,10 +2721,11 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   Primitive::Type field_type = instruction->GetFieldType();
-  bool is_object_type = field_type == Primitive::kPrimNot;
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue());
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
-  if (is_object_type) {
+  if (needs_write_barrier) {
     // Temporary registers for the write barrier.
     locations->AddTemp(Location::RequiresRegister());
     locations->AddTemp(Location::RequiresRegister());
@@ -2727,7 +2757,7 @@
     case Primitive::kPrimNot: {
       CpuRegister value = locations->InAt(1).As<CpuRegister>();
       __ movl(Address(cls, offset), value);
-      if (field_type == Primitive::kPrimNot) {
+      if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
         CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
         CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
         codegen_->MarkGCCard(temp, card, cls, value);
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 29eabe7..3e8361e 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -55,4 +55,16 @@
   }
 }
 
+void InstructionSimplifier::VisitArraySet(HArraySet* instruction) {
+  HInstruction* value = instruction->GetValue();
+  if (value->GetType() != Primitive::kPrimNot) return;
+
+  if (value->IsArrayGet()) {
+    if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
+      // If the code is just swapping elements in the array, no need for a type check.
+      instruction->ClearNeedsTypeCheck();
+    }
+  }
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h
index d74b624..3844d57 100644
--- a/compiler/optimizing/instruction_simplifier.h
+++ b/compiler/optimizing/instruction_simplifier.h
@@ -33,6 +33,7 @@
  private:
   virtual void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
   virtual void VisitEqual(HEqual* equal) OVERRIDE;
+  virtual void VisitArraySet(HArraySet* equal) OVERRIDE;
 };
 
 }  // namespace art
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 6224a11..9e79748 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2030,6 +2030,8 @@
   MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
   Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
 
+  HInstruction* GetValue() const { return InputAt(1); }
+
   DECLARE_INSTRUCTION(InstanceFieldSet);
 
  private:
@@ -2046,13 +2048,16 @@
     SetRawInputAt(1, index);
   }
 
-  virtual bool CanBeMoved() const { return true; }
-  virtual bool InstructionDataEquals(HInstruction* other) const {
+  bool CanBeMoved() const OVERRIDE { return true; }
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
     UNUSED(other);
     return true;
   }
   void SetType(Primitive::Type type) { type_ = type; }
 
+  HInstruction* GetArray() const { return InputAt(0); }
+  HInstruction* GetIndex() const { return InputAt(1); }
+
   DECLARE_INSTRUCTION(ArrayGet);
 
  private:
@@ -2068,20 +2073,29 @@
             uint32_t dex_pc)
       : HTemplateInstruction(SideEffects::ChangesSomething()),
         dex_pc_(dex_pc),
-        expected_component_type_(expected_component_type) {
+        expected_component_type_(expected_component_type),
+        needs_type_check_(value->GetType() == Primitive::kPrimNot) {
     SetRawInputAt(0, array);
     SetRawInputAt(1, index);
     SetRawInputAt(2, value);
   }
 
-  virtual bool NeedsEnvironment() const {
+  bool NeedsEnvironment() const {
     // We currently always call a runtime method to catch array store
     // exceptions.
-    return InputAt(2)->GetType() == Primitive::kPrimNot;
+    return needs_type_check_;
   }
 
+  void ClearNeedsTypeCheck() {
+    needs_type_check_ = false;
+  }
+
+  bool NeedsTypeCheck() const { return needs_type_check_; }
+
   uint32_t GetDexPc() const { return dex_pc_; }
 
+  HInstruction* GetArray() const { return InputAt(0); }
+  HInstruction* GetIndex() const { return InputAt(1); }
   HInstruction* GetValue() const { return InputAt(2); }
 
   Primitive::Type GetComponentType() const {
@@ -2100,6 +2114,7 @@
  private:
   const uint32_t dex_pc_;
   const Primitive::Type expected_component_type_;
+  bool needs_type_check_;
 
   DISALLOW_COPY_AND_ASSIGN(HArraySet);
 };
@@ -2368,6 +2383,8 @@
   MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
   Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
 
+  HInstruction* GetValue() const { return InputAt(1); }
+
   DECLARE_INSTRUCTION(StaticFieldSet);
 
  private:
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 6e3653a..ee92e89 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -286,6 +286,7 @@
     InstructionSimplifier(graph).Run();
     GlobalValueNumberer(graph->GetArena(), graph).Run();
     visualizer.DumpGraph(kGVNPassName);
+    InstructionSimplifier(graph).Run();
     PrepareForRegisterAllocation(graph).Run();
 
     SsaLivenessAnalysis liveness(*graph, codegen);