}
/**
- * Records a name that never exists.
+ * Records a class name that never exists.
* For example, a package name can be recorded by this method.
* This would improve execution performance
- * since <code>get()</code> does not search the class path at all
+ * since <code>get()</code> quickly throw an exception
+ * without searching the class path at all
* if the given name is an invalid name recorded by this method.
* Note that searching the class path takes relatively long time.
*
- * @param name a class name (separeted by dot).
+ * <p>The current implementation of this method performs nothing.
+ *
+ * @param name an invalid class name (separeted by dots).
+ * @deprecated
*/
public void recordInvalidClassName(String name) {
- source.recordInvalidClassName(name);
+ // source.recordInvalidClassName(name);
}
/**
final class ClassPoolTail {
protected ClassPathList pathList;
- private Hashtable packages; // should be synchronized.
public ClassPoolTail() {
pathList = null;
- packages = new Hashtable();
}
public String toString() {
return new DirClassPath(pathname);
}
- /**
- * You can record "System" so that java.lang.System can be quickly
- * found although "System" is not a package name.
- */
- public void recordInvalidClassName(String name) {
- packages.put(name, name);
- }
-
/**
* This method does not close the output stream.
*/
InputStream openClassfile(String classname)
throws NotFoundException
{
- if (packages.get(classname) != null)
- return null; // not found
-
ClassPathList list = pathList;
InputStream ins = null;
NotFoundException error = null;
* @return null if the class file could not be found.
*/
public URL find(String classname) {
- if (packages.get(classname) != null)
- return null;
-
ClassPathList list = pathList;
URL url = null;
while (list != null) {
exprType = CLASS;
arrayDim = 0;
className = nfe.getField(); // JVM-internal
- resolver.recordPackage(className);
isStatic = true;
}
Symbol fname = (Symbol)e.oprand2();
String cname = nfe.getField();
f = resolver.lookupFieldByJvmName2(cname, fname, expr);
- resolver.recordPackage(cname);
resultStatic = true;
return f;
}
package javassist.compiler;
+import java.util.Hashtable;
+import java.util.WeakHashMap;
import java.util.List;
import java.util.Iterator;
import javassist.*;
throw new CompileError("fatal");
}
- /**
- * @param jvmClassName a class name. Not a package name.
- */
- public void recordPackage(String jvmClassName) {
- String classname = jvmToJavaName(jvmClassName);
- for (;;) {
- int i = classname.lastIndexOf('.');
- if (i > 0) {
- classname = classname.substring(0, i);
- classPool.recordInvalidClassName(classname);
- }
- else
- break;
- }
- }
-
public static class Method {
public CtClass declaring;
public MethodInfo info;
* Only used by fieldAccess() in MemberCodeGen and TypeChecker.
*
* @param jvmClassName a JVM class name. e.g. java/lang/String
+ * @see #lookupClass(String, boolean)
*/
public CtField lookupFieldByJvmName2(String jvmClassName, Symbol fieldSym,
ASTree expr) throws NoFieldException
public CtClass lookupClass(String name, boolean notCheckInner)
throws CompileError
{
+ Hashtable cache = getInvalidNames();
+ Object found = cache.get(name);
+ if (found == INVALID)
+ throw new CompileError("no such class: " + name);
+ else if (found != null)
+ return (CtClass)found;
+
+ CtClass cc = null;
try {
- return lookupClass0(name, notCheckInner);
+ cc = lookupClass0(name, notCheckInner);
}
catch (NotFoundException e) {
- return searchImports(name);
+ cc = searchImports(name);
}
+
+ cache.put(name, cc);
+ return cc;
+ }
+
+ private static final String INVALID = "<invalid>";
+ private static WeakHashMap invalidNamesMap = new WeakHashMap();
+ private Hashtable invalidNames = null;
+
+ private Hashtable getInvalidNames() {
+ Hashtable ht = invalidNames;
+ if (ht == null) {
+ synchronized (MemberResolver.class) {
+ ht = (Hashtable)invalidNamesMap.get(classPool);
+ if (ht == null) {
+ ht = new Hashtable();
+ invalidNamesMap.put(classPool, ht);
+ }
+ }
+
+ invalidNames = ht;
+ }
+
+ return ht;
}
private CtClass searchImports(String orgName)
String pac = (String)it.next();
String fqName = pac + '.' + orgName;
try {
- CtClass cc = classPool.get(fqName);
- // if the class is found,
- classPool.recordInvalidClassName(orgName);
- return cc;
+ return classPool.get(fqName);
}
catch (NotFoundException e) {
- classPool.recordInvalidClassName(fqName);
try {
- if (pac.endsWith("." + orgName)) {
- CtClass cc = classPool.get(pac);
- // if the class is found,
- classPool.recordInvalidClassName(orgName);
- return cc;
- }
- }
- catch (NotFoundException e2) {
- classPool.recordInvalidClassName(pac);
+ if (pac.endsWith("." + orgName))
+ return classPool.get(pac);
}
+ catch (NotFoundException e2) {}
}
}
}
+ getInvalidNames().put(orgName, INVALID);
throw new CompileError("no such class: " + orgName);
}
--- /dev/null
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.NotFoundException;
+
+public class Jassist150 {
+
+ public static final String BASE_PATH="./";
+ public static final String JAVASSIST_JAR=BASE_PATH+"javassist.jar";
+ public static final String CLASSES_FOLDER=BASE_PATH+"build/classes";
+ public static final String TEST_CLASSES_FOLDER=BASE_PATH+"build/test-classes";
+
+ public static class Inner1 {
+ public static int get() {
+ return 0;
+ }
+ }
+
+ public static void implTestClassTailCache() throws NotFoundException, CannotCompileException {
+ ClassPool pool = new ClassPool(true);
+ for(int paths=0; paths<50; paths++) {
+ pool.appendClassPath(JAVASSIST_JAR);
+ pool.appendClassPath(CLASSES_FOLDER);
+ pool.appendClassPath(TEST_CLASSES_FOLDER);
+ }
+ CtClass cc = pool.get("Jassist150$Inner1");
+ CtMethod ccGet = cc.getDeclaredMethod("get");
+ String code1 = "{ int n1 = Integer.valueOf(1); " +
+ " int n2 = Integer.valueOf(2); " +
+ " int n3 = Integer.valueOf(3); " +
+ " int n4 = Integer.valueOf(4); " +
+ " int n5 = Integer.valueOf(5); " +
+ " return n1+n2+n3+n4+n5; }";
+ String code2 = "{ int n1 = java.lang.Integer.valueOf(1); " +
+ " int n2 = java.lang.Integer.valueOf(2); " +
+ " int n3 = java.lang.Integer.valueOf(3); " +
+ " int n4 = java.lang.Integer.valueOf(4); " +
+ " int n5 = java.lang.Integer.valueOf(5); " +
+ " return n1+n2+n3+n4+n5; }";
+ String code3 = "{ int n1 = java.lang.Integer#valueOf(1); " +
+ " int n2 = java.lang.Integer#valueOf(2); " +
+ " int n3 = java.lang.Integer#valueOf(3); " +
+ " int n4 = java.lang.Integer#valueOf(4); " +
+ " int n5 = java.lang.Integer#valueOf(5); " +
+ " return n1+n2+n3+n4+n5; }";
+ loop(cc, ccGet, code1);
+ }
+
+ public static void loop(CtClass cc, CtMethod ccGet, String code) throws CannotCompileException {
+ long startTime = System.currentTimeMillis();
+ for(int replace=0; replace<1000; replace++) {
+ ccGet.setBody(code);
+ }
+ long endTime = System.currentTimeMillis();
+ System.out.println("Test: Time (ms) "+(endTime-startTime));
+ }
+
+ public static void main(String[] args) {
+ for (int loop = 0; loop < 5; loop++) {
+ try {
+ implTestClassTailCache();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
\ No newline at end of file
Object obj = cl.newInstance();
assertEquals(packageName, obj.getClass().getPackage().getName());
}
+
+ public static final String BASE_PATH="../";
+ public static final String JAVASSIST_JAR=BASE_PATH+"javassist.jar";
+ public static final String CLASSES_FOLDER=BASE_PATH+"build/classes";
+ public static final String TEST_CLASSES_FOLDER=BASE_PATH+"build/test-classes";
+
+ public static class Inner1 {
+ public static int get() {
+ return 0;
+ }
+ }
+
+ public void testJIRA150() throws Exception {
+ ClassPool pool = new ClassPool(true);
+ for(int paths=0; paths<50; paths++) {
+ pool.appendClassPath(JAVASSIST_JAR);
+ pool.appendClassPath(CLASSES_FOLDER);
+ pool.appendClassPath(TEST_CLASSES_FOLDER);
+ }
+ CtClass cc = pool.get("Jassist150$Inner1");
+ CtMethod ccGet = cc.getDeclaredMethod("get");
+ long startTime = System.currentTimeMillis();
+ for(int replace=0; replace<1000; replace++) {
+ ccGet.setBody(
+ "{ int n1 = java.lang.Integer#valueOf(1); " +
+ " int n2 = java.lang.Integer#valueOf(2); " +
+ " int n3 = java.lang.Integer#valueOf(3); " +
+ " int n4 = java.lang.Integer#valueOf(4); " +
+ " int n5 = java.lang.Integer#valueOf(5); " +
+ " return n1+n2+n3+n4+n5; }");
+ }
+ long endTime = System.currentTimeMillis();
+ for(int replace=0; replace<1000; replace++) {
+ ccGet.setBody(
+ "{ int n1 = java.lang.Integer.valueOf(1); " +
+ " int n2 = java.lang.Integer.valueOf(2); " +
+ " int n3 = java.lang.Integer.valueOf(3); " +
+ " int n4 = java.lang.Integer.valueOf(4); " +
+ " int n5 = java.lang.Integer.valueOf(5); " +
+ " return n1+n2+n3+n4+n5; }");
+ }
+ long endTime2 = System.currentTimeMillis();
+ for(int replace=0; replace<1000; replace++) {
+ ccGet.setBody(
+ "{ int n1 = Integer.valueOf(1); " +
+ " int n2 = Integer.valueOf(2); " +
+ " int n3 = Integer.valueOf(3); " +
+ " int n4 = Integer.valueOf(4); " +
+ " int n5 = Integer.valueOf(5); " +
+ " return n1+n2+n3+n4+n5; }");
+ }
+ long endTime3 = System.currentTimeMillis();
+ long t1 = endTime - startTime;
+ long t2 = endTime2 - endTime;
+ long t3 = endTime3 - endTime2;
+ System.out.println("JIRA150: " + t1 + ", " + t2 + ", " + t3);
+ assertTrue(t2 < t1 * 2);
+ assertTrue(t3 < t1 * 2);
+ }
}