真intermediate languageのキホン

31
Intermediate Language のキホン 2016.3.19 第六回 CENTER CLR 勉強会 KOUJI MATSUI (@KEKYO2)

Upload: kouji-matsui

Post on 07-Jan-2017

4.155 views

Category:

Software


0 download

TRANSCRIPT

Page 1: 真Intermediate languageのキホン

真Intermediate Languageのキホン2016.3.19 第六回CENTER CLR勉強会 KOUJI MATSUI (@KEKYO2)

Page 2: 真Intermediate languageのキホン

自己紹介

けきょ (@kekyo2)

ロードバイク乗り

Microsoft MVP for Visual Studio and Development Technology

認定スクラムマスター・スクラムプロダクトオーナー

Center CLRオーガナイザー

Page 3: 真Intermediate languageのキホン

ようこそ

最近、VRとか話題に上っておりますね。

私もGAME ONでプレステVR体感してきましたよ。

IBMとかなんちゃってSAOとかやってるようで、気合の入り方が斜め上ですなぁ。

インサイド: http://www.inside-games.jp/article/2016/03/17/96944.html

Page 4: 真Intermediate languageのキホン

本日は

それはさておき、本日はIntermediate Language(中間言語)のお話です。

「よく来たなひよっこどもよ」

Page 5: 真Intermediate languageのキホン

本日は

ILは基礎的な学問でいう所の「算数」みたいなもので、とにかくやって理解するのが近しい。応用の事は2の次。

なので、

よく言えばワークショップ

悪く言えば算数ドリル

Page 6: 真Intermediate languageのキホン

はじめに

Page 7: 真Intermediate languageのキホン

導入前回結構大変だったので、今回は最初に少しだけ抑えるべきところを説明しておきます。

① ILで覚えておく最初のことは、

「System.Reflection.Emit名前空間」だ。

◦ MSDNやILSpyで調べる足掛かりにする。

Page 8: 真Intermediate languageのキホン

導入

「System.Reflection.Emit.OpCodesクラス」

◦このクラスに「オプコード」の定義が含まれている。

コードから使えるようにする利便性のため(Meta-programming)

Page 9: 真Intermediate languageのキホン

導入

②オプコード(OpCode)とは:◦ CLRが理解できる中間言語(バイトコード)

CLR

OpCode.Ldarg

OpCode.Add

OpCode.Ldfld

OpCode.Call

OpCode.Ret

0x20

0x58

0x7b, &_v

0x28, &ToString

0x2a

Page 10: 真Intermediate languageのキホン

導入

③ OpCodeにはいくつか種類がある◦定数系: Ldc Ldstr Ldnull Ldtoken

◦引数操作系: Ldarg Starg

◦ローカル変数系: Ldloc Stloc

◦フィールド操作系: Ldfld Stfld

◦配列操作系: Ldelem Stelem Newarr

◦計算系: Add Sub Mul Div And Or Xor Not Shl Shr

◦生成系: Newobj Dup

◦型変換系: Conv Castclass Box Unbox

◦遷移系: Br Call Callvirt Ret Throw Rethrow Switch

◦その他: Ldind Stind Localloc

Page 11: 真Intermediate languageのキホン

導入

④スタック操作・スタックマシンとは:◦ CLRがバイトコード由来で動作するための基礎となる構造

CLR

1. Ldarg

3. Add

2. Ldfld

CLR Stack

123

456

Page 12: 真Intermediate languageのキホン

導入

④スタック操作・スタックマシンとは:◦ CLRがバイトコード由来で動作するための基礎となる構造

CLR

3. Add

CLR Stack

123

456123

456

579

Page 13: 真Intermediate languageのキホン

導入

④スタック操作・スタックマシンとは:◦ CLRがバイトコード由来で動作するための基礎となる構造

CLR

3. Add

CLR Stack

579579

Page 14: 真Intermediate languageのキホン

いよいよ実践

Page 15: 真Intermediate languageのキホン

準備

適当にチーム分けします。

チームには少なくともVisual Studioが入ったPCを。

GitHub: https://github.com/kekyo/CenterCLR.ReflectionEmitTemplate.git

Macの人は、可能ならVisual Studio Codeと.NET Core5をインスコ(あんまりフォローできないけど、ソースはnetcore5で動くようにしてあります)

ILSpy必須(Bingる)

Page 16: 真Intermediate languageのキホン

Part 1引数の値に1を加算して返すようにする。

ポイント:◦引数の値はどうやって取得するか

◦加算するにはどうするか

ヒント:◦引数操作系: Ldarg Starg (MSDNのOpCodesクラスを見る)

◦計算系: Add Sub Mul Div And Or Xor Not Shl Shr

◦戻り値を返すには?元のコードはどうなっていた?

Page 17: 真Intermediate languageのキホン

Part 2引数を増やして、加算して返す

ポイント:◦引数を増やすためには、Emitterも変更する必要がある。

ヒント:◦ DefineMethodとは

