在我看来,从一个非常琐碎的测试案例来看,就像JVM将所有
double计算通过内存进行往返以获取所需的舍入。它似乎还对一些魔术常数做了一些奇怪的事情。这是一个简单的“天真地计算2
^ n”程序对我的作用:
0xb1e444b0: fld10xb1e444b2: jmp 0xb1e444dd ;*iload ; - fptest::calc@9 (line 6)0xb1e444b7: nop0xb1e444b8: fldt 0xb523a2c8 ; {external_word}0xb1e444be: fmulp %st,%st(1)0xb1e444c0: fmull 0xb1e44490 ; {section_word}0xb1e444c6: fldt 0xb523a2bc ; {external_word}0xb1e444cc: fmulp %st,%st(1)0xb1e444ce: fstpl 0x10(%esp)0xb1e444d2: inc %esi ; OopMap{off=51} ;*goto ; - fptest::calc@22 (line 6)0xb1e444d3: test %eax,0xb3f8d100 ; {poll}0xb1e444d9: fldl 0x10(%esp) ;*goto ; - fptest::calc@22 (line 6)0xb1e444dd: cmp %ecx,%esi0xb1e444df: jl 0xb1e444b8 ;*if_icmpge ; - fptest::calc@12 (line 6)我相信
0xb523a2c8和
0xb523a2bc是
_fpu_subnormal_bias1和
_fpu_subnormal_bias2从热点的源代码。
_fpu_subnormal_bias1看起来将会存在
0x03ff8000000000000000,
_fpu_subnormal_bias2看起来将会存在
0x7bff8000000000000000。
_fpu_subnormal_bias1具有将最小法线缩放
double到最小法线的作用
long double;
如果FPU舍入到53位,则将发生“正确的事情”。
我猜想那里似乎没有意义的
test指令,以便在需要GC的情况下可以通过将该页面标记为不可读来中断线程。
这是Java代码:
import java.io.*;public strictfp class fptest { public static double calc(int k) { double a = 2.0; double b = 1.0; for (int i = 0; i < k; i++) { b *= a; } return b; } public static double intest() { double d = 0; for (int i = 0; i < 4100; i++) d += calc(i); return d; } public static void main(String[] args) throws Exception { for (int i = 0; i < 100; i++) System.out.println(intest()); }}进一步挖掘,这些操作的代码在中的OpenJDK代码中很清楚
hotspot/src/cpu/x86/vm/x86_63.ad。相关片段:
instruct strictfp_mulD_reg(regDPR1 dst, regnotDPR1 src) %{ predicate( UseSSE<=1 && Compile::current()->has_method() && Compile::current()->method()->is_strict() ); match(Set dst (MulD dst src)); ins_cost(1); // Select this instruction for all strict FP double multiplies format %{ "FLD StubRoutines::_fpu_subnormal_bias1nt" "DMULp $dst,STnt" "FLD $srcnt" "DMULp $dst,STnt" "FLD StubRoutines::_fpu_subnormal_bias2nt" "DMULp $dst,STnt" %} oppre(0xDE, 0x1); ins_enpre( strictfp_bias1(dst), Push_Reg_D(src), OpcP, RegOpc(dst), strictfp_bias2(dst) ); ins_pipe( fpu_reg_reg );%}instruct strictfp_divD_reg(regDPR1 dst, regnotDPR1 src) %{ predicate (UseSSE<=1); match(Set dst (DivD dst src)); predicate( UseSSE<=1 && Compile::current()->has_method() && Compile::current()->method()->is_strict() ); ins_cost(01); format %{ "FLD StubRoutines::_fpu_subnormal_bias1nt" "DMULp $dst,STnt" "FLD $srcnt" "FDIVp $dst,STnt" "FLD StubRoutines::_fpu_subnormal_bias2nt" "DMULp $dst,STnt" %} oppre(0xDE, 0x7); ins_enpre( strictfp_bias1(dst), Push_Reg_D(src), OpcP, RegOpc(dst), strictfp_bias2(dst) ); ins_pipe( fpu_reg_reg );%}我看不到要加减的任何东西,但是我敢打赌他们只是在FPU的53位模式下进行加/减,然后将结果通过内存往返。我有点好奇是否有一个棘手的溢出情况,他们弄错了,但我并不好奇,无法找出答案。



