This patch should significantly reduce the method finding time in the
generated javax.rmi ties.

The tie must invoke the method by name (string). If there are many
methods (say 50-100), it is ineffective to compare the method
name with the known values - names of each method. In some cases
This may take more time than executing the method itself. Instead, the
method names are now grouped by the hash character that is the
most diverse character in the method name set. In many cases this
single character alone is sufficient to determine the method being
invoked. To support such grouping, the switch statement is added
to the generated code.

2006-02-11  Audrius Meskauskas  <[EMAIL PROTECTED]>

   * tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java
   * tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java
   * tools/gnu/classpath/tools/giop/grmic/templates/Tie.jav,
   tools/gnu/classpath/tools/giop/grmic/templates/TieMethod.jav,
   tools/gnu/classpath/tools/giop/grmic/templates/TieMethodVoid.jav:
   Rewritten.
   * tools/gnu/classpath/tools/giop/grmic/HashFinder.java: New file.
Index: tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java
===================================================================
RCS file: /sources/classpath/classpath/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java,v
retrieving revision 1.2
diff -u -r1.2 GiopRmicCompiler.java
--- tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java	9 Feb 2006 20:22:07 -0000	1.2
+++ tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java	11 Feb 2006 20:25:57 -0000
@@ -42,7 +42,10 @@
 import java.lang.reflect.Method;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Properties;
@@ -54,7 +57,8 @@
  * 
  * @author Audrius Meskauskas, Lithuania ([EMAIL PROTECTED])
  */
-public class GiopRmicCompiler extends Generator
+public class GiopRmicCompiler
+    extends Generator implements Comparator
 {
   /** The package name. */
   protected String packag;
@@ -69,7 +73,7 @@
    * The name (without package) of the class, passed as the parameter.
    */
   protected String implName;
-  
+
   /**
    * The proposed name for the stub.
    */
@@ -94,19 +98,19 @@
    * The map of all code generator variables.
    */
   public Properties vars = new Properties();
-  
+
   /**
    * If this flag is set (true by default), the compiler generates the Servant
    * based classes. If set to false, the compiler generates the old style
    * ObjectImpl based classes.
    */
   protected boolean poaMode = true;
-  
+
   /**
    * If this flag is set (true by default), the compiler emits warnings.
    */
   protected boolean warnings = true;
-  
+
   /**
    * Verbose output
    */
@@ -123,7 +127,7 @@
     methods.clear();
     vars.clear();
   }
-  
+
   /**
    * Compile the given class (the instance of Remote), generating the stub and
    * tie for it.
@@ -154,16 +158,16 @@
     // Drop the Impl suffix, if one exists.
     if (name.endsWith("Impl"))
       name = name.substring(0, name.length() - "Impl".length());
-    
+
     stubName = name;
 
     vars.put("#name", name);
     vars.put("#package", packag);
     vars.put("#implName", implName);
-    
+
     if (verbose)
       System.out.println("Package " + packag + ", name " + name + " impl "
-                       + implName);
+                         + implName);
 
     // Get the implemented remotes.
     Class[] interfaces = remote.getInterfaces();
@@ -172,7 +176,7 @@
       {
         if (Remote.class.isAssignableFrom(interfaces[i]))
           {
-            if (!interfaces[i].equals(Remote.class))
+            if (! interfaces[i].equals(Remote.class))
               {
                 implementedRemotes.add(interfaces[i]);
               }
@@ -202,7 +206,7 @@
                     remEx = true;
                     break;
                   }
-                if (!remEx)
+                if (! remEx)
                   throw new CompilationError(m[i].getName() + ", defined in "
                                              + c.getName()
                                              + ", does not throw "
@@ -213,7 +217,7 @@
           }
       }
   }
-  
+
   /**
    * Create the method generator for the given method.
    * 
@@ -259,9 +263,9 @@
     else
       {
         String n = nameIt.getName();
-        if (!nameIt.isArray() && !nameIt.isPrimitive())
-          if (!n.startsWith("java.lang")
-              && !(packag != null && n.startsWith(packag)))
+        if (! nameIt.isArray() && ! nameIt.isPrimitive())
+          if (! n.startsWith("java.lang")
+              && ! (packag != null && n.startsWith(packag)))
             extraImports.add(n);
 
         int p = n.lastIndexOf('.');
@@ -340,7 +344,7 @@
     String output = replaceAll(template, vars);
     return output;
   }
-  
+
   /**
    * Get the list of all interfaces, implemented by the class, that are
    * derived from Remote.
@@ -351,14 +355,14 @@
   {
     StringBuffer b = new StringBuffer();
     Iterator iter = implementedRemotes.iterator();
-    
+
     while (iter.hasNext())
       {
-        b.append(name( (Class) iter.next() ) );
+        b.append(name((Class) iter.next()));
         if (iter.hasNext())
           b.append(", ");
       }
-    
+
     return b.toString();
   }
 
@@ -376,11 +380,39 @@
       template = getResource("ImplTie.jav");
 
     // Generate methods.
-    StringBuffer b = new StringBuffer();
+    HashFinder hashFinder = new HashFinder();
+
+    // Find the hash character position:
     Iterator iter = methods.iterator();
+    String[] names = new String[methods.size()];
+    int p = 0;
+
+    for (int i = 0; i < names.length; i++)
+      names[i] = ((MethodGenerator) iter.next()).getGiopMethodName();
+
+    int hashCharPosition = hashFinder.findHashCharPosition(names);
+
+    iter = methods.iterator();
+    while (iter.hasNext())
+      ((MethodGenerator) iter.next()).hashCharPosition = hashCharPosition;
+
+    vars.put("#hashCharPos", Integer.toString(hashCharPosition));
+
+    ArrayList sortedMethods = new ArrayList(methods);
+    Collections.sort(sortedMethods, this);
+
+    iter = sortedMethods.iterator();
+
+    StringBuffer b = new StringBuffer();
+
+    MethodGenerator prev = null;
+
     while (iter.hasNext())
       {
-        AbstractMethodGenerator m = (AbstractMethodGenerator) iter.next();
+        MethodGenerator m = (MethodGenerator) iter.next();
+        m.previous = prev;
+        m.hashCharPosition = hashCharPosition;
+        prev = m;
         b.append(m.generateTieMethod());
       }
 
@@ -392,7 +424,14 @@
     return output;
   }
 
-  
+  public int compare(Object a, Object b)
+  {
+    MethodGenerator g1 = (MethodGenerator) a;
+    MethodGenerator g2 = (MethodGenerator) b;
+
+    return g1.getHashChar() - g2.getHashChar();
+  }
+
   /**
    * Import the extra classes, used as the method parameters and return values.
    * 
@@ -418,7 +457,7 @@
       }
     return b.toString();
   }
-  
+
   /**
    * If this flag is set (true by default), the compiler generates the Servant
    * based classes. If set to false, the compiler generates the old style
@@ -426,9 +465,9 @@
    */
   public void setPoaMode(boolean mode)
   {
-     poaMode = mode; 
+    poaMode = mode;
   }
