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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [java/] [lang/] [reflect/] [Proxy.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* Proxy.java -- build a proxy class that implements reflected interfaces
2
   Copyright (C) 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package java.lang.reflect;
40
 
41
import gnu.java.lang.reflect.TypeSignature;
42
 
43
import java.io.Serializable;
44
import java.security.ProtectionDomain;
45
import java.util.HashMap;
46
import java.util.HashSet;
47
import java.util.Iterator;
48
import java.util.Map;
49
import java.util.Set;
50
 
51
/**
52
 * This class allows you to dynamically create an instance of any (or
53
 * even multiple) interfaces by reflection, and decide at runtime
54
 * how that instance will behave by giving it an appropriate
55
 * {@link InvocationHandler}.  Proxy classes serialize specially, so
56
 * that the proxy object can be reused between VMs, without requiring
57
 * a persistent copy of the generated class code.
58
 *
59
 * <h3>Creation</h3>
60
 * To create a proxy for some interface Foo:
61
 *
62
 * <pre>
63
 *   InvocationHandler handler = new MyInvocationHandler(...);
64
 *   Class proxyClass = Proxy.getProxyClass(
65
 *       Foo.class.getClassLoader(), new Class[] { Foo.class });
66
 *   Foo f = (Foo) proxyClass
67
 *       .getConstructor(new Class[] { InvocationHandler.class })
68
 *       .newInstance(new Object[] { handler });
69
 * </pre>
70
 * or more simply:
71
 * <pre>
72
 *   Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
73
 *                                        new Class[] { Foo.class },
74
 *                                        handler);
75
 * </pre>
76
 *
77
 * <h3>Dynamic Proxy Classes</h3>
78
 * A dynamic proxy class is created at runtime, and has the following
79
 * properties:
80
 * <ul>
81
 *  <li>The class is <code>public</code> and <code>final</code>,
82
 *      and is neither <code>abstract</code> nor an inner class.</li>
83
 *  <li>The class has no canonical name (there is no formula you can use
84
 *      to determine or generate its name), but begins with the
85
 *      sequence "$Proxy".  Abuse this knowledge at your own peril.
86
 *      (For now, '$' in user identifiers is legal, but it may not
87
 *      be that way forever. You weren't using '$' in your
88
 *      identifiers, were you?)</li>
89
 *  <li>The class extends Proxy, and explicitly implements all the
90
 *      interfaces specified at creation, in order (this is important
91
 *      for determining how method invocation is resolved).  Note that
92
 *      a proxy class implements {@link Serializable}, at least
93
 *      implicitly, since Proxy does, but true serial behavior
94
 *      depends on using a serializable invocation handler as well.</li>
95
 *  <li>If at least one interface is non-public, the proxy class
96
 *      will be in the same package.  Otherwise, the package is
97
 *      unspecified.  This will work even if the package is sealed
98
 *      from user-generated classes, because Proxy classes are
99
 *      generated by a trusted source.  Meanwhile, the proxy class
100
 *      belongs to the classloader you designated.</li>
101
 *  <li>Reflection works as expected: {@link Class#getInterfaces()} and
102
 *      {@link Class#getMethods()} work as they do on normal classes.</li>
103
 *  <li>The method {@link #isProxyClass(Class)} will distinguish between
104
 *      true proxy classes and user extensions of this class.  It only
105
 *      returns true for classes created by {@link #getProxyClass}.</li>
106
 *  <li>The {@link ProtectionDomain} of a proxy class is the same as for
107
 *      bootstrap classes, such as Object or Proxy, since it is created by
108
 *      a trusted source.  This protection domain will typically be granted
109
 *      {@link java.security.AllPermission}. But this is not a security
110
 *      risk, since there are adequate permissions on reflection, which is
111
 *      the only way to create an instance of the proxy class.</li>
112
 *  <li>The proxy class contains a single constructor, which takes as
113
 *      its only argument an {@link InvocationHandler}.  The method
114
 *      {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)}
115
 *      is shorthand to do the necessary reflection.</li>
116
 * </ul>
117
 *
118
 * <h3>Proxy Instances</h3>
119
 * A proxy instance is an instance of a proxy class.  It has the
120
 * following properties, many of which follow from the properties of a
121
 * proxy class listed above:
122
 * <ul>
123
 *  <li>For a proxy class with Foo listed as one of its interfaces, the
124
 *      expression <code>proxy instanceof Foo</code> will return true,
125
 *      and the expression <code>(Foo) proxy</code> will succeed without
126
 *      a {@link ClassCastException}.</li>
127
 *  <li>Each proxy instance has an invocation handler, which can be
128
 *      accessed by {@link #getInvocationHandler(Object)}.  Any call
129
 *      to an interface method, including {@link Object#hashCode()},
130
 *      {@link Object#equals(Object)}, or {@link Object#toString()},
131
 *      but excluding the public final methods of Object, will be
132
 *      encoded and passed to the {@link InvocationHandler#invoke}
133
 *      method of this handler.</li>
134
 * </ul>
135
 *
136
 * <h3>Inheritance Issues</h3>
137
 * A proxy class may inherit a method from more than one interface.
138
 * The order in which interfaces are listed matters, because it determines
139
 * which reflected {@link Method} object will be passed to the invocation
140
 * handler.  This means that the dynamically generated class cannot
141
 * determine through which interface a method is being invoked.<p>
142
 *
143
 * In short, if a method is declared in Object (namely, hashCode,
144
 * equals, or toString), then Object will be used; otherwise, the
145
 * leftmost interface that inherits or declares a method will be used,
146
 * even if it has a more permissive throws clause than what the proxy
147
 * class is allowed. Thus, in the invocation handler, it is not always
148
 * safe to assume that every class listed in the throws clause of the
149
 * passed Method object can safely be thrown; fortunately, the Proxy
150
 * instance is robust enough to wrap all illegal checked exceptions in
151
 * {@link UndeclaredThrowableException}.
152
 *
153
 * @see InvocationHandler
154
 * @see UndeclaredThrowableException
155
 * @see Class
156
 * @author Eric Blake (ebb9@email.byu.edu)
157
 * @since 1.3
158
 * @status updated to 1.4, except for the use of ProtectionDomain
159
 */
160
public class Proxy implements Serializable
161
{
162
  /**
163
   * Compatible with JDK 1.3+.
164
   */
165
  private static final long serialVersionUID = -2222568056686623797L;
166
 
167
  /**
168
   * Map of ProxyType to proxy class.
169
   *
170
   * @XXX This prevents proxy classes from being garbage collected.
171
   * java.util.WeakHashSet is not appropriate, because that collects the
172
   * keys, but we are interested in collecting the elements.
173
   */
174
  private static final Map proxyClasses = new HashMap();
175
 
176
  /**
177
   * The invocation handler for this proxy instance.  For Proxy, this
178
   * field is unused, but it appears here in order to be serialized in all
179
   * proxy classes.
180
   *
181
   * <em>NOTE</em>: This implementation is more secure for proxy classes
182
   * than what Sun specifies. Sun does not require h to be immutable, but
183
   * this means you could change h after the fact by reflection.  However,
184
   * by making h immutable, we may break non-proxy classes which extend
185
   * Proxy.
186
   * @serial invocation handler associated with this proxy instance
187
   */
188
  protected InvocationHandler h;
189
 
190
  /**
191
   * Constructs a new Proxy from a subclass (usually a proxy class),
192
   * with the specified invocation handler.
193
   *
194
   * <em>NOTE</em>: This throws a NullPointerException if you attempt
195
   * to create a proxy instance with a null handler using reflection.
196
   * This behavior is not yet specified by Sun; see Sun Bug 4487672.
197
   *
198
   * @param handler the invocation handler, may be null if the subclass
199
   *        is not a proxy class
200
   * @throws NullPointerException if handler is null and this is a proxy
201
   *         instance
202
   */
203
  protected Proxy(InvocationHandler handler)
204
  {
205
    if (handler == null && isProxyClass(getClass()))
206
      throw new NullPointerException("invalid handler");
207
    h = handler;
208
  }
209
 
210
  /**
211
   * Returns the proxy {@link Class} for the given ClassLoader and array
212
   * of interfaces, dynamically generating it if necessary.
213
   *
214
   * <p>There are several restrictions on this method, the violation of
215
   * which will result in an IllegalArgumentException or
216
   * NullPointerException:</p>
217
   *
218
   * <ul>
219
   * <li>All objects in `interfaces' must represent distinct interfaces.
220
   *     Classes, primitive types, null, and duplicates are forbidden.</li>
221
   * <li>The interfaces must be visible in the specified ClassLoader.
222
   *     In other words, for each interface i:
223
   *     <code>Class.forName(i.getName(), false, loader) == i</code>
224
   *     must be true.</li>
225
   * <li>All non-public interfaces (if any) must reside in the same
226
   *     package, or the proxy class would be non-instantiable.  If
227
   *     there are no non-public interfaces, the package of the proxy
228
   *     class is unspecified.</li>
229
   * <li>All interfaces must be compatible - if two declare a method
230
   *     with the same name and parameters, the return type must be
231
   *     the same and the throws clause of the proxy class will be
232
   *     the maximal subset of subclasses of the throws clauses for
233
   *     each method that is overridden.</li>
234
   * <li>VM constraints limit the number of interfaces a proxy class
235
   *     may directly implement (however, the indirect inheritance
236
   *     of {@link Serializable} does not count against this limit).
237
   *     Even though most VMs can theoretically have 65535
238
   *     superinterfaces for a class, the actual limit is smaller
239
   *     because a class's constant pool is limited to 65535 entries,
240
   *     and not all entries can be interfaces.</li>
241
   * </ul>
242
   *
243
   * <p>Note that different orders of interfaces produce distinct classes.</p>
244
   *
245
   * @param loader the class loader to define the proxy class in; null
246
   *        implies the bootstrap class loader
247
   * @param interfaces the array of interfaces the proxy class implements,
248
   *        may be empty, but not null
249
   * @return the Class object of the proxy class
250
   * @throws IllegalArgumentException if the constraints above were
251
   *         violated, except for problems with null
252
   * @throws NullPointerException if `interfaces' is null or contains
253
   *         a null entry
254
   */
255
  // synchronized so that we aren't trying to build the same class
256
  // simultaneously in two threads
257
  public static synchronized Class getProxyClass(ClassLoader loader,
258
                                                 Class[] interfaces)
259
  {
260
    interfaces = (Class[]) interfaces.clone();
261
    ProxyType pt = new ProxyType(loader, interfaces);
262
    Class clazz = (Class) proxyClasses.get(pt);
263
    if (clazz == null)
264
      {
265
        if (VMProxy.HAVE_NATIVE_GET_PROXY_CLASS)
266
          clazz = VMProxy.getProxyClass(loader, interfaces);
267
        else
268
          {
269
            ProxyData data = (VMProxy.HAVE_NATIVE_GET_PROXY_DATA
270
                              ? VMProxy.getProxyData(loader, interfaces)
271
                              : ProxyData.getProxyData(pt));
272
 
273
            clazz = (VMProxy.HAVE_NATIVE_GENERATE_PROXY_CLASS
274
                     ? VMProxy.generateProxyClass(loader, data)
275
                     : new ClassFactory(data).generate(loader));
276
          }
277
 
278
        Object check = proxyClasses.put(pt, clazz);
279
        // assert check == null && clazz != null;
280
        if (check != null || clazz == null)
281
          throw new InternalError(/*"Fatal flaw in getProxyClass"*/);
282
      }
283
    return clazz;
284
  }
285
 
286
  /**
287
   * Combines several methods into one.  This is equivalent to:
288
   * <pre>
289
   *   Proxy.getProxyClass(loader, interfaces)
290
   *       .getConstructor(new Class[] {InvocationHandler.class})
291
   *       .newInstance(new Object[] {handler});
292
   * </pre>
293
   * except that it will not fail with the normal problems caused
294
   * by reflection.  It can still fail for the same reasons documented
295
   * in getProxyClass, or if handler is null.
296
   *
297
   * @param loader the class loader to define the proxy class in; null
298
   *        implies the bootstrap class loader
299
   * @param interfaces the array of interfaces the proxy class implements,
300
   *        may be empty, but not null
301
   * @param handler the invocation handler, may not be null
302
   * @return a proxy instance implementing the specified interfaces
303
   * @throws IllegalArgumentException if the constraints for getProxyClass
304
   *         were violated, except for problems with null
305
   * @throws NullPointerException if `interfaces' is null or contains
306
   *         a null entry, or if handler is null
307
   * @see #getProxyClass(ClassLoader, Class[])
308
   * @see Class#getConstructor(Class[])
309
   * @see Constructor#newInstance(Object[])
310
   */
311
  public static Object newProxyInstance(ClassLoader loader,
312
                                        Class[] interfaces,
313
                                        InvocationHandler handler)
314
  {
315
    try
316
      {
317
        // getProxyClass() and Proxy() throw the necessary exceptions
318
        return getProxyClass(loader, interfaces)
319
          .getConstructor(new Class[] {InvocationHandler.class})
320
          .newInstance(new Object[] {handler});
321
      }
322
    catch (RuntimeException e)
323
      {
324
        // Let IllegalArgumentException, NullPointerException escape.
325
        // assert e instanceof IllegalArgumentException
326
        //   || e instanceof NullPointerException;
327
        throw e;
328
      }
329
    catch (InvocationTargetException e)
330
      {
331
        // Let wrapped NullPointerException escape.
332
        // assert e.getTargetException() instanceof NullPointerException
333
        throw (NullPointerException) e.getCause();
334
      }
335
    catch (Exception e)
336
      {
337
        // Covers InstantiationException, IllegalAccessException,
338
        // NoSuchMethodException, none of which should be generated
339
        // if the proxy class was generated correctly.
340
        // assert false;
341
        throw (Error) new InternalError("Unexpected: " + e).initCause(e);
342
      }
343
  }
344
 
345
  /**
346
   * Returns true if and only if the Class object is a dynamically created
347
   * proxy class (created by <code>getProxyClass</code> or by the
348
   * syntactic sugar of <code>newProxyInstance</code>).
349
   *
350
   * <p>This check is secure (in other words, it is not simply
351
   * <code>clazz.getSuperclass() == Proxy.class</code>), it will not
352
   * be spoofed by non-proxy classes that extend Proxy.
353
   *
354
   * @param clazz the class to check, must not be null
355
   * @return true if the class represents a proxy class
356
   * @throws NullPointerException if clazz is null
357
   */
358
  // This is synchronized on the off chance that another thread is
359
  // trying to add a class to the map at the same time we read it.
360
  public static synchronized boolean isProxyClass(Class clazz)
361
  {
362
    if (! Proxy.class.isAssignableFrom(clazz))
363
      return false;
364
    // This is a linear search, even though we could do an O(1) search
365
    // using new ProxyType(clazz.getClassLoader(), clazz.getInterfaces()).
366
    return proxyClasses.containsValue(clazz);
367
  }
368
 
369
  /**
370
   * Returns the invocation handler for the given proxy instance.<p>
371
   *
372
   * <em>NOTE</em>: We guarantee a non-null result if successful,
373
   * but Sun allows the creation of a proxy instance with a null
374
   * handler.  See the comments for {@link #Proxy(InvocationHandler)}.
375
   *
376
   * @param proxy the proxy instance, must not be null
377
   * @return the invocation handler, guaranteed non-null.
378
   * @throws IllegalArgumentException if
379
   *         <code>Proxy.isProxyClass(proxy.getClass())</code> returns false.
380
   * @throws NullPointerException if proxy is null
381
   */
382
  public static InvocationHandler getInvocationHandler(Object proxy)
383
  {
384
    if (! isProxyClass(proxy.getClass()))
385
      throw new IllegalArgumentException("not a proxy instance");
386
    return ((Proxy) proxy).h;
387
  }
388
 
389
  /**
390
   * Helper class for mapping unique ClassLoader and interface combinations
391
   * to proxy classes.
392
   *
393
   * @author Eric Blake (ebb9@email.byu.edu)
394
   */
395
  private static final class ProxyType
396
  {
397
    /**
398
     * Store the class loader (may be null)
399
     */
400
    final ClassLoader loader;
401
 
402
    /**
403
     * Store the interfaces (never null, all elements are interfaces)
404
     */
405
    final Class[] interfaces;
406
 
407
    /**
408
     * Construct the helper object.
409
     *
410
     * @param loader the class loader to define the proxy class in; null
411
     *        implies the bootstrap class loader
412
     * @param interfaces an array of interfaces
413
     */
414
    ProxyType(ClassLoader loader, Class[] interfaces)
415
    {
416
      this.loader = loader;
417
      this.interfaces = interfaces;
418
    }
419
 
420
    /**
421
     * Calculates the hash code.
422
     *
423
     * @return a combination of the classloader and interfaces hashcodes.
424
     */
425
    public int hashCode()
426
    {
427
      int hash = loader == null ? 0 : loader.hashCode();
428
      for (int i = 0; i < interfaces.length; i++)
429
        hash = hash * 31 + interfaces[i].hashCode();
430
      return hash;
431
    }
432
 
433
    /**
434
     * Calculates equality.
435
     *
436
     * @param other object to compare to
437
     * @return true if it is a ProxyType with same data
438
     */
439
    public boolean equals(Object other)
440
    {
441
      ProxyType pt = (ProxyType) other;
442
      if (loader != pt.loader || interfaces.length != pt.interfaces.length)
443
        return false;
444
      for (int i = 0; i < interfaces.length; i++)
445
        if (interfaces[i] != pt.interfaces[i])
446
          return false;
447
      return true;
448
    }
449
  } // class ProxyType
450
 
451
  /**
452
   * Helper class which allows hashing of a method name and signature
453
   * without worrying about return type, declaring class, or throws clause,
454
   * and which reduces the maximally common throws clause between two methods
455
   *
456
   * @author Eric Blake (ebb9@email.byu.edu)
457
   */
458
  private static final class ProxySignature
459
  {
460
    /**
461
     * The core signatures which all Proxy instances handle.
462
     */
463
    static final HashMap coreMethods = new HashMap();
464
    static
465
    {
466
      try
467
        {
468
          ProxySignature sig
469
            = new ProxySignature(Object.class
470
                                 .getMethod("equals",
471
                                            new Class[] {Object.class}));
472
          coreMethods.put(sig, sig);
473
          sig = new ProxySignature(Object.class.getMethod("hashCode", null));
474
          coreMethods.put(sig, sig);
475
          sig = new ProxySignature(Object.class.getMethod("toString", null));
476
          coreMethods.put(sig, sig);
477
        }
478
      catch (Exception e)
479
        {
480
          // assert false;
481
          throw (Error) new InternalError("Unexpected: " + e).initCause(e);
482
        }
483
    }
484
 
485
    /**
486
     * The underlying Method object, never null
487
     */
488
    final Method method;
489
 
490
    /**
491
     * The set of compatible thrown exceptions, may be empty
492
     */
493
    final Set exceptions = new HashSet();
494
 
495
    /**
496
     * Construct a signature
497
     *
498
     * @param method the Method this signature is based on, never null
499
     */
500
    ProxySignature(Method method)
501
    {
502
      this.method = method;
503
      Class[] exc = method.getExceptionTypes();
504
      int i = exc.length;
505
      while (--i >= 0)
506
        {
507
          // discard unchecked exceptions
508
          if (Error.class.isAssignableFrom(exc[i])
509
              || RuntimeException.class.isAssignableFrom(exc[i]))
510
            continue;
511
          exceptions.add(exc[i]);
512
        }
513
    }
514
 
515
    /**
516
     * Given a method, make sure it's return type is identical
517
     * to this, and adjust this signature's throws clause appropriately
518
     *
519
     * @param other the signature to merge in
520
     * @throws IllegalArgumentException if the return types conflict
521
     */
522
    void checkCompatibility(ProxySignature other)
523
    {
524
      if (method.getReturnType() != other.method.getReturnType())
525
        throw new IllegalArgumentException("incompatible return types: "
526
                                           + method + ", " + other.method);
527
 
528
      // if you can think of a more efficient way than this O(n^2) search,
529
      // implement it!
530
      int size1 = exceptions.size();
531
      int size2 = other.exceptions.size();
532
      boolean[] valid1 = new boolean[size1];
533
      boolean[] valid2 = new boolean[size2];
534
      Iterator itr = exceptions.iterator();
535
      int pos = size1;
536
      while (--pos >= 0)
537
        {
538
          Class c1 = (Class) itr.next();
539
          Iterator itr2 = other.exceptions.iterator();
540
          int pos2 = size2;
541
          while (--pos2 >= 0)
542
            {
543
              Class c2 = (Class) itr2.next();
544
              if (c2.isAssignableFrom(c1))
545
                valid1[pos] = true;
546
              if (c1.isAssignableFrom(c2))
547
                valid2[pos2] = true;
548
            }
549
        }
550
      pos = size1;
551
      itr = exceptions.iterator();
552
      while (--pos >= 0)
553
        {
554
          itr.next();
555
          if (! valid1[pos])
556
            itr.remove();
557
        }
558
      pos = size2;
559
      itr = other.exceptions.iterator();
560
      while (--pos >= 0)
561
        {
562
          itr.next();
563
          if (! valid2[pos])
564
            itr.remove();
565
        }
566
      exceptions.addAll(other.exceptions);
567
    }
568
 
569
    /**
570
     * Calculates the hash code.
571
     *
572
     * @return a combination of name and parameter types
573
     */
574
    public int hashCode()
575
    {
576
      int hash = method.getName().hashCode();
577
      Class[] types = method.getParameterTypes();
578
      for (int i = 0; i < types.length; i++)
579
        hash = hash * 31 + types[i].hashCode();
580
      return hash;
581
    }
582
 
583
    /**
584
     * Calculates equality.
585
     *
586
     * @param other object to compare to
587
     * @return true if it is a ProxySignature with same data
588
     */
589
    public boolean equals(Object other)
590
    {
591
      ProxySignature ps = (ProxySignature) other;
592
      Class[] types1 = method.getParameterTypes();
593
      Class[] types2 = ps.method.getParameterTypes();
594
      if (! method.getName().equals(ps.method.getName())
595
          || types1.length != types2.length)
596
        return false;
597
      int i = types1.length;
598
      while (--i >= 0)
599
        if (types1[i] != types2[i])
600
          return false;
601
      return true;
602
    }
603
  } // class ProxySignature
604
 
605
  /**
606
   * A flat representation of all data needed to generate bytecode/instantiate
607
   * a proxy class.  This is basically a struct.
608
   *
609
   * @author Eric Blake (ebb9@email.byu.edu)
610
   */
611
  static final class ProxyData
612
  {
613
    /**
614
     * The package this class is in <b>including the trailing dot</b>
615
     * or an empty string for the unnamed (aka default) package.
616
     */
617
    String pack = "";
618
 
619
    /**
620
     * The interfaces this class implements.  Non-null, but possibly empty.
621
     */
622
    Class[] interfaces;
623
 
624
    /**
625
     * The Method objects this class must pass as the second argument to
626
     * invoke (also useful for determining what methods this class has).
627
     * Non-null, non-empty (includes at least Object.hashCode, Object.equals,
628
     * and Object.toString).
629
     */
630
    Method[] methods;
631
 
632
    /**
633
     * The exceptions that do not need to be wrapped in
634
     * UndeclaredThrowableException. exceptions[i] is the same as, or a
635
     * subset of subclasses, of methods[i].getExceptionTypes(), depending on
636
     * compatible throws clauses with multiple inheritance. It is unspecified
637
     * if these lists include or exclude subclasses of Error and
638
     * RuntimeException, but excluding them is harmless and generates a
639
     * smaller class.
640
     */
641
    Class[][] exceptions;
642
 
643
    /**
644
     * For unique id's
645
     */
646
    private static int count;
647
 
648
    /**
649
     * The id of this proxy class
650
     */
651
    final int id = count++;
652
 
653
    /**
654
     * Construct a ProxyData with uninitialized data members.
655
     */
656
    ProxyData()
657
    {
658
    }
659
 
660
    /**
661
     * Return the name of a package (including the trailing dot)
662
     * given the name of a class.
663
     * Returns an empty string if no package.  We use this in preference to
664
     * using Class.getPackage() to avoid problems with ClassLoaders
665
     * that don't set the package.
666
     */
667
    private static String getPackage(Class k)
668
    {
669
      String name = k.getName();
670
      int idx = name.lastIndexOf('.');
671
      return name.substring(0, idx + 1);
672
    }
673
 
674
    /**
675
     * Verifies that the arguments are legal, and sets up remaining data
676
     * This should only be called when a class must be generated, as
677
     * it is expensive.
678
     *
679
     * @param pt the ProxyType to convert to ProxyData
680
     * @return the flattened, verified ProxyData structure for use in
681
     *         class generation
682
     * @throws IllegalArgumentException if `interfaces' contains
683
     *         non-interfaces or incompatible combinations, and verify is true
684
     * @throws NullPointerException if interfaces is null or contains null
685
     */
686
    static ProxyData getProxyData(ProxyType pt)
687
    {
688
      Map method_set = (Map) ProxySignature.coreMethods.clone();
689
      boolean in_package = false; // true if we encounter non-public interface
690
 
691
      ProxyData data = new ProxyData();
692
      data.interfaces = pt.interfaces;
693
 
694
      // if interfaces is too large, we croak later on when the constant
695
      // pool overflows
696
      int i = data.interfaces.length;
697
      while (--i >= 0)
698
        {
699
          Class inter = data.interfaces[i];
700
          if (! inter.isInterface())
701
            throw new IllegalArgumentException("not an interface: " + inter);
702
          try
703
            {
704
              if (Class.forName(inter.getName(), false, pt.loader) != inter)
705
                throw new IllegalArgumentException("not accessible in "
706
                                                   + "classloader: " + inter);
707
            }
708
          catch (ClassNotFoundException e)
709
            {
710
              throw new IllegalArgumentException("not accessible in "
711
                                                 + "classloader: " + inter);
712
            }
713
          if (! Modifier.isPublic(inter.getModifiers()))
714
            if (in_package)
715
              {
716
                String p = getPackage(inter);
717
                if (! data.pack.equals(p))
718
                  throw new IllegalArgumentException("non-public interfaces "
719
                                                     + "from different "
720
                                                     + "packages");
721
              }
722
            else
723
              {
724
                in_package = true;
725
                data.pack = getPackage(inter);
726
              }
727
          for (int j = i-1; j >= 0; j--)
728
            if (data.interfaces[j] == inter)
729
              throw new IllegalArgumentException("duplicate interface: "
730
                                                 + inter);
731
          Method[] methods = inter.getMethods();
732
          int j = methods.length;
733
          while (--j >= 0)
734
            {
735
              ProxySignature sig = new ProxySignature(methods[j]);
736
              ProxySignature old = (ProxySignature) method_set.put(sig, sig);
737
              if (old != null)
738
                sig.checkCompatibility(old);
739
            }
740
        }
741
 
742
      i = method_set.size();
743
      data.methods = new Method[i];
744
      data.exceptions = new Class[i][];
745
      Iterator itr = method_set.values().iterator();
746
      while (--i >= 0)
747
        {
748
          ProxySignature sig = (ProxySignature) itr.next();
749
          data.methods[i] = sig.method;
750
          data.exceptions[i] = (Class[]) sig.exceptions
751
            .toArray(new Class[sig.exceptions.size()]);
752
        }
753
      return data;
754
    }
755
  } // class ProxyData
756
 
757
  /**
758
   * Does all the work of building a class. By making this a nested class,
759
   * this code is not loaded in memory if the VM has a native
760
   * implementation instead.
761
   *
762
   * @author Eric Blake (ebb9@email.byu.edu)
763
   */
764
  private static final class ClassFactory
765
  {
766
    /** Constants for assisting the compilation */
767
    private static final byte FIELD = 1;
768
    private static final byte METHOD = 2;
769
    private static final byte INTERFACE = 3;
770
    private static final String CTOR_SIG
771
      = "(Ljava/lang/reflect/InvocationHandler;)V";
772
    private static final String INVOKE_SIG = "(Ljava/lang/Object;"
773
      + "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;";
774
 
775
    /** Bytecodes for insertion in the class definition byte[] */
776
    private static final char ACONST_NULL = 1;
777
    private static final char ICONST_0 = 3;
778
    private static final char BIPUSH = 16;
779
    private static final char SIPUSH = 17;
780
    private static final char ILOAD = 21;
781
    private static final char ILOAD_0 = 26;
782
    private static final char ALOAD_0 = 42;
783
    private static final char ALOAD_1 = 43;
784
    private static final char AALOAD = 50;
785
    private static final char AASTORE = 83;
786
    private static final char DUP = 89;
787
    private static final char DUP_X1 = 90;
788
    private static final char SWAP = 95;
789
    private static final char IRETURN = 172;
790
    private static final char LRETURN = 173;
791
    private static final char FRETURN = 174;
792
    private static final char DRETURN = 175;
793
    private static final char ARETURN = 176;
794
    private static final char RETURN = 177;
795
    private static final char GETSTATIC = 178;
796
    private static final char GETFIELD = 180;
797
    private static final char INVOKEVIRTUAL = 182;
798
    private static final char INVOKESPECIAL = 183;
799
    private static final char INVOKEINTERFACE = 185;
800
    private static final char NEW = 187;
801
    private static final char ANEWARRAY = 189;
802
    private static final char ATHROW = 191;
803
    private static final char CHECKCAST = 192;
804
 
805
    // Implementation note: we use StringBuffers to hold the byte data, since
806
    // they automatically grow.  However, we only use the low 8 bits of
807
    // every char in the array, so we are using twice the necessary memory
808
    // for the ease StringBuffer provides.
809
 
810
    /** The constant pool. */
811
    private final StringBuffer pool = new StringBuffer();
812
    /** The rest of the class data. */
813
    private final StringBuffer stream = new StringBuffer();
814
 
815
    /** Map of strings to byte sequences, to minimize size of pool. */
816
    private final Map poolEntries = new HashMap();
817
 
818
    /** The VM name of this proxy class. */
819
    private final String qualName;
820
 
821
    /**
822
     * The Method objects the proxy class refers to when calling the
823
     * invocation handler.
824
     */
825
    private final Method[] methods;
826
 
827
    /**
828
     * Initializes the buffers with the bytecode contents for a proxy class.
829
     *
830
     * @param data the remainder of the class data
831
     * @throws IllegalArgumentException if anything else goes wrong this
832
     *         late in the game; as far as I can tell, this will only happen
833
     *         if the constant pool overflows, which is possible even when
834
     *         the user doesn't exceed the 65535 interface limit
835
     */
836
    ClassFactory(ProxyData data)
837
    {
838
      methods = data.methods;
839
 
840
      // magic = 0xcafebabe
841
      // minor_version = 0
842
      // major_version = 46
843
      // constant_pool_count: place-holder for now
844
      pool.append("\u00ca\u00fe\u00ba\u00be\0\0\0\56\0\0");
845
      // constant_pool[], filled in as we go
846
 
847
      // access_flags
848
      putU2(Modifier.SUPER | Modifier.FINAL | Modifier.PUBLIC);
849
      // this_class
850
      qualName = (data.pack + "$Proxy" + data.id);
851
      putU2(classInfo(TypeSignature.getEncodingOfClass(qualName, false)));
852
      // super_class
853
      putU2(classInfo("java/lang/reflect/Proxy"));
854
 
855
      // interfaces_count
856
      putU2(data.interfaces.length);
857
      // interfaces[]
858
      for (int i = 0; i < data.interfaces.length; i++)
859
        putU2(classInfo(data.interfaces[i]));
860
 
861
      // Recall that Proxy classes serialize specially, so we do not need
862
      // to worry about a <clinit> method for this field.  Instead, we
863
      // just assign it by reflection after the class is successfully loaded.
864
      // fields_count - private static Method[] m;
865
      putU2(1);
866
      // fields[]
867
      // m.access_flags
868
      putU2(Modifier.PRIVATE | Modifier.STATIC);
869
      // m.name_index
870
      putU2(utf8Info("m"));
871
      // m.descriptor_index
872
      putU2(utf8Info("[Ljava/lang/reflect/Method;"));
873
      // m.attributes_count
874
      putU2(0);
875
      // m.attributes[]
876
 
877
      // methods_count - # handler methods, plus <init>
878
      putU2(methods.length + 1);
879
      // methods[]
880
      // <init>.access_flags
881
      putU2(Modifier.PUBLIC);
882
      // <init>.name_index
883
      putU2(utf8Info("<init>"));
884
      // <init>.descriptor_index
885
      putU2(utf8Info(CTOR_SIG));
886
      // <init>.attributes_count - only Code is needed
887
      putU2(1);
888
      // <init>.Code.attribute_name_index
889
      putU2(utf8Info("Code"));
890
      // <init>.Code.attribute_length = 18
891
      // <init>.Code.info:
892
      //   $Proxynn(InvocationHandler h) { super(h); }
893
      // <init>.Code.max_stack = 2
894
      // <init>.Code.max_locals = 2
895
      // <init>.Code.code_length = 6
896
      // <init>.Code.code[]
897
      stream.append("\0\0\0\22\0\2\0\2\0\0\0\6" + ALOAD_0 + ALOAD_1
898
                    + INVOKESPECIAL);
899
      putU2(refInfo(METHOD, "java/lang/reflect/Proxy", "<init>", CTOR_SIG));
900
      // <init>.Code.exception_table_length = 0
901
      // <init>.Code.exception_table[]
902
      // <init>.Code.attributes_count = 0
903
      // <init>.Code.attributes[]
904
      stream.append(RETURN + "\0\0\0\0");
905
 
906
      for (int i = methods.length - 1; i >= 0; i--)
907
        emitMethod(i, data.exceptions[i]);
908
 
909
      // attributes_count
910
      putU2(0);
911
      // attributes[] - empty; omit SourceFile attribute
912
      // XXX should we mark this with a Synthetic attribute?
913
    }
914
 
915
    /**
916
     * Produce the bytecode for a single method.
917
     *
918
     * @param i the index of the method we are building
919
     * @param e the exceptions possible for the method
920
     */
921
    private void emitMethod(int i, Class[] e)
922
    {
923
      // First, we precalculate the method length and other information.
924
 
925
      Method m = methods[i];
926
      Class[] paramtypes = m.getParameterTypes();
927
      int wrap_overhead = 0; // max words taken by wrapped primitive
928
      int param_count = 1; // 1 for this
929
      int code_length = 16; // aload_0, getfield, aload_0, getstatic, const,
930
      // aaload, const/aconst_null, invokeinterface
931
      if (i > 5)
932
        {
933
          if (i > Byte.MAX_VALUE)
934
            code_length += 2; // sipush
935
          else
936
            code_length++; // bipush
937
        }
938
      if (paramtypes.length > 0)
939
        {
940
          code_length += 3; // anewarray
941
          if (paramtypes.length > Byte.MAX_VALUE)
942
            code_length += 2; // sipush
943
          else if (paramtypes.length > 5)
944
            code_length++; // bipush
945
          for (int j = 0; j < paramtypes.length; j++)
946
            {
947
              code_length += 4; // dup, const, load, store
948
              Class type = paramtypes[j];
949
              if (j > 5)
950
                {
951
                  if (j > Byte.MAX_VALUE)
952
                    code_length += 2; // sipush
953
                  else
954
                    code_length++; // bipush
955
                }
956
              if (param_count >= 4)
957
                code_length++; // 2-byte load
958
              param_count++;
959
              if (type.isPrimitive())
960
                {
961
                  code_length += 7; // new, dup, invokespecial
962
                  if (type == long.class || type == double.class)
963
                    {
964
                      wrap_overhead = 3;
965
                      param_count++;
966
                    }
967
                  else if (wrap_overhead < 2)
968
                    wrap_overhead = 2;
969
                }
970
            }
971
        }
972
      int end_pc = code_length;
973
      Class ret_type = m.getReturnType();
974
      if (ret_type == void.class)
975
        code_length++; // return
976
      else if (ret_type.isPrimitive())
977
        code_length += 7; // cast, invokevirtual, return
978
      else
979
        code_length += 4; // cast, return
980
      int exception_count = 0;
981
      boolean throws_throwable = false;
982
      for (int j = 0; j < e.length; j++)
983
        if (e[j] == Throwable.class)
984
          {
985
            throws_throwable = true;
986
            break;
987
          }
988
      if (! throws_throwable)
989
        {
990
          exception_count = e.length + 3; // Throwable, Error, RuntimeException
991
          code_length += 9; // new, dup_x1, swap, invokespecial, athrow
992
        }
993
      int handler_pc = code_length - 1;
994
      StringBuffer signature = new StringBuffer("(");
995
      for (int j = 0; j < paramtypes.length; j++)
996
        signature.append(TypeSignature.getEncodingOfClass(paramtypes[j]));
997
      signature.append(")").append(TypeSignature.getEncodingOfClass(ret_type));
998
 
999
      // Now we have enough information to emit the method.
1000
 
1001
      // handler.access_flags
1002
      putU2(Modifier.PUBLIC | Modifier.FINAL);
1003
      // handler.name_index
1004
      putU2(utf8Info(m.getName()));
1005
      // handler.descriptor_index
1006
      putU2(utf8Info(signature.toString()));
1007
      // handler.attributes_count - Code is necessary, Exceptions possible
1008
      putU2(e.length > 0 ? 2 : 1);
1009
 
1010
      // handler.Code.info:
1011
      //   type name(args) {
1012
      //     try {
1013
      //       return (type) h.invoke(this, methods[i], new Object[] {args});
1014
      //     } catch (<declared Exceptions> e) {
1015
      //       throw e;
1016
      //     } catch (Throwable t) {
1017
      //       throw new UndeclaredThrowableException(t);
1018
      //     }
1019
      //   }
1020
      // Special cases:
1021
      //  if arg_n is primitive, wrap it
1022
      //  if method throws Throwable, try-catch is not needed
1023
      //  if method returns void, return statement not needed
1024
      //  if method returns primitive, unwrap it
1025
      //  save space by sharing code for all the declared handlers
1026
 
1027
      // handler.Code.attribute_name_index
1028
      putU2(utf8Info("Code"));
1029
      // handler.Code.attribute_length
1030
      putU4(12 + code_length + 8 * exception_count);
1031
      // handler.Code.max_stack
1032
      putU2(param_count == 1 ? 4 : 7 + wrap_overhead);
1033
      // handler.Code.max_locals
1034
      putU2(param_count);
1035
      // handler.Code.code_length
1036
      putU4(code_length);
1037
      // handler.Code.code[]
1038
      putU1(ALOAD_0);
1039
      putU1(GETFIELD);
1040
      putU2(refInfo(FIELD, "java/lang/reflect/Proxy", "h",
1041
                    "Ljava/lang/reflect/InvocationHandler;"));
1042
      putU1(ALOAD_0);
1043
      putU1(GETSTATIC);
1044
      putU2(refInfo(FIELD, TypeSignature.getEncodingOfClass(qualName, false),
1045
                    "m", "[Ljava/lang/reflect/Method;"));
1046
      putConst(i);
1047
      putU1(AALOAD);
1048
      if (paramtypes.length > 0)
1049
        {
1050
          putConst(paramtypes.length);
1051
          putU1(ANEWARRAY);
1052
          putU2(classInfo("java/lang/Object"));
1053
          param_count = 1;
1054
          for (int j = 0; j < paramtypes.length; j++, param_count++)
1055
            {
1056
              putU1(DUP);
1057
              putConst(j);
1058
              if (paramtypes[j].isPrimitive())
1059
                {
1060
                  putU1(NEW);
1061
                  putU2(classInfo(wrapper(paramtypes[j])));
1062
                  putU1(DUP);
1063
                }
1064
              putLoad(param_count, paramtypes[j]);
1065
              if (paramtypes[j].isPrimitive())
1066
                {
1067
                  putU1(INVOKESPECIAL);
1068
                  putU2(refInfo(METHOD, wrapper(paramtypes[j]), "<init>",
1069
                                '(' + (TypeSignature
1070
                                       .getEncodingOfClass(paramtypes[j])
1071
                                       + ")V")));
1072
                  if (paramtypes[j] == long.class
1073
                      || paramtypes[j] == double.class)
1074
                    param_count++;
1075
                }
1076
              putU1(AASTORE);
1077
            }
1078
        }
1079
      else
1080
        putU1(ACONST_NULL);
1081
      putU1(INVOKEINTERFACE);
1082
      putU2(refInfo(INTERFACE, "java/lang/reflect/InvocationHandler",
1083
                    "invoke", INVOKE_SIG));
1084
      putU1(4); // InvocationHandler, this, Method, Object[]
1085
      putU1(0);
1086
      if (ret_type == void.class)
1087
        putU1(RETURN);
1088
      else if (ret_type.isPrimitive())
1089
        {
1090
          putU1(CHECKCAST);
1091
          putU2(classInfo(wrapper(ret_type)));
1092
          putU1(INVOKEVIRTUAL);
1093
          putU2(refInfo(METHOD, wrapper(ret_type),
1094
                        ret_type.getName() + "Value",
1095
                        "()" + TypeSignature.getEncodingOfClass(ret_type)));
1096
          if (ret_type == long.class)
1097
            putU1(LRETURN);
1098
          else if (ret_type == float.class)
1099
            putU1(FRETURN);
1100
          else if (ret_type == double.class)
1101
            putU1(DRETURN);
1102
          else
1103
            putU1(IRETURN);
1104
        }
1105
      else
1106
        {
1107
          putU1(CHECKCAST);
1108
          putU2(classInfo(ret_type));
1109
          putU1(ARETURN);
1110
        }
1111
      if (! throws_throwable)
1112
        {
1113
          putU1(NEW);
1114
          putU2(classInfo("java/lang/reflect/UndeclaredThrowableException"));
1115
          putU1(DUP_X1);
1116
          putU1(SWAP);
1117
          putU1(INVOKESPECIAL);
1118
          putU2(refInfo(METHOD,
1119
                        "java/lang/reflect/UndeclaredThrowableException",
1120
                        "<init>", "(Ljava/lang/Throwable;)V"));
1121
          putU1(ATHROW);
1122
        }
1123
 
1124
      // handler.Code.exception_table_length
1125
      putU2(exception_count);
1126
      // handler.Code.exception_table[]
1127
      if (! throws_throwable)
1128
        {
1129
          // handler.Code.exception_table.start_pc
1130
          putU2(0);
1131
          // handler.Code.exception_table.end_pc
1132
          putU2(end_pc);
1133
          // handler.Code.exception_table.handler_pc
1134
          putU2(handler_pc);
1135
          // handler.Code.exception_table.catch_type
1136
          putU2(classInfo("java/lang/Error"));
1137
          // handler.Code.exception_table.start_pc
1138
          putU2(0);
1139
          // handler.Code.exception_table.end_pc
1140
          putU2(end_pc);
1141
          // handler.Code.exception_table.handler_pc
1142
          putU2(handler_pc);
1143
          // handler.Code.exception_table.catch_type
1144
          putU2(classInfo("java/lang/RuntimeException"));
1145
          for (int j = 0; j < e.length; j++)
1146
            {
1147
              // handler.Code.exception_table.start_pc
1148
              putU2(0);
1149
              // handler.Code.exception_table.end_pc
1150
              putU2(end_pc);
1151
              // handler.Code.exception_table.handler_pc
1152
              putU2(handler_pc);
1153
              // handler.Code.exception_table.catch_type
1154
              putU2(classInfo(e[j]));
1155
            }
1156
          // handler.Code.exception_table.start_pc
1157
          putU2(0);
1158
          // handler.Code.exception_table.end_pc
1159
          putU2(end_pc);
1160
          // handler.Code.exception_table.handler_pc -
1161
          //   -8 for undeclared handler, which falls thru to normal one
1162
          putU2(handler_pc - 8);
1163
          // handler.Code.exception_table.catch_type
1164
          putU2(0);
1165
        }
1166
      // handler.Code.attributes_count
1167
      putU2(0);
1168
      // handler.Code.attributes[]
1169
 
1170
      if (e.length > 0)
1171
        {
1172
          // handler.Exceptions.attribute_name_index
1173
          putU2(utf8Info("Exceptions"));
1174
          // handler.Exceptions.attribute_length
1175
          putU4(2 * e.length + 2);
1176
          // handler.Exceptions.number_of_exceptions
1177
          putU2(e.length);
1178
          // handler.Exceptions.exception_index_table[]
1179
          for (int j = 0; j < e.length; j++)
1180
            putU2(classInfo(e[j]));
1181
        }
1182
    }
1183
 
1184
    /**
1185
     * Creates the Class object that corresponds to the bytecode buffers
1186
     * built when this object was constructed.
1187
     *
1188
     * @param loader the class loader to define the proxy class in; null
1189
     *        implies the bootstrap class loader
1190
     * @return the proxy class Class object
1191
     */
1192
    Class generate(ClassLoader loader)
1193
    {
1194
      byte[] bytecode = new byte[pool.length() + stream.length()];
1195
      // More efficient to bypass calling charAt() repetitively.
1196
      char[] c = pool.toString().toCharArray();
1197
      int i = c.length;
1198
      while (--i >= 0)
1199
        bytecode[i] = (byte) c[i];
1200
      c = stream.toString().toCharArray();
1201
      i = c.length;
1202
      int j = bytecode.length;
1203
      while (i > 0)
1204
        bytecode[--j] = (byte) c[--i];
1205
 
1206
      // Patch the constant pool size, which we left at 0 earlier.
1207
      int count = poolEntries.size() + 1;
1208
      bytecode[8] = (byte) (count >> 8);
1209
      bytecode[9] = (byte) count;
1210
 
1211
      try
1212
        {
1213
          Class vmClassLoader = Class.forName("java.lang.VMClassLoader");
1214
          Class[] types = {ClassLoader.class, String.class,
1215
                           byte[].class, int.class, int.class,
1216
                           ProtectionDomain.class };
1217
          Method m = vmClassLoader.getDeclaredMethod("defineClass", types);
1218
          // We can bypass the security check of setAccessible(true), since
1219
          // we're in the same package.
1220
          m.flag = true;
1221
 
1222
          Object[] args = {loader, qualName, bytecode, new Integer(0),
1223
                           new Integer(bytecode.length),
1224
                           Object.class.getProtectionDomain() };
1225
          Class clazz = (Class) m.invoke(null, args);
1226
 
1227
          // Finally, initialize the m field of the proxy class, before
1228
          // returning it.
1229
          Field f = clazz.getDeclaredField("m");
1230
          f.flag = true;
1231
          // we can share the array, because it is not publicized
1232
          f.set(null, methods);
1233
 
1234
          return clazz;
1235
        }
1236
      catch (Exception e)
1237
        {
1238
          // assert false;
1239
          throw (Error) new InternalError("Unexpected: " + e).initCause(e);
1240
        }
1241
    }
1242
 
1243
    /**
1244
     * Put a single byte on the stream.
1245
     *
1246
     * @param i the information to add (only lowest 8 bits are used)
1247
     */
1248
    private void putU1(int i)
1249
    {
1250
      stream.append((char) i);
1251
    }
1252
 
1253
    /**
1254
     * Put two bytes on the stream.
1255
     *
1256
     * @param i the information to add (only lowest 16 bits are used)
1257
     */
1258
    private void putU2(int i)
1259
    {
1260
      stream.append((char) (i >> 8)).append((char) i);
1261
    }
1262
 
1263
    /**
1264
     * Put four bytes on the stream.
1265
     *
1266
     * @param i the information to add (treated as unsigned)
1267
     */
1268
    private void putU4(int i)
1269
    {
1270
      stream.append((char) (i >> 24)).append((char) (i >> 16));
1271
      stream.append((char) (i >> 8)).append((char) i);
1272
    }
1273
 
1274
    /**
1275
     * Put bytecode to load a constant integer on the stream. This only
1276
     * needs to work for values less than Short.MAX_VALUE.
1277
     *
1278
     * @param i the int to add
1279
     */
1280
    private void putConst(int i)
1281
    {
1282
      if (i >= -1 && i <= 5)
1283
        putU1(ICONST_0 + i);
1284
      else if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE)
1285
        {
1286
          putU1(BIPUSH);
1287
          putU1(i);
1288
        }
1289
      else
1290
        {
1291
          putU1(SIPUSH);
1292
          putU2(i);
1293
        }
1294
    }
1295
 
1296
    /**
1297
     * Put bytecode to load a given local variable on the stream.
1298
     *
1299
     * @param i the slot to load
1300
     * @param type the base type of the load
1301
     */
1302
    private void putLoad(int i, Class type)
1303
    {
1304
      int offset = 0;
1305
      if (type == long.class)
1306
        offset = 1;
1307
      else if (type == float.class)
1308
        offset = 2;
1309
      else if (type == double.class)
1310
        offset = 3;
1311
      else if (! type.isPrimitive())
1312
        offset = 4;
1313
      if (i < 4)
1314
        putU1(ILOAD_0 + 4 * offset + i);
1315
      else
1316
        {
1317
          putU1(ILOAD + offset);
1318
          putU1(i);
1319
        }
1320
    }
1321
 
1322
    /**
1323
     * Given a primitive type, return its wrapper class name.
1324
     *
1325
     * @param clazz the primitive type (but not void.class)
1326
     * @return the internal form of the wrapper class name
1327
     */
1328
    private String wrapper(Class clazz)
1329
    {
1330
      if (clazz == boolean.class)
1331
        return "java/lang/Boolean";
1332
      if (clazz == byte.class)
1333
        return "java/lang/Byte";
1334
      if (clazz == short.class)
1335
        return "java/lang/Short";
1336
      if (clazz == char.class)
1337
        return "java/lang/Character";
1338
      if (clazz == int.class)
1339
        return "java/lang/Integer";
1340
      if (clazz == long.class)
1341
        return "java/lang/Long";
1342
      if (clazz == float.class)
1343
        return "java/lang/Float";
1344
      if (clazz == double.class)
1345
        return "java/lang/Double";
1346
      // assert false;
1347
      return null;
1348
    }
1349
 
1350
    /**
1351
     * Returns the entry of this String in the Constant pool, adding it
1352
     * if necessary.
1353
     *
1354
     * @param str the String to resolve
1355
     * @return the index of the String in the constant pool
1356
     */
1357
    private char utf8Info(String str)
1358
    {
1359
      String utf8 = toUtf8(str);
1360
      int len = utf8.length();
1361
      return poolIndex("\1" + (char) (len >> 8) + (char) (len & 0xff) + utf8);
1362
    }
1363
 
1364
    /**
1365
     * Returns the entry of the appropriate class info structure in the
1366
     * Constant pool, adding it if necessary.
1367
     *
1368
     * @param name the class name, in internal form
1369
     * @return the index of the ClassInfo in the constant pool
1370
     */
1371
    private char classInfo(String name)
1372
    {
1373
      char index = utf8Info(name);
1374
      char[] c = {7, (char) (index >> 8), (char) (index & 0xff)};
1375
      return poolIndex(new String(c));
1376
    }
1377
 
1378
    /**
1379
     * Returns the entry of the appropriate class info structure in the
1380
     * Constant pool, adding it if necessary.
1381
     *
1382
     * @param clazz the class type
1383
     * @return the index of the ClassInfo in the constant pool
1384
     */
1385
    private char classInfo(Class clazz)
1386
    {
1387
      return classInfo(TypeSignature.getEncodingOfClass(clazz.getName(),
1388
                                                        false));
1389
    }
1390
 
1391
    /**
1392
     * Returns the entry of the appropriate fieldref, methodref, or
1393
     * interfacemethodref info structure in the Constant pool, adding it
1394
     * if necessary.
1395
     *
1396
     * @param structure FIELD, METHOD, or INTERFACE
1397
     * @param clazz the class name, in internal form
1398
     * @param name the simple reference name
1399
     * @param type the type of the reference
1400
     * @return the index of the appropriate Info structure in the constant pool
1401
     */
1402
    private char refInfo(byte structure, String clazz, String name,
1403
                         String type)
1404
    {
1405
      char cindex = classInfo(clazz);
1406
      char ntindex = nameAndTypeInfo(name, type);
1407
      // relies on FIELD == 1, METHOD == 2, INTERFACE == 3
1408
      char[] c = {(char) (structure + 8),
1409
                  (char) (cindex >> 8), (char) (cindex & 0xff),
1410
                  (char) (ntindex >> 8), (char) (ntindex & 0xff)};
1411
      return poolIndex(new String(c));
1412
    }
1413
 
1414
    /**
1415
     * Returns the entry of the appropriate nameAndTyperef info structure
1416
     * in the Constant pool, adding it if necessary.
1417
     *
1418
     * @param name the simple name
1419
     * @param type the reference type
1420
     * @return the index of the NameAndTypeInfo structure in the constant pool
1421
     */
1422
    private char nameAndTypeInfo(String name, String type)
1423
    {
1424
      char nindex = utf8Info(name);
1425
      char tindex = utf8Info(type);
1426
      char[] c = {12, (char) (nindex >> 8), (char) (nindex & 0xff),
1427
                  (char) (tindex >> 8), (char) (tindex & 0xff)};
1428
      return poolIndex(new String(c));
1429
    }
1430
 
1431
    /**
1432
     * Converts a regular string to a UTF8 string, where the upper byte
1433
     * of every char is 0, and '\\u0000' is not in the string.  This is
1434
     * basically to use a String as a fancy byte[], and while it is less
1435
     * efficient in memory use, it is easier for hashing.
1436
     *
1437
     * @param str the original, in straight unicode
1438
     * @return a modified string, in UTF8 format in the low bytes
1439
     */
1440
    private String toUtf8(String str)
1441
    {
1442
      final char[] ca = str.toCharArray();
1443
      final int len = ca.length;
1444
 
1445
      // Avoid object creation, if str is already fits UTF8.
1446
      int i;
1447
      for (i = 0; i < len; i++)
1448
        if (ca[i] == 0 || ca[i] > '\u007f')
1449
          break;
1450
      if (i == len)
1451
        return str;
1452
 
1453
      final StringBuffer sb = new StringBuffer(str);
1454
      sb.setLength(i);
1455
      for ( ; i < len; i++)
1456
        {
1457
          final char c = ca[i];
1458
          if (c > 0 && c <= '\u007f')
1459
            sb.append(c);
1460
          else if (c <= '\u07ff') // includes '\0'
1461
            {
1462
              sb.append((char) (0xc0 | (c >> 6)));
1463
              sb.append((char) (0x80 | (c & 0x6f)));
1464
            }
1465
          else
1466
            {
1467
              sb.append((char) (0xe0 | (c >> 12)));
1468
              sb.append((char) (0x80 | ((c >> 6) & 0x6f)));
1469
              sb.append((char) (0x80 | (c & 0x6f)));
1470
            }
1471
        }
1472
      return sb.toString();
1473
    }
1474
 
1475
    /**
1476
     * Returns the location of a byte sequence (conveniently wrapped in
1477
     * a String with all characters between \u0001 and \u00ff inclusive)
1478
     * in the constant pool, adding it if necessary.
1479
     *
1480
     * @param sequence the byte sequence to look for
1481
     * @return the index of the sequence
1482
     * @throws IllegalArgumentException if this would make the constant
1483
     *         pool overflow
1484
     */
1485
    private char poolIndex(String sequence)
1486
    {
1487
      Integer i = (Integer) poolEntries.get(sequence);
1488
      if (i == null)
1489
        {
1490
          // pool starts at index 1
1491
          int size = poolEntries.size() + 1;
1492
          if (size >= 65535)
1493
            throw new IllegalArgumentException("exceeds VM limitations");
1494
          i = new Integer(size);
1495
          poolEntries.put(sequence, i);
1496
          pool.append(sequence);
1497
        }
1498
      return (char) i.intValue();
1499
    }
1500
  } // class ClassFactory
1501
}

powered by: WebSVN 2.1.0

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