这一篇将详细介绍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. Java实现导出Excel

    项目中实现的代码: 一.//controller @RequestMapping(value = "/exportAccountManager") public void expo ...

  2. 队列,一种"公平"的数据结构

    路过一家奶茶店,由于生意火爆,门口的排着长长的队伍,先排队的人先买到奶茶,然后再轮到下一个,秩序井然.有没有一种数据结构能体现"先来后到"这种顺序呢? 当然有,那就是队列.先看一下 ...

  3. Shell系列(19)- 正则表达式

    正则表达式与通配符 正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配.grep,awk,sed等命令可以支持正则表达式. 通配符用来匹配符号条件的文件名,通配符是完全匹配.ls,find,c ...

  4. JDBC-2(CRUD)

    3.PreparedStatement实现CRUD 3.1 操作和访问数据库 数据库连接被用于向数据库服务器发送命令和SQL语句,接受数据库服务器返回的结果.(一个数据库连接就是也给Socket连接) ...

  5. Java面向对象系列(14)- 接口的定义与实现

    接口 普通类:只有具体实现 抽象类:具体实现和规范(抽象方法)都有 接口:只有规范!约束和实现分离 接口就是规范,定义的是一组规则,体现了现实世界中"如果你是-则必须能-"的思想. ...

  6. Java学习之随堂笔记系列——day01

    学习方法:听.问.敲.悟听:前提:上课要听懂,没有听懂可以及时的问.问:任何的问题都要及时的问.敲:重点内容.多写多练,只有写和练习才能发现新的问题,有问题就问.悟:举一反三.提升自己.今日内容:1. ...

  7. layui 各项配置

    第一.如何全部选中table中每一条记录 1.首先给table的父类设置一个唯一id *这种方式不推荐,效果比较差,推荐第2种方式 再搜索 alias-table div.layui-table-fi ...

  8. css3中的陌生词汇

    Transform transform属性是静态属性,一旦写到style里面,将会直接显示作用,无任何变化过程.transform的主要用途是用来做元素的特殊变形. 关于图形变形的基础条件当中的原点设 ...

  9. 我决定!墙裂推荐高清无码Python电子书(文中福利)

    @ 目录 前言 视频网站学习的优点和缺点 Python基础 游戏 网站开发 前言 近几年学了Python,查阅了不少资料,如B站,慕课网,我要自学网等等,然后自己边看学书自己整理学习资料,想分享下如何 ...

  10. 深入浅出WPF-03.XAML语法

    2 XAML语法 树形结构,我们将整个XAML的结构想象成一棵树,我们从树的顶部向下看,形成俯视图.最上面的叶子节点会覆盖父节点,同级的子节点,后面的(也就是树的最上面)会覆盖前面的.覆盖包含了形状( ...