Java ASM系列:(038)GeneratorAdapter介绍

本文属于[Java ASM系列一:Core API](https://blog.51cto.com/lsieun/2924583)当中的一篇。 对于`GeneratorAdapter`类来说,它非常重要的一个特点:将一些`visitXxxInsn()`方法封装成一些常用的方法。 ## 1. GeneratorAdapter类 ### 1.1 class info 第一个部分,`GeneratorAdapter`类继承自`LocalVariablesSorter`类。 - org.objectweb.asm.MethodVisitor - org.objectweb.asm.commons.LocalVariablesSorter - org.objectweb.asm.commons.GeneratorAdapter - org.objectweb.asm.commons.AdviceAdapter ```java public class GeneratorAdapter extends LocalVariablesSorter { } ``` ### 1.2 fields 第二个部分,`GeneratorAdapter`类定义的字段有哪些。 ```java public class GeneratorAdapter extends LocalVariablesSorter { private final int access; private final String name; private final Type returnType; private final Type[] argumentTypes; } ``` ### 1.3 constructors 第三个部分,`GeneratorAdapter`类定义的构造方法有哪些。 ```java public class GeneratorAdapter extends LocalVariablesSorter { public GeneratorAdapter(final MethodVisitor methodVisitor, final int access, final String name, final String descriptor) { this(Opcodes.ASM9, methodVisitor, access, name, descriptor); } protected GeneratorAdapter(final int api, final MethodVisitor methodVisitor, final int access, final String name, final String descriptor) { super(api, access, descriptor, methodVisitor); this.access = access; this.name = name; this.returnType = Type.getReturnType(descriptor); this.argumentTypes = Type.getArgumentTypes(descriptor); } } ``` ### 1.4 methods 第四个部分,`GeneratorAdapter`类定义的方法有哪些。 ```java public class GeneratorAdapter extends LocalVariablesSorter { public int getAccess() { return access; } public String getName() { return name; } public Type getReturnType() { return returnType; } public Type[] getArgumentTypes() { return argumentTypes.clone(); } } ``` ## 2. 特殊方法举例 `GeneratorAdapter`类的特点是将一些`visitXxxInsn()`方法封装成一些常用的方法。在这里,我们给大家举几个有代表性的例子,更多的方法可以参考`GeneratorAdapter`类的源码。 ### 2.1 loadThis 在`GeneratorAdapter`类当中,`loadThis()`方法的本质是`mv.visitVarInsn(Opcodes.ALOAD, 0)`;但是,要注意static方法并不需要`this`变量。 ```java public class GeneratorAdapter extends LocalVariablesSorter { public void loadThis() { if ((access & Opcodes.ACC_STATIC) != 0) { // 注意,静态方法没有this throw new IllegalStateException("no 'this' pointer within static method"); } mv.visitVarInsn(Opcodes.ALOAD, 0); } } ``` ### 2.2 arg 在`GeneratorAdapter`类当中,定义了一些与方法参数相关的方法。 ```java public class GeneratorAdapter extends LocalVariablesSorter { private int getArgIndex(final int arg) { int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0; for (int i = 0; i < arg; i++) { index += argumentTypes[i].getSize(); } return index; } private void loadInsn(final Type type, final int index) { mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index); } private void storeInsn(final Type type, final int index) { mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index); } public void loadArg(final int arg) { loadInsn(argumentTypes[arg], getArgIndex(arg)); } public void loadArgs(final int arg, final int count) { int index = getArgIndex(arg); for (int i = 0; i < count; ++i) { Type argumentType = argumentTypes[arg + i]; loadInsn(argumentType, index); index += argumentType.getSize(); } } public void loadArgs() { loadArgs(0, argumentTypes.length); } public void loadArgArray() { push(argumentTypes.length); newArray(OBJECT_TYPE); for (int i = 0; i < argumentTypes.length; i++) { dup(); push(i); loadArg(i); box(argumentTypes[i]); arrayStore(OBJECT_TYPE); } } public void storeArg(final int arg) { storeInsn(argumentTypes[arg], getArgIndex(arg)); } } ``` ### 2.3 boxing and unboxing 在`GeneratorAdapter`类当中,定义了一些与boxing和unboxing相关的操作。 ```java public class GeneratorAdapter extends LocalVariablesSorter { public void box(final Type type) { if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { return; } if (type == Type.VOID_TYPE) { push((String) null); } else { Type boxedType = getBoxedType(type); newInstance(boxedType); if (type.getSize() == 2) { dupX2(); dupX2(); pop(); } else { dupX1(); swap(); } invokeConstructor(boxedType, new Method("", Type.VOID_TYPE, new Type[] {type})); } } public void unbox(final Type type) { Type boxedType = NUMBER_TYPE; Method unboxMethod; switch (type.getSort()) { case Type.VOID: return; case Type.CHAR: boxedType = CHARACTER_TYPE; unboxMethod = CHAR_VALUE; break; case Type.BOOLEAN: boxedType = BOOLEAN_TYPE; unboxMethod = BOOLEAN_VALUE; break; case Type.DOUBLE: unboxMethod = DOUBLE_VALUE; break; case Type.FLOAT: unboxMethod = FLOAT_VALUE; break; case Type.LONG: unboxMethod = LONG_VALUE; break; case Type.INT: case Type.SHORT: case Type.BYTE: unboxMethod = INT_VALUE; break; default: unboxMethod = null; break; } if (unboxMethod == null) { checkCast(type); } else { checkCast(boxedType); invokeVirtual(boxedType, unboxMethod); } } public void valueOf(final Type type) { if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { return; } if (type == Type.VOID_TYPE) { push((String) null); } else { Type boxedType = getBoxedType(type); invokeStatic(boxedType, new Method("valueOf", boxedType, new Type[] {type})); } } private static Type getBoxedType(final Type type) { switch (type.getSort()) { case Type.BYTE: return BYTE_TYPE; case Type.BOOLEAN: return BOOLEAN_TYPE; case Type.SHORT: return SHORT_TYPE; case Type.CHAR: return CHARACTER_TYPE; case Type.INT: return INTEGER_TYPE; case Type.FLOAT: return FLOAT_TYPE; case Type.LONG: return LONG_TYPE; case Type.DOUBLE: return DOUBLE_TYPE; default: return type; } } } ``` ## 3. 示例:生成类 ### 3.1 预期目标 我们想实现的预期目标:生成一个`HelloWorld`类,代码如下所示。 ```java public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } } ``` ### 3.2 编码实现 ```java import lsieun.utils.FileUtils; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import org.objectweb.asm.util.TraceClassVisitor; import java.io.PrintStream; import java.io.PrintWriter; import static org.objectweb.asm.Opcodes.*; public class GeneratorAdapterExample01 { public static void main(String[] args) throws Exception { String relative_path = "sample/HelloWorld.class"; String filepath = FileUtils.getFilePath(relative_path); // (1) 生成byte[]内容 byte[] bytes = dump(); // (2) 保存byte[]到文件 FileUtils.writeBytes(filepath, bytes); } public static byte[] dump() throws Exception { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); PrintWriter printWriter = new PrintWriter(System.out); TraceClassVisitor cv = new TraceClassVisitor(cw, printWriter); cv.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "sample/HelloWorld", null, "java/lang/Object", null); { Method m1 = Method.getMethod("void ()"); GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m1, null, null, cv); mg.loadThis(); mg.invokeConstructor(Type.getType(Object.class), m1); mg.returnValue(); mg.endMethod(); } { Method m2 = Method.getMethod("void main (String[])"); GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m2, null, null, cv); mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class)); mg.push("Hello World!"); mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)")); mg.returnValue(); mg.endMethod(); } cv.visitEnd(); return cw.toByteArray(); } } ``` ## 4. 总结 本文对`GeneratorAdapter`类进行介绍,内容总结如下: - 第一点,`GeneratorAdapter`类的特点是将一些`visitXxxInsn()`方法封装成一些常用的方法。 - 第二点,`GeneratorAdapter`类定义的新方法,并不是十分必要的;如果熟悉`MethodVisitor.visitXxxInsn()`方法,可以完全不考虑使用`GeneratorAdapter`类。
上一篇:LeetCode-038-外观数列


下一篇:038 序列类型操作-元组类型和列表类型