📄 proxy.java
字号:
// 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 */ 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 { 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); // We can bypass the security check of setAccessible(true), since // we're in the same package. 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); // Finally, initialize the m field of the proxy class, before // returning it. Field f = clazz.getDeclaredField("m"); f.flag = true; // we can share the array, because it is not publicized f.set(null, methods); return clazz; } catch (Exception 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -