Do type checks in ArraySet without read barriers.

This approach is valid in the case of Baker and non-Baker
read barriers.

Benchmarks (ARM64) score variations on Nexus 5X with CPU
cores clamped at 960000 Hz (aosp_bullhead-userdebug build,
medians of 10 runs for each suite):
- Ritzperf - average (lower is better):       -0.44% (virtually unchanged)
- CaffeineMark - average (higher is better):  -0.20% (virtually unchanged)
- DeltaBlue (lower is better):                -4.08% (slightly better)
- Richards - average (lower is better):       -0.57% (virtually unchanged)
- SciMark2 - average (higher is better):      -0.52% (virtually unchanged)

Details about Ritzperf benchmarks with meaningful variations
(lower is better):
- GenericCalcActions.MemAllocTest:            +3.02% (slightly worse)

Details about Richards benchmarks with meaningful variations
(lower is better):
- gibbons                                     -5.01% (better)

Boot image code size variation on Nexus 5X
(aosp_bullhead-userdebug build):
- total ARM64 framework Oat files size change:
  83127840 bytes -> 83082656 bytes (-45184 bytes, -0.05%)
- total ARM framework Oat files size change:
  72571872 bytes -> 72522796 bytes (-49076 bytes, -0.07%)

Test: ART_USE_READ_BARRIER=true ART_HEAP_POISONING=true m test-art-host
Test: ART_USE_READ_BARRIER=true ART_HEAP_POISONING=true m test-art-target
Bug: 29516974
Bug: 12687968
Change-Id: I8fe130156ace87dd2e4a15d9f8b4111287e735b3
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index d8866a9..b9f2056 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -4619,7 +4619,6 @@
   }
   if (needs_write_barrier) {
     // Temporary registers for the write barrier.
-    // These registers may be used for Baker read barriers too.
     locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
     locations->AddTemp(Location::RequiresRegister());
   }
@@ -4737,127 +4736,42 @@
           __ Bind(&non_zero);
         }
 
