版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://dreamhead.blogbus.com/logs/4007513.html

这里要说的ASM,并不是指汇编语言,而是一个操作Java bytecode的框架。对于Java平台而言,bytecode便是它的“汇编语言”,所以,ASM这个名字倒也算是实至名归。ASM本身很强大,有不少软件和框架选择它作为底层的实现,比如cglib。在这篇blog中,主要来关注一下它在代码生成方面的威力。

在起步阶段,Hello World总是一个很好的选择,也就是说,我们生成的目标代码是这样的:
public class AsmExample {
    public static void main(String[] args) {
        System.out.println("Hello, World");
    }
}

在Java中,代码是以类的形式进行组织的,.class文件便是bytecode的载体。对照上面这段代码,首先,我们需要一个类。
public class AsmMain {
    public static void main(String[] args) {
        ClassWriter cw = new ClassWriter(true);
        cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "AsmExample", null, "java/lang/Object", null);

...

cw.visitEnd();
    }
}

在上面这段代码中,ClassWriter就是ASM中用来生成bytecode形式的类。在这里,我们要为我们生成的类设置一些属性,比如类名、访问级别和超类,以及在bytecode层次上需要的版本号等等。至此,对应的Java代码如下:
public class AsmExample {
}

有了类,接下来就是对应的方法了,先来看看基本的结构:
        Method m = Method.getMethod("void main (String[])");
        GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, m, null, null, cw);
        ...
        mg.returnValue();
        mg.endMethod();
首先我们设置了一个方法的签名,包括方法名,参数和返回类型。我们要生成这个方法,还需要设置一些方法的属性,比如访问级别等等,通过cw这个参数,方法同类关联在了一起。到这里,对应的Java代码是这样的:
public class AsmExample {
    public static void main(String args[]) {
    }
}

前面所做的都是搭建静态结构的工作,接下来,我们要进入的才是让程序动起来的部分。
    mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class));
    mg.push("Hello world!");
    mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)"));

在这里,我们面对的实际上是JVM的指令,所以,如果面对汇编一样,所有的一切都一步一步说清楚。

首 先是获得System.out。我们通过getStatic这个方法实现,它表示从哪个类中取出哪个static字段,其类型是什么。而且实际上,这条指 令执行的结果是将这个取出的字段推到了堆栈上。随后,我们在把“Hello world!”也推入堆栈之中,很显然,这一切都是在为调用方法做准备。

对 于参数(这里的“Hello world!”)入栈,我们很容易接受,但为什么要把System.out也送入堆栈呢?再次提醒一下,这里我们是在JVM一级进行思考,在这里,方法调 用被打回了最原始的形态,在Java程序中被隐藏的this这时也要作为参数显式传递,也就是说,方法调用变成了这样:
    println(System.out, "Hello world!");

万 事俱备,调用方法。在Java中,方法调用需要区分类方法和实例方法,它们在虚拟机中有着不同的指令,这里我们要调用的是实例的方法,所以,这里用的是 invokeVirtual,指定了类型,指定了方法,方法就可以调用了。如果要调用类的方法,也就是static方法,那就需要让 invokeStatic上阵了。

对比一下invokeVirtual和invokeStatic的API定义,我们不难发现,它们之间实 际上没有什么区别,之所以要弄出两个来,与Java的设计不无关系,它把属于类的东西看作了一种特殊的东西,没有统一到对象体系之中。如果为Ruby设计 虚拟机,可以消除这样的问题,因为在Ruby中,类的方法就是类对象的实例方法,这样将类的东西统一到对象体系之中,不必额外区分。

到这里,我们的目标便已完全实现:
public class AsmExample {
    public static void main(String args[]) {
        System.out.println("Hello world!");
    }
}

之后,我们可以把定义的类转为字节,至于是加载到虚拟机中运行,还是保存到文件中,那就由自己的喜好了。
    byte[] code = cw.toByteArray();

和 ASM打交道,需要我们放低自己姿态,站在指令一级进行思考。比如,在这个层次上,实现判断语句,就需要设置label,然后进行相应的跳转;这里没有循 环语句,需要自己用判断加跳转打造循环结构。不过,总的来说,很容易同Java程序对应上,就像我们上面所做的那样。《深入Java虚拟机》可以让我们更 好的了解JVM,也可以让帮助我们更好的理解ASM的程序。

有几个帮手可以让我们更好进行bytecode生成这个游戏。 javap,JDK带的一个工具,可以用来反汇编Java bytecode。在接触ASM的最初,我们对指令不是很熟悉的时候,可以考虑先把自己的目标写成Java程序,编译之后用“javap -c”来查看,所有的指令便一览无余,我们就可以照方抓药了。jad,它为我们提供了一个将Java class文件反编译为Java文件,通过它,我们就可以知道生成的bytecode究竟是不是自己想要的,我所展示与生成过程对应的Java代码便是借助于jad的力量完成的。

