SlideShare a Scribd company logo
3
Bytecode DSL
& Indy
& Brainf*ck
G*Workshop Z 2013/09/20
上原潤二(NTTソフトウェア株式会社)
13年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
自己紹介
上原潤二(@uehaj)
NTTソフトウェア(株)Grails推進室
JGGUG(日本Grails/Groovyユーザグループ)運営委員
書籍:
プログラミングGROOVY(技術評論社)
Grails徹底入門(翔泳社)
ブログ「Grな日々」
GroovyServ, LispBuilder, GVM(JVM
written in Groovy)開発者
2
13年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
今日の内容
Indyの基礎
Bytecode DSL
Brainf*ckを実装してみた
G*Magazine Vol.7の宣伝
3
13年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
テーマ:Indyで遊びたい
Indy: Java VM上での動的言語の実行を効
率化することを目的とした一連の機能拡張
(JSR 292)
気軽でない
ASM面倒くさい
ByteCode DSLを使おう!
4
13年9月20日金曜日
35
Bytecode DSL
13年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
ByteCode DSL
Groovyの内部DSLで実現されたJava
バイトコードのアセンブラ
ASMのラッパー
Indy対応! (重要)
6
@groovyx.ast.bytecode.Bytecode
int	
  fib(int	
  i)	
  {
	
  	
  	
  	
  iload	
  1
	
  	
  	
  	
  iconst_2
	
  	
  	
  	
  if_icmpge	
  l1
	
  	
  	
  	
  iload	
  1
	
  	
  	
  	
  _goto	
  l2
	
  	
  	
  l1
	
  	
  	
  	
  aload	
  0
	
  	
  	
  	
  iload	
  1
	
  	
  	
  	
  iconst_2
	
  	
  	
  	
  isub
	
  	
  	
  	
  invokevirtual	
  '.fib',	
  '(I)I'
	
  	
  	
  	
  aload	
  0
	
  	
  	
  	
  iload	
  1
	
  	
  	
  	
  iconst_1
	
  	
  	
  	
  isub
	
  	
  	
  	
  invokevirtual	
  '.fib'	
  ,'(I)I'
	
  	
  	
  	
  iadd
	
  	
  	
  l2
	
  	
  	
  	
  ireturn
}
13年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
BytecodeDSL
以下で@Grab可
groovyによる実行
7
@GrabResolver(name="maven-­‐repox",	
  root	
  =	
  "https://
raw.github.com/uehaj/maven-­‐repo/gh-­‐pages/snapshot")
@Grab('groovyx.ast.bytecode:groovy-­‐bytecode-­‐ast:0.2.0-­‐
separate-­‐asm')
import	
  groovyx.ast.bytecode.Bytecode
$ groovy fib.groovy
102334155
13年9月20日金曜日
3
BytecodeDSLでHello Indy!
8
@GrabResolver(name="maven-­‐repo",	
  root="https://raw.github.com/uehaj/maven-­‐repo/gh-­‐pages/snapshot")
@Grab("groovyx.ast.bytecode:groovy-­‐bytecode-­‐ast:0.2.0-­‐separate-­‐asm")
import	
  groovyx.ast.bytecode.Bytecode
import	
  java.lang.invoke.*
import	
  java.lang.invoke.MethodHandles.Lookup
import	
  static	
  org.objectweb.asm.Opcodes.H_INVOKESTATIC
class	
  HelloIndy	
  {
	
  	
  	
  	
  public	
  static	
  CallSite	
  bootstrap(Lookup	
  lookup,	
  String	
  
methodName,	
  MethodType	
  type)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  assert	
  methodName	
  ==	
  'xx'
	
  	
  	
  	
  	
  	
  	
  	
  MethodHandle	
  mh	
  =	
  lookup.findVirtual(java.io.PrintStream,	
  
"println",	
  MethodType.methodType(void,[String]))
	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  ConstantCallSite(mh)
	
  	
  	
  	
  }
	
  	
  	
  	
  @Bytecode
	
  	
  	
  	
  static	
  main(args)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  getstatic	
  	
  	
  	
  	
  'java/lang/System.out','Ljava/io/PrintStream;'
	
  	
  	
  	
  	
  	
  	
  	
  ldc	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'Hello	
  Indy'
	
  	
  	
  	
  	
  	
  	
  	
  invokedynamic	
  'xx',	
  '(Ljava/io/PrintStream;Ljava/lang/
String;)V',	
  [H_INVOKESTATIC,	
  'HelloIndy','bootstrap',	
  [CallSite,	
  
Lookup,	
  String,	
  MethodType]]
	
  	
  	
  	
  	
  	
  	
  	
  vreturn
	
  	
  	
  	
  }
}
13年9月20日金曜日
3
実行
9
$ groovy -Dgroovy.target.bytecode=1.7 HelloIndy.groovy
Hello Indy
13年9月20日金曜日
310
Indy!!
13年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
Indy
Indyの動作は知ってますよね??
11
13年9月20日金曜日
3
従来のinvoke系命令のイメージ
バイトコード命令
バイトコード命令
Invokestatic/virtual/interface命令
メソッド
バイトコード命令
return命令
バイトコード命令
(1)Java VMによって解決さ
れて呼び出される
:
13年9月20日金曜日
3
invokedynamic命令のイメージ
バイトコード命令
バイトコード命令
Invokedynamic命令
メソッド
バイトコード命令
return命令
バイトコード命令
(1)Java以外の言語処理系
ランタイムによって解決
される
:
13年9月20日金曜日
3
invokedynamicのイメージ(2)
バイトコード命令
バイトコード命令
Invokedynamic命令
バイトコード命令
:
?
(2)クラスファイル上はブートスト
ラップメソッドというメソッドに
紐付けられている
Bootstarpメソッド
バイトコード命令
return命令
(1)クラスロード時には未定
13年9月20日金曜日
3
invokedynamicのイメージ(3)
バイトコード命令
バイトコード命令
Invokedynamic命令
バイトコード命令
:
呼び出し先決定メソッド
バイトコード命令
return命令
BootStrapメソッドを指すMH
(2)BootstrapメソッドはCallSiteオブジ
ェクトを返す
CallSite
呼び出し先メソッ
ドを参照するMH
(1)BootStrapメソッドを示す
MH(MethodHandle)で表現されている
13年9月20日金曜日
3
invokedynamicのイメージ(5)
バイトコード命令
バイトコード命令
Invokedynamic命令
バイトコード命令
:
CallSite
(1)invokedyamic命令にCallSiteが紐付
けられる
この結び付きはJVMの実行を通じて以後不可逆、不変なので、以下のようにinvokedynamic
がCallSiteに置き変わると考えても良いかも知れない。 (※CallSiteオブジェクトは複数の
invokedynamic命令でシェアされ得る点でこのイメージは正確ではない。)
バイトコード命令
バイトコード命令
CallSite
バイトコード命令
呼び出し先メソッドを参照するMH
呼び出し先メソッ
ドを参照するMH
13年9月20日金曜日
3
CallSite 呼び出し先メソッドを参照するMH
invokedynamicの最終形
バイトコード命令
バイトコード命令
メソッド
バイトコード命令
return命令
バイトコード命令
MHによるメソッド参照
:
13年9月20日金曜日
3
CallSite 呼び出し先メソッドを参照するMH
(Mutable¦Volatile)CallSite
バイトコード命令
バイトコード命令
バイトコード命令
:
(1)
メソッド1
メソッド2
×
Groovyで言うところのmetaClassの変更のタイミングで実際のメソッドの差し替え
を行なうことができるCallSiteもある。(これがキモ)
結局、「ポインタを解した呼び出し先アドレスの間接参照」を
オブジェクト指向的に、型安全に行なっている。
13年9月20日金曜日
3
Indyって結局何?
メソッド呼び出し先を間接参照を使って書き換える
しくみ
他言語メソッドの呼び出しが想定ユースケースだが技術
的にはそれに限らない(Java 8 Lambdaとか)
他言語だから、環境を持ち回したり引数をラップ・アン
ラップする処理が必要になる場合がある
メソッド呼び出しに伴なう前後処理(MHに対する高階
操作:後述)をJVM管理下で構成・実行するしくみがあ
ることがメリット
➡最適化(インライン展開)期待
➡そういう前後処理が不要な場合、速度メリットがあるかは??
※ 「MH呼び出しは速い」は都市伝説
19
13年9月20日金曜日
3
MHに対する高階操作
20
13年9月20日金曜日
321
Brainf*ck
13年9月20日金曜日
3
Brainf*ckをindyで実装してみた :
構成図
22
Brainf*ckソース
>+++++++++[<++++
++++>-]<.>+++++++
[<++++>-]<+.++++++
+..+++.[-]>++++++++
[<++++>-]<.>++++++
+++++[<+++++>-]<.>
++++++++[<+++>-]<.
+++.------.--------.[-]>+
+++++++[<++++>-]<
+.[-]++++++++++.
compile.
groovy
https://gist.github.com/uehaj/6614136
https://gist.github.com/uehaj/6614447
Brainf*ckコンパイラ
生成コード(Bytecode
DSL/indyを使用)
groovy
groovy
“hello
world”
JVM
JVM(Java7)
a.groovy
13年9月20日金曜日
3
Brainf*ckとindy
静的言語だからIndyの意味ない
(MutableCallSite出番なし)
invokedynamicの引数文字列から
一連のMHを連接させたものを
BootStrapメソッドで生成してみる
23
invokedynamic 'dummy', '()V', [H_INVOKESTATIC, 'Brainfuck',
'bootstrap', [CallSite, Lookup, String, MethodType,
String]], '>++++++++'
13年9月20日金曜日
3
MHを連接
MethodHandles#filterReturnValu
e(MH target, MH filter)
「filter(target())」を表現するMHを返す。
targetの戻り値の型がvoid、
filterの引数が無しであれば、単にtarget,
filterの順にMHを呼び出す
filterReternValueの結果を
filterReturnValueに与えることで任意個数
のMHを逐次実行できる
24
13年9月20日金曜日
3
CallSite 呼び出し先メソッドを参照するMH
MHを連接
バイトコード命令
バイトコード命令
メソッド(+)
バイトコード命令
return命令
バイトコード命令
:
filterReturlValueの結果得られ
る、2つのMHを呼ぶMH
filterReturlValueの結果得られ
る、2つのMHを呼ぶMH
メソッド(+)
バイトコード命令
return命令
メソッド(>)
バイトコード命令
return命令
13年9月20日金曜日
3
生成コード
26
	
  static	
  void	
  main(String[]	
  args)	
  throws	
  Exception	
  {
	
  	
  	
  	
  	
  	
  	
  	
  //	
  Brainfuckからコンバートされたコード
	
  	
  	
  	
  	
  	
  	
  	
  invokedynamic	
  'dummy',	
  '()V',	
  ...	
  '>+++++++++'
	
  	
  	
  	
  	
  	
  	
  	
  _GOTO	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  tmp1
	
  	
  	
  	
  lab1:
	
  	
  	
  	
  	
  	
  	
  	
  invokedynamic	
  'dummy',	
  '()V',	
  ...	
  '<++++++++>-­‐'
	
  	
  	
  	
  tmp1:
	
  	
  	
  	
  	
  	
  	
  	
  getstatic	
  	
  	
  	
  	
  '.data','[B'
	
  	
  	
  	
  	
  	
  	
  	
  getstatic	
  	
  	
  	
  	
  '.dp','I'
	
  	
  	
  	
  	
  	
  	
  	
  baload	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  ifne	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  lab1
	
  	
  	
  	
  	
  	
  	
  	
  invokedynamic	
  'dummy',	
  '()V',	
  ...	
  '<.>+++++++'
	
  	
  	
  	
  	
  	
  	
  	
  _GOTO	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  tmp2
	
  	
  	
  	
  lab2:
	
  	
  	
  	
  	
  	
  	
  	
  invokedynamic	
  'dummy',	
  '()V',	
  ....	
  '<++++>-­‐'
	
  	
  	
  	
  tmp2:
	
  	
  	
  	
  	
  	
  	
  	
  getstatic	
  	
  	
  	
  	
  '.data','[B'
	
  	
  	
  	
  	
  	
  	
  	
  getstatic	
  	
  	
  	
  	
  '.dp','I'
	
  	
  	
  	
  	
  	
  	
  	
  baload	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  ifne	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  lab2
	
  	
  	
  	
  	
  	
  	
  	
  invokedynamic	
  'dummy',	
  '()V',	
  ....	
  '<+.+++++++..+
++.'
	
  	
  	
  	
  	
  	
  	
  	
  _GOTO	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  tmp3
	
  	
  	
  	
  lab3:
:
>+++++++++
[
<++++++++>-
]
<.>+++++++
[
<++++>-
]
<+.+++++++..+++.
13年9月20日金曜日
3
実行
27
% cat hello.bf
>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.
[-]>++++++++[<++++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+
++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+.[-]+++++
+++++.
% groovy compile.groovy hello.bf > a.groovy
% groovy -Dgroovy.target.bytecode=1.7 a.groovy
Hello World!
13年9月20日金曜日
3
まとめ
Indyは面白い
G*Magazine Vol7乞う期待!
28
13年9月20日金曜日

More Related Content

Indy(Invokedynamic) and Bytecode DSL and Brainf*ck