changeset 10226:ffc348308de2 jdk8u40-b14

Merge
author amurillo
date Fri, 07 Nov 2014 09:22:58 -0800
parents 17481e84599c (current diff) 2f1ae696419c (diff)
children f5ba1bbe180b 48ff867c7f24 0a4ed597f229
files
diffstat 8 files changed, 407 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/make/mapfiles/libjava/mapfile-vers	Wed Nov 05 12:54:10 2014 -0800
+++ b/make/mapfiles/libjava/mapfile-vers	Fri Nov 07 09:22:58 2014 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1997, 2014, 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
@@ -269,6 +269,9 @@
 		Java_sun_reflect_Reflection_getCallerClass__;
 		Java_sun_reflect_Reflection_getCallerClass__I;
 		Java_sun_reflect_Reflection_getClassAccessFlags;
+		Java_sun_misc_URLClassPath_knownToNotExist0;
+                Java_sun_misc_URLClassPath_getLookupCacheURLs;
+                Java_sun_misc_URLClassPath_getLookupCacheForClassLoader;
                 Java_sun_misc_Version_getJdkVersionInfo;
                 Java_sun_misc_Version_getJdkSpecialVersion;
                 Java_sun_misc_Version_getJvmVersionInfo;
--- a/src/share/classes/sun/misc/Launcher.java	Wed Nov 05 12:54:10 2014 -0800
+++ b/src/share/classes/sun/misc/Launcher.java	Fri Nov 07 09:22:58 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2014, 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
@@ -162,6 +162,8 @@
          */
         public ExtClassLoader(File[] dirs) throws IOException {
             super(getExtURLs(dirs), null, factory);
+            SharedSecrets.getJavaNetAccess().
+                getURLClassPath(this).initLookupCache(this);
         }
 
         private static File[] getExtDirs() {
@@ -285,11 +287,15 @@
             });
         }
 
