文档章节

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

wkgcass
 wkgcass
发布于 2016/07/02 12:25
字数 1395
阅读 100
收藏 4

目录戳这里

如果能够做完语义分析,得到带类型的AST,或者更接近于虚拟机字节码的结构,那么你离整个编译器的“落成”就不远了!

在这个步骤,你可以直接操作byte数组,也可以使用第三方的中间结构,也可以使用字节码类库。

当然,最直接的当然是字节码库了,例如大名鼎鼎的ASM。

#ASM ASM库很小,但是功能非常完善。所有的属性都有一套封装来支持,栈的大小,StackMapTable的计算做的都很好。当然也有不好的地方,如果你给出的指令有问题它也不会报错,有时候计算StackMapTable时会抛出IndexOutOfBoundsException,让人摸不着头脑。而且,mvn中下载的是压缩版本,报错不带行数,也没有源码参考。用maven之类的进行管理时还可能出现依赖冲突。

所以正确的做法是像Spring一样,对它做一个repackaging,其实就是保留版权信息,然后把源代码直接往项目里放,包名调整一下。比如我这么做

字节码的生成本质上几个循环就可以搞定了。 对类型需要类型名称,修饰符,父类,接口,注解。 各字段,需要名称,descriptor,注解。 构造方法(<init>),普通方法,static块方法(<clinit>),它们需要名称,descriptor,注解。相比较语法语义分析来说这一步实在是太简单了。

这里介绍一下ASM库的组成吧。

ASM库主要由各个Visitor构成。而Visitor都是abstract的类型,我们实际需要用到的是Writer。

  • 类 ClassWriter
  • 注解 AnnotationWriter
  • 字段 FieldWriter
  • 方法 MethodWriter

其中,只有ClassWriter是需要手动构造的,其他几个都是可以通过方法调用来获取的。

new ClassWriter(ClassWriter.COMPUTE_FRAMES)

建议参数中的COMPUTE_MAXS不要加上。因为栈的弹出 我们需要在字节码生成步骤手动完成(当然,这取决于你的语义分析输出,我的输出是基本不带POP的,因为POP可以很自然的由当前栈深度分析出来,只有明确需要POP的地方才在语义分析中加上)。
比方说这样一条语句(Integer.valueOf(1)),它将返回一个Integer类型的值。但是这个值没有被变量或者字段接收,所以需要将其pop掉。这时可以分析出当前栈深度为1,需要pop一次。于是在此加入一个pop,并将当前栈深度减1。
实际上,要考虑的不仅仅是栈深度,还要考虑栈占用一个位置还是两个位置。比如doublelong就会占用两个栈的位置,pop时不能用pop指令,而需要使用pop2。比如这里的实现,定义了一个结构来指定占用多少的栈深度,并合理的pop出去。
由于有了这个自动pop的机制,栈最大深度也可以顺便做出来,不必使用自动计算的最大深度了。

#生成器 在字节码生成中,我定义了这样几个工具方法,来使代码逻辑更明确

这些东西经常需要获取,所以单独拎出来实现一下。

对于字段、方法、注解等结构自然也是各管各的分开实现:

其中buildAnnotation经常被调用,因为不管是类,字段还是方法,都可能会有注解,甚至注解中还可以包含注解。所以上述这几个方法内部都有buildAnnotation的调用。

#指令 我实现的语义分析输出的指令与字节码非常接近,所以对每一个指令加一个if分支,并调用对应的方法构造指令即可。

ASM将指令依据调用所需操作数(不是栈内操作数)进行了分类。

  • void visitInsn(int opcode) 不带任何操作数的指令
  • void visitIntInsn(int opcode, int operand) 只带一个整数作为操作数的指令
  • void visitVarInsn(int opcode, int var) 与局部变量相关的指令
  • void visitTypeInsn(int opcode, String type) 接收一个internal name的指令
  • void visitFieldInsn(int opcode, String owner, String name, String desc) 接收一个字段的指令。字段由类型/名称/descriptor表示
  • void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) 接收一个方法的指令。方法由类型/名称/descriptor/是否为接口方法 表示
  • void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) InvokeDynamic特有指令
  • void visitJumpInsn(int opcode, Label label) 跳转指令
  • void visitLdcInsn(Object cst) 取常量池指令。这里的参数会自动加到常量池中去。

