当前位置:  开发笔记 > 编程语言 > 正文

Linux平台中Java代码的调用约定是什么?

如何解决《Linux平台中Java代码的调用约定是什么?》经验,为你挑选了1个好方法。

我们知道调用约定"前六个整数或指针参数在寄存器RDI,RSI,RDX,RCX(Linux内核接口中的R10:124),R8和R9"中传递给c/c ++代码Linux平台基于以下文章. https://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_calling_conventions

然而,Linux平台中Java代码的调用约定是什么(假设JVM是热点)?以下是示例,什么寄存器存储这四个参数?

protected void caller( ) {
callee(1,"123", 123,1)
}

protected void callee(int a,String b, Integer c,Object d) {

}

apangin.. 10

未指定JVM如何在内部调用Java方法.各种JVM实现可以遵循不同的调用约定.以下是它在Linux x64上的HotSpot JVM中的工作原理.

Java方法可以在解释器中运行,也可以进行JIT编译.

解释和编译的代码使用不同的调用约定.

1.口译员方法录入

每个Java方法都有一个进入解释器的入口点.此条目用于从解释方法跳转到另一个解释方法.

所有参数都在堆栈中传递,从下到上.

rbx包含指向Method*结构的指针- 被调用方法的内部元数据.

r13保持sender_sp- 调用方法的堆栈指针.它可能与rsp + 8使用c2i适配器不同(见下文).

有关HotSpot源代码中解释器条目的更多详细信息:templateInterpreter_x86_64.cpp.

2.编入条目

编译后的方法有自己的入口点.编译代码通过此条目调用编译的方法.

多达6个第一整数参数被传递在寄存器:rsi,rdx,rcx,r8,r9,rdi.非静态方法接收this引用作为第一个参数rsi.

xmm0... xmm7寄存器中最多传递8个浮点参数.

所有其他参数从堆栈上下传递.

在assembler_x86.hpp中很好地说明了这个约定:

    |-------------------------------------------------------|
    | c_rarg0   c_rarg1  c_rarg2 c_rarg3 c_rarg4 c_rarg5    |
    |-------------------------------------------------------|
    | rcx       rdx      r8      r9      rdi*    rsi*       | windows (* not a c_rarg)
    | rdi       rsi      rdx     rcx     r8      r9         | solaris/linux
    |-------------------------------------------------------|
    | j_rarg5   j_rarg0  j_rarg1 j_rarg2 j_rarg3 j_rarg4    |
    |-------------------------------------------------------|

您可能会注意到Java调用约定看起来类似于C调用约定但右移一个参数.有意这样做是为了避免在调用JNI方法时额外的寄存器重排(你知道,JNI方法JNIEnv*在方法参数之前有额外的参数).

3.适配器

Java方法可能还有两个入口点:c2ii2c适配器.这些适配器是动态生成的代码片段,它们将编译的调用约定转换为解释器布局,反之亦然.?2ii2c入口点分别用于从已编译的代码和已解释的代码中编译的方法调用解释的方法.


PS JVM内部调用方法通常并不重要,因为这些只是对最终用户不透明的实现细节.此外,即使在较小的JDK更新中,这些细节也可能会发生变化.但是,我知道至少有一种情况,当Java调用约定的知识可能看起来很有用时 - 分析JVM崩溃转储时.



1> apangin..:

未指定JVM如何在内部调用Java方法.各种JVM实现可以遵循不同的调用约定.以下是它在Linux x64上的HotSpot JVM中的工作原理.

Java方法可以在解释器中运行,也可以进行JIT编译.

解释和编译的代码使用不同的调用约定.

1.口译员方法录入

每个Java方法都有一个进入解释器的入口点.此条目用于从解释方法跳转到另一个解释方法.

所有参数都在堆栈中传递,从下到上.

rbx包含指向Method*结构的指针- 被调用方法的内部元数据.

r13保持sender_sp- 调用方法的堆栈指针.它可能与rsp + 8使用c2i适配器不同(见下文).

有关HotSpot源代码中解释器条目的更多详细信息:templateInterpreter_x86_64.cpp.

2.编入条目

编译后的方法有自己的入口点.编译代码通过此条目调用编译的方法.

多达6个第一整数参数被传递在寄存器:rsi,rdx,rcx,r8,r9,rdi.非静态方法接收this引用作为第一个参数rsi.

xmm0... xmm7寄存器中最多传递8个浮点参数.

所有其他参数从堆栈上下传递.

在assembler_x86.hpp中很好地说明了这个约定:

    |-------------------------------------------------------|
    | c_rarg0   c_rarg1  c_rarg2 c_rarg3 c_rarg4 c_rarg5    |
    |-------------------------------------------------------|
    | rcx       rdx      r8      r9      rdi*    rsi*       | windows (* not a c_rarg)
    | rdi       rsi      rdx     rcx     r8      r9         | solaris/linux
    |-------------------------------------------------------|
    | j_rarg5   j_rarg0  j_rarg1 j_rarg2 j_rarg3 j_rarg4    |
    |-------------------------------------------------------|

您可能会注意到Java调用约定看起来类似于C调用约定但右移一个参数.有意这样做是为了避免在调用JNI方法时额外的寄存器重排(你知道,JNI方法JNIEnv*在方法参数之前有额外的参数).

3.适配器

Java方法可能还有两个入口点:c2ii2c适配器.这些适配器是动态生成的代码片段,它们将编译的调用约定转换为解释器布局,反之亦然.?2ii2c入口点分别用于从已编译的代码和已解释的代码中编译的方法调用解释的方法.


PS JVM内部调用方法通常并不重要,因为这些只是对最终用户不透明的实现细节.此外,即使在较小的JDK更新中,这些细节也可能会发生变化.但是,我知道至少有一种情况,当Java调用约定的知识可能看起来很有用时 - 分析JVM崩溃转储时.

推荐阅读
路人甲
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有