新闻正文

Javac1.7编译器源码分析_简介与安装

来源:JAVA天堂  J2SE  2007-6-5 00:33:22 网友评论 0 条 字体:[ ] ~我要投稿!

1.1:简介:

1.1.1 javac版本

SUN公司在2006年11月份已将java语言编译器(javac)源码通过GPLv2的方式开源,
还建立了“the Open-Source JDK Community”,网址是:http://openjdk.java.net/


截止到写这篇文章时,最新的javac Source Release已到了b13,
一般是半个月出一个beta版,从b04到b13变化都不大,javac类文件没有添加一个。
本文以及后续文章都是基于以下版本:
compiler-7-ea-src-b10-21_mar_2007 (为了方便起见,以后都简写成javac1.7)


1.1.2 我最初想到要分析javac源码的原因

a 看编译原理的书理论太多,想找个实际的编译器验证一下理论
b 之前在JDK1.4下写过一些java程序
c 对javac感兴趣,想要了解所有细节
d 要是还想分析HotSpot VM,先看javac有利
e 偶尔想到要反编译别人的代码


1.1.3 分析javac源码前最好具备的条件

a 编译原理的知识基本上忘记了不要紧,
  但还记得有LL(1)文法、递归下降算法、运算符优先这几个名词

b 知道基本的java语言语法,
  要是像我一样起初不懂Java 5之后的语言新特性也不要紧

c 越有耐心越好


1.1.4 java语言编译器是用什么语言编写的?

javac1.7的源代码本身是用java语言写的(用编译原理的术语叫“自举”),
源代码总行数不到8万行。

在James Gosling的blog上有一篇文章:
“Compiler fun” (http://blogs.sun.com/jag/entry/compiler_fun)
里面有提到最初的java语言编译器是用C语言写成的,不过我不能准确的知道从哪个
JDK发行版开始正式用java语言重写编译器,我尝试在JDK1.4到JDK1.6的tools.jar文件中
寻找javac,只能确定在JDK1.4到JDK1.6内嵌的java语言编译器都是java语言写的。

JDK1.6中的javac与开源的javac1.7生成的字节码几乎没有差别,这也肯定了一点:
开源的javac1.7并不是SUN公司为开源社区单独开发的一个版本,
javac1.7最终也会纳入未来的JDK1.7一起发行。

在“the Open-Source JDK Community”的邮件列表上也有一封邮件证实了这一点:
主题:OpenJDk7 opensource compiler final Java 7 compiler?
URL :https://openjdk.dev.java.net/servlets/ReadMsg?list=compiler-dev&msgNo=270


1.1.5 javac1.7编译流程概述

javac1.7的编译流程可以简单分为以下主要阶段:
(只大概说了一下,还有无数的细节问题会在以后详述,
有看到很讨厌的名词可以直接跳过这一节)

1) javac命令行选项及选项参数处理

   这一阶段主要是识别javac命令行选项是否是合法的,选项参数是否正确


2) 词法分析

   从头到尾分析源文件的字符流,形成关键字、标识符、数字、运算符等等
   具有独立意义的token序列,并去掉源文件中的空白与注释。


3) 语法分析

   词法分析在javac1.7中其实是做为语法分析阶段的一个过程(或方法)来
   驱动的,整个语法分析阶段完成的任务就是按照java语言的LL(1)文法
   采用递归下降算法并结合运算符优先规则,对token序列构造一棵
   抽象语法树(abstract syntax tree)


4) 符号识别(符号表)

   一个包、一个类、一个方法、一个字段都可以抽象成一个符号(symbol),
   不同种类的符号之间可以有包含嵌套关系:
   一个包符号可以包含多个类符号,
   一个类符号可以包含多个方法符号与多个字段符号。

   这一阶段的任务就是识别出各类符号,并对不同种类的符号按
   照包含嵌套关系进行归类,并挂接到抽象语法树对应的结点域。


5) 注释处理(可选阶段)


6) 属性分析(或称语义分析)
   这一阶段包含了一个复杂的类型系统,语义分析阶段检查语言规范中
   定义的各类规则


