「JVM 编译优化」javac 编译器源码解读
Java 的编译过程
- 前端编译: 编译器的前端,将 Java 文件转变成 Class 文件的过程;如 JDK 的 javac、Eclipse JDT 中的增量式编译器 ECJ;
- 即使编译: JIT,Just In Time Compiler,在运行期将字节码转变成本地机器码的过程;如 HotSpot VM 的 C1、C2 编译器,Graal 编译器;
- 提前编译: AOT,Ahead Of Time Compiler,直接静态将程序编译成目标机器指令集的二进制代码的过程;如 JDK 的 Jaotc、GNU Compiler for the Java(GCJ)、Excelsior JET;
即使编译器在运行期的优化支持了程序执行效率的提升,而前端编译器在编译期的优化支持了程序员的编码效率和语言使用幸福感的提高;
文章目录
- 1. javac 的源码与调试
- 2. 解析与填充符号表
- 3. 注解处理器
- 4. 语义分析与字节码生成
1. javac 的源码与调试
-
JDK 6 以前
,javac 不属于标准 Java SE API,代码独立存放在tools.jar
,使用时需要将路径加入ClassPath;
-
JDK 6 开始
,javac 晋升成标准 Java 类库,源码放在JDK_SRC_HOME/langtools/src/share/classes/com/sun/tools/javac
; -
JDK 9 开始
,整个 JDK 的 Java 类库模块化重构,javac 编译器放在jdk.compiler
模块,存放路径为JDK_SRC_HOME/src/jdk.compiler/share/classes/com/sun/tools/javac
; -
OpenJDK 源码
可以直接执行 javac.Main 的 main() 方法来执行编译,参数与直接使用 javac 命令一致;
从 javac 代码的总体结构看,编译过程大致可以分为 1 个准备过程和 3 个处理过程;
准备过程
: 初始化插入式注解处理器;解析与填充符号表
过程,包括:
a. 词法、语法分析;将源代码的字符流转变为标记集合,构造出抽象语法树;
b. 填充符号表;产生符号地址和符号信息;插入式注解处理器的注解处理
过程: 插入式注解处理器的执行阶段,影响 javac 的编译行为;分析与字节码生成
过程,包括:
a. 标注检查;对语法的静态信息进行检查;
b. 数据流及控制流分析;对程序动态运行过程进行检查;
c. 解语法糖;将简化代码编写的语法糖还原为原有的形式;
d. 字节码生成;将前面各个步骤所生成的信息转化成字节码;
插入式注解可能会产生新的符号,如果有新的符号产生,就必须转回解析、填充符号表的过程重新处理新的符号;
javac 编译入口代码在 com.sun.tools.javac.main.JavaCompiler
类的 compile() 方法;
2. 解析与填充符号表
parseFiles
: 1.1,词法分析、语法分析;enterTrees
: 1.2,输入到符号表;processAnnotations
: 2,执行注解处理;
a. 词法、语法分析
词法分析
,将源代码的字符流转变成标记(Token)集合,字符是程序编写的最小单元,而 Token 是编译的最小单元;关键字、变量名、字面量、运算符等都是 Token,不可再拆分;javac 的词法分析由com.sun.tools.javac.parser.Scanner
类实现;语法分析
,根据 Token 序列构造抽象语法树(Abstract Syntax Tree,AST,描述一个结构正确的源程序,程序语言结构的树形表示),树的每一个节点代表着程序的一个语法结构(Syntax Construct);包、类型、修饰符、运算符、接口、返回值、代码注释等,都可以是一种特定的语法结构;javac 的语法分析由com.sun.tools.javac.parser.Parser
类实现,抽象语法树以com.sun.tools.javac.tree.JCTree
类表示;
b. 填充符号表
- 符号表(Symbol Table),一组符号地址和符号信息构成的数据结构(包含每个编译单元的抽象语法树的顶级节点和 package-info.java 的顶级节点),类似于 Hash 表的键值对存储结构(也可以是有序符号表、树状符号表、栈结构符号表等形式);符号表在语义分析阶段用于语义检查和产生中间代码,在目标代码生成阶段用于地址分配;javac 中填充符号表由
com.sun.tools.javac.comp.Enter
类实现;
3. 注解处理器
Java 在 JDK 5 开始支持注解(Annotations),原只对程序运行期间发挥作用;到 JDK 6 时添加了插入式注解处理器
的标准 API,提前至编译期处理特定注解,可以影响前端编译器的工作过程;
插入式注解处理器相当于编译器的插件,通过这些插件可以读取、修改、添加抽象语法树的任意元素;若插件在处理注解期间对抽象语法树进行修改,编译器将回退至解析和填充符号表的过程,直到插入式注解处理器不再修改抽象语法树;每一次循环称为一个轮次(Round);
编码效率工具 Lombok 通过注解实现自动生成 getter/setter 方法、空置检查、生成受查异常表、生成 equals() 和 hashCode() 等功能,都是依赖插入式注解处理器实现的;
initProcessAnnotations
: 准备过程,初始化插入式注解处理器;processAnnotations
: 完成插入式注解执行处理;若有新的注解处理器需要执行,则通过com.sun.tools.javac.processing.JavacProcessingEnvironment
类的doProcessing()
生成一个新的JavaCompiler
对象,进行后续的编译已处理;
4. 语义分析与字节码生成
语义分析
,经过语法分析得到的抽象语法树可以表示一个结构正确的源程序,但无法保证源程序的语义符合逻辑;语义分析则是对结构上源程序进行上下文相关性质进行检查(类型检测、控制流检查、数据流检查等);
int a = 1;
boolean b = false;
char c = 2;
int d = a + c;
int d = b + c;
char d = a + c;
所有代码都可以构造正确的抽象语法树,但后两句在 Java 语言中是不符合逻辑的(语义分析异常,与具体的语言和上下文环境相关);
attribute
: 3.1,语义分析的标注检查;flow
: 3.2,语义分析的数据及控制流分析;desugar
: 3.3,解语法糖;generate
: 3.4. 生成字节码;
a. 标注检查
- 进行如变量使用前是否已被声明、变量与赋值之间的数据类型是否匹配等的检查;
常量折叠
(Constant Folding),javac 对源代码做的极少优化之一;
int a = 1 + 2;
在抽象语法树仍然存在字面量 1
、2
和操作符 +
,但经过代码折叠,变量的值会被标记为 3
;因此在代码里定义 a=1+2
和 a=3
相比,并不会浪费哪怕一个处理器时钟周期的时间;
javac 的标记检查由 com.sun.tools.javac.comp.Attr
类和 com.sun.tools.javac.comp.Check
类实现;
b. 数据及控制流分析
对程序上下文逻辑进行进一步验证,检查如程序局部变量在使用前是否赋值、方法的每个路径是否都有返回值、是否所有受检异常都被正确处理等;与类加载时的数据及控制流分析的目的一直,但校验范围不同;
public void foo(final int arg){final int var = 0;// do something;
}public void foo(int arg){int var = 0;// do something;
}
两种写法经过 javac 编译所得字节码完全一样,可见局部变量是否被 final 修饰对运行期是完全无影响的(不可知的),变量的不可变仅仅有 javac 编译器在编译期保障的;
javac 的数据及控制流分析由 com.sun.tools.javac.comp.Flow
类实现;
c. 解语法通
语法糖
,指计算机语言中的某种语法,其对语言的编译结果和功能不会有实际影响(JVM 不能支持这些语法,这些语法最终会被编译成基本语法结构),但却可以更方便编写者实用该语言(减少代码量、增加可读性、减少出错几率);如泛型(C# 的泛型是 CLR 支持的,不属于语法糖)、变长参数、自动装箱拆箱等;解语法糖
,将语法糖编译成原始基本语法结构;
javac 的解语法糖由 com.sun.tools.javac.comp.TransTypes
类和 com.sun.tools.javac.comp.Lower
类实现;
d. 字节码生成
把语法树、符号表转发成字节码指令写到磁盘,并进行少量代码添加和转换工作;
代码添加
,如在语法树中添加实例构造器<init>()
和类构造器<clinit>()
;编译器会把语句块(<init>()
的是{}
块,<clinit>()
的是static {}
块)、变量初始化(实例变量和类变量)、调用父类的实例构造器(只有<init>()
,<clinit>()
中无须调用父类的<clinit>()
,但经常会生成调用 java.lang.Object 的<init>()
的代码)等操作收敛到<init>()
和<clinit>()
,并保障一定顺序执行(先父类实例构造器、再初始化变量、最后语句块);代码转换
,如将字符串的加操作替换为 StringBuilder 或 StringBuffer 的 append() 操作;
javac 的字节码生成由 com.sun.tools.javac.jvm.Gen
类实现;将填充了所有信息的符号表输出到 Class 文件由 com.sun.tools.javac.jvm.CLassWriter
类实现;
上一篇:「JVM 原理使用」在远程服务端动态执行临时代码
PS:感谢每一位志同道合者的阅读,欢迎关注、评论、赞!
参考资料:
- [1]《深入理解 Java 虚拟机》
相关文章:
「JVM 编译优化」javac 编译器源码解读
Java 的编译过程 前端编译: 编译器的前端,将 Java 文件转变成 Class 文件的过程;如 JDK 的 javac、Eclipse JDT 中的增量式编译器 ECJ;即使编译: JIT,Just In Time Compiler,在运行期将字节码转变成本地机器码的过程&…...
Leetcode DAY 34: K次取反后最大化的数组和 and 加油站 and 分发糖果
1005.K次取反后最大化的数组和 class Solution:def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:nums sorted(nums, key abs, reverse True)for i in range(len(nums)):if nums[i] < 0:nums[i] -nums[i]k - 1else:continueif k 0:return sum(…...
2023美赛A题思路
在线解析 https://kdocs.cn/l/ccNGjN9sGugLkdocs.cn/l/ccNGjN9sGugL A题思路:(具体以题目解决问题顺序为主) 这道题分析植被就行,主要涉及不同植被间的相互作用,有竞争有相互促进,我查了下“植物科学数…...
前端上传文件
前言 以 vue 举例,原生 html css js 现在应该很少有人去写了 一、绘制样式 绘制两个标签,一个 <div></div> ,一个 <input type"file" />; 为 <div></div>添加 css 样式,…...
后台管理系统中选项卡的动态渲染
动态渲染选项卡其中router-link是为了当点击选项卡时跳转到选项卡所在的列表选项卡需要动态渲染,其中active是当选中后激活选中的样式为图标添加点击删除事件在状态机配置tabMenu(为了动态渲染)需要在tabMenu添加:active、title、…...
网络层重点协议之IP协议(IPv4)
网络层的作用就是来路由的选择,规划传输的路径,其中网络层的重点协议就是IP协议。4位版本号版本号的取值只有4和64位首部长度描述了IP报头有多长,报头中有一个选项部分,是变长的,是可有可无的部分,所以IP报…...
CentOS Stream 8配置DNS
1:用CentOS搭建DNS的目的是想解析一台下载服务器,IP地址172.18.0.58,现在是用IP地址方的式访问,想搭建DNS服务器用域名的方式访问。 使用下面的命令查看一下当前系统的Bind版本。 yum info bind 版本是9.11.36.我的CentOS是最小…...
【roLabelImg】windows下旋转框标注软件安装、使用、rolabelimg打包成exe
主要参考: roLabelImg安装、使用、数据格式roLabelImg在Win10系统下打包成exe - 问雪的文章 - 知乎 一、安装 1.1 直接下载exe运行 劝大家直接去下别人编译好的吧,本来是训练模型标记的,结果搞了半天去了解这个软件了,哎~ 我…...
2023美赛F题:绿色经济
文章目录背景要求词汇表背景 国内生产总值(GDP)可以说是最知名且最常用的衡量一个国家经济健康的指标之一。它通常用于确定一个国家的购买力和贷款能力,为国家提出提高GDP的政策和项目提供了动力。GDP “衡量一个国家在一段特定时间内生产的…...
华为OD机试 - 剩余可用字符集 | 备考思路,刷题要点,答疑 【新解法】
最近更新的博客 【新解法】华为OD机试 - 关联子串 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 停车场最大距离 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 任务调度 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试…...
“笨办法”学Python 3 ——练习 40. 模块、类和对象
练习40 模块、类和对象 知识点: 40.1.0 模块就像字典 my_stuff[apple] #my_stuff是字典,访问字典apple键的值 import mystuff mystuff.apple() #mystuff是模块,模块访问函数apple() print(mystuff.tangerine) #模块访问变量tangerine说明P…...
自动驾驶:BEVDet
自动驾驶:BEVDetIntroductionMethodoloData AugmentationNetwork StructureScale-NMS实验Introduction 作者通过现有的算法(LSS)、独特的数据增强方案与新的NMS方案整合了一个BEV框架(BEVDet)。 如下图: …...
vue的组件通信
文章目录3. 组件通信3.1 父组件-->子组件3.3组件自定义事件(子->父)3.4.全部事件总线(两代以上)3.5消息的订阅与发布3. 组件通信 3.1 父组件–>子组件 <Student name"张三" :age"18"></St…...
Typescript的定义及使用优势
编程语言的类型: 动态类型语言 (Dynamically Typed Language)静态类型语言 (Statically Typed Language) 两种语言的含义及区别: 比如JS、python就是动态类型语言,什么是动态类型语言,通俗的讲࿰…...
正则验证:手机号码验证
<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title></title> </head> <body> 手机号码<input type"text" id"phone"> <span…...
视频融合 flv流格式对接(上)
FLV 是FLASH VIDEO的简称,FLV流媒体格式是随着Flash MX的推出发展而来的视频格式。由于它形成的文件极小、加载速度极快,使得网络观看视频文件成为可能,它的出现有效地解决了视频文件导入Flash后,使导出的SWF文件体积庞大…...
提问:影视剪辑解说都是怎样配音的,软件合成还是自己配音?
“影视剪辑解说都是怎样配音的,软件合成还是自己配音?”这是一个很好的问题并且困扰着很多人,因为不知道该如何选择。究竟应该使用软件来完成配音工作呢?还是自己动手配音呢?这是一个很难回答的问题。如果你问我的话,…...
基于RK3588的嵌入式linux系统开发(二)——uboot源码移植及编译
由于官方的SDK占用空间较大(大约20GB左右),需要联系相关供应商提供,且官方的SDK通过各种脚本文件进行集成编译,难以理解系统开发的详细过程。本章介绍直接从官方Github网站下载源码进行移植,进行uboot移植及…...
excel报表技巧:几个关于汇报演示方面的小功能
年终了,总结汇报避免不了。如果你的PPT还不够好,那就直接用Excel做汇报吧~这里有5条小技巧,可以帮助你最高效地展示自己的成绩报表!想象一下,用SHIFTCTRLF1全屏显示你的工作表,配合上CtrlPageDown进行工作表…...
【数据结构与算法】Manacher算法
🌠作者:阿亮joy. 🎆专栏:《数据结构与算法要啸着学》 🎇座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉…...
【CMake】CMake构建C++代码(一)
在Linux开发过程中,难免会用到CMake来构建你的代码。本文将说明如何构建自己的代码,将自己的代码变为共享库,共其他代码使用。 文章目录在Linux开发过程中,难免会用到CMake来构建你的代码。本文将说明如何构建自己的代码ÿ…...
让我们,从头到尾,通透I/O模型
什么是IO 一句话总结 IO就是内存和硬盘的输入输出 I/O 其实就是 input 和 output 的缩写,即输入/输出。 那输入输出啥呢? 比如我们用键盘来敲代码其实就是输入,那显示器显示图案就是输出,这其实就是 I/O。 而我们时常关心的磁盘…...
Word控件Spire.Doc 【Table】教程(16):C#/VB.NET:在 Word 表格中插入或提取图像
Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下,轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具,专注于创建、编辑、转…...
C++如何实现系统语言切换功能,MessageBox的确认/取消按钮语言显示如何跟程序一致
文章目录前言 一、新建工程二、添加多国语言的资源三、程序语言设置四、语言切换五、字符串处理六、MessageBox的问题七、相关函数和类型参考文章前言 目前很多软件都是要出口到多个国家,多个地区,因此,为软件提供多国语言支持就成为了一个基…...
计算机组成原理学习笔记:循环冗余校验码
循环冗余校验码 CRC 码 循环冗余校验码 (cyclic redundancy Check, CRC) 十进制除法 从熟悉的十进制出发,假设现在你要给另一个人传送882这样的一个10进制数据,为了防止传送数据的过程中某一个数据发生错误你可以和你的另一个小伙伴约定一个除数&…...
Educational Codeforces Round 143 (Rated for Div. 2) A — C
Educational Codeforces Round 143 (Rated for Div. 2) 文章目录A. Two Towers题目大意题目分析codeB. Ideal Point题目大意题目分析codeC. Tea Tasting题目大意题目分析codeA. Two Towers 题目大意 有两个有红蓝两种颜色组成的塔,每次操作可以将其中一个塔顶的色…...
【Unity VR开发】结合VRTK4.0:将浮点数从交互器传递到可交互对象
语录: 愿你熬得过万丈孤独,藏得下星辰大海。 前言: 默认情况下,交互器只能将单个布尔操作传递给可交互对象,后者控制可交互对象上的抓取操作。在其他时候,交互器中的其他操作可能希望传递给可交互对象&…...
【图像分类】基于PyTorch搭建卷积神经网络实现MNIST手写数字识别(附项目完整代码)
写在前面: 首先感谢兄弟们的关注和订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 在【图像分类】基于PyTorch搭建LSTM实现MNIST手写数字体识别(单向LSTM,附完整代码和数据集)文章中,我们使用了…...
4.4 MQC
1. 实验目的 熟悉MQC的应用场景掌握MQC的配置方法2. 实验拓扑 实验拓扑如图4-10所示: 图4-10:MQC 3. 实验步骤 (1) IP地址的配置 AR1的配置 <Huawei>system-view...
ClickHouse列存储(十一)—— ClickHouse
文章目录一、重点内容:1.数据库基本概念2.列式存储3.clickHouse存储设计4.clickHouse典型应用场景二、准备工作:1、了解数据库基本概念2、了解列式存储相关概念3、了解ClickHouse存储设计4、了解 ClickHouse典型应用场景三、详细知识点介绍:1…...
一级a做爰片免费网站迅雷下载/东莞网站排名提升
1. os 这个模块包含普遍的操作系统功能。如果你希望你的程序能够与平台无关的话,这个模块是尤为重要的。即它允许一个程序在编写后不需要任何改动,也不会发生任何问题,就可以在Linux和Windows下运行。一个例子就是使用os.sep可以取代操作系统…...
哪个网站可以上传设计的作品/重庆百度
Flutter webview插件是用来在APP内部加载网页的,它跟Flutter url_launcher插件的不同之处在于:前者只是在app内部打开web网页,而url_launcher则是调用手机默认的功能做事情,例如调用默认的浏览器打开web网页(跳出app了)࿰…...
大连做网站企业/高级seo培训
本题是使得两个链表相加,每个链表中值均为0~9,对于两个链表对应的值相加值sum若大于9,则为sum%10,并在指向的下一对节点的和sum上加1。 做题思路: 判断两链表是否有空链表,若有,直接返回另一个链…...
七牛云加速WordPress/济南seo网站优化
前段时间遇到了这个问题 也百度了很多 不过还是用自己的方法解决了 一个超级简单的方法 简单到令人发指 由于直接写文本太丑了 所以还是截图吧 嘻嘻嘻 假如有一个这样的数组 (这是假如 可能每个人的数据都不一样哦 但是方法都是可用的) 因为我这个项目功…...
成都市区必去的景点/南宁优化网站网络服务
先解释下标题的意思: 就是点击上图中的上传图片之后,出现这个文件选择框的反应时间太长,IE和火狐浏览器还正常点。谷歌和360等浏览器一般要8秒左右才能打开,用户体验太差了。 这里我们要解决这个问题首先就得知道简单的文件上传的…...
wordpress new page/优化方案电子版
近日,360公司董事长周鸿祎做客腾讯科技《新产品经理》系列访谈,期间他将自己多年的产品心得和盘托出,甚至访谈中都不需要腾讯科技发问。不得不说,这 场访谈也是在《新产品经理》系列访谈中最精彩的对话之一。前言少叙,…...