ART: Add VarHandle fence intrinsics

Bug: 65872996
Test: art/test/run-test --host --64 709
Test: art/test.py --host -j32
Change-Id: I6fa399bb00f0c83048ac2b4372b08e4b4b29ce7f
diff --git a/compiler/intrinsics_list.h b/compiler/intrinsics_list.h
index c8a0119..bfefead 100644
--- a/compiler/intrinsics_list.h
+++ b/compiler/intrinsics_list.h
@@ -158,7 +158,12 @@
   V(UnsafeFullFence, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "fullFence", "()V") \
   V(ReferenceGetReferent, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/ref/Reference;", "getReferent", "()Ljava/lang/Object;") \
   V(IntegerValueOf, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "valueOf", "(I)Ljava/lang/Integer;") \
-  V(ThreadInterrupted, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kNoThrow, "Ljava/lang/Thread;", "interrupted", "()Z")
+  V(ThreadInterrupted, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kNoThrow, "Ljava/lang/Thread;", "interrupted", "()Z") \
+  V(VarHandleFullFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "fullFence", "()V") \
+  V(VarHandleAcquireFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "acquireFence", "()V") \
+  V(VarHandleReleaseFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "releaseFence", "()V") \
+  V(VarHandleLoadLoadFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "loadLoadFence", "()V") \
+  V(VarHandleStoreStoreFence, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "storeStoreFence", "()V") \
 
 #endif  // ART_COMPILER_INTRINSICS_LIST_H_
 #undef ART_COMPILER_INTRINSICS_LIST_H_   // #define is only for lint.
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index cf1cbd5..3164ce1 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -2330,6 +2330,21 @@
     case Intrinsics::kUnsafeFullFence:
       SimplifyMemBarrier(instruction, MemBarrierKind::kAnyAny);
       break;
+    case Intrinsics::kVarHandleFullFence:
+      SimplifyMemBarrier(instruction, MemBarrierKind::kAnyAny);
+      break;
+    case Intrinsics::kVarHandleAcquireFence:
+      SimplifyMemBarrier(instruction, MemBarrierKind::kLoadAny);
+      break;
+    case Intrinsics::kVarHandleReleaseFence:
+      SimplifyMemBarrier(instruction, MemBarrierKind::kAnyStore);
+      break;
+    case Intrinsics::kVarHandleLoadLoadFence:
+      SimplifyMemBarrier(instruction, MemBarrierKind::kLoadAny);
+      break;
+    case Intrinsics::kVarHandleStoreStoreFence:
+      SimplifyMemBarrier(instruction, MemBarrierKind::kStoreStore);
+      break;
     default:
       break;
   }
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index daec634..0f14d27 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -34,7 +34,7 @@
 #define CHECK_INTRINSICS_ENUM_VALUES(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   static_assert( \
       static_cast<uint32_t>(Intrinsics::k ## Name) <= (kAccIntrinsicBits >> CTZ(kAccIntrinsicBits)), \
-      "Instrinsics enumeration space overflow: ");
+      "Instrinsics enumeration space overflow.");
 #include "intrinsics_list.h"
   INTRINSICS_LIST(CHECK_INTRINSICS_ENUM_VALUES)
 #undef INTRINSICS_LIST
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 6411e82..7abfd5b 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -256,25 +256,30 @@
   LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic()      \
              << " should have been converted to HIR";                    \
 }
-#define UNREACHABLE_INTRINSICS(Arch)                \
-UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits)    \
-UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits) \
-UNREACHABLE_INTRINSIC(Arch, FloatIsNaN)             \
-UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN)            \
-UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft)      \
-UNREACHABLE_INTRINSIC(Arch, LongRotateLeft)         \
-UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight)     \
-UNREACHABLE_INTRINSIC(Arch, LongRotateRight)        \
-UNREACHABLE_INTRINSIC(Arch, IntegerCompare)         \
-UNREACHABLE_INTRINSIC(Arch, LongCompare)            \
-UNREACHABLE_INTRINSIC(Arch, IntegerSignum)          \
-UNREACHABLE_INTRINSIC(Arch, LongSignum)             \
-UNREACHABLE_INTRINSIC(Arch, StringCharAt)           \
-UNREACHABLE_INTRINSIC(Arch, StringIsEmpty)          \
-UNREACHABLE_INTRINSIC(Arch, StringLength)           \
-UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence)        \
-UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence)       \
-UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence)
+#define UNREACHABLE_INTRINSICS(Arch)                  \
+UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits)      \
+UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits)   \
+UNREACHABLE_INTRINSIC(Arch, FloatIsNaN)               \
+UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN)              \
+UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft)        \
+UNREACHABLE_INTRINSIC(Arch, LongRotateLeft)           \
+UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight)       \
+UNREACHABLE_INTRINSIC(Arch, LongRotateRight)          \
+UNREACHABLE_INTRINSIC(Arch, IntegerCompare)           \
+UNREACHABLE_INTRINSIC(Arch, LongCompare)              \
+UNREACHABLE_INTRINSIC(Arch, IntegerSignum)            \
+UNREACHABLE_INTRINSIC(Arch, LongSignum)               \
+UNREACHABLE_INTRINSIC(Arch, StringCharAt)             \
+UNREACHABLE_INTRINSIC(Arch, StringIsEmpty)            \
+UNREACHABLE_INTRINSIC(Arch, StringLength)             \
+UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence)          \
+UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence)         \
+UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence)          \
+UNREACHABLE_INTRINSIC(Arch, VarHandleFullFence)       \
+UNREACHABLE_INTRINSIC(Arch, VarHandleAcquireFence)    \
+UNREACHABLE_INTRINSIC(Arch, VarHandleReleaseFence)    \
+UNREACHABLE_INTRINSIC(Arch, VarHandleLoadLoadFence)   \
+UNREACHABLE_INTRINSIC(Arch, VarHandleStoreStoreFence)
 
 template <typename IntrinsicLocationsBuilder, typename Codegenerator>
 bool IsCallFreeIntrinsic(HInvoke* invoke, Codegenerator* codegen) {
diff --git a/runtime/image.cc b/runtime/image.cc
index 4c6529b..aae572b 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '4', '9', '\0' };  // 256 intrinsics
+const uint8_t ImageHeader::kImageVersion[] = { '0', '4', 'A', '\0' };  // VarHandle fence intrinsics
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc
index 74e6cd2..26de6b4 100644
--- a/runtime/interpreter/interpreter_intrinsics.cc
+++ b/runtime/interpreter/interpreter_intrinsics.cc
@@ -323,6 +323,25 @@
   return true;
 }
 
