这一篇将详细介绍invokespecial和invokestatic字节码指令的汇编实现逻辑

1、invokespecial指令

invokespecial指令的模板定义如下:

def(Bytecodes::_invokespecial       , ubcp|disp|clvm|____, vtos, vtos, invokespecial       , f1_byte      );

生成函数为invokespecial(),生成的汇编代码如下:

0x00007fffe1022250: mov    %r13,-0x38(%rbp)
0x00007fffe1022254: movzwl 0x1(%r13),%edx
0x00007fffe1022259: mov -0x28(%rbp),%rcx
0x00007fffe102225d: shl $0x2,%edx
0x00007fffe1022260: mov 0x10(%rcx,%rdx,8),%ebx
// 获取ConstantPoolCacheEntry中indices[b2,b1,constant pool index]中的b1
0x00007fffe1022264: shr $0x10,%ebx
0x00007fffe1022267: and $0xff,%ebx
// 检查invokespecial=183的bytecode是否已经连接,如果已经连接就进行跳转
0x00007fffe102226d: cmp $0xb7,%ebx
0x00007fffe1022273: je 0x00007fffe1022312 // ... 省略调用InterpreterRuntime::resolve_invoke()函数
// 对invokespecial=183的bytecode进行连接,
// 因为字节码指令还没有连接 // 将invokespecial x中的x加载到%edx中
0x00007fffe1022306: movzwl 0x1(%r13),%edx
// 将ConstantPoolCache的首地址存储到%rcx中
0x00007fffe102230b: mov -0x28(%rbp),%rcx
// %edx中存储的是ConstantPoolCacheEntry项的索引,转换为字偏移
0x00007fffe102230f: shl $0x2,%edx // 获取ConstantPoolCache::_f1属性的值
0x00007fffe1022312: mov 0x18(%rcx,%rdx,8),%rbx
// 获取ConstantPoolCache::_flags属性的值
0x00007fffe1022317: mov 0x28(%rcx,%rdx,8),%edx // 将flags移动到ecx中
0x00007fffe102231b: mov %edx,%ecx
// 从flags中取出参数大小
0x00007fffe102231d: and $0xff,%ecx
// 获取到recv,%rcx中保存的是参数大小,最终计算为 %rsp+%rcx*8-0x8,
// flags中的参数大小可能对实例方法来说,已经包括了recv的大小
// 如调用实例方法的第一个参数是this(recv)
0x00007fffe1022323: mov -0x8(%rsp,%rcx,8),%rcx
// 从flags中获取return type,也就是从_flags的高4位保存的TosState
0x00007fffe1022328: shr $0x1c,%edx
// 将TemplateInterpreter::invoke_return_entry地址存储到%r10
0x00007fffe102232b: movabs $0x7ffff73b6380,%r10
// 找到对应return type的invoke_return_entry的地址
0x00007fffe1022335: mov (%r10,%rdx,8),%rdx
// 通过invokespecial指令调用函数后的返回地址
0x00007fffe1022339: push %rdx // 空值检查
0x00007fffe102233a: cmp (%rcx),%rax // ... // 设置调用者栈顶
0x00007fffe102235c: lea 0x8(%rsp),%r13
// 向栈中last_sp的位置保存调用者栈顶
0x00007fffe1022361: mov %r13,-0x10(%rbp) // 跳转到Method::_from_interpretered_entry入口去执行
0x00007fffe1022365: jmpq *0x58(%rbx)  

invokespecial指令在调用private和构造方法时,不需要动态分发。在这个字节码指令解析完成后,ConstantPoolCacheEntry中的_f1指向目标方法的Method实例,_f2没有使用,所以如上汇编的逻辑非常简单,这里不再过多介绍。

2、invokestatic指令

invokestatic指令的模板定义如下:

def(Bytecodes::_invokestatic        , ubcp|disp|clvm|____, vtos, vtos, invokestatic        , f1_byte);

生成函数为invokestatic(),生成的汇编代码如下:

