--- a/jdk/src/share/classes/java/lang/ClassLoader.java Mon Apr 06 11:29:03 2009 +0100
+++ b/jdk/src/share/classes/java/lang/ClassLoader.java Mon Apr 06 18:46:20 2009 -0700
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,14 +40,17 @@
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
+import java.util.Collections;
import java.util.Enumeration;
-import java.util.Hashtable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import java.util.Map;
import java.util.Vector;
+import java.util.Hashtable;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
import sun.misc.ClassFileTransformer;
import sun.misc.CompoundEnumeration;
import sun.misc.Resource;
@@ -91,6 +94,17 @@
* called the "bootstrap class loader", does not itself have a parent but may
* 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
* system in a platform-dependent manner. For example, on UNIX systems, the
* virtual machine loads classes from the directory defined by the
@@ -160,31 +174,51 @@
public abstract class ClassLoader {
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 {
registerNatives();
+ parallelLoaders.add(ClassLoader.class);
}
// If initialization succeed this is set to true and security checks will
// succeed. Otherwise the object is not initialized and the object is
// useless.
- private boolean initialized = false;
+ private final boolean initialized;
// 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
- private Hashtable<String, Certificate[]> package2certs
- = new Hashtable<String, Certificate[]>(11);
+ private final Map <String, Certificate[]> package2certs;
// 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
+ // is to keep the classes from being GC'ed until the loader is GC'ed.
+ private final Vector<Class<?>> classes = new Vector<Class<?>>();
- // 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.
- private 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
- private Set<ProtectionDomain> domains = new HashSet<ProtectionDomain>();
+ private final Set<ProtectionDomain> domains;
// Invoked by the VM to record every loaded class with this loader.
void addClass(Class c) {
@@ -193,7 +227,9 @@
// The packages defined in this class loader. Each package name is mapped
// 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
@@ -220,6 +256,19 @@
security.checkCreateClassLoader();
}
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;
}
@@ -244,10 +293,22 @@
security.checkCreateClassLoader();
}
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;
}
-
// -- Class --
/**
@@ -296,6 +357,10 @@
* <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
* #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
* The <a href="#name">binary name</a> of the class
*
@@ -307,37 +372,80 @@
* @throws ClassNotFoundException
* If the class could not be found
*/
- protected synchronized Class<?> loadClass(String name, boolean resolve)
+ protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
- // First, check if the class has already been loaded
- Class c = findLoadedClass(name);
- if (c == null) {
- try {
- if (parent != null) {
- c = parent.loadClass(name, false);
- } else {
- c = findBootstrapClass0(name);
+ synchronized (getClassLoadingLock(name)) {
+ // First, check if the class has already been loaded
+ Class c = findLoadedClass(name);
+ if (c == null) {
+ try {
+ if (parent != null) {
+ c = parent.loadClass(name, false);
+ } 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
- // to find the class.
- c = findClass(name);
+ }
+ if (resolve) {
+ resolveClass(c);
+ }
+ 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) {
- resolveClass(c);
- }
- return c;
+ return lock;
}
// 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
{
- 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) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
@@ -486,31 +594,32 @@
/* Determine protection domain, and check that:
- 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,
- ProtectionDomain protectionDomain)
+ ProtectionDomain pd)
{
if (!checkName(name))
throw new NoClassDefFoundError("IllegalName: " + name);
if ((name != null) && name.startsWith("java.")) {
- throw new SecurityException("Prohibited package name: " +
- name.substring(0, name.lastIndexOf('.')));
+ throw new SecurityException
+ ("Prohibited package name: " +
+ name.substring(0, name.lastIndexOf('.')));
}
- if (protectionDomain == null) {
- protectionDomain = getDefaultDomain();
+ if (pd == null) {
+ pd = defaultDomain;
}
- if (name != null)
- checkCerts(name, protectionDomain.getCodeSource());
+ if (name != null) checkCerts(name, pd.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;
if (cs != null && cs.getLocation() != null) {
source = cs.getLocation().toString();
@@ -519,14 +628,15 @@
}
private Class defineTransformedClass(String name, byte[] b, int off, int len,
- ProtectionDomain protectionDomain,
+ ProtectionDomain pd,
ClassFormatError cfe, String source)
throws ClassFormatError
{
// Class format error - try to transform the bytecode and
// define the class again
//
- ClassFileTransformer[] transformers = ClassFileTransformer.getTransformers();
+ ClassFileTransformer[] transformers =
+ ClassFileTransformer.getTransformers();
Class c = null;
if (transformers != null) {
@@ -535,7 +645,7 @@
// Transform byte code using transformer
byte[] tb = transformer.transform(b, off, len);
c = defineClass1(name, tb, 0, tb.length,
- protectionDomain, source);
+ pd, source);
break;
} catch (ClassFormatError cfe2) {
// If ClassFormatError occurs, try next transformer
@@ -552,11 +662,10 @@
return c;
}
- private void postDefineClass(Class c, ProtectionDomain protectionDomain)
+ private void postDefineClass(Class c, ProtectionDomain pd)
{
- if (protectionDomain.getCodeSource() != null) {
- Certificate certs[] =
- protectionDomain.getCodeSource().getCertificates();
+ if (pd.getCodeSource() != null) {
+ Certificate certs[] = pd.getCodeSource().getCertificates();
if (certs != null)
setSigners(c, certs);
}
@@ -641,7 +750,8 @@
try {
c = defineClass1(name, b, off, len, protectionDomain, source);
} catch (ClassFormatError cfe) {
- c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source);
+ c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,
+ source);
}
postDefineClass(c, protectionDomain);
@@ -656,10 +766,10 @@
* specified in the documentation for {@link #defineClass(String, byte[],
* 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
- * certificates for the package, and the restrictions on class names are identical
- * to those specified in the documentation for {@link #defineClass(String, byte[],
- * int, int, ProtectionDomain)}.
+ * <p>The rules about the first class defined in a package determining the
+ * set of certificates for the package, and the restrictions on class names
+ * are identical to those specified in the documentation for {@link
+ * #defineClass(String, byte[], int, int, ProtectionDomain)}.
*
* <p> An invocation of this method of the form
* <i>cl</i><tt>.defineClass(</tt><i>name</i><tt>,</tt>
@@ -668,12 +778,13 @@
*
* <blockquote><tt>
* ...<br>
- * byte[] temp = new byte[</tt><i>bBuffer</i><tt>.{@link java.nio.ByteBuffer#remaining
- * remaining}()];<br>
+ * byte[] temp = new byte[</tt><i>bBuffer</i><tt>.{@link
+ * java.nio.ByteBuffer#remaining remaining}()];<br>
* </tt><i>bBuffer</i><tt>.{@link java.nio.ByteBuffer#get(byte[])
* get}(temp);<br>
* 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>
*
* @param name
@@ -682,9 +793,9 @@
*
* @param b
* The bytes that make up the class data. The bytes from positions
- * <tt>b.position()</tt> through <tt>b.position() + b.limit() -1 </tt>
- * should have the format of a valid class file as defined by the <a
- * href="http://java.sun.com/docs/books/vmspec/">Java Virtual
+ * <tt>b.position()</tt> through <tt>b.position() + b.limit() -1
+ * </tt> should have the format of a valid class file as defined by
+ * the <a href="http://java.sun.com/docs/books/vmspec/">Java Virtual
* Machine Specification</a>.
*
* @param protectionDomain
@@ -738,11 +849,13 @@
String source = defineClassSourceLocation(protectionDomain);
try {
- c = defineClass2(name, b, b.position(), len, protectionDomain, source);
+ c = defineClass2(name, b, b.position(), len, protectionDomain,
+ source);
} catch (ClassFormatError cfe) {
byte[] tb = new byte[len];
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);
@@ -769,33 +882,29 @@
return true;
}
- private synchronized void checkCerts(String name, CodeSource cs) {
+ private void checkCerts(String name, CodeSource cs) {
int i = name.lastIndexOf('.');
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();
+
+ Certificate[] certs = null;
+ if (cs != null) {
+ 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));
+ }
}
- 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)) {
- throw new SecurityException("class \""+ name +
- "\"'s signer information does not match signer information of other classes in the same package");
- }
+ 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 @@
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
* classes. This method locates the resource through the system class
@@ -1141,7 +1291,8 @@
private static Enumeration<URL> getBootstrapResources(String name)
throws IOException
{
- final Enumeration<Resource> e = getBootstrapClassPath().getResources(name);
+ final Enumeration<Resource> e =
+ getBootstrapClassPath().getResources(name);
return new Enumeration<URL> () {
public URL nextElement() {
return e.nextElement().getURL();
@@ -1377,9 +1528,11 @@
}
// The class loader for the system
+ // @GuardedBy("ClassLoader.class")
private static ClassLoader scl;
// Set to true once the system class loader has been set
+ // @GuardedBy("ClassLoader.class")
private static boolean sclSet;
@@ -1592,19 +1745,6 @@
}
}
- // 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.
private static Vector<String> loadedLibraryNames
= new Vector<String>();
@@ -1622,8 +1762,8 @@
= new Stack<NativeLibrary>();
// The paths searched for libraries
- static private String usr_paths[];
- static private String sys_paths[];
+ private static String usr_paths[];
+ private static String sys_paths[];
private static String[] initializePath(String propname) {
String ldpath = System.getProperty(propname, "");
@@ -1803,7 +1943,10 @@
// -- Assertion management --
+ final Object assertionLock;
+
// The default toggle for assertion checking.
+ // @GuardedBy("assertionLock")
private boolean defaultAssertionStatus = false;
// Maps String packageName to Boolean package default assertion status Note
@@ -1811,12 +1954,14 @@
// is null then we are delegating assertion status queries to the VM, i.e.,
// none of this ClassLoader's assertion status modification methods have
// been invoked.
+ // @GuardedBy("assertionLock")
private Map<String, Boolean> packageAssertionStatus = null;
// Maps String fullyQualifiedClassName to Boolean assertionStatus If this
// field is null then we are delegating assertion status queries to the VM,
// i.e., none of this ClassLoader's assertion status modification methods
// have been invoked.
+ // @GuardedBy("assertionLock")
Map<String, Boolean> classAssertionStatus = null;
/**
@@ -1834,11 +1979,13 @@
*
* @since 1.4
*/
- public synchronized void setDefaultAssertionStatus(boolean enabled) {
- if (classAssertionStatus == null)
- initializeJavaAssertionMaps();
+ public void setDefaultAssertionStatus(boolean enabled) {
+ synchronized (assertionLock) {
+ if (classAssertionStatus == null)
+ initializeJavaAssertionMaps();
- defaultAssertionStatus = enabled;
+ defaultAssertionStatus = enabled;
+ }
}
/**
@@ -1878,13 +2025,14 @@
*
* @since 1.4
*/
- public synchronized void setPackageAssertionStatus(String packageName,
- boolean enabled)
- {
- if (packageAssertionStatus == null)
- initializeJavaAssertionMaps();
+ public void setPackageAssertionStatus(String packageName,
+ boolean enabled) {
+ synchronized (assertionLock) {
+ if (packageAssertionStatus == null)
+ initializeJavaAssertionMaps();
- packageAssertionStatus.put(packageName, enabled);
+ packageAssertionStatus.put(packageName, enabled);
+ }
}
/**
@@ -1909,13 +2057,13 @@
*
* @since 1.4
*/
- public synchronized void setClassAssertionStatus(String className,
- boolean enabled)
- {
- if (classAssertionStatus == null)
- initializeJavaAssertionMaps();
+ public void setClassAssertionStatus(String className, boolean enabled) {
+ synchronized (assertionLock) {
+ if (classAssertionStatus == null)
+ initializeJavaAssertionMaps();
- classAssertionStatus.put(className, enabled);
+ classAssertionStatus.put(className, enabled);
+ }
}
/**
@@ -1928,15 +2076,16 @@
*
* @since 1.4
*/
- public synchronized void clearAssertionStatus() {
+ public void clearAssertionStatus() {
/*
* Whether or not "Java assertion maps" are initialized, set
* them to empty maps, effectively ignoring any present settings.
*/
- classAssertionStatus = new HashMap<String, Boolean>();
- packageAssertionStatus = new HashMap<String, Boolean>();
-
- defaultAssertionStatus = false;
+ synchronized (assertionLock) {
+ classAssertionStatus = new HashMap<String, Boolean>();
+ packageAssertionStatus = new HashMap<String, Boolean>();
+ defaultAssertionStatus = false;
+ }
}
/**
@@ -1961,39 +2110,40 @@
*
* @since 1.4
*/
- synchronized boolean desiredAssertionStatus(String className) {
- Boolean result;
-
- // assert classAssertionStatus != null;
- // assert packageAssertionStatus != null;
+ boolean desiredAssertionStatus(String className) {
+ synchronized (assertionLock) {
+ // assert classAssertionStatus != null;
+ // assert packageAssertionStatus != null;
- // 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);
+ // Check for a class entry
+ Boolean 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)
+ 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;
}
- 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.
+ // Note: Should only be called inside a synchronized block
private void initializeJavaAssertionMaps() {
- // assert Thread.holdsLock(this);
+ // assert Thread.holdsLock(assertionLock);
classAssertionStatus = new HashMap<String, Boolean>();
packageAssertionStatus = new HashMap<String, Boolean>();