-        if (kEmitCompilerReadBarrier) {
-          if (!kUseBakerReadBarrier) {
-            // When (non-Baker) read barriers are enabled, the type
-            // checking instrumentation requires two read barriers
-            // generated by CodeGeneratorARM::GenerateReadBarrierSlow:
-            //
-            //   __ Mov(temp2, temp1);
-            //   // /* HeapReference<Class> */ temp1 = temp1->component_type_
-            //   __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
-            //
-            //   // /* HeapReference<Class> */ temp2 = value->klass_
-            //   __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
-            //
-            //   __ cmp(temp1, ShifterOperand(temp2));
-            //
-            // However, the second read barrier may trash `temp`, as it
-            // is a temporary register, and as such would not be saved
-            // along with live registers before calling the runtime (nor
-            // restored afterwards).  So in this case, we bail out and
-            // delegate the work to the array set slow path.
-            //
-            // TODO: Extend the register allocator to support a new
-            // "(locally) live temp" location so as to avoid always
-            // going into the slow path when read barriers are enabled?
-            //
-            // There is no such problem with Baker read barriers (see below).
-            __ b(slow_path->GetEntryLabel());
-          } else {
-            Register temp3 = IP;
-            Location temp3_loc = Location::RegisterLocation(temp3);
+        // Note that when read barriers are enabled, the type checks
+        // are performed without read barriers.  This is fine, even in
+        // the case where a class object is in the from-space after
+        // the flip, as a comparison involving such a type would not
+        // produce a false positive; it may of course produce a false
+        // negative, in which case we would take the ArraySet slow
+        // path.
 
-            // Note: `temp3` (scratch register IP) cannot be used as
-            // `ref` argument of GenerateFieldLoadWithBakerReadBarrier
-            // calls below (see ReadBarrierMarkSlowPathARM for more
-            // details).
+        // /* HeapReference<Class> */ temp1 = array->klass_
+        __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ MaybeUnpoisonHeapReference(temp1);
 
-            // /* HeapReference<Class> */ temp1 = array->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
-                                                            temp1_loc,
-                                                            array,
-                                                            class_offset,
-                                                            temp3_loc,
-                                                            /* needs_null_check */ true);
+        // /* HeapReference<Class> */ temp1 = temp1->component_type_
+        __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
+        // /* HeapReference<Class> */ temp2 = value->klass_
+        __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
+        // If heap poisoning is enabled, no need to unpoison `temp1`
+        // nor `temp2`, as we are comparing two poisoned references.
+        __ cmp(temp1, ShifterOperand(temp2));
 
-            // /* HeapReference<Class> */ temp1 = temp1->component_type_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
-                                                            temp1_loc,
-                                                            temp1,
-                                                            component_offset,
-                                                            temp3_loc,
-                                                            /* needs_null_check */ false);
-            // Register `temp1` is not trashed by the read barrier
-            // emitted by GenerateFieldLoadWithBakerReadBarrier below,
-            // as that method produces a call to a ReadBarrierMarkRegX
-            // entry point, which saves all potentially live registers,
-            // including temporaries such a `temp1`.
-            // /* HeapReference<Class> */ temp2 = value->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
-                                                            temp2_loc,
-                                                            value,
-                                                            class_offset,
-                                                            temp3_loc,
-                                                            /* needs_null_check */ false);
-            // If heap poisoning is enabled, `temp1` and `temp2` have
-            // been unpoisoned by the the previous calls to
-            // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
-            __ cmp(temp1, ShifterOperand(temp2));
-
-            if (instruction->StaticTypeOfArrayIsObjectArray()) {
-              Label do_put;
-              __ b(&do_put, EQ);
-              // We do not need to emit a read barrier for the
-              // following heap reference load, as `temp1` is only used
-              // in a comparison with null below, and this reference
-              // is not kept afterwards.
-              // /* HeapReference<Class> */ temp1 = temp1->super_class_
-              __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
-              // If heap poisoning is enabled, no need to unpoison
-              // `temp`, as we are comparing against null below.
-              __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
-              __ Bind(&do_put);
-            } else {
-              __ b(slow_path->GetEntryLabel(), NE);
-            }
-          }
-        } else {
-          // Non read barrier code.
-
-          // /* HeapReference<Class> */ temp1 = array->klass_
-          __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
-          codegen_->MaybeRecordImplicitNullCheck(instruction);
+        if (instruction->StaticTypeOfArrayIsObjectArray()) {
+          Label do_put;
+          __ b(&do_put, EQ);
+          // If heap poisoning is enabled, the `temp1` reference has
+          // not been unpoisoned yet; unpoison it now.
           __ MaybeUnpoisonHeapReference(temp1);
 
-          // /* HeapReference<Class> */ temp1 = temp1->component_type_
-          __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
-          // /* HeapReference<Class> */ temp2 = value->klass_
-          __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
-          // If heap poisoning is enabled, no need to unpoison `temp1`
-          // nor `temp2`, as we are comparing two poisoned references.
-          __ cmp(temp1, ShifterOperand(temp2));
-
-          if (instruction->StaticTypeOfArrayIsObjectArray()) {
-            Label do_put;
-            __ b(&do_put, EQ);
-            // If heap poisoning is enabled, the `temp1` reference has
-            // not been unpoisoned yet; unpoison it now.
-            __ MaybeUnpoisonHeapReference(temp1);
-
-            // /* HeapReference<Class> */ temp1 = temp1->super_class_
-            __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
-            // If heap poisoning is enabled, no need to unpoison
-            // `temp1`, as we are comparing against null below.
-            __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
-            __ Bind(&do_put);
-          } else {
-            __ b(slow_path->GetEntryLabel(), NE);
-          }
+          // /* HeapReference<Class> */ temp1 = temp1->super_class_
+          __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
+          // If heap poisoning is enabled, no need to unpoison
+          // `temp1`, as we are comparing against null below.
+          __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
+          __ Bind(&do_put);
+        } else {
+          __ b(slow_path->GetEntryLabel(), NE);
         }
       }