[kaffe] jBoss & Kaffe

Dalibor Topic robilad@yahoo.com
Tue May 20 08:41:01 2003


--0-614432395-1053445396=:87251
Content-Type: text/plain; charset=us-ascii
Content-Id: 
Content-Disposition: inline

Hallo Helmer,

--- Helmer Krämer <hkraemer@freenet.de> wrote:
> On Wed, 14 May 2003 17:07:31 +0200
> Ronald Aigner <ra3@os.inf.tu-dresden.de> wrote:
> 
> Hi Ronald,
> 
> > On Wednesday 14 May 2003 14:05, Helmer Krämer wrote:
> > > i'll commit a patch later this week, which will fix this
> > > issue (that is, I hope so, since eclipse does something
> > > similar and is starting w/o problems with my patch).
> > this would be could, but would fix only some of jBoss' problems:
> > A collegue of mine hacked a fixed path into the mentioned code, so jBoss
> got a 
> > little further. It then crashes with:
> 
> with the patches I've checked, jBoss seems to start,
> print some logging messages about its version and
> crashes afterwards. IIRC, that crash happens while
> jBoss is creating a "UniversalClassLoader". It'd be
> really nice, if youn could take a look at this, since
> I don't have the time to do so (will fix any bug you
> find, though ;)). 

Yeah, it's one of those "calling a method that's redefined in extended class"
type of bugs. I fixed it by using an internalAddURL method. Patch attached,
I'll check it in tonight. 

Also in the patch is a first attempt at merging in java.lang.reflect.Proxy from
GNU Classpath. Now JBoss 3.2.1 fails somewhere in the Proxy class. Use jikes to
build, I haven't updated the class library profiles yet. ;)

cheers,
dalibor topic

__________________________________
Do you Yahoo!?
The New Yahoo! Search - Faster. Easier. Bingo.
http://search.yahoo.com
--0-614432395-1053445396=:87251
Content-Type: text/plain; name="proxy.diff"
Content-Description: proxy.diff
Content-Disposition: inline; filename="proxy.diff"

diff -urN -x CVS /HG/hiwis/topic/PROJECTS/kaffe/libraries/javalib/gnu/java/lang/reflect/TypeSignature.java kaffe/libraries/javalib/gnu/java/lang/reflect/TypeSignature.java
--- /HG/hiwis/topic/PROJECTS/kaffe/libraries/javalib/gnu/java/lang/reflect/TypeSignature.java	Thu Jan  1 01:00:00 1970
+++ kaffe/libraries/javalib/gnu/java/lang/reflect/TypeSignature.java	Tue May 20 16:48:13 2003
@@ -0,0 +1,261 @@
+/* TypeSignature.java -- Class used to compute type signatures
+   Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.lang.reflect;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+
+/**
+ * This class provides static methods that can be used to compute
+ * type-signatures of <code>Class</code>s or <code>Member</code>s.
+ * More specific methods are also provided for computing the
+ * type-signature of <code>Constructor</code>s and
+ * <code>Method</code>s.  Methods are also provided to go in the
+ * reverse direction.
+ *
+ * @author Eric Blake <ebb9@email.byu.edu>
+ */
+public class TypeSignature
+{
+  /**
+   * Returns a <code>String</code> representing the type-encoding of a class.
+   * The .class file format has different encodings for classes, depending
+   * on whether it must be disambiguated from primitive types or not; hence
+   * the descriptor parameter to choose between them. If you are planning
+   * on decoding primitive types along with classes, then descriptor should
+   * be true for correct results. Type-encodings are computed as follows:
+   *
+   * <pre>
+   * boolean -> "Z"
+   * byte    -> "B"
+   * char    -> "C"
+   * double  -> "D"
+   * float   -> "F"
+   * int     -> "I"
+   * long    -> "J"
+   * short   -> "S"
+   * void    -> "V"
+   * arrays  -> "[" + descriptor format of component type
+   * object  -> class format: fully qualified name with '.' replaced by '/'
+   *            descriptor format: "L" + class format + ";"
+   * </pre>
+   *
+   * @param type the class name to encode
+   * @param descriptor true to return objects in descriptor format
+   * @return the class name, as it appears in bytecode constant pools
+   * @see #getClassForEncoding(String)
+   */
+  public static String getEncodingOfClass(String type, boolean descriptor)
+  {
+    if (! descriptor || type.charAt(0) == '[')
+      return type.replace('.', '/');
+    if (type.equals("boolean"))
+      return "Z";
+    if (type.equals("byte"))
+      return "B";
+    if (type.equals("short"))
+      return "S";
+    if (type.equals("char"))
+      return "C";
+    if (type.equals("int"))
+      return "I";
+    if (type.equals("long"))
+      return "J";
+    if (type.equals("float"))
+      return "F";
+    if (type.equals("double"))
+      return "D";
+    if (type.equals("void"))
+      return "V";
+    return 'L' + type.replace('.', '/') + ';';
+  }
+
+  /**
+   * Gets the descriptor encoding for a class.
+   *
+   * @param clazz the class to encode
+   * @param descriptor true to return objects in descriptor format
+   * @return the class name, as it appears in bytecode constant pools
+   * @see #getEncodingOfClass(String, boolean)
+   */
+  public static String getEncodingOfClass(Class clazz, boolean descriptor)
+  {
+    return getEncodingOfClass(clazz.getName(), descriptor);
+  }
+
+  /**
+   * Gets the descriptor encoding for a class.
+   *
+   * @param clazz the class to encode
+   * @return the class name, as it appears in bytecode constant pools
+   * @see #getEncodingOfClass(String, boolean)
+   */
+  public static String getEncodingOfClass(Class clazz)
+  {
+    return getEncodingOfClass(clazz.getName(), true);
+  }
+
+
+  /**
+   * This function is the inverse of <code>getEncodingOfClass</code>. This
+   * accepts both object and descriptor formats, but must know which style
+   * of string is being passed in (usually, descriptor should be true). In
+   * descriptor format, "I" is treated as int.class, in object format, it
+   * is treated as a class named I in the unnamed package.
+   *
+   * @param type_code the class name to decode
+   * @param descriptor if the string is in descriptor format
+   * @return the corresponding Class object
+   * @throws ClassNotFoundException if the class cannot be located
+   * @see #getEncodingOfClass(Class, boolean)
+   */
+  public static Class getClassForEncoding(String type_code, boolean descriptor)
+    throws ClassNotFoundException
+  {
+    if (descriptor)
+      {
+        switch (type_code.charAt(0))
+          {
+          case 'B':
+            return byte.class;
+          case 'C':
+            return char.class;
+          case 'D':
+            return double.class;
+          case 'F':
+            return float.class;
+          case 'I':
+            return int.class;
+          case 'J':
+            return long.class;
+          case 'S':
+            return short.class;
+          case 'V':
+            return void.class;
+          case 'Z':
+            return boolean.class;
+          default:
+            throw new ClassNotFoundException("Invalid class name: "
+                                             + type_code);
+          case 'L':
+            type_code = type_code.substring(1, type_code.length() - 1);
+            // Fallthrough.
+          case '[':
+          }
+      }
+    return Class.forName(type_code.replace('/', '.'));
+  }
+
+  /**
+   * Gets the Class object for a type name.
+   *
+   * @param type_code the class name to decode
+   * @return the corresponding Class object
+   * @throws ClassNotFoundException if the class cannot be located
+   * @see #getClassForEncoding(String, boolean)
+   */
+  public static Class getClassForEncoding(String type_code)
+    throws ClassNotFoundException
+  {
+    return getClassForEncoding(type_code, true);
+  }
+
+  /**
+   * Returns a <code>String</code> representing the type-encoding of a
+   * method.  The type-encoding of a method is:
+   *
+   * "(" + parameter type descriptors + ")" + return type descriptor
+   *
+   * XXX This could be faster if it were implemented natively.
+   *
+   * @param m the method to encode
+   * @return the encoding
+   */
+  public static String getEncodingOfMethod(Method m)
+  {
+    Class[] paramTypes = m.getParameterTypes();
+    StringBuffer buf = new StringBuffer().append('(');
+    for (int i = 0; i < paramTypes.length; i++)
+      buf.append(getEncodingOfClass(paramTypes[i].getName(), true));
+    buf.append(')').append(getEncodingOfClass(m.getReturnType().getName(),
+                                              true));
+    return buf.toString();
+  }
+
+  /**
+   * Returns a <code>String</code> representing the type-encoding of a
+   * constructor. The type-encoding of a method is:
+   *
+   * "(" + parameter type descriptors + ")V"
+   *
+   * XXX This could be faster if it were implemented natively.
+   *
+   * @param c the constructor to encode
+   * @return the encoding
+   */
+  public static String getEncodingOfConstructor(Constructor c)
+  {
+    Class[] paramTypes = c.getParameterTypes();
+    StringBuffer buf = new StringBuffer().append('(');
+    for (int i = 0; i < paramTypes.length; i++)
+      buf.append(getEncodingOfClass(paramTypes[i].getName(), true));
+    buf.append(")V");
+    return buf.toString();
+  }
+
+  /**
+   * Returns a <code>String</code> representing the type-encoding of a
+   * class member. This appropriately handles Constructors, Methods, and
+   * Fields.
+   *
+   * @param mem the member to encode
+   * @return the encoding
+   */
+  public static String getEncodingOfMember(Member mem)
+  {
+    if (mem instanceof Constructor)
+      return getEncodingOfConstructor((Constructor) mem);
+    if (mem instanceof Method)
+      return getEncodingOfMethod((Method) mem);
+    else // Field
+      return getEncodingOfClass(((Field) mem).getType().getName(), true);
+  }
+} // class TypeSignature
diff -urN -x CVS /HG/hiwis/topic/PROJECTS/kaffe/libraries/javalib/java/lang/reflect/Modifier.java kaffe/libraries/javalib/java/lang/reflect/Modifier.java
--- /HG/hiwis/topic/PROJECTS/kaffe/libraries/javalib/java/lang/reflect/Modifier.java	Wed Apr 18 11:31:38 2001
+++ kaffe/libraries/javalib/java/lang/reflect/Modifier.java	Tue May 20 16:50:34 2003
@@ -20,6 +20,14 @@
   public static final int STATIC = 0x0008;
   public static final int FINAL = 0x0010;
   public static final int SYNCHRONIZED = 0x0020;
