Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize class loading #37

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import java.util.AbstractMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
Expand All @@ -73,11 +74,11 @@

/**
* The repository maintains information about which classes have been loaded.
*
*
* It loads its data from the ClassLoader implementation passed into its constructor.
*
*
* @see org.aspectj.apache.bcel.Repository
*
*
* @version $Id: ClassLoaderRepository.java,v 1.13 2009/09/09 19:56:20 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @author David Dixon-Peugh
Expand All @@ -95,6 +96,16 @@ public class ClassLoaderRepository implements Repository {

public static boolean useSharedCache = System.getProperty("org.aspectj.apache.bcel.useSharedCache", "true").equalsIgnoreCase("true");

//Cache not found classes as well to prevent unnecessary file I/O operations
public static final boolean useUnavailableClassesCache =
System.getProperty("org.aspectj.apache.bcel.useUnavailableClassesCache", "false").equalsIgnoreCase("true");
//Ignore cache clear requests to not build up the cache over and over again
public static final boolean ignoreCacheClearRequests =
System.getProperty("org.aspectj.apache.bcel.ignoreCacheClearRequests", "false").equalsIgnoreCase("true");

//Second cache for the unavailable classes
private static Set<String> unavailableClasses = new HashSet<String>();

private static int cacheHitsShared = 0;
private static int missSharedEvicted = 0; // Misses in shared cache access due to reference GC
private long timeManipulatingURLs = 0L;
Expand Down Expand Up @@ -183,8 +194,10 @@ public Set entrySet() {

@Override
public void clear() {
processQueue();
map.clear();
if (!ignoreCacheClearRequests) {
processQueue();
map.clear();
}
}

@Override
Expand Down Expand Up @@ -281,12 +294,19 @@ private URL toURL(String className) {
*/
public JavaClass loadClass(String className) throws ClassNotFoundException {

//Quick evaluation of unavailable classes to prevent unnecessary file I/O
if (useUnavailableClassesCache && unavailableClasses.contains(className))
throw new ClassNotFoundException(className + " not found.");

// translate to a URL
long time = System.currentTimeMillis();
java.net.URL url = toURL(className);
timeManipulatingURLs += (System.currentTimeMillis() - time);
if (url == null)
if (url == null) {
if (useUnavailableClassesCache)
unavailableClasses.add(className);
throw new ClassNotFoundException(className + " not found - unable to determine URL");
}

JavaClass clazz = null;

Expand Down Expand Up @@ -314,6 +334,9 @@ public JavaClass loadClass(String className) throws ClassNotFoundException {
InputStream is = (useSharedCache ? url.openStream() : loaderRef.getClassLoader().getResourceAsStream(
classFile + ".class"));
if (is == null) {
if (useUnavailableClassesCache) {
unavailableClasses.add(className);
}
throw new ClassNotFoundException(className + " not found using url " + url);
}
ClassParser parser = new ClassParser(is, className);
Expand All @@ -326,6 +349,9 @@ public JavaClass loadClass(String className) throws ClassNotFoundException {
classesLoadedCount++;
return clazz;
} catch (IOException e) {
if (useUnavailableClassesCache) {
unavailableClasses.add(className);
}
throw new ClassNotFoundException(e.toString());
}
}
Expand Down Expand Up @@ -384,10 +410,12 @@ public JavaClass loadClass(Class clazz) throws ClassNotFoundException {

/** Clear all entries from the local cache */
public void clear() {
if (useSharedCache)
sharedCache.clear();
else
localCache.clear();
if (!ignoreCacheClearRequests) {
if (useSharedCache)
sharedCache.clear();
else
localCache.clear();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,17 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {

private Repository bcelRepository;
private BcelWeakClassLoaderReference classLoaderRef;

private static Repository staticBcelRepository;
private static BcelWeakClassLoaderReference staticClassLoaderRef;

private World world;
private static boolean useCachingClassLoaderRepository;

//Use single instance of Repository and ClassLoader
public static final boolean useSingleInstances =
System.getProperty("org.aspectj.apache.bcel.useSingleRepositoryInstance", "false").equalsIgnoreCase("true");

static {
try {
useCachingClassLoaderRepository = System.getProperty("Xset:bcelRepositoryCaching","true").equalsIgnoreCase("true");
Expand All @@ -57,14 +65,31 @@ public Java15AnnotationFinder() {
}

public void setClassLoader(ClassLoader aLoader) {
this.classLoaderRef = new BcelWeakClassLoaderReference(aLoader);
//Set class loader ref
if (useSingleInstances && staticClassLoaderRef == null)
staticClassLoaderRef = new BcelWeakClassLoaderReference(aLoader);
else
this.classLoaderRef = new BcelWeakClassLoaderReference(aLoader);

//Set repository
if (useCachingClassLoaderRepository) {
this.bcelRepository = new ClassLoaderRepository(classLoaderRef);
} else {
this.bcelRepository = new NonCachingClassLoaderRepository(classLoaderRef);
if (useSingleInstances && staticBcelRepository == null)
staticBcelRepository = new ClassLoaderRepository(getClassLoader());
else
this.bcelRepository = new ClassLoaderRepository(classLoaderRef);
}
else {
if (useSingleInstances && staticBcelRepository == null)
staticBcelRepository = new NonCachingClassLoaderRepository(getClassLoader());
else
this.bcelRepository = new NonCachingClassLoaderRepository(classLoaderRef);
}
}

private Repository getBcelRepository() {
return useSingleInstances ? staticBcelRepository : bcelRepository;
}

public void setWorld(World aWorld) {
this.world = aWorld;
}
Expand Down Expand Up @@ -111,7 +136,7 @@ public Object getAnnotationFromMember(ResolvedType annotationType, Member aMembe
}

private ClassLoader getClassLoader() {
return classLoaderRef.getClassLoader();
return useSingleInstances ? staticClassLoaderRef.getClassLoader() : classLoaderRef.getClassLoader();
}

public AnnotationAJ getAnnotationOfType(UnresolvedType ofType, Member onMember) {
Expand Down Expand Up @@ -144,7 +169,7 @@ public AnnotationAJ getAnnotationOfType(UnresolvedType ofType, Member onMember)
anns = bcelField.getAnnotations();
}
// the answer is cached and we don't want to hold on to memory
bcelRepository.clear();
getBcelRepository().clear();
// OPTIMIZE make constant 0 size array for sharing
if (anns == null)
anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0];
Expand All @@ -163,7 +188,7 @@ public AnnotationAJ getAnnotationOfType(UnresolvedType ofType, Member onMember)

public String getAnnotationDefaultValue(Member onMember) {
try {
JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass());
if (onMember instanceof Method) {
org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);

Expand Down Expand Up @@ -199,7 +224,7 @@ public ResolvedType[] getAnnotations(Member onMember, boolean areRuntimeAnnotati
// we can just use reflection.
if (!areRuntimeAnnotationsSufficient) {
try {
JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass());
org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = null;
if (onMember instanceof Method) {
org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
Expand All @@ -214,7 +239,7 @@ public ResolvedType[] getAnnotations(Member onMember, boolean areRuntimeAnnotati
anns = bcelField.getAnnotations();
}
// the answer is cached and we don't want to hold on to memory
bcelRepository.clear();
getBcelRepository().clear();
if (anns == null || anns.length == 0) {
return ResolvedType.NONE;
}
Expand Down Expand Up @@ -245,9 +270,9 @@ public ResolvedType[] getAnnotations(Class forClass, World inWorld) {
// annotations so we bail out to Bcel and then chuck away the JavaClass so that we
// don't hog memory.
try {
JavaClass jc = bcelRepository.loadClass(forClass);
JavaClass jc = getBcelRepository().loadClass(forClass);
org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = jc.getAnnotations();
bcelRepository.clear();
getBcelRepository().clear();
if (anns == null) {
return ResolvedType.NONE;
} else {
Expand Down Expand Up @@ -275,7 +300,7 @@ public String[] getParameterNames(Member forMember) {
return null;

try {
JavaClass jc = bcelRepository.loadClass(forMember.getDeclaringClass());
JavaClass jc = getBcelRepository().loadClass(forMember.getDeclaringClass());
LocalVariableTable lvt = null;
int numVars = 0;
if (forMember instanceof Method) {
Expand Down Expand Up @@ -319,7 +344,7 @@ public ResolvedType[][] getParameterAnnotationTypes(Member onMember) {
// don't hog
// memory.
try {
JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass());
org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[][] anns = null;
if (onMember instanceof Method) {
org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
Expand All @@ -339,7 +364,7 @@ public ResolvedType[][] getParameterAnnotationTypes(Member onMember) {
// anns = null;
}
// the answer is cached and we don't want to hold on to memory
bcelRepository.clear();
getBcelRepository().clear();
if (anns == null)
return NO_PARAMETER_ANNOTATIONS;
ResolvedType[][] result = new ResolvedType[anns.length][];
Expand Down