Bu, ( openjdk version "1.8.0_222"
analizimde kullanılan), OpenJDK 12.0.1
(Oleksandr Pyrohov'a göre) ve OpenJDK 13 (Carlos Heuberger'e göre ) ile güvenilir bir şekilde çoğaltılabilir (veya ne istediğinize bağlı olarak çoğaltılamaz ).
Her -XX:+PrintCompilation
iki davranışı almak için yeterli kez kodu koştu ve işte farklılıklar.
Buggy uygulaması (çıktıyı görüntüler):
--- 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
Doğru çalışma (ekran yok):
--- 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)
Önemli bir fark görebiliriz. Doğru uygulama ile test()
iki kez derleriz. Bir kez başlangıçta ve daha sonra bir kez daha (muhtemelen JIT, yöntemin ne kadar sıcak olduğunu fark ettiği için). Buggy yürütme 5 kez test()
derlenir (veya ayrıştırılır) .
Ayrıca, birlikte çalıştığı -XX:-TieredCompilation
(ki ya yorumladığını veya kullanımları C2
) ya sahip -Xbatch
(paralel ana iş parçacığı çalıştırmak için derleme zorlar ki, yerine), çıkış olduğunu garanti böylece ve bir sürü malzeme dışarı 30000 yineleme baskılar ile C2
derleyici görünüyor suçlu olmak. Bu, çıktıyı -XX:TieredStopAtLevel=1
devre dışı bırakan C2
ve üretmeyen (ile 4. seviyede durmak hatayı tekrar gösterir) ile çalışarak onaylanır .
Doğru yürütmede, yöntem önce Seviye 3 derlemesi ile, daha sonra Seviye 4 ile derlenir .
Buggy yürütmesinde, önceki derlemeler çıkarılır ( made non entrant
) ve yine Düzey 3'te derlenir (yani C1
önceki bağlantıya bakın).
Bu yüzden kesinlikle bir hata C2
, ancak Seviye 3 derlemesine geri dönmesinin gerçeği etkilediğinden emin değilim (ve neden hala 3. seviyeye geri dönüyor, hala birçok belirsizlik var).
Sen tavşan deliğinden daha derinlere inmeye için aşağıdaki satırla montaj kodu oluşturabilirsiniz (ayrıca bkz bu baskı düzeneği etkinleştirmek için).
java -XX:+PrintCompilation -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly LoopOutPut > broken.asm
Bu noktada beceriler tükenmeye başlıyorum, buggy davranışı önceki derlenmiş sürümler atıldığında sergilenmeye başlıyor, ancak 90'lardan ne kadar az montaj becerisine sahibim, bu yüzden benden daha akıllı birine izin vereceğim buradan.
Bu kod zaten OP'ye başka biri tarafından sunulduğundan ve C2 kodunun hatasız olmadığı için bu konuda zaten bir hata raporu olması muhtemeldir . Umarım bu analiz bana olduğu kadar başkalarına da bilgilendirici olmuştur.
Saygıdeğer apangin yorumlarda belirtildiği gibi, bu son zamanlarda yapılan bir hatadır . İlgilenen ve yardımcı olan herkese çok yükümlü :)