7) 数据流分析

   这一阶段主要是检查final类型的字段与方法中定义的局部变量是否被赋值


8) Desugar

   在Java 5之后增加了很多语言新特性,但是JVM规范却没有什么变动,
   JVM指令集也没有增加,所以在这一阶段的任务主要是把采用新语言
   特性写成的源代码自动翻译转换成未使用新特性写成的代码。
   如:泛型类到普通类的转换,enhanced for loop到普通for loop的转换。
 

9) 代码生成

   构造常量池、筛选指令、生成class文件。


9) 错误处理:

   错误处理贯穿编译流程的所有阶段


其他:
javac1.7中没有使用像Lex、YACC这样的生成器工具,
词法、语法分析与代码生成全都是手工实现的,具有简单、灵活、高效的
特点,传统编译原理课本上讲授的知识更具通用性,但过于复杂,效率也是
个问题。
另外,可惜的是javac1.7(包括sun公司以往发行的JDK中内置的javac)不是
一个优化编译器,javac1.7并没有独立的优化阶段,
散落在其他阶段的“优化”可以省略不计。

比如:(例子不考虑人的因素,只考虑编译器的行为):

java 代码
  1. package my.test;   
  2. public class Test {   
  3.     Test() {   
  4.         int v1=1;   
  5.         while(v1<10000) {   
  6.             int v2=5;   
  7.             v1=v1+v2*2;   
  8.         }   
  9.     }   
  10. }  

用javac1.7或JDK1.6.0生成的字节码如下(部分内容)


(用命令行“javap -verbose my.test.Test”查看):
---------------------------------------------------
my.test.Test();
  Code:
   Stack=3, Locals=3, Args_size=1
   0: aload_0
   1: invokespecial #1; //Method java/lang/Object."":()V
   4: iconst_1  //将常量1压入堆栈
   5: istore_1  //将常量1弹出堆栈并存入局部变量v1,
   6: iload_1   //将局部变量v1的值压入堆栈
   7: sipush 10000   //将常量10000压入堆栈
   10: if_icmpge 24  //弹出常量10000,弹出局部变量v1的值,局部变量v1的值>=10000结束循环
   13: iconst_5  //将常量5压入堆栈
   14: istore_2  //将常量5弹出堆栈并存入局部变量v2,
   15: iload_1   //将局部变量v1的值压入堆栈
   16: iload_2   //将局部变量v2的值压入堆栈
   17: iconst_2  //将常量2压入堆栈
   18: imul      //弹出常量2,弹出局部变量v2的值,相乘后将结果压入堆栈
   19: iadd      //弹出结果,弹出局部变量v1的值,相加后将结果压入堆栈
   20: istore_1  //弹出结果并存入局部变量v1
   21: goto 6 //转到6: iload_1
   24: return
---------------------------------------------------

理想的优化编译器应该能生成如下类似的代码:

java 代码
  1. package my.test;   
  2. public class Test {   
  3.     Test() {   
  4.         int v1=1;   
  5.         while(v1<10000) {   
  6.             v1=v1+10;//v2=5与v2*2总是不变的,可以合并成10   
  7.         }   
  8.     }   
  9. }  


更理想的优化编译器应该能生成如下类似的代码:

java 代码
  1. package my.test;   
  2. public class Test {   
  3.     Test() {}//局部变量v1没有任何用处,完全可以删除   
  4. }  

关于编译流程简短说明的文档也可参考
Peter von der Ahé(javac编译器的主要开发者,前段时间已离开SUN公司)
在“the Open-Source JDK Community”的邮件列表上回复的一封邮件
主题:A set ot tutorials about the compiler
URL :https://openjdk.dev.java.net/servlets/ReadMsg?list=compiler-dev&msgNo=89


1.1.6 在没有任何设计文档的前提下如何分析javac1.7源码?

我只说说我采用的方法(我是第一次分析别人的源代码):
1) 找到一种最简单的办法完成源代码的第一次编译
2) 找到第一个开始运行的类文件(也就是找到切入点)
3) 粗略看一下这个类文件定义了哪些字段,有构造方法的话,
   粗略看一下构造方法中做了哪些初始化工作
