ASM - TreeApi Method组件和接口简介

简介: ASM - TreeApi Method组件和接口简介

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


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


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

Java代码

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

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

目录
相关文章
|
存储 Java API
ASM 关键接口 MethodVisitor
ASM 关键接口 MethodVisitor
444 0
ASM 关键接口 MethodVisitor
|
Java
JAVA-ASM学习笔记之java字节码简介
前言 由于之前接触了集团的故障演练平台monkeyking,对JavaAgent与ASM产生了兴趣。前段时间稍微总结了下JavaAgent的简单内容《JavaAgent学习笔记》。这次则想学习一下ASM(Java字节码操纵框架)。但是在学习的过程中,发现一直对类似如下的代码持续懵逼中,看来想要了解ASM,还是得学下JAVA字节码。 static ClassWriter createCl
15207 0
【ASM】多路径(multipath)简介及配置
【ASM】多路径           >>                                   ...
1422 0
|
关系型数据库 Oracle
【ASM】udev简介及配置、多路径(multipath)等
【ASM】udev简介及配置、多路径等 【ASM】Oracle ASM + 11gR2 + RHEL6.
1286 0
|
Java Spring SQL
ASM + 接口 动态生成类
好吧 ,我承认上篇文章 确认让人看不明白ASM到底有什么用,那么这篇来举个例子吧 ,比如 我制定任意的接口(接口名称,接口方法都是随意的) package com.
812 0
|
8月前
|
Oracle 关系型数据库
oracle asm 磁盘显示offline
oracle asm 磁盘显示offline
372 2
|
3月前
|
存储 Oracle 关系型数据库
数据库数据恢复—Oracle ASM磁盘组故障数据恢复案例
Oracle数据库数据恢复环境&故障: Oracle ASM磁盘组由4块磁盘组成。Oracle ASM磁盘组掉线 ,ASM实例不能mount。 Oracle数据库故障分析&恢复方案: 数据库数据恢复工程师对组成ASM磁盘组的磁盘进行分析。对ASM元数据进行分析发现ASM存储元数据损坏,导致磁盘组无法挂载。
|
8月前
|
存储 Oracle 关系型数据库
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
oracle数据库ASM磁盘组掉线,ASM实例不能挂载。数据库管理员尝试修复数据库,但是没有成功。
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
|
SQL Oracle 关系型数据库
Oracle ASM磁盘和磁盘组的常用SQL语句
Oracle ASM磁盘和磁盘组的常用SQL语句
295 0
|
文字识别 Oracle NoSQL
oracle 11g 单机asm配置
oracle 11g 单机asm配置
683 0