+        final URLClassPath ucp;
+
         /*
          * Creates a new AppClassLoader
          */
         AppClassLoader(URL[] urls, ClassLoader parent) {
             super(urls, parent, factory);
+            ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
+            ucp.initLookupCache(this);
         }
 
         /**
@@ -305,6 +311,23 @@
                     sm.checkPackageAccess(name.substring(0, i));
                 }
             }
+
+            if (ucp.knownToNotExist(name)) {
+                // The class of the given name is not found in the parent
+                // class loader as well as its local URLClassPath.
+                // Check if this class has already been defined dynamically;
+                // if so, return the loaded class; otherwise, skip the parent
+                // delegation and findClass.
+                Class<?> c = findLoadedClass(name);
+                if (c != null) {
+                    if (resolve) {
+                        resolveClass(c);
+                    }
+                    return c;
+                }
+                throw new ClassNotFoundException(name);
+            }
+
             return (super.loadClass(name, resolve));
         }
 
@@ -386,6 +409,7 @@
                 urls = new URL[0];
             }
             bcp = new URLClassPath(urls, factory);
+            bcp.initLookupCache(null);
         }
     }
 
--- a/src/share/classes/sun/misc/URLClassPath.java	Wed Nov 05 12:54:10 2014 -0800
+++ b/src/share/classes/sun/misc/URLClassPath.java	Fri Nov 07 09:22:58 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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
@@ -38,6 +38,7 @@
 import java.net.JarURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLClassLoader;
 import java.net.URLConnection;
 import java.net.HttpURLConnection;
 import java.net.URLStreamHandler;
@@ -52,6 +53,7 @@
 import java.security.cert.Certificate;
 import sun.misc.FileURLMapper;
 import sun.net.util.URLUtil;
+import sun.security.action.GetPropertyAction;
 
 /**
  * This class is used to maintain a search path of URLs for loading classes
@@ -63,15 +65,18 @@
     final static String USER_AGENT_JAVA_VERSION = "UA-Java-Version";
     final static String JAVA_VERSION;
     private static final boolean DEBUG;
+    private static final boolean DEBUG_LOOKUP_CACHE;
     private static final boolean DISABLE_JAR_CHECKING;
 
     static {
         JAVA_VERSION = java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("java.version"));
+            new GetPropertyAction("java.version"));
         DEBUG        = (java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.debug")) != null);
+            new GetPropertyAction("sun.misc.URLClassPath.debug")) != null);
+        DEBUG_LOOKUP_CACHE = (java.security.AccessController.doPrivileged(
+            new GetPropertyAction("sun.misc.URLClassPath.debugLookupCache")) != null);
         String p = java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.disableJarChecking"));
+            new GetPropertyAction("sun.misc.URLClassPath.disableJarChecking"));
         DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
     }
 
@@ -149,6 +154,12 @@
 
             urls.add(0, url);
             path.add(url);
+
+            if (lookupCacheURLs != null) {
+                // The lookup cache is no longer valid, since getLookupCache()
+                // does not consider the newly added url.
+                disableAllLookupCaches();
+            }
         }
     }
 
@@ -172,7 +183,8 @@
      */
     public URL findResource(String name, boolean check) {
         Loader loader;
-        for (int i = 0; (loader = getLoader(i)) != null; i++) {
+        int[] cache = getLookupCache(name);
+        for (int i = 0; (loader = getNextLoader(cache, i)) != null; i++) {
             URL url = loader.findResource(name, check);
             if (url != null) {
                 return url;
@@ -195,7 +207,8 @@
         }
 
         Loader loader;
-        for (int i = 0; (loader = getLoader(i)) != null; i++) {
+        int[] cache = getLookupCache(name);
+        for (int i = 0; (loader = getNextLoader(cache, i)) != null; i++) {
             Resource res = loader.getResource(name, check);
             if (res != null) {
                 return res;
@@ -215,6 +228,7 @@
                                      final boolean check) {
         return new Enumeration<URL>() {
             private int index = 0;
+            private int[] cache = getLookupCache(name);
             private URL url = null;
 
             private boolean next() {
@@ -222,7 +236,7 @@
                     return true;
                 } else {
                     Loader loader;
-                    while ((loader = getLoader(index++)) != null) {
+                    while ((loader = getNextLoader(cache, index++)) != null) {
                         url = loader.findResource(name, check);
                         if (url != null) {
                             return true;
@@ -262,6 +276,7 @@
                                     final boolean check) {
         return new Enumeration<Resource>() {
             private int index = 0;
+            private int[] cache = getLookupCache(name);
             private Resource res = null;
 
             private boolean next() {
@@ -269,7 +284,7 @@
                     return true;
                 } else {
                     Loader loader;
-                    while ((loader = getLoader(index++)) != null) {
+                    while ((loader = getNextLoader(cache, index++)) != null) {
                         res = loader.getResource(name, check);
                         if (res != null) {
                             return true;
@@ -298,6 +313,151 @@
         return getResources(name, true);
     }
 
+    private static volatile boolean lookupCacheEnabled
+        = "true".equals(VM.getSavedProperty("sun.cds.enableSharedLookupCache"));
+    private URL[] lookupCacheURLs;
+    private ClassLoader lookupCacheLoader;
+
+    synchronized void initLookupCache(ClassLoader loader) {
+        if ((lookupCacheURLs = getLookupCacheURLs(loader)) != null) {
+            lookupCacheLoader = loader;
+        } else {
+            // This JVM instance does not support lookup cache.
+            disableAllLookupCaches();
+        }
+    }
+
+    static void disableAllLookupCaches() {
+        lookupCacheEnabled = false;
+    }
+
+    private static native URL[] getLookupCacheURLs(ClassLoader loader);
+    private static native int[] getLookupCacheForClassLoader(ClassLoader loader,
+                                                             String name);
+    private static native boolean knownToNotExist0(ClassLoader loader,
+                                                   String className);
+
+    synchronized boolean knownToNotExist(String className) {
+        if (lookupCacheURLs != null && lookupCacheEnabled) {
+            return knownToNotExist0(lookupCacheLoader, className);
+        }
+
+        // Don't know if this class exists or not -- need to do a full search.
+        return false;
+    }
+
+    /**
+     * Returns an array of the index to lookupCacheURLs that may
+     * contain the specified resource. The values in the returned
+     * array are in strictly ascending order and must be a valid index
+     * to lookupCacheURLs array.
+     *
+     * This method returns an empty array if the specified resource
+     * cannot be found in this URLClassPath. If there is no lookup
+     * cache or it's disabled, this method returns null and the lookup
+     * should search the entire classpath.
+     *
+     * Example: if lookupCacheURLs contains {a.jar, b.jar, c.jar, d.jar}
+     * and package "foo" only exists in a.jar and c.jar,
+     * getLookupCache("foo/Bar.class") will return {0, 2}
+     *
+     * @param name the resource name
+     * @return an array of the index to lookupCacheURLs that may contain the
+     *         specified resource; or null if no lookup cache is used.
+     */
+    private synchronized int[] getLookupCache(String name) {
+        if (lookupCacheURLs == null || !lookupCacheEnabled) {
+            return null;
+        }
+
+        int[] cache = getLookupCacheForClassLoader(lookupCacheLoader, name);
+        if (cache != null && cache.length > 0) {
+            int maxindex = cache[cache.length - 1]; // cache[] is strictly ascending.
+            if (!ensureLoaderOpened(maxindex)) {
+                if (DEBUG_LOOKUP_CACHE) {
+                    System.out.println("Expanded loaders FAILED " +
+                                       loaders.size() + " for maxindex=" + maxindex);
+                }
+                return null;
+            }
+        }
+
+        return cache;
+    }
+
+    private boolean ensureLoaderOpened(int index) {
+        if (loaders.size() <= index) {
+            // Open all Loaders up to, and including, index
+            if (getLoader(index) == null) {
+                return false;
+            }
+            if (!lookupCacheEnabled) {
+                // cache was invalidated as the result of the above call.
+                return false;
+            }
+            if (DEBUG_LOOKUP_CACHE) {
+                System.out.println("Expanded loaders " + loaders.size() +
+                                   " to index=" + index);
+            }
+        }
+        return true;
+    }
+
+    /*
+     * The CLASS-PATH attribute was expanded by the VM when building
+     * the resource lookup cache in the same order as the getLoader
+     * method does. This method validates if the URL from the lookup
+     * cache matches the URL of the Loader at the given index;
+     * otherwise, this method disables the lookup cache.
+     */
+    private synchronized void validateLookupCache(int index,
+                                                  String urlNoFragString) {
+        if (lookupCacheURLs != null && lookupCacheEnabled) {
+            if (index < lookupCacheURLs.length &&
+                urlNoFragString.equals(
+                    URLUtil.urlNoFragString(lookupCacheURLs[index]))) {
+                return;
+            }
+            if (DEBUG || DEBUG_LOOKUP_CACHE) {
+                System.out.println("WARNING: resource lookup cache invalidated "
+                                   + "for lookupCacheLoader at " + index);
+            }
+            disableAllLookupCaches();
+        }
+    }
+
+    /**
+     * Returns the next Loader that may contain the resource to
+     * lookup. If the given cache is null, return loaders.get(index)
+     * that may be lazily created; otherwise, cache[index] is the next
+     * Loader that may contain the resource to lookup and so returns
+     * loaders.get(cache[index]).
+     *
+     * If cache is non-null, loaders.get(cache[index]) must be present.
+     *
+     * @param cache lookup cache. If null, search the entire class path
+     * @param index index to the given cache array; or to the loaders list.
+     */
+    private synchronized Loader getNextLoader(int[] cache, int index) {
+        if (closed) {
+            return null;
+        }
+        if (cache != null) {
+            if (index < cache.length) {
+                Loader loader = loaders.get(cache[index]);
+                if (DEBUG_LOOKUP_CACHE) {
+                    System.out.println("HASCACHE: Loading from : " + cache[index]
+                                       + " = " + loader.getBaseURL());
+                }
+                return loader;
+            } else {
+                return null; // finished iterating over cache[]
+            }
+        } else {
+            return getLoader(index);
+        }
+    }
+
     /*
      * Returns the Loader at the specified position in the URL search
      * path. The URLs are opened and expanded as needed. Returns null
@@ -341,9 +501,13 @@
                 continue;
             }
             // Finally, add the Loader to the search path.
+            validateLookupCache(loaders.size(), urlNoFragString);
             loaders.add(loader);
             lmap.put(urlNoFragString, loader);
         }
+        if (DEBUG_LOOKUP_CACHE) {
+            System.out.println("NOCACHE: Loading from : " + index );
+        }
         return loaders.get(index);
     }
 
--- a/src/share/classes/sun/misc/VM.java	Wed Nov 05 12:54:10 2014 -0800
+++ b/src/share/classes/sun/misc/VM.java	Fri Nov 07 09:22:58 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2014, 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
@@ -313,6 +313,9 @@
 
         // used by sun.launcher.LauncherHelper
         props.remove("sun.java.launcher.diag");
+
+        // used by sun.misc.URLClassPath
+        props.remove("sun.cds.enableSharedLookupCache");
     }
 
     // Initialize any miscellenous operating system settings that need to be
--- a/src/share/javavm/export/jvm.h	Wed Nov 05 12:54:10 2014 -0800
+++ b/src/share/javavm/export/jvm.h	Fri Nov 07 09:22:58 2014 -0800
@@ -1391,6 +1391,31 @@
 JNIEXPORT jobjectArray JNICALL
 JVM_GetThreadStateNames(JNIEnv* env, jint javaThreadState, jintArray values);
 
+/*
+ * Returns true if the JVM's lookup cache indicates that this class is
+ * known to NOT exist for the given loader.
+ */
+JNIEXPORT jboolean JNICALL
+JVM_KnownToNotExist(JNIEnv *env, jobject loader, const char *classname);
+
+/*
+ * Returns an array of all URLs that are stored in the JVM's lookup cache
+ * for the given loader. NULL if the lookup cache is unavailable.
+ */
+JNIEXPORT jobjectArray JNICALL
+JVM_GetResourceLookupCacheURLs(JNIEnv *env, jobject loader);
+
+/*
+ * Returns an array of all URLs that *may* contain the resource_name for the
+ * given loader. This function returns an integer array, each element
+ * of which can be used to index into the array returned by
+ * JVM_GetResourceLookupCacheURLs of the same loader to determine the
+ * URLs.
+ */
+JNIEXPORT jintArray JNICALL
+JVM_GetResourceLookupCache(JNIEnv *env, jobject loader, const char *resource_name);
+
+
 /* =========================================================================
  * The following defines a private JVM interface that the JDK can query
  * for the JVM version and capabilities.  sun.misc.Version defines
--- a/src/share/native/java/lang/ClassLoader.c	Wed Nov 05 12:54:10 2014 -0800
+++ b/src/share/native/java/lang/ClassLoader.c	Fri Nov 07 09:22:58 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2014, 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
@@ -51,7 +51,7 @@
 
 /* Convert java string to UTF char*. Use local buffer if possible,
    otherwise malloc new memory. Returns null IFF malloc failed. */
-static char*
+char*
 getUTF(JNIEnv *env, jstring str, char* localBuf, int bufSize)
 {
     char* utfStr = NULL;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/native/sun/misc/URLClassPath.c	Fri Nov 07 09:22:58 2014 -0800
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+#include <string.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jlong.h"
+#include "jvm.h"
+#include "jdk_util.h"
+
+#include "sun_misc_URLClassPath.h"
+
+extern char*
+getUTF(JNIEnv *env, jstring str, char* localBuf, int bufSize);
+
+
+JNIEXPORT jboolean JNICALL
+Java_sun_misc_URLClassPath_knownToNotExist0(JNIEnv *env, jclass cls, jobject loader,
+                                            jstring classname)
+{
+    char *clname;
+    jboolean result = JNI_FALSE;
+    char buf[128];
+
+    if (classname == NULL) {
+        JNU_ThrowNullPointerException(env, NULL);
+        return result;
+    }
+
+    clname = getUTF(env, classname, buf, sizeof(buf));
+    if (clname == NULL) {
+        JNU_ThrowOutOfMemoryError(env, NULL);
+        return result;
+    }
+    VerifyFixClassname(clname);
+
+    if (!VerifyClassname(clname, JNI_TRUE)) {  /* expects slashed name */
+        goto done;
+    }
+
+    result = JVM_KnownToNotExist(env, loader, clname);
+
+ done:
+    if (clname != buf) {
+        free(clname);
+    }
+
+    return result;
+}
+
+JNIEXPORT jobjectArray JNICALL
+Java_sun_misc_URLClassPath_getLookupCacheURLs(JNIEnv *env, jclass cls, jobject loader)
+{
+    return JVM_GetResourceLookupCacheURLs(env, loader);
+}
+
+
+JNIEXPORT jintArray JNICALL
+Java_sun_misc_URLClassPath_getLookupCacheForClassLoader(JNIEnv *env, jclass cls,
+                                                        jobject loader,
+                                                        jstring resource_name)
+{
+    char *resname;
+    jintArray result = NULL;
+    char buf[128];
+
+    if (resource_name == NULL) {
+        JNU_ThrowNullPointerException(env, NULL);
+        return result;
+    }
+
+    resname = getUTF(env, resource_name, buf, sizeof(buf));
+    if (resname == NULL) {
+        JNU_ThrowOutOfMemoryError(env, NULL);
+        return result;
+    }
+    result = JVM_GetResourceLookupCache(env, loader, resname);
+
+ done:
+    if (resname != buf) {
+        free(resname);
+    }
+
+    return result;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/URLClassPath/EnableLookupCache.java	Fri Nov 07 09:22:58 2014 -0800
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, 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 8061651
+ * @summary -Dsun.cds.enableSharedLookupCache specified on the command-line
+ *          should have no effect.
+ * @run main/othervm -Dsun.cds.enableSharedLookupCache=true -Xshare:off -Dfoo.foo.bar=xyz EnableLookupCache
+ */
+
+public class EnableLookupCache {
+    public static void main(String[] args) throws Exception {
+        // If JVM is started with -Xshare:off, the sun.cds.enableSharedLookupCache
+        // should never be true, even if it has been explicitly set in the
+        // command-line.
+        String prop = "sun.cds.enableSharedLookupCache";
+        String value = System.getProperty(prop);
+        System.out.println("System.getProperty(\"" + prop + "\") = \"" + value+ "\"");
+
+        if ("true".equals(value)) {
+            System.out.println("Test FAILED: system property " + prop +
+                               " is \"true\" (unexpected)");
+            throw new RuntimeException(prop + " should not be " + value);
+        }
+
+        // Make sure the -D... arguments in the @run tag are indeed used.
+        prop = "foo.foo.bar";
+        value = System.getProperty(prop);
+        System.out.println("System.getProperty(\"" + prop + "\") = \"" + value+ "\"");
+        if (!"xyz".equals(value)) {
+            System.out.println("Test FAILED: system property " + prop +
+                               " should be \"xyz\" -- is JTREG set up properly?");
+            throw new RuntimeException(prop + " should not be " + value);
+        }
+
+
+        // We should be able to load the other classes without issue.
+        A.test();
+        B.test();
+        System.out.println("Test PASSED");
+    }
+
+    static class A {static void test() {}}
+    static class B {static void test() {}}
+}
+