如何统计一个java程序执行的字节码数?
How to count the number of executed Bytecodes of a java program?
我正在尝试使用 Java ASM 编写一个简单的程序来计算执行的 Java 字节码的数量。
这个post问同样的问题,并且有使用ASM的解决方案。但是,答案指向一个不再可用的link。
我探索了 Java ASM API,找到了似乎允许此任务的基于树的 API。以下是我到目前为止所取得的成就。
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
public class Executor {
public static void main(String[] args) throws IOException {
Contract c = new Contract();
c.execute();
FileInputStream is = new FileInputStream("target/classes/Contract.class");
ClassReader cr = new ClassReader(is);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
final ClassNode classNode = new ClassNode();
cr.accept(classNode, 0);
classNode.fields.add(new FieldNode(Opcodes.ACC_PUBLIC,
"Counter", "I", null, new Integer(-1)));
FileOutputStream fos = new FileOutputStream("target/classes/ModifiedContract.class");
classNode.accept(cw);
fos.write(cw.toByteArray());
fos.close();
}
}
到目前为止我所取得的成就是将全局计数器添加到 .class 文件(字节码)。
据我了解,下一步是在每个字节码执行后添加一个 counter++ 语句。
从文档中我发现 MethodNode 中的 InsnList
对象对应一个字节码:这是正确的吗?
如果是这样,我可以为每个字节码添加一个 counter++ 语句的最佳方法是什么,以便最后我得到执行的字节码数(我对字节码总数不感兴趣,但只对执行的字节码感兴趣字节码)
(我是 Java + ASM 世界的新手)
谢谢
@Holger 评论的详细说明
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.ListIterator;
public class Executor {
public static void main(String[] args) throws IOException {
Contract c = new Contract();
c.execute();
FileInputStream is = new FileInputStream("target/classes/Contract.class");
ClassReader cr = new ClassReader(is);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
final ClassNode classNode = new ClassNode();
cr.accept(classNode, 0);
classNode.fields.add(new FieldNode(Opcodes.ACC_STATIC +Opcodes.ACC_PUBLIC, "count", "I", null, 0));
for (final MethodNode mn :classNode.methods) {
ListIterator<AbstractInsnNode> itr = mn.instructions.iterator();
// core insert
while (itr.hasNext()) {
AbstractInsnNode node = itr.next();
InsnList numCounting = new InsnList();
// insert count++
numCounting.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name, "count", "I"));
numCounting.add(new InsnNode(Opcodes.ICONST_1));
numCounting.add(new InsnNode(Opcodes.IADD));
numCounting.add(new FieldInsnNode(Opcodes.PUTSTATIC, classNode.name, "count", "I"));
// insert callme
// numCounting.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "com/lvxiaoxin/staticDemo", "callme", "()V", false));
mn.instructions.insert(node, numCounting);
}
}
FileOutputStream fos = new FileOutputStream("target/classes/Contract.class");
classNode.accept(cw);
fos.write(cw.toByteArray());
fos.close();
}
}
基本上这会在每个字节码执行后添加一个 count++ 语句。
作为示例,将以下 class 视为原始 java class。
public class Contract {
private double Cvar1;
private float Cvar2;
private char Cvar3;
private String Cvar4;
private int Cvar5;
private long Cvar6;
public Contract(){}
public void execute(){
double var1 = 0.1;
float var2 = 0.1F;
char var3 = 'a';
String var4 = "a";
int var5 = 1;
long var6 = 2;
System.out.println("Executing the contract");
}
}
现在,如果这个 class 被编译,并且使用执行器修改生成的字节码文件,则会生成以下反编译 class。
//
// IntelliJ IDEA 从 .class 文件重新创建的源代码
//
import java.io.PrintStream;
public class Contract {
private double Cvar1;
private float Cvar2;
private char Cvar3;
private String Cvar4;
private int Cvar5;
private long Cvar6;
public static int count;
public Contract() {
++count;
++count;
++count;
super();
++count;
}
public void execute() {
++count;
++count;
++count;
double var1 = 0.1D;
++count;
++count;
++count;
++count;
float var3 = 0.1F;
++count;
++count;
++count;
++count;
boolean var4 = true;
++count;
++count;
++count;
++count;
String var5 = "a";
++count;
++count;
++count;
++count;
boolean var6 = true;
++count;
++count;
++count;
++count;
long var7 = 2L;
++count;
++count;
++count;
PrintStream var10000 = System.out;
++count;
++count;
var10000.println("Executing the contract");
++count;
++count;
++count;
}
}
我正在尝试使用 Java ASM 编写一个简单的程序来计算执行的 Java 字节码的数量。
这个post问同样的问题,并且有使用ASM的解决方案。但是,答案指向一个不再可用的link。
我探索了 Java ASM API,找到了似乎允许此任务的基于树的 API。以下是我到目前为止所取得的成就。
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
public class Executor {
public static void main(String[] args) throws IOException {
Contract c = new Contract();
c.execute();
FileInputStream is = new FileInputStream("target/classes/Contract.class");
ClassReader cr = new ClassReader(is);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
final ClassNode classNode = new ClassNode();
cr.accept(classNode, 0);
classNode.fields.add(new FieldNode(Opcodes.ACC_PUBLIC,
"Counter", "I", null, new Integer(-1)));
FileOutputStream fos = new FileOutputStream("target/classes/ModifiedContract.class");
classNode.accept(cw);
fos.write(cw.toByteArray());
fos.close();
}
}
到目前为止我所取得的成就是将全局计数器添加到 .class 文件(字节码)。
据我了解,下一步是在每个字节码执行后添加一个 counter++ 语句。
从文档中我发现 MethodNode 中的 InsnList
对象对应一个字节码:这是正确的吗?
如果是这样,我可以为每个字节码添加一个 counter++ 语句的最佳方法是什么,以便最后我得到执行的字节码数(我对字节码总数不感兴趣,但只对执行的字节码感兴趣字节码)
(我是 Java + ASM 世界的新手)
谢谢
@Holger 评论的详细说明
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.ListIterator;
public class Executor {
public static void main(String[] args) throws IOException {
Contract c = new Contract();
c.execute();
FileInputStream is = new FileInputStream("target/classes/Contract.class");
ClassReader cr = new ClassReader(is);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
final ClassNode classNode = new ClassNode();
cr.accept(classNode, 0);
classNode.fields.add(new FieldNode(Opcodes.ACC_STATIC +Opcodes.ACC_PUBLIC, "count", "I", null, 0));
for (final MethodNode mn :classNode.methods) {
ListIterator<AbstractInsnNode> itr = mn.instructions.iterator();
// core insert
while (itr.hasNext()) {
AbstractInsnNode node = itr.next();
InsnList numCounting = new InsnList();
// insert count++
numCounting.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name, "count", "I"));
numCounting.add(new InsnNode(Opcodes.ICONST_1));
numCounting.add(new InsnNode(Opcodes.IADD));
numCounting.add(new FieldInsnNode(Opcodes.PUTSTATIC, classNode.name, "count", "I"));
// insert callme
// numCounting.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "com/lvxiaoxin/staticDemo", "callme", "()V", false));
mn.instructions.insert(node, numCounting);
}
}
FileOutputStream fos = new FileOutputStream("target/classes/Contract.class");
classNode.accept(cw);
fos.write(cw.toByteArray());
fos.close();
}
}
基本上这会在每个字节码执行后添加一个 count++ 语句。
作为示例,将以下 class 视为原始 java class。
public class Contract {
private double Cvar1;
private float Cvar2;
private char Cvar3;
private String Cvar4;
private int Cvar5;
private long Cvar6;
public Contract(){}
public void execute(){
double var1 = 0.1;
float var2 = 0.1F;
char var3 = 'a';
String var4 = "a";
int var5 = 1;
long var6 = 2;
System.out.println("Executing the contract");
}
}
现在,如果这个 class 被编译,并且使用执行器修改生成的字节码文件,则会生成以下反编译 class。
// // IntelliJ IDEA 从 .class 文件重新创建的源代码 //
import java.io.PrintStream;
public class Contract {
private double Cvar1;
private float Cvar2;
private char Cvar3;
private String Cvar4;
private int Cvar5;
private long Cvar6;
public static int count;
public Contract() {
++count;
++count;
++count;
super();
++count;
}
public void execute() {
++count;
++count;
++count;
double var1 = 0.1D;
++count;
++count;
++count;
++count;
float var3 = 0.1F;
++count;
++count;
++count;
++count;
boolean var4 = true;
++count;
++count;
++count;
++count;
String var5 = "a";
++count;
++count;
++count;
++count;
boolean var6 = true;
++count;
++count;
++count;
++count;
long var7 = 2L;
++count;
++count;
++count;
PrintStream var10000 = System.out;
++count;
++count;
var10000.println("Executing the contract");
++count;
++count;
++count;
}
}