Java ASM - 如何在方法中创建局部变量
Java ASM - How to create local variables in method
我正在尝试将 AST 编译成 java class 文件,使用 ASM 创建 class 本身。我 运行 在尝试向函数添加局部变量时遇到问题(函数已正确创建)。
F.e., 像这样一个简单的函数:
public void test() {
int a = 10;
int b = 11;
int c = 12;
int d = 1;
}
变成这样,一旦检测(使用 JD-GUI 反编译):
public void test() {
int i = 10;
int j = 11;
int k = 12;
int m = 4;
}
它的字节码如下所示:
public test() { //()V
bipush 10
istore1
bipush 11
istore2
bipush 12
istore3
iconst_4
istore4
return
}
我正在这样创建局部变量:
methodVisitor.visitVarInsn(Opcodes.BIPUSH, symbol.value);
methodVisitor.visitVarInsn(Opcodes.ISTORE, position);
symbol
是当前局部变量,position
是它的索引,从1开始。 F.e。 a
会在位置 1
而 d
会在位置 4
.
我的问题是 Opcodes
对不同值的正确使用。我试过 Opcodes
像 Opcodes.LDC
,但是生成的 class 在它的方法中没有任何局部变量,但是所有全局定义的变量和函数都在那里两次。
向方法添加任意类型和任意值的变量的正确方法是什么?
编辑:
根据评论,我尝试合并其他问题的答案如下:
MethodVisitor methodVisitor = cw.visitMethod(
access,
methodName,
typeDescriptors,
null,
null
);
LocalVariablesSorter mv = new LocalVariablesSorter(access, typeDescriptors, methodVisitor);
然后我使用 LocalVariablesSorter
添加一个局部变量,如下所示:
// type is net.bytebuddy.jar.asm.Type.INT_TYPE
net.bytebuddy.jar.asm.Type type = getType(symbol.type);
int id = mv.newLocal(type);
mv.visitVarInsn(Opcodes.ISTORE, id);
反编译为:
/* Error */
public void test()
{
// Byte code:
// 0: istore_2
// 1: istore 4
// 3: istore 6
// 5: istore 8
// 7: return
}
导致此字节码:
public test() { //()V
istore2
istore4
istore6
istore8
return
}
我在这里错过了什么?
ISTORE
指令将堆栈顶部的值存储到寄存器中。您在堆栈上没有任何值,这会导致验证错误。
如果要存储值2
,则需要先将值加载到堆栈上:
net.bytebuddy.jar.asm.Type type = getType(symbol.type);
int id = mv.newLocal(type);
mv.visitInsn(Opcodes.ICONST_2);
mv.visitVarInsn(Opcodes.ISTORE, id);
对于"higher"值,还有BIPUSH
或SIPUSH
等其他指令。否则,您可以使用 LDC
从常量池中加载一个值。这通常是最有效的存储值的方式; ASM 隐式删除其中的重复值。
我正在尝试将 AST 编译成 java class 文件,使用 ASM 创建 class 本身。我 运行 在尝试向函数添加局部变量时遇到问题(函数已正确创建)。
F.e., 像这样一个简单的函数:
public void test() {
int a = 10;
int b = 11;
int c = 12;
int d = 1;
}
变成这样,一旦检测(使用 JD-GUI 反编译):
public void test() {
int i = 10;
int j = 11;
int k = 12;
int m = 4;
}
它的字节码如下所示:
public test() { //()V
bipush 10
istore1
bipush 11
istore2
bipush 12
istore3
iconst_4
istore4
return
}
我正在这样创建局部变量:
methodVisitor.visitVarInsn(Opcodes.BIPUSH, symbol.value);
methodVisitor.visitVarInsn(Opcodes.ISTORE, position);
symbol
是当前局部变量,position
是它的索引,从1开始。 F.e。 a
会在位置 1
而 d
会在位置 4
.
我的问题是 Opcodes
对不同值的正确使用。我试过 Opcodes
像 Opcodes.LDC
,但是生成的 class 在它的方法中没有任何局部变量,但是所有全局定义的变量和函数都在那里两次。
向方法添加任意类型和任意值的变量的正确方法是什么?
编辑:
根据评论,我尝试合并其他问题的答案如下:
MethodVisitor methodVisitor = cw.visitMethod(
access,
methodName,
typeDescriptors,
null,
null
);
LocalVariablesSorter mv = new LocalVariablesSorter(access, typeDescriptors, methodVisitor);
然后我使用 LocalVariablesSorter
添加一个局部变量,如下所示:
// type is net.bytebuddy.jar.asm.Type.INT_TYPE
net.bytebuddy.jar.asm.Type type = getType(symbol.type);
int id = mv.newLocal(type);
mv.visitVarInsn(Opcodes.ISTORE, id);
反编译为:
/* Error */
public void test()
{
// Byte code:
// 0: istore_2
// 1: istore 4
// 3: istore 6
// 5: istore 8
// 7: return
}
导致此字节码:
public test() { //()V
istore2
istore4
istore6
istore8
return
}
我在这里错过了什么?
ISTORE
指令将堆栈顶部的值存储到寄存器中。您在堆栈上没有任何值,这会导致验证错误。
如果要存储值2
,则需要先将值加载到堆栈上:
net.bytebuddy.jar.asm.Type type = getType(symbol.type);
int id = mv.newLocal(type);
mv.visitInsn(Opcodes.ICONST_2);
mv.visitVarInsn(Opcodes.ISTORE, id);
对于"higher"值,还有BIPUSH
或SIPUSH
等其他指令。否则,您可以使用 LDC
从常量池中加载一个值。这通常是最有效的存储值的方式; ASM 隐式删除其中的重复值。