iload会将int类型的本地变量推送至栈顶。模板定义如下:

def(Bytecodes::_iload , ubcp|____|clvm|____, vtos, itos, iload ,  _ );

iload指令的格式如下:

iload index

index是一个无符号byte类型整数,指向局部变量表的索引值。

生成函数为TemplateTable::iload(),反编译后的汇编代码如下:

// 将%ebx指向下一条字节码指令的首地址
0x00007fffe1028d30: movzbl 0x2(%r13),%ebx
// $0x15为_iload指令的操作码值
0x00007fffe1028d35: cmp $0x15,%ebx
// 当下一条指令为iload时,直接跳转到done
0x00007fffe1028d38: je 0x00007fffe1028deb // done // 0xdf为_fast_iload指令的操作码值
0x00007fffe1028d3e: cmp $0xdf,%ebx
// 将_fast_iload2指令移动到%ecx
0x00007fffe1028d44: mov $0xe0,%ecx
0x00007fffe1028d49: je 0x00007fffe1028d5a // rewrite // 0x34为_caload指令的操作码
// _caload指令表示从数组中加载一个char类型数据到操作数栈
0x00007fffe1028d4b: cmp $0x34,%ebx
// 将_fast_icaload移动到%ecx中
0x00007fffe1028d4e: mov $0xe1,%ecx
0x00007fffe1028d53: je 0x00007fffe1028d5a // rewrite // 将_fast_iload移动到%ecx中
0x00007fffe1028d55: mov $0xdf,%ecx // -- rewrite -- // 调用patch_bytecode()函数
// 重写为fast版本,因为%cl中存储的是字节码的fast版本,%ecx的8位叫%cl
0x00007fffe1028de7: mov %cl,0x0(%r13) // -- done -- // 获取字节码指令的操作数,这个操作数为本地变量表的索引
0x00007fffe1028deb: movzbl 0x1(%r13),%ebx
0x00007fffe1028df0: neg %rbx
// 通过本地变量表索引从本地变量表中加载值到%eax中,
// %eax中存储的就是栈顶缓存值,所以不需要压入栈内
0x00007fffe1028df3: mov (%r14,%rbx,8),%eax

执行的逻辑如下:

假设现在有个方法的字节码指令流为连接3个iload指令,这3个iload指令前后都为非iload指令。那么重写的过程如下:

汇编代码在第一次执行时,如果判断最后一个_iload之后是非_iload指令,则会重写最后一个_iload指令为_fast_iload;第二次执行时,当第2个字节码指令为_iload,而之后接着判断为_fast_iload时,会更新第2个_iload为_fast_iload2。

执行_fast_iload和执行_fast_iload2都可以提高程序执行的效率,_fast_icaload指令也一样,下面详细介绍一下这几个指令。

1、_fast_iload指令

_fast_iload会将int类型的本地变量推送至栈顶。模板定义如下:

def(Bytecodes::_fast_iload , ubcp|____|____|____, vtos, itos, fast_iload , _ );

生成函数为TemplateTable::fast_iload() ,汇编代码如下:

0x00007fffe1023f90: movzbl 0x1(%r13),%ebx
0x00007fffe1023f95: neg %rbx
0x00007fffe1023f98: mov (%r14,%rbx,8),%eax

汇编代码很简单,这里不再过多说。

执行_fast_iload指令与执行_iload指令相比,不用再进行之前汇编介绍的那么多判断,也没有重写的逻辑,所以会提高执行效率。

2、_fast_iload2指令

_fast_iload2会将int类型的本地变量推送至栈顶。模板定义如下:

def(Bytecodes::_fast_iload2 , ubcp|____|____|____, vtos, itos, fast_iload2 , _ );

生成函数为TemplateTable::fast_iload2() ,汇编代码如下:

0x00007fffe1024010: movzbl  0x1(%r13),%ebx
0x00007fffe1024015: neg %rbx
0x00007fffe1024018: mov (%r14,%rbx,8),%eax
0x00007fffe102401c: push %rax
0x00007fffe102401d: movzbl 0x3(%r13),%ebx
0x00007fffe1024022: neg %rbx
0x00007fffe1024025: mov (%r14,%rbx,8),%eax

可以看到,此指令就相当于连续执行了2次iload指令,省去了指令跳转,所以效率要高一些。

3、_fast_icaload指令

caload指令表示从数组中加载一个char类型数据到操作数栈。

_fast_icaload会将char类型数组指定索引的值推送至栈顶。模板定义如下:

def(Bytecodes::_fast_icaload , ubcp|____|____|____, vtos, itos, fast_icaload , _ );

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

0x00007fffe1024090: movzbl 0x1(%r13),%ebx
0x00007fffe1024095: neg %rbx
// %eax中存储着index
0x00007fffe1024098: mov (%r14,%rbx,8),%eax
// %rdx中存储着arrayref
0x00007fffe102409c: pop %rdx
// 将一个双字扩展后送到一个四字中,%rax中存储着index
0x00007fffe102409d: movslq %eax,%rax
// %rdx指向数组对象的首地址,偏移0xc后获取length属性的值
0x00007fffe10240a0: cmp 0xc(%rdx),%eax
0x00007fffe10240a3: mov %eax,%ebx
// 如果数组索引index等于数组的长度或大于数组长度时,那么跳转
// 到_throw_ArrayIndexOutOfBoundsException_entry抛出异常
0x00007fffe10240a5: jae 0x00007fffe100ff20
// 在指定数组arrayref中加载指定索引处index的值
0x00007fffe10240ab: movzwl 0x10(%rdx,%rax,2),%eax

可以看到,此指令省去了指令跳转,所以效率要高一些。

最新文章

  1. Git本地仓库
  2. switch2osm使用open street map离线地图中文乱码方框解决办法
  3. .NET笔试题集(一)
  4. Oracle游标示例
  5. ios工程中ARC与非ARC的混合
  6. [ActionScript 3.0] AS3 用于拖动对象时跟随鼠标的缓动效果
  7. LoopBar – Tap酒吧与无限滚动
  8. Jquery mobile 学习笔记
  9. JavaScript入门(4)
  10. SQL 无法打开物理文件 XXX.mdf",操作系统错误 5:"5(拒绝访问。)"
  11. MySQL-MHA高可用方案
  12. python基础入门教程《python入门经典》
  13. 删除git项目
  14. 安装 Tensorflow
  15. SQLServer 2008R2主从部署实战
  16. Python 的名称空间和作用域
  17. 2017.12.10《“剑锋OI”普及组多校联盟系列赛(14)#Sooke#Kornal 的课余时间 》分析报告
  18. ssh框架中.xml文件小技巧分离xml
  19. cpu概念
  20. 【剑指offer】广度优先遍历二叉树

热门文章

  1. [Kotlin Tutorials 19] Kotlin Flows, SharedFlow and StateFlow in Android
  2. SpringBoot博客开发之AOP日志处理
  3. rabbitMq内存与磁盘分配问题
  4. IT项目经理-成长手记学习笔记
  5. 程序挂了之后别再跟我说让我帮你重启啦! 让supervisor帮你搞定...
  6. 安装配置Linux Squid代理服务器
  7. Geode member发现机制
  8. openwrt开发笔记二:树莓派刷openwrt
  9. Docker(23)- 注册 docker hub 的账号
  10. Docker(40)- docker 实战三之安装 ES+Kibana