4735126: (cl) ClassLoader.loadClass locks all instances in chain when delegating
Added support for parallel-capable class loaders Reviewed-by: alanb
This commit is contained in:
parent
91db470ae6
commit
c10f593c2c
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
# Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -135,7 +135,8 @@ SUNWprivate_1.1 {
|
|||||||
Java_java_lang_ClassLoader_00024NativeLibrary_find;
|
Java_java_lang_ClassLoader_00024NativeLibrary_find;
|
||||||
Java_java_lang_ClassLoader_00024NativeLibrary_load;
|
Java_java_lang_ClassLoader_00024NativeLibrary_load;
|
||||||
Java_java_lang_ClassLoader_00024NativeLibrary_unload;
|
Java_java_lang_ClassLoader_00024NativeLibrary_unload;
|
||||||
Java_java_lang_ClassLoader_registerNatives;
|
Java_java_lang_ClassLoader_getCaller;
|
||||||
|
Java_java_lang_ClassLoader_registerNatives;
|
||||||
Java_java_lang_Compiler_registerNatives;
|
Java_java_lang_Compiler_registerNatives;
|
||||||
Java_java_lang_Double_longBitsToDouble;
|
Java_java_lang_Double_longBitsToDouble;
|
||||||
Java_java_lang_Double_doubleToRawLongBits;
|
Java_java_lang_Double_doubleToRawLongBits;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1994-2008 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 1994-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -2846,14 +2846,14 @@ public final
|
|||||||
if (loader == null)
|
if (loader == null)
|
||||||
return desiredAssertionStatus0(this);
|
return desiredAssertionStatus0(this);
|
||||||
|
|
||||||
synchronized(loader) {
|
// If the classloader has been initialized with the assertion
|
||||||
// If the classloader has been initialized with
|
// directives, ask it. Otherwise, ask the VM.
|
||||||
// the assertion directives, ask it. Otherwise,
|
synchronized(loader.assertionLock) {
|
||||||
// ask the VM.
|
if (loader.classAssertionStatus != null) {
|
||||||
return (loader.classAssertionStatus == null ?
|
return loader.desiredAssertionStatus(getName());
|
||||||
desiredAssertionStatus0(this) :
|
}
|
||||||
loader.desiredAssertionStatus(getName()));
|
|
||||||
}
|
}
|
||||||
|
return desiredAssertionStatus0(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves the desired assertion status of this class from the VM
|
// Retrieves the desired assertion status of this class from the VM
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1994-2008 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 1994-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -40,14 +40,17 @@ import java.security.PrivilegedActionException;
|
|||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import sun.misc.ClassFileTransformer;
|
import sun.misc.ClassFileTransformer;
|
||||||
import sun.misc.CompoundEnumeration;
|
import sun.misc.CompoundEnumeration;
|
||||||
import sun.misc.Resource;
|
import sun.misc.Resource;
|
||||||
@ -91,6 +94,17 @@ import sun.security.util.SecurityConstants;
|
|||||||
* called the "bootstrap class loader", does not itself have a parent but may
|
* called the "bootstrap class loader", does not itself have a parent but may
|
||||||
* serve as the parent of a <tt>ClassLoader</tt> instance.
|
* serve as the parent of a <tt>ClassLoader</tt> instance.
|
||||||
*
|
*
|
||||||
|
* <p> Class loaders that support concurrent loading of classes are known as
|
||||||
|
* <em>parallel capable</em> class loaders and are required to register
|
||||||
|
* themselves at their class initialization time by invoking the
|
||||||
|
* {@link
|
||||||
|
* #registerAsParallelCapable <tt>ClassLoader.registerAsParallelCapable</tt>}
|
||||||
|
* method. In environments in which the delegation model is not strictly
|
||||||
|
* hierarchical, class loaders need to be parallel capable, otherise class
|
||||||
|
* loading can lead to deadlocks because the loader lock is held for the
|
||||||
|
* duration of the class loading process (see {@link #loadClass
|
||||||
|
* <tt>loadClass</tt>} methods).
|
||||||
|
*
|
||||||
* <p> Normally, the Java virtual machine loads classes from the local file
|
* <p> Normally, the Java virtual machine loads classes from the local file
|
||||||
* system in a platform-dependent manner. For example, on UNIX systems, the
|
* system in a platform-dependent manner. For example, on UNIX systems, the
|
||||||
* virtual machine loads classes from the directory defined by the
|
* virtual machine loads classes from the directory defined by the
|
||||||
@ -160,31 +174,51 @@ import sun.security.util.SecurityConstants;
|
|||||||
public abstract class ClassLoader {
|
public abstract class ClassLoader {
|
||||||
|
|
||||||
private static native void registerNatives();
|
private static native void registerNatives();
|
||||||
|
|
||||||
|
// Set of classes which are registered as parallel capable class loaders
|
||||||
|
private static final Set<Class<? extends ClassLoader>> parallelLoaders
|
||||||
|
= Collections.newSetFromMap(Collections.synchronizedMap
|
||||||
|
(new WeakHashMap<Class<? extends ClassLoader>, Boolean>()));
|
||||||
|
|
||||||
static {
|
static {
|
||||||
registerNatives();
|
registerNatives();
|
||||||
|
parallelLoaders.add(ClassLoader.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If initialization succeed this is set to true and security checks will
|
// If initialization succeed this is set to true and security checks will
|
||||||
// succeed. Otherwise the object is not initialized and the object is
|
// succeed. Otherwise the object is not initialized and the object is
|
||||||
// useless.
|
// useless.
|
||||||
private boolean initialized = false;
|
private final boolean initialized;
|
||||||
|
|
||||||
// The parent class loader for delegation
|
// The parent class loader for delegation
|
||||||
private ClassLoader parent;
|
// Note: VM hardcoded the offset of this field, thus all new fields
|
||||||
|
// must be added *after* it.
|
||||||
|
private final ClassLoader parent;
|
||||||
|
|
||||||
|
// Maps class name to the corresponding lock object when the current
|
||||||
|
// class loader is parallel capable.
|
||||||
|
// Note: VM also uses this field to decide if the current class loader
|
||||||
|
// is parallel capable and the appropriate lock object for class loading.
|
||||||
|
private final ConcurrentHashMap<String, Object> parallelLockMap;
|
||||||
|
|
||||||
// Hashtable that maps packages to certs
|
// Hashtable that maps packages to certs
|
||||||
private Hashtable<String, Certificate[]> package2certs
|
private final Map <String, Certificate[]> package2certs;
|
||||||
= new Hashtable<String, Certificate[]>(11);
|
|
||||||
|
|
||||||
// Shared among all packages with unsigned classes
|
// Shared among all packages with unsigned classes
|
||||||
Certificate[] nocerts;
|
private static final Certificate[] nocerts = new Certificate[0];
|
||||||
|
|
||||||
// The classes loaded by this class loader. The only purpose of this table
|
// The classes loaded by this class loader. The only purpose of this table
|
||||||
// is to keep the classes from being GC'ed until the loader is GC'ed.
|
// is to keep the classes from being GC'ed until the loader is GC'ed.
|
||||||
private Vector<Class<?>> classes = new Vector<Class<?>>();
|
private final Vector<Class<?>> classes = new Vector<Class<?>>();
|
||||||
|
|
||||||
|
// The "default" domain. Set as the default ProtectionDomain on newly
|
||||||
|
// created classes.
|
||||||
|
private final ProtectionDomain defaultDomain =
|
||||||
|
new ProtectionDomain(new CodeSource(null, (Certificate[]) null),
|
||||||
|
null, this, null);
|
||||||
|
|
||||||
// The initiating protection domains for all classes loaded by this loader
|
// The initiating protection domains for all classes loaded by this loader
|
||||||
private Set<ProtectionDomain> domains = new HashSet<ProtectionDomain>();
|
private final Set<ProtectionDomain> domains;
|
||||||
|
|
||||||
// Invoked by the VM to record every loaded class with this loader.
|
// Invoked by the VM to record every loaded class with this loader.
|
||||||
void addClass(Class c) {
|
void addClass(Class c) {
|
||||||
@ -193,7 +227,9 @@ public abstract class ClassLoader {
|
|||||||
|
|
||||||
// The packages defined in this class loader. Each package name is mapped
|
// The packages defined in this class loader. Each package name is mapped
|
||||||
// to its corresponding Package object.
|
// to its corresponding Package object.
|
||||||
private HashMap<String, Package> packages = new HashMap<String, Package>();
|
// @GuardedBy("itself")
|
||||||
|
private final HashMap<String, Package> packages =
|
||||||
|
new HashMap<String, Package>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new class loader using the specified parent class loader for
|
* Creates a new class loader using the specified parent class loader for
|
||||||
@ -220,6 +256,19 @@ public abstract class ClassLoader {
|
|||||||
security.checkCreateClassLoader();
|
security.checkCreateClassLoader();
|
||||||
}
|
}
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
if (parallelLoaders.contains(this.getClass())) {
|
||||||
|
parallelLockMap = new ConcurrentHashMap<String, Object>();
|
||||||
|
package2certs = new ConcurrentHashMap<String, Certificate[]>();
|
||||||
|
domains =
|
||||||
|
Collections.synchronizedSet(new HashSet<ProtectionDomain>());
|
||||||
|
assertionLock = new Object();
|
||||||
|
} else {
|
||||||
|
// no finer-grained lock; lock on the classloader instance
|
||||||
|
parallelLockMap = null;
|
||||||
|
package2certs = new Hashtable<String, Certificate[]>();
|
||||||
|
domains = new HashSet<ProtectionDomain>();
|
||||||
|
assertionLock = this;
|
||||||
|
}
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,10 +293,22 @@ public abstract class ClassLoader {
|
|||||||
security.checkCreateClassLoader();
|
security.checkCreateClassLoader();
|
||||||
}
|
}
|
||||||
this.parent = getSystemClassLoader();
|
this.parent = getSystemClassLoader();
|
||||||
|
if (parallelLoaders.contains(this.getClass())) {
|
||||||
|
parallelLockMap = new ConcurrentHashMap<String, Object>();
|
||||||
|
package2certs = new ConcurrentHashMap<String, Certificate[]>();
|
||||||
|
domains =
|
||||||
|
Collections.synchronizedSet(new HashSet<ProtectionDomain>());
|
||||||
|
assertionLock = new Object();
|
||||||
|
} else {
|
||||||
|
// no finer-grained lock; lock on the classloader instance
|
||||||
|
parallelLockMap = null;
|
||||||
|
package2certs = new Hashtable<String, Certificate[]>();
|
||||||
|
domains = new HashSet<ProtectionDomain>();
|
||||||
|
assertionLock = this;
|
||||||
|
}
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -- Class --
|
// -- Class --
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -296,6 +357,10 @@ public abstract class ClassLoader {
|
|||||||
* <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
|
* <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
|
||||||
* #findClass(String)}, rather than this method. </p>
|
* #findClass(String)}, rather than this method. </p>
|
||||||
*
|
*
|
||||||
|
* <p> Unless overridden, this method synchronizes on the result of
|
||||||
|
* {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method
|
||||||
|
* during the entire class loading process.
|
||||||
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* The <a href="#name">binary name</a> of the class
|
* The <a href="#name">binary name</a> of the class
|
||||||
*
|
*
|
||||||
@ -307,37 +372,80 @@ public abstract class ClassLoader {
|
|||||||
* @throws ClassNotFoundException
|
* @throws ClassNotFoundException
|
||||||
* If the class could not be found
|
* If the class could not be found
|
||||||
*/
|
*/
|
||||||
protected synchronized Class<?> loadClass(String name, boolean resolve)
|
protected Class<?> loadClass(String name, boolean resolve)
|
||||||
throws ClassNotFoundException
|
throws ClassNotFoundException
|
||||||
{
|
{
|
||||||
// First, check if the class has already been loaded
|
synchronized (getClassLoadingLock(name)) {
|
||||||
Class c = findLoadedClass(name);
|
// First, check if the class has already been loaded
|
||||||
if (c == null) {
|
Class c = findLoadedClass(name);
|
||||||
try {
|
if (c == null) {
|
||||||
if (parent != null) {
|
try {
|
||||||
c = parent.loadClass(name, false);
|
if (parent != null) {
|
||||||
} else {
|
c = parent.loadClass(name, false);
|
||||||
c = findBootstrapClass0(name);
|
} else {
|
||||||
|
c = findBootstrapClass0(name);
|
||||||
|
}
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
// If still not found, then invoke findClass in order
|
||||||
|
// to find the class.
|
||||||
|
c = findClass(name);
|
||||||
}
|
}
|
||||||
} catch (ClassNotFoundException e) {
|
}
|
||||||
// If still not found, then invoke findClass in order
|
if (resolve) {
|
||||||
// to find the class.
|
resolveClass(c);
|
||||||
c = findClass(name);
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the lock object for class loading operations.
|
||||||
|
* For backward compatibility, the default implementation of this method
|
||||||
|
* behaves as follows. If this ClassLoader object is registered as
|
||||||
|
* parallel capable, the method returns a dedicated object associated
|
||||||
|
* with the specified class name. Otherwise, the method returns this
|
||||||
|
* ClassLoader object. </p>
|
||||||
|
*
|
||||||
|
* @param className
|
||||||
|
* The name of the to-be-loaded class
|
||||||
|
*
|
||||||
|
* @return the lock for class loading operations
|
||||||
|
*
|
||||||
|
* @throws NullPointerException
|
||||||
|
* If registered as parallel capable and <tt>className</tt> is null
|
||||||
|
*
|
||||||
|
* @see #loadClass(String, boolean)
|
||||||
|
*
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
protected Object getClassLoadingLock(String className) {
|
||||||
|
Object lock = this;
|
||||||
|
if (parallelLockMap != null) {
|
||||||
|
Object newLock = new Object();
|
||||||
|
lock = parallelLockMap.putIfAbsent(className, newLock);
|
||||||
|
if (lock == null) {
|
||||||
|
lock = newLock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (resolve) {
|
return lock;
|
||||||
resolveClass(c);
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method is invoked by the virtual machine to load a class.
|
// This method is invoked by the virtual machine to load a class.
|
||||||
private synchronized Class loadClassInternal(String name)
|
private Class loadClassInternal(String name)
|
||||||
throws ClassNotFoundException
|
throws ClassNotFoundException
|
||||||
{
|
{
|
||||||
return loadClass(name);
|
// For backward compatibility, explicitly lock on 'this' when
|
||||||
|
// the current class loader is not parallel capable.
|
||||||
|
if (parallelLockMap == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
return loadClass(name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return loadClass(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invoked by the VM after loading class with this loader.
|
||||||
private void checkPackageAccess(Class cls, ProtectionDomain pd) {
|
private void checkPackageAccess(Class cls, ProtectionDomain pd) {
|
||||||
final SecurityManager sm = System.getSecurityManager();
|
final SecurityManager sm = System.getSecurityManager();
|
||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
@ -486,31 +594,32 @@ public abstract class ClassLoader {
|
|||||||
|
|
||||||
/* Determine protection domain, and check that:
|
/* Determine protection domain, and check that:
|
||||||
- not define java.* class,
|
- not define java.* class,
|
||||||
- signer of this class matches signers for the rest of the classes in package.
|
- signer of this class matches signers for the rest of the classes in
|
||||||
|
package.
|
||||||
*/
|
*/
|
||||||
private ProtectionDomain preDefineClass(String name,
|
private ProtectionDomain preDefineClass(String name,
|
||||||
ProtectionDomain protectionDomain)
|
ProtectionDomain pd)
|
||||||
{
|
{
|
||||||
if (!checkName(name))
|
if (!checkName(name))
|
||||||
throw new NoClassDefFoundError("IllegalName: " + name);
|
throw new NoClassDefFoundError("IllegalName: " + name);
|
||||||
|
|
||||||
if ((name != null) && name.startsWith("java.")) {
|
if ((name != null) && name.startsWith("java.")) {
|
||||||
throw new SecurityException("Prohibited package name: " +
|
throw new SecurityException
|
||||||
name.substring(0, name.lastIndexOf('.')));
|
("Prohibited package name: " +
|
||||||
|
name.substring(0, name.lastIndexOf('.')));
|
||||||
}
|
}
|
||||||
if (protectionDomain == null) {
|
if (pd == null) {
|
||||||
protectionDomain = getDefaultDomain();
|
pd = defaultDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name != null)
|
if (name != null) checkCerts(name, pd.getCodeSource());
|
||||||
checkCerts(name, protectionDomain.getCodeSource());
|
|
||||||
|
|
||||||
return protectionDomain;
|
return pd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String defineClassSourceLocation(ProtectionDomain protectionDomain)
|
private String defineClassSourceLocation(ProtectionDomain pd)
|
||||||
{
|
{
|
||||||
CodeSource cs = protectionDomain.getCodeSource();
|
CodeSource cs = pd.getCodeSource();
|
||||||
String source = null;
|
String source = null;
|
||||||
if (cs != null && cs.getLocation() != null) {
|
if (cs != null && cs.getLocation() != null) {
|
||||||
source = cs.getLocation().toString();
|
source = cs.getLocation().toString();
|
||||||
@ -519,14 +628,15 @@ public abstract class ClassLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Class defineTransformedClass(String name, byte[] b, int off, int len,
|
private Class defineTransformedClass(String name, byte[] b, int off, int len,
|
||||||
ProtectionDomain protectionDomain,
|
ProtectionDomain pd,
|
||||||
ClassFormatError cfe, String source)
|
ClassFormatError cfe, String source)
|
||||||
throws ClassFormatError
|
throws ClassFormatError
|
||||||
{
|
{
|
||||||
// Class format error - try to transform the bytecode and
|
// Class format error - try to transform the bytecode and
|
||||||
// define the class again
|
// define the class again
|
||||||
//
|
//
|
||||||
ClassFileTransformer[] transformers = ClassFileTransformer.getTransformers();
|
ClassFileTransformer[] transformers =
|
||||||
|
ClassFileTransformer.getTransformers();
|
||||||
Class c = null;
|
Class c = null;
|
||||||
|
|
||||||
if (transformers != null) {
|
if (transformers != null) {
|
||||||
@ -535,7 +645,7 @@ public abstract class ClassLoader {
|
|||||||
// Transform byte code using transformer
|
// Transform byte code using transformer
|
||||||
byte[] tb = transformer.transform(b, off, len);
|
byte[] tb = transformer.transform(b, off, len);
|
||||||
c = defineClass1(name, tb, 0, tb.length,
|
c = defineClass1(name, tb, 0, tb.length,
|
||||||
protectionDomain, source);
|
pd, source);
|
||||||
break;
|
break;
|
||||||
} catch (ClassFormatError cfe2) {
|
} catch (ClassFormatError cfe2) {
|
||||||
// If ClassFormatError occurs, try next transformer
|
// If ClassFormatError occurs, try next transformer
|
||||||
@ -552,11 +662,10 @@ public abstract class ClassLoader {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void postDefineClass(Class c, ProtectionDomain protectionDomain)
|
private void postDefineClass(Class c, ProtectionDomain pd)
|
||||||
{
|
{
|
||||||
if (protectionDomain.getCodeSource() != null) {
|
if (pd.getCodeSource() != null) {
|
||||||
Certificate certs[] =
|
Certificate certs[] = pd.getCodeSource().getCertificates();
|
||||||
protectionDomain.getCodeSource().getCertificates();
|
|
||||||
if (certs != null)
|
if (certs != null)
|
||||||
setSigners(c, certs);
|
setSigners(c, certs);
|
||||||
}
|
}
|
||||||
@ -641,7 +750,8 @@ public abstract class ClassLoader {
|
|||||||
try {
|
try {
|
||||||
c = defineClass1(name, b, off, len, protectionDomain, source);
|
c = defineClass1(name, b, off, len, protectionDomain, source);
|
||||||
} catch (ClassFormatError cfe) {
|
} catch (ClassFormatError cfe) {
|
||||||
c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source);
|
c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,
|
||||||
|
source);
|
||||||
}
|
}
|
||||||
|
|
||||||
postDefineClass(c, protectionDomain);
|
postDefineClass(c, protectionDomain);
|
||||||
@ -656,10 +766,10 @@ public abstract class ClassLoader {
|
|||||||
* specified in the documentation for {@link #defineClass(String, byte[],
|
* specified in the documentation for {@link #defineClass(String, byte[],
|
||||||
* int, int)}. Before the class can be used it must be resolved.
|
* int, int)}. Before the class can be used it must be resolved.
|
||||||
*
|
*
|
||||||
* <p>The rules about the first class defined in a package determining the set of
|
* <p>The rules about the first class defined in a package determining the
|
||||||
* certificates for the package, and the restrictions on class names are identical
|
* set of certificates for the package, and the restrictions on class names
|
||||||
* to those specified in the documentation for {@link #defineClass(String, byte[],
|
* are identical to those specified in the documentation for {@link
|
||||||
* int, int, ProtectionDomain)}.
|
* #defineClass(String, byte[], int, int, ProtectionDomain)}.
|
||||||
*
|
*
|
||||||
* <p> An invocation of this method of the form
|
* <p> An invocation of this method of the form
|
||||||
* <i>cl</i><tt>.defineClass(</tt><i>name</i><tt>,</tt>
|
* <i>cl</i><tt>.defineClass(</tt><i>name</i><tt>,</tt>
|
||||||
@ -668,12 +778,13 @@ public abstract class ClassLoader {
|
|||||||
*
|
*
|
||||||
* <blockquote><tt>
|
* <blockquote><tt>
|
||||||
* ...<br>
|
* ...<br>
|
||||||
* byte[] temp = new byte[</tt><i>bBuffer</i><tt>.{@link java.nio.ByteBuffer#remaining
|
* byte[] temp = new byte[</tt><i>bBuffer</i><tt>.{@link
|
||||||
* remaining}()];<br>
|
* java.nio.ByteBuffer#remaining remaining}()];<br>
|
||||||
* </tt><i>bBuffer</i><tt>.{@link java.nio.ByteBuffer#get(byte[])
|
* </tt><i>bBuffer</i><tt>.{@link java.nio.ByteBuffer#get(byte[])
|
||||||
* get}(temp);<br>
|
* get}(temp);<br>
|
||||||
* return {@link #defineClass(String, byte[], int, int, ProtectionDomain)
|
* return {@link #defineClass(String, byte[], int, int, ProtectionDomain)
|
||||||
* </tt><i>cl</i><tt>.defineClass}(</tt><i>name</i><tt>, temp, 0, temp.length, </tt><i>pd</i><tt>);<br>
|
* </tt><i>cl</i><tt>.defineClass}(</tt><i>name</i><tt>, temp, 0,
|
||||||
|
* temp.length, </tt><i>pd</i><tt>);<br>
|
||||||
* </tt></blockquote>
|
* </tt></blockquote>
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
@ -682,9 +793,9 @@ public abstract class ClassLoader {
|
|||||||
*
|
*
|
||||||
* @param b
|
* @param b
|
||||||
* The bytes that make up the class data. The bytes from positions
|
* The bytes that make up the class data. The bytes from positions
|
||||||
* <tt>b.position()</tt> through <tt>b.position() + b.limit() -1 </tt>
|
* <tt>b.position()</tt> through <tt>b.position() + b.limit() -1
|
||||||
* should have the format of a valid class file as defined by the <a
|
* </tt> should have the format of a valid class file as defined by
|
||||||
* href="http://java.sun.com/docs/books/vmspec/">Java Virtual
|
* the <a href="http://java.sun.com/docs/books/vmspec/">Java Virtual
|
||||||
* Machine Specification</a>.
|
* Machine Specification</a>.
|
||||||
*
|
*
|
||||||
* @param protectionDomain
|
* @param protectionDomain
|
||||||
@ -738,11 +849,13 @@ public abstract class ClassLoader {
|
|||||||
String source = defineClassSourceLocation(protectionDomain);
|
String source = defineClassSourceLocation(protectionDomain);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
c = defineClass2(name, b, b.position(), len, protectionDomain, source);
|
c = defineClass2(name, b, b.position(), len, protectionDomain,
|
||||||
|
source);
|
||||||
} catch (ClassFormatError cfe) {
|
} catch (ClassFormatError cfe) {
|
||||||
byte[] tb = new byte[len];
|
byte[] tb = new byte[len];
|
||||||
b.get(tb); // get bytes out of byte buffer.
|
b.get(tb); // get bytes out of byte buffer.
|
||||||
c = defineTransformedClass(name, tb, 0, len, protectionDomain, cfe, source);
|
c = defineTransformedClass(name, tb, 0, len, protectionDomain, cfe,
|
||||||
|
source);
|
||||||
}
|
}
|
||||||
|
|
||||||
postDefineClass(c, protectionDomain);
|
postDefineClass(c, protectionDomain);
|
||||||
@ -769,33 +882,29 @@ public abstract class ClassLoader {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void checkCerts(String name, CodeSource cs) {
|
private void checkCerts(String name, CodeSource cs) {
|
||||||
int i = name.lastIndexOf('.');
|
int i = name.lastIndexOf('.');
|
||||||
String pname = (i == -1) ? "" : name.substring(0, i);
|
String pname = (i == -1) ? "" : name.substring(0, i);
|
||||||
Certificate[] pcerts = package2certs.get(pname);
|
|
||||||
if (pcerts == null) {
|
|
||||||
// first class in this package gets to define which
|
|
||||||
// certificates must be the same for all other classes
|
|
||||||
// in this package
|
|
||||||
if (cs != null) {
|
|
||||||
pcerts = cs.getCertificates();
|
|
||||||
}
|
|
||||||
if (pcerts == null) {
|
|
||||||
if (nocerts == null)
|
|
||||||
nocerts = new Certificate[0];
|
|
||||||
pcerts = nocerts;
|
|
||||||
}
|
|
||||||
package2certs.put(pname, pcerts);
|
|
||||||
} else {
|
|
||||||
Certificate[] certs = null;
|
|
||||||
if (cs != null) {
|
|
||||||
certs = cs.getCertificates();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!compareCerts(pcerts, certs)) {
|
Certificate[] certs = null;
|
||||||
throw new SecurityException("class \""+ name +
|
if (cs != null) {
|
||||||
"\"'s signer information does not match signer information of other classes in the same package");
|
certs = cs.getCertificates();
|
||||||
|
}
|
||||||
|
Certificate[] pcerts = null;
|
||||||
|
if (parallelLockMap == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
pcerts = package2certs.get(pname);
|
||||||
|
if (pcerts == null) {
|
||||||
|
package2certs.put(pname, (certs == null? nocerts:certs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
pcerts = ((ConcurrentHashMap<String, Certificate[]>)package2certs).
|
||||||
|
putIfAbsent(pname, (certs == null? nocerts:certs));
|
||||||
|
}
|
||||||
|
if (pcerts != null && !compareCerts(pcerts, certs)) {
|
||||||
|
throw new SecurityException("class \""+ name +
|
||||||
|
"\"'s signer information does not match signer information of other classes in the same package");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1075,6 +1184,47 @@ public abstract class ClassLoader {
|
|||||||
return java.util.Collections.emptyEnumeration();
|
return java.util.Collections.emptyEnumeration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// index 0: java.lang.ClassLoader.class
|
||||||
|
// index 1: the immediate caller of index 0.
|
||||||
|
// index 2: the immediate caller of index 1.
|
||||||
|
private static native Class<? extends ClassLoader> getCaller(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the caller class loader as parallel capable.
|
||||||
|
* In order for the registration to succeed, all super classes
|
||||||
|
* of the caller class loader must also be registered as
|
||||||
|
* parallel capable when this method is called. </p>
|
||||||
|
* Note that once a class loader is registered as
|
||||||
|
* parallel capable, there is no way to change it back.
|
||||||
|
* In addition, registration should be done statically before
|
||||||
|
* any instance of the caller classloader being constructed. </p>
|
||||||
|
*
|
||||||
|
* @return true if the caller is successfully registered as
|
||||||
|
* parallel capable and false if otherwise.
|
||||||
|
*
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
protected static boolean registerAsParallelCapable() {
|
||||||
|
Class<? extends ClassLoader> caller = getCaller(1);
|
||||||
|
Class superCls = caller.getSuperclass();
|
||||||
|
boolean result = false;
|
||||||
|
// Explicit synchronization needed for composite action
|
||||||
|
synchronized (parallelLoaders) {
|
||||||
|
if (!parallelLoaders.contains(caller)) {
|
||||||
|
if (parallelLoaders.contains(superCls)) {
|
||||||
|
// register the immediate caller as parallel capable
|
||||||
|
// if and only if all of its super classes are.
|
||||||
|
// Note: given current classloading sequence, if
|
||||||
|
// the immediate super class is parallel capable,
|
||||||
|
// all the super classes higher up must be too.
|
||||||
|
result = true;
|
||||||
|
parallelLoaders.add(caller);
|
||||||
|
}
|
||||||
|
} else result = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a resource of the specified name from the search path used to load
|
* Find a resource of the specified name from the search path used to load
|
||||||
* classes. This method locates the resource through the system class
|
* classes. This method locates the resource through the system class
|
||||||
@ -1141,7 +1291,8 @@ public abstract class ClassLoader {
|
|||||||
private static Enumeration<URL> getBootstrapResources(String name)
|
private static Enumeration<URL> getBootstrapResources(String name)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
final Enumeration<Resource> e = getBootstrapClassPath().getResources(name);
|
final Enumeration<Resource> e =
|
||||||
|
getBootstrapClassPath().getResources(name);
|
||||||
return new Enumeration<URL> () {
|
return new Enumeration<URL> () {
|
||||||
public URL nextElement() {
|
public URL nextElement() {
|
||||||
return e.nextElement().getURL();
|
return e.nextElement().getURL();
|
||||||
@ -1377,9 +1528,11 @@ public abstract class ClassLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The class loader for the system
|
// The class loader for the system
|
||||||
|
// @GuardedBy("ClassLoader.class")
|
||||||
private static ClassLoader scl;
|
private static ClassLoader scl;
|
||||||
|
|
||||||
// Set to true once the system class loader has been set
|
// Set to true once the system class loader has been set
|
||||||
|
// @GuardedBy("ClassLoader.class")
|
||||||
private static boolean sclSet;
|
private static boolean sclSet;
|
||||||
|
|
||||||
|
|
||||||
@ -1592,19 +1745,6 @@ public abstract class ClassLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The "default" domain. Set as the default ProtectionDomain on newly
|
|
||||||
// created classes.
|
|
||||||
private ProtectionDomain defaultDomain = null;
|
|
||||||
|
|
||||||
// Returns (and initializes) the default domain.
|
|
||||||
private synchronized ProtectionDomain getDefaultDomain() {
|
|
||||||
if (defaultDomain == null) {
|
|
||||||
CodeSource cs = new CodeSource(null, (Certificate[]) null);
|
|
||||||
defaultDomain = new ProtectionDomain(cs, null, this, null);
|
|
||||||
}
|
|
||||||
return defaultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All native library names we've loaded.
|
// All native library names we've loaded.
|
||||||
private static Vector<String> loadedLibraryNames
|
private static Vector<String> loadedLibraryNames
|
||||||
= new Vector<String>();
|
= new Vector<String>();
|
||||||
@ -1622,8 +1762,8 @@ public abstract class ClassLoader {
|
|||||||
= new Stack<NativeLibrary>();
|
= new Stack<NativeLibrary>();
|
||||||
|
|
||||||
// The paths searched for libraries
|
// The paths searched for libraries
|
||||||
static private String usr_paths[];
|
private static String usr_paths[];
|
||||||
static private String sys_paths[];
|
private static String sys_paths[];
|
||||||
|
|
||||||
private static String[] initializePath(String propname) {
|
private static String[] initializePath(String propname) {
|
||||||
String ldpath = System.getProperty(propname, "");
|
String ldpath = System.getProperty(propname, "");
|
||||||
@ -1803,7 +1943,10 @@ public abstract class ClassLoader {
|
|||||||
|
|
||||||
// -- Assertion management --
|
// -- Assertion management --
|
||||||
|
|
||||||
|
final Object assertionLock;
|
||||||
|
|
||||||
// The default toggle for assertion checking.
|
// The default toggle for assertion checking.
|
||||||
|
// @GuardedBy("assertionLock")
|
||||||
private boolean defaultAssertionStatus = false;
|
private boolean defaultAssertionStatus = false;
|
||||||
|
|
||||||
// Maps String packageName to Boolean package default assertion status Note
|
// Maps String packageName to Boolean package default assertion status Note
|
||||||
@ -1811,12 +1954,14 @@ public abstract class ClassLoader {
|
|||||||
// is null then we are delegating assertion status queries to the VM, i.e.,
|
// is null then we are delegating assertion status queries to the VM, i.e.,
|
||||||
// none of this ClassLoader's assertion status modification methods have
|
// none of this ClassLoader's assertion status modification methods have
|
||||||
// been invoked.
|
// been invoked.
|
||||||
|
// @GuardedBy("assertionLock")
|
||||||
private Map<String, Boolean> packageAssertionStatus = null;
|
private Map<String, Boolean> packageAssertionStatus = null;
|
||||||
|
|
||||||
// Maps String fullyQualifiedClassName to Boolean assertionStatus If this
|
// Maps String fullyQualifiedClassName to Boolean assertionStatus If this
|
||||||
// field is null then we are delegating assertion status queries to the VM,
|
// field is null then we are delegating assertion status queries to the VM,
|
||||||
// i.e., none of this ClassLoader's assertion status modification methods
|
// i.e., none of this ClassLoader's assertion status modification methods
|
||||||
// have been invoked.
|
// have been invoked.
|
||||||
|
// @GuardedBy("assertionLock")
|
||||||
Map<String, Boolean> classAssertionStatus = null;
|
Map<String, Boolean> classAssertionStatus = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1834,11 +1979,13 @@ public abstract class ClassLoader {
|
|||||||
*
|
*
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
public synchronized void setDefaultAssertionStatus(boolean enabled) {
|
public void setDefaultAssertionStatus(boolean enabled) {
|
||||||
if (classAssertionStatus == null)
|
synchronized (assertionLock) {
|
||||||
initializeJavaAssertionMaps();
|
if (classAssertionStatus == null)
|
||||||
|
initializeJavaAssertionMaps();
|
||||||
|
|
||||||
defaultAssertionStatus = enabled;
|
defaultAssertionStatus = enabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1878,13 +2025,14 @@ public abstract class ClassLoader {
|
|||||||
*
|
*
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
public synchronized void setPackageAssertionStatus(String packageName,
|
public void setPackageAssertionStatus(String packageName,
|
||||||
boolean enabled)
|
boolean enabled) {
|
||||||
{
|
synchronized (assertionLock) {
|
||||||
if (packageAssertionStatus == null)
|
if (packageAssertionStatus == null)
|
||||||
initializeJavaAssertionMaps();
|
initializeJavaAssertionMaps();
|
||||||
|
|
||||||
packageAssertionStatus.put(packageName, enabled);
|
packageAssertionStatus.put(packageName, enabled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1909,13 +2057,13 @@ public abstract class ClassLoader {
|
|||||||
*
|
*
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
public synchronized void setClassAssertionStatus(String className,
|
public void setClassAssertionStatus(String className, boolean enabled) {
|
||||||
boolean enabled)
|
synchronized (assertionLock) {
|
||||||
{
|
if (classAssertionStatus == null)
|
||||||
if (classAssertionStatus == null)
|
initializeJavaAssertionMaps();
|
||||||
initializeJavaAssertionMaps();
|
|
||||||
|
|
||||||
classAssertionStatus.put(className, enabled);
|
classAssertionStatus.put(className, enabled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1928,15 +2076,16 @@ public abstract class ClassLoader {
|
|||||||
*
|
*
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
public synchronized void clearAssertionStatus() {
|
public void clearAssertionStatus() {
|
||||||
/*
|
/*
|
||||||
* Whether or not "Java assertion maps" are initialized, set
|
* Whether or not "Java assertion maps" are initialized, set
|
||||||
* them to empty maps, effectively ignoring any present settings.
|
* them to empty maps, effectively ignoring any present settings.
|
||||||
*/
|
*/
|
||||||
classAssertionStatus = new HashMap<String, Boolean>();
|
synchronized (assertionLock) {
|
||||||
packageAssertionStatus = new HashMap<String, Boolean>();
|
classAssertionStatus = new HashMap<String, Boolean>();
|
||||||
|
packageAssertionStatus = new HashMap<String, Boolean>();
|
||||||
defaultAssertionStatus = false;
|
defaultAssertionStatus = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1961,39 +2110,40 @@ public abstract class ClassLoader {
|
|||||||
*
|
*
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
synchronized boolean desiredAssertionStatus(String className) {
|
boolean desiredAssertionStatus(String className) {
|
||||||
Boolean result;
|
synchronized (assertionLock) {
|
||||||
|
// assert classAssertionStatus != null;
|
||||||
|
// assert packageAssertionStatus != null;
|
||||||
|
|
||||||
// assert classAssertionStatus != null;
|
// Check for a class entry
|
||||||
// assert packageAssertionStatus != null;
|
Boolean result = classAssertionStatus.get(className);
|
||||||
|
|
||||||
// Check for a class entry
|
|
||||||
result = classAssertionStatus.get(className);
|
|
||||||
if (result != null)
|
|
||||||
return result.booleanValue();
|
|
||||||
|
|
||||||
// Check for most specific package entry
|
|
||||||
int dotIndex = className.lastIndexOf(".");
|
|
||||||
if (dotIndex < 0) { // default package
|
|
||||||
result = packageAssertionStatus.get(null);
|
|
||||||
if (result != null)
|
if (result != null)
|
||||||
return result.booleanValue();
|
return result.booleanValue();
|
||||||
}
|
|
||||||
while(dotIndex > 0) {
|
|
||||||
className = className.substring(0, dotIndex);
|
|
||||||
result = packageAssertionStatus.get(className);
|
|
||||||
if (result != null)
|
|
||||||
return result.booleanValue();
|
|
||||||
dotIndex = className.lastIndexOf(".", dotIndex-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the classloader default
|
// Check for most specific package entry
|
||||||
return defaultAssertionStatus;
|
int dotIndex = className.lastIndexOf(".");
|
||||||
|
if (dotIndex < 0) { // default package
|
||||||
|
result = packageAssertionStatus.get(null);
|
||||||
|
if (result != null)
|
||||||
|
return result.booleanValue();
|
||||||
|
}
|
||||||
|
while(dotIndex > 0) {
|
||||||
|
className = className.substring(0, dotIndex);
|
||||||
|
result = packageAssertionStatus.get(className);
|
||||||
|
if (result != null)
|
||||||
|
return result.booleanValue();
|
||||||
|
dotIndex = className.lastIndexOf(".", dotIndex-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the classloader default
|
||||||
|
return defaultAssertionStatus;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the assertions with information provided by the VM.
|
// Set up the assertions with information provided by the VM.
|
||||||
|
// Note: Should only be called inside a synchronized block
|
||||||
private void initializeJavaAssertionMaps() {
|
private void initializeJavaAssertionMaps() {
|
||||||
// assert Thread.holdsLock(this);
|
// assert Thread.holdsLock(assertionLock);
|
||||||
|
|
||||||
classAssertionStatus = new HashMap<String, Boolean>();
|
classAssertionStatus = new HashMap<String, Boolean>();
|
||||||
packageAssertionStatus = new HashMap<String, Boolean>();
|
packageAssertionStatus = new HashMap<String, Boolean>();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -74,10 +74,10 @@ import sun.security.util.SecurityConstants;
|
|||||||
*/
|
*/
|
||||||
public class URLClassLoader extends SecureClassLoader implements Closeable {
|
public class URLClassLoader extends SecureClassLoader implements Closeable {
|
||||||
/* The search path for classes and resources */
|
/* The search path for classes and resources */
|
||||||
URLClassPath ucp;
|
private final URLClassPath ucp;
|
||||||
|
|
||||||
/* The context to be used when loading classes and resources */
|
/* The context to be used when loading classes and resources */
|
||||||
private AccessControlContext acc;
|
private final AccessControlContext acc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new URLClassLoader for the given URLs. The URLs will be
|
* Constructs a new URLClassLoader for the given URLs. The URLs will be
|
||||||
@ -105,7 +105,19 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
|||||||
security.checkCreateClassLoader();
|
security.checkCreateClassLoader();
|
||||||
}
|
}
|
||||||
ucp = new URLClassPath(urls);
|
ucp = new URLClassPath(urls);
|
||||||
acc = AccessController.getContext();
|
this.acc = AccessController.getContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
URLClassLoader(URL[] urls, ClassLoader parent,
|
||||||
|
AccessControlContext acc) {
|
||||||
|
super(parent);
|
||||||
|
// this is to make the stack depth consistent with 1.1
|
||||||
|
SecurityManager security = System.getSecurityManager();
|
||||||
|
if (security != null) {
|
||||||
|
security.checkCreateClassLoader();
|
||||||
|
}
|
||||||
|
ucp = new URLClassPath(urls);
|
||||||
|
this.acc = acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,7 +148,18 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
|||||||
security.checkCreateClassLoader();
|
security.checkCreateClassLoader();
|
||||||
}
|
}
|
||||||
ucp = new URLClassPath(urls);
|
ucp = new URLClassPath(urls);
|
||||||
acc = AccessController.getContext();
|
this.acc = AccessController.getContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
URLClassLoader(URL[] urls, AccessControlContext acc) {
|
||||||
|
super();
|
||||||
|
// this is to make the stack depth consistent with 1.1
|
||||||
|
SecurityManager security = System.getSecurityManager();
|
||||||
|
if (security != null) {
|
||||||
|
security.checkCreateClassLoader();
|
||||||
|
}
|
||||||
|
ucp = new URLClassPath(urls);
|
||||||
|
this.acc = acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -599,17 +622,14 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
|||||||
public static URLClassLoader newInstance(final URL[] urls,
|
public static URLClassLoader newInstance(final URL[] urls,
|
||||||
final ClassLoader parent) {
|
final ClassLoader parent) {
|
||||||
// Save the caller's context
|
// Save the caller's context
|
||||||
AccessControlContext acc = AccessController.getContext();
|
final AccessControlContext acc = AccessController.getContext();
|
||||||
// Need a privileged block to create the class loader
|
// Need a privileged block to create the class loader
|
||||||
URLClassLoader ucl = AccessController.doPrivileged(
|
URLClassLoader ucl = AccessController.doPrivileged(
|
||||||
new PrivilegedAction<URLClassLoader>() {
|
new PrivilegedAction<URLClassLoader>() {
|
||||||
public URLClassLoader run() {
|
public URLClassLoader run() {
|
||||||
return new FactoryURLClassLoader(urls, parent);
|
return new FactoryURLClassLoader(urls, parent, acc);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Now set the context on the loader using the one we saved,
|
|
||||||
// not the one inside the privileged block...
|
|
||||||
ucl.acc = acc;
|
|
||||||
return ucl;
|
return ucl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,18 +646,14 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
|||||||
*/
|
*/
|
||||||
public static URLClassLoader newInstance(final URL[] urls) {
|
public static URLClassLoader newInstance(final URL[] urls) {
|
||||||
// Save the caller's context
|
// Save the caller's context
|
||||||
AccessControlContext acc = AccessController.getContext();
|
final AccessControlContext acc = AccessController.getContext();
|
||||||
// Need a privileged block to create the class loader
|
// Need a privileged block to create the class loader
|
||||||
URLClassLoader ucl = AccessController.doPrivileged(
|
URLClassLoader ucl = AccessController.doPrivileged(
|
||||||
new PrivilegedAction<URLClassLoader>() {
|
new PrivilegedAction<URLClassLoader>() {
|
||||||
public URLClassLoader run() {
|
public URLClassLoader run() {
|
||||||
return new FactoryURLClassLoader(urls);
|
return new FactoryURLClassLoader(urls, acc);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Now set the context on the loader using the one we saved,
|
|
||||||
// not the one inside the privileged block...
|
|
||||||
ucl.acc = acc;
|
|
||||||
return ucl;
|
return ucl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,20 +665,26 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
ClassLoader.registerAsParallelCapable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class FactoryURLClassLoader extends URLClassLoader {
|
final class FactoryURLClassLoader extends URLClassLoader {
|
||||||
|
|
||||||
FactoryURLClassLoader(URL[] urls, ClassLoader parent) {
|
static {
|
||||||
super(urls, parent);
|
ClassLoader.registerAsParallelCapable();
|
||||||
}
|
}
|
||||||
|
|
||||||
FactoryURLClassLoader(URL[] urls) {
|
FactoryURLClassLoader(URL[] urls, ClassLoader parent,
|
||||||
super(urls);
|
AccessControlContext acc) {
|
||||||
|
super(urls, parent, acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final synchronized Class loadClass(String name, boolean resolve)
|
FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
|
||||||
|
super(urls, acc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Class loadClass(String name, boolean resolve)
|
||||||
throws ClassNotFoundException
|
throws ClassNotFoundException
|
||||||
{
|
{
|
||||||
// First check if we have permission to access the package. This
|
// First check if we have permission to access the package. This
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -45,14 +45,19 @@ public class SecureClassLoader extends ClassLoader {
|
|||||||
* succeed. Otherwise the object is not initialized and the object is
|
* succeed. Otherwise the object is not initialized and the object is
|
||||||
* useless.
|
* useless.
|
||||||
*/
|
*/
|
||||||
private boolean initialized = false;
|
private final boolean initialized;
|
||||||
|
|
||||||
// HashMap that maps CodeSource to ProtectionDomain
|
// HashMap that maps CodeSource to ProtectionDomain
|
||||||
private HashMap<CodeSource, ProtectionDomain> pdcache =
|
// @GuardedBy("pdcache")
|
||||||
|
private final HashMap<CodeSource, ProtectionDomain> pdcache =
|
||||||
new HashMap<CodeSource, ProtectionDomain>(11);
|
new HashMap<CodeSource, ProtectionDomain>(11);
|
||||||
|
|
||||||
private static final Debug debug = Debug.getInstance("scl");
|
private static final Debug debug = Debug.getInstance("scl");
|
||||||
|
|
||||||
|
static {
|
||||||
|
ClassLoader.registerAsParallelCapable();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new SecureClassLoader using the specified parent
|
* Creates a new SecureClassLoader using the specified parent
|
||||||
* class loader for delegation.
|
* class loader for delegation.
|
||||||
@ -136,10 +141,7 @@ public class SecureClassLoader extends ClassLoader {
|
|||||||
byte[] b, int off, int len,
|
byte[] b, int off, int len,
|
||||||
CodeSource cs)
|
CodeSource cs)
|
||||||
{
|
{
|
||||||
if (cs == null)
|
return defineClass(name, b, off, len, getProtectionDomain(cs));
|
||||||
return defineClass(name, b, off, len);
|
|
||||||
else
|
|
||||||
return defineClass(name, b, off, len, getProtectionDomain(cs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -172,10 +174,7 @@ public class SecureClassLoader extends ClassLoader {
|
|||||||
protected final Class<?> defineClass(String name, java.nio.ByteBuffer b,
|
protected final Class<?> defineClass(String name, java.nio.ByteBuffer b,
|
||||||
CodeSource cs)
|
CodeSource cs)
|
||||||
{
|
{
|
||||||
if (cs == null)
|
return defineClass(name, b, getProtectionDomain(cs));
|
||||||
return defineClass(name, b, (ProtectionDomain)null);
|
|
||||||
else
|
|
||||||
return defineClass(name, b, getProtectionDomain(cs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -209,12 +208,10 @@ public class SecureClassLoader extends ClassLoader {
|
|||||||
if (pd == null) {
|
if (pd == null) {
|
||||||
PermissionCollection perms = getPermissions(cs);
|
PermissionCollection perms = getPermissions(cs);
|
||||||
pd = new ProtectionDomain(cs, perms, this, null);
|
pd = new ProtectionDomain(cs, perms, this, null);
|
||||||
if (pd != null) {
|
pdcache.put(cs, pd);
|
||||||
pdcache.put(cs, pd);
|
if (debug != null) {
|
||||||
if (debug != null) {
|
debug.println(" getPermissions "+ pd);
|
||||||
debug.println(" getPermissions "+ pd);
|
debug.println("");
|
||||||
debug.println("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -120,7 +120,10 @@ public class Launcher {
|
|||||||
* The class loader used for loading installed extensions.
|
* The class loader used for loading installed extensions.
|
||||||
*/
|
*/
|
||||||
static class ExtClassLoader extends URLClassLoader {
|
static class ExtClassLoader extends URLClassLoader {
|
||||||
private File[] dirs;
|
|
||||||
|
static {
|
||||||
|
ClassLoader.registerAsParallelCapable();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create an ExtClassLoader. The ExtClassLoader is created
|
* create an ExtClassLoader. The ExtClassLoader is created
|
||||||
@ -146,12 +149,12 @@ public class Launcher {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (java.security.PrivilegedActionException e) {
|
} catch (java.security.PrivilegedActionException e) {
|
||||||
throw (IOException) e.getException();
|
throw (IOException) e.getException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addExtURL(URL url) {
|
void addExtURL(URL url) {
|
||||||
super.addURL(url);
|
super.addURL(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -159,7 +162,6 @@ public class Launcher {
|
|||||||
*/
|
*/
|
||||||
public ExtClassLoader(File[] dirs) throws IOException {
|
public ExtClassLoader(File[] dirs) throws IOException {
|
||||||
super(getExtURLs(dirs), null, factory);
|
super(getExtURLs(dirs), null, factory);
|
||||||
this.dirs = dirs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static File[] getExtDirs() {
|
private static File[] getExtDirs() {
|
||||||
@ -206,20 +208,27 @@ public class Launcher {
|
|||||||
*/
|
*/
|
||||||
public String findLibrary(String name) {
|
public String findLibrary(String name) {
|
||||||
name = System.mapLibraryName(name);
|
name = System.mapLibraryName(name);
|
||||||
for (int i = 0; i < dirs.length; i++) {
|
URL[] urls = super.getURLs();
|
||||||
// Look in architecture-specific subdirectory first
|
File prevDir = null;
|
||||||
String arch = System.getProperty("os.arch");
|
for (int i = 0; i < urls.length; i++) {
|
||||||
if (arch != null) {
|
// Get the ext directory from the URL
|
||||||
File file = new File(new File(dirs[i], arch), name);
|
File dir = new File(urls[i].getPath()).getParentFile();
|
||||||
|
if (dir != null && !dir.equals(prevDir)) {
|
||||||
|
// Look in architecture-specific subdirectory first
|
||||||
|
String arch = System.getProperty("os.arch");
|
||||||
|
if (arch != null) {
|
||||||
|
File file = new File(new File(dir, arch), name);
|
||||||
|
if (file.exists()) {
|
||||||
|
return file.getAbsolutePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Then check the extension directory
|
||||||
|
File file = new File(dir, name);
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
return file.getAbsolutePath();
|
return file.getAbsolutePath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Then check the extension directory
|
prevDir = dir;
|
||||||
File file = new File(dirs[i], name);
|
|
||||||
if (file.exists()) {
|
|
||||||
return file.getAbsolutePath();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -248,6 +257,10 @@ public class Launcher {
|
|||||||
*/
|
*/
|
||||||
static class AppClassLoader extends URLClassLoader {
|
static class AppClassLoader extends URLClassLoader {
|
||||||
|
|
||||||
|
static {
|
||||||
|
ClassLoader.registerAsParallelCapable();
|
||||||
|
}
|
||||||
|
|
||||||
public static ClassLoader getAppClassLoader(final ClassLoader extcl)
|
public static ClassLoader getAppClassLoader(final ClassLoader extcl)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
@ -281,7 +294,7 @@ public class Launcher {
|
|||||||
/**
|
/**
|
||||||
* Override loadClass so we can checkPackageAccess.
|
* Override loadClass so we can checkPackageAccess.
|
||||||
*/
|
*/
|
||||||
public synchronized Class loadClass(String name, boolean resolve)
|
public Class loadClass(String name, boolean resolve)
|
||||||
throws ClassNotFoundException
|
throws ClassNotFoundException
|
||||||
{
|
{
|
||||||
int i = name.lastIndexOf('.');
|
int i = name.lastIndexOf('.');
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1996-2005 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -437,3 +437,21 @@ Java_java_lang_ClassLoader_00024NativeLibrary_find
|
|||||||
(*env)->ReleaseStringUTFChars(env, name, cname);
|
(*env)->ReleaseStringUTFChars(env, name, cname);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_java_lang_ClassLoader_getCaller(JNIEnv *env, jclass cls, jint index)
|
||||||
|
{
|
||||||
|
jobjectArray jcallerStack;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
jcallerStack = JVM_GetClassContext(env);
|
||||||
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
len = (*env)->GetArrayLength(env, jcallerStack);
|
||||||
|
if (index < len) {
|
||||||
|
return (*env)->GetObjectArrayElement(env, jcallerStack, index);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
29
jdk/test/java/lang/ClassLoader/deadlock/Alice.java
Normal file
29
jdk/test/java/lang/ClassLoader/deadlock/Alice.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
package comSA;
|
||||||
|
|
||||||
|
public class Alice extends comSB.SupAlice {
|
||||||
|
static {
|
||||||
|
System.out.println("comSA.Alice loaded");
|
||||||
|
}
|
||||||
|
}
|
29
jdk/test/java/lang/ClassLoader/deadlock/Bob.java
Normal file
29
jdk/test/java/lang/ClassLoader/deadlock/Bob.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
package comSB;
|
||||||
|
|
||||||
|
public class Bob extends comSA.SupBob {
|
||||||
|
static {
|
||||||
|
System.out.println("comSB.Bob loaded");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.locks.*;
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
|
||||||
|
public class DelegatingLoader extends URLClassLoader {
|
||||||
|
|
||||||
|
private DelegatingLoader delLoader;
|
||||||
|
private String[] delClasses;
|
||||||
|
|
||||||
|
static {
|
||||||
|
boolean supportParallel = false;
|
||||||
|
try {
|
||||||
|
Class c = Class.forName("java.lang.ClassLoader");
|
||||||
|
Method m = c.getDeclaredMethod("registerAsParallelCapable",
|
||||||
|
new Class[0]);
|
||||||
|
m.setAccessible(true);
|
||||||
|
Object result = (Boolean) m.invoke(null);
|
||||||
|
if (result instanceof Boolean) {
|
||||||
|
supportParallel = ((Boolean) result).booleanValue();
|
||||||
|
} else {
|
||||||
|
// Should never happen
|
||||||
|
System.out.println("Error: ClassLoader.registerAsParallelCapable() did not return a boolean!");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
} catch (NoSuchMethodException nsme) {
|
||||||
|
System.out.println("No ClassLoader.registerAsParallelCapable() API");
|
||||||
|
} catch (NoSuchMethodError nsme2) {
|
||||||
|
System.out.println("No ClassLoader.registerAsParallelCapable() API");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
// Exit immediately to indicate an error
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
System.out.println("Parallel ClassLoader registration: " +
|
||||||
|
supportParallel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DelegatingLoader(URL urls[]) {
|
||||||
|
super(urls);
|
||||||
|
System.out.println("DelegatingLoader using URL " + urls[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDelegate(String[] delClasses, DelegatingLoader delLoader) {
|
||||||
|
this.delClasses = delClasses;
|
||||||
|
this.delLoader = delLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class loadClass(String className, boolean resolve)
|
||||||
|
throws ClassNotFoundException {
|
||||||
|
for (int i = 0; i < delClasses.length; i++) {
|
||||||
|
if (delClasses[i].equals(className)) {
|
||||||
|
Starter.log("Delegating class loading for " + className);
|
||||||
|
try {
|
||||||
|
Thread.sleep(500);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return delLoader.loadClass(className, resolve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Starter.log("Loading local class " + className);
|
||||||
|
// synchronized (getClassLoadingLock(className)) {
|
||||||
|
return super.loadClass(className, resolve);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
105
jdk/test/java/lang/ClassLoader/deadlock/Starter.java
Normal file
105
jdk/test/java/lang/ClassLoader/deadlock/Starter.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class Starter implements Runnable {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private DelegatingLoader dl;
|
||||||
|
private String startClass;
|
||||||
|
|
||||||
|
private static DelegatingLoader saLoader, sbLoader;
|
||||||
|
|
||||||
|
public static void log(String line) {
|
||||||
|
System.out.println(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
URL[] urlsa = new URL[1];
|
||||||
|
URL[] urlsb = new URL[1];
|
||||||
|
try {
|
||||||
|
String testDir = System.getProperty("test.classes", ".");
|
||||||
|
String sep = System.getProperty("file.separator");
|
||||||
|
urlsa[0] = new URL("file://" + testDir + sep + "SA" + sep);
|
||||||
|
urlsb[0] = new URL("file://" + testDir + sep + "SB" + sep);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
// Set up Classloader delegation hierarchy
|
||||||
|
saLoader = new DelegatingLoader(urlsa);
|
||||||
|
sbLoader = new DelegatingLoader(urlsb);
|
||||||
|
|
||||||
|
String[] saClasses = { "comSA.SupBob", "comSA.Alice" };
|
||||||
|
String[] sbClasses = { "comSB.SupAlice", "comSB.Bob" };
|
||||||
|
|
||||||
|
saLoader.setDelegate(sbClasses, sbLoader);
|
||||||
|
sbLoader.setDelegate(saClasses, saLoader);
|
||||||
|
|
||||||
|
// test one-way delegate
|
||||||
|
String testType = args[0];
|
||||||
|
if (testType.equals("one-way")) {
|
||||||
|
test("comSA.Alice", "comSA.SupBob");
|
||||||
|
} else if (testType.equals("cross")) {
|
||||||
|
// test cross delegate
|
||||||
|
test("comSA.Alice", "comSB.Bob");
|
||||||
|
} else {
|
||||||
|
System.out.println("ERROR: unsupported - " + testType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test(String clsForSA, String clsForSB) {
|
||||||
|
Starter ia = new Starter("SA", saLoader, clsForSA);
|
||||||
|
Starter ib = new Starter("SB", sbLoader, clsForSB);
|
||||||
|
new Thread(ia).start();
|
||||||
|
new Thread(ib).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sleep() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(500);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
log("Thread interrupted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Starter(String id, DelegatingLoader dl, String startClass) {
|
||||||
|
this.id = id;
|
||||||
|
this.dl = dl;
|
||||||
|
this.startClass = startClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
log("Spawned thread " + id + " running");
|
||||||
|
try {
|
||||||
|
// To mirror the WAS deadlock, need to ensure class load
|
||||||
|
// is routed via the VM.
|
||||||
|
Class.forName(startClass, true, dl);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
log("Thread " + id + " terminating");
|
||||||
|
}
|
||||||
|
}
|
29
jdk/test/java/lang/ClassLoader/deadlock/SupAlice.java
Normal file
29
jdk/test/java/lang/ClassLoader/deadlock/SupAlice.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
package comSB;
|
||||||
|
|
||||||
|
public class SupAlice {
|
||||||
|
static {
|
||||||
|
System.out.println("comSB.SupAlice loaded");
|
||||||
|
}
|
||||||
|
}
|
29
jdk/test/java/lang/ClassLoader/deadlock/SupBob.java
Normal file
29
jdk/test/java/lang/ClassLoader/deadlock/SupBob.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
package comSA;
|
||||||
|
|
||||||
|
public class SupBob {
|
||||||
|
static {
|
||||||
|
System.out.println("comSA.SupBob loaded");
|
||||||
|
}
|
||||||
|
}
|
105
jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh
Normal file
105
jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
# CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
# have any questions.
|
||||||
|
#
|
||||||
|
# @test
|
||||||
|
# @bug 4735126
|
||||||
|
# @summary (cl) ClassLoader.loadClass locks all instances in chain
|
||||||
|
# when delegating
|
||||||
|
#
|
||||||
|
# @run shell/timeout=10 TestCrossDelegate.sh
|
||||||
|
|
||||||
|
# if running by hand on windows, change TESTSRC and TESTCLASSES to "."
|
||||||
|
if [ "${TESTSRC}" = "" ] ; then
|
||||||
|
TESTSRC=`pwd`
|
||||||
|
fi
|
||||||
|
if [ "${TESTCLASSES}" = "" ] ; then
|
||||||
|
TESTCLASSES=`pwd`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if running by hand on windows, change this to appropriate value
|
||||||
|
if [ "${TESTJAVA}" = "" ] ; then
|
||||||
|
echo "TESTJAVA not set. Test cannot execute."
|
||||||
|
echo "FAILED!!!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo TESTSRC=${TESTSRC}
|
||||||
|
echo TESTCLASSES=${TESTCLASSES}
|
||||||
|
echo TESTJAVA=${TESTJAVA}
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# set platform-specific variables
|
||||||
|
OS=`uname -s`
|
||||||
|
case "$OS" in
|
||||||
|
SunOS )
|
||||||
|
FS="/"
|
||||||
|
;;
|
||||||
|
Linux )
|
||||||
|
FS="/"
|
||||||
|
;;
|
||||||
|
Windows* )
|
||||||
|
FS="\\"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# compile test
|
||||||
|
${TESTJAVA}${FS}bin${FS}javac \
|
||||||
|
-d ${TESTCLASSES} \
|
||||||
|
${TESTSRC}${FS}Starter.java ${TESTSRC}${FS}DelegatingLoader.java
|
||||||
|
|
||||||
|
STATUS=$?
|
||||||
|
if [ ${STATUS} -ne 0 ]
|
||||||
|
then
|
||||||
|
exit ${STATUS}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set up test
|
||||||
|
${TESTJAVA}${FS}bin${FS}javac \
|
||||||
|
-d ${TESTCLASSES}${FS} \
|
||||||
|
${TESTSRC}${FS}Alice.java ${TESTSRC}${FS}SupBob.java \
|
||||||
|
${TESTSRC}${FS}Bob.java ${TESTSRC}${FS}SupAlice.java
|
||||||
|
|
||||||
|
cd ${TESTCLASSES}
|
||||||
|
DIRS="SA SB"
|
||||||
|
for dir in $DIRS
|
||||||
|
do
|
||||||
|
if [ -d ${dir} ]; then
|
||||||
|
rm -rf ${dir}
|
||||||
|
fi
|
||||||
|
mkdir ${dir}
|
||||||
|
mv com${dir} ${dir}
|
||||||
|
done
|
||||||
|
|
||||||
|
# run test
|
||||||
|
${TESTJAVA}${FS}bin${FS}java \
|
||||||
|
-verbose:class -XX:+TraceClassLoading -cp . \
|
||||||
|
-Dtest.classes=${TESTCLASSES} \
|
||||||
|
Starter cross
|
||||||
|
# -XX:+UnlockDiagnosticVMOptions -XX:+UnsyncloadClass \
|
||||||
|
|
||||||
|
# save error status
|
||||||
|
STATUS=$?
|
||||||
|
|
||||||
|
# clean up
|
||||||
|
rm -rf ${TESTCLASSES}${FS}SA ${TESTCLASSES}${FS}SB
|
||||||
|
|
||||||
|
# return
|
||||||
|
exit ${STATUS}
|
105
jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh
Normal file
105
jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
# CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
# have any questions.
|
||||||
|
#
|
||||||
|
# @test
|
||||||
|
# @bug 4735126
|
||||||
|
# @summary (cl) ClassLoader.loadClass locks all instances in chain
|
||||||
|
# when delegating
|
||||||
|
#
|
||||||
|
# @run shell/timeout=10 TestOneWayDelegate.sh
|
||||||
|
|
||||||
|
# if running by hand on windows, change TESTSRC and TESTCLASSES to "."
|
||||||
|
if [ "${TESTSRC}" = "" ] ; then
|
||||||
|
TESTSRC=`pwd`
|
||||||
|
fi
|
||||||
|
if [ "${TESTCLASSES}" = "" ] ; then
|
||||||
|
TESTCLASSES=`pwd`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if running by hand on windows, change this to appropriate value
|
||||||
|
if [ "${TESTJAVA}" = "" ] ; then
|
||||||
|
echo "TESTJAVA not set. Test cannot execute."
|
||||||
|
echo "FAILED!!!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo TESTSRC=${TESTSRC}
|
||||||
|
echo TESTCLASSES=${TESTCLASSES}
|
||||||
|
echo TESTJAVA=${TESTJAVA}
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# set platform-specific variables
|
||||||
|
OS=`uname -s`
|
||||||
|
case "$OS" in
|
||||||
|
SunOS )
|
||||||
|
FS="/"
|
||||||
|
;;
|
||||||
|
Linux )
|
||||||
|
FS="/"
|
||||||
|
;;
|
||||||
|
Windows* )
|
||||||
|
FS="\\"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# compile test
|
||||||
|
${TESTJAVA}${FS}bin${FS}javac \
|
||||||
|
-d ${TESTCLASSES} \
|
||||||
|
${TESTSRC}${FS}Starter.java ${TESTSRC}${FS}DelegatingLoader.java
|
||||||
|
|
||||||
|
STATUS=$?
|
||||||
|
if [ ${STATUS} -ne 0 ]
|
||||||
|
then
|
||||||
|
exit ${STATUS}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set up test
|
||||||
|
${TESTJAVA}${FS}bin${FS}javac \
|
||||||
|
-d ${TESTCLASSES}${FS} \
|
||||||
|
${TESTSRC}${FS}Alice.java ${TESTSRC}${FS}SupBob.java \
|
||||||
|
${TESTSRC}${FS}Bob.java ${TESTSRC}${FS}SupAlice.java
|
||||||
|
|
||||||
|
cd ${TESTCLASSES}
|
||||||
|
DIRS="SA SB"
|
||||||
|
for dir in $DIRS
|
||||||
|
do
|
||||||
|
if [ -d ${dir} ]; then
|
||||||
|
rm -rf ${dir}
|
||||||
|
fi
|
||||||
|
mkdir ${dir}
|
||||||
|
mv com${dir} ${dir}
|
||||||
|
done
|
||||||
|
|
||||||
|
# run test
|
||||||
|
${TESTJAVA}${FS}bin${FS}java \
|
||||||
|
-verbose:class -XX:+TraceClassLoading -cp . \
|
||||||
|
-Dtest.classes=${TESTCLASSES} \
|
||||||
|
Starter one-way
|
||||||
|
# -XX:+UnlockDiagnosticVMOptions -XX:+UnsyncloadClass \
|
||||||
|
|
||||||
|
# save error status
|
||||||
|
STATUS=$?
|
||||||
|
|
||||||
|
# clean up
|
||||||
|
rm -rf ${TESTCLASSES}${FS}SA ${TESTCLASSES}${FS}SB
|
||||||
|
|
||||||
|
# return
|
||||||
|
exit ${STATUS}
|
Loading…
x
Reference in New Issue
Block a user