Wed, 23 Nov 2016 23:06:39 -0800
8134918: C2: Type speculation produces mismatched unsafe accesses
Reviewed-by: kvn, thartmann
1.1 --- a/src/share/vm/opto/compile.cpp Wed Nov 23 23:01:34 2016 -0800 1.2 +++ b/src/share/vm/opto/compile.cpp Wed Nov 23 23:06:39 2016 -0800 1.3 @@ -1595,6 +1595,17 @@ 1.4 } 1.5 } 1.6 1.7 +BasicType Compile::AliasType::basic_type() const { 1.8 + if (element() != NULL) { 1.9 + const Type* element = adr_type()->is_aryptr()->elem(); 1.10 + return element->isa_narrowoop() ? T_OBJECT : element->array_element_basic_type(); 1.11 + } if (field() != NULL) { 1.12 + return field()->layout_type(); 1.13 + } else { 1.14 + return T_ILLEGAL; // unknown 1.15 + } 1.16 +} 1.17 + 1.18 //---------------------------------print_on------------------------------------ 1.19 #ifndef PRODUCT 1.20 void Compile::AliasType::print_on(outputStream* st) {
2.1 --- a/src/share/vm/opto/compile.hpp Wed Nov 23 23:01:34 2016 -0800 2.2 +++ b/src/share/vm/opto/compile.hpp Wed Nov 23 23:06:39 2016 -0800 2.3 @@ -152,6 +152,8 @@ 2.4 _element = e; 2.5 } 2.6 2.7 + BasicType basic_type() const; 2.8 + 2.9 void print_on(outputStream* st) PRODUCT_RETURN; 2.10 }; 2.11
3.1 --- a/src/share/vm/opto/library_call.cpp Wed Nov 23 23:01:34 2016 -0800 3.2 +++ b/src/share/vm/opto/library_call.cpp Wed Nov 23 23:06:39 2016 -0800 3.3 @@ -2556,6 +2556,7 @@ 3.4 3.5 bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool unaligned) { 3.6 if (callee()->is_static()) return false; // caller must have the capability! 3.7 + assert(type != T_OBJECT || !unaligned, "unaligned access not supported with object type"); 3.8 3.9 #ifndef PRODUCT 3.10 { 3.11 @@ -2631,14 +2632,35 @@ 3.12 3.13 const TypePtr *adr_type = _gvn.type(adr)->isa_ptr(); 3.14 3.15 - // First guess at the value type. 3.16 - const Type *value_type = Type::get_const_basic_type(type); 3.17 - 3.18 // Try to categorize the address. If it comes up as TypeJavaPtr::BOTTOM, 3.19 // there was not enough information to nail it down. 3.20 Compile::AliasType* alias_type = C->alias_type(adr_type); 3.21 assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here"); 3.22 3.23 + assert(alias_type->adr_type() == TypeRawPtr::BOTTOM || alias_type->adr_type() == TypeOopPtr::BOTTOM || 3.24 + alias_type->basic_type() != T_ILLEGAL, "field, array element or unknown"); 3.25 + bool mismatched = false; 3.26 + BasicType bt = alias_type->basic_type(); 3.27 + if (bt != T_ILLEGAL) { 3.28 + if (bt == T_BYTE && adr_type->isa_aryptr()) { 3.29 + // Alias type doesn't differentiate between byte[] and boolean[]). 3.30 + // Use address type to get the element type. 3.31 + bt = adr_type->is_aryptr()->elem()->array_element_basic_type(); 3.32 + } 3.33 + if (bt == T_ARRAY || bt == T_NARROWOOP) { 3.34 + // accessing an array field with getObject is not a mismatch 3.35 + bt = T_OBJECT; 3.36 + } 3.37 + if ((bt == T_OBJECT) != (type == T_OBJECT)) { 3.38 + // Don't intrinsify mismatched object accesses 3.39 + return false; 3.40 + } 3.41 + mismatched = (bt != type); 3.42 + } 3.43 + 3.44 + // First guess at the value type. 3.45 + const Type *value_type = Type::get_const_basic_type(type); 3.46 + 3.47 // We will need memory barriers unless we can determine a unique 3.48 // alias category for this reference. (Note: If for some reason 3.49 // the barriers get omitted and the unsafe reference begins to "pollute" 3.50 @@ -2697,23 +2719,6 @@ 3.51 // around 5701, class sun/reflect/UnsafeBooleanFieldAccessorImpl. 3.52 if (need_mem_bar) insert_mem_bar(Op_MemBarCPUOrder); 3.53 3.54 - assert(alias_type->adr_type() == TypeRawPtr::BOTTOM || alias_type->adr_type() == TypeOopPtr::BOTTOM || 3.55 - alias_type->field() != NULL || alias_type->element() != NULL, "field, array element or unknown"); 3.56 - bool mismatched = false; 3.57 - if (alias_type->element() != NULL || alias_type->field() != NULL) { 3.58 - BasicType bt; 3.59 - if (alias_type->element() != NULL) { 3.60 - const Type* element = alias_type->element(); 3.61 - bt = element->isa_narrowoop() ? T_OBJECT : element->array_element_basic_type(); 3.62 - } else { 3.63 - bt = alias_type->field()->type()->basic_type(); 3.64 - } 3.65 - if (bt != type) { 3.66 - mismatched = true; 3.67 - } 3.68 - } 3.69 - assert(type != T_OBJECT || !unaligned, "unaligned access not supported with object type"); 3.70 - 3.71 if (!is_store) { 3.72 MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered; 3.73 // To be valid, unsafe loads may depend on other conditions than 3.74 @@ -2972,11 +2977,20 @@ 3.75 Node* adr = make_unsafe_address(base, offset); 3.76 const TypePtr *adr_type = _gvn.type(adr)->isa_ptr(); 3.77 3.78 + Compile::AliasType* alias_type = C->alias_type(adr_type); 3.79 + assert(alias_type->adr_type() == TypeRawPtr::BOTTOM || alias_type->adr_type() == TypeOopPtr::BOTTOM || 3.80 + alias_type->basic_type() != T_ILLEGAL, "field, array element or unknown"); 3.81 + BasicType bt = alias_type->basic_type(); 3.82 + if (bt != T_ILLEGAL && 3.83 + ((bt == T_OBJECT || bt == T_ARRAY) != (type == T_OBJECT))) { 3.84 + // Don't intrinsify mismatched object accesses. 3.85 + return false; 3.86 + } 3.87 + 3.88 // For CAS, unlike inline_unsafe_access, there seems no point in 3.89 // trying to refine types. Just use the coarse types here. 3.90 + assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here"); 3.91 const Type *value_type = Type::get_const_basic_type(type); 3.92 - Compile::AliasType* alias_type = C->alias_type(adr_type); 3.93 - assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here"); 3.94 3.95 if (kind == LS_xchg && type == T_OBJECT) { 3.96 const TypeOopPtr* tjp = sharpen_unsafe_type(alias_type, adr_type);
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/test/compiler/profiling/UnsafeAccess.java Wed Nov 23 23:06:39 2016 -0800 4.3 @@ -0,0 +1,88 @@ 4.4 +/* 4.5 + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.7 + * 4.8 + * This code is free software; you can redistribute it and/or modify it 4.9 + * under the terms of the GNU General Public License version 2 only, as 4.10 + * published by the Free Software Foundation. 4.11 + * 4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 4.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 4.15 + * version 2 for more details (a copy is included in the LICENSE file that 4.16 + * accompanied this code). 4.17 + * 4.18 + * You should have received a copy of the GNU General Public License version 4.19 + * 2 along with this work; if not, write to the Free Software Foundation, 4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 4.21 + * 4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 4.23 + * or visit www.oracle.com if you need additional information or have any 4.24 + * questions. 4.25 + */ 4.26 +/* 4.27 + * @test 4.28 + * @bug 8134918 4.29 + * @modules java.base/jdk.internal.misc 4.30 + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation -Xbatch 4.31 + * -XX:CompileCommand=dontinline,UnsafeAccess::test* 4.32 + * UnsafeAccess 4.33 + */ 4.34 +import sun.misc.Unsafe; 4.35 + 4.36 +public class UnsafeAccess { 4.37 + private static final Unsafe U = Unsafe.getUnsafe(); 4.38 + 4.39 + static Class cls = Object.class; 4.40 + static long off = U.ARRAY_OBJECT_BASE_OFFSET; 4.41 + 4.42 + static Object testUnsafeAccess(Object o, boolean isObjArray) { 4.43 + if (o != null && cls.isInstance(o)) { // speculates "o" type to int[] 4.44 + return helperUnsafeAccess(o, isObjArray); 4.45 + } 4.46 + return null; 4.47 + } 4.48 + 4.49 + static Object helperUnsafeAccess(Object o, boolean isObjArray) { 4.50 + if (isObjArray) { 4.51 + U.putObject(o, off, new Object()); 4.52 + } 4.53 + return o; 4.54 + } 4.55 + 4.56 + static Object testUnsafeLoadStore(Object o, boolean isObjArray) { 4.57 + if (o != null && cls.isInstance(o)) { // speculates "o" type to int[] 4.58 + return helperUnsafeLoadStore(o, isObjArray); 4.59 + } 4.60 + return null; 4.61 + } 4.62 + 4.63 + static Object helperUnsafeLoadStore(Object o, boolean isObjArray) { 4.64 + if (isObjArray) { 4.65 + Object o1 = U.getObject(o, off); 4.66 + U.compareAndSwapObject(o, off, o1, new Object()); 4.67 + } 4.68 + return o; 4.69 + } 4.70 + 4.71 + public static void main(String[] args) { 4.72 + Object[] objArray = new Object[10]; 4.73 + int[] intArray = new int[10]; 4.74 + 4.75 + for (int i = 0; i < 20_000; i++) { 4.76 + helperUnsafeAccess(objArray, true); 4.77 + } 4.78 + for (int i = 0; i < 20_000; i++) { 4.79 + testUnsafeAccess(intArray, false); 4.80 + } 4.81 + 4.82 + for (int i = 0; i < 20_000; i++) { 4.83 + helperUnsafeLoadStore(objArray, true); 4.84 + } 4.85 + for (int i = 0; i < 20_000; i++) { 4.86 + testUnsafeLoadStore(intArray, false); 4.87 + } 4.88 + 4.89 + System.out.println("TEST PASSED"); 4.90 + } 4.91 +}