From 0564d29d853bb18655c35405c74a421e2e550cef Mon Sep 17 00:00:00 2001 From: chiba Date: Sat, 11 Feb 2012 03:12:41 +0000 Subject: [PATCH] fixed JASSIST-150 git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@611 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- src/main/javassist/ClassPool.java | 12 ++- src/main/javassist/ClassPoolTail.java | 16 ---- .../javassist/compiler/MemberCodeGen.java | 2 - .../javassist/compiler/MemberResolver.java | 74 +++++++++++-------- src/test/Jassist150.java | 68 +++++++++++++++++ src/test/javassist/JvstTest4.java | 59 +++++++++++++++ 6 files changed, 177 insertions(+), 54 deletions(-) create mode 100644 src/test/Jassist150.java diff --git a/src/main/javassist/ClassPool.java b/src/main/javassist/ClassPool.java index dbbb99e5..2c467fb2 100644 --- a/src/main/javassist/ClassPool.java +++ b/src/main/javassist/ClassPool.java @@ -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 get() does not search the class path at all + * since get() 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). + *

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); } /** diff --git a/src/main/javassist/ClassPoolTail.java b/src/main/javassist/ClassPoolTail.java index 72470ed0..2fd952b7 100644 --- a/src/main/javassist/ClassPoolTail.java +++ b/src/main/javassist/ClassPoolTail.java @@ -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) { diff --git a/src/main/javassist/compiler/MemberCodeGen.java b/src/main/javassist/compiler/MemberCodeGen.java index d4cd254a..d5c61bd2 100644 --- a/src/main/javassist/compiler/MemberCodeGen.java +++ b/src/main/javassist/compiler/MemberCodeGen.java @@ -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; } diff --git a/src/main/javassist/compiler/MemberResolver.java b/src/main/javassist/compiler/MemberResolver.java index 164ca008..f35b0ef6 100644 --- a/src/main/javassist/compiler/MemberResolver.java +++ b/src/main/javassist/compiler/MemberResolver.java @@ -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 = ""; + 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); } diff --git a/src/test/Jassist150.java b/src/test/Jassist150.java new file mode 100644 index 00000000..741add0c --- /dev/null +++ b/src/test/Jassist150.java @@ -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(); + } + } + } +} \ No newline at end of file diff --git a/src/test/javassist/JvstTest4.java b/src/test/javassist/JvstTest4.java index 78bfd99e..3a2dca55 100644 --- a/src/test/javassist/JvstTest4.java +++ b/src/test/javassist/JvstTest4.java @@ -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); + } } -- 2.39.5