+#define VARHANDLE_FENCE_INTRINSIC(name, std_memory_operation)   \
+static ALWAYS_INLINE bool name(ShadowFrame* /* shadow_frame */, \
+                               const Instruction* /* inst */,   \
+                               uint16_t /* inst_data */,        \
+                               JValue* /* result_register */)   \
+    REQUIRES_SHARED(Locks::mutator_lock_) {                     \
+    std::atomic_thread_fence(std_memory_operation);             \
+    return true;                                                \
+}
+
+// The VarHandle fence methods are static (unlike sun.misc.Unsafe versions).
+// The fences for the LoadLoadFence and StoreStoreFence are stronger
+// than strictly required, but the impact should be marginal.
+VARHANDLE_FENCE_INTRINSIC(MterpVarHandleFullFence, std::memory_order_seq_cst)
+VARHANDLE_FENCE_INTRINSIC(MterpVarHandleAcquireFence, std::memory_order_acquire)
+VARHANDLE_FENCE_INTRINSIC(MterpVarHandleReleaseFence, std::memory_order_release)
+VARHANDLE_FENCE_INTRINSIC(MterpVarHandleLoadLoadFence, std::memory_order_acquire)
+VARHANDLE_FENCE_INTRINSIC(MterpVarHandleStoreStoreFence, std::memory_order_release)
+
 // Macro to help keep track of what's left to implement.
 #define UNIMPLEMENTED_CASE(name)    \
     case Intrinsics::k##name:       \
@@ -470,6 +489,11 @@
     UNIMPLEMENTED_CASE(ReferenceGetReferent /* ()Ljava/lang/Object; */)
     UNIMPLEMENTED_CASE(IntegerValueOf /* (I)Ljava/lang/Integer; */)
     UNIMPLEMENTED_CASE(ThreadInterrupted /* ()Z */)
+    INTRINSIC_CASE(VarHandleFullFence)
+    INTRINSIC_CASE(VarHandleAcquireFence)
+    INTRINSIC_CASE(VarHandleReleaseFence)
+    INTRINSIC_CASE(VarHandleLoadLoadFence)
+    INTRINSIC_CASE(VarHandleStoreStoreFence)
     case Intrinsics::kNone:
       res = false;
       break;
