提交 d4f9253f 编写于 作者: I iklam

8061651: Interface to the Lookup Index Cache to improve URLClassPath search time

Summary: Implemented the interface in sun.misc.URLClassPath and corresponding JVM_XXX APIs
Reviewed-by: mchung, acorn, jiangli, dholmes
上级 081e5a79
#
# 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 @@ SUNWprivate_1.1 {
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;
......
/*
* 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 class Launcher {
*/
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 @@ public class Launcher {
});
}
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 @@ public class Launcher {
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 @@ public class Launcher {
urls = new URL[0];
}
bcp = new URLClassPath(urls, factory);
bcp.initLookupCache(null);
}
}
......
/*
* 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.util.jar.Attributes.Name;
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.PrivilegedExceptionAction;
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 @@ public class URLClassPath {
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 @@ public class URLClassPath {
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 class URLClassPath {
*/
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 @@ public class URLClassPath {
}
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 @@ public class URLClassPath {
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 @@ public class URLClassPath {
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 @@ public class URLClassPath {
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 @@ public class URLClassPath {
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 @@ public class URLClassPath {
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 @@ public class URLClassPath {
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);
}
......
/*
* 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 @@ public class VM {
// 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
......
......@@ -1391,6 +1391,31 @@ JVM_GetThreadStateValues(JNIEnv* env, jint javaThreadState);
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
......
/*
* 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 @@ Java_java_lang_ClassLoader_registerNatives(JNIEnv *env, jclass cls)
/* 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;
......
/*
* 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;
}
/*
* 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() {}}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册