+
+  /**
+   * Super - treat invokespecial as polymorphic so that super.foo() works
+   * according to the JLS. This is a reuse of the synchronized constant
+   * to patch a hole in JDK 1.0. *shudder*.
+   */
+  static final int SUPER = 0x0020;
+
   public static final int VOLATILE = 0x0040;
   public static final int TRANSIENT = 0x0080;
   public static final int NATIVE = 0x0100;
diff -urN -x CVS /HG/hiwis/topic/PROJECTS/kaffe/libraries/javalib/java/lang/reflect/Proxy.java kaffe/libraries/javalib/java/lang/reflect/Proxy.java
--- /HG/hiwis/topic/PROJECTS/kaffe/libraries/javalib/java/lang/reflect/Proxy.java	Wed Apr 18 11:31:46 2001
+++ kaffe/libraries/javalib/java/lang/reflect/Proxy.java	Tue May 20 17:34:39 2003
@@ -1,54 +1,1624 @@
-/*
- * Java core library component.
+/* Proxy.java -- build a proxy class that implements reflected interfaces
+   Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.lang.reflect;
+
+import java.io.Serializable;
+import java.security.ProtectionDomain;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
+import gnu.classpath.Configuration;
+import gnu.java.lang.reflect.TypeSignature;
+
+/**
+ * This class allows you to dynamically create an instance of any (or
+ * even multiple) interfaces by reflection, and decide at runtime
+ * how that instance will behave by giving it an appropriate
+ * {@link InvocationHandler}.  Proxy classes serialize specially, so
+ * that the proxy object can be reused between VMs, without requiring
+ * a persistent copy of the generated class code.
+ *
+ * <h3>Creation</h3>
+ * To create a proxy for some interface Foo:
+ *
+ * <pre>
+ *   InvocationHandler handler = new MyInvocationHandler(...);
+ *   Class proxyClass = Proxy.getProxyClass(
+ *       Foo.class.getClassLoader(), new Class[] { Foo.class });
+ *   Foo f = (Foo) proxyClass
+ *       .getConstructor(new Class[] { InvocationHandler.class })
+ *       .newInstance(new Object[] { handler });
+ * </pre>
+ * or more simply:
+ * <pre>
+ *   Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
+ *                                        new Class[] { Foo.class },
+ *                                        handler);
+ * </pre>
  *
- * Copyright (c) 2001
- *      Edouard G. Parmelan.  All rights reserverd.
- * Copyright (c) 2001
- *      Transvirtual Technologies, Inc.  All rights reserved.
+ * <h3>Dynamic Proxy Classes</h3>
+ * A dynamic proxy class is created at runtime, and has the following
+ * properties:
+ * <ul>
+ *  <li>The class is <code>public</code> and <code>final</code>,
+ *      and is neither <code>abstract</code> nor an inner class.</li>
+ *  <li>The class has no canonical name (there is no formula you can use
+ *      to determine or generate its name), but begins with the
+ *      sequence "$Proxy".  Abuse this knowledge at your own peril.
+ *      (For now, '$' in user identifiers is legal, but it may not
+ *      be that way forever. You weren't using '$' in your
+ *      identifiers, were you?)</li>
+ *  <li>The class extends Proxy, and explicitly implements all the
+ *      interfaces specified at creation, in order (this is important
+ *      for determining how method invocation is resolved).  Note that
+ *      a proxy class implements {@link Serializable}, at least
+ *      implicitly, since Proxy does, but true serial behavior
+ *      depends on using a serializable invocation handler as well.</li>
+ *  <li>If at least one interface is non-public, the proxy class
+ *      will be in the same package.  Otherwise, the package is
+ *      unspecified.  This will work even if the package is sealed
+ *      from user-generated classes, because Proxy classes are
+ *      generated by a trusted source.  Meanwhile, the proxy class
+ *      belongs to the classloader you designated.</li>
+ *  <li>Reflection works as expected: {@link Class#getInterfaces()} and
+ *      {@link Class#getMethods()} work as they do on normal classes.</li>
+ *  <li>The method {@link #isProxyClass()} will distinguish between
+ *      true proxy classes and user extensions of this class.  It only
+ *      returns true for classes created by {@link #getProxyClass}.</li>
+ *  <li>The {@link ProtectionDomain} of a proxy class is the same as for
+ *      bootstrap classes, such as Object or Proxy, since it is created by
+ *      a trusted source.  This protection domain will typically be granted
+ *      {@link java.security.AllPermission}. But this is not a security
+ *      risk, since there are adequate permissions on reflection, which is
+ *      the only way to create an instance of the proxy class.</li>
+ *  <li>The proxy class contains a single constructor, which takes as
+ *      its only argument an {@link InvocationHandler}.  The method
+ *      {@link #newInstance} is shorthand to do the necessary
+ *      reflection.</li>
+ * </ul>
  *
- * See the file "license.terms" for information on usage and redistribution
- * of this file.
+ * <h3>Proxy Instances</h3>
+ * A proxy instance is an instance of a proxy class.  It has the
+ * following properties, many of which follow from the properties of a
+ * proxy class listed above:
+ * <ul>
+ *  <li>For a proxy class with Foo listed as one of its interfaces, the
+ *      expression <code>proxy instanceof Foo</code> will return true,
+ *      and the expression <code>(Foo) proxy</code> will succeed without
+ *      a {@link ClassCastException}.</li>
+ *  <li>Each proxy instance has an invocation handler, which can be
+ *      accessed by {@link #getInvocationHandler(Object)}.  Any call
+ *      to an interface method, including {@link Object#hashcode()},
+ *      {@link Object#equals(Object)}, or {@link Object#toString()},
+ *      but excluding the public final methods of Object, will be
+ *      encoded and passed to the {@link InvocationHandler#invoke}
+ *      method of this handler.</li>
+ * </ul>
  *
- * Author: Edouard G. Parmelan <egp@free.fr>
- * Checked Spec: JDK 1.3 - NotImplemented
+ * <h3>Inheritance Issues</h3>
+ * A proxy class may inherit a method from more than one interface.
+ * The order in which interfaces are listed matters, because it determines
+ * which reflected {@link Method} object will be passed to the invocation
+ * handler.  This means that the dynamically generated class cannot
+ * determine through which interface a method is being invoked.<p>
+ *
+ * In short, if a method is declared in Object (namely, hashCode,
+ * equals, or toString), then Object will be used; otherwise, the
+ * leftmost interface that inherits or declares a method will be used,
+ * even if it has a more permissive throws clause than what the proxy
+ * class is allowed. Thus, in the invocation handler, it is not always
+ * safe to assume that every class listed in the throws clause of the
+ * passed Method object can safely be thrown; fortunately, the Proxy
+ * instance is robust enough to wrap all illegal checked exceptions in
+ * {@link UndeclaredThrowableException}.
+ *
+ * @see InvocationHandler
+ * @see UndeclaredThrowableException
+ * @see Class
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.3
+ * @status updated to 1.4, except for the use of ProtectionDomain
  */
