/[classpath]/cp-tools/src/gnu/classpath/tools/rmi/rmic/RMIC.java
ViewVC logotype

Diff of /cp-tools/src/gnu/classpath/tools/rmi/rmic/RMIC.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by cbj, Sun Jan 30 04:19:27 2005 UTC revision 1.2 by tromey, Tue Jul 5 18:11:36 2005 UTC
# Line 1  Line 1 
1  /* RMIC.java --  /* ASMRMIC.java --
2     Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004     Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005
3     Free Software Foundation, Inc.     Free Software Foundation, Inc.
4    
5  This file is part of GNU Classpath.  This file is part of GNU Classpath.
# Line 22  Free Software Foundation, Inc., 59 Templ Line 22  Free Software Foundation, Inc., 59 Templ
22  package gnu.classpath.tools.rmi.rmic;  package gnu.classpath.tools.rmi.rmic;
23    
24  import gnu.java.rmi.server.RMIHashes;  import gnu.java.rmi.server.RMIHashes;
25    import java.io.ByteArrayOutputStream;
26    import java.io.DataOutputStream;
27  import java.io.File;  import java.io.File;
28    import java.io.FileOutputStream;
29  import java.io.FileWriter;  import java.io.FileWriter;
30  import java.io.IOException;  import java.io.IOException;
31    import java.io.ObjectInput;
32    import java.io.ObjectOutput;
33  import java.io.PrintWriter;  import java.io.PrintWriter;
34  import java.lang.reflect.Method;  import java.lang.reflect.Method;
35    import java.net.URL;
36    import java.net.URLClassLoader;
37    import java.rmi.MarshalException;
38    import java.rmi.Remote;
39  import java.rmi.RemoteException;  import java.rmi.RemoteException;
40    import java.rmi.UnexpectedException;
41    import java.rmi.UnmarshalException;
42    import java.rmi.server.Operation;
43    import java.rmi.server.RemoteCall;
44    import java.rmi.server.RemoteObject;
45    import java.rmi.server.RemoteRef;
46    import java.rmi.server.RemoteStub;
47    import java.rmi.server.Skeleton;
48    import java.rmi.server.SkeletonMismatchException;
49    import java.security.MessageDigest;
50    import java.util.ArrayList;
51  import java.util.Arrays;  import java.util.Arrays;
52  import java.util.HashSet;  import java.util.HashSet;
53  import java.util.Iterator;  import java.util.Iterator;
54    import java.util.List;
55  import java.util.Set;  import java.util.Set;
56    import java.util.StringTokenizer;
57    import org.objectweb.asm.ClassVisitor;
58    import org.objectweb.asm.ClassWriter;
59    import org.objectweb.asm.CodeVisitor;
60    import org.objectweb.asm.Constants;
61    import org.objectweb.asm.Label;
62    import org.objectweb.asm.Type;
63    
64  public class RMIC  public class RMIC
65  {  {
# Line 46  public class RMIC Line 72  public class RMIC
72    private boolean compile = true;    private boolean compile = true;
73    private boolean verbose;    private boolean verbose;
74    private String destination;    private String destination;
75    private PrintWriter out;    private String classpath;
76    private TabbedWriter ctrl;    private ClassLoader loader;
77      private int errorCount = 0;
78    
79    private Class clazz;    private Class clazz;
80    private String classname;    private String classname;
81      private String classInternalName;
82    private String fullclassname;    private String fullclassname;
83    private MethodRef[] remotemethods;    private MethodRef[] remotemethods;
84    private String stubname;    private String stubname;
85    private String skelname;    private String skelname;
86    private int errorCount = 0;    private List mRemoteInterfaces;
87    private Class mRemoteInterface;  
88      private static class C
89        implements Constants
90      {
91      }
92    
93    public RMIC(String[] a)    public RMIC(String[] a)
94    {    {
# Line 97  public class RMIC Line 130  public class RMIC
130      return (true);      return (true);
131    }    }
132    
133    private boolean processClass(String classname) throws Exception    private boolean processClass(String cls) throws Exception
134    {    {
135        // reset class specific vars
136        clazz = null;
137        classname = null;
138        classInternalName = null;
139        fullclassname = null;
140        remotemethods = null;
141        stubname = null;
142        skelname = null;
143        mRemoteInterfaces = new ArrayList();
144    
145      errorCount = 0;      errorCount = 0;
146      analyzeClass(classname);  
147        analyzeClass(cls);
148      if (errorCount > 0)      if (errorCount > 0)
149        System.exit(1);        System.exit(1);
150      generateStub();      generateStub();
151      if (need11Stubs)      if (need11Stubs)
152        generateSkel();        generateSkel();
     if (compile)  
       {  
         compile(stubname.replace('.', File.separatorChar) + ".java");  
         if (need11Stubs)  
           compile(skelname.replace('.', File.separatorChar) + ".java");  
       }  
     if (! keep)  
       {  
         (new File(stubname.replace('.', File.separatorChar) + ".java")).delete();  
         if (need11Stubs)  
           (new File(skelname.replace('.', File.separatorChar) + ".java"))  
           .delete();  
       }  
153      return (true);      return (true);
154    }    }
155    
# Line 133  public class RMIC Line 164  public class RMIC
164        classname = cname;        classname = cname;
165      fullclassname = cname;      fullclassname = cname;
166    
     HashSet rmeths = new HashSet();  
167      findClass();      findClass();
168        findRemoteMethods();
     // get the remote interface  
     mRemoteInterface = getRemoteInterface(clazz);  
     if (mRemoteInterface == null)  
       return;  
     if (verbose)  
       System.out.println("[implements " + mRemoteInterface.getName() + "]");  
   
     // check if the methods of the remote interface declare RemoteExceptions  
     Method[] meths = mRemoteInterface.getDeclaredMethods();  
     for (int i = 0; i < meths.length; i++)  
       {  
         Class[] exceptions = meths[i].getExceptionTypes();  
         int index = 0;  
         for (; index < exceptions.length; index++)  
           {  
             if (exceptions[index].equals(RemoteException.class))  
               break;  
           }  
         if (index < exceptions.length)  
           rmeths.add(meths[i]);  
         else  
           logError("Method " + meths[i]  
                    + " does not throw a java.rmi.RemoteException");  
       }  
   
     // Convert into a MethodRef array and sort them  
     remotemethods = new MethodRef[rmeths.size()];  
     int c = 0;  
     for (Iterator i = rmeths.iterator(); i.hasNext();)  
       remotemethods[c++] = new MethodRef((Method) i.next());  
     Arrays.sort(remotemethods);  
169    }    }
170    
171    public Exception getException()    public Exception getException()
# Line 174  public class RMIC Line 173  public class RMIC
173      return (exception);      return (exception);
174    }    }
175    
176    private void findClass() throws ClassNotFoundException    private void findClass()
177    {    {
178      clazz =      try
179        Class.forName(fullclassname, true, ClassLoader.getSystemClassLoader());        {
180            ClassLoader cl = (loader == null
181                              ? ClassLoader.getSystemClassLoader()
182                              : loader);
183            clazz = Class.forName(fullclassname, false, cl);
184          }
185        catch (ClassNotFoundException cnfe)
186          {
187            System.err.println(fullclassname + " not found in " + classpath);
188            throw new RuntimeException(cnfe);
189          }
190    
191        if (! Remote.class.isAssignableFrom(clazz))
192          {
193            logError("Class " + clazz.getName() + " is not a remote object. "
194                     + "It does not implement an interface that is a "
195                     + "java.rmi.Remote-interface.");
196            throw new RuntimeException
197              ("Class " + clazz.getName() + " is not a remote object. "
198               + "It does not implement an interface that is a "
199               + "java.rmi.Remote-interface.");
200          }
201    }    }
202    
203    private void generateStub() throws IOException    private static Type[] typeArray(Class[] cls)
204    {    {
205      stubname = fullclassname + "_Stub";      Type[] t = new Type[cls.length];
206      String stubclassname = classname + "_Stub";      for (int i = 0; i < cls.length; i++)
     ctrl =  
       new TabbedWriter(new FileWriter((destination == null ? ""  
                                                            : destination  
                                                            + File.separator)  
                                       + stubname.replace('.',  
                                                          File.separatorChar)  
                                       + ".java"));  
     out = new PrintWriter(ctrl);  
   
     if (verbose)  
       System.out.println("[Generating class " + stubname + ".java]");  
   
     out.println("// Stub class generated by rmic - DO NOT EDIT!");  
     out.println();  
     if (fullclassname != classname)  
207        {        {
208          String pname =          t[i] = Type.getType(cls[i]);
           fullclassname.substring(0, fullclassname.lastIndexOf('.'));  
         out.println("package " + pname + ";");  
         out.println();  
209        }        }
210    
211      out.print("public final class " + stubclassname);      return t;
212      ctrl.indent();    }
     out.println("extends java.rmi.server.RemoteStub");  
213    
214      // Output interfaces we implement    private static String[] internalNameArray(Type[] t)
215      out.print("implements ");    {
216      /* Scan implemented interfaces, and only print remote interfaces. */      String[] s = new String[t.length];
217      Class[] ifaces = clazz.getInterfaces();      for (int i = 0; i < t.length; i++)
     Set remoteIfaces = new HashSet();  
     for (int i = 0; i < ifaces.length; i++)  
218        {        {
219          Class iface = ifaces[i];          s[i] = t[i].getInternalName();
         if (java.rmi.Remote.class.isAssignableFrom(iface))  
           remoteIfaces.add(iface);  
220        }        }
     Iterator iter = remoteIfaces.iterator();  
     while (iter.hasNext())  
       {  
         /* Print remote interface. */  
         Class iface = (Class) iter.next();  
         out.print(iface.getName());  
221    
222          /* Print ", " if more remote interfaces follow. */      return s;
223          if (iter.hasNext())    }
           out.print(", ");  
       }  
     ctrl.unindent();  
     out.print("{");  
     ctrl.indent();  
