proxy.java
来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 1,490 行 · 第 1/4 页
JAVA
1,490 行
// 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);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?