【发布时间】:2017-08-01 15:29:57
【问题描述】:
我正在生成一个简单的类,但无法注入正确的变量名。
ASM 版本为5.2。
代码如下:
package com.test;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) throws Exception {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
String name = "com.test.Sub";
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name.replace('.', '/'), null, "java/lang/Object", null);
Method ctor = Method.getMethod("void <init>()");
GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, ctor, null, null, cw);
mg.visitCode();
mg.loadThis();
mg.invokeConstructor(Type.getType(Object.class), ctor);
int var = mg.newLocal(Type.INT_TYPE);
mg.push(42.42);
mg.storeLocal(var);
Label varLabel = mg.mark();
mg.returnValue();
Label endLabel = mg.mark();
mg.visitLocalVariable("x", "D", null, varLabel, endLabel, var);
mg.endMethod();
cw.visitEnd();
byte[] bytes = cw.toByteArray();
Files.write(Paths.get(name + ".class"), bytes);
}
}
我使用GeneratorAdapter 来简化代码生成。由于GeneratorAdapter是继承自LocalVariablesSorter,所以我假设允许使用newLocal(Type)方法。
除了变量名之外,发出的字节码没有任何问题。当调用visitLocalVariable() 方法时,它不会为变量分配名称,而是在字节码中创建一个新名称。
发出的字节码:
// class version 52.0 (52)
// access flags 0x1
public class com/test/Sub {
// access flags 0x1
public <init>()V
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
LDC 42.42
DSTORE 1
L0
RETURN
L1
LOCALVARIABLE x D L0 L1 3
MAXSTACK = 2
MAXLOCALS = 5
}
我正在使用newLocal() 在visitLocalVariable() 中调用提供的相同变量索引。但是在字节码映射索引中是3 而不是1。如果变量具有“较短”类型,例如 int,则索引将是 2,但仍不是应有的 1。
根据我的观察,发生这种情况的原因如下。 LocalVariablesSorter 维护从旧变量索引到新变量索引的映射。它还覆盖方法visitLocalVariable,并且在将调用委托给访问者链之前,它从映射中计算newIndex。 newIndex 是通过另一个私有方法 remap() 计算出来的。此方法检查给定变量的映射是否已经存在,如果不存在,则创建新映射。我看到的问题是newLocal() 方法没有向映射添加任何内容。
我还可以从 ASM 源代码中看到 storeInsn() in GeneratorAdapter 代表 visitVarInsn() 调用链而不是调用 LocalVariablesSorter 的实现。因为它在LocalVariablesSorter 实现中,所以为变量索引调用remap() 方法并更新映射。
因此我的问题是如何使用GeneratorAdapter 以便在发出的字节码中正确命名变量,或者如何将GeneratorAdapter 与LocalVariablesSorter 组合在一个链中以便它们一起正常工作?
【问题讨论】:
-
嗯,
LocalVariablesSorter的目的是修改后续visit…调用的行为。显然,所有不应该被改变的操作,都必须绕过LocalVariablesSorter,就像GeneratorAdapter引入的方法一样。 -
那如果
GeneratorAdapter不能提供父级的功能,为什么还要从LocalVariablesSorter继承呢? -
别问我,我不是做出这个决定的人。但是在目标访问者而不是适配器上调用该方法的问题在哪里?
-
问题是我不使用任何其他访问者,至少是明确的。我derive 我的发电机直接来自
ClassWriter。如果您能解释如何构建有效的方法访问者链,请这样做。
标签: java bytecode java-bytecode-asm