JVM源码剖析之JIT工作流程

chatgpt/2023/9/26 13:00:17

版本信息:

jdk版本:jdk8u40

思想至上

Hotspot中执行引擎分为解释器、JIT及时编译器,上篇文章描述到解释器过度到JIT的条件。JVM源码剖析之达到什么条件进行JIT优化 这篇文章大致讲述JIT的编译过程。在JDK中javac和JIT两部分跟编译原理挂钩,而编译原理抛开内部实现的算法,从思想的角度出发可以分为前端、中间IR、后端,见图1.1描述。比如拿javac举例,开发人员编写好xxx.java 文件,通过javac命令把xxx.java 文件编译成 xxx.class二进制文件交给JVM执行,其中编译的流程就如图1.1的流程。
图1.1 编译原理思想图
图1.1 编译原理思想图

而本文论述JIT,所以我们需要把编译原理的思想带入到JIT中,见图1.2,这里的输入为达到JIT编译阈值的方法对应的字节码,经过前端、中间IR语言、后端(这里为了容易理解,把前端、中间IR语言、后端想象成一个编译的黑盒程序)后得到输出结果为ISA指令集(ISA:CPU平台可执行指令)
图1.2 JIT的编译思想图
图1.2 JIT的编译思想图

源码论证

流程图先放在最前面,如图1.3
图1.3 JIT工作流程
图1.3 JIT工作流程

由图1.3可以得知Java工作线程(Java项目中运行的线程)和编译线程之间通过队列来通信(当然,这也是线程通信的最基本方式),CompileTask作为通信的载体,当Java线程执行某个方法当方法达到JIT优化的阈值或者回边计数器达到了阈值,此时会创建CompileTask投递到CompileQueue队列中。

/*
method_invocation_event->compile->submit_compile->compile_method->compile_method_base->create_compile_task
*/
// src/share/vm/compiler/compileBroker.cpp 文件中
CompileTask* CompileBroker::create_compile_task(CompileQueue* queue,int           compile_id,methodHandle  method,int           osr_bci,int           comp_level,methodHandle  hot_method,int           hot_count,const char*   comment,bool          blocking) {CompileTask* new_task = allocate_task();new_task->initialize(compile_id, method, osr_bci, comp_level,hot_method, hot_count, comment,blocking);// 给CompilerThread线程对应的队列投递编译任务。queue->add(new_task);return new_task;
}

java工作线程给编译线程队列投递任务后,此时编译线程开始干活,接收队列的compileTask任务,开始执行编译工作

// src/share/vm/compiler/compileBroker.cpp 文件中
void CompileBroker::compiler_thread_loop() {CompilerThread* thread = CompilerThread::current();// 拿到当前编译线程对应的队列CompileQueue* queue = thread->queue();…………while (!is_compilation_disabled_forever()) {// 从队列中获取到任务CompileTask* task = queue->get();if (task == NULL) {continue;}…………// 执行任务invoke_compiler_on_method(task);}
}

接下来的编译工作需要区分c1还是c2编译器,这个在Java工作线程投递compileTask任务的时候就已经确定(因为在检查阈值的时候即可确定)。在Hotspot中c1编译器用Compiler类作为抽象,c2编译器使用C2Compiler类作为抽象,不管是c1和c2都继承与AbstractCompiler,AbstractCompiler类中给予编译器公共的抽象。为了篇幅的简单,我们采用c1,也叫做client编译器。

/*
invoke_compiler_on_method->Compiler::compile_method(Compiler为c1编译器)->Compilation::Compilation->Compilation::compile_method
*/
// src/share/vm/c1/c1_Compilation.cpp 文件中
void Compilation::compile_method() {…………// compile methodint frame_size = compile_java_method();if (InstallMethods) {		// 在c1编译器中,默认为true,也即编译完成后安装机器码。// 安装代码(实际上就是把机器码执行地址放入Method对象中,下次执行方法就会执行JIT编译好的代码)install_code(frame_size);}…………
}int Compilation::compile_java_method() {// 从方法字节码构建出HIR中间语言。{PhaseTraceTime timeit(_t_buildIR);build_hir();}// 从HIR中间语言构建出LIR中间语言{PhaseTraceTime timeit(_t_emit_lir);_frame_map = new FrameMap(method(), hir()->number_of_locks(), MAX2(4, hir()->max_stack()));emit_lir();}// 从LIR中间语言生成机器代码{PhaseTraceTime timeit(_t_codeemit);return emit_code_body();}
}

在这里插入图片描述

