Điều này có thể được sao chép một cách đáng tin cậy (hoặc không được sao chép, tùy thuộc vào những gì bạn muốn) với openjdk version "1.8.0_222"
(được sử dụng trong phân tích của tôi), OpenJDK 12.0.1
(theo Oleksandr Pyrohov) và OpenJDK 13 (theo Carlos Heuberger).
Tôi đã chạy mã với -XX:+PrintCompilation
đủ thời gian để có được cả hai hành vi và đây là sự khác biệt.
Triển khai lỗi (hiển thị đầu ra):
--- 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
Chạy đúng (không hiển thị):
--- 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)
Chúng ta có thể nhận thấy một sự khác biệt đáng kể. Với việc thực hiện chính xác, chúng tôi biên dịch test()
hai lần. Một lần vào đầu và một lần nữa sau đó (có lẽ vì JIT thông báo phương pháp này nóng đến mức nào). Trong thực thi lỗi test()
được biên dịch (hoặc dịch ngược) 5 lần.
Ngoài ra, chạy với -XX:-TieredCompilation
(mà là phiên dịch hoặc sử dụng C2
) hoặc với -Xbatch
(buộc phải biên dịch chạy trong luồng chính, thay vì song song), đầu ra được đảm bảo và với 30000 lần lặp in ra rất nhiều thứ, vì vậy C2
trình biên dịch dường như là thủ phạm Điều này được xác nhận bằng cách chạy với -XX:TieredStopAtLevel=1
, điều này vô hiệu hóa C2
và không tạo ra đầu ra (dừng ở mức 4 sẽ hiển thị lại lỗi).
Trong thực thi chính xác, phương pháp đầu tiên được biên dịch với biên dịch cấp 3 , sau đó với cấp độ 4.
Trong quá trình thực thi lỗi, các phần tổng hợp trước đó bị loại bỏ ( made non entrant
) và nó lại được biên dịch ở Cấp độ 3 (nghĩa là C1
xem liên kết trước đó).
Vì vậy, nó chắc chắn là một lỗi trong C2
, mặc dù tôi không chắc chắn liệu thực tế rằng việc quay lại cấp độ 3 có ảnh hưởng đến nó hay không (và tại sao nó lại quay trở lại cấp 3, vẫn còn nhiều điều không chắc chắn).
Bạn có thể tạo mã lắp ráp với dòng sau để đi sâu hơn vào lỗ thỏ (cũng xem phần này để cho phép in lắp ráp).
java -XX:+PrintCompilation -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly LoopOutPut > broken.asm
Tại thời điểm này, tôi bắt đầu cạn kiệt các kỹ năng, hành vi lỗi bắt đầu xuất hiện khi các phiên bản được biên dịch trước đó bị loại bỏ, nhưng tôi có những kỹ năng lắp ráp nhỏ nào từ những năm 90, vì vậy tôi sẽ để ai đó thông minh hơn tôi. từ đây.
Có khả năng đã có báo cáo lỗi về điều này, vì mã được người khác trình bày cho OP và vì tất cả mã C2 không có lỗi . Tôi hy vọng phân tích này đã được cung cấp thông tin cho những người khác như nó đã được với tôi.
Như apangin đáng kính đã chỉ ra trong các ý kiến, đây là một lỗi gần đây . Rất nhiều nghĩa vụ cho tất cả những người quan tâm và hữu ích :)