当前位置: 首页 > news >正文

从iload_1 iload_2 iadd字节码角度看jvm字节码执行

ubuntu22 环境openjdk17

字节码执行流程分析

在Java字节码中,iload指令用于从局部变量加载int值到操作数栈,iadd指令用于将两个int值相加。在模板解释器中,执行字节码时会维护一个TosState(top-of-stack state),表示当前栈顶值的类型和位置(例如,vtos表示栈顶值在内存栈上,itos表示栈顶值在rax寄存器中)。

1. 第一个iload(例如iload_1
  • 字节码期望输入状态为vtos(栈顶无值在寄存器中),输出状态为itos(值在rax寄存器中)。

  • 根据C++代码中的iload函数:

    cpp

    transition(vtos, itos);
    __ movl(rax, iaddress(n));  // 将局部变量n的值加载到rax寄存器
  • 执行后,值被加载到rax寄存器中,当前状态变为itos

2. 第二个iload(例如iload_2
  • 第二个iload同样期望输入状态为vtos,但当前状态是itos(来自第一个iload)。因此,需要将当前rax中的值推送到内存栈上,以将状态调整为vtos

  • 在C++代码的set_vtos_entry_points函数中,对于itos状态,有:

    cpp

    aep = bep = cep = sep = iep = __ pc();      // [abcsi]tos entry point
    __ push_i_or_ptr();  // 将rax中的整数值推送到栈上
  • 推送后,状态变为vtos(值在栈上),然后执行iload_2

    cpp

    transition(vtos, itos);
    __ movl(rax, iaddress(n));  // 加载新值到rax
  • 执行后,栈上有一个值(来自第一个iload),rax寄存器中有新值(来自第二个iload),状态变为itos

3. iadd指令
  • iadd期望输入状态为itos(值在rax中),但需要另一个操作数从栈上弹出。

  • 根据C++代码中的iop2函数(用于整数操作):

    cpp

    transition(itos, itos);
    switch (op) {
    case add  :                    __ pop_i(rdx); __ addl (rax, rdx); break;
    }
  • __ pop_i(rdx)从栈上弹出值到rdx寄存器(即第一个iload推送的值),然后与rax寄存器中的值相加,结果保存在rax中,状态保持itos

用户理解的正确性

您的理解是正确的:

  • 第一个iload将值加载到rax,状态变为itos

  • 第二个iload时,当前状态是itos而不是期望的vtos,因此将前一个值(rax中的值)push入栈(状态变为vtos),然后加载新值到rax(状态又变为itos)。

  • iadd执行时,pop出栈顶值到rdx寄存器,然后与rax相加。

补充说明

  • 在模板解释器中,TosState的管理是为了优化性能,尽可能将值保留在寄存器中,减少内存访问。但当字节码期望的状态与当前状态不匹配时,需要通过push或pop操作进行转换。

##C++源码

  def(Bytecodes::_iadd                , ____|____|____|____, itos, itos, iop2                , add          );def(Bytecodes::_iload_1             , ____|____|____|____, vtos, itos, iload               ,  1           );def(Bytecodes::_iload_2             , ____|____|____|____, vtos, itos, iload               ,  2           );void TemplateInterpreterGenerator::set_short_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) {assert(t->is_valid(), "template must exist");switch (t->tos_in()) {case btos:case ztos:case ctos:case stos:ShouldNotReachHere();  // btos/ctos/stos should use itos.break;case atos: vep = __ pc(); __ pop(atos); aep = __ pc(); generate_and_dispatch(t); break;case itos: vep = __ pc(); __ pop(itos); iep = __ pc(); generate_and_dispatch(t); break;case ltos: vep = __ pc(); __ pop(ltos); lep = __ pc(); generate_and_dispatch(t); break;case ftos: vep = __ pc(); __ pop(ftos); fep = __ pc(); generate_and_dispatch(t); break;case dtos: vep = __ pc(); __ pop(dtos); dep = __ pc(); generate_and_dispatch(t); break;case vtos: set_vtos_entry_points(t, bep, cep, sep, aep, iep, lep, fep, dep, vep);     break;default  : ShouldNotReachHere();                                                 break;}
}void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,address& bep,address& cep,address& sep,address& aep,address& iep,address& lep,address& fep,address& dep,address& vep) {assert(t->is_valid() && t->tos_in() == vtos, "illegal template");Label L;
#ifndef _LP64fep = __ pc();     // ftos entry point__ push(ftos);__ jmp(L);dep = __ pc();     // dtos entry point__ push(dtos);__ jmp(L);
#elsefep = __ pc();     // ftos entry point__ push_f(xmm0);__ jmp(L);dep = __ pc();     // dtos entry point__ push_d(xmm0);__ jmp(L);
#endif // _LP64lep = __ pc();     // ltos entry point__ push_l();__ jmp(L);aep = bep = cep = sep = iep = __ pc();      // [abcsi]tos entry point//yym-gaizao// 增加日志输出,打印即将压入栈的整数值// 假设整数值在 rax 寄存器中__ push(rbx); // 保存 rbx 寄存器__ push(rax); // 保存 rax 寄存器__ movptr(rbx, rax); // 将值移动到 rbx 以便保存__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::print_int_value), rbx);__ pop(rax); // 恢复 rax 寄存器__ pop(rbx); // 恢复 rbx 寄存器__ push_i_or_ptr();vep = __ pc();    // vtos entry point__ bind(L);generate_and_dispatch(t);
}void TemplateTable::iop2(Operation op) {transition(itos, itos);switch (op) {case add  :                    __ pop_i(rdx); __ addl (rax, rdx); break;case sub  : __ movl(rdx, rax); __ pop_i(rax); __ subl (rax, rdx); break;case mul  :                    __ pop_i(rdx); __ imull(rax, rdx); break;case _and :                    __ pop_i(rdx); __ andl (rax, rdx); break;case _or  :                    __ pop_i(rdx); __ orl  (rax, rdx); break;case _xor :                    __ pop_i(rdx); __ xorl (rax, rdx); break;case shl  : __ movl(rcx, rax); __ pop_i(rax); __ shll (rax);      break;case shr  : __ movl(rcx, rax); __ pop_i(rax); __ sarl (rax);      break;case ushr : __ movl(rcx, rax); __ pop_i(rax); __ shrl (rax);      break;default   : ShouldNotReachHere();}
}void TemplateTable::iload(int n) {transition(vtos, itos);__ movl(rax, iaddress(n));#if 0// 保存到 rax 的值即为 iload 加载的整数,我们希望记录它// yym-gaizao: 添加日志记录{__ push(rax);  // 备份值__ movl(c_rarg0, rax);  // 将值传递给参数1(c_rarg0)__ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::log_iload),c_rarg0);__ pop(rax);  // 恢复寄存器}#endif
}void InterpreterMacroAssembler::pop(TosState state) {switch (state) {case atos: pop_ptr();                 break;case btos:case ztos:case ctos:case stos:case itos: pop_i();                   break;case ltos: pop_l();                   break;case ftos: pop_f(xmm0);               break;case dtos: pop_d(xmm0);               break;case vtos: /* nothing to do */        break;default:   ShouldNotReachHere();}interp_verify_oop(rax, state);
}#ifdef _LP64
void InterpreterMacroAssembler::pop_i(Register r) {// XXX can't use pop currently, upper half non cleanmovl(r, Address(rsp, 0));addptr(rsp, wordSize);
}void Assembler::push(int32_t imm32) {// in 64bits we push 64bits onto the stack but only// take a 32bit immediateemit_int8(0x68);emit_int32(imm32);
}

##志愿者

yym@yym:~/javaTest/javaByteCode$ cat ByteCodeTest.java
public class ByteCodeTest {public int add(int a, int b) {return a+b;}public int test() {int a = 2146598;int b = 1091754;int c = add(a, b);return c;}public static void main(String[] args) {ByteCodeTest byteCodeTest = new ByteCodeTest();byteCodeTest.test();}
}yym@yym:~/javaTest/javaByteCode$ javap -v ByteCodeTest
Classfile /home/yym/javaTest/javaByteCode/ByteCodeTest.classLast modified Sep. 19, 2025; size 459 bytesMD5 checksum 572a90d6c72910fade5618ef4133bc54Compiled from "ByteCodeTest.java"
public class ByteCodeTestminor version: 0major version: 55flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #5                          // ByteCodeTestsuper_class: #8                         // java/lang/Objectinterfaces: 0, fields: 0, methods: 4, attributes: 1
Constant pool:#1 = Methodref          #8.#21         // java/lang/Object."<init>":()V#2 = Integer            2146598#3 = Integer            1091754#4 = Methodref          #5.#22         // ByteCodeTest.add:(II)I#5 = Class              #23            // ByteCodeTest#6 = Methodref          #5.#21         // ByteCodeTest."<init>":()V#7 = Methodref          #5.#24         // ByteCodeTest.test:()I#8 = Class              #25            // java/lang/Object#9 = Utf8               <init>#10 = Utf8               ()V#11 = Utf8               Code#12 = Utf8               LineNumberTable#13 = Utf8               add#14 = Utf8               (II)I#15 = Utf8               test#16 = Utf8               ()I#17 = Utf8               main#18 = Utf8               ([Ljava/lang/String;)V#19 = Utf8               SourceFile#20 = Utf8               ByteCodeTest.java#21 = NameAndType        #9:#10         // "<init>":()V#22 = NameAndType        #13:#14        // add:(II)I#23 = Utf8               ByteCodeTest#24 = NameAndType        #15:#16        // test:()I#25 = Utf8               java/lang/Object
{public ByteCodeTest();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 1: 0public int add(int, int);descriptor: (II)Iflags: (0x0001) ACC_PUBLICCode:stack=2, locals=3, args_size=30: iload_11: iload_22: iadd3: ireturnLineNumberTable:line 4: 0public int test();descriptor: ()Iflags: (0x0001) ACC_PUBLICCode:stack=3, locals=4, args_size=10: ldc           #2                  // int 21465982: istore_13: ldc           #3                  // int 10917545: istore_26: aload_07: iload_18: iload_29: invokevirtual #4                  // Method add:(II)I12: istore_313: iload_314: ireturnLineNumberTable:line 8: 0line 9: 3line 10: 6line 11: 13public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: (0x0009) ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=10: new           #5                  // class ByteCodeTest3: dup4: invokespecial #6                  // Method "<init>":()V7: astore_18: aload_19: invokevirtual #7                  // Method test:()I12: pop13: returnLineNumberTable:line 15: 0line 16: 8line 17: 13
}

http://www.dtcms.com/a/392936.html

相关文章:

  • openssl 启用AES NI加速对AES加密性能影响的测试
  • LeetCode:32.随机链表的复制
  • 基于SpringBoot+Vue的旅游系统【协同过滤推荐算法+可视化统计】
  • 前端实现一个星空特效的效果(实战+讲解)
  • 【嵌入式】【科普】软件模块设计简介
  • 【ROS2】ROS2通讯机制Topic常用命令行
  • 欧姆龙NJ系列PLC编程标准化案例
  • 【OpenGL】LearnOpenGL学习笔记25 - 法线贴图 NormalMap
  • UE5 基础应用 —— 09 - 行为树 简单使用
  • 客户端实现信道管理
  • 异常解决记录 | Yarn NodeManager 注册异常
  • 【C#】C# 调用 Python 脚本正确姿势:解决 WaitForExit 死锁与退出检测问题
  • Java25新特性
  • 卷积神经网络CNN-part9-DenseNet
  • 深入浅出密码学第一章课后题(持续更新)
  • Mysql 入门概览
  • 大模型中权重共享的作用?
  • 【精品资料鉴赏】55页可编辑PPT详解 数字化高校智慧后勤解决方案
  • LLM大模型 - 实战篇 - AI Agents的开发应用
  • 【分布式技术】RedisShake相关功能详细介绍
  • qsv:一款高性能的CSV数据处理工具
  • `html` 将视频作为背景
  • 口播提词器怎么选?手机提词器实测指南与参数推荐
  • 解剖线性表
  • 计算数学研究方向有哪些细分领域?
  • [xboard]08-Makefile逐行分析2
  • Clash 中 REJECT 的技术原理与解决方案 —— 以哔哩哔哩延迟问题为例
  • 庖丁解牛与专家思维:道家的“心手合一”训练法
  • matlab通过GUI实现点云的读取、自定义显示和保存
  • 工业现场实战:如何利用智能网关实现西门子PLC与库卡机器人的无缝连接