【问题标题】:How to create a local variable with ASM?如何使用 ASM 创建局部变量?
【发布时间】:2012-11-27 17:38:50
【问题描述】:

我正在尝试使用 ASM 修补一个类。我需要在函数中添加一些逻辑。这个逻辑需要一个新的局部变量。这是我所做的:

class CreateHashTableMethodAdapter extends MethodAdapter {
    @Override  
    public void visitMethodInsn(int opcode, String owner,String name, String desc){
        System.out.println(opcode + "/" + owner + "/" + name + "/" + desc);

        if(opcode == Opcodes.INVOKESPECIAL &&
                "javax/naming/InitialContext".equals(owner) &&
                "<init>".equals(name) &&
                "()V".equals(desc)){

            System.out.println("In mod");
            //  83: new #436; //class javax/naming/InitialContext
            //  86: dup


            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "javax/naming/InitialContext", "<init>", "()V");
            mv.visitVarInsn(Opcodes.ASTORE, 1);

            Label start_patch = new Label();
            Label end_patch = new Label();

            mv.visitLabel(start_patch);



            mv.visitTypeInsn(Opcodes.NEW,"java/util/Hashtable");
            mv.visitInsn(Opcodes.DUP);
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/util/Hashtable", "<init>", "()V");  
            mv.visitVarInsn(Opcodes.ASTORE,9);

            // ........ sNip ..........

            mv.visitLabel(end_patch);
            mv.visitLocalVariable("env","Ljava/util/Hashtable;",null,start_patch,end_patch,9);

            //    127:  astore_1

        }
        else {
            mv.visitMethodInsn(opcode, owner, name, desc);
        }
    }
}

当我针对CheckClassAdapter 运行此方法适配器时,它指出:

org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 51: Trying to access an inexistant local variable 9
.... sNiP ....
00050 R R . . .  : R R  :     INVOKESPECIAL java/util/Hashtable.<init> ()V
00051 R R . . .  : R  :     ASTORE 9

我认为我滥用了 visitLocalVariable,但我不知道应该在哪里调用它。

当我 javap 生成字节码(不检查)时,我得到以下局部变量表:

LocalVariableTable: 
Start  Length  Slot  Name   Signature
91      40      9    env       Ljava/util/Hashtable;
0      343      0    this       Lpmu/jms/ServerJMS;
132      146      1    initialContext       Ljavax/naming/InitialContext;
153      125      2    topicConnectionFactory       Ljavax/jms/TopicConnectionFactory;
223      55      3    topic       Ljavax/jms/Topic;
249      29      4    topicSubscriber       Ljavax/jms/TopicSubscriber;
279      55      1    ex       Ljava/lang/Exception;
281      53      2    codeMessage       I
289      45      3    params       Lpmu/data/Parameters;
325      9      4    messageError       Ljava/lang/String;

你可能注意到了,我的变量在这里但是最上面?! 有什么想法吗?

【问题讨论】:

  • 只有在要生成调试信息时才需要调用 visitLocalVariable。否则可以删除。您发布的异常来自数据流分析器,它不查看调试信息。
  • 您在构造 ClassWriter 时是否传递了 ClassWriter.COMPUTE_MAXS,和/或调用 visitMaxs?您需要这样做以更改局部变量表的最大大小。
  • @EugeneKuleshov:好的,我不知道不需要变量声明。那么,我可以假设如果我想使用局部变量,我只需要表足够大吗?
  • @int3 是的,我使用 COMPUTE_MAXS
  • 实际上没有任何“表”。使用 COMPUTE_MAXS 标志 ASM 将在 visitMax() 调用中自动计算 maxVars 参数。无论如何,您应该提供一个足以重现您的问题的完整示例。

标签: java variables local bytecode java-bytecode-asm


【解决方案1】:

创建新局部变量的一种便捷方法是扩展 LocalVariablesSorter 而不是 MethodAdapter。然后,您可以根据需要使用newLocal() 分配局部变量,而不会干扰现有变量。有关详细信息,请参阅ASM homepage 上的 ASM 4.0 A Java 字节码工程库的第 3.3.3 节。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-15
    • 2013-09-04
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多