Java ASM GeneratorAdapter 变量命名

2023-12-05

我正在生成一个简单的类,无法注入正确的变量名。 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 with LocalVariablesSorter在一个链条中,以便它们能够正常工作?


自从GeneratorAdapter延伸LocalVariablesSorter,其目的是适应所有访问者调用,属于访问者 API 一部分的所有方法都会得到适应,这与 引入的专用方法不同GeneratorAdapter。这种设计允许将新代码插入到现有方法中,其中旧代码通过访问者 API 报告。

所以方法visitLocalVariable,它是访问者 API 的一部分,必须在目标上调用MethodVisitor,绕过LocalVariablesSorter:

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>()");
MethodVisitor direct = cw.visitMethod(
         Opcodes.ACC_PUBLIC, ctor.getName(), ctor.getDescriptor(), null, null);
GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, ctor, direct);
mg.visitCode();
mg.loadThis();
mg.invokeConstructor(Type.getType(Object.class), ctor);
int var = mg.newLocal(Type.DOUBLE_TYPE);
mg.push(42.42);
mg.storeLocal(var);
Label varLabel = mg.mark();
mg.returnValue();
Label endLabel = mg.mark();
direct.visitLocalVariable("x", "D", null, varLabel, endLabel, var);
mg.endMethod();
cw.visitEnd();
byte[] bytes = cw.toByteArray();
Files.write(Paths.get(name + ".class"), bytes);

由于这可能会令人困惑,因此这里有直接作用于目标的替代方案MethodVisitor完全没有任何方便的包装,例如GeneratorAdapter。它并不更复杂,尽管它需要更多的知识,但是,无论如何,在处理 Java 字节码和类文件时,开发人员都应该具备这些知识......

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
String name = "com.test.Sub";
String superClName = "java/lang/Object", ctorName = "<init>", ctorDesc = "()V";
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name.replace('.','/'), null, superClName, null);
MethodVisitor direct = cw.visitMethod(Opcodes.ACC_PUBLIC, ctorName, ctorDesc, null, null);
direct.visitCode();
// "this" is alway 0 (zero) and for parameterless methods the next var location is 1 (one)
int thisVar = 0, var = 1;
direct.visitVarInsn(Opcodes.ALOAD, thisVar);
direct.visitMethodInsn(Opcodes.INVOKESPECIAL, superClName, ctorName, ctorDesc, false);
direct.visitLdcInsn(42.42);
Label varLabel = new Label(), endLabel = new Label();
direct.visitVarInsn(Opcodes.DSTORE, var);
direct.visitLabel(varLabel);
direct.visitInsn(Opcodes.RETURN);
direct.visitLabel(endLabel);
direct.visitLocalVariable("x", "D", null, varLabel, endLabel, var);
direct.visitMaxs(-1, -1);// no actual values, using COMPUTE_FRAMES
direct.visitEnd();
cw.visitEnd();
byte[] bytes = cw.toByteArray();
Files.write(Paths.get(name + ".class"), bytes);

如果您使用起来感觉不舒服()V对于无参数的void直接方法,您仍然可以使用Method像之前一样的对象或Type.getMethodDescriptor(Type.VOID_TYPE)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java ASM GeneratorAdapter 变量命名 的相关文章

