当前位置: 首页 > news >正文

Javac编译器源代码分析

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

Javac编译器源代码分析 博客分类: java

Javac编译器的编译流程主要如下图:

 

 

 

各个阶段的作用:

 

词法分析:

 

主要的作用就是读入Java源代码文件,生成Token流,用到的类如下图:

 

 

 

 

 

 

Scanner调用nextToken()方法,返回一个Token。

 

Scanner它内部究竟是怎么获得Token的呢?

 

首先它会先把 Java源文件转为Char[]数组,逐个Char去判断,遇到单词分隔符(空格)、分隔语义时,分析出Java源文件中的词。再把分析出来的单词 Char[]数组传给Table.fromChars(chars)方法,Table会生成chars的hash值,也就是Table.hashs哈希表 的索引,当哈希表里不存在相应的Name时,生成新的一个Name,把它存入到哈希表Table.hashs中。再调用用 Keywords.key(name),直接由Keywords返回Token值。Keywords中存储的就是Name和Token的关系映射,它负责 将字符集合对应到Token。

 

语法分析:

 

主要把Token流组装成一棵基本的语法树。是一个递归下降且运算符优先级的语法分析器,使用com.sun.tools.javac.parser.Parser类,根据语法由Token序列生成相应的树节点,组装成抽象语法树。

 

语义分析:

 

语义分析包括:输入到符号表->  注解处理->标注(Attr)和检查(Check)->数据流分析(Flow)->数据流分析(Flow)->转换类型:(TransTypes)->  解除语法糖:(Lower)

 

输入到符号表:

 

使用com.sun.tools.javac.comp.Enter类,此过程每个编译单元的抽象语法树的顶局节点都先被放到待处理列表中并逐个处理列表中的节点

 

所有的类符号被输入到外围作用域的符号表中

 

确定类的参数(对泛型类型而言)、超类型和接口

 

如果需要添加默认构造器

 

将类中出现的符号输入到类自身的符号表中

 

分析和检查代码中的annotation

 

 注解处理:annotation processing

 

使用com.sun.tools.javac.processing.JavacProcessingEnvironment类,并且支持用户自定义的annotation

 

编译时lombook对java文件进行编译之后会再次进入Parse and Enter步骤

 

 标注(Attr)和检查(Check):

 

是语义分析的一个步骤,使用com.sun.tools.javac.comp.Attr类和com.sun.tools.javac.comp.Check类

 

主要作用有:

 

将语法树中名字、表达式等元素与变量、方法、类型等联系到一起

 

检查变量使用前是否已声明

 

推导泛型方法的类型参数

 

检查类型匹配性

 

进行常量折叠(将常量语法树合并)

 

数据流分析(Flow):

 

使用com.sun.tools.javac.comp.Flow类

 

检查所有语句都可到达

 

检查所有checked exception都被捕获或抛出

 

检查所有局部变量在使用前必项确定性赋值

 

 检查有返回值的方法必须确定性返回值

 

检查变量的确定性且不重复赋值

 

转换类型:(TransTypes)

 

使用com.sun.tools.javac.comp.TransTypes主要作用是将泛型java代码转换成普通的java代码

 

eg:

 

List<Integer> list = Arrays.asList(1, 2, 3);

 

int i = list.get(0);

 

转换后:

 

List list = Arrays.asList(1, 2, 3);

 

int i = (Integer)list.get(0);为了保证泛型的语义,增加了强制类型转换

 

 解除语法糖:(Lower)

 

使用com.sun.tools.javac.comp.Lower类

 

消除if(false){…}形式的无用代码

 

将含有语法糖的语法树改写为含有简单语言结构的语法树

 

eg

 

 具名内部类,匿名内部类,类字面量

 

自动装箱拆箱

 

断言

 

foreach循环

 

enum或String类型的switch(java7)

 

eg:

 

List<Integer> list = Arrays.asList(1, 2, 3);

 

int i = list.get(0);

 

转换后:

 

List list = Arrays.asList(//自动装箱拆箱

 

new Integer[]{

 

Integer.valueOf(1),

 

Integer.valueOf(2),

 

Integer.valueOf(3)

 

}

 

);

 

int i = ((Integer)list.get(0)).intValue();

 

 

 

生成字节码:(Gen)

 

使用com.sun.tool.javac.jvm.Gen

 

将实例成员初始化器收集到构造器中成为<init>()

 

将静态成员初始化器收集为<clinit>()

 

从抽象语法树生成字节码

 

后序遍历语法树

 

进行最后的少量代码转换

 

    String的+操作被生成为StringBuilder操作

 

    x++/x–在条件允许时被优化为++x/–x

 

    etc …

 

从符号表生成Class文件

 

    生成Class文件的结构信息

    生成元数据(包括常量池)

转载:http://beiden.me/archives/2660.htm

转载于:https://my.oschina.net/xiaominmin/blog/1598053

相关文章:

  • 物极必反,滥用闭包的结果就是回归结构化编程
  • 2017 年终总结 —— 在路上
  • 加密算法(对称加密)AES、DES (非对称加密)RSA、DSA
  • Hadoop集群(第10期)_MySQL关系数据库
  • python学习笔记(四)字符串及字符串操作
  • 【Dalston】【第六章】API服务网关(Zuul) 下
  • 解决 Nginx + PHP-FPM (Permission denied)报错的办法
  • sqlvarchar后自动填充空格解决办法(SET ANSI_PADDING)
  • 当文本输入框和是否勾选在同一列表时,你懵圈了吗
  • 01月03日三周二次【Python基础进阶】
  • linux下SVN忽略文件/文件夹的方法
  • Docker Registry Server 搭建,配置免费HTTPS证书,及拥有权限认证、TLS 的私有仓库
  • 5 秒创建 k8s 集群 - 每天5分钟玩转 Docker 容器技术(115)
  • 9.2. Buffering and Caching
  • golang 新人入门配置学习
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • 30秒的PHP代码片段(1)数组 - Array
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • Babel配置的不完全指南
  • Docker容器管理
  • echarts花样作死的坑
  • gcc介绍及安装
  • JS函数式编程 数组部分风格 ES6版
  • leetcode-27. Remove Element
  • Linux各目录及每个目录的详细介绍
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Spark in action on Kubernetes - Playground搭建与架构浅析
  • ucore操作系统实验笔记 - 重新理解中断
  • vue 配置sass、scss全局变量
  • vue数据传递--我有特殊的实现技巧
  • 关于使用markdown的方法(引自CSDN教程)
  • 模型微调
  • 批量截取pdf文件
  • 整理一些计算机基础知识!
  • # Panda3d 碰撞检测系统介绍
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #{}和${}的区别是什么 -- java面试
  • #13 yum、编译安装与sed命令的使用
  • #DBA杂记1
  • #ifdef 的技巧用法
  • ${ }的特别功能
  • (70min)字节暑假实习二面(已挂)
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (附源码)计算机毕业设计高校学生选课系统
  • (学习日记)2024.02.29:UCOSIII第二节
  • (一) springboot详细介绍
  • (转)Linq学习笔记
  • ./configure、make、make install 命令
  • .NET Core 将实体类转换为 SQL(ORM 映射)
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .Net6使用WebSocket与前端进行通信
  • .NET中使用Protobuffer 实现序列化和反序列化
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • @Autowired注解的实现原理
  • @SentinelResource详解