Page 18: 真Intermediate languageのキホン

Part 3引数の文字列を値に変換する

ポイント:◦ Convert.ToInt32メソッドを使う事にする

◦メソッドを呼び出すにはCallオプコードを使う

◦沢山のオーバーロードからどうやって絞り込むか?

ヒント:◦ MethodInfoはType.GetMethodsで取得する

Page 19: 真Intermediate languageのキホン

Part 4二つの引数の値をstring.Formatでフォーマットする

ポイント:◦ String.Formatメソッドのオーバーロードをどうやって特定するか?

◦型が違う場合は、変換する必要がある

ヒント:◦ MethodInfoはType.GetMethodで取得する

◦型変換のIL命令は2種類ある

◦ object hoge = 123; という式の暗黙変換の事を何て言ったっけ?

Page 20: 真Intermediate languageのキホン

Part 5インスタンスメソッドを作る(仕様はPart4のまま)

ポイント:◦ テンプレートコードはstaticメソッドを作って、そのデリゲートを返す。だからEmitterを変更する必要がある

◦ インスタンスメソッドを実行するには、インスタンスが必要(インスタンスの生成はILでやらなくて良い)

◦ thisはどこにあるのか◦ デフォルトコンストラクタを定義する

ヒント:◦ DefineMethodのフラグによって、定義するメソッドの属性が変わる◦ インスタンスメソッドの第0引数がthis◦ Activatorクラス

Page 21: 真Intermediate languageのキホン

Part 6フィールドを作り、前回の結果も加えて結果を計算する

ポイント:◦ TypeBuilderを使ってフィールドを定義する

◦フィールドにアクセスするIL命令

ヒント:◦「フィールドの値を読み書き」と言うより、「フィールドの値をスタックに積んだり出したり」

Page 22: 真Intermediate languageのキホン

Part 7C#で書いたクラスを継承する

ポイント:◦クラスはpublicでnon-sealedで定義する

◦クラスのコンストラクタは呼び出し可能でなければならない

ヒント:◦「継承するクラス型の指定」は、どこで定義される情報なのか?

Page 23: 真Intermediate languageのキホン

Part 8継承クラスのインスタンスメソッドを呼び出す

ポイント:◦継承元のクラスのメソッド定義を入手して呼び出す

◦呼び出しにthisが必要

ヒント:◦なし

Page 24: 真Intermediate languageのキホン

Part 9継承してオーバーライドされた仮想メソッドを呼び出す

ポイント:◦基底クラスのメソッド情報を使う

◦オーバーライドされたメソッドが呼び出される

ヒント:◦仮想メソッドを呼び出すIL命令

Page 25: 真Intermediate languageのキホン

Part 10オーバーライドされた仮想メソッドを無視し、基底メソッドを呼び出す

ポイント:◦ C#では実現できない

ヒント:◦ IL命令は実直

Page 26: 真Intermediate languageのキホン

Part 11クラスのインスタンスを生成する

ポイント:◦ newするには?

◦コンストラクタとは

ヒント:◦ newに対応するIL命令と、その引数

Page 27: 真Intermediate languageのキホン

Part 12プロパティを読み書きする

ポイント:◦プロパティ情報を取得する

◦ Getter/Setterメソッドとは

ヒント:◦なし

Page 28: 真Intermediate languageのキホン

Part 13Windows Formを表示し、タイトルバーに”Hello IL”と表示する

ポイント:◦ Formクラスを使い、インスタンスを生成し、プロパティにアクセスする

◦ ShowDialogメソッドを呼び出して表示する

ヒント:◦なし

Page 29: 真Intermediate languageのキホン

その他のトピック

デリゲートの生成:◦ Delegate.CreateDelegateとかをいじってからILに望むと吉。

イベント:◦プロパティと非常によく似ている。実態はadd/removeメソッド。

仮想メソッドのオーバーライド:◦まずDefineMethodでメソッドを定義してから、DefineMethodOverrideで基底メソッド定義と関連付ける。

インターフェイス型定義と実装:

Page 30: 真Intermediate languageのキホン

あとはほとんど応用だ!ILで書く範囲を少なくできるように工夫する。◦例:基底クラスやユーティリティクラスをC#で書いておき、複雑だがIL書かなくてもよい処理をオフロードする

Emitは色々つらいので、他の方法も理解しておく。◦ Emitは実行環境が限られる。Standard CLRやCore5ではサポートされているが、UWPとかダメ

◦ Emitでコードを量産しようとしている → T4テンプレートを使うと、似たようなソースコードをマクロ的に大量生産できる

◦動的型定義はなく、単に高速実行可能な動的言語がほしい → 式木を使う(式木構造について理解が必要だが、不正なILを作ってしまう危険はない)

◦サードパーティライブラリを使う(Mono.CecilはCLRに依存しないでバイナリを生成できる・Emit定義が楽になる各種補助ライブラリとか)

Page 31: 真Intermediate languageのキホン

がんばりました!!