--- old/src/share/vm/classfile/vmSymbols.hpp 2016-04-12 21:44:32.000000000 +0300 +++ new/src/share/vm/classfile/vmSymbols.hpp 2016-04-12 21:44:32.000000000 +0300 @@ -1068,7 +1068,7 @@ do_class(jdk_internal_misc_Unsafe, "jdk/internal/misc/Unsafe") \ \ do_intrinsic(_allocateInstance, jdk_internal_misc_Unsafe, allocateInstance_name, allocateInstance_signature, F_RN) \ - do_name( allocateInstance_name, "allocateInstance") \ + do_name( allocateInstance_name, "allocateInstance0") \ do_signature(allocateInstance_signature, "(Ljava/lang/Class;)Ljava/lang/Object;") \ do_intrinsic(_allocateUninitializedArray, jdk_internal_misc_Unsafe, allocateUninitializedArray_name, newArray_signature, F_R) \ do_name( allocateUninitializedArray_name, "allocateUninitializedArray0") \ --- old/src/share/vm/opto/library_call.cpp 2016-04-12 21:44:32.000000000 +0300 +++ new/src/share/vm/opto/library_call.cpp 2016-04-12 21:44:32.000000000 +0300 @@ -248,6 +248,7 @@ typedef enum { Relaxed, Opaque, Volatile, Acquire, Release } AccessKind; bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, AccessKind kind, bool is_unaligned); static bool klass_needs_init_guard(Node* kls); + Node* make_init_guard(Node* kls); bool inline_unsafe_allocate(); bool inline_unsafe_newArray(bool uninitialized); bool inline_unsafe_copyMemory(); @@ -3141,33 +3142,27 @@ return !ik->is_initialized(); } +Node* LibraryCallKit::make_init_guard(Node* kls) { + if (!klass_needs_init_guard(kls)) return NULL; + + Node* insp = basic_plus_adr(kls, in_bytes(InstanceKlass::init_state_offset())); + // Use T_BOOLEAN for InstanceKlass::_init_state so the compiler + // can generate code to load it as unsigned byte. + Node* inst = make_load(NULL, insp, TypeInt::UBYTE, T_BOOLEAN, MemNode::unordered); + Node* bits = intcon(InstanceKlass::fully_initialized); + + // The test is non-zero if we need to take a slow path. + return _gvn.transform(new SubINode(inst, bits)); + +} + //----------------------------inline_unsafe_allocate--------------------------- -// public native Object Unsafe.allocateInstance(Class cls); +// public native Object Unsafe.allocateInstance0(Class cls) throws InstantiationException; bool LibraryCallKit::inline_unsafe_allocate() { - if (callee()->is_static()) return false; // caller must have the capability! - null_check_receiver(); // null-check, then ignore Node* cls = null_check(argument(1)); - if (stopped()) return true; - Node* kls = load_klass_from_mirror(cls, false, NULL, 0); - kls = null_check(kls); - if (stopped()) return true; // argument was like int.class - - Node* test = NULL; - if (LibraryCallKit::klass_needs_init_guard(kls)) { - // Note: The argument might still be an illegal value like - // Serializable.class or Object[].class. The runtime will handle it. - // But we must make an explicit check for initialization. - Node* insp = basic_plus_adr(kls, in_bytes(InstanceKlass::init_state_offset())); - // Use T_BOOLEAN for InstanceKlass::_init_state so the compiler - // can generate code to load it as unsigned byte. - Node* inst = make_load(NULL, insp, TypeInt::UBYTE, T_BOOLEAN, MemNode::unordered); - Node* bits = intcon(InstanceKlass::fully_initialized); - test = _gvn.transform(new SubINode(inst, bits)); - // The 'test' is non-zero if we need to take a slow path. - } - + Node* test = make_init_guard(kls); Node* obj = new_instance(kls, test); set_result(obj); return true; --- old/src/share/vm/prims/unsafe.cpp 2016-04-12 21:44:33.000000000 +0300 +++ new/src/share/vm/prims/unsafe.cpp 2016-04-12 21:44:33.000000000 +0300 @@ -484,7 +484,7 @@ ////// Allocation requests -UNSAFE_ENTRY(jobject, Unsafe_AllocateInstance(JNIEnv *env, jobject unsafe, jclass cls)) { +UNSAFE_ENTRY(jobject, Unsafe_AllocateInstance0(JNIEnv *env, jobject unsafe, jclass cls)) { ThreadToNativeFromVM ttnfv(thread); return env->AllocObject(cls); } UNSAFE_END @@ -1183,7 +1183,7 @@ {CC "pageSize", CC "()I", FN_PTR(Unsafe_PageSize)}, {CC "defineClass0", CC "(" DC_Args ")" CLS, FN_PTR(Unsafe_DefineClass0)}, - {CC "allocateInstance", CC "(" CLS ")" OBJ, FN_PTR(Unsafe_AllocateInstance)}, + {CC "allocateInstance0", CC "(" CLS ")" OBJ, FN_PTR(Unsafe_AllocateInstance0)}, {CC "throwException", CC "(" THR ")V", FN_PTR(Unsafe_ThrowException)}, {CC "compareAndSwapObject", CC "(" OBJ "J" OBJ "" OBJ ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC "compareAndSwapInt", CC "(" OBJ "J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, --- /dev/null 2016-04-12 21:44:34.000000000 +0300 +++ new/test/compiler/unsafe/AllocateInstance.java 2016-04-12 21:44:33.000000000 +0300 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8153540 + * @modules java.base/jdk.internal.misc + * + * @run main/bootclasspath -Xbatch -XX:CompileCommand=dontinline,*AllocateInstance.test* + * compiler.unsafe.AllocateInstance + */ +package compiler.unsafe; + +import jdk.internal.misc.Unsafe; +import java.util.concurrent.Callable; + +public class AllocateInstance { + static final Unsafe U = Unsafe.getUnsafe(); + + static class T {} + static final Class T_CLASS; + static { + try { + T_CLASS = Class.forName(T.class.getName(), false, ClassLoader.getSystemClassLoader()); + } catch (ClassNotFoundException e) { + throw new Error(e); + } + } + + static abstract class A {} + + static Object testNull() throws InstantiationException { + return U.allocateInstance(null); + } + static Object testPrim() throws InstantiationException { + return U.allocateInstance(int.class); + } + static Object testPrimArray() throws InstantiationException { + return U.allocateInstance(int[].class); + } + static Object testObjArray() throws InstantiationException { + return U.allocateInstance(Object[].class); + } + static Object testIntf() throws InstantiationException { + return U.allocateInstance(Runnable.class); + } + static Object testAbstract() throws InstantiationException { + return U.allocateInstance(A.class); + } + static Object testObject() throws InstantiationException { + return U.allocateInstance(Object.class); + } + static Object testObjectInit() throws InstantiationException { + return U.allocateInstance(T_CLASS); + } + static Object testReflective(Class c) throws InstantiationException { + return U.allocateInstance(c); + } + + static void run(String name, Callable c, boolean shouldSucceed, boolean verbose) { + if (verbose) System.out.print(name); + run(c, shouldSucceed, verbose); + } + + static void run(Class c, boolean shouldSucceed, boolean verbose) { + if (verbose) System.out.print(c != null ? c.getName() : "null"); + run(() -> testReflective(c), shouldSucceed, verbose); + } + + static void run(Callable c, boolean shouldSucceed, boolean verbose) { + try { + Object o = c.call(); + if (o == null) { + System.out.println(" => null"); + } else { + if (verbose) System.out.println(" => allocated"); + } + if (!shouldSucceed) { + throw new AssertionError("allocation should fail"); + } + } catch (Exception e) { + if (verbose) { + System.out.println(" => exception " + e.getClass().getName() + ": " + e.getMessage()); + } + if (shouldSucceed) { + throw new AssertionError("allocation should succeed"); + } + } + } + + static void runTests(boolean verbose) { + run("null", AllocateInstance::testNull, false, verbose); + run("int", AllocateInstance::testPrim, false, verbose); + run("int[]", AllocateInstance::testPrimArray, false, verbose); + run("Object[]", AllocateInstance::testObjArray, false, verbose); + run("interface", AllocateInstance::testIntf, false, verbose); + run("abstract", AllocateInstance::testAbstract, false, verbose); + run("Object", AllocateInstance::testObject, true, verbose); + run("ObjectInit", AllocateInstance::testObjectInit, true, verbose); + + run((Class)null, false, verbose); + run(Object.class, true, verbose); + run(A.class, false, verbose); + run(Runnable.class, false, verbose); + run(Object[].class, false, verbose); + run(int.class, false, verbose); + run(int[].class, false, verbose); + } + + static void warmup() { + for (int i = 0; i < 20_000; i ++) { + runTests(false); + } + } + public static void main(String[] args) { + runTests(true); + warmup(); + runTests(true); + System.out.println("TEST PASSED"); + } +}