-  
+
   /**
    * Set the verbose output mode (false by default)
    * 
@@ -438,7 +477,7 @@
   {
     verbose = isVerbose;
   }
-  
+
   /**
    * If this flag is set (true by default), the compiler emits warnings.
    */
@@ -446,7 +485,7 @@
   {
     warnings = warn;
   }
-  
+
   /**
    * Get the package name.
    */
@@ -454,7 +493,7 @@
   {
     return packag;
   }
-  
+
   /**
    * Get the proposed stub name
    */
Index: tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java
===================================================================
RCS file: /sources/classpath/classpath/tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java,v
retrieving revision 1.2
diff -u -r1.2 MethodGenerator.java
--- tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java	9 Feb 2006 20:22:07 -0000	1.2
+++ tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java	11 Feb 2006 20:25:57 -0000
@@ -59,6 +59,17 @@
    * The parent code generator.
    */
   GiopRmicCompiler rmic;
+  
+  /**
+   * The previous method in the list, null for the first element. 
+   * Used to avoid repretetive inclusion of the same hash code label.
+   */
+  MethodGenerator previous = null;
+  
+  /**
+   * The hash character position.
+   */
+  int hashCharPosition;
 
   /**
    * Create the new method generator for the given method.
@@ -215,6 +226,11 @@
     vars.put("#argument_names", getArgumentNames());
 
     vars.put("#argument_write", getStubParaWriteStatement());
+    
+    if (previous == null || previous.getHashChar()!=getHashChar())
+      vars.put("#hashCodeLabel","    case '"+getHashChar()+"':");
+    else
+      vars.put("#hashCodeLabel","    // also '"+getHashChar()+"':");
 
     if (method.getReturnType().equals(void.class))
       templateName = "TieMethodVoid.jav";
@@ -244,7 +260,7 @@
 
     for (int i = 0; i < args.length; i++)
       {
-        b.append("            ");
+        b.append("                ");
         b.append(rmic.name(args[i]));
         b.append(" ");
         b.append("p"+i);
@@ -274,4 +290,12 @@
       }
     return b.toString();
   }
+  
+  /**
+   * Get the hash char.
+   */
+  public char getHashChar()
+  {
+    return getGiopMethodName().charAt(hashCharPosition);
+  }
 }
