专注虚拟机与编译器研究

2022年2月16日

第63篇-解释器与编译器适配(二)

摘要: 这一篇详细介绍相关适配器的代码片段。 1、解释执行切换到编译执行的例程 调用SharedRuntime::gen_i2c_adapter()函数生成解释执行切换到编译执行的例程,如下: 注意生成的汇编代码会以函数传入的实参的不同而不同,例如传入的实参是2时的汇编如下: 0x00007fffe110a 阅读全文

posted @ 2022-02-16 08:49 鸠摩(马智) 阅读(246) 评论(0) 推荐(1) 编辑

2022年2月11日

第62篇-解释器与编译器适配(一)

摘要: 对栈上替换的nmethod而言,执行栈上替换就相当于安装,因为栈上替换的nmethod都是方法内部的调用,所以实现相对简单点。对非栈上替换的nmethod而言,其安装稍微复杂点,需要考虑从Java代码和本地代码中调用nmethod安装完成的方法的情形,HotSpot VM的实现是通过一个在字节码解释 阅读全文

posted @ 2022-02-11 08:38 鸠摩(马智) 阅读(348) 评论(0) 推荐(2) 编辑

2022年2月10日

第61篇-安装与卸载编译方法和OSR

摘要: 如果方法或OSR完成编译后,还需要安装到对应的位置才能执行。 可以看一下Compilation::compile_method()函数,最重要的实现代码如下: // compile method int frame_size = compile_java_method(); // ... if (I 阅读全文

posted @ 2022-02-10 09:01 鸠摩(马智) 阅读(120) 评论(0) 推荐(0) 编辑

2022年1月23日

第60篇-获取编译任务

摘要: 在前面介绍过OSR或方法编译,如果已经决定要编译,都会调用SimpleThresholdPolicy::compile()函数进行编译。调用的相关函数如下: 1、提交编译任务 在SimpleThresholdPolicy::compile()函数中会调用SimpleThresholdPolicy:: 阅读全文

posted @ 2022-01-23 10:46 鸠摩(马智) 阅读(195) 评论(0) 推荐(0) 编辑

2022年1月22日

第59篇-编译策略

摘要: 在执行OSR或方法编译时,调用AdvancedThresholdPolicy::common()函数决定编译策略,这样才能在SimpleThresholdPolicy::submit_compile()函数提交编译任务。common()函数的实现如下: CompLevel AdvancedThres 阅读全文

posted @ 2022-01-22 08:22 鸠摩(马智) 阅读(165) 评论(0) 推荐(0) 编辑

2022年1月21日

第58篇-触发编译

摘要: 在之前介绍方法调用计数和回边计数时介绍过,当计数值超过阈值时会调用InterpreterRuntime::frequency_counter_overflow()函数对方法或块进行编译。此函数会进一步调用到CompilationPolicy::event()函数,在此函数中会根据当前的编译模式选择合 阅读全文

posted @ 2022-01-21 06:29 鸠摩(马智) 阅读(129) 评论(0) 推荐(0) 编辑

2022年1月20日

第57篇-profile实例

摘要: 之前已经介绍过回边计数和ProfileData与Layout,下面举个具体的例子看下MethodData是怎么利用ProfileData等记录详细的运行时信息的。实例如下: package com.test; import java.util.LinkedList; public class Com 阅读全文

posted @ 2022-01-20 08:07 鸠摩(马智) 阅读(178) 评论(0) 推荐(0) 编辑

2022年1月19日

第56篇-ProfileData与DataLayout

摘要: 某些指令需要创建某些实例,如下: 指令 对应的DataLayout._struct._tag值 _checkcast、_instanceof、_aastore receiver_type_data_tag bit_data_tag _invokespecial、_invokestatic call_ 阅读全文

posted @ 2022-01-19 08:43 鸠摩(马智) 阅读(138) 评论(0) 推荐(0) 编辑

2022年1月17日

第55篇-回边计数

