专注虚拟机与编译器研究

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 鸠摩(马智) 阅读(801) 评论(0) 推荐(0) 编辑

2021年11月1日

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

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

posted @ 2021-11-01 09:36 鸠摩(马智) 阅读(584) 评论(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 鸠摩(马智) 阅读(1014) 评论(0) 推荐(0) 编辑

2021年10月28日

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

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

posted @ 2021-10-28 10:22 鸠摩(马智) 阅读(495) 评论(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 鸠摩(马智) 阅读(1415) 评论(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 鸠摩(马智) 阅读(1016) 评论(0) 推荐(0) 编辑

2021年9月29日

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

摘要: 在第1篇中大概介绍过Java中主类方法main()的调用过程,这一篇介绍的详细一点,大概的调用过程如下图所示。 图片错误修正(如上为java或javaw,并不是java.exe和javaw.exe) 其中浅红色的函数由主线程执行,而另外的浅绿色部分由另外一个线程执行,这个线程最终也会负责执行Java 阅读全文

posted @ 2021-09-29 15:03 鸠摩(马智) 阅读(1603) 评论(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 鸠摩(马智) 阅读(542) 评论(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 鸠摩(马智) 阅读(640) 评论(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 鸠摩(马智) 阅读(425) 评论(0) 推荐(0) 编辑

2021年9月17日

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

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

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

2021年9月16日

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

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

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

2021年9月15日

第24篇-虚拟机对象操作指令之getstatic

摘要: Java虚拟机规范中定义的对象操作相关的字节码指令如下表所示。 0xb2 getstatic 获取指定类的静态域,并将其值压入栈顶 0xb3 putstatic 为指定的类的静态域赋值 0xb4 getfield 获取指定类的实例域,并将其值压入栈顶 0xb5 putfield 为指定的类的实例域赋 阅读全文

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

2021年9月14日

第23篇-虚拟机字节码指令之类型转换

摘要: Java虚拟机规范中定义的类型转换相关的字节码指令如下表所示。 0x85 i2l 将栈顶int型数值强制转换成long型数值并将结果压入栈顶 0x86 i2f 将栈顶int型数值强制转换成float型数值并将结果压入栈顶 0x87 i2d 将栈顶int型数值强制转换成double型数值并将结果压入栈 阅读全文

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

2021年9月13日

第22篇-虚拟机字节码之运算指令

摘要: 虚拟机规范中与运算相关的字节码指令如下表所示。 0x60 iadd 将栈顶两int型数值相加并将结果压入栈顶 0x61 ladd 将栈顶两long型数值相加并将结果压入栈顶 0x62 fadd 将栈顶两float型数值相加并将结果压入栈顶 0x63 dadd 将栈顶两double型数值相加并将结果压 阅读全文

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

2021年9月10日

第20篇-加载与存储指令之ldc与_fast_aldc指令(2)

摘要: ldc指令将int、float、或者一个类、方法类型或方法句柄的符号引用、还可能是String型常量值从常量池中推送至栈顶。 这一篇介绍一个虚拟机规范中定义的一个字节码指令ldc,另外还有一个虚拟机内部使用的字节码指令_fast_aldc。ldc指令可以加载String、方法类型或方法句柄的符号引用 阅读全文

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

2021年9月9日

第19篇-加载与存储指令(1)

摘要: TemplateInterpreterGenerator::generate_all()函数会生成许多例程(也就是机器指令片段,英文叫Stub),包括调用set_entry_points_for_all_bytes()函数生成各个字节码对应的例程。 最终会调用到TemplateInterpreter 阅读全文

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

2021年9月8日

第18章-x86指令集之常用指令

摘要: x86的指令集可分为以下4种: 通用指令 x87 FPU指令,浮点数运算的指令 SIMD指令,就是SSE指令 系统指令,写OS内核时使用的特殊指令 下面介绍一些通用的指令。指令由标识命令种类的助记符(mnemonic)和作为参数的操作数(operand)组成。例如move指令: 指令 操作数 描述 阅读全文

posted @ 2021-09-08 10:05 鸠摩(马智) 阅读(6756) 评论(0) 推荐(0) 编辑

2021年9月7日

第17章-x86-64寄存器

摘要: 不同的CPU都能够解释的机器语言的体系称为指令集架构(ISA,Instruction Set Architecture),也可以称为指令集(instruction set)。Intel将x86系列CPU之中的32位CPU指令集架构称为IA-32,IA是“Intel Architecture”的简称, 阅读全文

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

2021年9月6日

第16章-虚拟机中的汇编器

摘要: 汇编器的继承体系如下: 为解析器提供的相关汇编接口,所以每个字节码指令都会关联一个生成器函数,而生成器函数会调用汇编器生成机器指令片段,例如为iload字节码指令生成例程时,调用的生成函数为TemplateTable::iload(int n),此函数的实现如下: 源代码位置:hotspot/src 阅读全文

posted @ 2021-09-06 10:35 鸠摩(马智) 阅读(1147) 评论(0) 推荐(0) 编辑

2021年9月3日

第15章-解释器及解释器生成器

摘要: 方法解释执行时需要解释器与解释器生成器的支持。解释器与解释器生成器的继承体系如下: 下面详细介绍解释器与解释器生成器。 1、解释器 解释器是一堆本地代码例程构造的,这些例程会在虚拟机启动的时候写入到StubQueue中,以后解释执行时就只需要进入指定例程即可。 解释器的继承体系如下: Abstrac 阅读全文

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

2021年8月31日

第14篇-生成重要的例程

摘要: 之前介绍过TemplateInterpreter::initialize()函数,在这个函数中初始化了模板表和StubQueue实例,通过如下方式创建InterpreterGenerator实例: InterpreterGenerator g(_code); 在创建InterpreterGenera 阅读全文

posted @ 2021-08-31 10:19 鸠摩(马智) 阅读(799) 评论(0) 推荐(0) 编辑

2021年8月30日

第13篇-通过InterpreterCodelet存储机器指令片段

摘要: 在TemplateInterpreterGenerator::generate_all()函数中生成了许多字节码指令以及一些虚拟机辅助执行的机器指令片段,例如生成空指针异常抛出入口的实现如下: { CodeletMark cm(_masm, "throw exception entrypoints" 阅读全文

posted @ 2021-08-30 15:26 鸠摩(马智) 阅读(710) 评论(0) 推荐(1) 编辑

2021年8月27日

第12篇-认识CodeletMark

摘要: InterpreterCodelet依赖CodeletMark完成自动创建和初始化。CodeletMark继承自ResourceMark,允许自动析构,执行的主要操作就是,会按照InterpreterCodelet中存储的实际机器指令片段分配内存并提交。这个类的定义如下: class Codelet 阅读全文

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

2021年8月26日

第11篇-认识Stub与StubQueue

摘要: 在 第10篇-初始化模板表 我们介绍过TemplateInterpreterinitialize()函数,在这个函数中会调用TemplateTableinitialize()函数初始化模板表,随后会使用new关键字初始化定义在AbstractInterpreter类中的_code静态属性,如下: s 阅读全文

posted @ 2021-08-26 11:15 鸠摩(马智) 阅读(849) 评论(0) 推荐(1) 编辑

2021年8月25日

第10篇-初始化模板表

摘要: 在 第9篇-字节码指令的定义 我们介绍了字节码指令并且将字节码指令相关的信息都存储到了相关数组中,只需要通过Opcode就可从相关数组中获取对应的信息。 在init_globals()函数中调用bytecodes_init()函数初始化好字节码指令后会调用interpreter_init()函数初始 阅读全文

posted @ 2021-08-25 09:15 鸠摩(马智) 阅读(845) 评论(0) 推荐(0) 编辑

2021年8月24日

第9篇-字节码指令的定义

摘要: 之前的文章介绍了解释执行下的Java栈帧创建以及字节码分派逻辑,但是始终没有讲到虚拟机到底是怎么执行Java方法中的字节码的,在介绍字节码的执行之前,需要先知道字节码指令的定义。在Bytecodes::initialize()函数中会定义字节码指令的一些属性。这个函数的调用链如下: init_glo 阅读全文

posted @ 2021-08-24 10:13 鸠摩(马智) 阅读(1059) 评论(0) 推荐(0) 编辑

2021年8月23日

Java虚拟机漫漫学习路,我终于悟了

摘要: 毕业8年,前5年的职业规划是做计算广告,后来感觉计算广告这一行更注重的是业务而非技术,而自己的性格更适合做技术,所以毅然决然的辞职, 全职1年半时间写了2本关于Java前端编译器和Java虚拟机HotSpot的书,今年年初来到杭州做Java虚拟机开发相关的工作,也算是顺利切入Java虚拟机这一行了。 阅读全文

posted @ 2021-08-23 10:40 鸠摩(马智) 阅读(1377) 评论(2) 推荐(3) 编辑

2021年8月20日

第8篇-dispatch_next()函数分派字节码

摘要: 在generate_normal_entry()函数中会调用generate_fixed_frame()函数为Java方法的执行生成对应的栈帧,接下来还会调用dispatch_next()函数执行Java方法的字节码。generate_normal_entry()函数调用的dispatch_next 阅读全文

posted @ 2021-08-20 09:00 鸠摩(马智) 阅读(1077) 评论(0) 推荐(0) 编辑

2021年8月17日

第7篇-为Java方法创建栈帧

摘要: 在 第6篇-Java方法新栈帧的创建 介绍过局部变量表的创建,创建完成后的栈帧状态如下图所示。 各个寄存器的状态如下所示。 // %rax寄存器中存储的是返回地址 rax: return address // 要执行的Java方法的指针 rbx: Method* // 本地变量表指针 r14: po 阅读全文

posted @ 2021-08-17 11:07 鸠摩(马智) 阅读(1207) 评论(1) 推荐(0) 编辑

2021年8月16日

第6篇-Java方法新栈帧的创建

摘要: 在 第2篇-JVM虚拟机这样来调用Java主类的main()方法 介绍JavaCalls::call_helper()函数的实现时提到过如下一句代码: address entry_point = method->from_interpreted_entry(); 这个参数会做为实参传递给StubRo 阅读全文

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

2021年8月14日

第5篇-调用Java方法后弹出栈帧及处理返回结果

摘要: 在前一篇 第4篇-JVM终于开始调用Java主类的main()方法啦 介绍了通过callq调用entry point,不过我们并没有看完generate_call_stub()函数的实现。接下来在generate_call_stub()函数中会处理调用Java方法后的返回值,同时还需要执行退栈操作, 阅读全文

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

2021年8月13日

第4篇-JVM终于开始调用Java主类的main()方法啦

摘要: 在前一篇 第3篇-CallStub新栈帧的创建 中我们介绍了generate_call_stub()函数的部分实现,完成了向CallStub栈帧中压入参数的操作,此时的状态如下图所示。 ![](https://img2020.cnblogs.com/blog/1236123/202111/12361 阅读全文

posted @ 2021-08-13 15:31 鸠摩(马智) 阅读(1331) 评论(0) 推荐(0) 编辑

第3篇-CallStub新栈帧的创建

摘要: 在前一篇文章 第2篇-JVM虚拟机这样来调用Java主类的main()方法 中我们介绍了在call_helper()函数中通过函数指针的方式调用了一个函数,如下: StubRoutines::call_stub()( (address)&link, result_val_address, resul 阅读全文

posted @ 2021-08-13 09:07 鸠摩(马智) 阅读(1351) 评论(0) 推荐(0) 编辑

2021年8月12日

第2篇-Java虚拟机这样来调用Java主类的main()方法

摘要: 在前一篇 第1篇-关于Java虚拟机HotSpot,开篇说的简单些 中介绍了call_static()、call_virtual()等函数的作用,这些函数会调用JavaCalls::call()函数。我们看Java类中main()方法的调用,调用栈如下: ``` clone() at clone.S 阅读全文

posted @ 2021-08-12 16:50 鸠摩(马智) 阅读(1608) 评论(0) 推荐(1) 编辑

第1篇-关于Java虚拟机HotSpot,开篇说的简单点

摘要: 开讲Java运行时,这一篇讲一些简单的内容。我们写的主类中的main()方法是如何被Java虚拟机调用到的?在Java类中的一些方法会被由C/C++编写的HotSpot虚拟机的C/C++函数调用,不过由于Java方法与C/C++函数的调用约定不同,所以并不能直接调用,需要JavaCalls::cal 阅读全文

posted @ 2021-08-12 10:17 鸠摩(马智) 阅读(1961) 评论(0) 推荐(3) 编辑

2021年2月5日

深入剖析Java虚拟机目录(卷1-基础篇)

摘要: 阅读全文

posted @ 2021-02-05 20:29 鸠摩(马智) 阅读(609) 评论(5) 推荐(0) 编辑

2020年11月23日

第2.4篇-HotSpot VM类模型之ArrayKlass

摘要: 上一篇分析了 HotSpot类模型之InstanceKlass ,这次主要分析表示java数组类型的C++类。 1、ArrayKlass类 ArrayKlass继承自Klass,是所有数组类的抽象基类,类及重要属性的定义如下: 源代码位置:openjdk/hotspot/src/share/vm/o 阅读全文

posted @ 2020-11-23 07:44 鸠摩(马智) 阅读(705) 评论(0) 推荐(0) 编辑

2020年11月21日

第2.3篇-HotSpot VM类模型之InstanceKlass

摘要: 上一篇 HotSpot源码分析之类模型 介绍了类模型的基础类Klass的重要属性及方法,这一篇介绍一下InstanceKlass及InstanceKlass的子类。 1、InstanceKlass类 每个InstanceKlass实例表示一个具体的Java类型(这里的Java类型不包括Java数组类 阅读全文

posted @ 2020-11-21 09:46 鸠摩(马智) 阅读(3255) 评论(0) 推荐(2) 编辑

2020年11月20日

第2.2篇-HotSpot VM源码分析之类模型

摘要: HotSpot VM采用了OOP-Klass模型描述Java的类和对象。Klass模型采用Klass类及相关子类的对象来描述具体的Java类。一般HotSpot VM 在加载Java的Class 文件时,会在方法区创建Klass实例,这个实例用来保存Java类的元数据,包括常量池、字段、方法等。 K 阅读全文

posted @ 2020-11-20 06:44 鸠摩(马智) 阅读(2020) 评论(2) 推荐(1) 编辑

导航