OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [tools/] [gnu/] [classpath/] [tools/] [rmic/] [ClassRmicCompiler.java] - Blame information for rev 779

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.