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 + -
显示快捷键?