Application
HelloWorld
package sample;
public class HelloWorld {
public void test(int a, int b) {
int hashCode = this.hashCode();
int diff = a - b;
int sum = a + b;
int result = hashCode + diff * sum;
System.out.println(result);
}
@Override
public int hashCode() {
return 100;
}
}
test:(II)V
000: aload_0 {HelloWorld, I, I, ., ., ., .} | {}
001: invokevirtual HelloWorld.hashCode {HelloWorld, I, I, ., ., ., .} | {HelloWorld}
002: istore_3 {HelloWorld, I, I, ., ., ., .} | {I}
003: iload_1 {HelloWorld, I, I, I, ., ., .} | {}
004: iload_2 {HelloWorld, I, I, I, ., ., .} | {I}
005: isub {HelloWorld, I, I, I, ., ., .} | {I, I}
006: istore 4 {HelloWorld, I, I, I, ., ., .} | {I}
007: iload_1 {HelloWorld, I, I, I, I, ., .} | {}
008: iload_2 {HelloWorld, I, I, I, I, ., .} | {I}
009: iadd {HelloWorld, I, I, I, I, ., .} | {I, I}
010: istore 5 {HelloWorld, I, I, I, I, ., .} | {I}
011: iload_3 {HelloWorld, I, I, I, I, I, .} | {}
012: iload 4 {HelloWorld, I, I, I, I, I, .} | {I}
013: iload 5 {HelloWorld, I, I, I, I, I, .} | {I, I}
014: imul {HelloWorld, I, I, I, I, I, .} | {I, I, I}
015: iadd {HelloWorld, I, I, I, I, I, .} | {I, I}
016: istore 6 {HelloWorld, I, I, I, I, I, .} | {I}
017: getstatic System.out {HelloWorld, I, I, I, I, I, I} | {}
018: iload 6 {HelloWorld, I, I, I, I, I, I} | {PrintStream}
019: invokevirtual PrintStream.println {HelloWorld, I, I, I, I, I, I} | {PrintStream, I}
020: return {HelloWorld, I, I, I, I, I, I} | {}
HelloWorldRun
import sample.HelloWorld;
public class HelloWorldRun {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
HelloWorld instance = new HelloWorld();
instance.test(10, 5);
System.out.println("===========================");
}
}
}
优化
import lsieun.utils.FileUtils;
import org.objectweb.asm.*;
import static org.objectweb.asm.Opcodes.*;
public class HelloWorldGenerateCore {
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 {
// (1) 创建ClassWriter对象
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
// (2) 调用visitXxx()方法
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "sample/HelloWorld",
null, "java/lang/Object", null);
{
MethodVisitor mv1 = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv1.visitCode();
mv1.visitVarInsn(ALOAD, 0);
mv1.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
mv1.visitInsn(RETURN);
mv1.visitMaxs(1, 1);
mv1.visitEnd();
}
{
MethodVisitor mv2 = cw.visitMethod(ACC_PUBLIC, "test", "(II)V", null, null);
mv2.visitCode();
mv2.visitVarInsn(ALOAD, 0);
mv2.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I", false);
mv2.visitVarInsn(ISTORE, 0);
mv2.visitVarInsn(ILOAD, 1);
mv2.visitInsn(DUP);
mv2.visitVarInsn(ILOAD, 2);
mv2.visitInsn(ISUB);
mv2.visitVarInsn(ISTORE, 1);
mv2.visitVarInsn(ILOAD, 2);
mv2.visitInsn(IADD);
mv2.visitVarInsn(ISTORE, 2);
mv2.visitVarInsn(ILOAD, 0);
mv2.visitVarInsn(ILOAD, 1);
mv2.visitVarInsn(ILOAD, 2);
mv2.visitInsn(IMUL);
mv2.visitInsn(IADD);
mv2.visitVarInsn(ISTORE, 0);
mv2.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv2.visitVarInsn(ILOAD, 0);
mv2.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V", false);
mv2.visitInsn(RETURN);
mv2.visitMaxs(3, 3);
mv2.visitEnd();
}
{
MethodVisitor mv3 = cw.visitMethod(ACC_PUBLIC, "hashCode", "()I", null, null);
mv3.visitCode();
mv3.visitIntInsn(BIPUSH, 100);
mv3.visitInsn(IRETURN);
mv3.visitMaxs(1, 1);
mv3.visitEnd();
}
cw.visitEnd();
// (3) 调用toByteArray()方法
return cw.toByteArray();
}
}
test:(II)V
000: aload_0 {HelloWorld, I, I} | {}
001: invokevirtual Object.hashCode {HelloWorld, I, I} | {HelloWorld}
002: istore_0 {HelloWorld, I, I} | {I}
003: iload_1 {I, I, I} | {}
004: dup {I, I, I} | {I}
005: iload_2 {I, I, I} | {I, I}
006: isub {I, I, I} | {I, I, I}
007: istore_1 {I, I, I} | {I, I}
008: iload_2 {I, I, I} | {I}
009: iadd {I, I, I} | {I, I}
010: istore_2 {I, I, I} | {I}
011: iload_0 {I, I, I} | {}
012: iload_1 {I, I, I} | {I}
013: iload_2 {I, I, I} | {I, I}
014: imul {I, I, I} | {I, I, I}
015: iadd {I, I, I} | {I, I}
016: istore_0 {I, I, I} | {I}
017: getstatic System.out {I, I, I} | {}
018: iload_0 {I, I, I} | {PrintStream}
019: invokevirtual PrintStream.println {I, I, I} | {PrintStream, I}
020: return {I, I, I} | {}
处理
ChangeThisNode
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodNode;
import static org.objectweb.asm.Opcodes.*;
public class ChangeThisNode extends ClassNode {
public ChangeThisNode(int api, ClassVisitor cv) {
super(api);
this.cv = cv;
}
@Override
public void visitEnd() {
// 首先,处理自己的代码逻辑
int size = methods.size();
for (int i = 0; i < size; i++) {
MethodNode mn = methods.get(i);
if ("<init>".equals(mn.name) || "<clinit>".equals(mn.name)) {
continue;
}
InsnList instructions = mn.instructions;
if (instructions.size() == 0) {
continue;
}
int maxLocals = mn.maxLocals;
int api = Opcodes.ASM9;
MethodNode newMethodNode = new MethodNode(api, mn.access, mn.name, mn.desc, mn.signature, mn.exceptions.toArray(new String[0]));
MethodVisitor mv = new ChangeThisAdapter(api, newMethodNode, mn.access, mn.name, mn.desc, maxLocals);
mn.accept(mv);
methods.set(i, newMethodNode);
}
// 其次,调用父类的方法实现(根据实际情况,选择保留,或删除)
super.visitEnd();
// 最后,向后续ClassVisitor传递
if (cv != null) {
accept(cv);
}
}
private static class ChangeThisAdapter extends MethodVisitor {
private final int methodAccess;
private final String methodName;
private final String methodDesc;
private final int maxLocals;
public ChangeThisAdapter(int api, MethodVisitor mv, int access, String methodName, String descriptor, int maxLocals) {
super(api, mv);
this.methodAccess = access;
this.methodName = methodName;
this.methodDesc = descriptor;
this.maxLocals = maxLocals;
}
@Override
public void visitCode() {
// 首先,处理自己的代码逻辑
boolean isStatic = (methodAccess & ACC_STATIC) != 0;
// 第一步,考虑要不要复制this:
// - 如果是static方法,就不复制了;
// - 如果是non-static方法,就进行复制
if (!isStatic) {
//进入这里,说明是non-static方法,对this进行复制
super.visitVarInsn(ALOAD, 0);
super.visitVarInsn(ASTORE, getBackUpIndex(0));
}
// 第二步,考虑方法接收的参数
// 根据方法描述符(methodDesc)获取各个参数的类型
Type methodType = Type.getMethodType(methodDesc);
Type[] argumentTypes = methodType.getArgumentTypes();
// 对各个参数类型进行循环
int localIndex = isStatic ? 0 : 1;
for (Type t : argumentTypes) {
// 将参数加载到栈上
int load_opcode = t.getOpcode(ILOAD);
super.visitVarInsn(load_opcode, localIndex);
// 放到结尾目标位置
int store_opcode = t.getOpcode(ISTORE);
super.visitVarInsn(store_opcode, getBackUpIndex(localIndex));
// 更新索引的位置
localIndex += t.getSize();
}
// 其次,调用父类的方法实现
super.visitCode();
}
@Override
public void visitInsn(int opcode) {
// 首先,处理自己的代码逻辑
if (opcode == ATHROW || (opcode >= IRETURN && opcode <= RETURN)) {
// 首先,处理自己的代码逻辑
boolean isStatic = (methodAccess & ACC_STATIC) != 0;
if (!isStatic) {
super.visitVarInsn(ALOAD, getBackUpIndex(0));
super.visitInsn(POP);
}
Type methodType = Type.getMethodType(methodDesc);
Type[] argumentTypes = methodType.getArgumentTypes();
int localIndex = isStatic ? 0 : 1;
for (Type t : argumentTypes) {
int load_opcode = t.getOpcode(ILOAD);
super.visitVarInsn(load_opcode, getBackUpIndex(localIndex));
int size = t.getSize();
if (size == 1) {
super.visitInsn(POP);
}
else {
super.visitInsn(POP2);
}
localIndex += t.getSize();
}
super.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
super.visitLdcInsn("%s %s:%s");
super.visitInsn(ICONST_3);
super.visitTypeInsn(ANEWARRAY, "java/lang/Object");
super.visitInsn(DUP);
super.visitInsn(ICONST_0);
super.visitVarInsn(ALOAD, getBackUpIndex(0));
super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false);
super.visitInsn(AASTORE);
super.visitInsn(DUP);
super.visitInsn(ICONST_1);
super.visitLdcInsn(methodName);
super.visitInsn(AASTORE);
super.visitInsn(DUP);
super.visitInsn(ICONST_2);
super.visitLdcInsn(methodDesc);
super.visitInsn(AASTORE);
super.visitMethodInsn(INVOKESTATIC, "java/lang/String", "format", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;", false);
super.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
}
// 其次,调用父类的方法实现
super.visitInsn(opcode);
}
private int getBackUpIndex(int localIndex) {
return maxLocals + localIndex;
}
}
}
HelloWorldTransformTree
import lsieun.asm.tree.*;
import lsieun.utils.FileUtils;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
public class HelloWorldTransformTree {
public static void main(String[] args) {
String relative_path = "sample/HelloWorld.class";
String filepath = FileUtils.getFilePath(relative_path);
byte[] bytes1 = FileUtils.readBytes(filepath);
// (1)构建ClassReader
ClassReader cr = new ClassReader(bytes1);
// (2)构建ClassWriter
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
// (3)串连ClassNode
int api = Opcodes.ASM9;
ClassNode cn = new ChangeThisNode(api, cw);
//(4)结合ClassReader和ClassNode
int parsingOptions = ClassReader.SKIP_DEBUG;
cr.accept(cn, parsingOptions);
// (5) 生成byte[]
byte[] bytes2 = cw.toByteArray();
FileUtils.writeBytes(filepath, bytes2);
}
}