1 回答

TA貢獻1790條經驗 獲得超9個贊
僅比較字節碼甚至哈希的方法不會產生可靠的解決方案,事實上,對于此類問題根本沒有合理的解決方案。
我不知道,其中有多少適用于 Kotlin 編譯器,Java 編譯器不需要生成相同的字節碼,即使使用相同的版本來編譯完全相同的源代碼。
即使我們假設 Kotlin 編譯器具有出色的確定性,甚至跨版本,它也不能忽視 JVM 的演變。例如,任何編譯器都不能忽略/指令的刪除,即使在嘗試保守時也是如此。jsr
ret
但它很可能也會包含其他改進,即使不是被迫的1。
所以簡而言之,即使整個源代碼沒有改變,假設編譯后的形式必須保持不變也是不安全的。即使使用顯式確定性編譯器,我們也必須在使用更新版本重新編譯時為更改做好準備。
更糟糕的是,如果一種方法發生變化,它可能會對其他方法的編譯形式產生影響,因為只要需要常量或鏈接信息,指令就會引用常量池中的項目,并且這些索引可能會發生變化,具體取決于其他方法如何使用常量池。當訪問前 255 個池索引之一時,某些指令也有優化的形式,因此編號的更改可能需要更改指令的形式。這反過來可能對其他指令有影響,例如開關指令具有填充字節,具體取決于它們的字節代碼位置。
另一方面,如果新常量碰巧在池中與舊常量相同的位置結束,則僅在一個方法中使用的常量值的簡單更改可能根本不會影響方法的字節碼。
所以,要判斷兩個方法的代碼是否實際上相同,無法繞過指令解析并在一定程度上理解它們的含義。只比較字節或哈希是行不通的。
1 命名一些非強制性更改,類文字的編譯已更改,同樣,字符串連接從 using 更改StringBuffer
為 useStringBuilder
并再次更改為 useStringConcatFactory
,getClass()
內部null
檢查的使用更改為requireNonNull(…)
,等等。不同語言的編譯器不會必須跟隨,但沒有人愿意被落在后面……
還有一些錯誤需要修復,比如過時的指令,沒有編譯器會為了保持確定性而保留這些錯誤。
添加回答
舉報