นี้สามารถทำซ้ำได้อย่างน่าเชื่อถือ (หรือไม่ทำซ้ำขึ้นอยู่กับสิ่งที่คุณต้องการ) ด้วยopenjdk version "1.8.0_222"
(ใช้ในการวิเคราะห์ของฉัน), OpenJDK12.0.1
(ตาม Oleksandr Pyrohov) และ OpenJDK 13 (ตามคาร์ลอส Heuberger)
ฉันรันโค้ดด้วย -XX:+PrintCompilation
เวลาเพียงพอที่จะรับทั้งพฤติกรรมและนี่คือความแตกต่าง
การใช้งาน Buggy (แสดงผลลัพธ์):
--- Previous lines are identical in both
54 17 3 java.lang.AbstractStringBuilder::<init> (12 bytes)
54 23 3 LoopOutPut::test (57 bytes)
54 18 3 java.lang.String::<init> (82 bytes)
55 21 3 java.lang.AbstractStringBuilder::append (62 bytes)
55 26 4 java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes)
55 20 3 java.lang.StringBuilder::<init> (7 bytes)
56 19 3 java.lang.StringBuilder::toString (17 bytes)
56 25 3 java.lang.Integer::getChars (131 bytes)
56 22 3 java.lang.StringBuilder::append (8 bytes)
56 27 4 java.lang.String::equals (81 bytes)
56 10 3 java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes) made not entrant
56 28 4 java.lang.AbstractStringBuilder::append (50 bytes)
56 29 4 java.lang.String::getChars (62 bytes)
56 24 3 java.lang.Integer::stringSize (21 bytes)
58 14 3 java.lang.String::getChars (62 bytes) made not entrant
58 33 4 LoopOutPut::test (57 bytes)
59 13 3 java.lang.AbstractStringBuilder::append (50 bytes) made not entrant
59 34 4 java.lang.Integer::getChars (131 bytes)
60 3 3 java.lang.String::equals (81 bytes) made not entrant
60 30 4 java.util.Arrays::copyOfRange (63 bytes)
61 25 3 java.lang.Integer::getChars (131 bytes) made not entrant
61 32 4 java.lang.String::<init> (82 bytes)
61 16 3 java.util.Arrays::copyOfRange (63 bytes) made not entrant
61 31 4 java.lang.AbstractStringBuilder::append (62 bytes)
61 23 3 LoopOutPut::test (57 bytes) made not entrant
61 33 4 LoopOutPut::test (57 bytes) made not entrant
62 35 3 LoopOutPut::test (57 bytes)
63 36 4 java.lang.StringBuilder::append (8 bytes)
63 18 3 java.lang.String::<init> (82 bytes) made not entrant
63 38 4 java.lang.StringBuilder::append (8 bytes)
64 21 3 java.lang.AbstractStringBuilder::append (62 bytes) made not entrant
เรียกใช้ที่ถูกต้อง (ไม่มีจอแสดงผล):
--- Previous lines identical in both
55 23 3 LoopOutPut::test (57 bytes)
55 17 3 java.lang.AbstractStringBuilder::<init> (12 bytes)
56 18 3 java.lang.String::<init> (82 bytes)
56 20 3 java.lang.StringBuilder::<init> (7 bytes)
56 21 3 java.lang.AbstractStringBuilder::append (62 bytes)
56 26 4 java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes)
56 19 3 java.lang.StringBuilder::toString (17 bytes)
57 22 3 java.lang.StringBuilder::append (8 bytes)
57 24 3 java.lang.Integer::stringSize (21 bytes)
57 25 3 java.lang.Integer::getChars (131 bytes)
57 27 4 java.lang.String::equals (81 bytes)
57 28 4 java.lang.AbstractStringBuilder::append (50 bytes)
57 10 3 java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes) made not entrant
57 29 4 java.util.Arrays::copyOfRange (63 bytes)
60 16 3 java.util.Arrays::copyOfRange (63 bytes) made not entrant
60 13 3 java.lang.AbstractStringBuilder::append (50 bytes) made not entrant
60 33 4 LoopOutPut::test (57 bytes)
60 34 4 java.lang.Integer::getChars (131 bytes)
61 3 3 java.lang.String::equals (81 bytes) made not entrant
61 32 4 java.lang.String::<init> (82 bytes)
62 25 3 java.lang.Integer::getChars (131 bytes) made not entrant
62 30 4 java.lang.AbstractStringBuilder::append (62 bytes)
63 18 3 java.lang.String::<init> (82 bytes) made not entrant
63 31 4 java.lang.String::getChars (62 bytes)
เราสามารถสังเกตเห็นความแตกต่างที่สำคัญอย่างหนึ่ง ด้วยการดำเนินการที่ถูกต้องเรารวบรวมtest()
สองครั้ง ครั้งแรกในการเริ่มต้นและอีกครั้งหลังจากนั้น (น่าจะเป็นเพราะ JIT สังเกตเห็นวิธีการที่ร้อน) ในการดำเนินการรถมีการtest()
รวบรวม (หรือ decompiled) 5ครั้ง
นอกจากนี้การรันด้วย-XX:-TieredCompilation
(ซึ่งแปลหรือใช้C2
) หรือด้วย-Xbatch
(ซึ่งบังคับให้คอมไพล์รันในเธรดหลักแทนที่จะเป็นพารัลลี่) ผลลัพธ์ถูกรับประกันและด้วยการวนซ้ำ 30000 พิมพ์สิ่งต่าง ๆ มากมายดังนั้นC2
คอมไพเลอร์จึงดูเหมือนว่า เป็นผู้กระทำผิด สิ่งนี้ได้รับการยืนยันจากการรันด้วย-XX:TieredStopAtLevel=1
ซึ่งปิดใช้C2
และไม่สร้างเอาต์พุต (การหยุดที่ระดับ 4 แสดงข้อผิดพลาดอีกครั้ง)
ในการดำเนินการที่ถูกต้องวิธีการจะถูกรวบรวมครั้งแรกด้วย ระดับ 3จากนั้นตามด้วยระดับ 4
ในการดำเนินการแบบบั๊กการรวบรวมก่อนหน้านี้จะถูกแยกออก ( made non entrant
) และจะถูกรวบรวมอีกครั้งในระดับ 3 (ซึ่งก็คือC1
ดูลิงค์ก่อนหน้า)
ดังนั้นมันจึงเป็นข้อบกพร่องอย่างแน่นอน C2
ถึงแม้ว่าฉันจะไม่แน่ใจจริง ๆ ว่าการกลับไปสู่การรวบรวมระดับ 3 มีผลกับมันหรือไม่
คุณสามารถสร้างรหัสแอสเซมบลีด้วยบรรทัดต่อไปนี้เพื่อเจาะลึกลงไปในรูกระต่าย (ดูที่นี่เพื่อเปิดใช้งานการพิมพ์แอสเซมบลี)
java -XX:+PrintCompilation -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly LoopOutPut > broken.asm
ณ จุดนี้ฉันเริ่มหมดทักษะพฤติกรรมรถเริ่มแสดงเมื่อรุ่นที่รวบรวมก่อนหน้านี้ถูกทิ้ง แต่สิ่งที่ทักษะการชุมนุมเล็ก ๆ ที่ฉันได้มาจากยุค 90 ดังนั้นฉันจะให้ใครฉลาดกว่าฉันใช้มัน จากที่นี่.
อาจเป็นไปได้ว่ามีรายงานข้อผิดพลาดเกี่ยวกับเรื่องนี้อยู่แล้วเนื่องจากมีการนำเสนอรหัสต่อ OP โดยคนอื่นและเนื่องจากรหัสC2ทั้งหมดไม่มีข้อบกพร่องไม่ได้โดยไม่มีข้อบกพร่อง ฉันหวังว่าการวิเคราะห์นี้จะให้ข้อมูลกับคนอื่น ๆ เหมือนที่ฉันได้รับ
ในฐานะที่เป็นที่เคารพ apangin ชี้ให้เห็นในความคิดเห็นนี้เป็นข้อผิดพลาดที่ผ่านมา จำเป็นอย่างยิ่งต่อผู้ที่สนใจและเป็นประโยชน์ :)