0x00007fffe101c030: mov    %r13,-0x38(%rbp)
0x00007fffe101c034: movzwl 0x1(%r13),%edx
0x00007fffe101c039: mov -0x28(%rbp),%rcx
0x00007fffe101c03d: shl $0x2,%edx
0x00007fffe101c040: mov 0x10(%rcx,%rdx,8),%ebx
0x00007fffe101c044: shr $0x10,%ebx
0x00007fffe101c047: and $0xff,%ebx
0x00007fffe101c04d: cmp $0xb8,%ebx
// 检查invokestatic=184的bytecode是否已经连接,如果已经连接就进行跳转
0x00007fffe101c053: je 0x00007fffe101c0f2 // 调用InterpreterRuntime::resolve_invoke()函数对invokestatic=184的
// 的bytecode进行连接,因为字节码指令还没有连接
// ... 省略了解析invokestatic的汇编代码 // 将invokestatic x中的x加载到%edx中
0x00007fffe101c0e6: movzwl 0x1(%r13),%edx
// 将ConstantPoolCache的首地址存储到%rcx中
0x00007fffe101c0eb: mov -0x28(%rbp),%rcx
// %edx中存储的是ConstantPoolCacheEntry项的索引,转换为字偏移
0x00007fffe101c0ef: shl $0x2,%edx // 获取ConstantPoolCache::_f1属性的值
0x00007fffe101c0f2: mov 0x18(%rcx,%rdx,8),%rbx
// 获取ConstantPoolCache::_flags属性的值
0x00007fffe101c0f7: mov 0x28(%rcx,%rdx,8),%edx // 从flags中获取return type,也就是从_flags的高4位保存的TosState
0x00007fffe101c0fb: shr $0x1c,%edx
// 将TemplateInterpreter::invoke_return_entry地址存储到%r10
0x00007fffe101c0fe: movabs $0x7ffff73b5d00,%r10
// 找到对应return type的invoke_return_entry的地址
0x00007fffe101c108: mov (%r10,%rdx,8),%rdx
// 通过invokespecial指令调用函数后的返回地址
0x00007fffe101c10c: push %rdx // 设置调用者栈顶
0x00007fffe101c10d: lea 0x8(%rsp),%r13
// 向栈中last_sp的位置保存调用者栈顶
0x00007fffe101c112: mov %r13,-0x10(%rbp) // 跳转到Method::_from_interpretered_entry入口去执行
0x00007fffe101c116: jmpq *0x58(%rbx)  

invokespecial指令在调用静态方法时,不需要动态分发。在这个字节码指令解析完成后,ConstantPoolCacheEntry中的_f1指向目标方法的Method实例,_f2没有使用,所以如上汇编的逻辑非常简单,这里不再过多介绍。

关于invokestatic与invokespecial的解析过程这里就不再过多介绍了,有兴趣的可从LinkResolver::resolve_invoke()函数查看具体的解析过程。

推荐阅读:

第1篇-关于JVM运行时,开篇说的简单些

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

第3篇-CallStub新栈帧的创建

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

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

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

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

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

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

第10篇-初始化模板表

第11篇-认识Stub与StubQueue

第12篇-认识CodeletMark

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

第14篇-生成重要的例程

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

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

第17章-x86-64寄存器

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  

