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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [lang/] [reflect/] [Proxy.java] - Blame information for rev 775

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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