ASM的TreeApi 对于Method的转换、生成也提供了一系列的组件和接口。

MethodNode中大多数属性和方法都和ClassNode类似,其中最主要的属性就是InsnList了。

InsnList是一个双向链表对象,包含了存储方法的字节指令序。先来看下InsnList中的主要是属性和方法。

Java代码
  1. public class InsnList { // public accessors omitted
  2. private int size;
  3. private AbstractInsnNode first;
  4. private AbstractInsnNode last;
  5. AbstractInsnNode[] cache;
  6. int size();
  7. AbstractInsnNode getFirst();
  8. AbstractInsnNode getLast();
  9. AbstractInsnNode get(int index);
  10. boolean contains(AbstractInsnNode insn);
  11. int indexOf(AbstractInsnNode insn);
  12. void accept(MethodVisitor mv);
  13. ListIterator iterator();
  14. ListIterator iterator(int index);
  15. AbstractInsnNode[] toArray();
  16. void set(AbstractInsnNode location, AbstractInsnNode insn);
  17. void add(AbstractInsnNode insn);
  18. void add(InsnList insns);
  19. void insert(AbstractInsnNode insn);
  20. void insert(InsnList insns);
  21. void insert(AbstractInsnNode location, AbstractInsnNode insn);
  22. void insert(AbstractInsnNode location, InsnList insns);
  23. void insertBefore(AbstractInsnNode location, AbstractInsnNode insn);
  24. void insertBefore(AbstractInsnNode location, InsnList insns);
  25. void remove(AbstractInsnNode insn);
  26. void clear();
  27. }

可以看到InsnList 中主要是对AbstractInsnNode对象的操作方法,AbstractInsnNode也就是链表中的元素。

AbstractInsnNode数组存储了字节码指令对象的链表连接关系。AbstractInsnNode是一个抽象父类,代表了字节指令的一个抽象类。AbstractInsnNode的主要方法如下。

Java代码
  1. public abstract class AbstractInsnNode {
  2. public int getOpcode();
  3. public int getType();
  4. public AbstractInsnNode getPrevious();
  5. public AbstractInsnNode getNext();
  6. public void accept(MethodVisitor cv);
  7. public AbstractInsnNode clone(Map labels);
  8. }

子类

1 VarInsnNode

表示局部变量指令的节点。 局部变量指令是load或store局部变量值的指令。

(代表局部变量表的操作指令对象,如xstore,xload)是和MethodVisitor中的visitVarInsn(int opcode, int var)关联的指令访问方法。

1.1 属性

/** The operand of this instruction. This operand is the index of a local variable. */
public int var;

LabelNode, FrameNode 以及 LineNumberNode也继承了AbstractInsnNode。这样就可以像CoreApi中MethodVisitor提供的visitXX 方法一样,插入在关联的指令前。在TreeApi中可以通过对象的getNext()方法方便找到跳转到的指令,并且移除指令的时候,只要label不变,也不会影响原有的跳转指令的跳转地址。同Core 不同的就是,从调用MethodVisitor各个指令对应的visitXX方法,改成对MethodNode 中InsnList对象的链表节点操作。

生成Method

通过下面这个例子就会更加一目了然。当然,MethodNode生成class的效率要比MethodVisitor低,内存消耗也会大,但是我们可以更轻松得实现一段注入逻辑。

方法内部的字节码结构样例,我们依然沿用一下在CoreApi 的Method介绍中使用的http://yunshen0909.iteye.com/blog/2221144的例子。然后可以对比一下两种实现方式的不同。

Java代码  
  1. package asm.tree.method;
  2. import org.objectweb.asm.ClassWriter;
  3. import org.objectweb.asm.Opcodes;
  4. import org.objectweb.asm.tree.*;
  5. import java.io.File;
  6. import java.io.FileOutputStream;
  7. import java.io.IOException;
  8. /**
  9. * tree api method 生成字节码 Created by yunshen.ljy on 2015/7/20.
  10. */
  11. public class GenerateClasses {
  12. public static void main(String[] args) throws IOException {
  13. ClassNode classNode = new ClassNode();
  14. classNode.version = Opcodes.V1_8;
  15. classNode.access = Opcodes.ACC_PUBLIC;
  16. classNode.name = "bytecode/TreeMethodGenClass";
  17. classNode.superName = "java/lang/Object";
  18. classNode.fields.add(new FieldNode(Opcodes.ACC_PRIVATE, "espresso", "I", nullnull));
  19. // public void addEspresso(int espresso) 方法生命
  20. MethodNode mn = new MethodNode(Opcodes.ACC_PUBLIC, "addEspresso", "(I)V", nullnull);
  21. classNode.methods.add(mn);
  22. InsnList il = mn.instructions;
  23. il.add(new VarInsnNode(Opcodes.ILOAD, 1));
  24. il.add(new InsnNode(Opcodes.ICONST_1));
  25. LabelNode label = new LabelNode();
  26. // if (espresso > 0) 跳转通过LabelNode标记跳转地址
  27. il.add(new JumpInsnNode(Opcodes.IF_ICMPLE, label));
  28. il.add(new VarInsnNode(Opcodes.ALOAD, 0));
  29. il.add(new VarInsnNode(Opcodes.ILOAD, 1));
  30. // this.espresso = var1;
  31. il.add(new FieldInsnNode(Opcodes.PUTFIELD, "bytecode/TreeMethodGenClass", "espresso", "I"));
  32. LabelNode end = new LabelNode();
  33. il.add(new JumpInsnNode(Opcodes.GOTO, end));
  34. // label 后紧跟着下一个指令地址
  35. il.add(label);
  36. // java7之后对stack map frame 的处理
  37. il.add(new FrameNode(Opcodes.F_SAME, 0, null, 0, null));
  38. // throw new IllegalArgumentException();
  39. il.add(new TypeInsnNode(Opcodes.NEW, "java/lang/IllegalArgumentException"));
  40. il.add(new InsnNode(Opcodes.DUP));
  41. il.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "()V", false));
  42. il.add(new InsnNode(Opcodes.ATHROW));
  43. il.add(end);
  44. // stack map 的第二次偏移记录
  45. il.add(new FrameNode(Opcodes.F_SAME, 0, null, 0, null));
  46. il.add(new InsnNode(Opcodes.RETURN));
  47. // 局部变量表和操作数栈大小的处理
  48. mn.maxStack = 2;
  49. mn.maxLocals = 2;
  50. mn.visitEnd();
  51. // 打印查看class的生成结果
  52. ClassWriter cw = new ClassWriter(Opcodes.ASM5);
  53. classNode.accept(cw);
  54. File file = new File("TreeMethodGenClass.class");
  55. FileOutputStream fout = new FileOutputStream(file);
  56. try {
  57. fout.write(cw.toByteArray());
  58. fout.close();
  59. catch (IOException e) {
  60. e.printStackTrace();
  61. }
  62. }
  63. }