整个c1编译器的编译过程就论述完毕了(仅仅是宏观上,微观上还存在众多算法和平台指令的生成,这个跟编译原理的算法和Hotspot中JIT优化的思想有关,这里不做论述)

这里对IR中间语言做一个简单的论述,为什么Hotspot中JIT需要存在HIR和LIR 2个中间语言呢?在编译原理中,IR的作用是承上启下,由于中间层的出现,这也让前端和后端更加灵活多变,此时,这也让笔者不经想起一句话" 计算机的世界没有加一个中间层解决不了的问题,如果不行,那就再加一层 ",并且有了中间层的出现,便可以在中间表示层做你想做的语言优化工作。说回Hotspot中,既然分了HIR(High-level Intermediate Representation)和LIR(Low-level Intermediate Representation)两层中间层,所以抽象的行为更加的具体,并且模块化更细粒度。HIR在JIT中是平台无关的中间语言,这一层完全可以用来对接字节码,并且做优化工作,优化完毕后,生成LIR中间语言,而LIR中间语言与平台相关,可以说已经非常接近平台相关指令(机器语言),这一层便可以做平台相关的优化工作。一层一层的过度,这像不像解释器过度到JIT的过程。

在GCC编译器中IR中间层就分为GENERIC、GIMPLE、RTL,也是一层一层的过度,最终RTL最接近机器语言的表现形式

在Coins编译器中,IR中间层也是分为HIR、LIR,跟Hotspot一样,从HIR过度到LIR,LIR接近机器语言的表现形式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.exyb.cn/news/show-5313897.html

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

ES-5-进阶

单机 & 集群 单台 Elasticsearch 服务器提供服务,往往都有最大的负载能力,超过这个阈值,服务器 性能就会大大降低甚至不可用,所以生产环境中,一般都是运行在指定服务器集群中 配置服务器集群时,集…

JavaSE类和对象(2)(重点:封装、包、static静态变量和方法)

目录 一、封装 1.封装:从语法来看,就是被private修饰的成员变量或者成员方法。只能在当前类当中使用。 2.快捷键,自动生成set或者get方法 3.限定访问修饰符(private、 protected、public) public:可以理…

《cuda c编程权威指南》03 - cuda小功能汇总

1. 计时 1.1 linux #include <sys/time.h>double cpuSecond() {struct timeval tp;gettimeofday(&tp, NULL);return ((double)tp.tv_sec (double)tp.tv_usec*1e-6); }// 调用 double start cpuSecond(); kernel_name << <grid, block >> > (ar…

生态伙伴 | 华秋硬创联合长虹创投,共同打造更优生态系统

01大赛介绍 中国硬件创新创客大赛始于2015年&#xff0c;由深圳华秋电子有限公司主办&#xff0c;至今已经成功举办八届&#xff0c;赛事范围覆盖华南、华东、华北三大地区&#xff0c;超10个省市区域。 大赛影响了超过45万工程师群体&#xff0c;吸引了35000多名硬创先锋报名参…

如何在线制作闪图?手把手教你快速生成GIF闪图

网上那种卟玲卟领的闪动GIF图片效果非常的炫丽&#xff0c;这种GIF闪图是怎么制作的呢&#xff1f;很简单&#xff0c;只需要使用专业的gif制作&#xff08;https://www.gif.cn/&#xff09;工具-GIF中文网&#xff0c;上传多张颜色、大小不同&#xff0c;内容相同的jpg、png格…

【外卖系统】文件上传与下载

文件上传 文件上传又称upload&#xff0c;将本地图片、视频等文件上传到服务器上&#xff0c;供其他用户下载或者浏览。 form表单&#xff1a;HTML中的form元素用于创建一个包含表单字段的区域&#xff0c;用户可以在该区域输入数据&#xff0c;并通过提交表单将数据发送到服务…

STM32使用HAL库中外设初始化MSP回调机制及中断回调机制详解

STM32使用HAL库之Msp回调函数 1.问题提出 在STM32的HAL库使用中&#xff0c;会发现库函数大都被设计成了一对&#xff1a; HAL_PPP/PPPP_Init HAL_PPP/PPPP_MspInit 而且HAL_PPP/PPPP_MspInit函数的defination前面还会有__weak关键字 上面的PPP/PPPP代表常见外设的名称为…

9.环境对象和回调函数

9.1环境对象 指的是函数内部特殊的变量this&#xff0c;它代表着当前函数运行时所处的环境 作用&#xff1a; 弄清楚this的指向&#xff0c;可以让我们代码更简洁 ➢函数的调用方式不同&#xff0c;this指代的对象也不同 ➢[谁调用&#xff0c;this 就指代谁] 是判断this指向的…
推荐文章