Record implicit null checks at the actual invoke time.

ImplicitNullChecks are recorded only for instructions directly (see NB
below) preceeded by NullChecks in the graph. This way we avoid recording
redundant safepoints and minimize the code size increase.

NB: ParallalelMoves might be inserted by the register allocator between
the NullChecks and their uses. These modify the environment and the
correct action would be to reverse their modification. This will be
addressed in a follow-up CL.

Change-Id: Ie50006e5a4bd22932dcf11348f5a655d253cd898
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 07c84bc..980de04 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1226,6 +1226,7 @@
   } else {
     __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
   }
+  codegen_->MaybeRecordImplicitNullCheck(invoke);
   // temp = temp->GetMethodAt(method_offset);
   uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
       kArmWordSize).Int32Value();
@@ -1264,6 +1265,7 @@
   } else {
     __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
   }
+  codegen_->MaybeRecordImplicitNullCheck(invoke);
   // temp = temp->GetImtEntryAt(method_offset);
   uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
       kArmWordSize).Int32Value();
@@ -2579,7 +2581,8 @@
                                                           Register value_lo,
                                                           Register value_hi,
                                                           Register temp1,
-                                                          Register temp2) {
+                                                          Register temp2,
+                                                          HInstruction* instruction) {
   Label fail;
   if (offset != 0) {
     __ LoadImmediate(temp1, offset);
@@ -2590,6 +2593,7 @@
   // We need a load followed by store. (The address used in a STREX instruction must
   // be the same as the address in the most recently executed LDREX instruction.)
   __ ldrexd(temp1, temp2, addr);
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
   __ strexd(temp1, value_lo, value_hi, addr);
   __ cmp(temp1, ShifterOperand(0));
   __ b(&fail, NE);
@@ -2664,13 +2668,7 @@
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      Register value_reg = value.AsRegister<Register>();
-      __ StoreToOffset(kStoreWord, value_reg, base, offset);
-      if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
-        Register temp = locations->GetTemp(0).AsRegister<Register>();
-        Register card = locations->GetTemp(1).AsRegister<Register>();
-        codegen_->MarkGCCard(temp, card, base, value_reg);
-      }
+      __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
       break;
     }
 
@@ -2680,9 +2678,11 @@
                                 value.AsRegisterPairLow<Register>(),
                                 value.AsRegisterPairHigh<Register>(),
                                 locations->GetTemp(0).AsRegister<Register>(),
-                                locations->GetTemp(1).AsRegister<Register>());
+                                locations->GetTemp(1).AsRegister<Register>(),
+                                instruction);
       } else {
         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
       }
       break;
     }
@@ -2704,9 +2704,11 @@
                                 value_reg_lo,
                                 value_reg_hi,
                                 locations->GetTemp(2).AsRegister<Register>(),
-                                locations->GetTemp(3).AsRegister<Register>());
+                                locations->GetTemp(3).AsRegister<Register>(),
+                                instruction);
       } else {
         __ StoreDToOffset(value_reg, base, offset);
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
       }
       break;
     }
@@ -2716,6 +2718,17 @@
       UNREACHABLE();
   }
 
+  // Longs and doubles are handled in the switch.
+  if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
+    codegen_->MaybeRecordImplicitNullCheck(instruction);
+  }
+
+  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
+    Register temp = locations->GetTemp(0).AsRegister<Register>();
+    Register card = locations->GetTemp(1).AsRegister<Register>();
+    codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
+  }
+
   if (is_volatile) {
     GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
   }
@@ -2804,9 +2817,11 @@
         Register lo = locations->GetTemp(0).AsRegister<Register>();
         Register hi = locations->GetTemp(1).AsRegister<Register>();
         GenerateWideAtomicLoad(base, offset, lo, hi);
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
         __ vmovdrr(out_reg, lo, hi);
       } else {
         __ LoadDFromOffset(out_reg, base, offset);
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
       }
       break;
     }
@@ -2816,6 +2831,11 @@
       UNREACHABLE();
   }
 
+  // Doubles are handled in the switch.
+  if (field_type != Primitive::kPrimDouble) {
+    codegen_->MaybeRecordImplicitNullCheck(instruction);
+  }
+
   if (is_volatile) {
     GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   }
@@ -2856,17 +2876,18 @@
 void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
-      ? Location::RequiresRegister()
-      : Location::RegisterOrConstant(instruction->InputAt(0));
-  locations->SetInAt(0, loc);
+  locations->SetInAt(0, Location::RequiresRegister());
   if (instruction->HasUses()) {
     locations->SetOut(Location::SameAsFirstInput());
   }
 }
 
 void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
+  if (codegen_->CanMoveNullCheckToUser(instruction)) {
+    return;
+  }
   Location obj = instruction->GetLocations()->InAt(0);
+
   __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
 }
@@ -2878,14 +2899,8 @@
   LocationSummary* locations = instruction->GetLocations();
   Location obj = locations->InAt(0);
 
-  if (obj.IsRegister()) {
-    __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
-    __ b(slow_path->GetEntryLabel(), EQ);
-  } else {
-    DCHECK(obj.IsConstant()) << obj;
-    DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
-    __ b(slow_path->GetEntryLabel());
-  }
+  __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
+  __ b(slow_path->GetEntryLabel(), EQ);
 }
 
 void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
@@ -3028,6 +3043,7 @@
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
       UNREACHABLE();
   }
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
 }
 
 void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
@@ -3111,6 +3127,7 @@
           __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
           __ StoreToOffset(kStoreWord, value, IP, data_offset);
         }
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
         if (needs_write_barrier) {
           DCHECK_EQ(value_type, Primitive::kPrimNot);
           Register temp = locations->GetTemp(0).AsRegister<Register>();
@@ -3165,6 +3182,7 @@
         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
         __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
       }
+
       break;
     }
 
@@ -3172,6 +3190,11 @@
       LOG(FATAL) << "Unreachable type " << value_type;
       UNREACHABLE();
   }
+
+  // Ints and objects are handled in the switch.
+  if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
+    codegen_->MaybeRecordImplicitNullCheck(instruction);
+  }
 }
 
 void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
@@ -3187,6 +3210,7 @@
   Register obj = locations->InAt(0).AsRegister<Register>();
   Register out = locations->Out().AsRegister<Register>();
   __ LoadFromOffset(kLoadWord, out, obj, offset);
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
 }
 
 void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {