Java ASM GeneratorAdapter变量命名
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java ASM GeneratorAdapter变量命名,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4957字,纯文字阅读大概需要8分钟。
内容图文
![Java ASM GeneratorAdapter变量命名](/upload/InfoBanner/zyjiaocheng/697/c38c2105e8044c899c90e7cd6a359a02.jpg)
我正在生成一个简单的类,无法注入适当的变量名称.
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
}
我在visitLocalVariable()中使用newLocal()调用提供的相同变量索引.但是在字节码中,映射索引是3而不是1.如果变量具有“较短”类型(如int),则索引将为2,仍然不应该为1.
根据我的观察,这是因为以下原因. LocalVariablesSorter维护从旧变量索引到新变量索引的映射.它还会覆盖方法visitLocalVariable,并且在向访问者链委托调用之前,它会根据映射计算newIndex. newIndex是通过另一个私有方法remap()计算的.此方法检查给定变量的映射是否已存在,如果不存在,则创建新映射.我认为问题是newLocal()方法不会向映射添加任何内容.
我还可以从ASM源看到,GeneratorAdapter中的storeInsn()委托visitVarInsn()调用链而不是调用LocalVariablesSorter的实现.因为它在LocalVariablesSorter实现中,所以为变量索引调用remap()方法并更新映射.
因此,我的问题是如何使用GeneratorAdapter,以便在发出的字节码中正确命名变量,或者如何将ChainAdapter与LocalVariablesSorter组合在一起,以便它们一起正常工作?
解决方法:
由于GeneratorAdapter扩展了LocalVariablesSorter,其目的是调整所有访问者调用,所以作为访问者API的一部分的所有方法都得到了调整,这与GeneratorAdapter引入的专用方法不同.此设计允许将新代码插入到现有方法中,其中旧代码通过访问者API进行报告.
因此必须在目标MethodVisitor上调用visitLocalVariable方法(它是访问者API的一部分),绕过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)
内容总结
以上是互联网集市为您收集整理的Java ASM GeneratorAdapter变量命名全部内容,希望文章能够帮你解决Java ASM GeneratorAdapter变量命名所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。