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