到此,整个编译器主体已经完成(因为是JVM语言,所以编译目标到字节码即可)。然而,接下来要做的工作还有很多,Evaluator,REPL,编译器交互,语法高亮,ide支持等。不过至少最困难的部分终于结束了!

下一篇说说Evaluator和REPL怎么实现~

最后,希望看官能够关注我的编译器哦~Latte

© 著作权归作者所有

wkgcass
粉丝 22
博文 19
码字总数 25933
作品 3
苏州
程序员
私信 提问
Java 字节码工具 ASM 在 web services 开发中的应用

在基于 JAX-WS 标准的 web services 的开发中,不少实际场景都是希望采用自底向上的开发方式, 即基于已有的 Java bean 来创建 web services 。WebSphere Application Server ( 以下简称 WA...

IBMdW
2011/09/26
2K
2
ASMSupport 0.4 版本发布,Java 字节码操作

ASMSupport 0.4发布,0.4版本主要改变是采用了全新的Dummy方式的API来生成class,比如希望生成如下代码 0.3以前版本 新版本 除此之外还有如下突破。 新特性 增加全新Dummy方式API 采用链式结...

Erroooooor
2015/04/07
1K
6
深入字节码 -- 使用 ASM 实现 AOP

AOP 的概念已经不是什么新鲜事物,所以我在这里就不在介绍 Aop 的概念。目前市面上要做到 Aop 是一件十分简单的事情。Spring、AspectJ、CGLib等等都可以帮助你达到目的,但是它们也只不过是一...

哈库纳
2013/09/20
0
35
深度探讨Java字节代码的操纵方法

本文为IBM工程师成富编写的《Java深度历险》的第一部分Java字节代码的操纵,像这样Java语言的深度理解和运用还没有很多文章,我们把他奉献给读者,希望读者们喜欢。 51CTO编者按:我们曾给大...

mj4738
2011/11/02
0
0
Android 编程必看的十个建议

A:成为一名真正的Android高手必须掌握和遵循的一些准则: 1)学会懒惰 aDon't Reinvent the Wheel(不要重复发明轮子)。 bInventing the Wheel(发明轮子)。 cDon't Reinvent the Wheel(不要重...

迷途d书童
2012/03/26
213
0

没有更多内容

加载失败,请刷新页面

加载更多

mysql报错 [ERROR] Fatal error: Can't open and lock privilege tables: Table 'mysql.host' doesn't exist

CentOS 6.5 下安装配置 mysql 使用yum安装,具体过程参见最下边的参考文章。 安装之后启动失败: [root@localhost ~]# service mysqld startStarting mysqld: ...

BG2KNT
19分钟前
1
0
IOC的学习(1)

IOC IOC创建bean的4种方式: 无参构造器, 有参构造器,其中<constructor-arg>可以通过index="0"或者type="int"来指定构造方法参数。 静态工厂方法,factory-method。 普通工厂方法,需要指定......

太猪-YJ
33分钟前
1
0
tomcat 莫名奔溃问题

Apr 24, 2019 6:18:11 PM org.apache.coyote.AbstractProtocol pause INFO: Pausing ProtocolHandler ["http-nio-8080"] Apr 24, 2019 6:18:12 PM org.apache.coyote.AbstractProtocol pause......

mellen
50分钟前
3
0
组件开发规范 class名身份识别

组件需要通过一个组件共有的class来标识这个组件,外部调用的时候,可以通过锁定这个class来方便地改变组件的css样式。 设置方式 .my-checkbox { width: 20px; height: 20px; font-...

Carbenson
58分钟前
3
0
如何在工作中快速成长?致工程师的10个简单技巧

阿里妹导读:阿里有句非常经典的土话,“今天的最好表现,是明天的最低要求。”如何挖掘潜能、发现更好的自己?今天,阿里巴巴高级无线开发专家江建明将认知升级的方法总结出来,帮助你获得快...

阿里云云栖社区
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部