# HG changeset patch # User bchristi # Date 1572896544 28800 # Node ID d67ebc838ab8d05da50ad20bfb0bab613004e4fd # Parent 1d1f9c43138fe1d72d42f699dc4d713530382c11 8233091: Backout JDK-8212117: Class.forName loads a class but not linked if class is not initialized Reviewed-by: alanb, dholmes, mchung diff -r 1d1f9c43138f -r d67ebc838ab8 make/hotspot/symbols/symbols-unix --- a/make/hotspot/symbols/symbols-unix Mon Nov 04 11:05:10 2019 -0800 +++ b/make/hotspot/symbols/symbols-unix Mon Nov 04 11:42:24 2019 -0800 @@ -148,7 +148,6 @@ JVM_IsThreadAlive JVM_IsVMGeneratedMethodIx JVM_LatestUserDefinedLoader -JVM_LinkClass JVM_LoadLibrary JVM_MaxMemory JVM_MaxObjectInspectionAge diff -r 1d1f9c43138f -r d67ebc838ab8 src/hotspot/share/include/jvm.h --- a/src/hotspot/share/include/jvm.h Mon Nov 04 11:05:10 2019 -0800 +++ b/src/hotspot/share/include/jvm.h Mon Nov 04 11:42:24 2019 -0800 @@ -346,11 +346,6 @@ JNIEXPORT jclass JNICALL JVM_FindPrimitiveClass(JNIEnv *env, const char *utf); -/* - * Link the 'arg' class - */ -JNIEXPORT void JNICALL -JVM_LinkClass(JNIEnv *env, jclass classClass, jclass arg); /* * Find a class from a boot class loader. Returns NULL if class not found. diff -r 1d1f9c43138f -r d67ebc838ab8 src/hotspot/share/prims/jni.cpp --- a/src/hotspot/share/prims/jni.cpp Mon Nov 04 11:05:10 2019 -0800 +++ b/src/hotspot/share/prims/jni.cpp Mon Nov 04 11:42:24 2019 -0800 @@ -419,7 +419,7 @@ } TempNewSymbol sym = SymbolTable::new_symbol(name); - result = find_class_from_class_loader(env, sym, true, true, loader, + result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, thread); if (log_is_enabled(Debug, class, resolve) && result != NULL) { @@ -3208,7 +3208,7 @@ Handle protection_domain; // null protection domain TempNewSymbol sym = SymbolTable::new_symbol(name); - jclass result = find_class_from_class_loader(env, sym, true, true, loader, protection_domain, true, CHECK_NULL); + jclass result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL); if (log_is_enabled(Debug, class, resolve) && result != NULL) { trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))); diff -r 1d1f9c43138f -r d67ebc838ab8 src/hotspot/share/prims/jvm.cpp --- a/src/hotspot/share/prims/jvm.cpp Mon Nov 04 11:05:10 2019 -0800 +++ b/src/hotspot/share/prims/jvm.cpp Mon Nov 04 11:42:24 2019 -0800 @@ -742,17 +742,6 @@ // Misc. class handling /////////////////////////////////////////////////////////// -JVM_ENTRY(void, JVM_LinkClass(JNIEnv* env, jclass classClass, jclass arg)) - JVMWrapper("JVM_LinkClass"); - - oop r = JNIHandles::resolve(arg); - Klass* klass = java_lang_Class::as_Klass(r); - - if (!ClassForNameDeferLinking && klass->is_instance_klass()) { - InstanceKlass::cast(klass)->link_class(CHECK); - } -JVM_END - JVM_ENTRY(jclass, JVM_GetCallerClass(JNIEnv* env)) JVMWrapper("JVM_GetCallerClass"); @@ -863,10 +852,9 @@ Handle h_loader(THREAD, loader_oop); Handle h_prot(THREAD, protection_domain); - - jboolean link = !ClassForNameDeferLinking; - jclass result = find_class_from_class_loader(env, h_name, init, link, h_loader, + jclass result = find_class_from_class_loader(env, h_name, init, h_loader, h_prot, false, THREAD); + if (log_is_enabled(Debug, class, resolve) && result != NULL) { trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))); } @@ -903,7 +891,7 @@ } Handle h_loader(THREAD, class_loader); Handle h_prot (THREAD, protection_domain); - jclass result = find_class_from_class_loader(env, h_name, init, false, h_loader, + jclass result = find_class_from_class_loader(env, h_name, init, h_loader, h_prot, true, thread); if (log_is_enabled(Debug, class, resolve) && result != NULL) { @@ -3410,12 +3398,9 @@ // Shared JNI/JVM entry points ////////////////////////////////////////////////////////////// -jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, jboolean link, +jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS) { - // Initialization also implies linking - check for coherent args - assert((init && link) || !init, "incorrect use of init/link arguments"); - // Security Note: // The Java level wrapper will perform the necessary security check allowing // us to pass the NULL as the initiating class loader. The VM is responsible for @@ -3424,11 +3409,9 @@ // if there is no security manager in 3-arg Class.forName(). Klass* klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError != 0, CHECK_NULL); - // Check if we should initialize the class (which implies linking), or just link it + // Check if we should initialize the class if (init && klass->is_instance_klass()) { klass->initialize(CHECK_NULL); - } else if (link && klass->is_instance_klass()) { - InstanceKlass::cast(klass)->link_class(CHECK_NULL); } return (jclass) JNIHandles::make_local(env, klass->java_mirror()); } diff -r 1d1f9c43138f -r d67ebc838ab8 src/hotspot/share/prims/jvm_misc.hpp --- a/src/hotspot/share/prims/jvm_misc.hpp Mon Nov 04 11:05:10 2019 -0800 +++ b/src/hotspot/share/prims/jvm_misc.hpp Mon Nov 04 11:42:24 2019 -0800 @@ -31,8 +31,7 @@ // Useful entry points shared by JNI and JVM interface. // We do not allow real JNI or JVM entry point to call each other. -jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, jboolean link, - Handle loader, Handle protection_domain, jboolean throwError, TRAPS); +jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS); void trace_class_resolution(Klass* to_class); diff -r 1d1f9c43138f -r d67ebc838ab8 src/hotspot/share/runtime/globals.hpp --- a/src/hotspot/share/runtime/globals.hpp Mon Nov 04 11:05:10 2019 -0800 +++ b/src/hotspot/share/runtime/globals.hpp Mon Nov 04 11:42:24 2019 -0800 @@ -2223,9 +2223,6 @@ "Maximum total size of NIO direct-buffer allocations") \ range(0, max_jlong) \ \ - product(bool, ClassForNameDeferLinking, false, \ - "Revert to not linking in Class.forName()") \ - \ /* Flags used for temporary code during development */ \ \ diagnostic(bool, UseNewCode, false, \ diff -r 1d1f9c43138f -r d67ebc838ab8 src/java.base/share/classes/java/lang/Class.java --- a/src/java.base/share/classes/java/lang/Class.java Mon Nov 04 11:05:10 2019 -0800 +++ b/src/java.base/share/classes/java/lang/Class.java Mon Nov 04 11:42:24 2019 -0800 @@ -392,10 +392,6 @@ * * @see java.lang.Class#forName(String) * @see java.lang.ClassLoader - * - * @jls 12.2 Loading of Classes and Interfaces - * @jls 12.3 Linking of Classes and Interfaces - * @jls 12.4 Initialization of Classes and Interfaces * @since 1.2 */ @CallerSensitive @@ -442,10 +438,6 @@ *