224    
225      // UID    private static String[] internalNameArray(Class[] c)
226      if (need12Stubs)    {
227        return internalNameArray(typeArray(c));
228      }
229    
230      private static final String forName = "class$";
231    
232      private static Object param(Method m, int argIndex)
233      {
234        List l = new ArrayList();
235        l.add(m);
236        l.add(new Integer(argIndex));
237        return l;
238      }
239    
240      private static void generateClassForNamer(ClassVisitor cls)
241      {
242        CodeVisitor cv =
243          cls.visitMethod
244          (C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_SYNTHETIC, forName,
245           Type.getMethodDescriptor
246           (Type.getType(Class.class), new Type[] { Type.getType(String.class) }),
247           null, null);
248    
249        Label start = new Label();
250        cv.visitLabel(start);
251        cv.visitVarInsn(C.ALOAD, 0);
252        cv.visitMethodInsn
253          (C.INVOKESTATIC,
254           Type.getInternalName(Class.class),
255           "forName",
256           Type.getMethodDescriptor
257           (Type.getType(Class.class), new Type[] { Type.getType(String.class) }));
258        cv.visitInsn(C.ARETURN);
259    
260        Label handler = new Label();
261        cv.visitLabel(handler);
262        cv.visitVarInsn(C.ASTORE, 1);
263        cv.visitTypeInsn(C.NEW, typeArg(NoClassDefFoundError.class));
264        cv.visitInsn(C.DUP);
265        cv.visitVarInsn(C.ALOAD, 1);
266        cv.visitMethodInsn
267          (C.INVOKEVIRTUAL,
268           Type.getInternalName(ClassNotFoundException.class),
269           "getMessage",
270           Type.getMethodDescriptor(Type.getType(String.class), new Type[] {}));
271        cv.visitMethodInsn
272          (C.INVOKESPECIAL,
273           Type.getInternalName(NoClassDefFoundError.class),
274           "<init>",
275           Type.getMethodDescriptor
276           (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
277        cv.visitInsn(C.ATHROW);
278        cv.visitTryCatchBlock
279          (start, handler, handler,
280           Type.getInternalName(ClassNotFoundException.class));
281        cv.visitMaxs(-1, -1);
282      }
283    
284      private void generateClassConstant(CodeVisitor cv, Class cls) {
285        if (cls.isPrimitive())
286        {        {
287          out.println("private static final long serialVersionUID = 2L;");          Class boxCls;
288          out.println();          if (cls.equals(Boolean.TYPE))
289              boxCls = Boolean.class;
290            else if (cls.equals(Character.TYPE))
291              boxCls = Character.class;
292            else if (cls.equals(Byte.TYPE))
293              boxCls = Byte.class;
294            else if (cls.equals(Short.TYPE))
295              boxCls = Short.class;
296            else if (cls.equals(Integer.TYPE))
297              boxCls = Integer.class;
298            else if (cls.equals(Long.TYPE))
299              boxCls = Long.class;
300            else if (cls.equals(Float.TYPE))
301              boxCls = Float.class;
302            else if (cls.equals(Double.TYPE))
303              boxCls = Double.class;
304            else if (cls.equals(Void.TYPE))
305              boxCls = Void.class;
306            else
307              throw new IllegalArgumentException("unknown primitive type " + cls);
308    
309            cv.visitFieldInsn
310              (C.GETSTATIC, Type.getInternalName(boxCls), "TYPE",
311               Type.getDescriptor(Class.class));
312            return;
313          }
314        cv.visitLdcInsn(cls.getName());
315        cv.visitMethodInsn
316          (C.INVOKESTATIC, classInternalName, forName,
317           Type.getMethodDescriptor
318           (Type.getType(Class.class),
319            new Type[] { Type.getType(String.class) }));
320      }
321    
322      private void generateClassArray(CodeVisitor code, Class[] classes)
323      {
324        code.visitLdcInsn(new Integer(classes.length));
325        code.visitTypeInsn(C.ANEWARRAY, typeArg(Class.class));
326        for (int i = 0; i < classes.length; i++)
327          {
328            code.visitInsn(C.DUP);
329            code.visitLdcInsn(new Integer(i));
330            generateClassConstant(code, classes[i]);
331            code.visitInsn(C.AASTORE);
332        }        }
333      }
334    
335      // InterfaceHash - don't know how to calculate this - XXX    private void fillOperationArray(CodeVisitor clinit)
336      if (need11Stubs)    {
337        // Operations array
338        clinit.visitLdcInsn(new Integer(remotemethods.length));
339        clinit.visitTypeInsn(C.ANEWARRAY, typeArg(Operation.class));
340        clinit.visitFieldInsn
341          (C.PUTSTATIC, classInternalName, "operations",
342           Type.getDescriptor(Operation[].class));
343    
344        for (int i = 0; i < remotemethods.length; i++)
345        {        {
346          out.println("private static final long interfaceHash = "          Method m = remotemethods[i].meth;
                     + RMIHashes.getInterfaceHash(clazz) + "L;");  
         out.println();  
         if (need12Stubs)  
           {  
             out.println("private static boolean useNewInvoke;");  
             out.println();  
           }  
347    
348          // Operation table          StringBuffer desc = new StringBuffer();
349          out.print("private static final java.rmi.server.Operation[] operations = {");          desc.append(getPrettyName(m.getReturnType()) + " ");
350            desc.append(m.getName() + "(");
351    
352            // signature
353            Class[] sig = m.getParameterTypes();
354            for (int j = 0; j < sig.length; j++)
355              {
356                desc.append(getPrettyName(sig[j]));
357                if (j + 1 < sig.length)
358                    desc.append(", ");
359              }
360    
361            // push operations array
362            clinit.visitFieldInsn
363              (C.GETSTATIC, classInternalName, "operations",
364               Type.getDescriptor(Operation[].class));
365    
366            // push array index
367            clinit.visitLdcInsn(new Integer(i));
368    
369            // instantiate operation and leave a copy on the stack
370            clinit.visitTypeInsn(C.NEW, typeArg(Operation.class));
371            clinit.visitInsn(C.DUP);
372            clinit.visitLdcInsn(desc.toString());
373            clinit.visitMethodInsn
374              (C.INVOKESPECIAL,
375               Type.getInternalName(Operation.class),
376               "<init>",
377               Type.getMethodDescriptor
378               (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
379    
380          ctrl.indent();          // store in operations array
381          for (int i = 0; i < remotemethods.length; i++)          clinit.visitInsn(C.AASTORE);
           {  
             Method m = remotemethods[i].meth;  
             out.print("new java.rmi.server.Operation(\"");  
             out.print(getPrettyName(m.getReturnType()) + " ");  
             out.print(m.getName() + "(");  
             // Output signature  
             Class[] sig = m.getParameterTypes();  
             for (int j = 0; j < sig.length; j++)  
               {  
                 out.print(getPrettyName(sig[j]));  
                 if (j + 1 < sig.length)  
                   out.print(", ");  
               }  
             out.print(")\")");  
             if (i + 1 < remotemethods.length)  
               out.println(",");  
           }  
         ctrl.unindent();  
         out.println("};");  
         out.println();  
382        }        }
383      }
384    
385      // Set of method references.    private void generateStaticMethodObjs(CodeVisitor clinit)
386      if (need12Stubs)    {
387        for (int i = 0; i < remotemethods.length; i++)
388        {        {
389          for (int i = 0; i < remotemethods.length; i++)          Method m = remotemethods[i].meth;
           {  
             Method m = remotemethods[i].meth;  
             out.println("private static java.lang.reflect.Method $method_"  
                         + m.getName() + "_" + i + ";");  
           }  
   
         // Initialize the methods references.  
         out.println();  
         out.print("static {");  
         ctrl.indent();  
390    
391          out.print("try {");          /*
392          ctrl.indent();           * $method_<i>m.getName()</i>_<i>i</i> =
393             *   <i>m.getDeclaringClass()</i>.class.getMethod
394             *     (m.getName(), m.getParameterType())
395             */
396            String methodVar = "$method_" + m.getName() + "_" + i;
397            generateClassConstant(clinit, m.getDeclaringClass());
398            clinit.visitLdcInsn(m.getName());
399            generateClassArray(clinit, m.getParameterTypes());
400            clinit.visitMethodInsn
401              (C.INVOKEVIRTUAL,
402               Type.getInternalName(Class.class),
403               "getMethod",
404               Type.getMethodDescriptor
405               (Type.getType(Method.class),
406                new Type[] { Type.getType(String.class),
407                             Type.getType(Class[].class) }));
408    
409            clinit.visitFieldInsn
410              (C.PUTSTATIC, classInternalName, methodVar,
411               Type.getDescriptor(Method.class));
412          }
413      }
414    
415          if (need11Stubs)    private void generateStub() throws IOException
416            {    {
417              out.println("java.rmi.server.RemoteRef.class.getMethod(\"invoke\", new java.lang.Class[] { java.rmi.Remote.class, java.lang.reflect.Method.class, java.lang.Object[].class, long.class });");      stubname = fullclassname + "_Stub";
418              out.println("useNewInvoke = true;");      String stubclassname = classname + "_Stub";
419            }      File file = new File((destination == null ? "." : destination)
420                             + File.separator
421                             + stubname.replace('.', File.separatorChar)
422                             + ".class");
423    
424          for (int i = 0; i < remotemethods.length; i++)      if (verbose)
425            {        System.out.println("[Generating class " + stubname + "]");
             Method m = remotemethods[i].meth;  
             out.print("$method_" + m.getName() + "_" + i + " = ");  
             out.print(mRemoteInterface.getName() + ".class.getMethod(\""  
                       + m.getName() + "\"");  
             out.print(", new java.lang.Class[] {");  
             // Output signature  
             Class[] sig = m.getParameterTypes();  
             for (int j = 0; j < sig.length; j++)  
               {  
                 out.print(getPrettyName(sig[j]) + ".class");  
                 if (j + 1 < sig.length)  
                   out.print(", ");  
               }  
             out.println("});");  
           }  
         ctrl.unindent();  
         out.println("}");  
         out.print("catch (java.lang.NoSuchMethodException e) {");  
         ctrl.indent();  
         if (need11Stubs)  
           out.print("useNewInvoke = false;");  
         else  
           out.print("throw new java.lang.NoSuchMethodError(\"stub class initialization failed\");");  
426    
427          ctrl.unindent();      final ClassWriter stub = new ClassWriter(true);
428          out.print("}");      classInternalName = stubname.replace('.', '/');
429        final String superInternalName =
430          Type.getType(RemoteStub.class).getInternalName();
431    
432        String[] remoteInternalNames =
433          internalNameArray((Class[]) mRemoteInterfaces.toArray(new Class[] {}));
434        stub.visit
435          (C.V1_2, C.ACC_PUBLIC + C.ACC_FINAL, classInternalName,
436           superInternalName, remoteInternalNames, null);
437    
438          ctrl.unindent();      if (need12Stubs)
439          out.println("}");        {
440          out.println();          stub.visitField
441              (C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_FINAL, "serialVersionUID",
442               Type.LONG_TYPE.getDescriptor(), new Long(2L), null);
443        }        }
444    
     // Constructors  
445      if (need11Stubs)      if (need11Stubs)
446        {        {
447          out.print("public " + stubclassname + "() {");          stub.visitField
448          ctrl.indent();            (C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_FINAL,
449          out.print("super();");             "interfaceHash", Type.LONG_TYPE.getDescriptor(),
450          ctrl.unindent();             new Long(RMIHashes.getInterfaceHash(clazz)), null);
451          out.println("}");  
452            if (need12Stubs)
453              {
454                stub.visitField
455                  (C.ACC_PRIVATE + C.ACC_STATIC, "useNewInvoke",
456                   Type.BOOLEAN_TYPE.getDescriptor(), null, null);
457              }
458    
459            stub.visitField
460              (C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_FINAL,
461               "operations", Type.getDescriptor(Operation[].class), null, null);
462        }        }
463    
464        // Set of method references.
465      if (need12Stubs)      if (need12Stubs)
466        {        {
467          out.print("public " + stubclassname          for (int i = 0; i < remotemethods.length; i++)
468                    + "(java.rmi.server.RemoteRef ref) {");            {
469          ctrl.indent();              Method m = remotemethods[i].meth;
470          out.print("super(ref);");              String slotName = "$method_" + m.getName() + "_" + i;
471          ctrl.unindent();              stub.visitField
472          out.println("}");                (C.ACC_PRIVATE + C.ACC_STATIC, slotName,
473                   Type.getDescriptor(Method.class), null, null);
474              }
475        }        }
476    
477      // Method implementations      CodeVisitor clinit = stub.visitMethod
478      for (int i = 0; i < remotemethods.length; i++)        (C.ACC_STATIC, "<clinit>",
479        {         Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null);
         Method m = remotemethods[i].meth;  
         Class[] sig = m.getParameterTypes();  
         Class returntype = m.getReturnType();  
         Class[] except = sortExceptions(m.getExceptionTypes());  
   
         out.println();  
         out.print("public " + getPrettyName(returntype) + " " + m.getName()  
                   + "(");  
         for (int j = 0; j < sig.length; j++)  
           {  
             out.print(getPrettyName(sig[j]));  
             out.print(" $param_" + j);  
             if (j + 1 < sig.length)  
               out.print(", ");  
           }  
         out.print(") ");  
         out.print("throws ");  
         for (int j = 0; j < except.length; j++)  
           {  
             out.print(getPrettyName(except[j]));  
             if (j + 1 < except.length)  
               out.print(", ");  
           }  
         out.print(" {");  
         ctrl.indent();  
   
         out.print("try {");  
         ctrl.indent();  
   
         if (need12Stubs)  
           {  
             if (need11Stubs)  
               {  
                 out.print("if (useNewInvoke) {");  
                 ctrl.indent();  
               }  
             if (returntype != Void.TYPE)  
               out.print("java.lang.Object $result = ");  
             out.print("ref.invoke(this, $method_" + m.getName() + "_" + i  
                       + ", ");  
             if (sig.length == 0)  
               out.print("null, ");  
             else  
               {  
                 out.print("new java.lang.Object[] {");  
                 for (int j = 0; j < sig.length; j++)  
                   {  
                     if (sig[j] == Boolean.TYPE)  
                       out.print("new java.lang.Boolean($param_" + j + ")");  
                     else if (sig[j] == Byte.TYPE)  
                       out.print("new java.lang.Byte($param_" + j + ")");  
                     else if (sig[j] == Character.TYPE)  
                       out.print("new java.lang.Character($param_" + j + ")");  
                     else if (sig[j] == Short.TYPE)  
                       out.print("new java.lang.Short($param_" + j + ")");  
                     else if (sig[j] == Integer.TYPE)  
                       out.print("new java.lang.Integer($param_" + j + ")");  
                     else if (sig[j] == Long.TYPE)  
                       out.print("new java.lang.Long($param_" + j + ")");  
                     else if (sig[j] == Float.TYPE)  
                       out.print("new java.lang.Float($param_" + j + ")");  
                     else if (sig[j] == Double.TYPE)  
                       out.print("new java.lang.Double($param_" + j + ")");  
                     else  
                       out.print("$param_" + j);  
                     if (j + 1 < sig.length)  
                       out.print(", ");  
                   }  
                 out.print("}, ");  
               }  
             out.print(Long.toString(remotemethods[i].hash) + "L");  
             out.print(");");  
   
             if (returntype != Void.TYPE)  
               {  
                 out.println();  
                 out.print("return (");  
                 if (returntype == Boolean.TYPE)  
                   out.print("((java.lang.Boolean)$result).booleanValue()");  
                 else if (returntype == Byte.TYPE)  
                   out.print("((java.lang.Byte)$result).byteValue()");  
                 else if (returntype == Character.TYPE)  
                   out.print("((java.lang.Character)$result).charValue()");  
                 else if (returntype == Short.TYPE)  
                   out.print("((java.lang.Short)$result).shortValue()");  
                 else if (returntype == Integer.TYPE)  
                   out.print("((java.lang.Integer)$result).intValue()");  
                 else if (returntype == Long.TYPE)  
                   out.print("((java.lang.Long)$result).longValue()");  
                 else if (returntype == Float.TYPE)  
                   out.print("((java.lang.Float)$result).floatValue()");  
                 else if (returntype == Double.TYPE)  
                   out.print("((java.lang.Double)$result).doubleValue()");  
                 else  
                   out.print("(" + getPrettyName(returntype) + ")$result");  
                 out.print(");");  
               }  
480    
481              if (need11Stubs)      if (need11Stubs)
482                {        {
483                  ctrl.unindent();          fillOperationArray(clinit);
484                  out.println("}");          if (! need12Stubs)
485                  out.print("else {");            clinit.visitInsn(C.RETURN);
486                  ctrl.indent();        }
               }  
           }  
487    
488          if (need11Stubs)      if (need12Stubs)
489            {        {
490              out.println("java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, "          // begin of try
491                          + i + ", interfaceHash);");          Label begin = new Label();
             out.print("try {");  
             ctrl.indent();  
             out.print("java.io.ObjectOutput out = call.getOutputStream();");  
             for (int j = 0; j < sig.length; j++)  
               {  
                 out.println();  
                 if (sig[j] == Boolean.TYPE)  
                   out.print("out.writeBoolean(");  
                 else if (sig[j] == Byte.TYPE)  
                   out.print("out.writeByte(");  
                 else if (sig[j] == Character.TYPE)  
                   out.print("out.writeChar(");  
                 else if (sig[j] == Short.TYPE)  
                   out.print("out.writeShort(");  
                 else if (sig[j] == Integer.TYPE)  
                   out.print("out.writeInt(");  
                 else if (sig[j] == Long.TYPE)  
                   out.print("out.writeLong(");  
                 else if (sig[j] == Float.TYPE)  
                   out.print("out.writeFloat(");  
                 else if (sig[j] == Double.TYPE)  
                   out.print("out.writeDouble(");  
                 else  
                   out.print("out.writeObject(");  
                 out.print("$param_" + j + ");");  
               }  
             ctrl.unindent();  
             out.println("}");  
             out.print("catch (java.io.IOException e) {");  
             ctrl.indent();  
             out.print("throw new java.rmi.MarshalException(\"error marshalling arguments\", e);");  
             ctrl.unindent();  
             out.println("}");  
             out.println("ref.invoke(call);");  
             if (returntype != Void.TYPE)  
               out.println(getPrettyName(returntype) + " $result;");  
             out.print("try {");  
             ctrl.indent();  
             out.print("java.io.ObjectInput in = call.getInputStream();");  
             boolean needcastcheck = false;  
             if (returntype != Void.TYPE)  
               {  
                 out.println();  
                 out.print("$result = ");  
                 if (returntype == Boolean.TYPE)  
                   out.print("in.readBoolean();");  
                 else if (returntype == Byte.TYPE)  
                   out.print("in.readByte();");  
                 else if (returntype == Character.TYPE)  
                   out.print("in.readChar();");  
                 else if (returntype == Short.TYPE)  
                   out.print("in.readShort();");  
                 else if (returntype == Integer.TYPE)  
                   out.print("in.readInt();");  
                 else if (returntype == Long.TYPE)  
                   out.print("in.readLong();");  
                 else if (returntype == Float.TYPE)  
                   out.print("in.readFloat();");  
                 else if (returntype == Double.TYPE)  
                   out.print("in.readDouble();");  
                 else  
                   {  
                     if (returntype != Object.class)  
                       out.print("(" + getPrettyName(returntype) + ")");  
                     else  
                       needcastcheck = true;  
                     out.print("in.readObject();");  
                   }  
                 out.println();  
                 out.print("return ($result);");  
               }  
             ctrl.unindent();  
             out.println("}");  
             out.print("catch (java.io.IOException e) {");  
             ctrl.indent();  
             out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);");  
             ctrl.unindent();  
             out.println("}");  
             if (needcastcheck)  
               {  
                 out.print("catch (java.lang.ClassNotFoundException e) {");  
                 ctrl.indent();  
                 out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);");  
                 ctrl.unindent();  
                 out.println("}");  
               }  
             out.print("finally {");  
             ctrl.indent();  
             out.print("ref.done(call);");  
             ctrl.unindent();  
             out.print("}");  
492    
493              if (need12Stubs && need11Stubs)          // beginning of catch
494                {          Label handler = new Label();
495                  ctrl.unindent();          clinit.visitLabel(begin);
496                  out.print("}");  
497                }          // Initialize the methods references.
498            }          if (need11Stubs)
499              {
500                /*
501                 * RemoteRef.class.getMethod("invoke", new Class[] {
502                 *   Remote.class, Method.class, Object[].class, long.class })
503                 */
504                generateClassConstant(clinit, RemoteRef.class);
505                clinit.visitLdcInsn("invoke");
506                generateClassArray
507                  (clinit, new Class[] { Remote.class, Method.class,
508                                         Object[].class, long.class });
509                clinit.visitMethodInsn
510                  (C.INVOKEVIRTUAL,
511                   Type.getInternalName(Class.class),
512                   "getMethod",
513                   Type.getMethodDescriptor
514                   (Type.getType(Method.class),
515                    new Type[] { Type.getType(String.class),
516                                 Type.getType(Class[].class) }));
517    
518                // useNewInvoke = true
519                clinit.visitInsn(C.ICONST_1);
520                clinit.visitFieldInsn
521                  (C.PUTSTATIC, classInternalName, "useNewInvoke",
522                   Type.BOOLEAN_TYPE.getDescriptor());
523              }
524    
525            generateStaticMethodObjs(clinit);
526    
527            // jump past handler
528            clinit.visitInsn(C.RETURN);
529            clinit.visitLabel(handler);
530            if (need11Stubs)
531              {
532                // useNewInvoke = false
533                clinit.visitInsn(C.ICONST_0);
534                clinit.visitFieldInsn
535                  (C.PUTSTATIC, classInternalName, "useNewInvoke",
536                   Type.BOOLEAN_TYPE.getDescriptor());
537                clinit.visitInsn(C.RETURN);
538              }
539            else
540              {
541                // throw NoSuchMethodError
542                clinit.visitTypeInsn(C.NEW, typeArg(NoSuchMethodError.class));
543                clinit.visitInsn(C.DUP);
544                clinit.visitLdcInsn("stub class initialization failed");
545                clinit.visitMethodInsn
546                  (C.INVOKESPECIAL,
547                   Type.getInternalName(NoSuchMethodError.class),
548                   "<init>",
549                   Type.getMethodDescriptor
550                   (Type.VOID_TYPE,
551                    new Type[] { Type.getType(String.class) }));
552                clinit.visitInsn(C.ATHROW);
553              }
554    
555            clinit.visitTryCatchBlock
556              (begin, handler, handler,
557               Type.getInternalName(NoSuchMethodException.class));
558    
559          ctrl.unindent();        }
         out.print("}");  
560    
561          boolean needgeneral = true;      clinit.visitMaxs(-1, -1);
         for (int j = 0; j < except.length; j++)  
           {  
             out.println();  
             out.print("catch (" + getPrettyName(except[j]) + " e) {");  
             ctrl.indent();  
             out.print("throw e;");  
             ctrl.unindent();  
             out.print("}");  
             if (except[j] == Exception.class)  
               needgeneral = false;  
           }  
         if (needgeneral)  
           {  
             out.println();  
             out.print("catch (java.lang.Exception e) {");  
             ctrl.indent();  
             out.print("throw new java.rmi.UnexpectedException(\"undeclared checked exception\", e);");  
             ctrl.unindent();  
             out.print("}");  
           }  
562    
563          ctrl.unindent();      generateClassForNamer(stub);
         out.print("}");  
         out.println();  
       }  
564    
565      ctrl.unindent();      // Constructors
566      out.println("}");      if (need11Stubs)
567          {
568            // no arg public constructor
569            CodeVisitor code = stub.visitMethod
570              (C.ACC_PUBLIC, "<init>",
571               Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}),
572               null, null);
573            code.visitVarInsn(C.ALOAD, 0);
574            code.visitMethodInsn
575              (C.INVOKESPECIAL, superInternalName, "<init>",
576               Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));
577            code.visitInsn(C.RETURN);
578    
579            code.visitMaxs(-1, -1);
580          }
581    
582        // public RemoteRef constructor
583        CodeVisitor constructor = stub.visitMethod
584          (C.ACC_PUBLIC, "<init>",
585           Type.getMethodDescriptor
586           (Type.VOID_TYPE, new Type[] {Type.getType(RemoteRef.class)}),
587           null, null);
588        constructor.visitVarInsn(C.ALOAD, 0);
589        constructor.visitVarInsn(C.ALOAD, 1);
590        constructor.visitMethodInsn
591          (C.INVOKESPECIAL, superInternalName, "<init>",
592           Type.getMethodDescriptor
593           (Type.VOID_TYPE, new Type[] {Type.getType(RemoteRef.class)}));
594        constructor.visitInsn(C.RETURN);
595        constructor.visitMaxs(-1, -1);
596    
597      out.close();      // Method implementations
598        for (int i = 0; i < remotemethods.length; i++)
599          {
600            Method m = remotemethods[i].meth;
601            Class[] sig = m.getParameterTypes();
602            Class returntype = m.getReturnType();
603            Class[] except = sortExceptions
604              ((Class[]) remotemethods[i].exceptions.toArray(new Class[0]));
605    
606            CodeVisitor code = stub.visitMethod
607              (C.ACC_PUBLIC,
608               m.getName(),
609               Type.getMethodDescriptor(Type.getType(returntype), typeArray(sig)),
610               internalNameArray(typeArray(except)),
611               null);
612    
613            final Variables var = new Variables();
614    
615            // this and parameters are the declared vars
616            var.declare("this");
617            for (int j = 0; j < sig.length; j++)
618              var.declare(param(m, j), size(sig[j]));
619    
620            Label methodTryBegin = new Label();
621            code.visitLabel(methodTryBegin);
622    
623            if (need12Stubs)
624              {
625                Label oldInvoke = new Label();
626                if (need11Stubs)
627                  {
628                    // if not useNewInvoke jump to old invoke
629                    code.visitFieldInsn
630                      (C.GETSTATIC, classInternalName, "useNewInvoke",
631                       Type.getDescriptor(boolean.class));
632                    code.visitJumpInsn(C.IFEQ, oldInvoke);
633                  }
634    
635                // this.ref
636                code.visitVarInsn(C.ALOAD, var.get("this"));
637                code.visitFieldInsn
638                  (C.GETFIELD, Type.getInternalName(RemoteObject.class),
639                   "ref", Type.getDescriptor(RemoteRef.class));
640    
641                // "this" is first arg to invoke
642                code.visitVarInsn(C.ALOAD, var.get("this"));
643    
644                // method object is second arg to invoke
645                String methName = "$method_" + m.getName() + "_" + i;
646                code.visitFieldInsn
647                  (C.GETSTATIC, classInternalName, methName,
648                   Type.getDescriptor(Method.class));
649    
650                // args to remote method are third arg to invoke
651                if (sig.length == 0)
652                  code.visitInsn(C.ACONST_NULL);
653                else
654                  {
655                    // create arg Object[] (with boxed primitives) and push it
656                    code.visitLdcInsn(new Integer(sig.length));
657                    code.visitTypeInsn(C.ANEWARRAY, typeArg(Object.class));
658    
659                    var.allocate("argArray");
660                    code.visitVarInsn(C.ASTORE, var.get("argArray"));
661    
662                    for (int j = 0; j < sig.length; j++)
663                      {
664                        int size = size(sig[j]);
665                        int insn = loadOpcode(sig[j]);
666                        Class box = sig[j].isPrimitive() ? box(sig[j]) : null;
667    
668                        code.visitVarInsn(C.ALOAD, var.get("argArray"));
669                        code.visitLdcInsn(new Integer(j));
670    
671                        // put argument on stack
672                        if (box != null)
673                          {
674                            code.visitTypeInsn(C.NEW, typeArg(box));
675                            code.visitInsn(C.DUP);
676                            code.visitVarInsn(insn, var.get(param(m, j)));
677                            code.visitMethodInsn
678                              (C.INVOKESPECIAL,
679                               Type.getInternalName(box),
680                               "<init>",
681                               Type.getMethodDescriptor
682                               (Type.VOID_TYPE,
683                                new Type[] { Type.getType(sig[j]) }));
684                          }
685                        else
686                          code.visitVarInsn(insn, var.get(param(m, j)));
687    
688                        code.visitInsn(C.AASTORE);
689                      }
690    
691                    code.visitVarInsn(C.ALOAD, var.deallocate("argArray"));
692                  }
693    
694                // push remote operation opcode
695                code.visitLdcInsn(new Long(remotemethods[i].hash));
696                code.visitMethodInsn
697                  (C.INVOKEINTERFACE,
698                   Type.getInternalName(RemoteRef.class),
699                   "invoke",
700                   Type.getMethodDescriptor
701                   (Type.getType(Object.class),
702                    new Type[] { Type.getType(Remote.class),
703                                 Type.getType(Method.class),
704                                 Type.getType(Object[].class),
705                                 Type.LONG_TYPE }));
706    
707                if (! returntype.equals(Void.TYPE))
708                  {
709                    int retcode = returnOpcode(returntype);
710                    Class boxCls =
711                      returntype.isPrimitive() ? box(returntype) : null;
712                    code.visitTypeInsn
713                      (C.CHECKCAST, typeArg(boxCls == null ? returntype : boxCls));
714                    if (returntype.isPrimitive())
715                      {
716                        // unbox
717                        code.visitMethodInsn
718                          (C.INVOKEVIRTUAL,
719                           Type.getType(boxCls).getInternalName(),
720                           unboxMethod(returntype),
721                           Type.getMethodDescriptor
722                           (Type.getType(returntype), new Type[] {}));
723                      }
724    
725                    code.visitInsn(retcode);
726                  }
727                else
728                  code.visitInsn(C.RETURN);
729    
730    
731                if (need11Stubs)
732                  code.visitLabel(oldInvoke);
733              }
734    
735            if (need11Stubs)
736              {
737    
738                // this.ref.newCall(this, operations, index, interfaceHash)
739                code.visitVarInsn(C.ALOAD, var.get("this"));
740                code.visitFieldInsn
741                  (C.GETFIELD,
742                   Type.getInternalName(RemoteObject.class),
743                   "ref",
744                   Type.getDescriptor(RemoteRef.class));
745    
746                // "this" is first arg to newCall
747                code.visitVarInsn(C.ALOAD, var.get("this"));
748    
749                // operations is second arg to newCall
750                code.visitFieldInsn
751                  (C.GETSTATIC, classInternalName, "operations",
752                   Type.getDescriptor(Operation[].class));
753    
754                // method index is third arg
755                code.visitLdcInsn(new Integer(i));
756    
757                // interface hash is fourth arg
758                code.visitFieldInsn
759                  (C.GETSTATIC, classInternalName, "interfaceHash",
760                   Type.LONG_TYPE.getDescriptor());
761    
762                code.visitMethodInsn
763                  (C.INVOKEINTERFACE,
764                   Type.getInternalName(RemoteRef.class),
765                   "newCall",
766                   Type.getMethodDescriptor
767                   (Type.getType(RemoteCall.class),
768                    new Type[] { Type.getType(RemoteObject.class),
769                                 Type.getType(Operation[].class),
770                                 Type.INT_TYPE,
771                                 Type.LONG_TYPE }));
772    
773                // store call object on stack and leave copy on stack
774                var.allocate("call");
775                code.visitInsn(C.DUP);
776                code.visitVarInsn(C.ASTORE, var.get("call"));
777    
778                Label beginArgumentTryBlock = new Label();
779                code.visitLabel(beginArgumentTryBlock);
780    
781                // ObjectOutput out = call.getOutputStream();
782                code.visitMethodInsn
783                  (C.INVOKEINTERFACE,
784                   Type.getInternalName(RemoteCall.class),
785                   "getOutputStream",
786                   Type.getMethodDescriptor
787                   (Type.getType(ObjectOutput.class), new Type[] {}));
788    
789                for (int j = 0; j < sig.length; j++)
790                  {
791                    // dup the ObjectOutput
792                    code.visitInsn(C.DUP);
793    
794                    // get j'th arg to remote method
795                    code.visitVarInsn(loadOpcode(sig[j]), var.get(param(m, j)));
796    
797                    Class argCls =
798                      sig[j].isPrimitive() ? sig[j] : Object.class;
799    
800                    // out.writeFoo
801                    code.visitMethodInsn
802                      (C.INVOKEINTERFACE,
803                       Type.getInternalName(ObjectOutput.class),
804                       writeMethod(sig[j]),
805                       Type.getMethodDescriptor
806                       (Type.VOID_TYPE,
807                        new Type[] { Type.getType(argCls) }));
808                  }
809    
810                // pop ObjectOutput
811                code.visitInsn(C.POP);
812    
813                Label iohandler = new Label();
814                Label endArgumentTryBlock = new Label();
815                code.visitJumpInsn(C.GOTO, endArgumentTryBlock);
816                code.visitLabel(iohandler);
817    
818                // throw new MarshalException(msg, ioexception);
819                code.visitVarInsn(C.ASTORE, var.allocate("exception"));
820                code.visitTypeInsn(C.NEW, typeArg(MarshalException.class));
821                code.visitInsn(C.DUP);
822                code.visitLdcInsn("error marshalling arguments");
823                code.visitVarInsn(C.ALOAD, var.deallocate("exception"));
824                code.visitMethodInsn
825                  (C.INVOKESPECIAL,
826                   Type.getInternalName(MarshalException.class),
827                   "<init>",
828                   Type.getMethodDescriptor
829                   (Type.VOID_TYPE,
830                    new Type[] { Type.getType(String.class),
831                                 Type.getType(Exception.class) }));
832                code.visitInsn(C.ATHROW);
833    
834                code.visitLabel(endArgumentTryBlock);
835                code.visitTryCatchBlock
836                  (beginArgumentTryBlock, iohandler, iohandler,
837                   Type.getInternalName(IOException.class));
838    
839                // this.ref.invoke(call)
840                code.visitVarInsn(C.ALOAD, var.get("this"));
841                code.visitFieldInsn
842                  (C.GETFIELD, Type.getInternalName(RemoteObject.class),
843                   "ref", Type.getDescriptor(RemoteRef.class));
844                code.visitVarInsn(C.ALOAD, var.get("call"));
845                code.visitMethodInsn
846                  (C.INVOKEINTERFACE,
847                   Type.getInternalName(RemoteRef.class),
848                   "invoke",
849                   Type.getMethodDescriptor
850                   (Type.VOID_TYPE,
851                    new Type[] { Type.getType(RemoteCall.class) }));
852    
853                // handle return value
854                boolean needcastcheck = false;
855    
856                Label beginReturnTryCatch = new Label();
857                code.visitLabel(beginReturnTryCatch);
858    
859                int returncode = returnOpcode(returntype);
860    
861                if (! returntype.equals(Void.TYPE))
862                  {
863                    // call.getInputStream()
864                    code.visitVarInsn(C.ALOAD, var.get("call"));
865                    code.visitMethodInsn
866                      (C.INVOKEINTERFACE,
867                       Type.getInternalName(RemoteCall.class),
868                       "getInputStream",
869                       Type.getMethodDescriptor
870                       (Type.getType(ObjectInput.class), new Type[] {}));
871    
872                    Class readCls =
873                      returntype.isPrimitive() ? returntype : Object.class;
874                    code.visitMethodInsn
875                      (C.INVOKEINTERFACE,
876                       Type.getInternalName(ObjectInput.class),
877                       readMethod(returntype),
878                       Type.getMethodDescriptor
879                       (Type.getType(readCls), new Type[] {}));
880    
881                    boolean castresult = false;
882    
883                    if (! returntype.isPrimitive())
884                      {
885                        if (! returntype.equals(Object.class))
886                          castresult = true;
887                        else
888                          needcastcheck = true;
889                      }
890    
891                    if (castresult)
892                      code.visitTypeInsn(C.CHECKCAST, typeArg(returntype));
893    
894                    // leave result on stack for return
895                  }
896    
897                // this.ref.done(call)
898                code.visitVarInsn(C.ALOAD, var.get("this"));
899                code.visitFieldInsn
900                  (C.GETFIELD,
901                   Type.getInternalName(RemoteObject.class),
902                   "ref",
903                   Type.getDescriptor(RemoteRef.class));
904                code.visitVarInsn(C.ALOAD, var.deallocate("call"));
905                code.visitMethodInsn
906                  (C.INVOKEINTERFACE,
907                   Type.getInternalName(RemoteRef.class),
908                   "done",
909                   Type.getMethodDescriptor
910                   (Type.VOID_TYPE,
911                    new Type[] { Type.getType(RemoteCall.class) }));
912    
913                // return; or return result;
914                code.visitInsn(returncode);
915    
916                // exception handler
917                Label handler = new Label();
918                code.visitLabel(handler);
919                code.visitVarInsn(C.ASTORE, var.allocate("exception"));
920    
921                // throw new UnmarshalException(msg, e)
922                code.visitTypeInsn(C.NEW, typeArg(UnmarshalException.class));
923                code.visitInsn(C.DUP);
924                code.visitLdcInsn("error unmarshalling return");
925                code.visitVarInsn(C.ALOAD, var.deallocate("exception"));
926                code.visitMethodInsn
927                  (C.INVOKESPECIAL,
928                   Type.getInternalName(UnmarshalException.class),
929                   "<init>",
930                   Type.getMethodDescriptor
931                   (Type.VOID_TYPE,
932                    new Type[] { Type.getType(String.class),
933                                 Type.getType(Exception.class) }));
934                code.visitInsn(C.ATHROW);
935    
936                Label endReturnTryCatch = new Label();
937    
938                // catch IOException
939                code.visitTryCatchBlock
940                  (beginReturnTryCatch, handler, handler,
941                   Type.getInternalName(IOException.class));
942    
943                if (needcastcheck)
944                  {
945                    // catch ClassNotFoundException
946                    code.visitTryCatchBlock
947                      (beginReturnTryCatch, handler, handler,
948                       Type.getInternalName(ClassNotFoundException.class));
949                  }
950              }
951    
952            Label rethrowHandler = new Label();
953            code.visitLabel(rethrowHandler);
954            // rethrow declared exceptions
955            code.visitInsn(C.ATHROW);
956    
957            boolean needgeneral = true;
958            for (int j = 0; j < except.length; j++)
959              {
960                if (except[j] == Exception.class)
961                  needgeneral = false;
962              }
963    
964            for (int j = 0; j < except.length; j++)
965              {
966                code.visitTryCatchBlock
967                  (methodTryBegin, rethrowHandler, rethrowHandler,
968                   Type.getInternalName(except[j]));
969              }
970    
971            if (needgeneral)
972              {
973                // rethrow unchecked exceptions
974                code.visitTryCatchBlock
975                  (methodTryBegin, rethrowHandler, rethrowHandler,
976                   Type.getInternalName(RuntimeException.class));
977    
978                Label generalHandler = new Label();
979                code.visitLabel(generalHandler);
980                String msg = "undeclared checked exception";
981    
982                // throw new java.rmi.UnexpectedException(msg, e)
983                code.visitVarInsn(C.ASTORE, var.allocate("exception"));
984                code.visitTypeInsn(C.NEW, typeArg(UnexpectedException.class));
985                code.visitInsn(C.DUP);
986                code.visitLdcInsn(msg);
987                code.visitVarInsn(C.ALOAD, var.deallocate("exception"));
988                code.visitMethodInsn
989                  (C.INVOKESPECIAL,
990                   Type.getInternalName(UnexpectedException.class),
991                   "<init>",
992                   Type.getMethodDescriptor
993                   (Type.VOID_TYPE,
994                    new Type [] { Type.getType(String.class),
995                                  Type.getType(Exception.class) }));
996                code.visitInsn(C.ATHROW);
997    
998                code.visitTryCatchBlock
999                  (methodTryBegin, rethrowHandler, generalHandler,
1000                   Type.getInternalName(Exception.class));
1001              }
1002    
1003            code.visitMaxs(-1, -1);
1004          }
1005    
1006        stub.visitEnd();
1007        byte[] classData = stub.toByteArray();
1008        if (file.exists())
1009          file.delete();
1010        if (file.getParentFile() != null)
1011          file.getParentFile().mkdirs();
1012        FileOutputStream fos = new FileOutputStream(file);
1013        fos.write(classData);
1014        fos.flush();
1015        fos.close();
1016    }    }
1017    
1018    private void generateSkel() throws IOException    private void generateSkel() throws IOException
1019    {    {
1020      skelname = fullclassname + "_Skel";      skelname = fullclassname + "_Skel";
1021      String skelclassname = classname + "_Skel";      String skelclassname = classname + "_Skel";
1022      ctrl =      File file = new File(destination == null ? "" : destination
1023        new TabbedWriter(new FileWriter((destination == null ? ""                           + File.separator
1024                                                             : destination                           + skelname.replace('.', File.separatorChar)
1025                                                             + File.separator)                           + ".class");
                                       + skelname.replace('.',  
                                                          File.separatorChar)  
                                       + ".java"));  
     out = new PrintWriter(ctrl);  
   
1026      if (verbose)      if (verbose)
1027        System.out.println("[Generating class " + skelname + ".java]");        System.out.println("[Generating class " + skelname + "]");
1028    
1029        final ClassWriter skel = new ClassWriter(true);
1030        classInternalName = skelname.replace('.', '/');
1031        skel.visit
1032          (C.V1_1, C.ACC_PUBLIC + C.ACC_FINAL,
1033           classInternalName, Type.getInternalName(Object.class),
1034           new String[] { Type.getType(Skeleton.class).getInternalName() }, null);
1035    
1036        skel.visitField
1037          (C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_FINAL, "interfaceHash",
1038           Type.LONG_TYPE.getDescriptor(),
1039           new Long(RMIHashes.getInterfaceHash(clazz)),
1040           null);
1041    
1042        skel.visitField
1043          (C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_FINAL, "operations",
1044           Type.getDescriptor(Operation[].class), null, null);
1045    
1046        CodeVisitor clinit = skel.visitMethod
1047          (C.ACC_STATIC, "<clinit>",
1048           Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null);
1049    
1050        fillOperationArray(clinit);
1051        clinit.visitInsn(C.RETURN);
1052    
1053        clinit.visitMaxs(-1, -1);
1054    
1055        // no arg public constructor
1056        CodeVisitor init = skel.visitMethod
1057          (C.ACC_PUBLIC, "<init>",
1058           Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null);
1059        init.visitVarInsn(C.ALOAD, 0);
1060        init.visitMethodInsn
1061          (C.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>",
1062           Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));
1063        init.visitInsn(C.RETURN);
1064        init.visitMaxs(-1, -1);
1065    
1066        /*
1067         * public Operation[] getOperations()
1068         * returns a clone of the operations array
1069         */
1070        CodeVisitor getOp = skel.visitMethod
1071          (C.ACC_PUBLIC, "getOperations",
1072           Type.getMethodDescriptor
1073           (Type.getType(Operation[].class), new Type[] {}),
1074           null, null);
1075        getOp.visitFieldInsn
1076          (C.GETSTATIC, classInternalName, "operations",
1077           Type.getDescriptor(Operation[].class));
1078        getOp.visitMethodInsn
1079          (C.INVOKEVIRTUAL, Type.getInternalName(Object.class),
1080           "clone", Type.getMethodDescriptor(Type.getType(Object.class),
1081                                             new Type[] {}));
1082        getOp.visitTypeInsn(C.CHECKCAST, typeArg(Operation[].class));
1083        getOp.visitInsn(C.ARETURN);
1084        getOp.visitMaxs(-1, -1);
1085    
1086        // public void dispatch(Remote, RemoteCall, int opnum, long hash)
1087        CodeVisitor dispatch = skel.visitMethod
1088          (C.ACC_PUBLIC,
1089           "dispatch",
1090           Type.getMethodDescriptor
1091           (Type.VOID_TYPE,
1092            new Type[] { Type.getType(Remote.class),
1093                         Type.getType(RemoteCall.class),
1094                         Type.INT_TYPE, Type.LONG_TYPE }),
1095           new String[] { Type.getInternalName(Exception.class) },
1096           null);
1097    
1098        Variables var = new Variables();
1099        var.declare("this");
1100        var.declare("remoteobj");
1101        var.declare("remotecall");
1102        var.declare("opnum");
1103        var.declareWide("hash");
1104    
1105        /*
1106         * if opnum >= 0
1107         * XXX it is unclear why there is handling of negative opnums
1108         */
1109        dispatch.visitVarInsn(C.ILOAD, var.get("opnum"));
1110        Label nonNegativeOpnum = new Label();
1111        Label opnumSet = new Label();
1112        dispatch.visitJumpInsn(C.IFGE, nonNegativeOpnum);
1113    
1114      out.println("// Skel class generated by rmic - DO NOT EDIT!");      for (int i = 0; i < remotemethods.length; i++)
     out.println();  
     if (fullclassname != classname)  
1115        {        {
1116          String pname =          // assign opnum if hash matches supplied hash
1117            fullclassname.substring(0, fullclassname.lastIndexOf('.'));          dispatch.visitVarInsn(C.LLOAD, var.get("hash"));
1118          out.println("package " + pname + ";");          dispatch.visitLdcInsn(new Long(remotemethods[i].hash));
1119          out.println();          Label notIt = new Label();
1120        }          dispatch.visitInsn(C.LCMP);
1121            dispatch.visitJumpInsn(C.IFNE, notIt);
1122    
1123            // opnum = <opnum>
1124            dispatch.visitLdcInsn(new Integer(i));
1125            dispatch.visitVarInsn(C.ISTORE, var.get("opnum"));
1126            dispatch.visitJumpInsn(C.GOTO, opnumSet);
1127            dispatch.visitLabel(notIt);
1128          }
1129    
1130        // throw new SkeletonMismatchException
1131        Label mismatch = new Label();
1132        dispatch.visitJumpInsn(C.GOTO, mismatch);
1133    
1134        dispatch.visitLabel(nonNegativeOpnum);
1135    
1136        // if opnum is already set, check that the hash matches the interface
1137        dispatch.visitVarInsn(C.LLOAD, var.get("hash"));
1138        dispatch.visitFieldInsn
1139          (C.GETSTATIC, classInternalName,
1140           "interfaceHash", Type.LONG_TYPE.getDescriptor());
1141        dispatch.visitInsn(C.LCMP);
1142        dispatch.visitJumpInsn(C.IFEQ, opnumSet);
1143    
1144        dispatch.visitLabel(mismatch);
1145        dispatch.visitTypeInsn
1146          (C.NEW, typeArg(SkeletonMismatchException.class));
1147        dispatch.visitInsn(C.DUP);
1148        dispatch.visitLdcInsn("interface hash mismatch");
1149        dispatch.visitMethodInsn
1150          (C.INVOKESPECIAL,
1151           Type.getInternalName(SkeletonMismatchException.class),
1152           "<init>",
1153           Type.getMethodDescriptor
1154           (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
1155        dispatch.visitInsn(C.ATHROW);
1156    
1157        // opnum has been set
1158        dispatch.visitLabel(opnumSet);
1159    
1160        dispatch.visitVarInsn(C.ALOAD, var.get("remoteobj"));
1161        dispatch.visitTypeInsn(C.CHECKCAST, typeArg(clazz));
1162        dispatch.visitVarInsn(C.ASTORE, var.get("remoteobj"));
1163    
1164        Label deflt = new Label();
1165        Label[] methLabels = new Label[remotemethods.length];
1166        for (int i = 0; i < methLabels.length; i++)
1167          methLabels[i] = new Label();
1168    
1169        // switch on opnum
1170        dispatch.visitVarInsn(C.ILOAD, var.get("opnum"));
1171        dispatch.visitTableSwitchInsn
1172          (0, remotemethods.length - 1, deflt, methLabels);
1173    
1174      out.print("public final class " + skelclassname);      // Method dispatch
1175      ctrl.indent();      for (int i = 0; i < remotemethods.length; i++)
1176          {
1177            dispatch.visitLabel(methLabels[i]);
1178            Method m = remotemethods[i].meth;
1179            generateMethodSkel(dispatch, m, var);
1180          }
1181    
1182        dispatch.visitLabel(deflt);
1183        dispatch.visitTypeInsn(C.NEW, typeArg(UnmarshalException.class));
1184        dispatch.visitInsn(C.DUP);
1185        dispatch.visitLdcInsn("invalid method number");
1186        dispatch.visitMethodInsn
1187          (C.INVOKESPECIAL,
1188           Type.getInternalName(UnmarshalException.class),
1189           "<init>",
1190           Type.getMethodDescriptor
1191           (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
1192        dispatch.visitInsn(C.ATHROW);
1193    
1194        dispatch.visitMaxs(-1, -1);
1195    
1196        skel.visitEnd();
1197        byte[] classData = skel.toByteArray();
1198        if (file.exists())
1199          file.delete();
1200        if (file.getParentFile() != null)
1201          file.getParentFile().mkdirs();
1202        FileOutputStream fos = new FileOutputStream(file);
1203        fos.write(classData);
1204        fos.flush();
1205        fos.close();
1206      }
1207    
1208      // Output interfaces we implement    private void generateMethodSkel(CodeVisitor cv, Method m, Variables var)
1209      out.print("implements java.rmi.server.Skeleton");    {
1210        Class[] sig = m.getParameterTypes();
1211    
1212      ctrl.unindent();      Label readArgs = new Label();
1213      out.print("{");      cv.visitLabel(readArgs);
     ctrl.indent();  
1214    
1215      // Interface hash - don't know how to calculate this - XXX      boolean needcastcheck = false;
     out.println("private static final long interfaceHash = "  
                 + RMIHashes.getInterfaceHash(clazz) + "L;");  
     out.println();  
1216    
1217      // Operation table      // ObjectInput in = call.getInputStream();
1218      out.print("private static final java.rmi.server.Operation[] operations = {");      cv.visitVarInsn(C.ALOAD, var.get("remotecall"));
1219        cv.visitMethodInsn
1220          (C.INVOKEINTERFACE,
1221           Type.getInternalName(RemoteCall.class), "getInputStream",
1222           Type.getMethodDescriptor
1223           (Type.getType(ObjectInput.class), new Type[] {}));
1224        cv.visitVarInsn(C.ASTORE, var.allocate("objectinput"));
1225    
1226        for (int i = 0; i < sig.length; i++)
1227          {
1228            // dup input stream
1229            cv.visitVarInsn(C.ALOAD, var.get("objectinput"));
1230    
1231            Class readCls = sig[i].isPrimitive() ? sig[i] : Object.class;
1232    
1233            // in.readFoo()
1234            cv.visitMethodInsn
1235              (C.INVOKEINTERFACE,
1236               Type.getInternalName(ObjectInput.class),
1237               readMethod(sig[i]),
1238               Type.getMethodDescriptor
1239               (Type.getType(readCls), new Type [] {}));
1240    
1241            if (! sig[i].isPrimitive() && ! sig[i].equals(Object.class))
1242              {
1243                needcastcheck = true;
1244                cv.visitTypeInsn(C.CHECKCAST, typeArg(sig[i]));
1245              }
1246    
1247            // store arg in variable
1248            cv.visitVarInsn
1249              (storeOpcode(sig[i]), var.allocate(param(m, i), size(sig[i])));
1250          }
1251    
1252        var.deallocate("objectinput");
1253    
1254        Label doCall = new Label();
1255        Label closeInput = new Label();
1256    
1257        cv.visitJumpInsn(C.JSR, closeInput);
1258        cv.visitJumpInsn(C.GOTO, doCall);
1259    
1260        // throw new UnmarshalException
1261        Label handler = new Label();
1262        cv.visitLabel(handler);
1263        cv.visitVarInsn(C.ASTORE, var.allocate("exception"));
1264        cv.visitTypeInsn(C.NEW, typeArg(UnmarshalException.class));
1265        cv.visitInsn(C.DUP);
1266        cv.visitLdcInsn("error unmarshalling arguments");
1267        cv.visitVarInsn(C.ALOAD, var.deallocate("exception"));
1268        cv.visitMethodInsn
1269          (C.INVOKESPECIAL,
1270           Type.getInternalName(UnmarshalException.class),
1271           "<init>",
1272           Type.getMethodDescriptor
1273           (Type.VOID_TYPE, new Type[] { Type.getType(String.class),
1274                                         Type.getType(Exception.class) }));
1275        cv.visitVarInsn(C.ASTORE, var.allocate("toThrow"));
1276        cv.visitJumpInsn(C.JSR, closeInput);
1277        cv.visitVarInsn(C.ALOAD, var.get("toThrow"));
1278        cv.visitInsn(C.ATHROW);
1279    
1280        cv.visitTryCatchBlock
1281          (readArgs, handler, handler, Type.getInternalName(IOException.class));
1282        if (needcastcheck)
1283          {
1284            cv.visitTryCatchBlock
1285              (readArgs, handler, handler,
1286               Type.getInternalName(ClassCastException.class));
1287          }
1288    
1289        // finally block
1290        cv.visitLabel(closeInput);
1291        cv.visitVarInsn(C.ASTORE, var.allocate("retAddress"));
1292        cv.visitVarInsn(C.ALOAD, var.get("remotecall"));
1293        cv.visitMethodInsn
1294          (C.INVOKEINTERFACE,
1295           Type.getInternalName(RemoteCall.class),
1296           "releaseInputStream",
1297           Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));
1298        cv.visitVarInsn(C.RET, var.deallocate("retAddress"));
1299        var.deallocate("toThrow");
1300    
1301        // do the call using args stored as variables
1302        cv.visitLabel(doCall);
1303        cv.visitVarInsn(C.ALOAD, var.get("remoteobj"));
1304        for (int i = 0; i < sig.length; i++)
1305          cv.visitVarInsn(loadOpcode(sig[i]), var.deallocate(param(m, i)));
1306        cv.visitMethodInsn
1307          (C.INVOKEVIRTUAL, Type.getInternalName(clazz), m.getName(),
1308           Type.getMethodDescriptor(m));
1309    
1310        Class returntype = m.getReturnType();
1311        if (! returntype.equals(Void.TYPE))
1312          {
1313            cv.visitVarInsn
1314              (storeOpcode(returntype), var.allocate("result", size(returntype)));
1315          }
1316    
1317        // write result to result stream
1318        Label writeResult = new Label();
1319        cv.visitLabel(writeResult);
1320        cv.visitVarInsn(C.ALOAD, var.get("remotecall"));
1321        cv.visitInsn(C.ICONST_1);
1322        cv.visitMethodInsn
1323          (C.INVOKEINTERFACE,
1324           Type.getInternalName(RemoteCall.class),
1325           "getResultStream",
1326           Type.getMethodDescriptor
1327           (Type.getType(ObjectOutput.class),
1328            new Type[] { Type.BOOLEAN_TYPE }));
1329    
1330        if (! returntype.equals(Void.TYPE))
1331          {
1332            // out.writeFoo(result)
1333            cv.visitVarInsn(loadOpcode(returntype), var.deallocate("result"));
1334            Class writeCls = returntype.isPrimitive() ? returntype : Object.class;
1335            cv.visitMethodInsn
1336              (C.INVOKEINTERFACE,
1337               Type.getInternalName(ObjectOutput.class),
1338               writeMethod(returntype),
1339               Type.getMethodDescriptor
1340               (Type.VOID_TYPE, new Type[] { Type.getType(writeCls) }));
1341          }
1342    
1343        cv.visitInsn(C.RETURN);
1344    
1345        // throw new MarshalException
1346        Label marshalHandler = new Label();
1347        cv.visitLabel(marshalHandler);
1348        cv.visitVarInsn(C.ASTORE, var.allocate("exception"));
1349        cv.visitTypeInsn(C.NEW, typeArg(MarshalException.class));
1350        cv.visitInsn(C.DUP);
1351        cv.visitLdcInsn("error marshalling return");
1352        cv.visitVarInsn(C.ALOAD, var.deallocate("exception"));
1353        cv.visitMethodInsn
1354          (C.INVOKESPECIAL,
1355           Type.getInternalName(MarshalException.class),
1356           "<init>",
1357           Type.getMethodDescriptor
1358           (Type.VOID_TYPE, new Type[] { Type.getType(String.class),
1359                                         Type.getType(Exception.class) }));
1360        cv.visitInsn(C.ATHROW);
1361        cv.visitTryCatchBlock
1362          (writeResult, marshalHandler, marshalHandler,
1363           Type.getInternalName(IOException.class));
1364      }
1365    
1366      ctrl.indent();    private static String typeArg(Class cls)
1367      for (int i = 0; i < remotemethods.length; i++)    {
1368        {      if (cls.isArray())
1369          Method m = remotemethods[i].meth;        return Type.getDescriptor(cls);
         out.print("new java.rmi.server.Operation(\"");  
         out.print(getPrettyName(m.getReturnType()) + " ");  
         out.print(m.getName() + "(");  
         // Output signature  
         Class[] sig = m.getParameterTypes();  
         for (int j = 0; j < sig.length; j++)  
           {  
             out.print(getPrettyName(sig[j]));  
             if (j + 1 < sig.length)  
               out.print(", ");  
           }  
         out.print("\")");  
         if (i + 1 < remotemethods.length)  
           out.println(",");  
       }  
     ctrl.unindent();  
     out.println("};");  
   
     out.println();  
   
     // getOperations method  
     out.print("public java.rmi.server.Operation[] getOperations() {");  
     ctrl.indent();  
     out.print("return ((java.rmi.server.Operation[]) operations.clone());");  
     ctrl.unindent();  
     out.println("}");  
   
     out.println();  
   
     // Dispatch method  
     out.print("public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception {");  
     ctrl.indent();  
1370    
1371      out.print("if (opnum < 0) {");      return Type.getInternalName(cls);
1372      ctrl.indent();    }
1373    
1374      for (int i = 0; i < remotemethods.length; i++)    private static String readMethod(Class cls)
1375        {    {
1376          out.print("if (hash == " + Long.toString(remotemethods[i].hash)      if (cls.equals(Void.TYPE))
1377                    + "L) {");        throw new IllegalArgumentException("can not read void");
         ctrl.indent();  
         out.print("opnum = " + i + ";");  
         ctrl.unindent();  
         out.println("}");  
         out.print("else ");  
       }  
     out.print("{");  
     ctrl.indent();  
     out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");");  
     ctrl.unindent();  
     out.print("}");  
   
     ctrl.unindent();  
     out.println("}");  
     out.print("else if (hash != interfaceHash) {");  
     ctrl.indent();  
     out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");");  
     ctrl.unindent();  
     out.println("}");  
1378    
1379      out.println();      String method;
1380        if (cls.equals(Boolean.TYPE))
1381          method = "readBoolean";
1382        else if (cls.equals(Byte.TYPE))
1383          method = "readByte";
1384        else if (cls.equals(Character.TYPE))
1385          method = "readChar";
1386        else if (cls.equals(Short.TYPE))
1387          method = "readShort";
1388        else if (cls.equals(Integer.TYPE))
1389          method = "readInt";
1390        else if (cls.equals(Long.TYPE))
1391          method = "readLong";
1392        else if (cls.equals(Float.TYPE))
1393          method = "readFloat";
1394        else if (cls.equals(Double.TYPE))
1395          method = "readDouble";
1396        else
1397          method = "readObject";
1398    
1399      out.println(fullclassname + " server = (" + fullclassname + ")obj;");      return method;
1400      out.println("switch (opnum) {");    }
1401    
1402      // Method dispatch    private static String writeMethod(Class cls)
1403      for (int i = 0; i < remotemethods.length; i++)    {
1404        {      if (cls.equals(Void.TYPE))
1405          Method m = remotemethods[i].meth;        throw new IllegalArgumentException("can not read void");
         out.println("case " + i + ":");  
         out.print("{");  
         ctrl.indent();  
1406    
1407          Class[] sig = m.getParameterTypes();      String method;
1408          for (int j = 0; j < sig.length; j++)      if (cls.equals(Boolean.TYPE))
1409            {        method = "writeBoolean";
1410              out.print(getPrettyName(sig[j]));      else if (cls.equals(Byte.TYPE))
1411              out.println(" $param_" + j + ";");        method = "writeByte";
1412            }      else if (cls.equals(Character.TYPE))
1413          method = "writeChar";
1414        else if (cls.equals(Short.TYPE))
1415          method = "writeShort";
1416        else if (cls.equals(Integer.TYPE))
1417          method = "writeInt";
1418        else if (cls.equals(Long.TYPE))
1419          method = "writeLong";
1420        else if (cls.equals(Float.TYPE))
1421          method = "writeFloat";
1422        else if (cls.equals(Double.TYPE))
1423          method = "writeDouble";
1424        else
1425          method = "writeObject";
1426    
1427          out.print("try {");      return method;
1428          boolean needcastcheck = false;    }
         ctrl.indent();  
         out.println("java.io.ObjectInput in = call.getInputStream();");  
         for (int j = 0; j < sig.length; j++)  
           {  
             out.print("$param_" + j + " = ");  
             if (sig[j] == Boolean.TYPE)  
               out.print("in.readBoolean();");  
             else if (sig[j] == Byte.TYPE)  
               out.print("in.readByte();");  
             else if (sig[j] == Character.TYPE)  
               out.print("in.readChar();");  
             else if (sig[j] == Short.TYPE)  
               out.print("in.readShort();");  
             else if (sig[j] == Integer.TYPE)  
               out.print("in.readInt();");  
             else if (sig[j] == Long.TYPE)  
               out.print("in.readLong();");  
             else if (sig[j] == Float.TYPE)  
               out.print("in.readFloat();");  
             else if (sig[j] == Double.TYPE)  
               out.print("in.readDouble();");  
             else  
               {  
                 if (sig[j] != Object.class)  
                   {  
                     out.print("(" + getPrettyName(sig[j]) + ")");  
                     needcastcheck = true;  
                   }  
                 out.print("in.readObject();");  
               }  
             out.println();  
           }  
         ctrl.unindent();  
         out.println("}");  
         out.print("catch (java.io.IOException e) {");  
         ctrl.indent();  
         out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);");  
         ctrl.unindent();  
         out.println("}");  
         if (needcastcheck)  
           {  
             out.print("catch (java.lang.ClassCastException e) {");  
             ctrl.indent();  
             out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);");  
             ctrl.unindent();  
             out.println("}");  
           }  
         out.print("finally {");  
         ctrl.indent();  
         out.print("call.releaseInputStream();");  
         ctrl.unindent();  
         out.println("}");  
   
         Class returntype = m.getReturnType();  
         if (returntype != Void.TYPE)  
           out.print(getPrettyName(returntype) + " $result = ");  
         out.print("server." + m.getName() + "(");  
         for (int j = 0; j < sig.length; j++)  
           {  
             out.print("$param_" + j);  
             if (j + 1 < sig.length)  
               out.print(", ");  
           }  
         out.println(");");  