InsnList il = mn.instructions;所有的方法指令都放在InsnList这样一个链表结构中。当然,这个链表结构也维系了整个字节码指令的结构。

ASM - TreeApi Method组件和接口简介相关推荐

  1. 以太网接口MII,RMII,SMII,GMII总线接口简介

    以太网接口MII,RMII,SMII,GMII总线接口简介 所有的这些接口都从MII而来,MII是(MediumIndependent Interface)的意思,是指不用考虑媒体是铜轴.光纤.电缆等 ...

  2. keil 生成三角波dac0832_弹性波,时域显式接口简介

    COMSOL Multiphysics® 软件 5.5 版本中提供了一个节省内存的物理场接口,用于模拟弹性波在固体中的传播(结构中的振动).该弹性波,时域显式接口基于时域显示时间积分方案的高阶间断伽辽 ...

  3. Java Iterator 接口简介和简单用法.

    Iterator 的中文意思是迭代器. 单单从中文翻译也不易理解迭代器的意思啊,  其实Iterator是1个接口,  它的作用就是遍历容器的所有元素. 一, Iterator 接口简介 Iterat ...

  4. java中接口文件创建_功能接口简介–在Java 8中重新创建的概念

    java中接口文件创建 世界各地的所有Java开发人员都将至少使用以下接口之一:java.lang.Runnable,java.awt.event.ActionListener,java.util.C ...

  5. 功能接口简介–在Java 8中重新创建的概念

    世界各地的所有Java开发人员都将至少使用以下接口之一:java.lang.Runnable,java.awt.event.ActionListener,java.util.Comparator,ja ...

  6. 接口简介 java 1614100890

    接口简介 java 1614100890 生活中的接口 不同厂家的接口 家里的电器都可以使用 为什么? 因为他们是按照相同的规范设计的 不同厂家生产的电脑,USB接口也是同理 相关设置都可以直接使用 ...

  7. 对系统组件化接口设计的一点看法

    今天海浪分享一篇对系统组件化接口设计的一点看法.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:of ...

  8. TypeScript基础入门 - 接口 - 简介

    转载地址 TypeScript基础入门 - 接口 - 简介 项目实践仓库 https://github.com/durban89/typescript_demo.git tag: 1.0.6 为了保证 ...

  9. 路由器广域网接口简介

    路由器广域网接口简介1.WAN侧FE接口WAN侧FE接口工作在网络层,可以配置IP地址,处理三层协议,提供路由功能,FE接口支持的最大速率为100Mbit/s2.WAN侧GE接口WAN侧GE接口工作在 ...

最新文章

  1. c#语言呈现位置信息,c#实现根据网络IP显示地理位置功能示例
  2. 图像文字识别(二):java调用tesseract 识别图片文字
  3. talentcentral测评结果_WinTalent人才测评系统
  4. ASP.Net学习笔记010--加法计算器
  5. code128java字符_java相关:如何使用Code128字体将文本转换为code128条形码
  6. 实用的工具 —— 百度云、everything(全局搜索)、Everest(硬件检测)、TechPowerUp GPU-Z
  7. 结构方程模型-中介效应检验(Amos)
  8. 利用矩阵快速幂求解斐波那契数列
  9. 访问阿里云服务器配置的ftp后,报错227 entering passive mode
  10. 渗透测试之信息收集 -tryhackme-Content Discovery
  11. 钉钉机器人给指定人发消息
  12. ESP32 模拟键盘的简单操作 (ESP32 for Arduino)
  13. 常用数字、模拟量输出传感器原理介绍
  14. 【虹科】人工智能和工业相机助力瓶盖质量控制
  15. Coursera半价优惠
  16. FTP服务器的上传与下载
  17. python实现一个学生管理系统
  18. ChinaSkills-网络系统管理(2022改革Linux部分SDN软件定义网络[OpenDayLight]CentOS7.9安装运行预测)
  19. 解构「私域流量」(一)|底层思维
  20. 条码打印软件之Code32条形码

热门文章

  1. 【Pytorch-从一团乱麻到入门】:3、模型效果评估指标:ROC、AUC、precision、recall
  2. 谁是三鹿奶粉事件的真凶
  3. 由旧版本环信对接之后没有声音,探索AVAudioSession的Category和Option
  4. ppt基础篇--自学笔记
  5. 电子商务B2C网站购物车设计
  6. R语言机器学习篇——随机森林
  7. 科普:alphago是什么
  8. 我们是如何测试360手机浏览器的 –360手机浏览器测试范围概述
  9. iqooneo5隐藏应用方法分享(2021)
  10. html如何制作一个手机商城网页通栏