proxy.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 1,490 行 · 第 1/4 页

JAVA
1,490
字号
			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.VMClassLoader");
				Class[] types = { ClassLoader.class, 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.flag = true;
				Object[] args = { loader, qualName, bytecode, new Integer(0), new Integer(bytecode.length),
					/* Object.class.getProtectionDomain() */
				};
				Class clazz = (Class) m.invoke(null, args);
				m.flag = 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.flag = true;
				// we can share the array, because it is not publicized
				f.set(null, methods);
				f.flag = 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();
		}

		/**
		 * 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) {
			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
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?