随机推荐

  • 使用c#在Word中按名称访问表

    我有一个包含很多表格的文档 我想使用 C 和 Microsoft Office Interop Word 修改这些表 我读到我可以使用 Tables 接口迭代所有表 问题 是否可以为表指定名称 ID 并通过名称访问表 就像 Powerpoi
  • 通过 github API 关闭拉取请求

    根据我们应用程序的设计要求 我们曾经使用 gitlab API 删除 Gitlab 中的合并请求 现在我们正在迁移到 Github 我正在寻找类似的 API 调用来关闭 Github 上的拉取请求 我通读了文档here 但它没有回答我的问题
  • 对数据框的每一行进行排序[重复]

    这个问题在这里已经有答案了 我正在尝试使用这一行对数据框的每一行进行排序 sapply df function x sort x 但是 对列进行排序而不是对行进行排序 例如 这个数据框 5 10 7 1 5 6 3 9 2 4 4 5 1
  • *a, b, c = line.split() 中的星号有什么作用?

    Assume line is Chicago Sun 01 52 什么是 a b c line split 做 特别是 星号的意义是什么 编辑 经过测试 似乎 Chicago Sun and 01 52 都存储在a b and c 星号似乎
  • 一级缓存可以与 ICriteria 或其他 API 一起使用吗?

    In NHibernate使用时您可以轻松地从一级缓存中受益Load or Get方法 但是关于ICriteria HQL Linq to NHibernate and QueryOver 他们也使用一级缓存吗 他们使用它来返回实体 但查询
  • PowerMockito.doReturn 返回 null

    这是我正在测试的课程 public class A public Integer callMethod return someMethod private Integer someMethod Some Code HttpPost http
  • 在Linux上,如何确保解锁被锁定在死亡/终止的线程中的互斥体?

    这是一道面试题 在 Linux 上 如何确保解锁被锁定在死亡 终止的 POSIX 线程中的 POSIX 互斥锁 我的想法 Linux向程序发送kill或终止信号时会自动释放它吗 但是 我找不到有关操作系统如何执行此操作的更多详细信息 tha
  • Facebook.php 和 facebookapi_php5 文档

    我在哪里可以找到关于这两个 PHP 文件的良好文档以及每个函数的更详细和深入的使用 Facebook 文档 信息不够丰富 哈哈 我感受到你的痛苦 facebookapi php5主要是各个API方法 facebook 主要用于会话 身份验证
  • 如何动态添加新方法到 php 对象?

    如何 即时 向对象添加新方法 me new stdClass me gt doSomething function echo I ve done something me gt doSomething Fatal error Call to
  • Cordova 文件插件在 Android 中从未准备就绪

    我有一个非常简单的 Cordova 应用程序 只有一个插件 org apache cordova file 当我在 Android 模拟器中模拟该应用程序时 deviceready事件永远不会被触发 我得到以下输出 D CordovaLog
  • Zend Framework 2 - 注释表单不起作用

    谢谢 光新藤我调查了AnnotationForms这似乎是最好的解决方法ModelForms 但示例所示here对我不起作用 use Zend Form Annotation AnnotationBuilder builder new An
  • 构建项目时出现转换异常[重复]

    这个问题在这里已经有答案了 当我尝试运行我的应用程序时 出现以下错误 Error Execution failed for task app transformClassesWithDexForDebug gt com android bu
  • 绑定和解构块参数

    在 ruby 中 有没有一种方法可以同时将块的参数绑定到局部变量并对其进行解构 谷歌搜索没有找到我任何东西 并且在 IRB 中玩也毫无结果 但我想我回想起了类似于以下功能的功能 gt gt 1 2 3 4 map x y z x y z g
  • 将 DateTime.Add(TimeSpan) 与 LINQ 结合使用

    我必须运行如下查询 它实际上更复杂 但这里是重要的部分 var results from b in context Bookings where b ScheduleDate Add b StartTime gt DateTime UtcN
  • 批次中的随机生成器

    我有一个bat文件 echo RANDOM 并使用命令行执行它 start randomcheck bat start randomcheck bat 打开两个控制台 并且都包含相同的数字 4645 这无法达到随机的目的提供不同的临时文件夹
  • ASP.Net Core 文件上传进度会话

    我正在 ASP Net Core 中编写文件上传 并尝试更新进度栏 但是当从 javascript 调用 进度 操作时 会话值未正确更新 进度使用以下方式保存在用户会话中 public static void StoreInt ISessi
  • 如何在 Windows 上使用 python 2.6 安装 pip

    我尝试在我的开发计算机上安装带有 python 2 6 的 pip 以尝试匹配也使用 python 2 6 的部署环境 Python 2 6 安装正常 我尝试使用 get pip py 安装 pip 如此处所述https pip pypa
  • 使用 .NET Core System.Text.Json 序列化/反序列化类层次结构

    我有一个简单的类层次结构 我想使用 System Text Json 对其进行序列化 有3个班级 基地是Shape 继承的有Box and Circle 我计划在我的前端应用程序上使用这些类作为标记联合 所以我刚刚引入了一个鉴别器属性Tag
  • 如何使用 cffi 在 C 中嵌入返回字符串的 Python 函数?

    我正在尝试使用 PyPy 和 cffi 在 C 中嵌入 Python 函数 我正在跟进本指南来自 PyPy 文档 问题是 我发现的所有示例都对整数进行操作 而我的函数接受一个字符串并返回一个字符串 我似乎不知道如何在 C 中嵌入这个函数 因
  • Java ASM GeneratorAdapter 变量命名

    我正在生成一个简单的类 无法注入正确的变量名 ASM版本是5 2 这是代码 package com test import org objectweb asm import org objectweb asm commons Generat