I've refactored this class to not cache the results any more. This is a

tradeoff in testing I've found the CPU tradeoff is negligeable. With the
cache, large codebases consumed a lot of memory and slowed down greatly when approaching 3,000 classes.

Also fixes some false positives.


git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/trunk@4892 51baf565-9d33-0410-a72c-fc3788e3496d
This commit is contained in:
Allan Caplan
2006-12-19 01:02:12 +00:00
parent 9f6ee02e66
commit 9e7deee88f

View File

@ -6,71 +6,49 @@ package net.sourceforge.pmd.typeresolution;
import net.sourceforge.pmd.typeresolution.visitors.PMDASMVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/*
* I've refactored this class to not cache the results any more. This is a
* tradeoff in testing I've found the CPU tradeoff is negligeable. With the
* cache, large codebases consumed a lot of memory and slowed down greatly when
* approaching 3,000 classes. I'm adding this comment in case someone is looking
* at this code and thinks a cache may help.
*/
public class PMDASMClassLoader extends ClassLoader {
public PMDASMClassLoader() {
}
public PMDASMClassLoader() {
}
public synchronized Class loadClass(String name) throws ClassNotFoundException {
return defineClass(name);
}
private Set dontBother = new HashSet();
private Map importedClasses = new HashMap();
public Map getImportedClasses(String name) throws ClassNotFoundException {
private Set dontBother = new HashSet();
if (dontBother.contains(name)) {
throw new ClassNotFoundException(name);
}
try {
ClassReader reader = new ClassReader(getResourceAsStream(name.replace('.', '/') + ".class"));
PMDASMVisitor asmVisitor = new PMDASMVisitor();
reader.accept(asmVisitor, 0);
public Map getImportedClasses(String className) {
Map ret = (Map) importedClasses.get(className);
return ret == null ? new HashMap() : ret;
}
private Class defineClass(String name) throws ClassNotFoundException {
if (dontBother.contains(name)) {
throw new ClassNotFoundException(name);
}
try {
if (name.startsWith("java.")) {
return Class.forName(name);
}
if (importedClasses.containsKey(name)) {
if (super.findLoadedClass(name) != null) {
return super.findLoadedClass(name);
}
}
ClassReader reader = new ClassReader(getResourceAsStream(name.replace('.', '/') + ".class"));
PMDASMVisitor asmVisitor = new PMDASMVisitor();
reader.accept(asmVisitor, 0);
List inner = asmVisitor.getInnerClasses();
if (inner != null && !inner.isEmpty()) {
for (int ix = 0; ix < inner.size(); ix++) {
String str = (String) inner.get(ix);
ClassReader innerReader = new ClassReader(getResourceAsStream(str.replace('.', '/') + ".class"));
innerReader.accept(asmVisitor, 0);
}
}
importedClasses.put(name, asmVisitor.getPackages());
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
reader.accept(writer, 0);
byte[] byteCode = writer.toByteArray();
return defineClass(name, byteCode, 0, byteCode.length);
} catch (ClassNotFoundException e) {
dontBother.add(name);
throw e;
} catch (IOException e) {
dontBother.add(name);
throw new ClassNotFoundException(name, e);
}
}
List inner = asmVisitor.getInnerClasses();
if (inner != null && !inner.isEmpty()) {
for (int ix = 0; ix < inner.size(); ix++) {
String str = (String) inner.get(ix);
reader = new ClassReader(getResourceAsStream(str.replace('.', '/') + ".class"));
reader.accept(asmVisitor, 0);
}
}
return asmVisitor.getPackages();
} catch (IOException e) {
dontBother.add(name);
throw new ClassNotFoundException(name);
}
}
}