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.

Var handles jjug_ccc_spring_2018

1,128 views

Published on

Java 9 から Variable Handles が導入されました。利用価値の高い機能ではありますが、多くの方々が活用を始めるには至っていないと思われます。Variable Handleは何のためにあるのか、そしてどう使用したらいいのかを解説します。

Published in: Software
  • Be the first to comment

  • Be the first to like this

Var handles jjug_ccc_spring_2018

  1. 1. VarHandles David Buck 日本オラクル株式会社
  2. 2. • JVM Sustaining Engineer • OpenJDK 8 Update Project Maintainer • JavaOne Rock Star • Co-author of Oracle WebLogic Server 11g 構築・運用ガイド • @DavidBuckJP • https://blogs.oracle.com/buc k/ Who am I? バック デイビッド(左)
  3. 3. 今日触れる内容 • Java のメモリモデル • MethodHandle • sun.misc.Unsafe • VarHandle • ゴキブリホイホイ
  4. 4. Project Valhalla Emil Doepler - Doepler, Emil. ca. 1905. Walhall, die Götterwelt der Germanen. Martin Oldenbourg, Berlin. Photographed by Haukurth cropped by Bloodofox, Public Domain
  5. 5. Project Loom 織機 By en:Yanagawa Shigenobu - This image is available from the United States Library of Congress's Prints and Photographs division under the digital ID jpd.00091. パブリック・ドメイン, https://commons.wikimedia.org/w/index.php?curid=3505580
  6. 6. Project Panama パナマ運河 By US DOT - https://www.transportation.gov/fastlane/expanded-canal-means-an-expanded-economy, Public Domain, https://commons.wikimedia.org/w/index.php?curid=54989250
  7. 7. Project Valhalla Emil Doepler - Doepler, Emil. ca. 1905. Walhall, die Götterwelt der Germanen. Martin Oldenbourg, Berlin. Photographed by Haukurth cropped by Bloodofox, Public Domain
  8. 8. Project Valhalla Valhalla == VALue types
  9. 9. Project Valhalla • Value Types (値型) • Generic Specialization (ジェネリックの特殊化) • VarHandles (JDK 9 でリリースされた)
  10. 10. Project Valhalla • Value Types (値型) • Generic Specialization (ジェネリックの特殊化) • VarHandles (JDK 9 でリリースされた)
  11. 11. Project Valhalla • Value Types (値型) • Generic Specialization (ジェネリックの特殊化) • VarHandles (JDK 9 でリリースされた)
  12. 12. 余談その1(マイコン) By Cbmeeks / processed by Pixel8 - Original uploader was Cbmeeks at en.wikipedia, CC 表示-継承 3.0, https://commons.wikimedia.org/w/index.php?curid=3672924
  13. 13. 昔の BASIC 言語の魔法のキーワード • PEEK • 任意のメモリアドレスの値を取得する • POKE • 任意のメモリアドレスに任意の値を格納する
  14. 14. ???
  15. 15. sun.misc.Unsafe • JVM の内部機能を直接に呼び出す内部のインタフェース • Java SE ライブラリを実現するためのもの • Sun (Oracle) 以外の利用は想定外 • いろいろな機能 • 初期化せずに Heap メモリを取得 • PEEK / POKE • Java MM より細かいメモリ操作
  16. 16. sun.misc.Unsafe • Reflection • Serialization • NIO • java.util.concurrent • 暗号化・複合化 • BigDecimal / BigInteger • Java2D • CPU の使用率 (JMX) 内部利用
  17. 17. sun.misc.Unsafe • JVM の内部機能を直接に呼び出す内部のインタフェース • Java SE ライブラリを実現するためのもの • Sun (Oracle) 以外の利用は想定外 • いろいろな機能 • 初期化せずに Heap メモリを取得 • PEEK / POKE • Java MM より細かいメモリ操作
  18. 18. sun.misc.Unsafe • JVM の内部機能を直接に呼び出す内部のインタフェース • Java SE ライブラリを実現するためのもの • Sun (Oracle) 以外の利用は想定外 • いろいろな機能 • 初期化せずに Heap メモリを取得 • PEEK / POKE • Java MM より細かいメモリ操作
  19. 19. private static final Unsafe theUnsafe = new Unsafe(); public static Unsafe getUnsafe() { Class cc = sun.reflect.Reflection.getCallerClass(2); if (cc.getClassLoader() != null) throw new SecurityException("Unsafe"); return theUnsafe; }
  20. 20. Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); unsafe = (Unsafe) f.get(null);
  21. 21. Unsafe Demo!
  22. 22. sun.misc.Unsafe By Jared Tarbell - Flickr: sky puzzle, CC BY 2.0, https://commons.wikimedia.org/w/index.php?curid=31953973 JDK 9 – Project Jigsaw
  23. 23. sun.misc.Unsafe • メモリ管理 • メモリレイアウト • メモリアクセス • Valhalla • Panama • Arrays 2.0
  24. 24. sun.misc.Unsafe JVM / ネイティブを跨る処理 • Panama • Foreign Function Interface
  25. 25. sun.misc.Unsafe 細かいメモリモデル Variable Handles
  26. 26. sun.misc.Unsafe • JVM の内部機能を直接に呼び出す内部のインタフェース • Java SE ライブラリを実現するためのもの • Sun (Oracle) 以外の利用は想定外 • いろいろな機能 • 初期化せずに Heap メモリを取得 • PEEK / POKE • Java MM より細かいメモリ操作
  27. 27. sun.misc.Unsafe • JVM の内部機能を直接に呼び出す内部のインタフェース • Java SE ライブラリを実現するためのもの • Sun (Oracle) 以外の利用は想定外 • いろいろな機能 • 初期化せずに Heap メモリを取得 • PEEK / POKE • Java MM より細かいメモリ操作
  28. 28. JEP 193: Variable Handles • C11/C++11 のメモリモデルに合わせる • j.u.c の atomic のような変数の変更も出来る • sun.misc.Unsafe のメモリアクセスの API をリプレース
  29. 29. JEP 193: Variable Handles • C11/C++11 のメモリモデルに合わせる • j.u.c の atomic のような変数の変更も出来る • sun.misc.Unsafe のメモリアクセスの API をリプレース
  30. 30. C++ メモリモデル • C++11 で導入された • Atomic メモリアクセス (std::atomic) • Happens-before (std::memory_order) typedef enum memory_order { memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst } memory_order;
  31. 31. C++ メモリモデル • 従来の Java のメモリモデルより細かい • データの単位ではなく • アクセスの単位で決める • 他の言語などで導入されれている傾向がある
  32. 32. JEP 193: Variable Handles • C11/C++11 のメモリモデルに合わせる • j.u.c の atomic のような変数の変更も出来る • sun.misc.Unsafe のメモリアクセスの API をリプレース
  33. 33. class Counter { private int c = 0; public void increment() { c++; } public void decrement() { c--; } public int value() { return c; } }
  34. 34. volatile int c = 0; void increment() { c++; }
  35. 35. volatile int c = 0; void increment() { c++; } reg = [id] reg++ [id] = reg
  36. 36. スレッド1 reg = [id] // reg==3 reg++ // reg==4 [id] = reg // id==4 スレッド2 reg = [id] // reg==3 reg++ // reg==4 [id] = reg // id==4
  37. 37. class Counter { private int c = 0; public void increment() { c++; } public void decrement() { c--; } public int value() { return c; } }
  38. 38. class SynchronizedCounter { private int c = 0; public synchronized void increment() { c++; } public synchronized void decrement() { c--; } public synchronized int value() { return c; } }
  39. 39. 余談その2 ゴキブリホイホイ obj.a = 1; obj.b = 2; synchronized(this) { obj.c = 3; obj.d = 4; } obj.e = 5; obj.f = 6;
  40. 40. 余談その2 ゴキブリホイホイ obj.a = 1; obj.b = 2; synchronized(this) { obj.c = 3; obj.d = 4; } obj.e = 5; obj.f = 6; obj.a = 1; synchronized(this) { obj.b = 2; obj.c = 3; obj.d = 4; obj.e= 5; } obj.f=6;
  41. 41. 余談その2 ゴキブリホイホイ obj.a = 1; obj.b = 2; synchronized(this) { obj.c = 3; obj.d = 4; } obj.e = 5; obj.f = 6; obj.a = 1; synchronized(this) { obj.b = 2; obj.c = 3; obj.d = 4; obj.e= 5; } obj.f=6;
  42. 42. import java.util.concurrent.atomic.AtomicInteger; class AtomicCounter { private AtomicInteger c = new AtomicInteger(0); public void increment() { c.incrementAndGet(); } public void decrement() { c.decrementAndGet(); } public int value() { return c.get(); } }
  43. 43. Field データ Class ポインター ロック情報 hashcode ・その他
  44. 44. class Counter { private int c = 0; public void increment() { c++; } public void decrement() { c--; } public int value() { return c; } }
  45. 45. Counter c Class ポインター ロック情報 hashcode ・その他
  46. 46. import java.util.concurrent.atomic.AtomicInteger; class AtomicCounter { private AtomicInteger c = new AtomicInteger(0); public void increment() { c.incrementAndGet(); } public void decrement() { c.decrementAndGet(); } public int value() { return c.get(); } }
  47. 47. AtomicCounter c Class ポインター ロック情報 hashcode ・その他 value Class ポインター ロック情報 hashcode ・その他 AtomicCounter AtomicInteger
  48. 48. class BadCounter { private int c = 0; public void increment() { unsafe.getAndAddInt(this, valueOffset, 1); } public void decrement() { unsafe.getAndAddInt(this, valueOffset, -1); } public int value() { return c; } }
  49. 49. static { // get unsafe try { valueOffset = unsafe.objectFieldOffset (BadCounter.class.getDeclaredField(“c")); } catch (Exception ex) { throw new Error(ex); } }
  50. 50. static { // get unsafe try { valueOffset = unsafe.objectFieldOffset (BadCounter.class.getDeclaredField(“c")); } catch (Exception ex) { throw new Error(ex); } }
  51. 51. VarHandle 登場!
  52. 52. VarHandle を理解するには
  53. 53. VarHandle を理解するには MethodHandle の知識は不可欠!
  54. 54. Da Vinci Machine Project • Java 以外の言語を使っても、JVM はいい仮想マシン • パフォーマンスがいい • ポータビリティー(移植性) • セキュリティ(バイトコード) • 既存のフレームワークやライブラリ By Web Gallery of Art: Image Info about artwork, Public Domain, https://commons.wikimedia.org/w/index.php?curid=15497207
  55. 55. Java Code 言語ランタイムとは 57 JVM OS Java Class Library JRuby Runtime JVM OS Java Class Library Ruby Code
  56. 56. MethodHandle 58 int foo()Method Handle
  57. 57. 59 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
  58. 58. 60 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
  59. 59. 61 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()
  60. 60. 62 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
  61. 61. 63 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
  62. 62. 64 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 int bar()
  63. 63. 65 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 int bar()Method Handle
  64. 64. MethodHandle • 関数ポインター
  65. 65. MethodHandle • 関数ポインター • Reflection API の代わりに利用出来る場合がある • Field のアクセス(読み込み・書き込み) • その他 • 例外を投げる • 定数を返す • など
  66. 66. MethodHandle の魅力 • 生成時のアクセスチェック • setuid のような動き • シグネチャ・ポリモーフィズム
  67. 67. シグネチャ・ポリモーフィズム • すべてオブジェクトで渡す必要はない • JVM と javac によって特別な扱い • MethodHandle • VarHandle
  68. 68. public class Receiver { private volatile String vfield; private static final MethodHandle MH_GETTER_V_FIELD; private static final MethodHandle MH_SETTER_V_FIELD;
  69. 69. static { try { MH_GETTER_V_FIELD = MethodHandles.lookup().findGetter(Receiver.class, "vfield", String.class); MH_SETTER_V_FIELD = MethodHandles.lookup().findSetter(Receiver.class, "vfield", String.class); } catch (Exception e) { throw new Error(e); } } }
  70. 70. public void setValue(String s) { try { MH_SETTER_V_FIELD.invokeExact(this, s); } catch (Throwable t) { throw new RuntimeException(t); } }
  71. 71. public String getValue() { try { return (String) MH_GETTER_V_FIELD.invokeExact(this); } catch (Throwable t) { throw new RuntimeException(t); } } } // class Receiver
  72. 72. public void setValue(java.lang.String); descriptor: (Ljava/lang/String;)V flags: ACC_PUBLIC Code: stack=3, locals=3, args_size=2 0: getstatic #2 // Field MH_SETTER_V_FIELD:Ljava/lang/invoke/MethodHandle; 3: aload_0 4: aload_1 5: invokevirtual #3 // Method java/lang/invoke/MethodHandle.invokeExact:(LReceiver;Ljava/lang/String;)V 8: goto 21 11: astore_2 12: new #5 // class java/lang/RuntimeException 15: dup 16: aload_2 17: invokespecial #6 // Method java/lang/RuntimeException."<init>":(Ljava/lang/Throwable;)V 20: athrow 21: return
  73. 73. public void setValue(java.lang.String); descriptor: (Ljava/lang/String;)V flags: ACC_PUBLIC Code: stack=3, locals=3, args_size=2 0: getstatic #2 // Field MH_SETTER_V_FIELD:Ljava/lang/invoke/MethodHandle; 3: aload_0 4: aload_1 5: invokevirtual #3 // Method java/lang/invoke/MethodHandle.invokeExact:(LReceiver;Ljava/lang/String;)V 8: goto 21 11: astore_2 12: new #5 // class java/lang/RuntimeException 15: dup 16: aload_2 17: invokespecial #6 // Method java/lang/RuntimeException."<init>":(Ljava/lang/Throwable;)V 20: athrow 21: return
  74. 74. public java.lang.String getValue(); descriptor: ()Ljava/lang/String; flags: ACC_PUBLIC Code: stack=3, locals=2, args_size=1 0: getstatic #7 // Field MH_GETTER_V_FIELD:Ljava/lang/invoke/MethodHandle; 3: aload_0 4: invokevirtual #8 // Method java/lang/invoke/MethodHandle.invokeExact:(LReceiver;)Ljava/lang/String; 7: areturn 8: astore_1 9: new #5 // class java/lang/RuntimeException 12: dup 13: aload_1 14: invokespecial #6 // Method java/lang/RuntimeException."<init>":(Ljava/lang/Throwable;)V 17: athrow
  75. 75. public java.lang.String getValue(); descriptor: ()Ljava/lang/String; flags: ACC_PUBLIC Code: stack=3, locals=2, args_size=1 0: getstatic #7 // Field MH_GETTER_V_FIELD:Ljava/lang/invoke/MethodHandle; 3: aload_0 4: invokevirtual #8 // Method java/lang/invoke/MethodHandle.invokeExact:(LReceiver;)Ljava/lang/String; 7: areturn 8: astore_1 9: new #5 // class java/lang/RuntimeException 12: dup 13: aload_1 14: invokespecial #6 // Method java/lang/RuntimeException."<init>":(Ljava/lang/Throwable;)V 17: athrow
  76. 76. class VHCounter { private int c = 0; public void increment() { for (;;) { int current = get(); int next = current + 1; if (VH.compareAndSet(this, current, next)) return; } }
  77. 77. public void decrement() { for (;;) { int current = get(); int next = current - 1; if (VH.compareAndSet(this, current, next)) return; } }
  78. 78. public int get() { return (int)VH.get(this); }
  79. 79. static { try { MethodHandles.Lookup l = MethodHandles.lookup(); VALUE = l.findVarHandle(VHCounter.class, “c", Object.class); } catch (ReflectiveOperationException e) { throw new ExceptionInInitializerError(e); } } } // VHCounter class
  80. 80. JEP 193: Variable Handles • C11/C++11 のメモリモデルに合わせる • j.u.c の atomic のような変数の変更も出来る • sun.misc.Unsafe のメモリアクセスの API をリプレース
  81. 81. int data = 0; boolean ready = false; void hoge3() { while (!ready) {}; assert data == 42; } void hoge4() { data = 42; ready = true; }
  82. 82. int data = 0; boolean ready = false; void hoge3() { while (!ready) {}; assert data == 42; } void hoge4() { data = 42; ready = true; }
  83. 83. JSR-133 の volatile void hoge4() { data = 42; ready = true; } void hoge3() { while (!ready) {}; assert data == 42; } volatile boolean ready = false;
  84. 84. VarHandle や Unsafe だと • 必要な時だけ volatile としてアクセスすることが出来る
  85. 85. 要は • VarHandle は普段利用されない(Unsafe のように) • MethodHandle はかなり役に立つ • sun.misc.Unsafe などの内部APIが利用出来なくなる
  86. 86. Thank You!
  87. 87. 参考 OpenJDK Project Page http://openjdk.java.net/projects/valhalla/ JEP 193: Variable Handles http://openjdk.java.net/jeps/193 VarHandle API https://docs.oracle.com/javase/10/docs/api/index.html?java/lang/invoke/VarHan dle.html JVM Language Summit http://openjdk.java.net/projects/mlvm/jvmlangsummit/

×