Make heap reference poisoning work with the interpreter.

It is disabled by default.

Bug: 12687968
Change-Id: Iee0cad647f341a7b566f4cf74c2770d1c19312c9
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index 828dffa..dbd078a 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -1550,6 +1550,9 @@
   CHECK(dst.IsCoreRegister() && dst.IsCoreRegister()) << dst;
   LoadFromOffset(kLoadWord, dst.AsCoreRegister(),
                  base.AsArm().AsCoreRegister(), offs.Int32Value());
+  if (kPoisonHeapReferences) {
+    rsb(dst.AsCoreRegister(), dst.AsCoreRegister(), ShifterOperand(0));
+  }
 }
 
 void ArmAssembler::LoadRef(ManagedRegister mdest, FrameOffset  src) {
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index fdd2bab..ce21b84 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -684,6 +684,9 @@
   CHECK(dest.IsCoreRegister() && dest.IsCoreRegister());
   LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
                  base.AsMips().AsCoreRegister(), offs.Int32Value());
+  if (kPoisonHeapReferences) {
+    Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister());
+  }
 }
 
 void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 136d248..1616502 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1553,6 +1553,9 @@
   X86ManagedRegister dest = mdest.AsX86();
   CHECK(dest.IsCpuRegister() && dest.IsCpuRegister());
   movl(dest.AsCpuRegister(), Address(base.AsX86().AsCpuRegister(), offs));
+  if (kPoisonHeapReferences) {
+    negl(dest.AsCpuRegister());
+  }
 }
 
 void X86Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
diff --git a/runtime/globals.h b/runtime/globals.h
index 83e3028..5bc4b91 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -99,6 +99,9 @@
 static constexpr bool kUseBrooksPointer = false;
 #endif
 
+// If true, references within the heap are poisoned (negated).
+static constexpr bool kPoisonHeapReferences = false;
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_GLOBALS_H_
diff --git a/runtime/mirror/object_reference.h b/runtime/mirror/object_reference.h
index b30890f..94869e5 100644
--- a/runtime/mirror/object_reference.h
+++ b/runtime/mirror/object_reference.h
@@ -17,6 +17,7 @@
 #ifndef ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_
 #define ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_
 
+#include "globals.h"
 #include "locks.h"
 
 namespace art {
@@ -74,7 +75,7 @@
 
 // References between objects within the managed heap.
 template<class MirrorType>
-class MANAGED HeapReference : public ObjectReference<false, MirrorType> {
+class MANAGED HeapReference : public ObjectReference<kPoisonHeapReferences, MirrorType> {
  public:
   static HeapReference<MirrorType> FromMirrorPtr(MirrorType* mirror_ptr)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -82,7 +83,7 @@
   }
  private:
   HeapReference<MirrorType>(MirrorType* mirror_ptr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : ObjectReference<false, MirrorType>(mirror_ptr) {}
+      : ObjectReference<kPoisonHeapReferences, MirrorType>(mirror_ptr) {}
 };
 
 }  // namespace mirror
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 04f1a05..37db462 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -147,7 +147,13 @@
 
   compiler_callbacks_ = nullptr;
   is_zygote_ = false;
-  interpreter_only_ = false;
+  if (kPoisonHeapReferences) {
+    // kPoisonHeapReferences currently works only with the interpreter only.
+    // TODO: make it work with the compiler.
+    interpreter_only_ = true;
+  } else {
+    interpreter_only_ = false;
+  }
   is_explicit_gc_disabled_ = false;
 
   long_pause_log_threshold_ = gc::Heap::kDefaultLongPauseLogThreshold;