首页 » 网站建设 » 浮屠php8开启jit技巧_Java中有一个令人惊异的bug

浮屠php8开启jit技巧_Java中有一个令人惊异的bug

访客 2024-11-16 0

扫一扫用手机浏览

文章目录 [+]

浮屠php8开启jit技巧_Java中有一个令人惊异的bug

浮屠php8开启jit技巧_Java中有一个令人惊异的bug
(图片来自网络侵删)

本日,分享一个JDK中令人惊异的BUG,这个BUG的神奇之处在于,复现它的用例太大略了,人肉眼就能回答的问题,JDK中却存在了十几年。
经由测试,我们创造从JDK8到14都存在这个问题。

大家可以在自己的开拓平台上试试这段代码:

publicclassHello{publicvoidtest(){int i=8;while ((i-=3)>0);System.out.println("i="+i);}publicstaticvoidmain(String[]args){Hellohello=newHello();for(int i=0;i<50_000;i++){hello.test();}}}

再利用以下命令实行:java Hello

然后,就会看到这样的输出:

当然,在程序的开始阶段,还是能打印出精确的"i = -1"。

这个问题终极Huawei JDK的两名同事办理掉了,并且回合到社区。
我这里大概讲一下剖析的思路。

首先,利用阐明实行可以创造,结果都是精确的,这就解释,这基本上是JIT编译器的问题,然后通过-XX:-TieredCompilation关闭C1编译,问题同样复现,但是利用-XX:TieredStopAtLevel=3将JIT编译勾留在C阶段,问题就不复现,这可以确定是C2的问题了。

接下来,一名同事立即猜想到这个"/"实在是('0'-1),刚好是字符零的ascii码减掉1。
嗯,熟记ascii码表的主要性就表示出来了。
接下来,便是找到c2中 int 转字符的地方。
关键点,就在于这个字符'0',当然这里要对C2有足够的理解,立时就找到c2中字符转化的方法(详细的代码 ,请参考OpenJDK社区):

voidPhaseStringOpts::int_getChars(GraphKit&kit,Nodearg,Nodechar_array,Nodestart,Nodeend){//......//charsign=0;Nodei=arg;Nodesign=__intcon(0);//if(i<0){//sign='-';//i=-i;//}{IfNodeiff=kit.create_and_map_if(kit.control(),__Bool(__CmpI(arg,__intcon(0)),BoolTest::lt),PROB_FAIR,COUNT_UNKNOWN);RegionNodemerge=new(C)RegionNode(3);kit.gvn().set_type(merge,Type::CONTROL);i=new(C)PhiNode(merge,TypeInt::INT);kit.gvn().set_type(i,TypeInt::INT);sign=new(C)PhiNode(merge,TypeInt::INT);kit.gvn().set_type(sign,TypeInt::INT);merge->init_req(1,__IfTrue(iff));i->init_req(1,__SubI(__intcon(0),arg));sign->init_req(1,__intcon('-'));merge->init_req(2,__IfFalse(iff));i->init_req(2,arg);sign->init_req(2,__intcon(0));kit.set_control(merge);C->record_for_igvn(merge);C->record_for_igvn(i);C->record_for_igvn(sign);}//for(;;){//q=i/10;//r=i-((q<<3)+(q<<1));//r=i-(q10)...//buf[--charPos]=digits[r];//i=q;//if(i==0)break;//}{//略去和这个循环相对应的代码}//略去很多代码}

可以看到,这里在中间表示阶段引入了一个“i < 0"的判断。
紧张便是那个CmpI结点,看起来这里的逻辑走错了,导致 i 明明小于0,结果却走到了大于0的分支,这样,直接拿字符'0'与i求和的结果,便是错的了。

那这个CmpI为什么会错呢?利用c2visualizer工具可以看到,在GVN阶段,上面循环中的CmpI和这里引入的CmpI被合并了。
GVN的全称是Global Value Numbering,名字很高大上,实在便是表达式去重。
例如:

上面的例子中,两个 CmpI 的输入参数是完备相同的。
都是变量 i 和整数 0,那么,这两个CmpI 结点实在便是完备相同的。
这样的话,编译器在做中间优化的时候就会把这两个CmpI结点合并成一个。

到这里为止,实在还是没问题的。
但接下来,编译器会对空的循环体做一些特殊的变换,编译器能直接打算出空循环体结束往后,i 的值是 -1,又创造空循环体什么都不做,以是,它干脆把CmpI的两个参数都换成了 -1,以便于让循环走不进来——而且,编译器再做一次常量传播就可以把这个CmpI彻底干掉了。
但是,这里CmpI就有问题了,这里强行搞成 False 让循环不实行,并且把 i 的值也直接变成循环结束的那个值。
但刚才合并的那个CmpI 也被吃掉了。

这就导致,直接拿着 i = -1 这个值进到了 i >= 0 的分支里了。
以是修正也很大略,那便是在对CmpI变换的时候,看看它还有没有其他的out,如果有,就复制一份出来。

这个BUG的干系issue和patch在这里:

bugs.openjdk.java.net/projects/JDK/issues/JDK-8231988?filter=allissues

JBS系统上没有详细的剖析过程,只有末了的patch,以是我把这个问题写了个总结发在这里。
可以看到,纵然是很大略的测试用例,在编译器内部也会经历各种繁芜的变换和优化。
然后一些阶段的优化可能会影响后一个阶段的,以是编译器的BUG也每每晦涩。
但反过来说,也很故意思

相关文章

介绍皮肤设置,如何打造理想肌肤状态

随着科技的发展和人们对美的追求,皮肤设置已成为美容护肤的重要一环。如何根据皮肤类型、肤质、年龄等因素进行合理设置,已成为众多爱美人...

网站建设 2025-01-03 阅读1 评论0

介绍盖章制作,传承文化,彰显权威

自古以来,盖章在我国文化中具有重要的地位。从古代的官印、私印到现代的公章、合同章,盖章已成为一种独特的文化符号,承载着丰富的历史内...

网站建设 2025-01-03 阅读1 评论0

介绍监控破坏,技术手段与法律风险并存

随着科技的飞速发展,监控设备已遍布大街小巷,成为维护社会治安的重要手段。一些不法分子为了逃避法律制裁,开始研究如何破坏监控设备。本...

网站建设 2025-01-03 阅读1 评论0

介绍登录不上之谜,技术故障还是人为疏忽

随着互联网的普及,登录已成为人们日常生活中不可或缺的一部分。在享受便捷的登录不上这一问题也困扰着许多用户。本文将深入剖析登录不上之...

网站建设 2025-01-03 阅读1 评论0

介绍电脑键盘调出方法,让操作更高效

随着科技的发展,电脑已经成为了我们日常生活中不可或缺的工具。而电脑键盘,作为电脑输入设备,更是我们与电脑进行交流的桥梁。你是否知道...

网站建设 2025-01-03 阅读1 评论0

介绍磁力链,高效便捷的文件下载利器

在互联网高速发展的今天,文件下载已成为日常生活中不可或缺的一部分。而磁力链作为一种新型的文件下载方式,凭借其高效、便捷的特点,受到...

网站建设 2025-01-03 阅读1 评论0