+public class Proxy implements Serializable
+{
+  /**
+   * Compatible with JDK 1.3+.
+   */
+  private static final long serialVersionUID = -2222568056686623797L;
 
-package java.lang.reflect;
+  /**
+   * Map of ProxyType to proxy class.
+   *
+   * @XXX This prevents proxy classes from being garbage collected.
+   * java.util.WeakHashSet is not appropriate, because that collects the
+   * keys, but we are interested in collecting the elements.
+   */
+  private static final Map proxyClasses = new HashMap();
 
-import java.io.Serializable;
+  /**
+   * The invocation handler for this proxy instance.  For Proxy, this
+   * field is unused, but it appears here in order to be serialized in all
+   * proxy classes.
+   *
+   * <em>NOTE</em>: This implementation is more secure for proxy classes
+   * than what Sun specifies. Sun does not require h to be immutable, but
+   * this means you could change h after the fact by reflection.  However,
+   * by making h immutable, we may break non-proxy classes which extend
+   * Proxy.
+   * @serial invocation handler associated with this proxy instance
+   */
+  protected InvocationHandler h;
 
-public class Proxy
-    implements Serializable
-{
-    protected InvocationHandler h;
+  /**
+   * Constructs a new Proxy from a subclass (usually a proxy class),
+   * with the specified invocation handler.
+   *
+   * <em>NOTE</em>: This throws a NullPointerException if you attempt
+   * to create a proxy instance with a null handler using reflection.
+   * This behavior is not yet specified by Sun; see Sun Bug 4487672.
+   *
+   * @param handler the invocation handler, may be null if the subclass
+   *        is not a proxy class
+   * @throws NullPointerException if handler is null and this is a proxy
+   *         instance
+   */
+  protected Proxy(InvocationHandler handler)
+  {
+    if (handler == null && isProxyClass(getClass()))
+      throw new NullPointerException("invalid handler");
+    h = handler;
+  }
+
+  /**
+   * Returns the proxy {@link Class} for the given ClassLoader and array
+   * of interfaces, dynamically generating it if necessary.
+   *
+   * There are several restrictions on this method, the violation of
+   * which will result in an IllegalArgumentException or
+   * NullPointerException:
+   * <ul>
+   *  <li>All objects in `interfaces' must represent distinct interfaces.
+   *      Classes, primitive types, null, and duplicates are forbidden.</li>
+   *  <li>The interfaces must be visible in the specified ClassLoader.
+   *      In other words, for each interface i:
+   *      <code>Class.forName(i.getName(), false, loader) == i</code>
+   *      must be true.</li>
+   *  <li>All non-public interfaces (if any) must reside in the same
+   *      package, or the proxy class would be non-instantiable.  If
+   *      there are no non-public interfaces, the package of the proxy
+   *      class is unspecified.</li>
+   *  <li>All interfaces must be compatible - if two declare a method
+   *      with the same name and parameters, the return type must be
+   *      the same and the throws clause of the proxy class will be
+   *      the maximal subset of subclasses of the throws clauses for
+   *      each method that is overridden.</li>
+   *  <li>VM constraints limit the number of interfaces a proxy class
+   *      may directly implement (however, the indirect inheritance
+   *      of {@link Serializable} does not count against this limit).
+   *      Even though most VMs can theoretically have 65535
+   *      superinterfaces for a class, the actual limit is smaller
+   *      because a class's constant pool is limited to 65535 entries,
+   *      and not all entries can be interfaces.</li>
+   * </ul><p>
+   *
+   * Note that different orders of interfaces produce distinct classes.
+   *
+   * @param loader the class loader to define the proxy class in; null
+   *        implies the bootstrap class loader
+   * @param interfaces the array of interfaces the proxy class implements,
+   *        may be empty, but not null
+   * @return the Class object of the proxy class
+   * @throws IllegalArgumentException if the constraints above were
+   *         violated, except for problems with null
+   * @throws NullPointerException if `interfaces' is null or contains
+   *         a null entry
+   */
+  // synchronized so that we aren't trying to build the same class
+  // simultaneously in two threads
+  public static synchronized Class getProxyClass(ClassLoader loader,
+                                                 Class[] interfaces)
+  {
+    interfaces = (Class[]) interfaces.clone();
+    ProxyType pt = new ProxyType(loader, interfaces);
+    Class clazz = (Class) proxyClasses.get(pt);
+    if (clazz == null)
+      {
+        if (Configuration.HAVE_NATIVE_GET_PROXY_CLASS)
+          clazz = getProxyClass0(loader, interfaces);
+        else
+          {
+            ProxyData data = (Configuration.HAVE_NATIVE_GET_PROXY_DATA
+                              ? getProxyData0(loader, interfaces)
+                              : ProxyData.getProxyData(pt));
+
+            // FIXME workaround for bug in gcj 3.0.x
+            // Not needed with the latest gcj from cvs
+            //clazz = (Configuration.HAVE_NATIVE_GENERATE_PROXY_CLASS
+            //	       ? generateProxyClass0(loader, data)
+            //         : new ClassFactory(data).generate(loader));
+            if (Configuration.HAVE_NATIVE_GENERATE_PROXY_CLASS)
+              clazz = generateProxyClass0(loader, data);
+            else
+              {
+                ClassFactory cf = new ClassFactory(data);
+                clazz = cf.generate(loader);
+              }
+          }
+
+        Object check = proxyClasses.put(pt, clazz);
+        // assert check == null && clazz != null;
+        if (check != null || clazz == null)
+          throw new InternalError(/*"Fatal flaw in getProxyClass"*/);
+      }
+    return clazz;
+  }
+
+  /**
+   * Combines several methods into one.  This is equivalent to:
+   * <pre>
+   *   Proxy.getProxyClass(loader, interfaces)
+   *       .getConstructor(new Class[] {InvocationHandler.class})
+   *       .newInstance(new Object[] {handler});
+   * </pre>
+   * except that it will not fail with the normal problems caused
+   * by reflection.  It can still fail for the same reasons documented
+   * in getProxyClass, or if handler is null.
+   *
+   * @param loader the class loader to define the proxy class in; null
+   *        implies the bootstrap class loader
+   * @param interfaces the array of interfaces the proxy class implements,
+   *        may be empty, but not null
+   * @param handler the invocation handler, may not be null
+   * @return a proxy instance implementing the specified interfaces
+   * @throws IllegalArgumentException if the constraints for getProxyClass
+   *         were violated, except for problems with null
+   * @throws NullPointerException if `interfaces' is null or contains
+   *         a null entry, or if handler is null
+   * @see #getProxyClass(ClassLoader, Class[])
+   * @see Class#getConstructor(Class[])
+   * @see Constructor#newInstance(Object[])
+   */
+  public static Object newProxyInstance(ClassLoader loader,
+                                        Class[] interfaces,
+                                        InvocationHandler handler)
+  {
+    try
+      {
+        // getProxyClass() and Proxy() throw the necessary exceptions
+        return getProxyClass(loader, interfaces)
+          .getConstructor(new Class[] {InvocationHandler.class})
+          .newInstance(new Object[] {handler});
+      }
+    catch (RuntimeException e)
+      {
+        // Let IllegalArgumentException, NullPointerException escape.
+        // assert e instanceof IllegalArgumentException
+        //   || e instanceof NullPointerException;
+        throw e;
+      }
+    catch (InvocationTargetException e)
+      {
+        // Let wrapped NullPointerException escape.
+        // assert e.getTargetException() instanceof NullPointerException
+        throw (NullPointerException) e.getCause();
+      }
+    catch (Exception e)
+      {
+        // Covers InstantiationException, IllegalAccessException,
+        // NoSuchMethodException, none of which should be generated
+        // if the proxy class was generated correctly.
+        // assert false;
+        throw (Error) new InternalError("Unexpected: " + e).initCause(e);
+      }
+  }
+
+  /**
+   * Returns true if and only if the Class object is a dynamically created
+   * proxy class (created by <code>getProxyClass</code> or by the
+   * syntactic sugar of <code>newProxyInstance</code>).
+   *
+   * <p>This check is secure (in other words, it is not simply
+   * <code>clazz.getSuperclass() == Proxy.class</code>), it will not
+   * be spoofed by non-proxy classes that extend Proxy.
+   *
+   * @param clazz the class to check, must not be null
+   * @return true if the class represents a proxy class
+   * @throws NullPointerException if clazz is null
+   */
+  // This is synchronized on the off chance that another thread is
+  // trying to add a class to the map at the same time we read it.
+  public static synchronized boolean isProxyClass(Class clazz)
+  {
+    if (! Proxy.class.isAssignableFrom(clazz))
+      return false;
+    // This is a linear search, even though we could do an O(1) search
+    // using new ProxyType(clazz.getClassLoader(), clazz.getInterfaces()).
+    return proxyClasses.containsValue(clazz);
+  }
+
+  /**
+   * Returns the invocation handler for the given proxy instance.<p>
+   *
+   * <em>NOTE</em>: We guarantee a non-null result if successful,
+   * but Sun allows the creation of a proxy instance with a null
+   * handler.  See the comments for {@link #Proxy(InvocationHandler)}.
+   *
+   * @param proxy the proxy instance, must not be null
+   * @return the invocation handler, guaranteed non-null.
+   * @throws IllegalArgumentException if
+   *         <code>Proxy.isProxyClass(proxy.getClass())</code> returns false.
+   * @throws NullPointerException if proxy is null
+   */
+  public static InvocationHandler getInvocationHandler(Object proxy)
+  {
+    if (! isProxyClass(proxy.getClass()))
+      throw new IllegalArgumentException("not a proxy instance");
+    return ((Proxy) proxy).h;
+  }
+
+  /**
+   * Optional native method to replace (and speed up) the pure Java
+   * implementation of getProxyClass.  Only needed if
+   * Configuration.HAVE_NATIVE_GET_PROXY_CLASS is true, this does the
+   * work of both getProxyData0 and generateProxyClass0 with no
+   * intermediate form in Java. The native code may safely assume that
+   * this class must be created, and does not already exist.
+   *
+   * @param loader the class loader to define the proxy class in; null
+   *        implies the bootstrap class loader
+   * @param interfaces the interfaces the class will extend
+   * @return the generated proxy class
+   * @throws IllegalArgumentException if the constraints for getProxyClass
+   *         were violated, except for problems with null
+   * @throws NullPointerException if `interfaces' is null or contains
+   *         a null entry, or if handler is null
+   * @see Configuration#HAVE_NATIVE_GET_PROXY_CLASS
+   * @see #getProxyClass(ClassLoader, Class[])
+   * @see #getProxyData0(ClassLoader, Class[])
+   * @see #generateProxyClass0(ProxyData)
+   */
+  private static native Class getProxyClass0(ClassLoader loader,
+                                             Class[] interfaces);
+
+  /**
+   * Optional native method to replace (and speed up) the pure Java
+   * implementation of getProxyData.  Only needed if
+   * Configuration.HAVE_NATIVE_GET_PROXY_DATA is true. The native code
+   * may safely assume that a new ProxyData object must be created which
+   * does not duplicate any existing ones.
+   *
+   * @param loader the class loader to define the proxy class in; null
+   *        implies the bootstrap class loader
+   * @param interfaces the interfaces the class will extend
+   * @return all data that is required to make this proxy class
+   * @throws IllegalArgumentException if the constraints for getProxyClass
+   *         were violated, except for problems with null
+   * @throws NullPointerException if `interfaces' is null or contains
+   *         a null entry, or if handler is null
+   * @see Configuration.HAVE_NATIVE_GET_PROXY_DATA
+   * @see #getProxyClass(ClassLoader, Class[])
+   * @see #getProxyClass0(ClassLoader, Class[])
+   * @see ProxyType#getProxyData()
+   */
+  private static native ProxyData getProxyData0(ClassLoader loader,
+                                                Class[] interfaces);
+
+  /**
+   * Optional native method to replace (and speed up) the pure Java
+   * implementation of generateProxyClass.  Only needed if
+   * Configuration.HAVE_NATIVE_GENERATE_PROXY_CLASS is true. The native
+   * code may safely assume that a new Class must be created, and that
+   * the ProxyData object does not describe any existing class.
+   *
+   * @param loader the class loader to define the proxy class in; null
+   *        implies the bootstrap class loader
+   * @param data the struct of information to convert to a Class. This
+   *        has already been verified for all problems except exceeding
+   *        VM limitations
+   * @return the newly generated class
+   * @throws IllegalArgumentException if VM limitations are exceeded
+   * @see #getProxyClass(ClassLoader, Class[])
+   * @see #getProxyClass0(ClassLoader, Class[])
+   * @see ProxyData#generateProxyClass(ClassLoader)
+   */
+  private static native Class generateProxyClass0(ClassLoader loader,
+                                                  ProxyData data);
+
+  /**
+   * Helper class for mapping unique ClassLoader and interface combinations
+   * to proxy classes.
+   *
+   * @author Eric Blake <ebb9@email.byu.edu>
+   */
+  private static final class ProxyType
+  {
+    /**
+     * Store the class loader (may be null)
+     */
+    final ClassLoader loader;
+
+    /**
+     * Store the interfaces (never null, all elements are interfaces)
+     */
+    final Class[] interfaces;
+
+    /**
+     * Construct the helper object.
+     *
+     * @param loader the class loader to define the proxy class in; null
+     *        implies the bootstrap class loader
+     * @param interfaces an array of interfaces
+     */
+    ProxyType(ClassLoader loader, Class[] interfaces)
+    {
+      if (loader == null)
+         loader = ClassLoader.getSystemClassLoader();
+      this.loader = loader;
+      this.interfaces = interfaces;
+    }
+
+    /**
+     * Calculates the hash code.
+     *
+     * @return a combination of the classloader and interfaces hashcodes.
+     */
+    public int hashCode()
+    {
+      //loader is always not null
+      int hash = loader.hashCode();
+      for (int i = 0; i < interfaces.length; i++)
+        hash = hash * 31 + interfaces[i].hashCode();
+      return hash;
+    }
 
-    private Proxy() {
+    // A more comprehensive comparison of two arrays,
+    //   ignore array element order, and
+    //   ignore redundant elements
+    private static boolean sameTypes(Class arr1[], Class arr2[]) {
+      if (arr1.length == 1 && arr2.length == 1) {
+        return arr1[0] == arr2[0];
+      }
+        
+      // total occurrance of elements of arr1 in arr2
+      int total_occ_of_arr1_in_arr2 = 0;
+    each_type:
+      for (int i = arr1.length; --i >= 0; ) 
+      {
+        Class t = arr1[i];
+        for (int j = i; --j >= 0; ) 
+        {
+          if (t == arr1[j]) 
+          { //found duplicate type
+            continue each_type;  
+          }
+        }
+            
+        // count c(a unique element of arr1)'s 
+        //   occurrences in arr2
+        int occ_in_arr2 = 0;
+        for (int j = arr2.length; --j >= 0; ) 
+        {
+          if (t == arr2[j]) 
+          {
+            ++occ_in_arr2;
+          }
+        }
+        if (occ_in_arr2 == 0) 
+        { // t does not occur in arr2
+          return false;
+        }
+        
+        total_occ_of_arr1_in_arr2 += occ_in_arr2;
+      }
+      // now, each element of arr2 must have been visited
+      return total_occ_of_arr1_in_arr2 == arr2.length;
+    }
+
+    /**
+     * Calculates equality.
+     *
+     * @param the object to compare to
+     * @return true if it is a ProxyType with same data
+     */
+    public boolean equals(Object other)
+    {
+      ProxyType pt = (ProxyType) other;
+      if (loader != pt.loader || interfaces.length != pt.interfaces.length)
+        return false;
+	  return sameTypes(interfaces, pt.interfaces);
     }
+  } // class ProxyType
+
+  /**
+   * Helper class which allows hashing of a method name and signature
+   * without worrying about return type, declaring class, or throws clause,
+   * and which reduces the maximally common throws clause between two methods
+   *
+   * @author Eric Blake <ebb9@email.byu.edu>
+   */
+  private static final class ProxySignature
+  {
+    /**
+     * The core signatures which all Proxy instances handle.
+     */
+    static final HashMap coreMethods = new HashMap();
+    static
+    {
+      try
+        {
+          ProxySignature sig
+            = new ProxySignature(Object.class
+                                 .getMethod("equals",
+                                            new Class[] {Object.class}));
+          coreMethods.put(sig, sig);
+          sig = new ProxySignature(Object.class.getMethod("hashCode", null));
+          coreMethods.put(sig, sig);
+          sig = new ProxySignature(Object.class.getMethod("toString", null));
+          coreMethods.put(sig, sig);
+        }
+      catch (Exception e)
+        {
+          // assert false;
+          throw (Error) new InternalError("Unexpected: " + e).initCause(e);
+        }
+    }
+
+    /**
+     * The underlying Method object, never null
+     */
+    final Method method;
 
-    protected Proxy(InvocationHandler h) {
-	this.h = h;
+    /**
+     * The set of compatible thrown exceptions, may be empty
+     */
+    final Set exceptions = new HashSet();
+
+    /**
+     * Construct a signature
+     *
+     * @param method the Method this signature is based on, never null
+     */
+    ProxySignature(Method method)
+    {
+      this.method = method;
+      Class[] exc = method.getExceptionTypes();
+      int i = exc.length;
+      while (--i >= 0)
+        {
+          // discard unchecked exceptions
+          if (Error.class.isAssignableFrom(exc[i])
+              || RuntimeException.class.isAssignableFrom(exc[i]))
+            continue;
+          exceptions.add(exc[i]);
+        }
     }
 
-    public static Class getProxyClass(ClassLoader loader, Class[] interfaces)
-	throws IllegalArgumentException
+    /**
+     * Given a method, make sure it's return type is identical
+     * to this, and adjust this signature's throws clause appropriately
+     *
+     * @param other the signature to merge in
+     * @throws IllegalArgumentException if the return types conflict
+     */
+    void checkCompatibility(ProxySignature other)
     {
-	throw new kaffe.util.NotImplemented("java.lang.reflect.Proxy");
+      if (method.getReturnType() != other.method.getReturnType())
+        throw new IllegalArgumentException("incompatible return types: "
+                                           + method + ", " + other.method);
+
+      // if you can think of a more efficient way than this O(n^2) search,
+      // implement it!
+      int size1 = exceptions.size();
+      int size2 = other.exceptions.size();
+      boolean[] valid1 = new boolean[size1];
+      boolean[] valid2 = new boolean[size2];
+      Iterator itr = exceptions.iterator();
+      int pos = size1;
+      while (--pos >= 0)
+        {
+          Class c1 = (Class) itr.next();
+          Iterator itr2 = other.exceptions.iterator();
+          int pos2 = size2;
+          while (--pos2 >= 0)
+            {
+              Class c2 = (Class) itr2.next();
+              if (c2.isAssignableFrom(c1))
+                valid1[pos] = true;
+              if (c1.isAssignableFrom(c2))
+                valid2[pos2] = true;
+            }
+        }
+      pos = size1;
+      itr = exceptions.iterator();
+      while (--pos >= 0)
+        {
+          itr.next();
+          if (! valid1[pos])
+            itr.remove();
+        }
+      pos = size2;
+      itr = other.exceptions.iterator();
+      while (--pos >= 0)
+        {
+          itr.next();
+          if (! valid2[pos])
+            itr.remove();
+        }
+      exceptions.addAll(other.exceptions);
     }
 
-    public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
-	throws IllegalArgumentException
+    /**
+     * Calculates the hash code.
+     *
+     * @return a combination of name and parameter types
+     */
+    public int hashCode()
     {
-	throw new kaffe.util.NotImplemented("java.lang.reflect.Proxy");
+      int hash = method.getName().hashCode();
+      Class[] types = method.getParameterTypes();
+      for (int i = 0; i < types.length; i++)
+        hash = hash * 31 + types[i].hashCode();
+      return hash;
     }
 
-    public static boolean isProxyClass(Class cl)
+    /**
+     * Calculates equality.
+     *
+     * @param the object to compare to
+     * @return true if it is a ProxySignature with same data
+     */
+    public boolean equals(Object other)
     {
-	throw new kaffe.util.NotImplemented("java.lang.reflect.Proxy");
+      ProxySignature ps = (ProxySignature) other;
+      Class[] types1 = method.getParameterTypes();
+      Class[] types2 = ps.method.getParameterTypes();
+      if (! method.getName().equals(ps.method.getName())
+          || types1.length != types2.length)
+        return false;
+      int i = types1.length;
+      while (--i >= 0)
+        if (types1[i] != types2[i])
+          return false;
+      return true;
+    }
+  } // class ProxySignature
+
+  /**
+   * A flat representation of all data needed to generate bytecode/instantiate
+   * a proxy class.  This is basically a struct.
+   *
+   * @author Eric Blake <ebb9@email.byu.edu>
+   */
+  private static final class ProxyData
+  {
+    /**
+     * The package this class is in.  Possibly null, meaning the unnamed
+     * package.
+     */
+    Package pack;
+
+    /**
+     * The interfaces this class implements.  Non-null, but possibly empty.
+     */
+    Class[] interfaces;
+
+    /**
+     * The Method objects this class must pass as the second argument to
+     * invoke (also useful for determining what methods this class has).
+     * Non-null, non-empty (includes at least Object.hashCode, Object.equals,
+     * and Object.toString).
+     */
+    Method[] methods;
+
+    /**
+     * The exceptions that do not need to be wrapped in
+     * UndeclaredThrowableException. exceptions[i] is the same as, or a
+     * subset of subclasses, of methods[i].getExceptionTypes(), depending on
+     * compatible throws clauses with multiple inheritance. It is unspecified
+     * if these lists include or exclude subclasses of Error and
+     * RuntimeException, but excluding them is harmless and generates a
+     * smaller class.
+     */
+    Class[][] exceptions;
+
+    /**
+     * For unique id's
+     */
+    private static int count = 0;
+
+    /**
+     * The id of this proxy class
+     */
+    final int id = count++;
+
+    /**
+     * Construct a ProxyData with uninitialized data members.
+     */
+    ProxyData()
+    {
+    }
+
+    /**
+     * Verifies that the arguments are legal, and sets up remaining data
+     * This should only be called when a class must be generated, as
+     * it is expensive.
+     *
+     * @param pt the ProxyType to convert to ProxyData
+     * @return the flattened, verified ProxyData structure for use in
+     *         class generation
+     * @throws IllegalArgumentException if `interfaces' contains
+     *         non-interfaces or incompatible combinations, and verify is true
+     * @throws NullPointerException if interfaces is null or contains null
+     */
+    static ProxyData getProxyData(ProxyType pt)
+    {
+      Map method_set = (Map) ProxySignature.coreMethods.clone();
+      boolean in_package = false; // true if we encounter non-public interface
+
+      ProxyData data = new ProxyData();
+      data.interfaces = pt.interfaces;
+
+      // if interfaces is too large, we croak later on when the constant
+      // pool overflows
+      int i = data.interfaces.length;
+      while (--i >= 0)
+        {
+          Class inter = data.interfaces[i];
+          if (! inter.isInterface())
+            throw new IllegalArgumentException("not an interface: " + inter);
+          try
+            {
+              if (Class.forName(inter.getName(), false, pt.loader) != inter)
+                throw new IllegalArgumentException("not accessible in "
+                                                   + "classloader: " + inter);
+            }
+          catch (ClassNotFoundException e)
+            {
+              throw new IllegalArgumentException("not accessible in "
+                                                 + "classloader: " + inter);
+            }
+          if (! Modifier.isPublic(inter.getModifiers()))
+            if (in_package)
+              {
+                Package p = inter.getPackage();
+                if (data.pack != inter.getPackage())
+                  throw new IllegalArgumentException("non-public interfaces "
+                                                     + "from different "
+                                                     + "packages");
+              }
+            else
+              {
+                in_package = true;
+                data.pack = inter.getPackage();
+              }
+          for (int j = i-1; j >= 0; j--)
+            if (data.interfaces[j] == inter)
+              throw new IllegalArgumentException("duplicate interface: "
+                                                 + inter);
+          Method[] methods = inter.getMethods();
+          int j = methods.length;
+          while (--j >= 0)
+            {
+              ProxySignature sig = new ProxySignature(methods[j]);
+              ProxySignature old = (ProxySignature) method_set.put(sig, sig);
+              if (old != null)
+                sig.checkCompatibility(old);
+            }
+        }
+
+      i = method_set.size();
+      data.methods = new Method[i];
+      data.exceptions = new Class[i][];
+      Iterator itr = method_set.values().iterator();
+      while (--i >= 0)
+        {
+          ProxySignature sig = (ProxySignature) itr.next();
+          data.methods[i] = sig.method;
+          data.exceptions[i] = (Class[]) sig.exceptions
+            .toArray(new Class[sig.exceptions.size()]);
+        }
+      return data;
+    }
+  } // class ProxyData
+
+  /**
+   * Does all the work of building a class. By making this a nested class,
+   * this code is not loaded in memory if the VM has a native
+   * implementation instead.
+   *
+   * @author Eric Blake <ebb9@email.byu.edu>
+   */
+  private static final class ClassFactory
+  {
+    /** Constants for assisting the compilation */
+    private static final byte POOL = 0;
+    private static final byte FIELD = 1;
+    private static final byte METHOD = 2;
+    private static final byte INTERFACE = 3;
+    private static final String CTOR_SIG
+      = "(Ljava/lang/reflect/InvocationHandler;)V";
+    private static final String INVOKE_SIG = "(Ljava/lang/Object;"
+      + "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;";
+
+    /** Bytecodes for insertion in the class definition byte[] */
+    private static final char ACONST_NULL = 1;
+    private static final char ICONST_0 = 3;
+    private static final char BIPUSH = 16;
+    private static final char SIPUSH = 17;
+    private static final char ILOAD = 21;
+    private static final char ILOAD_0 = 26;
+    private static final char ALOAD_0 = 42;
+    private static final char ALOAD_1 = 43;
+    private static final char AALOAD = 50;
+    private static final char AASTORE = 83;
+    private static final char DUP = 89;
+    private static final char DUP_X1 = 90;
+    private static final char SWAP = 95;
+    private static final char IRETURN = 172;
+    private static final char LRETURN = 173;
+    private static final char FRETURN = 174;
+    private static final char DRETURN = 175;
+    private static final char ARETURN = 176;
+    private static final char RETURN = 177;
+    private static final char GETSTATIC = 178;
+    private static final char GETFIELD = 180;
+    private static final char INVOKEVIRTUAL = 182;
+    private static final char INVOKESPECIAL = 183;
+    private static final char INVOKESTATIC = 184;
+    private static final char INVOKEINTERFACE = 185;
+    private static final char NEW = 187;
+    private static final char ANEWARRAY = 189;
+    private static final char ATHROW = 191;
+    private static final char CHECKCAST = 192;
+
+    // Implementation note: we use StringBuffers to hold the byte data, since
+    // they automatically grow.  However, we only use the low 8 bits of
+    // every char in the array, so we are using twice the necessary memory
+    // for the ease StringBuffer provides.
+
+    /** The constant pool. */
+    private final StringBuffer pool = new StringBuffer();
+    /** The rest of the class data. */
+    private final StringBuffer stream = new StringBuffer();
+
+    /** Map of strings to byte sequences, to minimize size of pool. */
+    private final Map poolEntries = new HashMap();
+
+    /** The VM name of this proxy class. */
+    private final String qualName;
+
+    /**
+     * The Method objects the proxy class refers to when calling the
+     * invocation handler.
+     */
+    private final Method[] methods;
+
+    /**
+     * Initializes the buffers with the bytecode contents for a proxy class.
+     *
+     * @param data the remainder of the class data
+     * @throws IllegalArgumentException if anything else goes wrong this
+     *         late in the game; as far as I can tell, this will only happen
+     *         if the constant pool overflows, which is possible even when
+     *         the user doesn't exceed the 65535 interface limit
+     */
+    ClassFactory(ProxyData data)
+    {
+      methods = data.methods;
+
+      // magic = 0xcafebabe
+      // minor_version = 0
+      // major_version = 46
+      // constant_pool_count: place-holder for now
+      pool.append("\u00ca\u00fe\u00ba\u00be\0\0\0\56\0\0");
+      // constant_pool[], filled in as we go
+
+      // access_flags
+      putU2(Modifier.SUPER | Modifier.FINAL | Modifier.PUBLIC);
+      // this_class
+      qualName = ((data.pack == null ? "" : data.pack.getName() + '.')
+                  + "$Proxy" + data.id);
+      putU2(classInfo(TypeSignature.getEncodingOfClass(qualName, false)));
+      // super_class
+      putU2(classInfo("java/lang/reflect/Proxy"));
+
+      // interfaces_count
+      putU2(data.interfaces.length);
+      // interfaces[]
+      for (int i = 0; i < data.interfaces.length; i++)
+        putU2(classInfo(data.interfaces[i]));
+
+      // Recall that Proxy classes serialize specially, so we do not need
+      // to worry about a <clinit> method for this field.  Instead, we
+      // just assign it by reflection after the class is successfully loaded.
+      // fields_count - private static Method[] m;
+      putU2(1);
+      // fields[]
+      // m.access_flags
+      putU2(Modifier.PRIVATE | Modifier.STATIC);
+      // m.name_index
+      putU2(utf8Info("m"));
+      // m.descriptor_index
+      putU2(utf8Info("[Ljava/lang/reflect/Method;"));
+      // m.attributes_count
+      putU2(0);
+      // m.attributes[]
+
+      // methods_count - # handler methods, plus <init>
+      putU2(methods.length + 1);
+      // methods[]
+      // <init>.access_flags
+      putU2(Modifier.PUBLIC);
+      // <init>.name_index
+      putU2(utf8Info("<init>"));
+      // <init>.descriptor_index
+      putU2(utf8Info(CTOR_SIG));
+      // <init>.attributes_count - only Code is needed
+      putU2(1);
+      // <init>.Code.attribute_name_index
+      putU2(utf8Info("Code"));
+      // <init>.Code.attribute_length = 18
+      // <init>.Code.info:
+      //   $Proxynn(InvocationHandler h) { super(h); }
+      // <init>.Code.max_stack = 2
+      // <init>.Code.max_locals = 2
+      // <init>.Code.code_length = 6
+      // <init>.Code.code[]
+      stream.append("\0\0\0\22\0\2\0\2\0\0\0\6" + ALOAD_0 + ALOAD_1
+                    + INVOKESPECIAL);
+      putU2(refInfo(METHOD, "java/lang/reflect/Proxy", "<init>", CTOR_SIG));
+      // <init>.Code.exception_table_length = 0
+      // <init>.Code.exception_table[]
+      // <init>.Code.attributes_count = 0
+      // <init>.Code.attributes[]
+      stream.append(RETURN + "\0\0\0\0");
+
+      for (int i = methods.length - 1; i >= 0; i--)
+        emitMethod(i, data.exceptions[i]);
+
+      // attributes_count
+      putU2(0);
+      // attributes[] - empty; omit SourceFile attribute
+      // XXX should we mark this with a Synthetic attribute?
+    }
+
+    /**
+     * Produce the bytecode for a single method.
+     *
+     * @param i the index of the method we are building
+     * @param e the exceptions possible for the method
+     */
+    private void emitMethod(int i, Class[] e)
+    {
+      // First, we precalculate the method length and other information.
+
+      Method m = methods[i];
+      Class[] paramtypes = m.getParameterTypes();
+      int wrap_overhead = 0; // max words taken by wrapped primitive
+      int param_count = 1; // 1 for this
+      int code_length = 16; // aload_0, getfield, aload_0, getstatic, const,
+      // aaload, const/aconst_null, invokeinterface
+      if (i > 5)
+        {
+          if (i > Byte.MAX_VALUE)
+            code_length += 2; // sipush
+          else
+            code_length++; // bipush
+        }
+      if (paramtypes.length > 0)
+        {
+          code_length += 3; // anewarray
+          if (paramtypes.length > Byte.MAX_VALUE)
+            code_length += 2; // sipush
+          else if (paramtypes.length > 5)
+            code_length++; // bipush
+          for (int j = 0; j < paramtypes.length; j++)
+            {
+              code_length += 4; // dup, const, load, store
+              Class type = paramtypes[j];
+              if (j > 5)
+                {
+                  if (j > Byte.MAX_VALUE)
+                    code_length += 2; // sipush
+                  else
+                    code_length++; // bipush
+                }
+              if (param_count >= 4)
+                code_length++; // 2-byte load
+              param_count++;
+              if (type.isPrimitive())
+                {
+                  code_length += 7; // new, dup, invokespecial
+                  if (type == long.class || type == double.class)
+                    {
+                      wrap_overhead = 3;
+                      param_count++;
+                    }
+                  else if (wrap_overhead < 2)
+                    wrap_overhead = 2;
+                }
+            }
+        }
+      int end_pc = code_length;
+      Class ret_type = m.getReturnType();
+      if (ret_type == void.class)
+        code_length++; // return
+      else if (ret_type.isPrimitive())
+        code_length += 7; // cast, invokevirtual, return
+      else
+        code_length += 4; // cast, return
+      int exception_count = 0;
+      boolean throws_throwable = false;
+      for (int j = 0; j < e.length; j++)
+        if (e[j] == Throwable.class)
+          {
+            throws_throwable = true;
+            break;
+          }
+      if (! throws_throwable)
+        {
+          exception_count = e.length + 3; // Throwable, Error, RuntimeException
+          code_length += 9; // new, dup_x1, swap, invokespecial, athrow
+        }
+      int handler_pc = code_length - 1;
+      StringBuffer signature = new StringBuffer("(");
+      for (int j = 0; j < paramtypes.length; j++)
+        signature.append(TypeSignature.getEncodingOfClass(paramtypes[j]));
+      signature.append(")").append(TypeSignature.getEncodingOfClass(ret_type));
+
+      // Now we have enough information to emit the method.
+
+      // handler.access_flags
+      putU2(Modifier.PUBLIC | Modifier.FINAL);
+      // handler.name_index
+      putU2(utf8Info(m.getName()));
+      // handler.descriptor_index
+      putU2(utf8Info(signature.toString()));
+      // handler.attributes_count - Code is necessary, Exceptions possible
+      putU2(e.length > 0 ? 2 : 1);
+
+      // handler.Code.info:
+      //   type name(args) {
+      //     try {
+      //       return (type) h.invoke(this, methods[i], new Object[] {args});
+      //     } catch (<declared Exceptions> e) {
+      //       throw e;
+      //     } catch (Throwable t) {
+      //       throw new UndeclaredThrowableException(t);
+      //     }
+      //   }
+      // Special cases:
+      //  if arg_n is primitive, wrap it
+      //  if method throws Throwable, try-catch is not needed
+      //  if method returns void, return statement not needed
+      //  if method returns primitive, unwrap it
+      //  save space by sharing code for all the declared handlers
+
+      // handler.Code.attribute_name_index
+      putU2(utf8Info("Code"));
+      // handler.Code.attribute_length
+      putU4(12 + code_length + 8 * exception_count);
+      // handler.Code.max_stack
+      putU2(param_count == 1 ? 4 : 7 + wrap_overhead);
+      // handler.Code.max_locals
+      putU2(param_count);
+      // handler.Code.code_length
+      putU4(code_length);
+      // handler.Code.code[]
+      putU1(ALOAD_0);
+      putU1(GETFIELD);
+      putU2(refInfo(FIELD, "java/lang/reflect/Proxy", "h",
+                    "Ljava/lang/reflect/InvocationHandler;"));
+      putU1(ALOAD_0);
+      putU1(GETSTATIC);
+      putU2(refInfo(FIELD, TypeSignature.getEncodingOfClass(qualName, false),
+                    "m", "[Ljava/lang/reflect/Method;"));
+      putConst(i);
+      putU1(AALOAD);
+      if (paramtypes.length > 0)
+        {
+          putConst(paramtypes.length);
+          putU1(ANEWARRAY);
+          putU2(classInfo("java/lang/Object"));
+          param_count = 1;
+          for (int j = 0; j < paramtypes.length; j++, param_count++)
+            {
+              putU1(DUP);
+              putConst(j);
+              if (paramtypes[j].isPrimitive())
+                {
+                  putU1(NEW);
+                  putU2(classInfo(wrapper(paramtypes[j])));
+                  putU1(DUP);
+                }
+              putLoad(param_count, paramtypes[j]);
+              if (paramtypes[j].isPrimitive())
+                {
+                  putU1(INVOKESPECIAL);
+                  putU2(refInfo(METHOD, wrapper(paramtypes[j]), "<init>",
+                                '(' + (TypeSignature
+                                       .getEncodingOfClass(paramtypes[j])
+                                       + ")V")));
+                  if (paramtypes[j] == long.class
+                      || paramtypes[j] == double.class)
+                    param_count++;
+                }
+              putU1(AASTORE);
+            }
+        }
+      else
+        putU1(ACONST_NULL);
+      putU1(INVOKEINTERFACE);
+      putU2(refInfo(INTERFACE, "java/lang/reflect/InvocationHandler",
+                    "invoke", INVOKE_SIG));
+      putU1(4); // InvocationHandler, this, Method, Object[]
+      putU1(0);
+      if (ret_type == void.class)
+        putU1(RETURN);
+      else if (ret_type.isPrimitive())
+        {
+          putU1(CHECKCAST);
+          putU2(classInfo(wrapper(ret_type)));
+          putU1(INVOKEVIRTUAL);
+          putU2(refInfo(METHOD, wrapper(ret_type),
+                        ret_type.getName() + "Value",
+                        "()" + TypeSignature.getEncodingOfClass(ret_type)));
+          if (ret_type == long.class)
+            putU1(LRETURN);
+          else if (ret_type == float.class)
+            putU1(FRETURN);
+          else if (ret_type == double.class)
+            putU1(DRETURN);
+          else
+            putU1(IRETURN);
+        }
+      else
+        {
+          putU1(CHECKCAST);
+          putU2(classInfo(ret_type));
+          putU1(ARETURN);
+        }
+      if (! throws_throwable)
+        {
+          putU1(NEW);
+          putU2(classInfo("java/lang/reflect/UndeclaredThrowableException"));
+          putU1(DUP_X1);
+          putU1(SWAP);
+          putU1(INVOKESPECIAL);
+          putU2(refInfo(METHOD,
+                        "java/lang/reflect/UndeclaredThrowableException",
+                        "<init>", "(Ljava/lang/Throwable;)V"));
+          putU1(ATHROW);
+        }
+
+      // handler.Code.exception_table_length
+      putU2(exception_count);
+      // handler.Code.exception_table[]
+      if (! throws_throwable)
+        {
+          // handler.Code.exception_table.start_pc
+          putU2(0);
+          // handler.Code.exception_table.end_pc
+          putU2(end_pc);
+          // handler.Code.exception_table.handler_pc
+          putU2(handler_pc);
+          // handler.Code.exception_table.catch_type
+          putU2(classInfo("java/lang/Error"));
+          // handler.Code.exception_table.start_pc
+          putU2(0);
+          // handler.Code.exception_table.end_pc
+          putU2(end_pc);
+          // handler.Code.exception_table.handler_pc
+          putU2(handler_pc);
+          // handler.Code.exception_table.catch_type
+          putU2(classInfo("java/lang/RuntimeException"));
+          for (int j = 0; j < e.length; j++)
+            {
+              // handler.Code.exception_table.start_pc
+              putU2(0);
+              // handler.Code.exception_table.end_pc
+              putU2(end_pc);
+              // handler.Code.exception_table.handler_pc
+              putU2(handler_pc);
+              // handler.Code.exception_table.catch_type
+              putU2(classInfo(e[j]));
+            }
+          // handler.Code.exception_table.start_pc
+          putU2(0);
+          // handler.Code.exception_table.end_pc
+          putU2(end_pc);
+          // handler.Code.exception_table.handler_pc -
+          //   -8 for undeclared handler, which falls thru to normal one
+          putU2(handler_pc - 8);
+          // handler.Code.exception_table.catch_type
+          putU2(0);
+        }
+      // handler.Code.attributes_count
+      putU2(0);
+      // handler.Code.attributes[]
+
+      if (e.length > 0)
+        {
+          // handler.Exceptions.attribute_name_index
+          putU2(utf8Info("Exceptions"));
+          // handler.Exceptions.attribute_length
+          putU4(2 * e.length + 2);
+          // handler.Exceptions.number_of_exceptions
+          putU2(e.length);
+          // handler.Exceptions.exception_index_table[]
+          for (int j = 0; j < e.length; j++)
+            putU2(classInfo(e[j]));
+        }
+    }
+
+    /**
+     * Creates the Class object that corresponds to the bytecode buffers
+     * built when this object was constructed.
+     *
+     * @param loader the class loader to define the proxy class in; null
+     *        implies the bootstrap class loader
+     * @return the proxy class Class object
+     */
+    final Class generate(ClassLoader loader)
+    {
+      byte[] bytecode = new byte[pool.length() + stream.length()];
+      // More efficient to bypass calling charAt() repetitively.
+      char[] c = pool.toString().toCharArray();
+      int i = c.length;
+      while (--i >= 0)
+        bytecode[i] = (byte) c[i];
+      c = stream.toString().toCharArray();
+      i = c.length;
+      int j = bytecode.length;
+      while (i > 0)
+        bytecode[--j] = (byte) c[--i];
+
+      // Patch the constant pool size, which we left at 0 earlier.
+      int count = poolEntries.size() + 1;
+      bytecode[8] = (byte) (count >> 8);
+      bytecode[9] = (byte) count;
+
+      try
+        {
+          // XXX Do we require more native support here?
+
+          // XXX Security hole - it is possible for another thread to grab the
+          // VMClassLoader.defineClass Method object, and abuse it while we
+          // have temporarily made it accessible. Do we need to add some
+          // synchronization lock to prevent user reflection while we use it?
+
+          // XXX This is waiting on VM support for protection domains.
+
+          Class vmClassLoader = Class.forName("java.lang.ClassLoader");
+          Class[] types = {String.class,
+                           byte[].class, int.class, int.class,
+                           /* ProtectionDomain.class */ };
+          Method m = vmClassLoader.getDeclaredMethod("defineClass", types);
+
+          // Bypass the security check of setAccessible(true), since this
+          // is trusted code. But note the comment above about the security
+          // risk of doing this outside a synchronized block.
+          m.setAccessible(true);
+          Object[] args = {qualName, bytecode, new Integer(0),
+                           new Integer(bytecode.length),
+                           /* Object.class.getProtectionDomain() */ };
+          Class clazz = (Class) m.invoke(loader, args);
+          m.setAccessible(false);
+
+          // Finally, initialize the m field of the proxy class, before
+          // returning it.
+
+          // No security risk here, since clazz has not been exposed yet,
+          // so user code cannot grab the same reflection object.
+          Field f = clazz.getDeclaredField("m");
+          f.setAccessible(true);
+          // we can share the array, because it is not publicized
+          f.set(null, methods);
+          f.setAccessible(false);
+
+          return clazz;
+        }
+      catch (Throwable e)
+        {
+          // assert false;
+          throw (Error) new InternalError("Unexpected: " + e).initCause(e);
+        }
+    }
+
+    /**
+     * Put a single byte on the stream.
+     *
+     * @param i the information to add (only lowest 8 bits are used)
+     */
+    private void putU1(int i)
+    {
+      stream.append((char) i);
+    }
+
+    /**
+     * Put two bytes on the stream.
+     *
+     * @param i the information to add (only lowest 16 bits are used)
+     */
+    private void putU2(int i)
+    {
+      stream.append((char) (i >> 8)).append((char) i);
+    }
+
+    /**
+     * Put four bytes on the stream.
+     *
+     * @param i the information to add (treated as unsigned)
+     */
+    private void putU4(int i)
+    {
+      stream.append((char) (i >> 24)).append((char) (i >> 16));
+      stream.append((char) (i >> 8)).append((char) i);
+    }
+
+    /**
+     * Put bytecode to load a constant integer on the stream. This only
+     * needs to work for values less than Short.MAX_VALUE.
+     *
+     * @param i the int to add
+     */
+    private void putConst(int i)
+    {
+      if (i >= -1 && i <= 5)
+        putU1(ICONST_0 + i);
+      else if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE)
+        {
+          putU1(BIPUSH);
+          putU1(i);
+        }
+      else
+        {
+          putU1(SIPUSH);
+          putU2(i);
+        }
+    }
+
+    /**
+     * Put bytecode to load a given local variable on the stream.
+     *
+     * @param i the slot to load
+     * @param type the base type of the load
+     */
+    private void putLoad(int i, Class type)
+    {
+      int offset = 0;
+      if (type == long.class)
+        offset = 1;
+      else if (type == float.class)
+        offset = 2;
+      else if (type == double.class)
+        offset = 3;
+      else if (! type.isPrimitive())
+        offset = 4;
+      if (i < 4)
+        putU1(ILOAD_0 + 4 * offset + i);
+      else
+        {
+          putU1(ILOAD + offset);
+          putU1(i);
+        }
+    }
+
+    /**
+     * Given a primitive type, return its wrapper class name.
+     *
+     * @param clazz the primitive type (but not void.class)
+     * @return the internal form of the wrapper class name
+     */
+    private String wrapper(Class clazz)
+    {
+      if (clazz == boolean.class)
+        return "java/lang/Boolean";
+      if (clazz == byte.class)
+        return "java/lang/Byte";
+      if (clazz == short.class)
+        return "java/lang/Short";
+      if (clazz == char.class)
+        return "java/lang/Character";
+      if (clazz == int.class)
+        return "java/lang/Integer";
+      if (clazz == long.class)
+        return "java/lang/Long";
+      if (clazz == float.class)
+        return "java/lang/Float";
+      if (clazz == double.class)
+        return "java/lang/Double";
+      // assert false;
+      return null;
+    }
+
+    /**
+     * Returns the entry of this String in the Constant pool, adding it
+     * if necessary.
+     *
+     * @param str the String to resolve
+     * @return the index of the String in the constant pool
+     */
+    private char utf8Info(String str)
+    {
+      String utf8 = toUtf8(str);
+      int len = utf8.length();
+      return poolIndex("\1" + (char) (len >> 8) + (char) (len & 0xff) + utf8);
+    }
+
+    /**
+     * Returns the entry of the appropriate class info structure in the
+     * Constant pool, adding it if necessary.
+     *
+     * @param name the class name, in internal form
+     * @return the index of the ClassInfo in the constant pool
+     */
+    private char classInfo(String name)
+    {
+      char index = utf8Info(name);
+      char[] c = {7, (char) (index >> 8), (char) (index & 0xff)};
+      return poolIndex(new String(c));
+    }
+
+    /**
+     * Returns the entry of the appropriate class info structure in the
+     * Constant pool, adding it if necessary.
+     *
+     * @param clazz the class type
+     * @return the index of the ClassInfo in the constant pool
+     */
+    private char classInfo(Class clazz)
+    {
+      return classInfo(TypeSignature.getEncodingOfClass(clazz.getName(),
+                                                        false));
+    }
+
+    /**
+     * Returns the entry of the appropriate fieldref, methodref, or
+     * interfacemethodref info structure in the Constant pool, adding it
+     * if necessary.
+     *
+     * @param structure FIELD, METHOD, or INTERFACE
+     * @param clazz the class name, in internal form
+     * @param name the simple reference name
+     * @param type the type of the reference
+     * @return the index of the appropriate Info structure in the constant pool
+     */
+    private char refInfo(byte structure, String clazz, String name,
+                         String type)
+    {
+      char cindex = classInfo(clazz);
+      char ntindex = nameAndTypeInfo(name, type);
+      // relies on FIELD == 1, METHOD == 2, INTERFACE == 3
+      char[] c = {(char) (structure + 8),
+                  (char) (cindex >> 8), (char) (cindex & 0xff),
+                  (char) (ntindex >> 8), (char) (ntindex & 0xff)};
+      return poolIndex(new String(c));
+    }
+
+    /**
+     * Returns the entry of the appropriate nameAndTyperef info structure
+     * in the Constant pool, adding it if necessary.
+     *
+     * @param name the simple name
+     * @param type the reference type
+     * @return the index of the NameAndTypeInfo structure in the constant pool
+     */
+    private char nameAndTypeInfo(String name, String type)
+    {
+      char nindex = utf8Info(name);
+      char tindex = utf8Info(type);
+      char[] c = {12, (char) (nindex >> 8), (char) (nindex & 0xff),
+                  (char) (tindex >> 8), (char) (tindex & 0xff)};
+      return poolIndex(new String(c));
+    }
+
+    /**
+     * Converts a regular string to a UTF8 string, where the upper byte
+     * of every char is 0, and '\\u0000' is not in the string.  This is
+     * basically to use a String as a fancy byte[], and while it is less
+     * efficient in memory use, it is easier for hashing.
+     *
+     * @param str the original, in straight unicode
+     * @return a modified string, in UTF8 format in the low bytes
+     */
+    private String toUtf8(String str)
+    {
+      final char[] ca = str.toCharArray();
+      final int len = ca.length;
+
+      // Avoid object creation, if str is already fits UTF8.
+      int i;
+      for (i = 0; i < len; i++)
+        if (ca[i] == 0 || ca[i] > '\u007f')
+          break;
+      if (i == len)
+        return str;
+
+      final StringBuffer sb = new StringBuffer(str);
+      sb.setLength(i);
+      for ( ; i < len; i++)
+        {
+          final char c = ca[i];
+          if (c > 0 && c <= '\u007f')
+            sb.append(c);
+          else if (c <= '\u07ff') // includes '\0'
+            {
+              sb.append((char) (0xc0 | (c >> 6)));
+              sb.append((char) (0x80 | (c & 0x6f)));
+            }
+          else
+            {
+              sb.append((char) (0xe0 | (c >> 12)));
+              sb.append((char) (0x80 | ((c >> 6) & 0x6f)));
+              sb.append((char) (0x80 | (c & 0x6f)));
+            }
+        }
+      return sb.toString();
     }
 
-    public static InvocationHandler getInvocationHandler(Object proxy)
-	throws IllegalArgumentException
+    /**
+     * Returns the location of a byte sequence (conveniently wrapped in
+     * a String with all characters between \u0001 and \u00ff inclusive)
+     * in the constant pool, adding it if necessary.
+     *
+     * @param sequence the byte sequence to look for
+     * @return the index of the sequence
+     * @throws IllegalArgumentException if this would make the constant
+     *         pool overflow
+     */
+    private char poolIndex(String sequence)
     {
-	throw new kaffe.util.NotImplemented("java.lang.reflect.Proxy");
+      Integer i = (Integer) poolEntries.get(sequence);
+      if (i == null)
+        {
+          // pool starts at index 1
+          int size = poolEntries.size() + 1;
+          if (size >= 65535)
+            throw new IllegalArgumentException("exceeds VM limitations");
+          i = new Integer(size);
+          poolEntries.put(sequence, i);
+          pool.append(sequence);
+        }
+      return (char) i.intValue();
     }
+  } // class ClassFactory
 }
diff -urN -x CVS /HG/hiwis/topic/PROJECTS/kaffe/libraries/javalib/java/net/URLClassLoader.java kaffe/libraries/javalib/java/net/URLClassLoader.java
--- /HG/hiwis/topic/PROJECTS/kaffe/libraries/javalib/java/net/URLClassLoader.java	Tue May 20 15:24:56 2003
+++ kaffe/libraries/javalib/java/net/URLClassLoader.java	Tue May 20 16:44:01 2003
@@ -54,11 +54,15 @@
 		this.urls = new Vector();
 		this.factory = factory;
 		for (int i = 0; i < urls.length; i++) {
-			addURL(urls[i]);
+			internalAddURL(urls[i]);
 		}
 	}
 
 	protected void addURL(URL url) {
+		internalAddURL(url);
+	}
+
+	private void internalAddURL(URL url) {
 		urls.addElement(url);
 	}
 

--0-614432395-1053445396=:87251--