Index: tools/gnu/classpath/tools/giop/grmic/templates/Tie.jav
===================================================================
RCS file: /sources/classpath/classpath/tools/gnu/classpath/tools/giop/grmic/templates/Tie.jav,v
retrieving revision 1.1
diff -u -r1.1 Tie.jav
--- tools/gnu/classpath/tools/giop/grmic/templates/Tie.jav	8 Feb 2006 07:35:30 -0000	1.1
+++ tools/gnu/classpath/tools/giop/grmic/templates/Tie.jav	11 Feb 2006 20:25:57 -0000
@@ -164,8 +164,11 @@
     try
       {
         InputStream in =(InputStream) parameter_stream;
-          
-#tie_methods          
+        switch (method.charAt(#hashCharPos))
+          {
+#tie_methods
+            default: break;
+          }
           
        throw new BAD_OPERATION("No such method: '"+method+"'");
       }
Index: tools/gnu/classpath/tools/giop/grmic/templates/TieMethod.jav
===================================================================
RCS file: /sources/classpath/classpath/tools/gnu/classpath/tools/giop/grmic/templates/TieMethod.jav,v
retrieving revision 1.1
diff -u -r1.1 TieMethod.jav
--- tools/gnu/classpath/tools/giop/grmic/templates/TieMethod.jav	8 Feb 2006 07:35:30 -0000	1.1
+++ tools/gnu/classpath/tools/giop/grmic/templates/TieMethod.jav	11 Feb 2006 20:25:57 -0000
@@ -1,9 +1,11 @@
-         // #method_name
-        if (method.equals("#giop_method_name"))
-          {
+          #hashCodeLabel
+            // #method_name
+            if (method.equals("#giop_method_name"))
+              {
 #read_and_define_args
-            OutputStream out = reply.createReply();
-            #return_type result = target.#method_name(#argument_names);
-            #write_result                  
-            return out;
-          }
+                OutputStream out = reply.createReply();
+                #return_type result = 
+                  target.#method_name(#argument_names);
+                #write_result                  
+                return out;
+              }
Index: tools/gnu/classpath/tools/giop/grmic/templates/TieMethodVoid.jav
===================================================================
RCS file: /sources/classpath/classpath/tools/gnu/classpath/tools/giop/grmic/templates/TieMethodVoid.jav,v
retrieving revision 1.1
diff -u -r1.1 TieMethodVoid.jav
--- tools/gnu/classpath/tools/giop/grmic/templates/TieMethodVoid.jav	8 Feb 2006 07:35:30 -0000	1.1
+++ tools/gnu/classpath/tools/giop/grmic/templates/TieMethodVoid.jav	11 Feb 2006 20:25:57 -0000
@@ -1,8 +1,9 @@
-         // #method_name
-        if (method.equals("#giop_method_name"))
-          {
+          #hashCodeLabel
+            // #method_name
+            if (method.equals("#giop_method_name"))
+              {
 #read_and_define_args
-            OutputStream out = reply.createReply();
-            target.#method_name(#argument_names);
-            return out;
-          }
+                OutputStream out = reply.createReply();
+                target.#method_name(#argument_names);
+                return out;
+              }
Index: tools/gnu/classpath/tools/giop/grmic/HashFinder.java
===================================================================
RCS file: tools/gnu/classpath/tools/giop/grmic/HashFinder.java
diff -N tools/gnu/classpath/tools/giop/grmic/HashFinder.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tools/gnu/classpath/tools/giop/grmic/HashFinder.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,62 @@
+package gnu.classpath.tools.giop.grmic;
+
+import java.util.HashSet;
+
+/**
+ * This class finds the hash character (the most different character in
+ * the passed array of strings). This character is used to accelerate the
+ * method invocation by name.
+ *
+ * @author Audrius Meskauskas ([EMAIL PROTECTED]) 
+ */
+public class HashFinder
+{
+   /**
+   * Find the hash char position in the given collection of strings.
+   * 
+   * @param strings the string collection
+   * 
+   * @return the optimal hash character position, always less then the
+   * length of the shortest string.
+   */
+  public int findHashCharPosition(String[] strings)
+  {
+    // Find the length of the shortest string:
+
+    int l = strings[0].length();
+    for (int i = 1; i < strings.length; i++)
+      {
+        if (strings[i].length() < l)
+          l = strings[i].length();
+      }
+
+    // Find the position with the smallest number of the matching characters:
+    HashSet[] charLists = new HashSet[l];
+
+    for (int i = 0; i < charLists.length; i++)
+      {
+        charLists[i] = new HashSet(strings.length);
+      }
+
+    for (int i = 0; i < strings.length; i++)
+      for (int p = 0; p < l; p++)
+        {
+          charLists[p].add(new Integer(strings[i].charAt(p)));
+        }
+    
+    int m = 0;
+    int v = charLists[0].size();
+    
+    for (int i = 1; i < charLists.length; i++)
+      {
+        // Replace on equality also, seeking the hash char closer to the end
+        // of line.
+        if (charLists[i].size()>=v)
+          {
+            m = i;
+            v = charLists[i].size();
+          }
+      }
+    return m;
+  }
+}

Reply via email to