git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@611 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -331,17 +331,21 @@ public class ClassPool { | |||
} | |||
/** | |||
* 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); | |||
} | |||
/** |
@@ -178,11 +178,9 @@ final class JarClassPath implements ClassPath { | |||
final class ClassPoolTail { | |||
protected ClassPathList pathList; | |||
private Hashtable packages; // should be synchronized. | |||
public ClassPoolTail() { | |||
pathList = null; | |||
packages = new Hashtable(); | |||
} | |||
public String toString() { | |||
@@ -269,14 +267,6 @@ final class ClassPoolTail { | |||
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. | |||
*/ | |||
@@ -325,9 +315,6 @@ final class ClassPoolTail { | |||
InputStream openClassfile(String classname) | |||
throws NotFoundException | |||
{ | |||
if (packages.get(classname) != null) | |||
return null; // not found | |||
ClassPathList list = pathList; | |||
InputStream ins = null; | |||
NotFoundException error = null; | |||
@@ -361,9 +348,6 @@ final class ClassPoolTail { | |||
* @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) { |
@@ -504,7 +504,6 @@ public class MemberCodeGen extends CodeGen { | |||
exprType = CLASS; | |||
arrayDim = 0; | |||
className = nfe.getField(); // JVM-internal | |||
resolver.recordPackage(className); | |||
isStatic = true; | |||
} | |||
@@ -1078,7 +1077,6 @@ public class MemberCodeGen extends CodeGen { | |||
Symbol fname = (Symbol)e.oprand2(); | |||
String cname = nfe.getField(); | |||
f = resolver.lookupFieldByJvmName2(cname, fname, expr); | |||
resolver.recordPackage(cname); | |||
resultStatic = true; | |||
return f; | |||
} |
@@ -16,6 +16,8 @@ | |||
package javassist.compiler; | |||
import java.util.Hashtable; | |||
import java.util.WeakHashMap; | |||
import java.util.List; | |||
import java.util.Iterator; | |||
import javassist.*; | |||
@@ -37,22 +39,6 @@ public class MemberResolver implements TokenId { | |||
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; | |||
@@ -276,6 +262,7 @@ public class MemberResolver implements TokenId { | |||
* 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 | |||
@@ -406,12 +393,44 @@ public class MemberResolver implements TokenId { | |||
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) | |||
@@ -423,28 +442,19 @@ public class MemberResolver implements TokenId { | |||
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); | |||
} | |||
@@ -0,0 +1,68 @@ | |||
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(); | |||
} | |||
} | |||
} | |||
} |
@@ -598,4 +598,63 @@ public class JvstTest4 extends JvstTestRoot { | |||
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); | |||
} | |||
} |