摘要: 在前面介绍控制转移指令时只简单介绍了相关字节码解释执行的主要逻辑,没有介绍过统计相关的逻辑。对于控制转移指令来说,通常会调用TemplateTable::branch(bool is_jsr, bool is_wide)函数生成相关的汇编代码,这些汇编代码会含有统计的逻辑,这一篇将详细介绍。 控制转 阅读全文

posted @ 2022-01-17 08:46 鸠摩(马智) 阅读(242) 评论(0) 推荐(1) 编辑

2022年1月14日

第54篇-方法调用计数

摘要: 前一篇介绍了编译策略,编译策略依赖于性能计数,所以HotSpot VM中有许多性能统计相关的代码,如统计方法调用次数的代码,统计回边的次数,这就是方法调用计数器(Invocation Counter )和回边计数器(Back Edge Counter )。有了这些统计信息,HotSpot VM就会判 阅读全文

posted @ 2022-01-14 08:56 鸠摩(马智) 阅读(293) 评论(0) 推荐(0) 编辑

2022年1月13日

第53篇-编译线程的初始化

摘要: 即时编译(Just In Time,JIT)的运行模式有两种:client模式(C1编译器)和server模式(C2编译器)。这两种模式采用的编译器是不一样的,client模式采用的是代号为C1的轻量级编译器,特点是启动快,但是编译不够彻底;而server模式采用的是代号为C2的编译器,特点是启动比 阅读全文

posted @ 2022-01-13 09:21 鸠摩(马智) 阅读(361) 评论(1) 推荐(0) 编辑

2022年1月12日

第52篇-即时编译器

摘要: 一般来说,Java代码会先被HotSpot VM解释执行,之后将统计出的热点代码通过即时编译器C1、C2或Graal编译成机器码,直接运行在底层硬件之上。解释器在之前的文章中已经介绍了不少,但是编译器还没有介绍,关于Java涉及到的编译器如下图所示。 前端编译器就是将遵循Java语言规范的Java源 阅读全文

posted @ 2022-01-12 08:23 鸠摩(马智) 阅读(433) 评论(0) 推荐(1) 编辑

2022年1月11日

第51篇-SharedRuntime::generate_native_wrapper()生成编译入口

摘要: 当某个native方法被调用时,一开始它会从解释入口进入,也就是我之前介绍的、由InterpreterGenerator::generate_native_entry()函数生成的入口例程。在这个例程中,其实还有一些统计的相关代码,但是当时为了专注研究解释执行的主要流程,为虚拟机增加了-XX:-Pr 阅读全文

posted @ 2022-01-11 08:54 鸠摩(马智) 阅读(193) 评论(0) 推荐(0) 编辑

2022年1月7日

第50篇-调用约定(2)

摘要: 前面已经介绍了解释执行的Java方法、编译执行的Java方法和native方法的调用约定。这一篇我们看一下HotSpot VM中辅助实现调用约定的相关函数。 1、SharedRuntime::java_calling_convention()函数 当需要编译执行Java方法时,会调用SharedRu 阅读全文

posted @ 2022-01-07 09:43 鸠摩(马智) 阅读(190) 评论(0) 推荐(0) 编辑

2021年12月31日

第49篇-调用约定(1)