This method does not check whether the requested class is * accessible to its caller.

* - *

Note that this method throws errors related to loading and linking as - * specified in Sections 12.2 and 12.3 of The Java Language - * Specification. - * * @apiNote * This method returns {@code null} on failure rather than * throwing a {@link ClassNotFoundException}, as is done by @@ -473,8 +465,6 @@ * in a module. * * - * @jls 12.2 Loading of Classes and Interfaces - * @jls 12.3 Linking of Classes and Interfaces * @since 9 * @spec JPMS */ @@ -498,21 +488,13 @@ cl = module.getClassLoader(); } - Class ret; if (cl != null) { - ret = cl.loadClass(module, name); + return cl.loadClass(module, name); } else { - ret = BootLoader.loadClass(module, name); + return BootLoader.loadClass(module, name); } - if (ret != null) { - // The loaded class should also be linked - linkClass(ret); - } - return ret; } - private static native void linkClass(Class c); - /** * Creates a new instance of the class represented by this {@code Class} * object. The class is instantiated as if by a {@code new} diff -r 1d1f9c43138f -r d67ebc838ab8 src/java.base/share/classes/java/lang/invoke/MethodHandles.java --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Mon Nov 04 11:05:10 2019 -0800 +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Mon Nov 04 11:42:24 2019 -0800 @@ -1933,17 +1933,12 @@ } /** - * Looks up a class by name from the lookup context defined by this {@code Lookup} object. - * This method attempts to locate, load, and link the class, and then determines whether - * the class is accessible to this {@code Lookup} object. The static + * Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static * initializer of the class is not run. *

* The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, its class - * loader, and the {@linkplain #lookupModes() lookup modes}. - *

- * Note that this method throws errors related to loading and linking as - * specified in Sections 12.2 and 12.3 of The Java Language - * Specification. + * loader, and the {@linkplain #lookupModes() lookup modes}. In particular, the method first attempts to + * load the requested class, and then determines whether the class is accessible to this lookup object. * * @param targetName the fully qualified name of the class to be looked up. * @return the requested class. @@ -1955,9 +1950,6 @@ * modes. * @throws SecurityException if a security manager is present and it * refuses access - * - * @jls 12.2 Loading of Classes and Interfaces - * @jls 12.3 Linking of Classes and Interfaces * @since 9 */ public Class findClass(String targetName) throws ClassNotFoundException, IllegalAccessException { diff -r 1d1f9c43138f -r d67ebc838ab8 src/java.base/share/classes/sun/launcher/LauncherHelper.java --- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java Mon Nov 04 11:05:10 2019 -0800 +++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java Mon Nov 04 11:42:24 2019 -0800 @@ -62,7 +62,6 @@ import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; -import java.security.AccessControlException; import java.text.Normalizer; import java.text.MessageFormat; import java.util.ArrayList; @@ -725,9 +724,6 @@ } catch (LinkageError le) { abort(null, "java.launcher.module.error3", mainClass, m.getName(), le.getClass().getName() + ": " + le.getLocalizedMessage()); - } catch (AccessControlException ace) { - abort(ace, "java.launcher.module.error5", mainClass, m.getName(), - ace.getClass().getName(), ace.getLocalizedMessage()); } if (c == null) { abort(null, "java.launcher.module.error2", mainClass, mainModule); @@ -784,9 +780,6 @@ } catch (LinkageError le) { abort(le, "java.launcher.cls.error6", cn, le.getClass().getName() + ": " + le.getLocalizedMessage()); - } catch (AccessControlException ace) { - abort(ace, "java.launcher.cls.error7", cn, - ace.getClass().getName(), ace.getLocalizedMessage()); } return mainClass; } diff -r 1d1f9c43138f -r d67ebc838ab8 src/java.base/share/native/libjava/Class.c --- a/src/java.base/share/native/libjava/Class.c Mon Nov 04 11:05:10 2019 -0800 +++ b/src/java.base/share/native/libjava/Class.c Mon Nov 04 11:42:24 2019 -0800 @@ -73,7 +73,6 @@ {"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations}, {"getNestHost0", "()" CLS, (void *)&JVM_GetNestHost}, {"getNestMembers0", "()[" CLS, (void *)&JVM_GetNestMembers}, - {"linkClass", "(" CLS ")V", (void *)&JVM_LinkClass}, }; #undef OBJ diff -r 1d1f9c43138f -r d67ebc838ab8 test/hotspot/jtreg/gc/logging/TestMetaSpaceLog.java --- a/test/hotspot/jtreg/gc/logging/TestMetaSpaceLog.java Mon Nov 04 11:05:10 2019 -0800 +++ b/test/hotspot/jtreg/gc/logging/TestMetaSpaceLog.java Mon Nov 04 11:42:24 2019 -0800 @@ -130,7 +130,7 @@ public static void loadClass(WhiteBox wb) { try { URLClassLoader ucl = new URLClassLoader(urls); - ucl.loadClass("case00"); + Class.forName("case00", false, ucl); } catch (Exception e) { e.printStackTrace(); } diff -r 1d1f9c43138f -r d67ebc838ab8 test/hotspot/jtreg/serviceability/jvmti/ClassStatus/ClassStatus.java --- a/test/hotspot/jtreg/serviceability/jvmti/ClassStatus/ClassStatus.java Mon Nov 04 11:05:10 2019 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019, 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. - * - * 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 8212117 - * @summary Verify JVMTI GetClassStatus returns CLASS_PREPARE after call to Class.forName() - * @run main/othervm/native -agentlib:ClassStatus ClassStatus - */ - - -public class ClassStatus { - static { - try { - System.out.println("ClassStatus static block"); - System.loadLibrary("ClassStatus"); - } catch (UnsatisfiedLinkError ule) { - System.err.println("Could not load ClassStatus library"); - System.err.println("java.library.path: " - + System.getProperty("java.library.path")); - throw ule; - } - } - - static native int check(Class klass); - - public static void main(String[] args) throws ClassNotFoundException { - ClassLoader loader = ClassStatus.class.getClassLoader(); - Module module = loader.getUnnamedModule(); - - // Load class, but don't initialize it - Class foo2 = Class.forName(module, "Foo2"); - Class foo3 = Class.forName("Foo3", false, loader); - - System.out.println("Loaded: " + foo2); - System.out.println("Loaded: " + foo3); - - int status2 = check(foo2); - int status3 = check(foo3); - - new Foo2().bar(); - new Foo3().bar(); - - if (status2 != 0) { - System.out.println("The agent returned non-zero exit status for Foo2: " + status2); - } - if (status3 != 0) { - System.out.println("The agent returned non-zero exit status for Foo3: " + status3); - } - if (status2 != 0 || status3 != 0) { - throw new RuntimeException("Non-zero status returned from the agent"); - } - } -} - -class Foo2 { - static { - System.out.println("Foo2 is initialized"); - } - void bar() { - System.out.println("Foo2.bar() is called"); - } -} - -class Foo3 { - static { - System.out.println("Foo3 is initialized"); - } - void bar() { - System.out.println("Foo3.bar() is called"); - } -} diff -r 1d1f9c43138f -r d67ebc838ab8 test/hotspot/jtreg/serviceability/jvmti/ClassStatus/libClassStatus.c --- a/test/hotspot/jtreg/serviceability/jvmti/ClassStatus/libClassStatus.c Mon Nov 04 11:05:10 2019 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2019, 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. - * - * 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. - */ - -#include -#include -#include -#include -#include "jvmti.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef JNI_ENV_ARG - -#ifdef __cplusplus -#define JNI_ENV_ARG(x, y) y -#define JNI_ENV_PTR(x) x -#else -#define JNI_ENV_ARG(x,y) x, y -#define JNI_ENV_PTR(x) (*x) -#endif - -#endif - -#define PASSED 0 -#define FAILED 2 - -static jvmtiEnv* jvmti = NULL; - -static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); - -JNIEXPORT jint JNICALL -Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { - return Agent_Initialize(jvm, options, reserved); -} - -JNIEXPORT jint JNICALL -Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { - return Agent_Initialize(jvm, options, reserved); -} - -JNIEXPORT jint JNICALL -JNI_OnLoad(JavaVM *jvm, void *reserved) { - return JNI_VERSION_9; -} - -static void -check_jvmti_error(jvmtiEnv *jvmti, char* fname, jvmtiError err) { - if (err != JVMTI_ERROR_NONE) { - printf(" ## %s error: %d\n", fname, err); - fflush(0); - exit(err); - } -} - -static char* -get_class_signature(jvmtiEnv *jvmti, jclass klass) { - char* sign = NULL; - jvmtiError err = (*jvmti)->GetClassSignature(jvmti, klass, &sign, NULL); - - check_jvmti_error(jvmti, "GetClassSignature", err); - return sign; -} - -static jboolean -is_class_status_prepared(jvmtiEnv *jvmti, jclass klass) { - char* sign = get_class_signature(jvmti, klass); - jint status = 0; - jvmtiError err = (*jvmti)->GetClassStatus(jvmti, klass, &status); - - check_jvmti_error(jvmti, "GetClassStatus", err); - printf(" Class %s status: 0x%08x\n", sign, status); - printf(" Class %s is prepared: %d\n", sign, (status & JVMTI_CLASS_STATUS_PREPARED) != 0); - fflush(0); - - return (status & JVMTI_CLASS_STATUS_PREPARED) != 0; -} - -static jboolean -is_class_in_loaded_classes(JNIEnv *env, jclass klass) { - char* sign = get_class_signature(jvmti, klass); - jint class_count = 0; - jclass* classes = NULL; - jvmtiError err = (*jvmti)->GetLoadedClasses(jvmti, &class_count, &classes); - - check_jvmti_error(jvmti, "GetLoadedClasses", err); - - for (int i = 0; i < class_count; i++) { - jclass cls = classes[i]; - jboolean same = (*env)->IsSameObject(env, cls, klass); - if (same) { - printf("Found class %s in the list of loaded classes\n", sign); - fflush(0); - return JNI_TRUE; - } - } - printf("Error: Have not found class %s in the list of loaded classes\n", sign); - fflush(0); - return JNI_FALSE; -} - -static void JNICALL -ClassPrepare(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) { - char* sign = get_class_signature(jvmti, klass); - - sign = (sign == NULL) ? "NULL" : sign; - - if (strcmp(sign, "LFoo2;") == 0 || strcmp(sign, "LFoo3;") == 0) { - printf("ClassPrepare event for class: %s\n", sign); - fflush(0); - } -} - -static jint -Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { - jvmtiError err; - jint size; - jint res; - jvmtiEventCallbacks callbacks; - - printf("Agent_Initialize started\n"); - fflush(0); - res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), JVMTI_VERSION_9); - if (res != JNI_OK || jvmti == NULL) { - printf("## Agent_Initialize: Error in GetEnv: res: %d, jvmti env: %p\n", res, jvmti); - return JNI_ERR; - } - - size = (jint)sizeof(callbacks); - memset(&callbacks, 0, size); - callbacks.ClassPrepare = ClassPrepare; - - err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size); - check_jvmti_error(jvmti, "## Agent_Initialize: SetEventCallbacks", err); - - err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL); - check_jvmti_error(jvmti, "## Agent_Initialize: SetEventNotificationMode CLASS_PREPARE", err); - return JNI_OK; -} - -JNIEXPORT jint JNICALL -Java_ClassStatus_check(JNIEnv *env, jclass cls, jclass klass) { - if (is_class_in_loaded_classes(env, klass) != JNI_TRUE || - is_class_status_prepared(jvmti, klass) != JNI_TRUE) { - return FAILED; - } - return PASSED; -} - -#ifdef __cplusplus -} -#endif