ASM很强大,这里只介绍了ASM中的代码生成,实际上,就连代码生成这一项工作介绍的都不那么完整,ASM还提供了另外一种生成方式,不过,用起来不如这里的GeneratorAdapter,需要更多的JVM指令的智慧,优势在于速度稍快一些。

转载于:https://www.cnblogs.com/yezhenhan/archive/2011/04/21/2024338.html

[转]Hello, ASM——代码生成相关推荐

  1. 从零开始开发JVM语言(十三)代码生成与ASM

    2019独角兽企业重金招聘Python工程师标准>>> 目录戳这里 如果能够做完语义分析,得到带类型的AST,或者更接近于虚拟机字节码的结构,那么你离整个编译器的"落成&q ...

  2. 【字节码插桩】AOP 技术 ( “字节码插桩“ 技术简介 | AspectJ 插桩工具 | ASM 插桩工具 )

    文章目录 一." 字节码插桩 " 技术简介 二.AspectJ 插桩工具 三.ASM 插桩工具 一." 字节码插桩 " 技术简介 性能优化 , 插件化 , 热修 ...

  3. 转:AOP 的利器:ASM 3.0 介绍

    引言 什么是 ASM ? ASM 是一个 Java 字节码操控框架.它能被用来动态生成类或者增强既有类的功能.ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态 ...

  4. spring core源码解读之ASM4用户手册翻译之一asm简介

    第一章:ASM介绍 1.1 ASM动机: 程序的分析,生成,转换技术可以应用到许多场景: 1.程序分析,从简单的语法解析到完整的语义分析,可以应用在程序中找到潜在的bug,发现无用的代码,工程代码的逆 ...

  5. AOP 的利器:ASM 3.0 介绍

    引言 什么是 ASM ? ASM 是一个 Java 字节码操控框架.它能被用来动态生成类或者增强既有类的功能.ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态 ...

  6. [转载] 深入了解Java ClassLoader、Bytecode 、ASM、cglib

    转载自http://www.iteye.com/topic/98178 一.Java ClassLoader 1,什么是ClassLoader  与 C 或 C++ 编写的程序不同,Java 程序并不 ...

  7. ucc编译器(中间代码生成)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 所谓中间代码生成,就是生成一种和具体汇编语言无关的中间代码.生成中间代码有很多的好处,一方面它可 ...

  8. Freemaker之代码生成

    今天是年后的第一天上班,年前开始研究代码生成,年前先后研究了ASM,JAVASSIST等框架,发现各有各的特点,今天我们研究模板式的代码生成,那就不得不说Freemaker了,我们先看看官网是如何介绍 ...

  9. JAVA 中的代码生成包 CGLIB (Code Generation Library)

    JAVA 中的代码生成包 CGLIB (Code Generation Library) CGLIB 是一个功能强大,高性能的代码生成包.它为没有实现接口的类提供代理,为 JDK 的动态代理提供了很好 ...

  10. ASM介绍及简易教程

    随着 AOP(Aspect Oriented Programming)的发展,代码动态生成已然成为 Java 世界中不可或缺的一环.本文将介绍一种小巧轻便的 Java 字节码操控框架 ASM,它能方便 ...

最新文章

  1. 新进展!英伟达用 AI 给纪录片配音,情绪语调拿捏得稳稳地
  2. 在内部循环中Continue外部循环
  3. MYSQL 实时升级
  4. C#中Console.ReadKey()与ConsoleKey的一些用法
  5. PHP+Ajax手机移动端发红包实例
  6. mysql的引双向链表_一分钟掌握MySQL的InnoDB引擎B+树索引
  7. ibtais中把clob数据类型转换成string并插入到数据库中
  8. WARNING:tensorflow:Entity <bound method GRUCell.call of <tensorflow.python.ops.rnn_cell_impl.GRUCell
  9. delphi android路径 TPath 文件路径,文件管理
  10. paip.转账功能设计流程
  11. Java完全自学手册,你要悄悄努力,然后惊艳所有人
  12. Reactor | Epoll 模型理解
  13. IT十八掌徐培成第一天笔记
  14. 【22.05.14】native thread exiting without having called DetachCurrentThread
  15. 爬取阿里云物联网平台设备的物模型数据
  16. Linux下实现炫酷的终端分屏
  17. 关于jmeter中编写shell脚本json的应用
  18. qbo base board debug
  19. python 通过腾讯地图API获取全国关键词(楼盘/商场)位置信息
  20. 云服务器能干什么用?云服务器使用场景列举

热门文章

  1. 朴素贝叶斯分类算法(Naive Bayesian classification)
  2. Python:Matplotlib 画图
  3. 神经网络的Dropout正则化
  4. python 包的使用 (二)——pyecharts
  5. flow time 是什么
  6. fabric1.0 java sdk_运行 fabric-sdk-java 官方示例
  7. SpringMVC学习(二)使用注解开发SpringMVC
  8. python语法学习第二天--条件与循环
  9. SpringSession
  10. 计算机二级做的完吗,大学计算机二级都没过 毕业后却做起了IT。。。。。