我正在尝试编写一个实用方法,该方法将捕获调用它的方法的局部变量的当前值的快照(如果我理解正确,从字节码的角度来看,这些还包括方法参数) .
这是我要为每个局部变量捕获的信息:
class VariableInfo
{
public String name;
public String desc;
public Object value;
VariableInfo(String name, String desc, Object value) {
this.name = name;
this.desc = desc;
this.value = value;
}
}
我能够使用ASM
...找到名称和说明(类型)
问题:我怎样才能找到局部变量的运行时当前值,例如通过它的索引?有可能做到ASM
吗?还有什么办法?显然这些数据在相关的堆栈帧中更新了,但是我怎样才能访问它呢?
这是我到目前为止的一般方法:
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.tree.*;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
public Map<String, List<VariableInfo>> recordMethodVariableValues() throws IOException {
//TraceHelper is a utility class, to let me look one stack frame above the current one (i.e. the method that called this utility method)
int depth = 1;
String className = TraceHelper.getClassName(depth);
String methodName = TraceHelper.getMethodName(depth);
InputStream is = readClass(className);
ClassReader reader = new ClassReader(is);
ClassNode classNode = new ClassNode();
reader.accept((ClassVisitor) classNode, 0);
//Since the method may be overloaded, and I look it up by name, I may find several matching methods... is there a better way to identify only the encapsulating method?
Map<String, List<VariableInfo>> methodInfos = new HashMap<>();
int counter = 0;
for (final MethodNode mn : classNode.methods) {
if (methodName.equals(mn.name))
{
System.out.println("Looking up variables of method: " + mn.name);
List<VariableInfo> variableInfos = new ArrayList<>();
for (LocalVariableNode n : mn.localVariables)
{
System.out.println("Looking up value of variable: " + n.name);
//TODO... How to find the local variable current value, e.g. by its index?
variableInfos.add(new VariableInfo(n.name, n.desc, getLocalVariableValueByIndex(n.index)));
}
methodInfos.put(mn.name + "-" + ++counter, variableInfos);
}
}
return methodInfos;
}