Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Lambda: A Peek Under The Hood [Java Day Tokyo 2015 6-3]

34 views

Published on

Java SE 8の主要な機能として、Lambda(クロージャ)とデフォルト・メソッド(従来ディフェンダー・メソッドもしくはエクステンション・メソッドと呼ばれていた)があります。クロージャを言語に追加することによってアプリケーションやライブラリに新たな表現の機会が与えられましたが、実際にはどのように実装すべきなのでしょうか。Lambdaはインナー・クラスによってシンプルでかつ文法的にコンパクトになるということは広く理解されていると思います。しかし、現実にはLambdaによる記述は、Invokedynamicを使った実装によって従来のJavaとは異なったものになっています。本セッションでLambdaについて、さらに深く理解してください。

Published in: Software
  • Be the first to comment

  • Be the first to like this

Lambda: A Peek Under The Hood [Java Day Tokyo 2015 6-3]

  1. 1. Lambda: A Peek Under The Hood 日本オラクル株式会社 Java SE サステイニング エンジニアリング バック デイビッド Java Day Tokyo 2015 2015年4月8日 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. |
  2. 2. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | • 以下の事項は、弊社の一般的な製品の方向性に関する概要を説明するものです。 また、情報提供を唯一の目的とするものであり、いかなる契約にも組み込むこ とはできません。以下の事項は、マテリアルやコード、機能を提供することを コミットメント(確約)するものではないため、購買決定を行う際の判断材料 になさらないで下さい。オラクル製品に関して記載されている機能の開発、リ リースおよび時期については、弊社の裁量により決定されます。 Oracle Confidential – 4 OracleとJavaは、Oracle Corporation 及びその子会社、関連会社の米国及びその他の国における登録商標です。 文中の社名、商品名等は各社の商標または登録商標である場合があります。
  3. 3. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 自己紹介 バック デイビッド • Java SE サステイニング エンジニアリング • JVM のバグを直す人 • 趣味:プログラミング
  4. 4. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 予定 • 背景・目標 • JSR-292 の紹介 – Invoke Dynamic – MethodHandle • ラムダ式の実装 – javac の出力 – Java SE Runtime の実装
  5. 5. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 目標 • ラムダ式に該当するバイトコードを理解する • ラムダ式のパフォーマンスの影響を把握する
  6. 6. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 寄り道 • ラムダ式の実装を理解するには – ラムダ式(Java 言語レベル) – Java バイトコード – JSR 292 (動的なメソッド呼び出し) • JSR-292分かる方は少し珍しいので、今日先にカバーします。
  7. 7. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | JSR-292 (動的なメソッド呼び出し)
  8. 8. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Da Vinci Machine Project • Java 以外の言語を使っても、JVM はいい仮想マシン – パフォーマンスがいい – ポータビリティー(移植性) – セキュリティ(バイトコード) – 既存のフレームワークやライブラリ
  9. 9. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | • JVM専用 – Scala – Clojure – Groovy – Ceylon – Fortress – Gosu – Kotlin • JVMへポートされた – JRuby – Jython – Smalltalk – Ada – Scheme – REXX – Prolog – Pascal – Common LISP JVM 言語(例)
  10. 10. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Java Code 言語ランタイムとは 12 JVM OS Java Class Library JRuby Runtime JVM OS Java Class Library Ruby Code
  11. 11. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Java 以外の言語をより使いやすくする • 継続 (continuations) • 動的型付け呼び出し • 末尾再帰 • インタフェース注入 • その他
  12. 12. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Java 以外の言語をより使いやすくする • 継続 (continuations) • ネック:動的型付け呼び出し • 末尾再帰 • インタフェース注入 • その他
  13. 13. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 従来のメソッドの呼び出し命令 • invokevirtual – インスタンスメソッド • invokeinterface – インタフェースのメソッド • invokestatic – クラスメソッド • invokespecial – その他(コンストラクタ、スーパークラス、private など)
  14. 14. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Java 言語に適切 他の言語にとっては利用出来ない場合がある
  15. 15. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ディスパッチのエミュレーション • JIT 最適化が出来ない – 特に、インラインが出来ない • エミュレーション自体のオーバーヘッドが高い
  16. 16. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | JSR-292 • Java 以外の言語の呼び出しロジックも直接サポートする • 問題: 言語によってディスパッチのロジックが異なります • 解決: ディスパッチ ロジックを固定しない
  17. 17. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | JSR-292 • java.lang.invoke API ディスパッチ ロジックを定義するため • invokedynamic バイトコード命令 invoke API で定義したロジックを利用するディスパッチ
  18. 18. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | invokedynamic • Indy (インディ)と呼ばれることが多い • 最初は Java 言語で利用される予定はなかった • java 言語に該当するものはない • 歴史的 – 初めて命令が追加された – 初めて JVM を他の言語のために変更しました
  19. 19. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | java.lang.invoke API • MethodHandle • CallSite • Bootstrap Method (BSM)
  20. 20. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | MethodHandle 22 int foo()Method Handle
  21. 21. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | MethodHandle • メソッドを指定する • 「関数ポインタ」(秘密!) • 多相シグネチャ
  22. 22. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | CallSite 24 private void doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return CS Method Handle int foo()
  23. 23. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | CallSite 25 private void doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return CS int bar() int foo()
  24. 24. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | CallSite • Indy の呼び出しを具象化する • MethodHandle を持つ
  25. 25. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Bootstrapping ステップ1 27 private void doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return
  26. 26. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Bootstrapping ステップ2 28 private void doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return BootStrap Method
  27. 27. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Bootstrapping ステップ3 29 private void doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return BootStrap Method int foo()
  28. 28. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Bootstrapping ステップ4 30 private void doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return BootStrap Method int foo() CS
  29. 29. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Bootstrapping ステップ5 31 private void doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return int foo() CS
  30. 30. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Bootstrap Method • indy 命令の一回目の実行で呼ばれる • CallSite を返す
  31. 31. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Indy のライフサイクル 1回目の実行 1. 特定の Indy 命令が始めて実行される 2. bootstrap メソッドが呼ばれ、1の indy 命令に該当するメソッドを 選ぶ 3. bootstrap メソッドがこの indy 命令に該当する CallSite を生成し、戻 す。 4. CallSite の MethodHandle が指定するメソッドへジャンプ
  32. 32. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Indy のライフサイクル 2回目からの実行 CallSite の MethodHandle が指定するメソッドへジャンプ
  33. 33. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Invalidation • 言語の runtime (JRuby, Groovy)がいつでも、CallSiteのMethodHandle を 自由に変更することが出来る • 例: – 引数のオブジェクトのタイプが違う – タイプグラフが変更された – 既にロードされたクラスのメソッドが動的にリプレースされる
  34. 34. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | JSR-292 まとめ • リンク処理は言語ランタイムに任せる • 汎用的なので、動的型付け言語ではなくても、利用出来る • CallSite を変更しない限り、2回目の呼び出しは速い
  35. 35. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ラムダ式の実装 バイトコード レベル
  36. 36. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ラムダ式の型 新しい種類の型(関数型)を追加すると。。。 • バイトコード側でどうやって型を表現するか? • 新規の関数インスタンスをどうやって生成する? • variance (変位)をどうすべきか?
  37. 37. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Variance (変位) • String instanceof Object == true • String[] instanceof Object[] == true • ArrayList<String> instanceof ArrayList<Object> == false • 関数は? • (String -> Boolean) instanceof (Object -> Boolean) == ?? 39
  38. 38. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 関数型インタフェース • 一つの Abstract メソッドしか持たないインタフェース • 別名 Single Abstract Method (SAM) インタフェース • 既存のライブラリをそのまま利用出来る • Java の開発者にとって一番自然 • 例 – Runnable – Comparator – Executor – ActionListener
  39. 39. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 関数型インタフェースのインスタンスを生成するには? 41
  40. 40. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 内部クラス Thread t = new Thread( () -> System.out.println("Hello Tokyo!") );
  41. 41. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 内部クラス Thread t = new Thread( new Runnable() { public void run() { System.out.println("Hello Tokyo!"); } } );
  42. 42. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 内部クラスの欠点 • ラムダ式ごとに一つのクラスが生成される • ラムダ式ごとに new が呼ばれる • タイプ汚染
  43. 43. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | DEMO (内部クラス) public class Worker { public void doWork(Runnable r) { r.run(); } } 45
  44. 44. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 他の選択肢 • メソッドハンドル – 多相シグネチャの型消去の問題 • dynamic proxies か MethodHandleProxy – パフォーマンスが問題 • JVM の内部API を解してクラスを作る • Wrapper Class (インタフェース毎に一つの実装クラス)
  45. 45. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 質問 ラムダ式をどうやって、バイトコードで表現し、実行する? 47
  46. 46. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 実は、2つの質問! どうやってバイトコードで表現する? どうやって実行する? 48
  47. 47. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 2つの話 • ラムダ式 ==「何をやって欲しいか」 – バイトコードの表現を固定する必要がある • 内部クラス、MethodHandle、など==「どうやって実行するか」 – ベストの答えがない – 実装を固定したくはない
  48. 48. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 解決 • "All problems in computer science can be solved by another level of indirection“ コンピュータ科学のいかなる問題も他のレベルの インダイレクションによって解決できる -David Wheeler 氏
  49. 49. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 解決 • バイトコードで実行方法を指定しないこと – 実行は Runtime に任せることが出来る – Runtime によって実装を自由に変えることが出来る – javac より JVM のほうが判断力は適切
  50. 50. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ラムダ式のレシピ • メソッドの本体(body)のバイトコード (ある場合) • 生成する関数型インタフェース (Runnable など) • 構文(lexical)スコープから取得した値 • 他のメタデータ(serializable など)
  51. 51. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ラムダ式のレシピ(メソッドの本体) String msg = "Hello Tokyo!" Thread t = new Thread( () -> System.out.println(msg) ); 53
  52. 52. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ラムダ式のレシピ(関数型インタフェース) java.lang.Runnable String msg = "Hello Tokyo!" Thread t = new Thread( () -> System.out.println(msg) ); 54
  53. 53. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ラムダ式のレシピ (取得した値) String msg = "Hello Tokyo!" Thread t = new Thread( () -> System.out.println(msg) ); 55
  54. 54. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ラムダ式のレシピ他の(メタデータ) (今回は特に無し) String msg = "Hello Tokyo!" Thread t = new Thread( () -> System.out.println(msg) ); 56
  55. 55. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | レシピを JSR-292 で表現出来る • Indy の呼び出し – 関数型インタフェースのインスタンスを戻す – Lambda Factory と呼ばれます • MethodHandle / CallSite – ラムダ式の「本体」メソッドを指す • Bootstrap method (BSM) – 上記 MethodHandle / CallSite を戻す – Lambda Factory を用意する(つくる) – ので、LambdaMetaFactory と呼ばれる
  56. 56. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ラムダの工場 • Indy の呼び出しはラムダ式を作るので「lambda factory」(ラムダ工 場)と呼ばれます。
  57. 57. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ラムダ工場を作る工場 • Lambda factory (invoke dynamic) に該当する Callsite を用意する bootstrap method は lambda meta-facotry と呼ばれます。 • java.lang.invoke.LambdaMetaFactory
  58. 58. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ラムダ式の CallSite • 動的型付けのタイプではない • Bootstrap メソッドによって生成されたら、変わらない(固定 CallSite) • 2回目の呼び出しから普通のコールと同じパフォーマンス
  59. 59. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Demo (ラムダ式) 61
  60. 60. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ラムダ式の実装 Oracle Java SE 8 の実装 62
  61. 61. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 現在の Java SE の実装 • 内部クラスを生成する • ASM を利用する • 構文スコープの値を取得しない場合、singleton を利用する
  62. 62. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 裏を覗いてみよう • jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java • 下記のシステムプロパティで生成されたクラスをダンプすることが 出来る。 jdk.internal.lambda.dumpProxyClasses
  63. 63. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | まとめ • バイトコードレベルでラムダ式のレシピだけがある。 • 実現方法は Java のランタイムに依存します。 • パフォーマンス 現在の実装 >= 内部クラス
  64. 64. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Thank You!
  65. 65. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | オマケ David Wheeler 氏曰く • All problems in computer science can be solved by another level of indirection, except of course for the problem of too many indirections. コンピュータ科学のいかなる問題も他のレベルのインダイレクショ ンによって解決できる。ただし、あまりに間接参照のレイヤーが重 なり過ぎるという問題だけは解決できない。 • Compatibility means deliberately repeating other people's mistakes. 互換性は他の人々の間違いを意図的に繰り返すことを意味する
  66. 66. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Safe Harbor Statement The preceding is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle. 68
  67. 67. Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 69

×