我注意到我的一个数字处理程序中的一些看似无辜的 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/