]> source.dussan.org Git - javassist.git/commitdiff
fixed JASSIST-150
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Sat, 11 Feb 2012 03:12:41 +0000 (03:12 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Sat, 11 Feb 2012 03:12:41 +0000 (03:12 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@611 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

src/main/javassist/ClassPool.java
src/main/javassist/ClassPoolTail.java
src/main/javassist/compiler/MemberCodeGen.java
src/main/javassist/compiler/MemberResolver.java
src/test/Jassist150.java [new file with mode: 0644]
src/test/javassist/JvstTest4.java

index dbbb99e5dc657b8e5fceb0a4f84632ba9ddc1787..2c467fb250094c173cfc30f707886043d80bd168 100644 (file)
@@ -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);
     }
 
     /**
index 72470ed02a1ad958918f8a85747bed619ba1276c..2fd952b7547d271341e1e071fc83b73a74911355 100644 (file)
@@ -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) {
index d4cd254a5ce07a07497a09765e72a520fbc3c0da..d5c61bd2fce722761f7ec997ea4f8ea1bf6e1985 100644 (file)
@@ -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;
                 }
index 164ca008ee5ece274a5f3d277dad61f23f668c4f..f35b0ef606f33a23fdce85c6b609d22aaa3dab6c 100644 (file)
@@ -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);
     }
 
diff --git a/src/test/Jassist150.java b/src/test/Jassist150.java
new file mode 100644 (file)
index 0000000..741add0
--- /dev/null
@@ -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
index 78bfd99ed472a864baf40afca446455cfbd947fc..3a2dca5538b0c466dc27e1d3498f6993f2638173 100644 (file)
@@ -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);
+    }
 }