第35篇-方法调用指令之invokespecial与invokestatic的更多相关文章

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

    invokevirtual字节码指令的模板定义如下: def(Bytecodes::_invokeinterface , ubcp|disp|clvm|____, vtos, vtos, invoke ...

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

    invokevirtual字节码指令的模板定义如下: def(Bytecodes::_invokevirtual , ubcp|disp|clvm|____, vtos, vtos, invokevi ...

  3. JAVA方法调用中的解析与分派

    JAVA方法调用中的解析与分派 本文算是<深入理解JVM>的读书笔记,参考书中的相关代码示例,从字节码指令角度看看解析与分派的区别. 方法调用,其实就是要回答一个问题:JVM在执行一个方法 ...

  4. jvm 字节码执行 (一)方法调用

    “虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上,而虚拟机的执行引擎是 由自己实现的,因此可以自行制定指令集 ...

  5. JVM方法调用过程

    JVM方法调用过程 重载和重写 同一个类中,如果出现多个名称相同,并且参数类型相同的方法,将无法通过编译.因此,想要在同一个类中定义名字相同的方法,那么它们的参数类型必须不同.这种方法上的联系就是重载 ...

  6. 深入理解java虚拟机(十一) 方法调用-解析调用与分派调用

    方法调用过程是指确定被调用方法的版本(即调用哪一个方法),并不包括方法执行过程.我们知道,Class 文件的编译过程中并不包括传统编译中的连接步骤,一切方法调用在 Class 文件调用里面存储的都只是 ...

  7. 04 JVM是如何执行方法调用的(下)

    虚方法调用 Java 里所有非私有实例方法调用都会被编译成 invokevirtual 指令,而接口方法调用会被编译成 invokeinterface 指令.这两种指令,均属于 Java 虚拟机中的虚 ...

  8. JVM系列-方法调用的原理

    JVM系列-方法调用的原理 最近重新看了一些JVM方面的笔记和资料,收获颇丰,尤其解决了长久以来心中关于JVM方法管理的一些疑问.下面介绍一下JVM中有关方法调用的知识. 目的 方法调用,目的是选择方 ...

  9. 深入解析多态和方法调用在JVM中的实现

    深入解析多态和方法调用在JVM中的实现 1. 什么是多态 多态(polymorphism)是面向对象编程的三大特性之一,它建立在继承的基础之上.在<Java核心技术卷>中这样定义: 一个对 ...

随机推荐

  1. POJ1741——Tree(树的点分治)

    1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-11-17 1 ...

  2. mysql数据库备份参数

    我用来实现自动全备份的脚本(可以满足一般有前后版本兼容要求的导出导入操作,我的字符集是latin1): mysqldump.exe -umyusername -pmypass -h localhost ...

  3. 解决IE浏览器 点击子元素重复调用执行 mouseover 与mouseout兼容性问题

    将函数配对换为下面2个就可以解决兼容性问题. mouseenter() mouseleave(0

  4. seo执行步骤

    第一个金字塔策略这个很适用于大型网站,我想做过大型网站,特别是关键词比较多比较杂乱的站长来说,这个图太熟悉不过了,就算是没有见过,但实际操作中早就用到了这些手法.如果能把这个图领会透并实际应用,做一个 ...

  5. Kafka 3.0新特性

    1.概述 Kafka是一个分布表示实时数据流平台,可独立部署在单台服务器上,也可部署在多台服务器上构成集群.它提供了发布与订阅的功能,用户可以发送数据到Kafka集群中,也可以从Kafka集群中读取数 ...

  6. 如何理解 jmeter 的线程数与并发数之间的关系

    https://blog.csdn.net/weixin_39955351/article/details/110548162 多个线程组的并发是如何计算的?

  7. win10家庭版 不能远程登录 windows 10 mstsc不可用

    Windows10家庭版的用户,因为系统中没有组策略编辑器,需要修改注册表来实现. 注册表路径:HKLM\Software\Microsoft\Windows\CurrentVersion\Polic ...

  8. regexp 正则表达式

    * 给定字符串 str,检查其是否包含连续重复的字母(a-zA-Z),包含返回 true,否则返回 false input: 'rattler' output: true function conta ...

  9. Uncaught TypeError: upload is not a function at HTMLInputElement.onclick

    js 中标签的id名称不能和方法名一样, <tr> <td><input type="button" id="login" val ...

  10. 鸿蒙内核源码分析(GN应用篇) | GN语法及在鸿蒙的使用 | 百篇博客分析OpenHarmony源码 | v60.01

    百篇博客系列篇.本篇为: v60.xx 鸿蒙内核源码分析(gn应用篇) | gn语法及在鸿蒙的使用 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙 ...