如何在 Javassist 中创建或检索 StackMapTable
How to create or retrieve a StackMapTable in Javassist
在 javassist API 中似乎没有直接的方法可以在 CodeAttribute 属性 中手动添加任何内容 属性。
给出这个例子:
CtMethod m;
m.getMethodInfo().getCodeAttribute().setAttribute(???);
这似乎是改变属性的唯一方法。但是,既不可能检索原始属性并修改它们(它 returns 一个 AttributeInfo 列表),也不存在 StackMapTable 的 public 构造函数,这似乎是唯一可接受的输入。
有人知道如何做这样的事情吗?
CodeAttribute对象负责保存表示方法流的字节码。您可以使用它来迭代表示方法逻辑的字节码。
这基本上意味着它代表编译方法本身。我知道您可以使用此对象手动修改字节码本身,例如删除两行之间的所有指令:
// erase from line 4 to 6
int startingLineNumber= 6;
// Access the code attribute
CodeAttribute codeAttribute = mymethod.getMethodInfo().getCodeAttribute();
LineNumberAttribute lineNumberAttribute = (LineNumberAttribute) codeAttribute.getAttribute(LineNumberAttribute.tag);
// Index in bytecode array where we start to delete
int firstIndex = lineNumberAttribute.toStartPc(startingLineNumber);
// Index in the bytecode where the first instruction that we keep starts
int secondIndex = lineNumberAttribute.toStartPc(startingLineNumber+2);
// go through the bytecode array
byte[] code = codeAttribute.getCode();
for (int i = firstIndex ; i < secondIndex ; i++) {
// set the bytecode of this line to No OPeration
code[i] = CodeAttribute.NOP;
}
然而,这可能真的很棘手,很容易失控。
我建议做的是只创建一个新的 CodeAttribute rom scratch 并将其替换到您的方法中以避免不愉快的意外:
ClassFile cf = ...;
MethodInfo minfo = cf.getMethod("yourMethod");
Bytecode code = new Bytecode(cf.getConstPool());
// insert your logic here
code.addAload(0);
code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V");
code.addReturn(null);
code.setMaxLocals(1);
MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V");
minfo.setCodeAttribute(code.toCodeAttribute());
但是,由于您直接处理字节码,因此该方法也可能存在相当大的风险。可能最好的方法就是删除您的方法并添加一个新的方法来代替您的逻辑。
在 javassist API 中似乎没有直接的方法可以在 CodeAttribute 属性 中手动添加任何内容 属性。
给出这个例子:
CtMethod m;
m.getMethodInfo().getCodeAttribute().setAttribute(???);
这似乎是改变属性的唯一方法。但是,既不可能检索原始属性并修改它们(它 returns 一个 AttributeInfo 列表),也不存在 StackMapTable 的 public 构造函数,这似乎是唯一可接受的输入。
有人知道如何做这样的事情吗?
CodeAttribute对象负责保存表示方法流的字节码。您可以使用它来迭代表示方法逻辑的字节码。
这基本上意味着它代表编译方法本身。我知道您可以使用此对象手动修改字节码本身,例如删除两行之间的所有指令:
// erase from line 4 to 6
int startingLineNumber= 6;
// Access the code attribute
CodeAttribute codeAttribute = mymethod.getMethodInfo().getCodeAttribute();
LineNumberAttribute lineNumberAttribute = (LineNumberAttribute) codeAttribute.getAttribute(LineNumberAttribute.tag);
// Index in bytecode array where we start to delete
int firstIndex = lineNumberAttribute.toStartPc(startingLineNumber);
// Index in the bytecode where the first instruction that we keep starts
int secondIndex = lineNumberAttribute.toStartPc(startingLineNumber+2);
// go through the bytecode array
byte[] code = codeAttribute.getCode();
for (int i = firstIndex ; i < secondIndex ; i++) {
// set the bytecode of this line to No OPeration
code[i] = CodeAttribute.NOP;
}
然而,这可能真的很棘手,很容易失控。 我建议做的是只创建一个新的 CodeAttribute rom scratch 并将其替换到您的方法中以避免不愉快的意外:
ClassFile cf = ...;
MethodInfo minfo = cf.getMethod("yourMethod");
Bytecode code = new Bytecode(cf.getConstPool());
// insert your logic here
code.addAload(0);
code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V");
code.addReturn(null);
code.setMaxLocals(1);
MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V");
minfo.setCodeAttribute(code.toCodeAttribute());
但是,由于您直接处理字节码,因此该方法也可能存在相当大的风险。可能最好的方法就是删除您的方法并添加一个新的方法来代替您的逻辑。