diff options
| author | 2016-03-08 00:05:02 +0000 | |
|---|---|---|
| committer | 2016-03-08 00:05:02 +0000 | |
| commit | 2fadae77e0293bcee73b2b8f5d92f9db19d3d9b3 (patch) | |
| tree | 93aa158d913b24fbdd8290e0aa70e527417524b6 | |
| parent | dcb5aca20fb670e9981af92c05060e8dcd80b364 (diff) | |
| parent | 0310fb0279d283439633b7c32801f2bb9443dbe1 (diff) | |
Merge "Unsafe: Recognize intrinsics for 1.8 java.util.concurrent With unit test."
am: 0310fb0279
* commit '0310fb0279d283439633b7c32801f2bb9443dbe1':
Unsafe: Recognize intrinsics for 1.8 java.util.concurrent With unit test.
| -rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.cc | 49 | ||||
| -rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.h | 11 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics.cc | 18 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm.cc | 10 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 10 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_list.h | 8 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_mips.cc | 12 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_mips64.cc | 10 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 10 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 10 | ||||
| -rw-r--r-- | runtime/quick/inline_method_analyser.h | 11 | ||||
| -rw-r--r-- | test/004-UnsafeTest/src/Main.java | 2 | ||||
| -rw-r--r-- | test/004-checker-UnsafeTest18/expected.txt | 2 | ||||
| -rw-r--r-- | test/004-checker-UnsafeTest18/info.txt | 1 | ||||
| -rw-r--r-- | test/004-checker-UnsafeTest18/src/Main.java | 252 |
15 files changed, 413 insertions, 3 deletions
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc index ad4ddadd2f..8f5d3ae4bd 100644 --- a/compiler/dex/quick/dex_file_method_inliner.cc +++ b/compiler/dex/quick/dex_file_method_inliner.cc @@ -101,6 +101,14 @@ static constexpr bool kIntrinsicIsStatic[] = { false, // kIntrinsicCas false, // kIntrinsicUnsafeGet false, // kIntrinsicUnsafePut + false, // kIntrinsicUnsafeGetAndAddInt, + false, // kIntrinsicUnsafeGetAndAddLong, + false, // kIntrinsicUnsafeGetAndSetInt, + false, // kIntrinsicUnsafeGetAndSetLong, + false, // kIntrinsicUnsafeGetAndSetObject, + false, // kIntrinsicUnsafeLoadFence, + false, // kIntrinsicUnsafeStoreFence, + false, // kIntrinsicUnsafeFullFence, true, // kIntrinsicSystemArrayCopyCharArray true, // kIntrinsicSystemArrayCopy }; @@ -177,6 +185,14 @@ static_assert(kIntrinsicIsStatic[kIntrinsicPoke], "Poke must be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicCas], "Cas must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGet], "UnsafeGet must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafePut], "UnsafePut must not be static"); +static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndAddInt], "UnsafeGetAndAddInt must not be static"); +static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndAddLong], "UnsafeGetAndAddLong must not be static"); +static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetInt], "UnsafeGetAndSetInt must not be static"); +static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetLong], "UnsafeGetAndSetLong must not be static"); +static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetObject], "UnsafeGetAndSetObject must not be static"); +static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeLoadFence], "UnsafeLoadFence must not be static"); +static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeStoreFence], "UnsafeStoreFence must not be static"); +static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeFullFence], "UnsafeFullFence must not be static"); static_assert(kIntrinsicIsStatic[kIntrinsicSystemArrayCopyCharArray], "SystemArrayCopyCharArray must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicSystemArrayCopy], @@ -318,6 +334,14 @@ const char* const DexFileMethodInliner::kNameCacheNames[] = { "putObject", // kNameCachePutObject "putObjectVolatile", // kNameCachePutObjectVolatile "putOrderedObject", // kNameCachePutOrderedObject + "getAndAddInt", // kNameCacheGetAndAddInt, + "getAndAddLong", // kNameCacheGetAndAddLong, + "getAndSetInt", // kNameCacheGetAndSetInt, + "getAndSetLong", // kNameCacheGetAndSetLong, + "getAndSetObject", // kNameCacheGetAndSetObject, + "loadFence", // kNameCacheLoadFence, + "storeFence", // kNameCacheStoreFence, + "fullFence", // kNameCacheFullFence, "arraycopy", // kNameCacheArrayCopy "bitCount", // kNameCacheBitCount "compare", // kNameCacheCompare @@ -404,10 +428,14 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { kClassCacheJavaLangObject, kClassCacheJavaLangObject } }, // kProtoCacheObjectJ_I { kClassCacheInt, 2, { kClassCacheJavaLangObject, kClassCacheLong } }, + // kProtoCacheObjectJI_I + { kClassCacheInt, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } }, // kProtoCacheObjectJI_V { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } }, // kProtoCacheObjectJ_J { kClassCacheLong, 2, { kClassCacheJavaLangObject, kClassCacheLong } }, + // kProtoCacheObjectJJ_J + { kClassCacheLong, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } }, // kProtoCacheObjectJJ_V { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } }, // kProtoCacheObjectJ_Object @@ -415,6 +443,9 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { // kProtoCacheObjectJObject_V { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheJavaLangObject } }, + // kProtoCacheObjectJObject_Object + { kClassCacheJavaLangObject, 3, { kClassCacheJavaLangObject, kClassCacheLong, + kClassCacheJavaLangObject } }, // kProtoCacheCharArrayICharArrayII_V { kClassCacheVoid, 5, {kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt} }, @@ -609,6 +640,16 @@ const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject), #undef UNSAFE_GET_PUT + // 1.8 + INTRINSIC(SunMiscUnsafe, GetAndAddInt, ObjectJI_I, kIntrinsicUnsafeGetAndAddInt, 0), + INTRINSIC(SunMiscUnsafe, GetAndAddLong, ObjectJJ_J, kIntrinsicUnsafeGetAndAddLong, 0), + INTRINSIC(SunMiscUnsafe, GetAndSetInt, ObjectJI_I, kIntrinsicUnsafeGetAndSetInt, 0), + INTRINSIC(SunMiscUnsafe, GetAndSetLong, ObjectJJ_J, kIntrinsicUnsafeGetAndSetLong, 0), + INTRINSIC(SunMiscUnsafe, GetAndSetObject, ObjectJObject_Object, kIntrinsicUnsafeGetAndSetObject, 0), + INTRINSIC(SunMiscUnsafe, LoadFence, _V, kIntrinsicUnsafeLoadFence, 0), + INTRINSIC(SunMiscUnsafe, StoreFence, _V, kIntrinsicUnsafeStoreFence, 0), + INTRINSIC(SunMiscUnsafe, FullFence, _V, kIntrinsicUnsafeFullFence, 0), + INTRINSIC(JavaLangSystem, ArrayCopy, CharArrayICharArrayII_V , kIntrinsicSystemArrayCopyCharArray, 0), INTRINSIC(JavaLangSystem, ArrayCopy, ObjectIObjectII_V , kIntrinsicSystemArrayCopy, @@ -815,6 +856,14 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { case kIntrinsicRotateRight: case kIntrinsicRotateLeft: case kIntrinsicSignum: + case kIntrinsicUnsafeGetAndAddInt: + case kIntrinsicUnsafeGetAndAddLong: + case kIntrinsicUnsafeGetAndSetInt: + case kIntrinsicUnsafeGetAndSetLong: + case kIntrinsicUnsafeGetAndSetObject: + case kIntrinsicUnsafeLoadFence: + case kIntrinsicUnsafeStoreFence: + case kIntrinsicUnsafeFullFence: case kIntrinsicSystemArrayCopy: return false; // not implemented in quick. default: diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h index b465db2c54..34b56cd494 100644 --- a/compiler/dex/quick/dex_file_method_inliner.h +++ b/compiler/dex/quick/dex_file_method_inliner.h @@ -227,6 +227,14 @@ class DexFileMethodInliner { kNameCachePutObject, kNameCachePutObjectVolatile, kNameCachePutOrderedObject, + kNameCacheGetAndAddInt, + kNameCacheGetAndAddLong, + kNameCacheGetAndSetInt, + kNameCacheGetAndSetLong, + kNameCacheGetAndSetObject, + kNameCacheLoadFence, + kNameCacheStoreFence, + kNameCacheFullFence, kNameCacheArrayCopy, kNameCacheBitCount, kNameCacheCompare, @@ -282,11 +290,14 @@ class DexFileMethodInliner { kProtoCacheObjectJJJ_Z, kProtoCacheObjectJObjectObject_Z, kProtoCacheObjectJ_I, + kProtoCacheObjectJI_I, kProtoCacheObjectJI_V, kProtoCacheObjectJ_J, + kProtoCacheObjectJJ_J, kProtoCacheObjectJJ_V, kProtoCacheObjectJ_Object, kProtoCacheObjectJObject_V, + kProtoCacheObjectJObject_Object, kProtoCacheCharArrayICharArrayII_V, kProtoCacheObjectIObjectII_V, kProtoCacheIICharArrayI_V, diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 3ed0278871..5d4c4e2950 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -472,6 +472,24 @@ static Intrinsics GetIntrinsic(InlineMethod method) { break; } + // 1.8. + case kIntrinsicUnsafeGetAndAddInt: + return Intrinsics::kUnsafeGetAndAddInt; + case kIntrinsicUnsafeGetAndAddLong: + return Intrinsics::kUnsafeGetAndAddLong; + case kIntrinsicUnsafeGetAndSetInt: + return Intrinsics::kUnsafeGetAndSetInt; + case kIntrinsicUnsafeGetAndSetLong: + return Intrinsics::kUnsafeGetAndSetLong; + case kIntrinsicUnsafeGetAndSetObject: + return Intrinsics::kUnsafeGetAndSetObject; + case kIntrinsicUnsafeLoadFence: + return Intrinsics::kUnsafeLoadFence; + case kIntrinsicUnsafeStoreFence: + return Intrinsics::kUnsafeStoreFence; + case kIntrinsicUnsafeFullFence: + return Intrinsics::kUnsafeFullFence; + // Virtual cases. case kIntrinsicReferenceGetReferent: diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 69c970852d..b599d42c4b 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -2002,6 +2002,16 @@ UNIMPLEMENTED_INTRINSIC(ARM, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM, IntegerLowestOneBit) UNIMPLEMENTED_INTRINSIC(ARM, LongLowestOneBit) +// 1.8. +UNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndAddInt) +UNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndAddLong) +UNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndSetInt) +UNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndSetLong) +UNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndSetObject) +UNIMPLEMENTED_INTRINSIC(ARM, UnsafeLoadFence) +UNIMPLEMENTED_INTRINSIC(ARM, UnsafeStoreFence) +UNIMPLEMENTED_INTRINSIC(ARM, UnsafeFullFence) + UNREACHABLE_INTRINSICS(ARM) #undef __ diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 934b42762e..ccbbd43258 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -1953,6 +1953,16 @@ UNIMPLEMENTED_INTRINSIC(ARM64, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM64, IntegerLowestOneBit) UNIMPLEMENTED_INTRINSIC(ARM64, LongLowestOneBit) +// 1.8. +UNIMPLEMENTED_INTRINSIC(ARM64, UnsafeGetAndAddInt) +UNIMPLEMENTED_INTRINSIC(ARM64, UnsafeGetAndAddLong) +UNIMPLEMENTED_INTRINSIC(ARM64, UnsafeGetAndSetInt) +UNIMPLEMENTED_INTRINSIC(ARM64, UnsafeGetAndSetLong) +UNIMPLEMENTED_INTRINSIC(ARM64, UnsafeGetAndSetObject) +UNIMPLEMENTED_INTRINSIC(ARM64, UnsafeLoadFence) +UNIMPLEMENTED_INTRINSIC(ARM64, UnsafeStoreFence) +UNIMPLEMENTED_INTRINSIC(ARM64, UnsafeFullFence) + UNREACHABLE_INTRINSICS(ARM64) #undef __ diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h index b8933e1684..dd9294d486 100644 --- a/compiler/optimizing/intrinsics_list.h +++ b/compiler/optimizing/intrinsics_list.h @@ -128,6 +128,14 @@ V(UnsafePutLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ V(UnsafePutLongOrdered, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ V(UnsafePutLongVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ + V(UnsafeGetAndAddInt, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ + V(UnsafeGetAndAddLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ + V(UnsafeGetAndSetInt, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ + V(UnsafeGetAndSetLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ + V(UnsafeGetAndSetObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ + V(UnsafeLoadFence, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ + V(UnsafeStoreFence, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ + V(UnsafeFullFence, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ V(ReferenceGetReferent, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) #endif // ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_ diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc index 710df0a822..697b8fe882 100644 --- a/compiler/optimizing/intrinsics_mips.cc +++ b/compiler/optimizing/intrinsics_mips.cc @@ -1832,9 +1832,17 @@ UNIMPLEMENTED_INTRINSIC(MIPS, MathSinh) UNIMPLEMENTED_INTRINSIC(MIPS, MathTan) UNIMPLEMENTED_INTRINSIC(MIPS, MathTanh) -UNREACHABLE_INTRINSICS(MIPS) +// 1.8. +UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndAddInt) +UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndAddLong) +UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetInt) +UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetLong) +UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetObject) +UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeLoadFence) +UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeStoreFence) +UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeFullFence) -#undef UNIMPLEMENTED_INTRINSIC +UNREACHABLE_INTRINSICS(MIPS) #undef __ diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index 617844bb18..83dff33ec0 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -1729,6 +1729,16 @@ UNIMPLEMENTED_INTRINSIC(MIPS64, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(MIPS64, IntegerLowestOneBit) UNIMPLEMENTED_INTRINSIC(MIPS64, LongLowestOneBit) +// 1.8. +UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndAddInt) +UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndAddLong) +UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetInt) +UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetLong) +UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetObject) +UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeLoadFence) +UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeStoreFence) +UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeFullFence) + UNREACHABLE_INTRINSICS(MIPS64) #undef __ diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 9a2dc4182d..048590e1be 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -2637,6 +2637,16 @@ UNIMPLEMENTED_INTRINSIC(X86, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(X86, IntegerLowestOneBit) UNIMPLEMENTED_INTRINSIC(X86, LongLowestOneBit) +// 1.8. +UNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndAddInt) +UNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndAddLong) +UNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndSetInt) +UNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndSetLong) +UNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndSetObject) +UNIMPLEMENTED_INTRINSIC(X86, UnsafeLoadFence) +UNIMPLEMENTED_INTRINSIC(X86, UnsafeStoreFence) +UNIMPLEMENTED_INTRINSIC(X86, UnsafeFullFence) + UNREACHABLE_INTRINSICS(X86) #undef __ diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 75204b4b49..35e13a6540 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -2715,6 +2715,16 @@ UNIMPLEMENTED_INTRINSIC(X86_64, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(X86_64, FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(X86_64, DoubleIsInfinite) +// 1.8. +UNIMPLEMENTED_INTRINSIC(X86_64, UnsafeGetAndAddInt) +UNIMPLEMENTED_INTRINSIC(X86_64, UnsafeGetAndAddLong) +UNIMPLEMENTED_INTRINSIC(X86_64, UnsafeGetAndSetInt) +UNIMPLEMENTED_INTRINSIC(X86_64, UnsafeGetAndSetLong) +UNIMPLEMENTED_INTRINSIC(X86_64, UnsafeGetAndSetObject) +UNIMPLEMENTED_INTRINSIC(X86_64, UnsafeLoadFence) +UNIMPLEMENTED_INTRINSIC(X86_64, UnsafeStoreFence) +UNIMPLEMENTED_INTRINSIC(X86_64, UnsafeFullFence) + UNREACHABLE_INTRINSICS(X86_64) #undef __ diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h index 7e84b405e7..0e12d73595 100644 --- a/runtime/quick/inline_method_analyser.h +++ b/runtime/quick/inline_method_analyser.h @@ -101,6 +101,17 @@ enum InlineMethodOpcode : uint16_t { kIntrinsicCas, kIntrinsicUnsafeGet, kIntrinsicUnsafePut, + + // 1.8. + kIntrinsicUnsafeGetAndAddInt, + kIntrinsicUnsafeGetAndAddLong, + kIntrinsicUnsafeGetAndSetInt, + kIntrinsicUnsafeGetAndSetLong, + kIntrinsicUnsafeGetAndSetObject, + kIntrinsicUnsafeLoadFence, + kIntrinsicUnsafeStoreFence, + kIntrinsicUnsafeFullFence, + kIntrinsicSystemArrayCopyCharArray, kIntrinsicSystemArrayCopy, diff --git a/test/004-UnsafeTest/src/Main.java b/test/004-UnsafeTest/src/Main.java index a9a7a058e0..b2f905e0ee 100644 --- a/test/004-UnsafeTest/src/Main.java +++ b/test/004-UnsafeTest/src/Main.java @@ -40,7 +40,7 @@ public class Main { } private static Unsafe getUnsafe() throws Exception { - Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); + Class<?> unsafeClass = Unsafe.class; Field f = unsafeClass.getDeclaredField("theUnsafe"); f.setAccessible(true); return (Unsafe) f.get(null); diff --git a/test/004-checker-UnsafeTest18/expected.txt b/test/004-checker-UnsafeTest18/expected.txt new file mode 100644 index 0000000000..651da727af --- /dev/null +++ b/test/004-checker-UnsafeTest18/expected.txt @@ -0,0 +1,2 @@ +starting +passed diff --git a/test/004-checker-UnsafeTest18/info.txt b/test/004-checker-UnsafeTest18/info.txt new file mode 100644 index 0000000000..0fca5ebf03 --- /dev/null +++ b/test/004-checker-UnsafeTest18/info.txt @@ -0,0 +1 @@ +Test support for 1.8 sun.misc.Unsafe. diff --git a/test/004-checker-UnsafeTest18/src/Main.java b/test/004-checker-UnsafeTest18/src/Main.java new file mode 100644 index 0000000000..bb6de2ef28 --- /dev/null +++ b/test/004-checker-UnsafeTest18/src/Main.java @@ -0,0 +1,252 @@ +/* + * 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.reflect.Field; + +import sun.misc.Unsafe; + +/** + * 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 { + + private static final Unsafe unsafe = getUnsafe(); + + private static Thread[] sThreads = new Thread[10]; + + // + // Fields accessed by setters and adders. + // + + public int i = 0; + public long l = 0; + public Object o = null; + + // + // Setters. + // + + /// CHECK-START: int Main.set32(java.lang.Object, long, int) intrinsics_recognition (after) + /// CHECK-DAG: <<Result:i\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetInt + /// CHECK-DAG: Return [<<Result>>] + private static int set32(Object o, long offset, int newValue) { + return unsafe.getAndSetInt(o, offset, newValue); + } + + /// CHECK-START: long Main.set64(java.lang.Object, long, long) intrinsics_recognition (after) + /// CHECK-DAG: <<Result:j\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetLong + /// CHECK-DAG: Return [<<Result>>] + private static long set64(Object o, long offset, long newValue) { + return unsafe.getAndSetLong(o, offset, newValue); + } + + /// CHECK-START: java.lang.Object Main.setObj(java.lang.Object, long, java.lang.Object) intrinsics_recognition (after) + /// CHECK-DAG: <<Result:l\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetObject + /// CHECK-DAG: Return [<<Result>>] + private static Object setObj(Object o, long offset, Object newValue) { + return unsafe.getAndSetObject(o, offset, newValue); + } + + // + // Adders. + // + + /// CHECK-START: int Main.add32(java.lang.Object, long, int) intrinsics_recognition (after) + /// CHECK-DAG: <<Result:i\d+>> InvokeVirtual intrinsic:UnsafeGetAndAddInt + /// CHECK-DAG: Return [<<Result>>] + private static int add32(Object o, long offset, int delta) { + return unsafe.getAndAddInt(o, offset, delta); + } + + /// CHECK-START: long Main.add64(java.lang.Object, long, long) intrinsics_recognition (after) + /// CHECK-DAG: <<Result:j\d+>> InvokeVirtual intrinsic:UnsafeGetAndAddLong + /// CHECK-DAG: Return [<<Result>>] + private static long add64(Object o, long offset, long delta) { + return unsafe.getAndAddLong(o, offset, delta); + } + + // + // Fences (native). + // + + /// CHECK-START: void Main.load() intrinsics_recognition (after) + /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeLoadFence + private static void load() { + unsafe.loadFence(); + } + + /// CHECK-START: void Main.store() intrinsics_recognition (after) + /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeStoreFence + private static void store() { + unsafe.storeFence(); + } + + /// CHECK-START: void Main.full() intrinsics_recognition (after) + /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeFullFence + private static void full() { + unsafe.fullFence(); + } + + // + // Thread fork/join. + // + + private static void fork(Runnable r) { + for (int i = 0; i < 10; i++) { + sThreads[i] = new Thread(r); + sThreads[i].start(); + } + } + + private static void join() { + try { + for (int i = 0; i < 10; i++) { + sThreads[i].join(); + } + } catch (InterruptedException e) { + throw new Error("Failed join: " + e); + } + } + + // + // Driver. + // + + public static void main(String[] args) { + System.out.println("starting"); + + final Main m = new Main(); + + // Get the offsets. + + final long intOffset, longOffset, objOffset; + try { + Field intField = Main.class.getDeclaredField("i"); + Field longField = Main.class.getDeclaredField("l"); + Field objField = Main.class.getDeclaredField("o"); + + intOffset = unsafe.objectFieldOffset(intField); + longOffset = unsafe.objectFieldOffset(longField); + objOffset = unsafe.objectFieldOffset(objField); + + } catch (NoSuchFieldException e) { + throw new Error("No offset: " + e); + } + + // Some sanity within same thread. + + set32(m, intOffset, 3); + expectEquals32(3, m.i); + + set64(m, longOffset, 7L); + expectEquals64(7L, m.l); + + setObj(m, objOffset, m); + expectEqualsObj(m, m.o); + + add32(m, intOffset, 11); + expectEquals32(14, m.i); + + add64(m, longOffset, 13L); + expectEquals64(20L, m.l); + + // Some sanity on setters within different threads. + + fork(new Runnable() { + public void run() { + for (int i = 0; i < 10; i++) + set32(m, intOffset, i); + } + }); + join(); + expectEquals32(9, m.i); // one thread's last value wins + + fork(new Runnable() { + public void run() { + for (int i = 0; i < 10; i++) + set64(m, longOffset, (long) (100 + i)); + } + }); + join(); + expectEquals64(109L, m.l); // one thread's last value wins + + fork(new Runnable() { + public void run() { + for (int i = 0; i < 10; i++) + setObj(m, objOffset, sThreads[i]); + } + }); + join(); + expectEqualsObj(sThreads[9], m.o); // one thread's last value wins + + // Some sanity on adders within different threads. + + fork(new Runnable() { + public void run() { + for (int i = 0; i < 10; i++) + add32(m, intOffset, i + 1); + } + }); + join(); + expectEquals32(559, m.i); // all values accounted for + + fork(new Runnable() { + public void run() { + for (int i = 0; i < 10; i++) + add64(m, longOffset, (long) (i + 1)); + } + }); + join(); + expectEquals64(659L, m.l); // all values accounted for + + // TODO: the fences + + System.out.println("passed"); + } + + // Use reflection to implement "Unsafe.getUnsafe()"; + private static Unsafe getUnsafe() { + try { + Class<?> unsafeClass = Unsafe.class; + Field f = unsafeClass.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (Unsafe) f.get(null); + } catch (Exception e) { + throw new Error("Cannot get Unsafe instance"); + } + } + + private static void expectEquals32(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals64(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEqualsObj(Object expected, Object result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} |