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.