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

「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;

在抽象语法树仍然存在字面量 12 和操作符 +,但经过代码折叠,变量的值会被标记为 3;因此在代码里定义 a=1+2a=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 的编译过程 前端编译: 编译器的前端&#xff0c;将 Java 文件转变成 Class 文件的过程&#xff1b;如 JDK 的 javac、Eclipse JDT 中的增量式编译器 ECJ&#xff1b;即使编译: JIT&#xff0c;Just In Time Compiler&#xff0c;在运行期将字节码转变成本地机器码的过程&…...

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/ccNGjN9sGugL​kdocs.cn/l/ccNGjN9sGugL A题思路&#xff1a;&#xff08;具体以题目解决问题顺序为主&#xff09; 这道题分析植被就行&#xff0c;主要涉及不同植被间的相互作用&#xff0c;有竞争有相互促进&#xff0c;我查了下“植物科学数…...

前端上传文件

前言 以 vue 举例&#xff0c;原生 html css js 现在应该很少有人去写了 一、绘制样式 绘制两个标签&#xff0c;一个 <div></div> &#xff0c;一个 <input type"file" />&#xff1b; 为 <div></div>添加 css 样式&#xff0c…...

后台管理系统中选项卡的动态渲染

动态渲染选项卡其中router-link是为了当点击选项卡时跳转到选项卡所在的列表选项卡需要动态渲染&#xff0c;其中active是当选中后激活选中的样式为图标添加点击删除事件在状态机配置tabMenu&#xff08;为了动态渲染&#xff09;需要在tabMenu添加&#xff1a;active、title、…...

网络层重点协议之IP协议(IPv4)

网络层的作用就是来路由的选择&#xff0c;规划传输的路径&#xff0c;其中网络层的重点协议就是IP协议。4位版本号版本号的取值只有4和64位首部长度描述了IP报头有多长&#xff0c;报头中有一个选项部分&#xff0c;是变长的&#xff0c;是可有可无的部分&#xff0c;所以IP报…...

CentOS Stream 8配置DNS

1&#xff1a;用CentOS搭建DNS的目的是想解析一台下载服务器&#xff0c;IP地址172.18.0.58&#xff0c;现在是用IP地址方的式访问&#xff0c;想搭建DNS服务器用域名的方式访问。 使用下面的命令查看一下当前系统的Bind版本。 yum info bind 版本是9.11.36.我的CentOS是最小…...

【roLabelImg】windows下旋转框标注软件安装、使用、rolabelimg打包成exe

主要参考&#xff1a; roLabelImg安装、使用、数据格式roLabelImg在Win10系统下打包成exe - 问雪的文章 - 知乎 一、安装 1.1 直接下载exe运行 劝大家直接去下别人编译好的吧&#xff0c;本来是训练模型标记的&#xff0c;结果搞了半天去了解这个软件了&#xff0c;哎~ 我…...

2023美赛F题:绿色经济

文章目录背景要求词汇表背景 国内生产总值&#xff08;GDP&#xff09;可以说是最知名且最常用的衡量一个国家经济健康的指标之一。它通常用于确定一个国家的购买力和贷款能力&#xff0c;为国家提出提高GDP的政策和项目提供了动力。GDP “衡量一个国家在一段特定时间内生产的…...

华为OD机试 - 剩余可用字符集 | 备考思路,刷题要点,答疑 【新解法】

最近更新的博客 【新解法】华为OD机试 - 关联子串 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 停车场最大距离 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 任务调度 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试…...

“笨办法”学Python 3 ——练习 40. 模块、类和对象

练习40 模块、类和对象 知识点&#xff1a; 40.1.0 模块就像字典 my_stuff[apple] #my_stuff是字典&#xff0c;访问字典apple键的值 import mystuff mystuff.apple() #mystuff是模块&#xff0c;模块访问函数apple() print(mystuff.tangerine) #模块访问变量tangerine说明P…...

自动驾驶:BEVDet

自动驾驶&#xff1a;BEVDetIntroductionMethodoloData AugmentationNetwork StructureScale-NMS实验Introduction 作者通过现有的算法&#xff08;LSS&#xff09;、独特的数据增强方案与新的NMS方案整合了一个BEV框架&#xff08;BEVDet&#xff09;。 如下图&#xff1a; …...

vue的组件通信

文章目录3. 组件通信3.1 父组件-->子组件3.3组件自定义事件&#xff08;子->父&#xff09;3.4.全部事件总线&#xff08;两代以上&#xff09;3.5消息的订阅与发布3. 组件通信 3.1 父组件–>子组件 <Student name"张三" :age"18"></St…...

Typescript的定义及使用优势

编程语言的类型&#xff1a; 动态类型语言 (Dynamically Typed Language&#xff09;静态类型语言 (Statically Typed Language&#xff09; 两种语言的含义及区别&#xff1a; 比如JS、python就是动态类型语言&#xff0c;什么是动态类型语言&#xff0c;通俗的讲&#xff0…...

正则验证:手机号码验证

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title></title> </head> <body> 手机号码<input type"text" id"phone"> <span…...

视频融合 flv流格式对接(上)

FLV 是FLASH VIDEO的简称&#xff0c;FLV流媒体格式是随着Flash MX的推出发展而来的视频格式。由于它形成的文件极小、加载速度极快&#xff0c;使得网络观看视频文件成为可能&#xff0c;它的出现有效地解决了视频文件导入Flash后&#xff0c;使导出的SWF文件体积庞大&#xf…...

提问:影视剪辑解说都是怎样配音的,软件合成还是自己配音?

“影视剪辑解说都是怎样配音的&#xff0c;软件合成还是自己配音&#xff1f;”这是一个很好的问题并且困扰着很多人&#xff0c;因为不知道该如何选择。究竟应该使用软件来完成配音工作呢?还是自己动手配音呢&#xff1f;这是一个很难回答的问题。如果你问我的话&#xff0c;…...

基于RK3588的嵌入式linux系统开发(二)——uboot源码移植及编译

由于官方的SDK占用空间较大&#xff08;大约20GB左右&#xff09;&#xff0c;需要联系相关供应商提供&#xff0c;且官方的SDK通过各种脚本文件进行集成编译&#xff0c;难以理解系统开发的详细过程。本章介绍直接从官方Github网站下载源码进行移植&#xff0c;进行uboot移植及…...

excel报表技巧:几个关于汇报演示方面的小功能

年终了&#xff0c;总结汇报避免不了。如果你的PPT还不够好&#xff0c;那就直接用Excel做汇报吧~这里有5条小技巧&#xff0c;可以帮助你最高效地展示自己的成绩报表&#xff01;想象一下&#xff0c;用SHIFTCTRLF1全屏显示你的工作表&#xff0c;配合上CtrlPageDown进行工作表…...

【数据结构与算法】Manacher算法

&#x1f320;作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《数据结构与算法要啸着学》 &#x1f387;座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...