java - 了解 Java 热点 JIT 生成的用于 float 测试的代码

标签 java assembly jit disassembly jvm-hotspot

我注意到我的一个数字处理程序中的一些看似无辜的 if 语句显着降低了执行速度(JRE 1.8.25、64 位 Hotspot 版本 25.25-b02、Intel 64 位 CPU)。

我检查了 JIT 编译器生成的代码,看起来有点奇怪。这是一个简单的函数来说明问题:

private float test(float a,float b) {
    float c=a+b;
    if(c<0) {
        return -1;
    }
    return 0;
}

这是生成的代码中有趣的部分:

...
0x2bd17ae: vaddss  xmm0,xmm0,xmm1
0x2bd17b2: vxorps  xmm1,xmm1,xmm1
0x2bd17b6: vucomiss xmm0,xmm1
0x2bd17ba: mov     esi,1h
0x2bd17bf: jp      2bd17d8h
0x2bd17c5: jnbe    2bd17d8h
0x2bd17cb: mov     esi,0h
0x2bd17d0: je      2bd17d8h
0x2bd17d6: dec     esi               ;*fcmpg
0x2bd17d8: cmp     esi,0h
0x2bd17db: mov     rsi,57448760h     ; {metadata(method data for {method} ...}
0x2bd17e5: mov     rdi,108h
0x2bd17ef: jnl     2bd17ffh
0x2bd17f5: mov     rdi,118h
0x2bd17ff: mov     rbx,qword ptr [rsi+rdi]
0x2bd1803: lea     rbx,[rbx+1h]
0x2bd1807: mov     qword ptr [rsi+rdi],rbx
0x2bd180b: jnl     2bd1c1fh          ;*ifge
...
// straightforward code for "return -1f" and "return 0f" follows
...

从 0x2bd17ba 到 0x2bd1807 的代码对我来说没有多大意义。为什么它在那里?知道它有什么作用吗?

编辑:想一想,这可能是 JIT 编译器添加的一些代码来收集运行时统计信息(只是因为“元数据”注释而猜测)。但问题是:为什么会有?我已经调用该方法数百万次,因此我认为代码应该已达到最终的优化形式。

最佳答案

(v)ucommiss 设置标志如下:

unordered    zf,pf,cf = 111
greater      zf,pf,cf = 000
less than    zf,pf,cf = 001
equal        zf,pf,cf = 100

所以这段代码:

    mov     esi,1h
    jp      label  ; if unordered, or
    jnbe    label  ; if greater than, keep it at 1
    mov     esi,0h
    je      label  ; if equal, make 0
    dec     esi    ; otherwise -1
label:

使 esi = 1(如果无序或更大)、esi = 0(如果相等)、esi = -1(如果更小)

然后它将 esi 与 0 进行比较,标记为“ifge”的行确实​​通过检查 esi 不小于 0 来检查“如果大于或等于”(某种程度上,还包括无序情况),因此分支的“else”部分。

从 0x2bd17db 到 0x2bd1807 的部分有条件地递增两个计数器,无论是其中一个还是另一个,具体取决于分支采用的方式。所以这是某种分析。也许稍后会用于优化,但我不知道(不过你还会用它做什么)。

他们本来可以这样做:

vaddss  xmm0,xmm0,xmm1
vxorps  xmm1,xmm1,xmm1
vcmpss  xmm0,xmm1,1
vandps  xmm0,xmm0,[rel negative_one]
ret

没有分析,但是就没有分支,所以没有什么可以分析的。

关于java - 了解 Java 热点 JIT 生成的用于 float 测试的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26811217/

相关文章:

java - 了解 Java 中的 Try-Catch 和异常处理

C# 带有分支的奇怪行为

c# - 如何在内存中运行一些代码?

javascript - React Native 在 Android 上使用 JIT(Just in Time)编译还是解释 JavaScript 代码?

java - 如何在保持旋转角度的同时使用补间 x,y?

java - 将函数作为对 Java 中另一个方法的引用传递

c++ - x64 函数调用参数推送/移动顺序 (MSVC)

assembly - 传递指向汇编函数的指针

java - Seam & 多个 war : Contexts. getSessionContext() 在其他 war 中为 null

assembly - 汇编语言是如何结合到程序中的?