1429    
1430          out.print("try {");    private static int returnOpcode(Class cls)
1431          ctrl.indent();    {
1432          out.print("java.io.ObjectOutput out = call.getResultStream(true);");      int returncode;
1433          if (returntype != Void.TYPE)      if (cls.equals(Boolean.TYPE))
1434            {        returncode = C.IRETURN;
1435              out.println();      else if (cls.equals(Byte.TYPE))
1436              if (returntype == Boolean.TYPE)        returncode = C.IRETURN;
1437                out.print("out.writeBoolean($result);");      else if (cls.equals(Character.TYPE))
1438              else if (returntype == Byte.TYPE)        returncode = C.IRETURN;
1439                out.print("out.writeByte($result);");      else if (cls.equals(Short.TYPE))
1440              else if (returntype == Character.TYPE)        returncode = C.IRETURN;
1441                out.print("out.writeChar($result);");      else if (cls.equals(Integer.TYPE))
1442              else if (returntype == Short.TYPE)        returncode = C.IRETURN;
1443                out.print("out.writeShort($result);");      else if (cls.equals(Long.TYPE))
1444              else if (returntype == Integer.TYPE)        returncode = C.LRETURN;
1445                out.print("out.writeInt($result);");      else if (cls.equals(Float.TYPE))
1446              else if (returntype == Long.TYPE)        returncode = C.FRETURN;
1447                out.print("out.writeLong($result);");      else if (cls.equals(Double.TYPE))
1448              else if (returntype == Float.TYPE)        returncode = C.DRETURN;
1449                out.print("out.writeFloat($result);");      else if (cls.equals(Void.TYPE))
1450              else if (returntype == Double.TYPE)        returncode = C.RETURN;
1451                out.print("out.writeDouble($result);");      else
1452              else        returncode = C.ARETURN;
               out.print("out.writeObject($result);");  
           }  
         ctrl.unindent();  
         out.println("}");  
         out.print("catch (java.io.IOException e) {");  
         ctrl.indent();  
         out.print("throw new java.rmi.MarshalException(\"error marshalling return\", e);");  
         ctrl.unindent();  
         out.println("}");  
         out.print("break;");  
1453    
1454          ctrl.unindent();      return returncode;
1455          out.println("}");    }
         out.println();  
       }  
