Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Java8〜16におけるバイトコード生成の変化 / Changes of Bytecode G...

Java8〜16におけるバイトコード生成の変化 / Changes of Bytecode Generation from Java 8 to 16

JJUG CCC 2021 Springで発表したものです。Java8〜16においてOpenJDKが生成するバイトコードにどのような変化があったのか、静的解析ツール開発者の視点から紹介します。
https://fortee.jp/jjug-ccc-2021-spring/proposal/288ac3a0-9683-4ed5-89e9-fbe1a61ca5c8

Kengo TODA

May 23, 2021
Tweet

More Decks by Kengo TODA

Other Decks in Technology

Transcript

  1. Java 9 警戒していたほど 大変ではなかった jigsaw対応 • JEP 220: Modular Run-Time

    Images • JEP 238: Multi-Release JAR Files • JEP 213: Milling Project Coin 5
  2. Java 11 JLSに沿うように実装を 修正したら、様々なツールが 壊れた回 11 • A change around

    try-with-resources • JEP 181: Nest-Based Access Control • JEP 336: Deprecate the Pack200 Tools and API
  3. Dead code in $closeResource()? Java 9で導入された手法にもデッドコードがあるということでより効率的な方法をJava 11 b07で導入したところ、JaCoCoとSpotBugsで誤作動が発生。JaCoCoは修正済みだが SpotBugsは4.2.2時点で一部のみ対応。 SpotBugsが誤検知した内容は「nullじゃないとわかっているローカル変数のnullチェック

    をしている」。Eclipseのコンパイラ(ecj)では問題なし。 バイトコードを見てみると、確かにインスタンスのメソッドを利用したあとで、そのインスタン スがnullかどうか確認している。javacのバグでは? 12
  4. try-with-resources構文のバイトコード変化まとめ 15 • Java 7でtry-with-resources構文が導入される。 • Java 9で、デッドコードを減らしコードの重複を省く目的で、 $closeResource() メソッ

    ドが自動的に生成されるようになる。メソッドをまたいだ解析が必要になる。 • Java 11 b7で、デッドコードを減らす目的で $closeResource() メソッドが削除され る。無意味なnullチェックコードが含まれているが、JLSに必要と記載されているので 問題ない。
  5. そのほかのJava 11の変更 • JEP 181: Nest-Based Access Controlについてはじゅくちょー氏のブログに詳しい ので割愛。SpotBugsでの修正はこちら。 •

    JEP 336: Deprecate the Pack200 Tools and APIはバイトコードの変化ではない が、JaCoCoに影響を及ぼしたということでここに載せておきます。 16
  6. Pattern Matching:ことの発端 Number number = 1f; if (number instanceof Float

    f) { System.out.println( "number is a float: " + f ); } 一見問題なさそうなコードだが、 SpotBugsではロー カル変数を自分自身と比較している という警告が出 る。 JaCoCoではカバレッジの異常として報告される。 Eclipseのコンパイラ(ecj)では問題なし。 18
  7. どのようなバイトコードか 7: aload_2 8: instanceof #8 // class java/lang/Float 11:

    ifeq ... 14: aload_2 15: checkcast #8 // class java/lang/Float 18: dup 19: astore_1 20: aload_2 21: checkcast #8 // class java/lang/Float 24: if_acmpne ... jdk-14.0.2+12同梱のjavacで確認。 確かにaload_2で取り出した同じローカル変数を if_acmpneで比較している。 19
  8. Java15で変化した内容 11: ifeq ... 14: aload_2 15: checkcast #8 //

    class java/lang/Float - 18: dup - 19: astore_1 - 20: aload_2 - 21: checkcast #8 // class java/lang/Float - 24: if_acmpne ... + 18: astore_1 余計な比較が無くなり、非常にシンプルなバイト コードに。🎉 素早いリリースサイクルとオープンな開発体制がプ ラスに働いた模範的な事例ではないでしょうか? 24
  9. Microbenchmark in my local (https://git.io/JODNQ) IntelliJ IDEAの生成したhashCode()実装と、 record標準のinvokedynamicを利用した hashCode()実装との単純な性能比較。横軸は Recordに含まれるフィールドの数と種類。縦軸は秒

    間実行回数で、高い方が速い。 invokedynamicを利用したhashCode()実装の方が 若干遅い。primitiveだと特に差が顕著。 今は遅いとはいえ、ObjectMethodsクラスが生成す るロジックはJavaの成長とともに成長するので、強 い理由がなければinvokedynamicを利用した hashCode()実装で良いのでは。 29
  10. まとめ Java 9, 11, 14, 16にわたって 様々な変更を見てきた • OpenJDK is

    Open • 14に問題があったら15で直せば いい • デッドコード削除やIndy活用など 33
  11. 付録:Attributesは増えたか? 増えた • JVMS 4.7.25. The Module Attribute • JVMS

    4.7.26. The ModulePackages Attribute • JVMS 4.7.27. The ModuleMainClass Attribute • JVMS 4.7.28. The NestHost Attribute • JVMS 4.7.29. The NestMembers Attribute • JVMS 4.7.30. The Record Attribute 37