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_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 87b6de3..12c4b2c 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -4759,7 +4759,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());
   }
@@ -4849,105 +4848,40 @@
           __ Bind(&not_null);
         }
 
-        if (kEmitCompilerReadBarrier) {
-          if (!kUseBakerReadBarrier) {
-            // When (non-Baker) read barriers are enabled, the type
-            // checking instrumentation requires two read barriers
-            // generated by CodeGeneratorX86_64::GenerateReadBarrierSlow:
-            //
-            //   __ movl(temp2, temp);
-            //   // /* HeapReference<Class> */ temp = temp->component_type_
-            //   __ movl(temp, Address(temp, component_offset));
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp_loc, temp_loc, temp2_loc, component_offset);
-            //
-            //   // /* HeapReference<Class> */ temp2 = register_value->klass_
-            //   __ movl(temp2, Address(register_value, class_offset));
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp2_loc, temp2_loc, value, class_offset, temp_loc);
-            //
-            //   __ cmpl(temp, 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).
-            __ jmp(slow_path->GetEntryLabel());
-          } else {
-            Location temp2_loc = locations->GetTemp(1);
-            CpuRegister temp2 = temp2_loc.AsRegister<CpuRegister>();
-            // /* HeapReference<Class> */ temp = array->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(
-                instruction, temp_loc, array, class_offset, /* needs_null_check */ true);
+        // Note that when Baker 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.
 
-            // /* HeapReference<Class> */ temp = temp->component_type_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(
-                instruction, temp_loc, temp, component_offset, /* needs_null_check */ false);
-            // Register `temp` 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 `temp`.
-            // /* HeapReference<Class> */ temp2 = register_value->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(
-                instruction, temp2_loc, register_value, class_offset, /* needs_null_check */ false);
-            // If heap poisoning is enabled, `temp` and `temp2` have
-            // been unpoisoned by the the previous calls to
-            // CodeGeneratorX86_64::GenerateFieldLoadWithBakerReadBarrier.
-            __ cmpl(temp, temp2);
+        // /* HeapReference<Class> */ temp = array->klass_
+        __ movl(temp, Address(array, class_offset));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ MaybeUnpoisonHeapReference(temp);
 
-            if (instruction->StaticTypeOfArrayIsObjectArray()) {
-              __ j(kEqual, &do_put);
-              // We do not need to emit a read barrier for the
-              // following heap reference load, as `temp` is only used
-              // in a comparison with null below, and this reference
-              // is not kept afterwards. Also, if heap poisoning is
-              // enabled, there is no need to unpoison that heap
-              // reference for the same reason (comparison with null).
-              __ cmpl(Address(temp, super_offset), Immediate(0));
-              __ j(kNotEqual, slow_path->GetEntryLabel());
-              __ Bind(&do_put);
-            } else {
-              __ j(kNotEqual, slow_path->GetEntryLabel());
-            }
-          }
-        } else {
-          // Non read barrier code.
+        // /* HeapReference<Class> */ temp = temp->component_type_
+        __ movl(temp, Address(temp, component_offset));
+        // If heap poisoning is enabled, no need to unpoison `temp`
+        // nor the object reference in `register_value->klass`, as
+        // we are comparing two poisoned references.
+        __ cmpl(temp, Address(register_value, class_offset));
 
-          // /* HeapReference<Class> */ temp = array->klass_
-          __ movl(temp, Address(array, class_offset));
-          codegen_->MaybeRecordImplicitNullCheck(instruction);
+        if (instruction->StaticTypeOfArrayIsObjectArray()) {
+          __ j(kEqual, &do_put);
+          // If heap poisoning is enabled, the `temp` reference has
+          // not been unpoisoned yet; unpoison it now.
           __ MaybeUnpoisonHeapReference(temp);
 
-          // /* HeapReference<Class> */ temp = temp->component_type_
-          __ movl(temp, Address(temp, component_offset));
-          // If heap poisoning is enabled, no need to unpoison `temp`
-          // nor the object reference in `register_value->klass`, as
-          // we are comparing two poisoned references.
-          __ cmpl(temp, Address(register_value, class_offset));
-
-          if (instruction->StaticTypeOfArrayIsObjectArray()) {
-            __ j(kEqual, &do_put);
-            // If heap poisoning is enabled, the `temp` reference has
-            // not been unpoisoned yet; unpoison it now.
-            __ MaybeUnpoisonHeapReference(temp);
-
-            // If heap poisoning is enabled, no need to unpoison the
-            // heap reference loaded below, as it is only used for a
-            // comparison with null.
-            __ cmpl(Address(temp, super_offset), Immediate(0));
-            __ j(kNotEqual, slow_path->GetEntryLabel());
-            __ Bind(&do_put);
-          } else {
-            __ j(kNotEqual, slow_path->GetEntryLabel());
-          }
+          // If heap poisoning is enabled, no need to unpoison the
+          // heap reference loaded below, as it is only used for a
+          // comparison with null.
+          __ cmpl(Address(temp, super_offset), Immediate(0));
+          __ j(kNotEqual, slow_path->GetEntryLabel());
+          __ Bind(&do_put);
+        } else {
+          __ j(kNotEqual, slow_path->GetEntryLabel());
         }
       }