[转]Hello, ASM——代码生成
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
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——代码生成相关推荐
- 从零开始开发JVM语言(十三)代码生成与ASM
2019独角兽企业重金招聘Python工程师标准>>> 目录戳这里 如果能够做完语义分析,得到带类型的AST,或者更接近于虚拟机字节码的结构,那么你离整个编译器的"落成&q ...
- 【字节码插桩】AOP 技术 ( “字节码插桩“ 技术简介 | AspectJ 插桩工具 | ASM 插桩工具 )
文章目录 一." 字节码插桩 " 技术简介 二.AspectJ 插桩工具 三.ASM 插桩工具 一." 字节码插桩 " 技术简介 性能优化 , 插件化 , 热修 ...
- 转:AOP 的利器:ASM 3.0 介绍
引言 什么是 ASM ? ASM 是一个 Java 字节码操控框架.它能被用来动态生成类或者增强既有类的功能.ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态 ...
- spring core源码解读之ASM4用户手册翻译之一asm简介
第一章:ASM介绍 1.1 ASM动机: 程序的分析,生成,转换技术可以应用到许多场景: 1.程序分析,从简单的语法解析到完整的语义分析,可以应用在程序中找到潜在的bug,发现无用的代码,工程代码的逆 ...
- AOP 的利器:ASM 3.0 介绍
引言 什么是 ASM ? ASM 是一个 Java 字节码操控框架.它能被用来动态生成类或者增强既有类的功能.ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态 ...
- [转载] 深入了解Java ClassLoader、Bytecode 、ASM、cglib
转载自http://www.iteye.com/topic/98178 一.Java ClassLoader 1,什么是ClassLoader 与 C 或 C++ 编写的程序不同,Java 程序并不 ...
- ucc编译器(中间代码生成)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 所谓中间代码生成,就是生成一种和具体汇编语言无关的中间代码.生成中间代码有很多的好处,一方面它可 ...
- Freemaker之代码生成
今天是年后的第一天上班,年前开始研究代码生成,年前先后研究了ASM,JAVASSIST等框架,发现各有各的特点,今天我们研究模板式的代码生成,那就不得不说Freemaker了,我们先看看官网是如何介绍 ...
- JAVA 中的代码生成包 CGLIB (Code Generation Library)
JAVA 中的代码生成包 CGLIB (Code Generation Library) CGLIB 是一个功能强大,高性能的代码生成包.它为没有实现接口的类提供代理,为 JDK 的动态代理提供了很好 ...
- ASM介绍及简易教程
随着 AOP(Aspect Oriented Programming)的发展,代码动态生成已然成为 Java 世界中不可或缺的一环.本文将介绍一种小巧轻便的 Java 字节码操控框架 ASM,它能方便 ...
最新文章
- 新进展!英伟达用 AI 给纪录片配音,情绪语调拿捏得稳稳地
- 在内部循环中Continue外部循环
- MYSQL 实时升级
- C#中Console.ReadKey()与ConsoleKey的一些用法
- PHP+Ajax手机移动端发红包实例
- mysql的引双向链表_一分钟掌握MySQL的InnoDB引擎B+树索引
- ibtais中把clob数据类型转换成string并插入到数据库中
- WARNING:tensorflow:Entity <bound method GRUCell.call of <tensorflow.python.ops.rnn_cell_impl.GRUCell
- delphi android路径 TPath 文件路径,文件管理
- paip.转账功能设计流程
- Java完全自学手册,你要悄悄努力,然后惊艳所有人
- Reactor | Epoll 模型理解
- IT十八掌徐培成第一天笔记
- 【22.05.14】native thread exiting without having called DetachCurrentThread
- 爬取阿里云物联网平台设备的物模型数据
- Linux下实现炫酷的终端分屏
- 关于jmeter中编写shell脚本json的应用
- qbo base board debug
- python 通过腾讯地图API获取全国关键词(楼盘/商场)位置信息
- 云服务器能干什么用?云服务器使用场景列举