4) 要是定义的字段、构造方法太多,把它们都copy一份,单独放到一个文件

5) 找到第一个被运行的方法,
   在方法开头和末尾打上Debug(包装System.out.println()后写成的一个类),
   觉得关键的字段(或局部变量),用自己喜欢的方式也打上Debug,
   如果类文件源码超过200行(javac1.7源码中有许多核心类文件大多超过1000行),
   为了切换方便,把这方法copy一份,单独放到一个文件

6) 当在一个方法中调用了另一个类的方法时,转到3)
7) 当一个类文件中定义的方法有85%都已Debug过了,从头到尾细细分析一遍类文件
8) Debug的输出信息最好重定向到一个自定义的文件
9) 方法中有复杂算法时最好用笔画在纸上

10)有很多个方法同时来回调用时,把每个方法按调用的顺序单独打开,对照Debug
   信息一起看(我经常打开5、6个EditPlus窗口实例同时看20几个类文件)

11)记住随心所欲地想把一个个类文件不打Debug、不按流程顺序分析,是非常低效
   的一种方法,除非这个类文件很独立,只是简单的字段值存取功能。

 

1.2:安装

1.2.1 运行环境

我的OS是Windows XP

建议安装JDK1.6,我的JDK版本是
-------------------------------
java version "1.6.0-beta2"
Java(TM) SE Runtime Environment (build 1.6.0-beta2-b86)
Java HotSpot(TM) Client VM (build 1.6.0-beta2-b86, mixed mode, sharing)
-------------------------------

安装JDK后,请在系统变量Path中加入 %JAVA_HOME%bin,
其中%JAVA_HOME%是JDK安装目录。


1.2.2 下载javac1.7源码

下载地址:
http://www.java.net/download/openjdk/jdk7/promoted/b10/compiler-7-ea-src-b10-21_mar_2007.zip
解压后会有一个“compiler”目录,
如果你习惯使用Ant、NetBeans或其他IDE工具编译源码,请直
接参考“compilerREADME.html”文件,然后跳到“第1.3节”;
如果你像我一样不会用(或不想用)IDE或想操控一切,
请按下面的简单步骤操作:


1.2.3 下载附件中的"Javac.jar"文件,解压到一个目录(这里以“F:Javac”为例)
(注:"Javac.jar"文件只包含了“compilersrcshareclasses”目录下的
两个子目录“com”与“javax”,其他子目录或文件都是我自建的,javac1.7源码中
还包含了无数的测试用例,我觉得它太繁琐了,就自己一边看源码,一边写自己的
测试例子,所以我把它省略掉了)


1.2.4 编译javac1.7源码

打开一个Dos命令行窗口,切换到“F:Javac”目录
输入“com”按回车,稍等片刻就可以完成编译


1.2.5 用javac1.7编译其他java源文件

打开一个Dos命令行窗口,切换到“F:Javac”目录
输入“run”按回车,打开“F:Javacmyout.txt”文件,就可以看到Debug信息。
在F:Javacrun.bat文件中默认是编译F:JavacbinmysrcmytestTest.java文件
你可以随意替换成你自己的java源文件

1.2.6 javac1.7源码的切入点是F:JavaccomsuntoolsjavacMain.java文件

 

1.3:几个有帮助的网址

James Gosling 的blog:
http://blogs.sun.com/jag/

Peter von der Ahé 的blog:
http://blogs.sun.com/ahe/

the Open-Source JDK Community:
http://openjdk.java.net/

The Java Language Specification, Third Edition:
http://java.sun.com/docs/books/jls/third_edition/html/j3TOC.html

The JavaTM Virtual Machine Specification Second Edition
http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html



收藏到ViVi   收藏此页到365Key
上一篇:从Coding Fan到真正的技术专家
下一篇:Spring开发入门问题集锦
用户名:新注册) 密码: 匿名评论 [所有评论]
评论内容:不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
本栏搜索
  • Google
   网站首页 -  网站地图 -  技术学习 -  网站投稿 -  帮助中心
Copyright 2003-2008 www.javah.net All Rights Reserved
2008 如果你喜欢本站 请收藏本站 并推荐给你的朋友一起分享