2021-07-16 17:12:20 -05:00

183 lines
5.8 KiB
Java

/*
* @(#) $(JCGO)/goclsp/vm/java/lang/reflect/VMProxy.java --
* VM specific methods for Java class "Proxy" implementation.
**
* Project: JCGO (http://www.ivmaisoft.com/jcgo/)
* Copyright (C) 2001-2007 Ivan Maidanski <ivmai@ivmaisoft.com>
* All rights reserved.
**
* Class specification origin: GNU Classpath v0.93 vm/reference
*/
/*
* This 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.
**
* This software 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 (GPL) for more details.
**
* 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;
final class VMProxy
{
static final boolean HAVE_NATIVE_GET_PROXY_CLASS = true;
static boolean HAVE_NATIVE_GET_PROXY_DATA = false;
static boolean HAVE_NATIVE_GENERATE_PROXY_CLASS = true;
private VMProxy() {}
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
{
return generateProxyClass(loader,
checkAndComputePkgName(loader, interfaces), interfaces);
}
static Proxy.ProxyData getProxyData(ClassLoader loader, Class[] interfaces)
{
/* dummy */
throw new InternalError();
}
static Class generateProxyClass(ClassLoader loader, Proxy.ProxyData data)
{
return generateProxyClass(loader, data.pack, data.interfaces);
}
static final Object invokeProxyHandler0X(Object proxyObj,
Class declaringClass, int[] intArgs, long[] longArgs, float[] floatArgs,
double[] doubleArgs, Object[] objectArgs, int slot, int proxySlot)
throws Throwable /* hard-coded method signature */
{ /* called from native code */
Proxy proxy = (Proxy) proxyObj;
InvocationHandler handler = proxy.h;
if (handler == null)
throw new NullPointerException();
return VMMethod.invokeProxyHandler(handler, proxy, declaringClass, intArgs,
longArgs, floatArgs, doubleArgs, objectArgs, slot, proxySlot);
}
private static String checkAndComputePkgName(ClassLoader loader,
Class[] interfaces)
{
String packageName = null;
int i = interfaces.length;
while (i-- > 0)
{
Class iface = interfaces[i];
String ifaceName = iface.getName();
if (!iface.isInterface())
throw new IllegalArgumentException("not an interface: " + ifaceName);
Class aclass = null;
try
{
aclass = Class.forName(ifaceName, false, loader);
}
catch (ClassNotFoundException e) {}
if (aclass != iface)
throw new IllegalArgumentException(
"interface not accessible in classloader: " + ifaceName);
if ((iface.getModifiers() & Modifier.PUBLIC) == 0)
{
String pkgName = ifaceName.substring(0, ifaceName.lastIndexOf('.') + 1);
if (packageName != null)
{
if (!packageName.equals(pkgName))
throw new IllegalArgumentException(
"non-public interfaces from different packages: " + ifaceName);
}
else packageName = pkgName;
}
for (int j = 0; j < i; j++)
if (interfaces[j] == iface)
throw new IllegalArgumentException("duplicate interface: " + ifaceName);
/* check for methods return type not implemented */
}
return packageName != null ? packageName : "";
}
private static Class generateProxyClass(ClassLoader loader,
String packageName, Class[] interfaces)
{
if (interfaces == null) /* hack */
{
try
{
invokeProxyHandler0X(new Proxy(null), null, null, null, null, null, null,
-1, -1); /* hack */
}
catch (Throwable e) {}
}
String proxyClassName = makeProxyClassName(packageName, interfaces);
if (loader == null)
loader = ClassLoader.getSystemClassLoader();
try
{
return loader.loadClass(proxyClassName);
}
catch (ClassNotFoundException e) {}
throw new OutOfMemoryError("cannot create proxy class for: " +
ifacesToString(interfaces));
}
private static String makeProxyClassName(String packageName,
Class[] interfaces)
{
StringBuilder sb = new StringBuilder();
sb.append(packageName).append("$Proxy");
int count = interfaces.length;
for (int i = 0; i < count; i++)
{
String name = interfaces[i].getName();
int pos = -1;
while ((pos = name.indexOf('$', pos + 1) + 1) > 0)
name = name.substring(0, pos) + "$" + name.substring(pos);
sb.append("$00");
int next;
while ((next = name.indexOf('.', pos)) >= 0)
{
sb.append(name.substring(pos, next)).append("$0");
pos = next + 1;
}
sb.append(name.substring(pos));
}
return sb.toString();
}
private static String ifacesToString(Class[] interfaces)
{
int count = interfaces.length;
if (count == 0)
return "<no interfaces>";
StringBuilder sb = new StringBuilder();
sb.append(interfaces[0].getName());
for (int i = 1; i < count; i++)
sb.append(", ").append(interfaces[i].getName());
return sb.toString();
}
}