1456    
1457      out.print("default:");    private static int loadOpcode(Class cls)
1458      ctrl.indent();    {
1459      out.print("throw new java.rmi.UnmarshalException(\"invalid method number\");");      if (cls.equals(Void.TYPE))
1460      ctrl.unindent();        throw new IllegalArgumentException("can not load void");
     out.print("}");  
1461    
1462      ctrl.unindent();      int loadcode;
1463      out.print("}");      if (cls.equals(Boolean.TYPE))
1464          loadcode = C.ILOAD;
1465        else if (cls.equals(Byte.TYPE))
1466          loadcode = C.ILOAD;
1467        else if (cls.equals(Character.TYPE))
1468          loadcode = C.ILOAD;
1469        else if (cls.equals(Short.TYPE))
1470          loadcode = C.ILOAD;
1471        else if (cls.equals(Integer.TYPE))
1472          loadcode = C.ILOAD;
1473        else if (cls.equals(Long.TYPE))
1474          loadcode = C.LLOAD;
1475        else if (cls.equals(Float.TYPE))
1476          loadcode = C.FLOAD;
1477        else if (cls.equals(Double.TYPE))
1478          loadcode = C.DLOAD;
1479        else
1480          loadcode = C.ALOAD;
1481    
1482        return loadcode;
1483      }
1484    
1485      ctrl.unindent();    private static int storeOpcode(Class cls)
1486      out.println("}");    {
1487        if (cls.equals(Void.TYPE))
1488          throw new IllegalArgumentException("can not load void");
1489    
1490      out.close();      int storecode;
1491        if (cls.equals(Boolean.TYPE))
1492          storecode = C.ISTORE;
1493        else if (cls.equals(Byte.TYPE))
1494          storecode = C.ISTORE;
1495        else if (cls.equals(Character.TYPE))
1496          storecode = C.ISTORE;
1497        else if (cls.equals(Short.TYPE))
1498          storecode = C.ISTORE;
1499        else if (cls.equals(Integer.TYPE))
1500          storecode = C.ISTORE;
1501        else if (cls.equals(Long.TYPE))
1502          storecode = C.LSTORE;
1503        else if (cls.equals(Float.TYPE))
1504          storecode = C.FSTORE;
1505        else if (cls.equals(Double.TYPE))
1506          storecode = C.DSTORE;
1507        else
1508          storecode = C.ASTORE;
1509    
1510        return storecode;
1511    }    }
1512    
1513    private void compile(String name) throws Exception    private static String unboxMethod(Class primitive)
1514    {    {
1515      Compiler comp = Compiler.getInstance();      if (! primitive.isPrimitive())
1516      if (verbose)        throw new IllegalArgumentException("can not unbox nonprimitive");
1517        System.out.println("[Compiling class " + name + "]");  
1518      comp.setDestination(destination);      String method;
1519      comp.compile(name);      if (primitive.equals(Boolean.TYPE))
1520          method = "booleanValue";
1521        else if (primitive.equals(Byte.TYPE))
1522          method = "byteValue";
1523        else if (primitive.equals(Character.TYPE))
1524          method = "charValue";
1525        else if (primitive.equals(Short.TYPE))
1526          method = "shortValue";
1527        else if (primitive.equals(Integer.TYPE))
1528          method = "intValue";
1529        else if (primitive.equals(Long.TYPE))
1530          method = "longValue";
1531        else if (primitive.equals(Float.TYPE))
1532          method = "floatValue";
1533        else if (primitive.equals(Double.TYPE))
1534          method = "doubleValue";
1535        else
1536          throw new IllegalStateException("unknown primitive class " + primitive);
1537    
1538        return method;
1539    }    }
1540    
1541    private static String getPrettyName(Class cls)    public static Class box(Class cls)
1542    {    {
1543      StringBuffer str = new StringBuffer();      if (! cls.isPrimitive())
1544      for (int count = 0;; count++)        throw new IllegalArgumentException("can only box primitive");
1545        {  
1546          if (! cls.isArray())      Class box;
1547            {      if (cls.equals(Boolean.TYPE))
1548              str.append(cls.getName());        box = Boolean.class;
1549              for (; count > 0; count--)      else if (cls.equals(Byte.TYPE))
1550                str.append("[]");        box = Byte.class;
1551              return (str.toString());      else if (cls.equals(Character.TYPE))
1552            }        box = Character.class;
1553          cls = cls.getComponentType();      else if (cls.equals(Short.TYPE))
1554        }        box = Short.class;
1555        else if (cls.equals(Integer.TYPE))
1556          box = Integer.class;
1557        else if (cls.equals(Long.TYPE))
1558          box = Long.class;
1559        else if (cls.equals(Float.TYPE))
1560          box = Float.class;
1561        else if (cls.equals(Double.TYPE))
1562          box = Double.class;
1563        else
1564          throw new IllegalStateException("unknown primitive type " + cls);
1565    
1566        return box;
1567      }
1568    
1569      private static int size(Class cls) {
1570        if (cls.equals(Long.TYPE) || cls.equals(Double.TYPE))
1571          return 2;
1572        else
1573          return 1;
1574    }    }
1575    
1576  /**    /**
1577   * Sort exceptions so the most general go last.     * Sort exceptions so the most general go last.
1578   */     */
1579    private Class[] sortExceptions(Class[] except)    private Class[] sortExceptions(Class[] except)
1580    {    {
1581      for (int i = 0; i < except.length; i++)      for (int i = 0; i < except.length; i++)
# Line 903  public class RMIC Line 1593  public class RMIC
1593      return (except);      return (except);
1594    }    }
1595    
1596  /**    /**
1597   * Process the options until we find the first argument.     * Process the options until we find the first argument.
1598   */     */
1599    private void parseOptions()    private void parseOptions()
1600    {    {
1601      for (;;)      for (;;)
# Line 952  public class RMIC Line 1642  public class RMIC
1642          else if (arg.equals("-nocompile"))          else if (arg.equals("-nocompile"))
1643            compile = false;            compile = false;
1644          else if (arg.equals("-classpath"))          else if (arg.equals("-classpath"))
1645            next++;            {
1646                classpath = args[next];
1647                next++;
1648                StringTokenizer st =
1649                  new StringTokenizer(classpath, File.pathSeparator);
1650                URL[] u = new URL[st.countTokens()];
1651                for (int i = 0; i < u.length; i++)
1652                  {
1653                    String path = st.nextToken();
1654                    File f = new File(path);
1655                    try
1656                      {
1657                        u[i] = f.toURL();
1658                      }
1659                    catch (java.net.MalformedURLException mue)
1660                      {
1661                        error("malformed classpath component " + path);
1662                      }
1663                  }
1664                loader = new URLClassLoader(u);
1665              }
1666          else if (arg.equals("-help"))          else if (arg.equals("-help"))
1667            usage();            usage();
1668          else if (arg.equals("-version"))          else if (arg.equals("-version"))
# Line 978  public class RMIC Line 1688  public class RMIC
1688        }        }
1689    }    }
1690    
1691  /**    private void findRemoteMethods() {
1692   * Looks for the java.rmi.Remote interface that that is implemented by theClazz.      List rmeths = new ArrayList();
1693   * @param theClazz the class to look in      for (Class cur = clazz; cur != null; cur = cur.getSuperclass())
1694   * @return the Remote interface of theClazz or null if theClazz does not implement a Remote interface        {
1695   */          Class[] interfaces = cur.getInterfaces();
1696    private Class getRemoteInterface(Class theClazz)          for (int i = 0; i < interfaces.length; i++)
1697    {            {
1698      Class[] interfaces = theClazz.getInterfaces();              if (java.rmi.Remote.class.isAssignableFrom(interfaces[i]))
1699      for (int i = 0; i < interfaces.length; i++)                {
1700        {                  Class remoteInterface = interfaces[i];
1701          if (java.rmi.Remote.class.isAssignableFrom(interfaces[i]))                  if (verbose)
1702            return interfaces[i];                    System.out.println
1703        }                      ("[implements " + remoteInterface.getName() + "]");
1704      logError("Class " + theClazz.getName()  
1705               + " is not a remote object. It does not implement an interface that is a java.rmi.Remote-interface.");                  // check if the methods declare RemoteExceptions
1706      return null;                  Method[] meths = remoteInterface.getMethods();
1707    }                  for (int j = 0; j < meths.length; j++)
1708                      {
1709  /**                      Method m = meths[j];
1710   * Prints an error to System.err and increases the error count.                      Class[] exs = m.getExceptionTypes();
1711   * @param theError  
1712   */                      boolean throwsRemote = false;
1713                        for (int k = 0; k < exs.length; k++)
1714                          {
1715                            if (exs[k].isAssignableFrom(RemoteException.class))
1716                              throwsRemote = true;
1717                          }
1718    
1719                        if (! throwsRemote)
1720                          {
1721                            logError("Method " + m
1722                                     + " does not throw a RemoteException");
1723                            continue;
1724                          }
1725    
1726                        rmeths.add(m);
1727                      }
1728    
1729                    mRemoteInterfaces.add(remoteInterface);
1730                  }
1731              }
1732          }
1733    
1734        // intersect exceptions for doubly inherited methods
1735        boolean[] skip = new boolean[rmeths.size()];
1736        for (int i = 0; i < skip.length; i++)
1737          skip[i] = false;
1738        List methrefs = new ArrayList();
1739        for (int i = 0; i < rmeths.size(); i++)
1740          {
1741            if (skip[i]) continue;
1742            Method current = (Method) rmeths.get(i);
1743            MethodRef ref = new MethodRef(current);
1744            for (int j = i+1; j < rmeths.size(); j++)
1745              {
1746                Method other = (Method) rmeths.get(j);
1747                if (ref.isMatch(other))
1748                  {
1749                    ref.intersectExceptions(other);
1750                    skip[j] = true;
1751                  }
1752              }
1753            methrefs.add(ref);
1754          }
1755    
1756        // Convert into a MethodRef array and sort them
1757        remotemethods = (MethodRef[])
1758          methrefs.toArray(new MethodRef[methrefs.size()]);
1759        Arrays.sort(remotemethods);
1760      }
1761    
1762      /**
1763       * Prints an error to System.err and increases the error count.
1764       * @param theError
1765       */
1766    private void logError(String theError)    private void logError(String theError)
1767    {    {
1768      errorCount++;      errorCount++;
# Line 1016  public class RMIC Line 1779  public class RMIC
1779    private static void usage()    private static void usage()
1780    {    {
1781      System.out.println("Usage: rmic [OPTION]... CLASS...\n" + "\n"      System.out.println("Usage: rmic [OPTION]... CLASS...\n" + "\n"
1782                         + "      -keep                   Don't delete any intermediate files\n"                         + "      -keep *                 Don't delete any intermediate files\n"
1783                         + "      -keepgenerated          Same as -keep\n"                         + "      -keepgenerated *        Same as -keep\n"
1784                         + "      -v1.1                   Java 1.1 style stubs only\n"                         + "      -v1.1                   Java 1.1 style stubs only\n"
1785                         + "      -vcompat                Java 1.1 & Java 1.2 stubs\n"                         + "      -vcompat                Java 1.1 & Java 1.2 stubs\n"
1786                         + "      -v1.2                   Java 1.2 style stubs only\n"                         + "      -v1.2                   Java 1.2 style stubs only\n"
1787                         + "      -g *                    Generated debugging information\n"                         + "      -g *                    Generated debugging information\n"
1788                         + "      -depend *               Recompile out-of-date files\n"                         + "      -depend *               Recompile out-of-date files\n"
1789                         + "      -nowarn *               Suppress warning messages\n"                         + "      -nowarn *               Suppress warning messages\n"
1790                         + "      -nocompile              Don't compile the generated files\n"                         + "      -nocompile *            Don't compile the generated files\n"
1791                         + "      -verbose                Output what's going on\n"                         + "      -verbose                Output what's going on\n"
1792                         + "      -classpath <path> *     Use given path as classpath\n"                         + "      -classpath <path>       Use given path as classpath\n"
1793                         + "      -d <directory>          Specify where to place generated classes\n"                         + "      -d <directory>          Specify where to place generated classes\n"
1794                         + "      -J<flag> *              Pass flag to Java\n"                         + "      -J<flag> *              Pass flag to Java\n"
1795                         + "      -help                   Print this help, then exit\n"                         + "      -help                   Print this help, then exit\n"
# Line 1036  public class RMIC Line 1799  public class RMIC
1799      System.exit(0);      System.exit(0);
1800    }    }
1801    
1802    static class MethodRef    private static String getPrettyName(Class cls)
1803      {
1804        StringBuffer str = new StringBuffer();
1805        for (int count = 0;; count++)
1806          {
1807            if (! cls.isArray())
1808              {
1809                str.append(cls.getName());
1810                for (; count > 0; count--)
1811                  str.append("[]");
1812                return (str.toString());
1813              }
1814            cls = cls.getComponentType();
1815          }
1816      }
1817    
1818      private static class MethodRef
1819      implements Comparable      implements Comparable
1820    {    {
1821      Method meth;      Method meth;
     String sig;  
1822      long hash;      long hash;
1823        List exceptions;
1824        private String sig;
1825    
1826      MethodRef(Method m)      MethodRef(Method m) {
     {  
1827        meth = m;        meth = m;
1828        // We match on the name - but what about overloading? - XXX        sig = Type.getMethodDescriptor(meth);
       sig = m.getName();  
1829        hash = RMIHashes.getMethodHash(m);        hash = RMIHashes.getMethodHash(m);
1830          // add exceptions removing subclasses
1831          exceptions = removeSubclasses(m.getExceptionTypes());
1832      }      }
1833    
1834      public int compareTo(Object obj)      public int compareTo(Object obj) {
     {  
1835        MethodRef that = (MethodRef) obj;        MethodRef that = (MethodRef) obj;
1836        return (this.sig.compareTo(that.sig));        int name = this.meth.getName().compareTo(that.meth.getName());
1837          if (name == 0) {
1838            return this.sig.compareTo(that.sig);
1839          }
1840          return name;
1841        }
1842    
1843        public boolean isMatch(Method m)
1844        {
1845          if (!meth.getName().equals(m.getName()))
1846            return false;
1847    
1848          Class[] params1 = meth.getParameterTypes();
1849          Class[] params2 = m.getParameterTypes();
1850          if (params1.length != params2.length)
1851            return false;
1852    
1853          for (int i = 0; i < params1.length; i++)
1854            if (!params1[i].equals(params2[i])) return false;
1855    
1856          return true;
1857        }
1858    
1859        private static List removeSubclasses(Class[] classes)
1860        {
1861          List list = new ArrayList();
1862          for (int i = 0; i < classes.length; i++)
1863            {
1864              Class candidate = classes[i];
1865              boolean add = true;
1866              for (int j = 0; j < classes.length; j++)
1867                {
1868                  if (classes[j].equals(candidate))
1869                    continue;
1870                  else if (classes[j].isAssignableFrom(candidate))
1871                    add = false;
1872                }
1873              if (add) list.add(candidate);
1874            }
1875    
1876          return list;
1877        }
1878    
1879        public void intersectExceptions(Method m)
1880        {
1881          List incoming = removeSubclasses(m.getExceptionTypes());
1882    
1883          List updated = new ArrayList();
1884    
1885          for (int i = 0; i < exceptions.size(); i++)
1886            {
1887              Class outer = (Class) exceptions.get(i);
1888              boolean addOuter = false;
1889              for (int j = 0; j < incoming.size(); j++)
1890                {
1891                  Class inner = (Class) incoming.get(j);
1892    
1893                  if (inner.equals(outer) || inner.isAssignableFrom(outer))
1894                    addOuter = true;
1895                  else if (outer.isAssignableFrom(inner))
1896                    updated.add(inner);
1897                }
1898    
1899              if (addOuter)
1900                updated.add(outer);
1901            }
1902    
1903          exceptions = updated;
1904      }      }
1905    }    }
1906  }  }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.2

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26