摘要: JVM字节码使用了一些专业术语,当谈到调用点时,它指的是某个方法(调用者)内的一个位置,在那里另外一个方法(被调用者)被调用了,不仅如此,在非静态方法调用的情况下,我们总是将方法解析到某个对象上。这个对象就是所谓的接收者对象(receiver object),其运行时类型被称为接收者类型(recei 阅读全文

posted @ 2021-12-31 09:46 鸠摩(马智) 阅读(265) 评论(0) 推荐(0) 编辑

2021年12月30日

第48篇-native方法调用解释执行的Java方法

摘要: 举一个native方法调用解释执行的Java方法的实例,如下: public class TestJNI { static { System.load("/media/mazhi/sourcecode/workspace/projectjava/projectjava01/src/main/java 阅读全文

posted @ 2021-12-30 09:09 鸠摩(马智) 阅读(296) 评论(0) 推荐(0) 编辑

2021年12月29日

第47篇-解释执行的Java方法调用native方法小实例

摘要: 举个小实例,如下: public class TestJNI { static { // 程序在加载时,自动加载libdiaoyong.so库 System.loadLibrary("diaoyong"); } public static native int get(); public stati 阅读全文

posted @ 2021-12-29 14:37 鸠摩(马智) 阅读(379) 评论(0) 推荐(0) 编辑

2021年12月17日

第46篇-signature_handler与result_handler

摘要: 在之前介绍为native方法设置解释执行的入口时介绍过,当Method::native_function为空时会调用InterpreterRuntime::prepare_native_call()函数,这个函数不但会查找本地函数,而且还会确保Method::signature_handler也完成 阅读全文

posted @ 2021-12-17 09:19 鸠摩(马智) 阅读(168) 评论(0) 推荐(2) 编辑

2021年12月16日

第45篇-查找native方法的本地实现函数native_function

摘要: 在之前介绍为native方法设置解释执行的入口时讲到过Method实例的内存布局,如下: 对于第1个slot来说,如果是native方法,其对应的本地函数的实现会放到Method实例的native_function这个slot中,将本地函数放到这个slot就是registerNative()函数要完 阅读全文

posted @ 2021-12-16 09:10 鸠摩(马智) 阅读(311) 评论(0) 推荐(0) 编辑

2021年12月15日

第44篇-为native方法设置解释执行入口

摘要: 对于Java中的native方法来说,实际上调用的是C/C++实现的本地函数,由于可能会在Java解释执行过程中调用native方法,或在本地函数的实现过程中调用Java方法,所以当两者相互调用时,必须要遵守调用约定,同时要保证在被调用方法执行完成后,调用者的方法能继续向下执行。 在HotSpot 阅读全文

posted @ 2021-12-15 09:51 鸠摩(马智) 阅读(313) 评论(0) 推荐(0) 编辑

2021年12月14日

第43篇-JNI引用的管理(2)

摘要: 之前我们已经介绍了JNIHandleBlock,但是没有具体介绍JNIHandleBlock中存储的句柄,这一篇我们将详细介绍对这些句柄的操作。 JNI句柄分为两种,全局和局部对象引用: (1)大部分对象的引用属于局部对象引用,最终还是调用了JNIHandleBlock来管理,因为JNIHandle 阅读全文

posted @ 2021-12-14 09:09 鸠摩(马智) 阅读(257) 评论(0) 推荐(0) 编辑

2021年12月3日

第42篇-JNI引用的管理(1)

摘要: 在本地函数中会使用Java服务,这些服务都可以通过调用JNIEnv中封装的函数获取。我们在本地函数中可以访问所传入的引用类型参数,也可以通过JNI函数创建新的 Java 对象。这些 Java 对象显然也会受到GC的影响。所以我们需要通过JNI 的局部引用(Local Reference)和全局引用( 阅读全文

posted @ 2021-12-03 09:55 鸠摩(马智) 阅读(301) 评论(0) 推荐(0) 编辑

2021年12月2日

第41篇-JNIEnv与JavaVM的初始化

摘要: JavaVM和JNIEnv的初始化和JVM各模块的初始化都是在JNI_CreateJavaVM()函数中完成。这一篇将详细介绍JavaVM和JNIEnv的初始化过程。 1、初始化JavaVM JavaVM的初始化都是在JNI_CreateJavaVM()函数中完成,调用链如下: JavaMain() 阅读全文

posted @ 2021-12-02 09:07 鸠摩(马智) 阅读(428) 评论(0) 推荐(0) 编辑

2021年11月10日

第40篇-JNIEnv和JavaVM

摘要: 下面介绍2个与JNI机制相关的类型JNIEnv和JavaVM。 1、JNIEnv JNIEnv一般是是由虚拟机传入,而且与线程相关的变量,也就说线程A不能使用线程B的JNIEnv。而作为一个结构体,它里面定义了JNI系统操作函数。在之前介绍的实例中,可以看到C的Java_TestJNI_set()或 阅读全文

posted @ 2021-11-10 09:48 鸠摩(马智) 阅读(408) 评论(0) 推荐(1) 编辑

2021年11月9日

第39篇-Java通过JNI调用C/C++函数

摘要: 在某些情况下,Java语言需要通过调用C/C++函数来实现某些功能,因为Java有时候对这些功能显的无能为力,如想使用X86_64 的 SIMD 指令提升一下业务方法中关键代码的性能,又或者想要获取某个体系架构或者操作系统特有功能的支持。为了能在Java 代码中调用 C/C++函数,JVM提供了Ja 阅读全文

posted @ 2021-11-09 13:55 鸠摩(马智) 阅读(854) 评论(0) 推荐(0) 编辑

2021年11月8日

第38篇-解释方法之间的调用小实例

摘要: 这一篇我们介绍一下解释执行的main()方法调用解析执行的add()方法的小实例,这个例子如下: package com.classloading; public class TestInvokeMethod { public int add(int a, int b) { return a + b 阅读全文

posted @ 2021-11-08 14:00 鸠摩(马智) 阅读(267) 评论(0) 推荐(0) 编辑

2021年11月4日

第37篇-Interpreter::_invoke_return_entry等例程

摘要: 我们在之前介绍过return字节码指令的执行逻辑,这个字节码指令只会执行释放锁和退出当前栈帧的操作,但是当控制权转移给调用者时,还需要恢复调用者的栈帧状态,如让%r13指向bcp、%r14指向局部变量表等,另外还需要弹出压入的实参、跳转到调用者的下一个字节码指令继续执行,而这一切操作都是由Inter 阅读全文

posted @ 2021-11-04 10:10 鸠摩(马智) 阅读(129) 评论(0) 推荐(0) 编辑

2021年11月3日

第36篇-return字节码指令

摘要: 方法返回的字节码相关指令如下表所示。 0xac ireturn 从当前方法返回int 0xad lreturn 从当前方法返回long 0xae freturn 从当前方法返回float 0xaf dreturn 从当前方法返回double 0xb0 areturn 从当前方法返回对象引用 0xb1 阅读全文

posted @ 2021-11-03 10:58 鸠摩(马智) 阅读(337) 评论(0) 推荐(1) 编辑

2021年11月2日

第35篇-方法调用指令之invokespecial与invokestatic

摘要: 这一篇将详细介绍invokespecial和invokestatic字节码指令的汇编实现逻辑 1、invokespecial指令 invokespecial指令的模板定义如下: def(Bytecodes::_invokespecial , ubcp|disp|clvm|____, vtos, vt 阅读全文

posted @ 2021-11-02 09:47 鸠摩(马智) 阅读(335) 评论(0) 推荐(0) 编辑

2021年11月1日

第34篇-解析invokeinterface字节码指令

摘要: 与invokevirtual指令类似,当没有对目标方法进行解析时,需要调用LinkResolver::resolve_invoke()函数进行解析,这个函数会调用其它一些函数完成方法的解析,如下图所示。 上图中粉色的部分与解析invokevirtual字节码指令有所区别,resolve_pool() 阅读全文

posted @ 2021-11-01 09:36 鸠摩(马智) 阅读(342) 评论(0) 推荐(0) 编辑

2021年10月29日

第33篇-方法调用指令之invokeinterface

摘要: invokevirtual字节码指令的模板定义如下: def(Bytecodes::_invokeinterface , ubcp|disp|clvm|____, vtos, vtos, invokeinterface , f1_byte ); 可以看到指令的生成函数为TemplateTable:: 阅读全文

posted @ 2021-10-29 11:02 鸠摩(马智) 阅读(529) 评论(0) 推荐(0) 编辑

2021年10月28日

第32篇-解析interfacevirtual字节码指令

摘要: 在前面介绍invokevirtual指令时,如果判断出ConstantPoolCacheEntry中的_indices字段的_f2属性的值为空,则认为调用的目标方法没有连接,也就是没有向ConstantPoolCacheEntry中保存调用方法的相关信息,需要调用InterpreterRuntime 阅读全文

posted @ 2021-10-28 10:22 鸠摩(马智) 阅读(243) 评论(0) 推荐(1) 编辑

2021年10月27日

第31篇-方法调用指令之invokevirtual

摘要: invokevirtual字节码指令的模板定义如下: def(Bytecodes::_invokevirtual , ubcp|disp|clvm|____, vtos, vtos, invokevirtual , f2_byte ); 生成函数为invokevirtual,传递的参数为f2_byt 阅读全文

posted @ 2021-10-27 10:33 鸠摩(马智) 阅读(688) 评论(0) 推荐(0) 编辑

2021年10月14日

第30篇-main()方法的执行

摘要: 在第7篇详细介绍过为Java方法创建的栈帧,如下图所示。 调用完generate_fixed_frame()函数后一些寄存器中保存的值如下: rbx:Method* ecx:invocation counter r13:bcp(byte code pointer) rdx:ConstantPool* 阅读全文

posted @ 2021-10-14 10:30 鸠摩(马智) 阅读(646) 评论(0) 推荐(0) 编辑

2021年9月29日

第29篇-调用Java主类的main()方法

摘要: 在第1篇中大概介绍过Java中主类方法main()的调用过程,这一篇介绍的详细一点,大概的调用过程如下图所示。 其中浅红色的函数由主线程执行,而另外的浅绿色部分由另外一个线程执行,这个线程最终也会负责执行Java主类中的main()方法。在JavaMain()函数中调用LoadMainClass() 阅读全文

posted @ 2021-09-29 15:03 鸠摩(马智) 阅读(750) 评论(0) 推荐(0) 编辑

第21篇-加载与存储指令之iload、_fast_iload等(3)

摘要: iload会将int类型的本地变量推送至栈顶。模板定义如下: def(Bytecodes::_iload , ubcp|____|clvm|____, vtos, itos, iload , _ ); iload指令的格式如下: iload index index是一个无符号byte类型整数,指向局 阅读全文

posted @ 2021-09-29 14:59 鸠摩(马智) 阅读(203) 评论(0) 推荐(0) 编辑

2021年9月27日

第28篇-虚拟机字节码指令之控制转移指令

摘要: 控制转移相关的字节码指令如下表所示。 0x99 ifeq 当栈顶int型数值等于0时跳转 0x9a ifne 当栈顶int型数值不等于0时跳转 0x9b iflt 当栈顶int型数值小于0时跳转 0x9c ifge 当栈顶int型数值大于等于0时跳转 0x9d ifgt 当栈顶int型数值大于0时跳 阅读全文

posted @ 2021-09-27 10:40 鸠摩(马智) 阅读(284) 评论(0) 推荐(0) 编辑

2021年9月22日

第27篇-虚拟机字节码指令之操作数栈管理指令

摘要: 操作数栈管理相关的字节码指令如下表所示。 0x57 pop 将栈顶数值弹出 (数值不能是long或double类型的) 0x58 pop2 将栈顶的一个(long或double类型的)或两个数值弹出(其它) 0x59 dup 复制栈顶数值并将复制值压入栈顶 0x5a dup_x1 复制栈顶数值并将两 阅读全文

posted @ 2021-09-22 08:53 鸠摩(马智) 阅读(237) 评论(0) 推荐(0) 编辑

2021年9月17日

第26篇-虚拟机对象操作指令之putstatic

摘要: 之前已经介绍了getstatic与getfield指令的汇编代码执行逻辑,这一篇介绍putstatic指令的执行逻辑,putfield将不再介绍,大家可以自己去研究,相信大家有这个实力。 putstatic指令为指定类的静态域赋值。字节码指令的格式如下: putstatic indexbyte1 i 阅读全文

posted @ 2021-09-17 09:23 鸠摩(马智) 阅读(702) 评论(0) 推荐(0) 编辑

2021年9月16日

第25篇-虚拟机对象操作指令之getfield

摘要: getfield指令表示获取指定类的实例域,并将其值压入栈顶。其格式如下: getstatic indexbyte1 indexbyte2 无符号数indexbyte1和indexbyte2构建为(indexbyte1<<8)|indexbyte2,这个值指明了一个当前类的运行时常量池索引值,指向的 阅读全文

posted @ 2021-09-16 16:55 鸠摩(马智) 阅读(450) 评论(0) 推荐(1) 编辑

导航