diff --git a/test/709-checker-varhandles/build b/test/709-checker-varhandles/build
new file mode 100755
index 0000000..2b0b2c1
--- /dev/null
+++ b/test/709-checker-varhandles/build
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# make us exit on a failure
+set -e
+
+./default-build "$@" --experimental method-handles
diff --git a/test/709-checker-varhandles/expected.txt b/test/709-checker-varhandles/expected.txt
new file mode 100644
index 0000000..651da72
--- /dev/null
+++ b/test/709-checker-varhandles/expected.txt
@@ -0,0 +1,2 @@
+starting
+passed
diff --git a/test/709-checker-varhandles/info.txt b/test/709-checker-varhandles/info.txt
new file mode 100644
index 0000000..2221240
--- /dev/null
+++ b/test/709-checker-varhandles/info.txt
@@ -0,0 +1 @@
+Test support for intrinsics in Java 9 java.lang.invoke.VarHandle.
diff --git a/test/709-checker-varhandles/src-art/Main.java b/test/709-checker-varhandles/src-art/Main.java
new file mode 100644
index 0000000..46aaa38
--- /dev/null
+++ b/test/709-checker-varhandles/src-art/Main.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.invoke.VarHandle;
+
+/**
+ * Checker test on the 1.8 unsafe operations. Note, this is by no means an
+ * exhaustive unit test for these CAS (compare-and-swap) and fence operations.
+ * Instead, this test ensures the methods are recognized as intrinsic and behave
+ * as expected.
+ */
+public class Main {
+
+  //
+  // Fences (native).
+  //
+
+  /// CHECK-START: void Main.fullFence() intrinsics_recognition (after)
+  /// CHECK-DAG: InvokeStaticOrDirect intrinsic:VarHandleFullFence
+  //
+  /// CHECK-START: void Main.fullFence() instruction_simplifier (after)
+  /// CHECK-NOT: InvokeStaticOrDirect intrinsic:VarHandleFullFence
+  //
+  /// CHECK-START: void Main.fullFence() instruction_simplifier (after)
+  /// CHECK-DAG: MemoryBarrier kind:AnyAny
+  private static void fullFence() {
+      VarHandle.fullFence();
+  }
+
+  /// CHECK-START: void Main.acquireFence() intrinsics_recognition (after)
+  /// CHECK-DAG: InvokeStaticOrDirect intrinsic:VarHandleAcquireFence
+  //
+  /// CHECK-START: void Main.acquireFence() instruction_simplifier (after)
+  /// CHECK-NOT: InvokeStaticOrDirect intrinsic:VarHandleAcquireFence
+  //
+  /// CHECK-START: void Main.acquireFence() instruction_simplifier (after)
+  /// CHECK-DAG: MemoryBarrier kind:LoadAny
+  private static void acquireFence() {
+      VarHandle.acquireFence();
+  }
+
+  /// CHECK-START: void Main.releaseFence() intrinsics_recognition (after)
+  /// CHECK-DAG: InvokeStaticOrDirect intrinsic:VarHandleReleaseFence
+  //
+  /// CHECK-START: void Main.releaseFence() instruction_simplifier (after)
+  /// CHECK-NOT: InvokeStaticOrDirect intrinsic:VarHandleReleaseFence
+  //
+  /// CHECK-START: void Main.releaseFence() instruction_simplifier (after)
+  /// CHECK-DAG: MemoryBarrier kind:AnyStore
+  private static void releaseFence() {
+      VarHandle.releaseFence();
+  }
+
+  /// CHECK-START: void Main.loadLoadFence() intrinsics_recognition (after)
+  /// CHECK-DAG: InvokeStaticOrDirect intrinsic:VarHandleLoadLoadFence
+  //
+  /// CHECK-START: void Main.loadLoadFence() instruction_simplifier (after)
+  /// CHECK-NOT: InvokeStaticOrDirect intrinsic:VarHandleLoadLoadFence
+  //
+  /// CHECK-START: void Main.loadLoadFence() instruction_simplifier (after)
+  /// CHECK-DAG: MemoryBarrier kind:LoadAny
+  private static void loadLoadFence() {
+      VarHandle.loadLoadFence();
+  }
+
+  /// CHECK-START: void Main.storeStoreFence() intrinsics_recognition (after)
+  /// CHECK-DAG: InvokeStaticOrDirect intrinsic:VarHandleStoreStoreFence
+  //
+  /// CHECK-START: void Main.storeStoreFence() instruction_simplifier (after)
+  /// CHECK-NOT: InvokeStaticOrDirect intrinsic:VarHandleStoreStoreFence
+  //
+  /// CHECK-START: void Main.storeStoreFence() instruction_simplifier (after)
+  /// CHECK-DAG: MemoryBarrier kind:StoreStore
+  private static void storeStoreFence() {
+      VarHandle.storeStoreFence();
+  }
+
+  //
+  // Driver.
+  //
+
+  public static void main(String[] args) {
+    System.out.println("starting");
+    acquireFence();
+    releaseFence();
+    loadLoadFence();
+    storeStoreFence();
+    fullFence();
+    System.out.println("passed");
+  }
+}
diff --git a/test/988-method-trace/gen_srcs.py b/test/988-method-trace/gen_srcs.py
index c1ce35c..8f1082f 100755
--- a/test/988-method-trace/gen_srcs.py
+++ b/test/988-method-trace/gen_srcs.py
@@ -38,7 +38,8 @@
 IDX_CLASS_NAME = -3
 
 # Exclude all hidden API.
-KLASS_BLACK_LIST = ['sun.misc.Unsafe', 'libcore.io.Memory', 'java.lang.StringFactory']
+KLASS_BLACK_LIST = ['sun.misc.Unsafe', 'libcore.io.Memory', 'java.lang.StringFactory',
+                    'java.lang.invoke.VarHandle' ]  # TODO(b/65872996): Enable when VarHandle is visible.
 METHOD_BLACK_LIST = [('java.lang.ref.Reference', 'getReferent'),
                      ('java.lang.String', 'getCharsNoCheck'),
                      ('java.lang.System', 'arraycopy')]  # arraycopy has a manual test.